+
+
New in version 1.4.3 (11/1/2008)
+
task-1.4.3.tar.gz
+
+ Mac OS X 10.5 (Leopard) Intel-only:
+
task-1.4.3.pkg
+
+ Debian package:
task_1.4.3-1_i386.deb
+ (Thanks to
Richard Querin)
+
+
+
+ - Fixed misleading task count at bottom of "info" report.
+
- Added support for a shadow file that contains a plain text task report,
+ with the "shadow.file" and "shadow.command" configuration variables.
+ The shadow file is automatically updated whenever the task database
+ changes. Useful for integrating with "Samurize".
+
- Task now displays a message whenever a shadow file is updated, if the
+ "shadow.notify" configuration variable is set "on".
+
- Fixed bug whereby adding a task with a \n, \r or \f dit not fail properly.
+
- Removed "task usage" command.
+
- Added documentation for Shadow files.
+
- Added documentation for task filters.
+
+
+
New in version 1.4.2 (9/18/2008)
task-1.4.2.tar.gz
diff --git a/src/.gitignore b/src/.gitignore
index 2327b8b98..5761abcfd 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,2 +1 @@
-./Makefile
*.o
diff --git a/src/Config.cpp b/src/Config.cpp
index 81bfcb6d2..03ca730dd 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -130,6 +130,10 @@ void Config::createDefault (const std::string& home)
fprintf (out, "#color.tag.bug=yellow\n");
fprintf (out, "#color.project.home=on_green\n");
fprintf (out, "#color.keyword.car=on_blue\n");
+ fprintf (out, "#shadow.file=%s/shadow.txt\n", dataDir.c_str ());
+ fprintf (out, "#shadow.command=list\n");
+ fprintf (out, "#shadow.notify=on\n");
+ fprintf (out, "#default.command=list\n");
fclose (out);
diff --git a/src/TDB.cpp b/src/TDB.cpp
index 9a67015b0..e531f10a1 100644
--- a/src/TDB.cpp
+++ b/src/TDB.cpp
@@ -204,9 +204,7 @@ bool TDB::deleteT (const T& t)
sprintf (endTime, "%u", (unsigned int) time (NULL));
it->setAttribute ("end", endTime);
- bool status = overwritePending (all);
- dbChanged ();
- return status;
+ return overwritePending (all);
}
return false;
@@ -230,9 +228,7 @@ bool TDB::completeT (const T& t)
sprintf (endTime, "%u", (unsigned int) time (NULL));
it->setAttribute ("end", endTime);
- bool status = overwritePending (all);
- dbChanged ();
- return status;
+ return overwritePending (all);
}
return false;
@@ -259,14 +255,10 @@ bool TDB::addT (const T& t)
if (task.getStatus () == T::pending ||
task.getStatus () == T::recurring)
{
- bool status = writePending (task);
- dbChanged ();
- return status;
+ return writePending (task);
}
- bool status = writeCompleted (task);
- dbChanged ();
- return status;
+ return writeCompleted (task);
}
////////////////////////////////////////////////////////////////////////////////
@@ -291,9 +283,7 @@ bool TDB::modifyT (const T& t)
pending.push_back (*it);
}
- bool status = overwritePending (pending);
- dbChanged ();
- return status;
+ return overwritePending (pending);
}
////////////////////////////////////////////////////////////////////////////////
@@ -324,6 +314,7 @@ bool TDB::overwritePending (std::vector
& all)
fputs (it->compose ().c_str (), out);
fclose (out);
+ dbChanged ();
return true;
}
@@ -331,7 +322,7 @@ bool TDB::overwritePending (std::vector & all)
}
////////////////////////////////////////////////////////////////////////////////
-bool TDB::writePending (const T& t) const
+bool TDB::writePending (const T& t)
{
// Write a single task to the pending file
FILE* out;
@@ -346,6 +337,7 @@ bool TDB::writePending (const T& t) const
fputs (t.compose ().c_str (), out);
fclose (out);
+ dbChanged ();
return true;
}
@@ -353,7 +345,7 @@ bool TDB::writePending (const T& t) const
}
////////////////////////////////////////////////////////////////////////////////
-bool TDB::writeCompleted (const T& t) const
+bool TDB::writeCompleted (const T& t)
{
// Write a single task to the pending file
FILE* out;
@@ -368,6 +360,8 @@ bool TDB::writeCompleted (const T& t) const
fputs (t.compose ().c_str (), out);
fclose (out);
+ // Note: No call to dbChanged here because this call never occurs by itself.
+ // It is always accompanied by an overwritePending call.
return true;
}
@@ -439,8 +433,11 @@ int TDB::gc ()
}
}
- // Dump all clean tasks into pending.
- overwritePending (pending);
+ // Dump all clean tasks into pending. But don't bother unless at least one
+ // task was transferred.
+ if (count)
+ overwritePending (pending);
+
return count;
}
diff --git a/src/TDB.h b/src/TDB.h
index 266800580..d335e909b 100644
--- a/src/TDB.h
+++ b/src/TDB.h
@@ -56,8 +56,8 @@ public:
private:
bool lock (FILE*) const;
bool overwritePending (std::vector &);
- bool writePending (const T&) const;
- bool writeCompleted (const T&) const;
+ bool writePending (const T&);
+ bool writeCompleted (const T&);
bool readLockedFile (const std::string&, std::vector &) const;
void dbChanged ();
diff --git a/src/command.cpp b/src/command.cpp
index b444b9515..a404dc399 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -26,6 +26,7 @@
////////////////////////////////////////////////////////////////////////////////
#include
#include
+#include
#include
#include
#include
@@ -67,7 +68,6 @@ void handleAdd (TDB& tdb, T& task, Config& conf)
task.setAttribute ("mask", "");
}
-/**/
// Override with default.project, if not specified.
if (task.getAttribute ("project") == "")
task.setAttribute ("project", conf.get ("default.project", ""));
@@ -79,18 +79,20 @@ void handleAdd (TDB& tdb, T& task, Config& conf)
if (validPriority (defaultPriority))
task.setAttribute ("priority", defaultPriority);
}
-/**/
+ // Disallow blank descriptions.
if (task.getDescription () == "")
- throw std::string ("Cannot add a blank task.");
+ throw std::string ("Cannot add a task that is blank, or contains or characters.");
if (!tdb.addT (task))
throw std::string ("Could not create new task.");
}
////////////////////////////////////////////////////////////////////////////////
-void handleProjects (TDB& tdb, T& task, Config& conf)
+std::string handleProjects (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
// Get all the tasks, including deleted ones.
std::vector tasks;
tdb.pendingT (tasks);
@@ -127,21 +129,25 @@ void handleProjects (TDB& tdb, T& task, Config& conf)
table.addCell (row, 1, i->second);
}
- std::cout << optionalBlankLine (conf)
- << table.render ()
- << optionalBlankLine (conf)
- << unique.size ()
- << (unique.size () == 1 ? " project" : " projects")
- << std::endl;
+ out << optionalBlankLine (conf)
+ << table.render ()
+ << optionalBlankLine (conf)
+ << unique.size ()
+ << (unique.size () == 1 ? " project" : " projects")
+ << std::endl;
}
else
- std::cout << "No projects."
- << std::endl;
+ out << "No projects."
+ << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
-void handleTags (TDB& tdb, T& task, Config& conf)
+std::string handleTags (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
// Get all the tasks.
std::vector tasks;
tdb.pendingT (tasks);
@@ -166,20 +172,23 @@ void handleTags (TDB& tdb, T& task, Config& conf)
std::cout << i->first << std::endl;
if (unique.size ())
- std::cout << optionalBlankLine (conf)
- << unique.size ()
- << (unique.size () == 1 ? " tag" : " tags")
- << std::endl;
+ out << optionalBlankLine (conf)
+ << unique.size ()
+ << (unique.size () == 1 ? " tag" : " tags")
+ << std::endl;
else
- std::cout << "No tags."
- << std::endl;
+ out << "No tags."
+ << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
// If a task is deleted, but is still in the pending file, then it may be
// undeleted simply by changing it's status.
-void handleUndelete (TDB& tdb, T& task, Config& conf)
+std::string handleUndelete (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
std::vector all;
tdb.allPendingT (all);
@@ -193,8 +202,8 @@ void handleUndelete (TDB& tdb, T& task, Config& conf)
{
if (it->getAttribute ("recur") != "")
{
- std::cout << "Task does not support 'undelete' for recurring tasks." << std::endl;
- return;
+ out << "Task does not support 'undelete' for recurring tasks." << std::endl;
+ return out.str ();
}
T restored (*it);
@@ -202,27 +211,31 @@ void handleUndelete (TDB& tdb, T& task, Config& conf)
restored.removeAttribute ("end");
tdb.modifyT (restored);
- std::cout << "Task " << id << " successfully undeleted." << std::endl;
- return;
+ out << "Task " << id << " successfully undeleted." << std::endl;
+ return out.str ();
}
else
{
- std::cout << "Task " << id << " is not deleted - therefore cannot undelete." << std::endl;
- return;
+ out << "Task " << id << " is not deleted - therefore cannot undelete." << std::endl;
+ return out.str ();
}
}
}
- std::cout << "Task " << id
- << " not found - tasks can only be reliably undeleted if the undelete" << std::endl
- << "command is run immediately after the errant delete command." << std::endl;
+ out << "Task " << id
+ << " not found - tasks can only be reliably undeleted if the undelete" << std::endl
+ << "command is run immediately after the errant delete command." << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
// If a task is done, but is still in the pending file, then it may be undone
// simply by changing it's status.
-void handleUndo (TDB& tdb, T& task, Config& conf)
+std::string handleUndo (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
std::vector all;
tdb.allPendingT (all);
@@ -235,35 +248,36 @@ void handleUndo (TDB& tdb, T& task, Config& conf)
if (it->getStatus () == T::completed)
{
if (it->getAttribute ("recur") != "")
- {
- std::cout << "Task does not support 'undo' for recurring tasks." << std::endl;
- return;
- }
+ return std::string ("Task does not support 'undo' for recurring tasks.\n");
T restored (*it);
restored.setStatus (T::pending);
restored.removeAttribute ("end");
tdb.modifyT (restored);
- std::cout << "Task " << id << " successfully undone." << std::endl;
- return;
+ out << "Task " << id << " successfully undone." << std::endl;
+ return out.str ();
}
else
{
- std::cout << "Task " << id << " is not done - therefore cannot be undone." << std::endl;
- return;
+ out << "Task " << id << " is not done - therefore cannot be undone." << std::endl;
+ return out.str ();
}
}
}
- std::cout << "Task " << id
- << " not found - tasks can only be reliably undone if the undo" << std::endl
- << "command is run immediately after the errant done command." << std::endl;
+ out << "Task " << id
+ << " not found - tasks can only be reliably undone if the undo" << std::endl
+ << "command is run immediately after the errant done command." << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
-void handleVersion (Config& conf)
+std::string handleVersion (Config& conf)
{
+ std::stringstream out;
+
// Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES
@@ -329,40 +343,42 @@ void handleVersion (Config& conf)
}
}
- std::cout << "Copyright (C) 2006 - 2008, P. Beckingham."
- << std::endl
- << (conf.get ("color", true) ? Text::colorize (Text::bold, Text::nocolor, PACKAGE) : PACKAGE)
- << " "
- << (conf.get ("color", true) ? Text::colorize (Text::bold, Text::nocolor, VERSION) : VERSION)
- << std::endl
- << disclaimer.render ()
- << std::endl
- << table.render ()
- << link.render ()
- << std::endl;
+ out << "Copyright (C) 2006 - 2008, P. Beckingham."
+ << std::endl
+ << (conf.get ("color", true) ? Text::colorize (Text::bold, Text::nocolor, PACKAGE) : PACKAGE)
+ << " "
+ << (conf.get ("color", true) ? Text::colorize (Text::bold, Text::nocolor, VERSION) : VERSION)
+ << std::endl
+ << disclaimer.render ()
+ << std::endl
+ << table.render ()
+ << link.render ()
+ << std::endl;
// Verify installation. This is mentioned in the documentation as the way to
// ensure everything is properly installed.
if (all.size () == 0)
- std::cout << "Configuration error: .taskrc contains no entries"
- << std::endl;
+ out << "Configuration error: .taskrc contains no entries"
+ << std::endl;
else
{
if (conf.get ("data.location") == "")
- std::cout << "Configuration error: data.location not specified in .taskrc "
- "file."
- << std::endl;
+ out << "Configuration error: data.location not specified in .taskrc "
+ "file."
+ << std::endl;
if (access (expandPath (conf.get ("data.location")).c_str (), X_OK))
- std::cout << "Configuration error: data.location contains a directory name"
- " that doesn't exist, or is unreadable."
- << std::endl;
+ out << "Configuration error: data.location contains a directory name"
+ " that doesn't exist, or is unreadable."
+ << std::endl;
}
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
-void handleDelete (TDB& tdb, T& task, Config& conf)
+std::string handleDelete (TDB& tdb, T& task, Config& conf)
{
if (conf.get ("confirmation") != "yes" || confirm ("Permanently delete task?"))
{
@@ -386,7 +402,7 @@ void handleDelete (TDB& tdb, T& task, Config& conf)
sibling->getUUID () == parent)
tdb.deleteT (*sibling);
- return;
+ return std::string ("");
}
else
{
@@ -394,7 +410,7 @@ void handleDelete (TDB& tdb, T& task, Config& conf)
t->setStatus (T::deleted);
updateRecurrenceMask (tdb, all, *t);
tdb.deleteT (*t);
- return;
+ return std::string ("");
}
}
else
@@ -405,11 +421,13 @@ void handleDelete (TDB& tdb, T& task, Config& conf)
}
}
else
- std::cout << "Task not deleted." << std::endl;
+ return std::string ("Task not deleted.\n");
+
+ return std::string ("");
}
////////////////////////////////////////////////////////////////////////////////
-void handleStart (TDB& tdb, T& task, Config& conf)
+std::string handleStart (TDB& tdb, T& task, Config& conf)
{
std::vector all;
tdb.pendingT (all);
@@ -431,18 +449,23 @@ void handleStart (TDB& tdb, T& task, Config& conf)
tdb.modifyT (original);
nag (tdb, task, conf);
- return;
+ return std::string ("");
}
else
- std::cout << "Task " << task.getId () << " already started." << std::endl;
+ {
+ std::stringstream out;
+ out << "Task " << task.getId () << " already started." << std::endl;
+ return out.str ();
+ }
}
}
throw std::string ("Task not found.");
+ return std::string (""); // To satisfy gcc.
}
////////////////////////////////////////////////////////////////////////////////
-void handleStop (TDB& tdb, T& task, Config& conf)
+std::string handleStop (TDB& tdb, T& task, Config& conf)
{
std::vector all;
tdb.pendingT (all);
@@ -461,14 +484,19 @@ void handleStop (TDB& tdb, T& task, Config& conf)
tdb.modifyT (original);
nag (tdb, task, conf);
- return;
+ return std::string ("");
}
else
- std::cout << "Task " << task.getId () << " not started." << std::endl;
+ {
+ std::stringstream out;
+ out << "Task " << task.getId () << " not started." << std::endl;
+ return out.str ();
+ }
}
}
throw std::string ("Task not found.");
+ return std::string (""); // To satisfy gcc.
}
////////////////////////////////////////////////////////////////////////////////
@@ -627,87 +655,91 @@ void handleModify (TDB& tdb, T& task, Config& conf)
}
////////////////////////////////////////////////////////////////////////////////
-void handleColor (Config& conf)
+std::string handleColor (Config& conf)
{
+ std::stringstream out;
+
if (conf.get ("color", true))
{
- std::cout << optionalBlankLine (conf) << "Foreground" << std::endl
- << " "
- << Text::colorize (Text::bold, Text::nocolor, "bold") << " "
- << Text::colorize (Text::underline, Text::nocolor, "underline") << " "
- << Text::colorize (Text::bold_underline, Text::nocolor, "bold_underline") << std::endl
+ out << optionalBlankLine (conf) << "Foreground" << std::endl
+ << " "
+ << Text::colorize (Text::bold, Text::nocolor, "bold") << " "
+ << Text::colorize (Text::underline, Text::nocolor, "underline") << " "
+ << Text::colorize (Text::bold_underline, Text::nocolor, "bold_underline") << std::endl
- << " " << Text::colorize (Text::black, Text::nocolor, "black") << " "
- << Text::colorize (Text::bold_black, Text::nocolor, "bold_black") << " "
- << Text::colorize (Text::underline_black, Text::nocolor, "underline_black") << " "
- << Text::colorize (Text::bold_underline_black, Text::nocolor, "bold_underline_black") << std::endl
+ << " " << Text::colorize (Text::black, Text::nocolor, "black") << " "
+ << Text::colorize (Text::bold_black, Text::nocolor, "bold_black") << " "
+ << Text::colorize (Text::underline_black, Text::nocolor, "underline_black") << " "
+ << Text::colorize (Text::bold_underline_black, Text::nocolor, "bold_underline_black") << std::endl
- << " " << Text::colorize (Text::red, Text::nocolor, "red") << " "
- << Text::colorize (Text::bold_red, Text::nocolor, "bold_red") << " "
- << Text::colorize (Text::underline_red, Text::nocolor, "underline_red") << " "
- << Text::colorize (Text::bold_underline_red, Text::nocolor, "bold_underline_red") << std::endl
+ << " " << Text::colorize (Text::red, Text::nocolor, "red") << " "
+ << Text::colorize (Text::bold_red, Text::nocolor, "bold_red") << " "
+ << Text::colorize (Text::underline_red, Text::nocolor, "underline_red") << " "
+ << Text::colorize (Text::bold_underline_red, Text::nocolor, "bold_underline_red") << std::endl
- << " " << Text::colorize (Text::green, Text::nocolor, "green") << " "
- << Text::colorize (Text::bold_green, Text::nocolor, "bold_green") << " "
- << Text::colorize (Text::underline_green, Text::nocolor, "underline_green") << " "
- << Text::colorize (Text::bold_underline_green, Text::nocolor, "bold_underline_green") << std::endl
+ << " " << Text::colorize (Text::green, Text::nocolor, "green") << " "
+ << Text::colorize (Text::bold_green, Text::nocolor, "bold_green") << " "
+ << Text::colorize (Text::underline_green, Text::nocolor, "underline_green") << " "
+ << Text::colorize (Text::bold_underline_green, Text::nocolor, "bold_underline_green") << std::endl
- << " " << Text::colorize (Text::yellow, Text::nocolor, "yellow") << " "
- << Text::colorize (Text::bold_yellow, Text::nocolor, "bold_yellow") << " "
- << Text::colorize (Text::underline_yellow, Text::nocolor, "underline_yellow") << " "
- << Text::colorize (Text::bold_underline_yellow, Text::nocolor, "bold_underline_yellow") << std::endl
+ << " " << Text::colorize (Text::yellow, Text::nocolor, "yellow") << " "
+ << Text::colorize (Text::bold_yellow, Text::nocolor, "bold_yellow") << " "
+ << Text::colorize (Text::underline_yellow, Text::nocolor, "underline_yellow") << " "
+ << Text::colorize (Text::bold_underline_yellow, Text::nocolor, "bold_underline_yellow") << std::endl
- << " " << Text::colorize (Text::blue, Text::nocolor, "blue") << " "
- << Text::colorize (Text::bold_blue, Text::nocolor, "bold_blue") << " "
- << Text::colorize (Text::underline_blue, Text::nocolor, "underline_blue") << " "
- << Text::colorize (Text::bold_underline_blue, Text::nocolor, "bold_underline_blue") << std::endl
+ << " " << Text::colorize (Text::blue, Text::nocolor, "blue") << " "
+ << Text::colorize (Text::bold_blue, Text::nocolor, "bold_blue") << " "
+ << Text::colorize (Text::underline_blue, Text::nocolor, "underline_blue") << " "
+ << Text::colorize (Text::bold_underline_blue, Text::nocolor, "bold_underline_blue") << std::endl
- << " " << Text::colorize (Text::magenta, Text::nocolor, "magenta") << " "
- << Text::colorize (Text::bold_magenta, Text::nocolor, "bold_magenta") << " "
- << Text::colorize (Text::underline_magenta, Text::nocolor, "underline_magenta") << " "
- << Text::colorize (Text::bold_underline_magenta, Text::nocolor, "bold_underline_magenta") << std::endl
+ << " " << Text::colorize (Text::magenta, Text::nocolor, "magenta") << " "
+ << Text::colorize (Text::bold_magenta, Text::nocolor, "bold_magenta") << " "
+ << Text::colorize (Text::underline_magenta, Text::nocolor, "underline_magenta") << " "
+ << Text::colorize (Text::bold_underline_magenta, Text::nocolor, "bold_underline_magenta") << std::endl
- << " " << Text::colorize (Text::cyan, Text::nocolor, "cyan") << " "
- << Text::colorize (Text::bold_cyan, Text::nocolor, "bold_cyan") << " "
- << Text::colorize (Text::underline_cyan, Text::nocolor, "underline_cyan") << " "
- << Text::colorize (Text::bold_underline_cyan, Text::nocolor, "bold_underline_cyan") << std::endl
+ << " " << Text::colorize (Text::cyan, Text::nocolor, "cyan") << " "
+ << Text::colorize (Text::bold_cyan, Text::nocolor, "bold_cyan") << " "
+ << Text::colorize (Text::underline_cyan, Text::nocolor, "underline_cyan") << " "
+ << Text::colorize (Text::bold_underline_cyan, Text::nocolor, "bold_underline_cyan") << std::endl
- << " " << Text::colorize (Text::white, Text::nocolor, "white") << " "
- << Text::colorize (Text::bold_white, Text::nocolor, "bold_white") << " "
- << Text::colorize (Text::underline_white, Text::nocolor, "underline_white") << " "
- << Text::colorize (Text::bold_underline_white, Text::nocolor, "bold_underline_white") << std::endl
+ << " " << Text::colorize (Text::white, Text::nocolor, "white") << " "
+ << Text::colorize (Text::bold_white, Text::nocolor, "bold_white") << " "
+ << Text::colorize (Text::underline_white, Text::nocolor, "underline_white") << " "
+ << Text::colorize (Text::bold_underline_white, Text::nocolor, "bold_underline_white") << std::endl
- << std::endl << "Background" << std::endl
- << " " << Text::colorize (Text::nocolor, Text::on_black, "on_black") << " "
- << Text::colorize (Text::nocolor, Text::on_bright_black, "on_bright_black") << std::endl
+ << std::endl << "Background" << std::endl
+ << " " << Text::colorize (Text::nocolor, Text::on_black, "on_black") << " "
+ << Text::colorize (Text::nocolor, Text::on_bright_black, "on_bright_black") << std::endl
- << " " << Text::colorize (Text::nocolor, Text::on_red, "on_red") << " "
- << Text::colorize (Text::nocolor, Text::on_bright_red, "on_bright_red") << std::endl
+ << " " << Text::colorize (Text::nocolor, Text::on_red, "on_red") << " "
+ << Text::colorize (Text::nocolor, Text::on_bright_red, "on_bright_red") << std::endl
- << " " << Text::colorize (Text::nocolor, Text::on_green, "on_green") << " "
- << Text::colorize (Text::nocolor, Text::on_bright_green, "on_bright_green") << std::endl
+ << " " << Text::colorize (Text::nocolor, Text::on_green, "on_green") << " "
+ << Text::colorize (Text::nocolor, Text::on_bright_green, "on_bright_green") << std::endl
- << " " << Text::colorize (Text::nocolor, Text::on_yellow, "on_yellow") << " "
- << Text::colorize (Text::nocolor, Text::on_bright_yellow, "on_bright_yellow") << std::endl
+ << " " << Text::colorize (Text::nocolor, Text::on_yellow, "on_yellow") << " "
+ << Text::colorize (Text::nocolor, Text::on_bright_yellow, "on_bright_yellow") << std::endl
- << " " << Text::colorize (Text::nocolor, Text::on_blue, "on_blue") << " "
- << Text::colorize (Text::nocolor, Text::on_bright_blue, "on_bright_blue") << std::endl
+ << " " << Text::colorize (Text::nocolor, Text::on_blue, "on_blue") << " "
+ << Text::colorize (Text::nocolor, Text::on_bright_blue, "on_bright_blue") << std::endl
- << " " << Text::colorize (Text::nocolor, Text::on_magenta, "on_magenta") << " "
- << Text::colorize (Text::nocolor, Text::on_bright_magenta, "on_bright_magenta") << std::endl
+ << " " << Text::colorize (Text::nocolor, Text::on_magenta, "on_magenta") << " "
+ << Text::colorize (Text::nocolor, Text::on_bright_magenta, "on_bright_magenta") << std::endl
- << " " << Text::colorize (Text::nocolor, Text::on_cyan, "on_cyan") << " "
- << Text::colorize (Text::nocolor, Text::on_bright_cyan, "on_bright_cyan") << std::endl
+ << " " << Text::colorize (Text::nocolor, Text::on_cyan, "on_cyan") << " "
+ << Text::colorize (Text::nocolor, Text::on_bright_cyan, "on_bright_cyan") << std::endl
- << " " << Text::colorize (Text::nocolor, Text::on_white, "on_white") << " "
- << Text::colorize (Text::nocolor, Text::on_bright_white, "on_bright_white") << std::endl
+ << " " << Text::colorize (Text::nocolor, Text::on_white, "on_white") << " "
+ << Text::colorize (Text::nocolor, Text::on_bright_white, "on_bright_white") << std::endl
- << optionalBlankLine (conf);
+ << optionalBlankLine (conf);
}
else
{
- std::cout << "Color is currently turned off in your .taskrc file." << std::endl;
+ out << "Color is currently turned off in your .taskrc file." << std::endl;
}
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/parse.cpp b/src/parse.cpp
index 1e88ef534..43bc893c4 100644
--- a/src/parse.cpp
+++ b/src/parse.cpp
@@ -284,10 +284,21 @@ static bool validTag (const std::string& input)
////////////////////////////////////////////////////////////////////////////////
static bool validDescription (const std::string& input)
{
- if (input.length () > 0)
+/*
+ if (input.length () > 0 &&
+ input.find ("\r") == std::string::npos &&
+ input.find ("\f") == std::string::npos &&
+ input.find ("\n") == std::string::npos)
return true;
return false;
+*/
+ if (input.length () == 0) return false;
+ if (input.find ("\r") != std::string::npos) return false;
+ if (input.find ("\f") != std::string::npos) return false;
+ if (input.find ("\n") != std::string::npos) return false;
+
+ return true;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/report.cpp b/src/report.cpp
index eb3a03de0..2f29f95ed 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -26,6 +26,7 @@
////////////////////////////////////////////////////////////////////////////////
#include
#include
+#include
#include
#include
#include
@@ -110,8 +111,10 @@ void filter (std::vector& all, T& task)
////////////////////////////////////////////////////////////////////////////////
// Successively apply filters based on the task object built from the command
// line. Tasks that match all the specified criteria are listed.
-void handleList (TDB& tdb, T& task, Config& conf)
+std::string handleList (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
// Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES
@@ -124,7 +127,6 @@ void handleList (TDB& tdb, T& task, Config& conf)
#endif
// Get the pending tasks.
- tdb.gc ();
std::vector tasks;
tdb.allPendingT (tasks);
handleRecurrence (tdb, tasks);
@@ -242,23 +244,27 @@ void handleList (TDB& tdb, T& task, Config& conf)
}
if (table.rowCount ())
- std::cout << optionalBlankLine (conf)
- << table.render ()
- << optionalBlankLine (conf)
- << table.rowCount ()
- << (table.rowCount () == 1 ? " task" : " tasks")
- << std::endl;
+ out << optionalBlankLine (conf)
+ << table.render ()
+ << optionalBlankLine (conf)
+ << table.rowCount ()
+ << (table.rowCount () == 1 ? " task" : " tasks")
+ << std::endl;
else
- std::cout << "No matches."
- << std::endl;
+ out << "No matches."
+ << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
// Successively apply filters based on the task object built from the command
// line. Tasks that match all the specified criteria are listed. Show a narrow
// list that works better on mobile devices.
-void handleSmallList (TDB& tdb, T& task, Config& conf)
+std::string handleSmallList (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
// Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES
@@ -271,7 +277,6 @@ void handleSmallList (TDB& tdb, T& task, Config& conf)
#endif
// Get the pending tasks.
- tdb.gc ();
std::vector tasks;
tdb.allPendingT (tasks);
handleRecurrence (tdb, tasks);
@@ -371,22 +376,26 @@ void handleSmallList (TDB& tdb, T& task, Config& conf)
}
if (table.rowCount ())
- std::cout << optionalBlankLine (conf)
- << table.render ()
- << optionalBlankLine (conf)
- << table.rowCount ()
- << (table.rowCount () == 1 ? " task" : " tasks")
- << std::endl;
+ out << optionalBlankLine (conf)
+ << table.render ()
+ << optionalBlankLine (conf)
+ << table.rowCount ()
+ << (table.rowCount () == 1 ? " task" : " tasks")
+ << std::endl;
else
- std::cout << "No matches."
- << std::endl;
+ out << "No matches."
+ << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
// Successively apply filters based on the task object built from the command
// line. Tasks that match all the specified criteria are listed.
-void handleCompleted (TDB& tdb, T& task, Config& conf)
+std::string handleCompleted (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
// Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES
@@ -399,7 +408,6 @@ void handleCompleted (TDB& tdb, T& task, Config& conf)
#endif
// Get the pending tasks.
- tdb.gc ();
std::vector tasks;
tdb.completedT (tasks);
filter (tasks, task);
@@ -459,21 +467,25 @@ void handleCompleted (TDB& tdb, T& task, Config& conf)
}
if (table.rowCount ())
- std::cout << optionalBlankLine (conf)
- << table.render ()
- << optionalBlankLine (conf)
- << table.rowCount ()
- << (table.rowCount () == 1 ? " task" : " tasks")
- << std::endl;
+ out << optionalBlankLine (conf)
+ << table.render ()
+ << optionalBlankLine (conf)
+ << table.rowCount ()
+ << (table.rowCount () == 1 ? " task" : " tasks")
+ << std::endl;
else
- std::cout << "No matches."
- << std::endl;
+ out << "No matches."
+ << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
// Display all information for the given task.
-void handleInfo (TDB& tdb, T& task, Config& conf)
+std::string handleInfo (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
// Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES
@@ -657,18 +669,22 @@ void handleInfo (TDB& tdb, T& task, Config& conf)
}
if (table.rowCount ())
- std::cout << optionalBlankLine (conf)
- << table.render ()
- << std::endl;
+ out << optionalBlankLine (conf)
+ << table.render ()
+ << std::endl;
else
- std::cout << "No matches." << std::endl;
+ out << "No matches." << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
// Successively apply filters based on the task object built from the command
// line. Tasks that match all the specified criteria are listed.
-void handleLongList (TDB& tdb, T& task, Config& conf)
+std::string handleLongList (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
// Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES
@@ -681,7 +697,6 @@ void handleLongList (TDB& tdb, T& task, Config& conf)
#endif
// Get all the tasks.
- tdb.gc ();
std::vector tasks;
tdb.allPendingT (tasks);
handleRecurrence (tdb, tasks);
@@ -824,24 +839,27 @@ void handleLongList (TDB& tdb, T& task, Config& conf)
}
if (table.rowCount ())
- std::cout << optionalBlankLine (conf)
- << table.render ()
- << optionalBlankLine (conf)
- << table.rowCount ()
- << (table.rowCount () == 1 ? " task" : " tasks")
- << std::endl;
+ out << optionalBlankLine (conf)
+ << table.render ()
+ << optionalBlankLine (conf)
+ << table.rowCount ()
+ << (table.rowCount () == 1 ? " task" : " tasks")
+ << std::endl;
else
- std::cout << "No matches." << std::endl;
+ out << "No matches." << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
// Project Tasks Avg Age Status
// A 12 13d XXXXXXXX------
// B 109 3d 12h XX------------
-void handleReportSummary (TDB& tdb, T& task, Config& conf)
+std::string handleReportSummary (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
// Generate unique list of project names.
- tdb.gc ();
std::map allProjects;
std::vector pending;
tdb.allPendingT (pending);
@@ -981,14 +999,16 @@ void handleReportSummary (TDB& tdb, T& task, Config& conf)
}
if (table.rowCount ())
- std::cout << optionalBlankLine (conf)
- << table.render ()
- << optionalBlankLine (conf)
- << table.rowCount ()
- << (table.rowCount () == 1 ? " project" : " projects")
- << std::endl;
+ out << optionalBlankLine (conf)
+ << table.render ()
+ << optionalBlankLine (conf)
+ << table.rowCount ()
+ << (table.rowCount () == 1 ? " project" : " projects")
+ << std::endl;
else
- std::cout << "No projects." << std::endl;
+ out << "No projects." << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
@@ -1010,10 +1030,11 @@ void handleReportSummary (TDB& tdb, T& task, Config& conf)
//
// Make the "three" tasks a configurable number
//
-void handleReportNext (TDB& tdb, T& task, Config& conf)
+std::string handleReportNext (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
// Load all pending.
- tdb.gc ();
std::vector pending;
tdb.allPendingT (pending);
handleRecurrence (tdb, pending);
@@ -1034,8 +1055,6 @@ void handleReportNext (TDB& tdb, T& task, Config& conf)
}
#endif
- tdb.gc ();
-
// Get the pending tasks.
std::vector tasks;
tdb.pendingT (tasks);
@@ -1151,15 +1170,17 @@ void handleReportNext (TDB& tdb, T& task, Config& conf)
}
if (table.rowCount ())
- std::cout << optionalBlankLine (conf)
- << table.render ()
- << optionalBlankLine (conf)
- << table.rowCount ()
- << (table.rowCount () == 1 ? " task" : " tasks")
- << std::endl;
+ out << optionalBlankLine (conf)
+ << table.render ()
+ << optionalBlankLine (conf)
+ << table.rowCount ()
+ << (table.rowCount () == 1 ? " task" : " tasks")
+ << std::endl;
else
- std::cout << "No matches."
- << std::endl;
+ out << "No matches."
+ << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
@@ -1184,15 +1205,16 @@ time_t monthlyEpoch (const std::string& date)
return 0;
}
-void handleReportHistory (TDB& tdb, T& task, Config& conf)
+std::string handleReportHistory (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
std::map groups;
std::map addedGroup;
std::map completedGroup;
std::map deletedGroup;
// Scan the pending tasks.
- tdb.gc ();
std::vector pending;
tdb.allPendingT (pending);
handleRecurrence (tdb, pending);
@@ -1360,16 +1382,20 @@ void handleReportHistory (TDB& tdb, T& task, Config& conf)
}
if (table.rowCount ())
- std::cout << optionalBlankLine (conf)
- << table.render ()
- << std::endl;
+ out << optionalBlankLine (conf)
+ << table.render ()
+ << std::endl;
else
- std::cout << "No tasks." << std::endl;
+ out << "No tasks." << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
-void handleReportGHistory (TDB& tdb, T& task, Config& conf)
+std::string handleReportGHistory (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
// Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES
@@ -1388,7 +1414,6 @@ void handleReportGHistory (TDB& tdb, T& task, Config& conf)
std::map deletedGroup;
// Scan the pending tasks.
- tdb.gc ();
std::vector pending;
tdb.allPendingT (pending);
handleRecurrence (tdb, pending);
@@ -1583,24 +1608,26 @@ void handleReportGHistory (TDB& tdb, T& task, Config& conf)
if (table.rowCount ())
{
- std::cout << optionalBlankLine (conf)
- << table.render ()
- << std::endl;
+ out << optionalBlankLine (conf)
+ << table.render ()
+ << std::endl;
if (conf.get ("color", true))
- std::cout << "Legend: "
- << Text::colorize (Text::black, Text::on_red, "added")
- << ", "
- << Text::colorize (Text::black, Text::on_green, "completed")
- << ", "
- << Text::colorize (Text::black, Text::on_yellow, "deleted")
- << optionalBlankLine (conf)
- << std::endl;
+ out << "Legend: "
+ << Text::colorize (Text::black, Text::on_red, "added")
+ << ", "
+ << Text::colorize (Text::black, Text::on_green, "completed")
+ << ", "
+ << Text::colorize (Text::black, Text::on_yellow, "deleted")
+ << optionalBlankLine (conf)
+ << std::endl;
else
- std::cout << "Legend: + added, X completed, - deleted" << std::endl;
+ out << "Legend: + added, X completed, - deleted" << std::endl;
}
else
- std::cout << "No tasks." << std::endl;
+ out << "No tasks." << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
@@ -1728,10 +1755,11 @@ std::string renderMonths (
}
////////////////////////////////////////////////////////////////////////////////
-void handleReportCalendar (TDB& tdb, T& task, Config& conf)
+std::string handleReportCalendar (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
// Load all the pending tasks.
- tdb.gc ();
std::vector pending;
tdb.allPendingT (pending);
handleRecurrence (tdb, pending);
@@ -1760,7 +1788,7 @@ void handleReportCalendar (TDB& tdb, T& task, Config& conf)
int mTo = newest.month ();
int yTo = newest.year ();
- std::cout << std::endl;
+ out << std::endl;
std::string output;
int monthsPerLine = (conf.get ("monthsperline", 1));
@@ -1777,11 +1805,11 @@ void handleReportCalendar (TDB& tdb, T& task, Config& conf)
int left = (18 - month.length ()) / 2 + 1;
int right = 18 - left - month.length ();
- std::cout << std::setw (left) << ' '
- << month
- << ' '
- << nextY
- << std::setw (right) << ' ';
+ out << std::setw (left) << ' '
+ << month
+ << ' '
+ << nextY
+ << std::setw (right) << ' ';
if (++nextM > 12)
{
@@ -1790,10 +1818,10 @@ void handleReportCalendar (TDB& tdb, T& task, Config& conf)
}
}
- std::cout << std::endl
- << optionalBlankLine (conf)
- << renderMonths (mFrom, yFrom, today, pending, conf)
- << std::endl;
+ out << std::endl
+ << optionalBlankLine (conf)
+ << renderMonths (mFrom, yFrom, today, pending, conf)
+ << std::endl;
mFrom += monthsPerLine;
if (mFrom > 12)
@@ -1803,20 +1831,24 @@ void handleReportCalendar (TDB& tdb, T& task, Config& conf)
}
}
- std::cout << "Legend: "
- << Text::colorize (Text::cyan, Text::nocolor, "today")
- << ", "
- << Text::colorize (Text::black, Text::on_yellow, "due")
- << ", "
- << Text::colorize (Text::black, Text::on_red, "overdue")
- << "."
- << optionalBlankLine (conf)
- << std::endl;
+ out << "Legend: "
+ << Text::colorize (Text::cyan, Text::nocolor, "today")
+ << ", "
+ << Text::colorize (Text::black, Text::on_yellow, "due")
+ << ", "
+ << Text::colorize (Text::black, Text::on_red, "overdue")
+ << "."
+ << optionalBlankLine (conf)
+ << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
-void handleReportActive (TDB& tdb, T& task, Config& conf)
+std::string handleReportActive (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
// Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES
@@ -1829,7 +1861,6 @@ void handleReportActive (TDB& tdb, T& task, Config& conf)
#endif
// Get all the tasks.
- tdb.gc ();
std::vector tasks;
tdb.pendingT (tasks);
filter (tasks, task);
@@ -1922,19 +1953,23 @@ void handleReportActive (TDB& tdb, T& task, Config& conf)
}
if (table.rowCount ())
- std::cout << optionalBlankLine (conf)
- << table.render ()
- << optionalBlankLine (conf)
- << table.rowCount ()
- << (table.rowCount () == 1 ? " task" : " tasks")
- << std::endl;
+ out << optionalBlankLine (conf)
+ << table.render ()
+ << optionalBlankLine (conf)
+ << table.rowCount ()
+ << (table.rowCount () == 1 ? " task" : " tasks")
+ << std::endl;
else
- std::cout << "No active tasks." << std::endl;
+ out << "No active tasks." << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
-void handleReportOverdue (TDB& tdb, T& task, Config& conf)
+std::string handleReportOverdue (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
// Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES
@@ -2029,21 +2064,25 @@ void handleReportOverdue (TDB& tdb, T& task, Config& conf)
}
if (table.rowCount ())
- std::cout << optionalBlankLine (conf)
- << table.render ()
- << optionalBlankLine (conf)
- << table.rowCount ()
- << (table.rowCount () == 1 ? " task" : " tasks")
- << std::endl;
+ out << optionalBlankLine (conf)
+ << table.render ()
+ << optionalBlankLine (conf)
+ << table.rowCount ()
+ << (table.rowCount () == 1 ? " task" : " tasks")
+ << std::endl;
else
- std::cout << "No overdue tasks." << std::endl;
+ out << "No overdue tasks." << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
// Successively apply filters based on the task object built from the command
// line. Tasks that match all the specified criteria are listed.
-void handleReportOldest (TDB& tdb, T& task, Config& conf)
+std::string handleReportOldest (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
// Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES
@@ -2056,7 +2095,6 @@ void handleReportOldest (TDB& tdb, T& task, Config& conf)
#endif
// Get the pending tasks.
- tdb.gc ();
std::vector tasks;
tdb.allPendingT (tasks);
handleRecurrence (tdb, tasks);
@@ -2173,22 +2211,26 @@ void handleReportOldest (TDB& tdb, T& task, Config& conf)
}
if (table.rowCount ())
- std::cout << optionalBlankLine (conf)
- << table.render ()
- << optionalBlankLine (conf)
- << table.rowCount ()
- << (table.rowCount () == 1 ? " task" : " tasks")
- << std::endl;
+ out << optionalBlankLine (conf)
+ << table.render ()
+ << optionalBlankLine (conf)
+ << table.rowCount ()
+ << (table.rowCount () == 1 ? " task" : " tasks")
+ << std::endl;
else
- std::cout << "No matches."
- << std::endl;
+ out << "No matches."
+ << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
// Successively apply filters based on the task object built from the command
// line. Tasks that match all the specified criteria are listed.
-void handleReportNewest (TDB& tdb, T& task, Config& conf)
+std::string handleReportNewest (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
// Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80);
#ifdef HAVE_LIBNCURSES
@@ -2201,7 +2243,6 @@ void handleReportNewest (TDB& tdb, T& task, Config& conf)
#endif
// Get the pending tasks.
- tdb.gc ();
std::vector tasks;
tdb.allPendingT (tasks);
handleRecurrence (tdb, tasks);
@@ -2319,21 +2360,25 @@ void handleReportNewest (TDB& tdb, T& task, Config& conf)
}
if (table.rowCount ())
- std::cout << optionalBlankLine (conf)
- << table.render ()
- << optionalBlankLine (conf)
- << table.rowCount ()
- << (table.rowCount () == 1 ? " task" : " tasks")
- << std::endl;
+ out << optionalBlankLine (conf)
+ << table.render ()
+ << optionalBlankLine (conf)
+ << table.rowCount ()
+ << (table.rowCount () == 1 ? " task" : " tasks")
+ << std::endl;
else
- std::cout << "No matches."
- << std::endl;
+ out << "No matches."
+ << std::endl;
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
-void handleReportStats (TDB& tdb, T& task, Config& conf)
+std::string handleReportStats (TDB& tdb, T& task, Config& conf)
{
+ std::stringstream out;
+
// Get all the tasks.
std::vector tasks;
tdb.allT (tasks);
@@ -2380,40 +2425,42 @@ void handleReportStats (TDB& tdb, T& task, Config& conf)
if (tags.size ()) ++taggedT;
}
- std::cout << "Pending " << pendingT << std::endl
- << "Recurring " << recurringT << std::endl
- << "Completed " << completedT << std::endl
- << "Deleted " << deletedT << std::endl
- << "Total " << totalT << std::endl;
+ out << "Pending " << pendingT << std::endl
+ << "Recurring " << recurringT << std::endl
+ << "Completed " << completedT << std::endl
+ << "Deleted " << deletedT << std::endl
+ << "Total " << totalT << std::endl;
if (tasks.size ())
{
Date e (earliest);
- std::cout << "Oldest task " << e.toString (conf.get ("dateformat", "m/d/Y")) << std::endl;
+ out << "Oldest task " << e.toString (conf.get ("dateformat", "m/d/Y")) << std::endl;
Date l (latest);
- std::cout << "Newest task " << l.toString (conf.get ("dateformat", "m/d/Y")) << std::endl;
- std::cout << "Task used for " << formatSeconds (latest - earliest) << std::endl;
+ out << "Newest task " << l.toString (conf.get ("dateformat", "m/d/Y")) << std::endl;
+ out << "Task used for " << formatSeconds (latest - earliest) << std::endl;
}
if (totalT)
- std::cout << "Task added every " << formatSeconds ((latest - earliest) / totalT) << std::endl;
+ out << "Task added every " << formatSeconds ((latest - earliest) / totalT) << std::endl;
if (completedT)
- std::cout << "Task completed every " << formatSeconds ((latest - earliest) / completedT) << std::endl;
+ out << "Task completed every " << formatSeconds ((latest - earliest) / completedT) << std::endl;
if (deletedT)
- std::cout << "Task deleted every " << formatSeconds ((latest - earliest) / deletedT) << std::endl;
+ out << "Task deleted every " << formatSeconds ((latest - earliest) / deletedT) << std::endl;
if (pendingT || completedT)
- std::cout << "Average time pending "
+ out << "Average time pending "
<< formatSeconds ((int) ((daysPending / (pendingT + completedT)) * 86400))
<< std::endl;
if (totalT)
{
- std::cout << "Average desc length " << (int) (descLength / totalT) << " characters" << std::endl;
- std::cout << "Tasks tagged " << std::setprecision (3) << (100.0 * taggedT / totalT) << "%" << std::endl;
+ out << "Average desc length " << (int) (descLength / totalT) << " characters" << std::endl;
+ out << "Tasks tagged " << std::setprecision (3) << (100.0 * taggedT / totalT) << "%" << std::endl;
}
+
+ return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/task.cpp b/src/task.cpp
index 1a54418f9..98489b952 100644
--- a/src/task.cpp
+++ b/src/task.cpp
@@ -319,18 +319,18 @@ int main (int argc, char** argv)
tdb.onChange (&onChangeCallback);
}
- runTaskCommand (argc, argv, tdb, conf);
+ std::cout << runTaskCommand (argc, argv, tdb, conf);
}
catch (std::string& error)
{
- std::cout << error << std::endl;
+ std::cerr << error << std::endl;
return -1;
}
catch (...)
{
- std::cout << "Unknown error." << std::endl;
+ std::cerr << "Unknown error." << std::endl;
return -2;
}
@@ -679,16 +679,14 @@ void onChangeCallback ()
{
if (gConf && gTdb)
{
- gConf->set ("curses", "off");
- gConf->set ("color", "off");
-
// Determine if shadow file is enabled.
std::string shadowFile = expandPath (gConf->get ("shadow.file"));
if (shadowFile != "")
{
- // Capture std::cout for the shadow file.
- std::ofstream shadow (shadowFile.c_str ());
- std::streambuf* original = std::cout.rdbuf (shadow.rdbuf ());
+ std::string oldCurses = gConf->get ("curses");
+ std::string oldColor = gConf->get ("color");
+ gConf->set ("curses", "off");
+ gConf->set ("color", "off");
// Run report. Use shadow.command, using default.command as a fallback
// with "list" as a default.
@@ -696,13 +694,26 @@ void onChangeCallback ()
gConf->get ("default.command", "list"));
std::vector args;
split (args, command, ' ');
- runTaskCommand (args, *gTdb, *gConf);
+ std::string result = runTaskCommand (args, *gTdb, *gConf);
- // Restore std::cout.
- std::cout.rdbuf (original);
+ std::ofstream out (shadowFile.c_str ());
+ if (out.good ())
+ {
+ out << result;
+ out.close ();
+ }
+ else
+ throw std::string ("Could not write file '") + shadowFile + "'";
+
+ gConf->set ("curses", oldCurses);
+ gConf->set ("color", oldColor);
}
else
- throw std::string ("Could not write to '") + shadowFile + "'.";
+ throw std::string ("No specified shadow file '") + shadowFile + "'.";
+
+ // Optionally display a notification that the shadow file was updated.
+ if (gConf->get (std::string ("shadow.notify"), false))
+ std::cout << "[Shadow file '" << shadowFile << "' updated]" << std::endl;
}
else
throw std::string ("Internal error (TDB/Config).");
@@ -720,24 +731,26 @@ void onChangeCallback ()
}
////////////////////////////////////////////////////////////////////////////////
-void runTaskCommand (
+std::string runTaskCommand (
int argc,
char** argv,
TDB& tdb,
- Config& conf)
+ Config& conf,
+ bool gc /* = true */)
{
std::vector args;
for (int i = 1; i < argc; ++i)
args.push_back (argv[i]);
- runTaskCommand (args, tdb, conf);
+ return runTaskCommand (args, tdb, conf, gc);
}
////////////////////////////////////////////////////////////////////////////////
-void runTaskCommand (
+std::string runTaskCommand (
std::vector & args,
TDB& tdb,
- Config& conf)
+ Config& conf,
+ bool gc /* = false */)
{
// If argc == 1 and the default.command configuration variable is set,
// then use that, otherwise stick with argc/argv.
@@ -754,36 +767,40 @@ void runTaskCommand (
T task;
parse (args, command, task, conf);
- if (command == "add") handleAdd (tdb, task, conf);
- else if (command == "projects") handleProjects (tdb, task, conf);
- else if (command == "tags") handleTags (tdb, task, conf);
- else if (command == "list") handleList (tdb, task, conf);
- else if (command == "info") handleInfo (tdb, task, conf);
- else if (command == "undelete") handleUndelete (tdb, task, conf);
- else if (command == "long") handleLongList (tdb, task, conf);
- else if (command == "ls") handleSmallList (tdb, task, conf);
- else if (command == "colors") handleColor ( conf);
- else if (command == "completed") handleCompleted (tdb, task, conf);
- else if (command == "delete") handleDelete (tdb, task, conf);
- else if (command == "start") handleStart (tdb, task, conf);
- else if (command == "stop") handleStop (tdb, task, conf);
- else if (command == "done") handleDone (tdb, task, conf);
- else if (command == "undo") handleUndo (tdb, task, conf);
- else if (command == "export") handleExport (tdb, task, conf);
- else if (command == "version") handleVersion ( conf);
- else if (command == "summary") handleReportSummary (tdb, task, conf);
- else if (command == "next") handleReportNext (tdb, task, conf);
- else if (command == "history") handleReportHistory (tdb, task, conf);
- else if (command == "ghistory") handleReportGHistory (tdb, task, conf);
- else if (command == "calendar") handleReportCalendar (tdb, task, conf);
- else if (command == "active") handleReportActive (tdb, task, conf);
- else if (command == "overdue") handleReportOverdue (tdb, task, conf);
- else if (command == "oldest") handleReportOldest (tdb, task, conf);
- else if (command == "newest") handleReportNewest (tdb, task, conf);
- else if (command == "stats") handleReportStats (tdb, task, conf);
- else if (command == "" && task.getId ()) handleModify (tdb, task, conf);
- else if (command == "help") longUsage (conf);
- else shortUsage (conf);
+ std::string out = "";
+
+ if (command == "" && task.getId ()) { handleModify (tdb, task, conf); }
+ else if (command == "add") { handleAdd (tdb, task, conf); }
+ else if (command == "done") { handleDone (tdb, task, conf); }
+ else if (command == "export") { handleExport (tdb, task, conf); }
+ else if (command == "projects") { out = handleProjects (tdb, task, conf); }
+ else if (command == "tags") { out = handleTags (tdb, task, conf); }
+ else if (command == "info") { out = handleInfo (tdb, task, conf); }
+ else if (command == "undelete") { out = handleUndelete (tdb, task, conf); }
+ else if (command == "delete") { out = handleDelete (tdb, task, conf); }
+ else if (command == "start") { out = handleStart (tdb, task, conf); }
+ else if (command == "stop") { out = handleStop (tdb, task, conf); }
+ else if (command == "undo") { out = handleUndo (tdb, task, conf); }
+ else if (command == "stats") { out = handleReportStats (tdb, task, conf); }
+ else if (command == "list") { if (gc) tdb.gc (); out = handleList (tdb, task, conf); }
+ else if (command == "long") { if (gc) tdb.gc (); out = handleLongList (tdb, task, conf); }
+ else if (command == "ls") { if (gc) tdb.gc (); out = handleSmallList (tdb, task, conf); }
+ else if (command == "completed") { if (gc) tdb.gc (); out = handleCompleted (tdb, task, conf); }
+ else if (command == "summary") { if (gc) tdb.gc (); out = handleReportSummary (tdb, task, conf); }
+ else if (command == "next") { if (gc) tdb.gc (); out = handleReportNext (tdb, task, conf); }
+ else if (command == "history") { if (gc) tdb.gc (); out = handleReportHistory (tdb, task, conf); }
+ else if (command == "ghistory") { if (gc) tdb.gc (); out = handleReportGHistory (tdb, task, conf); }
+ else if (command == "calendar") { if (gc) tdb.gc (); out = handleReportCalendar (tdb, task, conf); }
+ else if (command == "active") { if (gc) tdb.gc (); out = handleReportActive (tdb, task, conf); }
+ else if (command == "overdue") { if (gc) tdb.gc (); out = handleReportOverdue (tdb, task, conf); }
+ else if (command == "oldest") { if (gc) tdb.gc (); out = handleReportOldest (tdb, task, conf); }
+ else if (command == "newest") { if (gc) tdb.gc (); out = handleReportNewest (tdb, task, conf); }
+ else if (command == "colors") { out = handleColor ( conf); }
+ else if (command == "version") { out = handleVersion ( conf); }
+ else if (command == "help") { longUsage ( conf); }
+ else { shortUsage ( conf); }
+
+ return out;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/task.h b/src/task.h
index 1f550bd34..b74aa1e6a 100644
--- a/src/task.h
+++ b/src/task.h
@@ -67,41 +67,41 @@ bool generateDueDates (T&, std::vector &);
Date getNextRecurrence (Date&, std::string&);
void updateRecurrenceMask (TDB&, std::vector &, T&);
void onChangeCallback ();
-void runTaskCommand (int, char**, TDB&, Config&);
-void runTaskCommand (std::vector &, TDB&, Config&);
+std::string runTaskCommand (int, char**, TDB&, Config&, bool gc = true);
+std::string runTaskCommand (std::vector &, TDB&, Config&, bool gc = false);
// command.cpp
void handleAdd (TDB&, T&, Config&);
-void handleProjects (TDB&, T&, Config&);
-void handleTags (TDB&, T&, Config&);
-void handleUndelete (TDB&, T&, Config&);
-void handleVersion (Config&);
void handleExport (TDB&, T&, Config&);
-void handleDelete (TDB&, T&, Config&);
-void handleStart (TDB&, T&, Config&);
-void handleStop (TDB&, T&, Config&);
void handleDone (TDB&, T&, Config&);
-void handleUndo (TDB&, T&, Config&);
void handleModify (TDB&, T&, Config&);
-void handleColor (Config&);
+std::string handleProjects (TDB&, T&, Config&);
+std::string handleTags (TDB&, T&, Config&);
+std::string handleUndelete (TDB&, T&, Config&);
+std::string handleVersion (Config&);
+std::string handleDelete (TDB&, T&, Config&);
+std::string handleStart (TDB&, T&, Config&);
+std::string handleStop (TDB&, T&, Config&);
+std::string handleUndo (TDB&, T&, Config&);
+std::string handleColor (Config&);
// report.cpp
void filter (std::vector&, T&);
-void handleList (TDB&, T&, Config&);
-void handleInfo (TDB&, T&, Config&);
-void handleLongList (TDB&, T&, Config&);
-void handleSmallList (TDB&, T&, Config&);
-void handleCompleted (TDB&, T&, Config&);
-void handleReportSummary (TDB&, T&, Config&);
-void handleReportNext (TDB&, T&, Config&);
-void handleReportHistory (TDB&, T&, Config&);
-void handleReportGHistory (TDB&, T&, Config&);
-void handleReportCalendar (TDB&, T&, Config&);
-void handleReportActive (TDB&, T&, Config&);
-void handleReportOverdue (TDB&, T&, Config&);
-void handleReportStats (TDB&, T&, Config&);
-void handleReportOldest (TDB&, T&, Config&);
-void handleReportNewest (TDB&, T&, Config&);
+std::string handleList (TDB&, T&, Config&);
+std::string handleInfo (TDB&, T&, Config&);
+std::string handleLongList (TDB&, T&, Config&);
+std::string handleSmallList (TDB&, T&, Config&);
+std::string handleCompleted (TDB&, T&, Config&);
+std::string handleReportSummary (TDB&, T&, Config&);
+std::string handleReportNext (TDB&, T&, Config&);
+std::string handleReportHistory (TDB&, T&, Config&);
+std::string handleReportGHistory (TDB&, T&, Config&);
+std::string handleReportCalendar (TDB&, T&, Config&);
+std::string handleReportActive (TDB&, T&, Config&);
+std::string handleReportOverdue (TDB&, T&, Config&);
+std::string handleReportStats (TDB&, T&, Config&);
+std::string handleReportOldest (TDB&, T&, Config&);
+std::string handleReportNewest (TDB&, T&, Config&);
// util.cpp
bool confirm (const std::string&);
diff --git a/src/tests/out b/src/tests/out
deleted file mode 100755
index c0b81f3b4..000000000
--- a/src/tests/out
+++ /dev/null
@@ -1,15 +0,0 @@
-./task li due:monday
-./task li due:tuesday
-./task li due:wednesday
-./task li due:thursday
-./task li due:friday
-./task li due:saturday
-./task li due:sunday
-./task li due:yesterday
-./task li due:today
-./task li due:tomorrow
-./task li due:eow
-./task li due:eom
-./task li due:eoy
-./task li due:21st
-