diff --git a/src/command.cpp b/src/command.cpp index 769fa4af1..16740bf59 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -48,8 +48,10 @@ #endif //////////////////////////////////////////////////////////////////////////////// -void handleAdd (TDB& tdb, T& task, Config& conf) +std::string handleAdd (TDB& tdb, T& task, Config& conf) { + std::stringstream out; + char entryTime[16]; sprintf (entryTime, "%u", (unsigned int) time (NULL)); task.setAttribute ("entry", entryTime); @@ -86,6 +88,8 @@ void handleAdd (TDB& tdb, T& task, Config& conf) if (!tdb.addT (task)) throw std::string ("Could not create new task."); + + return out.str (); } //////////////////////////////////////////////////////////////////////////////// @@ -547,8 +551,10 @@ std::string handleStop (TDB& tdb, T& task, Config& conf) } //////////////////////////////////////////////////////////////////////////////// -void handleDone (TDB& tdb, T& task, Config& conf) +std::string handleDone (TDB& tdb, T& task, Config& conf) { + std::stringstream out; + if (!tdb.completeT (task)) throw std::string ("Could not mark task as completed."); @@ -566,11 +572,14 @@ void handleDone (TDB& tdb, T& task, Config& conf) } nag (tdb, task, conf); + return out.str (); } //////////////////////////////////////////////////////////////////////////////// -void handleExport (TDB& tdb, T& task, Config& conf) +std::string handleExport (TDB& tdb, T& task, Config& conf) { + std::stringstream out; + // Use the description as a file name, then clobber the description so the // file name isn't used for filtering. std::string file = trim (task.getDescription ()); @@ -610,11 +619,14 @@ void handleExport (TDB& tdb, T& task, Config& conf) } else throw std::string ("You must specify a file to write to."); + + return out.str (); } //////////////////////////////////////////////////////////////////////////////// -void handleModify (TDB& tdb, T& task, Config& conf) +std::string handleModify (TDB& tdb, T& task, Config& conf) { + std::stringstream out; std::vector all; tdb.pendingT (all); @@ -695,11 +707,12 @@ void handleModify (TDB& tdb, T& task, Config& conf) tdb.modifyT (original); } - return; + return out.str (); } } throw std::string ("Task not found."); + return out.str (); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/task.cpp b/src/task.cpp index 132879e4c..d31952f02 100644 --- a/src/task.cpp +++ b/src/task.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -47,8 +48,9 @@ #endif //////////////////////////////////////////////////////////////////////////////// -static void shortUsage (Config& conf) +static std::string shortUsage (Config& conf) { + std::stringstream out; Table table; int width = conf.get ("defaultwidth", 80); #ifdef HAVE_LIBNCURSES @@ -192,48 +194,51 @@ static void shortUsage (Config& conf) table.addCell (row, 2, description); } - std::cout << table.render () - << std::endl - << "See http://www.beckingham.net/task.html for the latest releases and a " - << "full tutorial. New releases containing fixes and enhancements are " - << "made frequently." - << std::endl - << std::endl; + out << table.render () + << std::endl + << "See http://www.beckingham.net/task.html for the latest releases and a " + << "full tutorial. New releases containing fixes and enhancements are " + << "made frequently." + << std::endl + << std::endl; + + return out.str (); } //////////////////////////////////////////////////////////////////////////////// -static void longUsage (Config& conf) +static std::string longUsage (Config& conf) { - shortUsage (conf); + std::stringstream out; + out << shortUsage (conf) + << "ID is the numeric identifier displayed by the 'task list' command." << "\n" + << "\n" + << "Tags are arbitrary words, any quantity:" << "\n" + << " +tag The + means add the tag" << "\n" + << " -tag The - means remove the tag" << "\n" + << "\n" + << "Attributes are:" << "\n" + << " project: Project name" << "\n" + << " priority: Priority" << "\n" + << " due: Due date" << "\n" + << " recur: Recurrence frequency" << "\n" + << " until: Recurrence end date" << "\n" + << " fg: Foreground color" << "\n" + << " bg: Background color" << "\n" + << " rc: Alternate .taskrc file" << "\n" + << "\n" + << "Any command or attribute name may be abbreviated if still unique:" << "\n" + << " task list project:Home" << "\n" + << " task li pro:Home" << "\n" + << "\n" + << "Some task descriptions need to be escaped because of the shell:" << "\n" + << " task add \"quoted ' quote\"" << "\n" + << " task add escaped \\' quote" << "\n" + << "\n" + << "Many characters have special meaning to the shell, including:" << "\n" + << " $ ! ' \" ( ) ; \\ ` * ? { } [ ] < > | & % # ~" << "\n" + << std::endl; - std::cout - << "ID is the numeric identifier displayed by the 'task list' command." << "\n" - << "\n" - << "Tags are arbitrary words, any quantity:" << "\n" - << " +tag The + means add the tag" << "\n" - << " -tag The - means remove the tag" << "\n" - << "\n" - << "Attributes are:" << "\n" - << " project: Project name" << "\n" - << " priority: Priority" << "\n" - << " due: Due date" << "\n" - << " recur: Recurrence frequency" << "\n" - << " until: Recurrence end date" << "\n" - << " fg: Foreground color" << "\n" - << " bg: Background color" << "\n" - << " rc: Alternate .taskrc file" << "\n" - << "\n" - << "Any command or attribute name may be abbreviated if still unique:" << "\n" - << " task list project:Home" << "\n" - << " task li pro:Home" << "\n" - << "\n" - << "Some task descriptions need to be escaped because of the shell:" << "\n" - << " task add \"quoted ' quote\"" << "\n" - << " task add escaped \\' quote" << "\n" - << "\n" - << "Many characters have special meaning to the shell, including:" << "\n" - << " $ ! ' \" ( ) ; \\ ` * ? { } [ ] < > | & % # ~" << "\n" - << std::endl; + return out.str (); } //////////////////////////////////////////////////////////////////////////////// @@ -790,34 +795,49 @@ std::string runTaskCommand ( T task; parse (args, command, task, conf); - std::string out = ""; + bool gcMod = false; // Change occurred by way of gc. + bool cmdMod = false; // Change occurred by way of command type. + std::string out; - if (command == "" && task.getId ()) { handleModify (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } - else if (command == "add") { handleAdd (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } - else if (command == "done") { handleDone (tdb, task, conf ); if (shadow) updateShadowFile (tdb, 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 ); if (shadow) updateShadowFile (tdb, conf); } - else if (command == "delete") { out = handleDelete (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } - else if (command == "start") { out = handleStart (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } - else if (command == "stop") { out = handleStop (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } - else if (command == "undo") { out = handleUndo (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } - else if (command == "stats") { out = handleReportStats (tdb, task, conf ); } - else if (command == "completed") { if (gc) tdb.gc (); out = handleCompleted (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } // TODO replace with Custom - else if (command == "summary") { if (gc) tdb.gc (); out = handleReportSummary (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } - else if (command == "next") { if (gc) tdb.gc (); out = handleReportNext (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } // TODO replace with Custom - else if (command == "history") { if (gc) tdb.gc (); out = handleReportHistory (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } - else if (command == "ghistory") { if (gc) tdb.gc (); out = handleReportGHistory (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } - else if (command == "calendar") { if (gc) tdb.gc (); out = handleReportCalendar (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } - else if (command == "active") { if (gc) tdb.gc (); out = handleReportActive (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } // TODO replace with Custom - else if (command == "overdue") { if (gc) tdb.gc (); out = handleReportOverdue (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } // TODO replace with Custom - else if (command == "colors") { out = handleColor ( conf ); } - else if (command == "version") { out = handleVersion ( conf ); } - else if (command == "help") { longUsage ( conf ); } - else if (isCustomReport (command)) { if (gc) tdb.gc (); out = handleCustomReport (tdb, task, conf, command); if (shadow) updateShadowFile (tdb, conf); } // New Custom reports - else { shortUsage ( conf ); } + // Read-only commands with no side effects. + if (command == "export") { out = 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 == "stats") { out = handleReportStats (tdb, task, conf); } + else if (command == "history") { out = handleReportHistory (tdb, task, conf); } + else if (command == "ghistory") { out = handleReportGHistory (tdb, task, conf); } + else if (command == "calendar") { out = handleReportCalendar (tdb, task, conf); } + else if (command == "summary") { out = handleReportSummary (tdb, task, conf); } + else if (command == "colors") { out = handleColor ( conf); } + else if (command == "version") { out = handleVersion ( conf); } + else if (command == "help") { out = longUsage ( conf); } + + // Commands that cause updates. + else if (command == "" && task.getId ()) { cmdMod = true; out = handleModify (tdb, task, conf); } + else if (command == "add") { cmdMod = true; out = handleAdd (tdb, task, conf); } + else if (command == "done") { cmdMod = true; out = handleDone (tdb, task, conf); } + else if (command == "undelete") { cmdMod = true; out = handleUndelete (tdb, task, conf); } + else if (command == "delete") { cmdMod = true; out = handleDelete (tdb, task, conf); } + else if (command == "start") { cmdMod = true; out = handleStart (tdb, task, conf); } + else if (command == "stop") { cmdMod = true; out = handleStop (tdb, task, conf); } + else if (command == "undo") { cmdMod = true; out = handleUndo (tdb, task, conf); } + + // Command that display IDs and therefore need TDB::gc first. + + else if (command == "completed") { if (gc) gcMod = tdb.gc (); out = handleCompleted (tdb, task, conf); } + else if (command == "next") { if (gc) gcMod = tdb.gc (); out = handleReportNext (tdb, task, conf); } + else if (command == "active") { if (gc) gcMod = tdb.gc (); out = handleReportActive (tdb, task, conf); } + else if (command == "overdue") { if (gc) gcMod = tdb.gc (); out = handleReportOverdue (tdb, task, conf); } + else if (isCustomReport (command)) { if (gc) gcMod = tdb.gc (); out = handleCustomReport (tdb, task, conf, command); } + + // If the command is not recognized, display usage. + else { out = shortUsage (conf); } + + // Only update the shadow file if such an update was not suppressed (shadow), + // and if an actual change occurred (gcMod || cmdMod). + if (shadow && (gcMod || cmdMod)) + updateShadowFile (tdb, conf); return out; } diff --git a/src/task.h b/src/task.h index 05b710497..5ddd81f6f 100644 --- a/src/task.h +++ b/src/task.h @@ -74,10 +74,10 @@ std::string runTaskCommand (int, char**, TDB&, Config&, bool gc = true, bool sha std::string runTaskCommand (std::vector &, TDB&, Config&, bool gc = false, bool shadow = false); // command.cpp -void handleAdd (TDB&, T&, Config&); -void handleExport (TDB&, T&, Config&); -void handleDone (TDB&, T&, Config&); -void handleModify (TDB&, T&, Config&); +std::string handleAdd (TDB&, T&, Config&); +std::string handleExport (TDB&, T&, Config&); +std::string handleDone (TDB&, T&, Config&); +std::string handleModify (TDB&, T&, Config&); std::string handleProjects (TDB&, T&, Config&); std::string handleTags (TDB&, T&, Config&); std::string handleUndelete (TDB&, T&, Config&);