diff --git a/ChangeLog b/ChangeLog
index 3bbf572d8..3342bfba3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,7 +7,9 @@ represents a feature release, and the Z represents a patch.
------ current release ---------------------------
-1.5.0 (?/?/?)
+1.5.0 (?/?/2008)
+ + "task undo" can now retract a "task done" command, provided no reports
+ have been run (and therefore TDB::gc run)
------ old releases ------------------------------
diff --git a/html/task.html b/html/task.html
index 84f28544e..b536566dd 100644
--- a/html/task.html
+++ b/html/task.html
@@ -94,7 +94,8 @@
New in version 1.5.0 (?/?/?)
- -
+
- "task undo" can now retract a "task done" command, provided no
+ reports have been run.
diff --git a/src/command.cpp b/src/command.cpp
index 5344a4037..91a3053f2 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -203,6 +203,49 @@ void handleUndelete (TDB& tdb, T& task, Config& conf)
<< "command is run immediately after the errant delete command." << std::endl;
}
+////////////////////////////////////////////////////////////////////////////////
+// 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::vector all;
+ tdb.allPendingT (all);
+
+ int id = task.getId ();
+ std::vector ::iterator it;
+ for (it = all.begin (); it != all.end (); ++it)
+ {
+ if (it->getId () == id)
+ {
+ if (it->getStatus () == T::completed)
+ {
+ if (it->getAttribute ("recur") != "")
+ {
+ std::cout << "Task does not support 'undo' for recurring tasks." << std::endl;
+ return;
+ }
+
+ T restored (*it);
+ restored.setStatus (T::pending);
+ restored.removeAttribute ("end");
+ tdb.modifyT (restored);
+
+ std::cout << "Task " << id << " successfully undone." << std::endl;
+ return;
+ }
+ else
+ {
+ std::cout << "Task " << id << " is not done - therefore cannot be undone." << std::endl;
+ return;
+ }
+ }
+ }
+
+ 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;
+}
+
////////////////////////////////////////////////////////////////////////////////
void handleVersion (Config& conf)
{
diff --git a/src/parse.cpp b/src/parse.cpp
index 770c2b2f0..a8bba1e57 100644
--- a/src/parse.cpp
+++ b/src/parse.cpp
@@ -141,6 +141,7 @@ static const char* commands[] =
"summary",
"tags",
"undelete",
+ "undo",
"usage",
"version",
"",
diff --git a/src/task.cpp b/src/task.cpp
index 0d3f6c7f5..cc192e18e 100644
--- a/src/task.cpp
+++ b/src/task.cpp
@@ -125,6 +125,10 @@ static void shortUsage (Config& conf)
table.addCell (row, 1, "task done ID");
table.addCell (row, 2, "Marks the specified task as completed");
+ row = table.addRow ();
+ table.addCell (row, 1, "task undo ID");
+ table.addCell (row, 2, "Marks the specified done task as pending, provided a report has not yet been run");
+
row = table.addRow ();
table.addCell (row, 1, "task projects");
table.addCell (row, 2, "Shows a list of all project names used, and how many tasks are in each");
@@ -316,6 +320,7 @@ int main (int argc, char** argv)
else if (command == "delete") handleDelete (tdb, task, conf);
else if (command == "start") handleStart (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);
diff --git a/src/task.h b/src/task.h
index 4a8dc78fd..ced6b3c18 100644
--- a/src/task.h
+++ b/src/task.h
@@ -76,6 +76,7 @@ void handleExport (TDB&, T&, Config&);
void handleDelete (TDB&, T&, Config&);
void handleStart (TDB&, T&, Config&);
void handleDone (TDB&, T&, Config&);
+void handleUndo (TDB&, T&, Config&);
void handleModify (TDB&, T&, Config&);
void handleColor (Config&);