diff --git a/ChangeLog b/ChangeLog index 0058c17f1..c527d5f58 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,8 @@ due dates, which are no longer relevant to a completed task (thanks to Cory Donnelly). + Fixed bug that was causing the 'completed' report to sort incorrectly. + + Added feature #336 which gives task a 'prepend' command for symmetry + with the 'append' command. ------ old releases ------------------------------ diff --git a/doc/man/task.1 b/doc/man/task.1 index 838e6571f..b109a0c0b 100644 --- a/doc/man/task.1 +++ b/doc/man/task.1 @@ -19,8 +19,11 @@ Adds a new task to the task list. .TP .B append [tags] [attrs] description -Appends more information to an existing -task. +Appends information to an existing task. + +.TP +.B prepend [tags] [attrs] description +Prepends information to an existing task. .TP .B annotate ID description diff --git a/i18n/strings.en-US b/i18n/strings.en-US index 78a9e78f9..a27f83e27 100644 --- a/i18n/strings.en-US +++ b/i18n/strings.en-US @@ -46,7 +46,7 @@ 214 ghistory 215 import 216 info - +217 prepend 218 overdue 219 projects 220 start diff --git a/src/Cmd.cpp b/src/Cmd.cpp index 457f11f04..fab2d0b83 100644 --- a/src/Cmd.cpp +++ b/src/Cmd.cpp @@ -125,6 +125,7 @@ void Cmd::load () commands.push_back (context.stringtable.get (CMD_GHISTORY, "ghistory")); commands.push_back (context.stringtable.get (CMD_IMPORT, "import")); commands.push_back (context.stringtable.get (CMD_INFO, "info")); + commands.push_back (context.stringtable.get (CMD_PREPEND, "prepend")); commands.push_back (context.stringtable.get (CMD_PROJECTS, "projects")); #ifdef FEATURE_SHELL commands.push_back (context.stringtable.get (CMD_SHELL, "shell")); @@ -223,6 +224,7 @@ bool Cmd::isWriteCommand () command == context.stringtable.get (CMD_DUPLICATE, "duplicate") || command == context.stringtable.get (CMD_EDIT, "edit") || command == context.stringtable.get (CMD_IMPORT, "import") || + command == context.stringtable.get (CMD_PREPEND, "prepend") || command == context.stringtable.get (CMD_START, "start") || command == context.stringtable.get (CMD_STOP, "stop") || command == context.stringtable.get (CMD_UNDO, "undo")) diff --git a/src/Context.cpp b/src/Context.cpp index bae490707..734af52b4 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -199,6 +199,7 @@ int Context::dispatch (std::string &out) else if (cmd.command == "timesheet") { rc = handleReportTimesheet (out); } else if (cmd.command == "add") { rc = handleAdd (out); } else if (cmd.command == "append") { rc = handleAppend (out); } + else if (cmd.command == "prepend") { rc = handlePrepend (out); } else if (cmd.command == "annotate") { rc = handleAnnotate (out); } else if (cmd.command == "done") { rc = handleDone (out); } else if (cmd.command == "delete") { rc = handleDelete (out); } diff --git a/src/command.cpp b/src/command.cpp index fe90eded2..9830fd87d 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -1100,6 +1100,74 @@ int handleAppend (std::string &outs) return 0; } +//////////////////////////////////////////////////////////////////////////////// +int handlePrepend (std::string &outs) +{ + int count = 0; + std::stringstream out; + + std::vector tasks; + context.tdb.lock (context.config.get ("locking", true)); + Filter filter; + context.tdb.loadPending (tasks, filter); + + // Filter sequence. + std::vector all = tasks; + context.filter.applySequence (tasks, context.sequence); + + Permission permission; + if (context.sequence.size () > (size_t) context.config.get ("bulk", 2)) + permission.bigSequence (); + + foreach (task, tasks) + { + foreach (other, all) + { + if (other->id == task->id || // Self + (task->has ("parent") && + task->get ("parent") == other->get ("parent")) || // Sibling + other->get ("uuid") == task->get ("parent")) // Parent + { + Task before (*other); + + // A non-zero value forces a file write. + int changes = 0; + + // Apply other deltas. + changes += deltaPrepend (*other); + changes += deltaTags (*other); + changes += deltaAttributes (*other); + + if (taskDiff (before, *other)) + { + if (changes && permission.confirmed (before, taskDifferences (before, *other) + "Are you sure?")) + { + context.tdb.update (*other); + + if (context.config.get ("echo.command", true)) + out << "Prepended '" + << context.task.get ("description") + << "' to task " + << other->id + << std::endl; + + ++count; + } + } + } + } + } + + context.tdb.commit (); + context.tdb.unlock (); + + if (context.config.get ("echo.command", true)) + out << "Appended " << count << " task" << (count == 1 ? "" : "s") << std::endl; + + outs = out.str (); + return 0; +} + //////////////////////////////////////////////////////////////////////////////// int handleDuplicate (std::string &outs) { @@ -1410,6 +1478,19 @@ int deltaAppend (Task& task) return 0; } +//////////////////////////////////////////////////////////////////////////////// +int deltaPrepend (Task& task) +{ + if (context.task.has ("description")) + { + task.set ("description", + context.task.get ("description") + " " + task.get ("description")); + return 1; + } + + return 0; +} + //////////////////////////////////////////////////////////////////////////////// int deltaDescription (Task& task) { diff --git a/src/i18n.h b/src/i18n.h index e06698a1c..129b47224 100644 --- a/src/i18n.h +++ b/src/i18n.h @@ -83,7 +83,7 @@ #define CMD_GHISTORY 214 #define CMD_IMPORT 215 #define CMD_INFO 216 - +#define CMD_PREPEND 217 #define CMD_OVERDUE 218 #define CMD_PROJECTS 219 #define CMD_START 220 diff --git a/src/main.h b/src/main.h index c775f2930..1d973f3d7 100644 --- a/src/main.h +++ b/src/main.h @@ -57,6 +57,7 @@ bool nag (Task&); // command.cpp int handleAdd (std::string &); int handleAppend (std::string &); +int handlePrepend (std::string &); int handleExport (std::string &); int handleDone (std::string &); int handleModify (std::string &); @@ -79,6 +80,7 @@ void handleUndo (); void handleShell (); #endif int deltaAppend (Task&); +int deltaPrepend (Task&); int deltaDescription (Task&); int deltaTags (Task&); int deltaAttributes (Task&); diff --git a/src/report.cpp b/src/report.cpp index c6ae2ea0b..f0df5b16d 100644 --- a/src/report.cpp +++ b/src/report.cpp @@ -80,6 +80,10 @@ int shortUsage (std::string &outs) table.addCell (row, 1, "task append [tags] [attrs] desc..."); table.addCell (row, 2, "Appends more description to an existing task."); + row = table.addRow (); + table.addCell (row, 1, "task prepend [tags] [attrs] desc..."); + table.addCell (row, 2, "Prepends more description to an existing task."); + row = table.addRow (); table.addCell (row, 1, "task annotate ID desc..."); table.addCell (row, 2, "Adds an annotation to an existing task."); diff --git a/src/tests/prepend.t b/src/tests/prepend.t new file mode 100755 index 000000000..7808680dd --- /dev/null +++ b/src/tests/prepend.t @@ -0,0 +1,58 @@ +#! /usr/bin/perl +################################################################################ +## task - a command line task list manager. +## +## Copyright 2006 - 2009, Paul Beckingham. +## All rights reserved. +## +## This program is free software; you can redistribute it and/or modify it under +## the terms of the GNU General Public License as published by the Free Software +## Foundation; either version 2 of the License, or (at your option) any later +## version. +## +## This program is distributed in the hope that it will be useful, but WITHOUT +## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +## details. +## +## You should have received a copy of the GNU General Public License along with +## this program; if not, write to the +## +## Free Software Foundation, Inc., +## 51 Franklin Street, Fifth Floor, +## Boston, MA +## 02110-1301 +## USA +## +################################################################################ + +use strict; +use warnings; +use Test::More tests => 5; + +# Create the rc file. +if (open my $fh, '>', 'prepend.rc') +{ + print $fh "data.location=.\n"; + close $fh; + ok (-r 'prepend.rc', 'Created prepend.rc'); +} + +# Add a task, then prepend more decsription. +qx{../task rc:prepend.rc add bar}; +qx{../task rc:prepend.rc 1 prepend foo}; +my $output = qx{../task rc:prepend.rc info 1}; +like ($output, qr/Description\s+foo\sbar\n/, 'prepend worked'); + +# Cleanup. +unlink 'pending.data'; +ok (!-r 'pending.data', 'Removed pending.data'); + +unlink 'undo.data'; +ok (!-r 'undo.data', 'Removed undo.data'); + +unlink 'prepend.rc'; +ok (!-r 'prepend.rc', 'Removed prepend.rc'); + +exit 0; +