mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
Enhancement - wait status
- Supports the new Task::waiting status. - Supports: task <id> wait:<date> - Supports: task <id> wait: - Supports: task waiting
This commit is contained in:
parent
40bde9e765
commit
329a78039a
12 changed files with 131 additions and 16 deletions
14
src/Att.cpp
14
src/Att.cpp
|
@ -62,6 +62,7 @@ static const char* modifiableNames[] =
|
|||
"due",
|
||||
"recur",
|
||||
"until",
|
||||
"wait",
|
||||
};
|
||||
|
||||
// Synonyms on the same line.
|
||||
|
@ -324,8 +325,9 @@ bool Att::validNameValue (
|
|||
Text::guessColor (value);
|
||||
}
|
||||
|
||||
else if (name == "due" ||
|
||||
name == "until")
|
||||
else if (name == "due" ||
|
||||
name == "until" ||
|
||||
name == "wait")
|
||||
{
|
||||
// Validate and convert to epoch.
|
||||
if (value != "")
|
||||
|
@ -356,6 +358,7 @@ bool Att::validNameValue (
|
|||
candidates.push_back ("completed");
|
||||
candidates.push_back ("deleted");
|
||||
candidates.push_back ("recurring");
|
||||
candidates.push_back ("waiting");
|
||||
autoComplete (value, candidates, matches);
|
||||
|
||||
if (matches.size () == 1)
|
||||
|
@ -363,7 +366,7 @@ bool Att::validNameValue (
|
|||
else
|
||||
throw std::string ("\"") +
|
||||
value +
|
||||
"\" is not a valid status. Use 'pending', 'completed', 'deleted' or 'recurring'.";
|
||||
"\" is not a valid status. Use 'pending', 'completed', 'deleted', 'recurring' or 'waiting'.";
|
||||
}
|
||||
|
||||
else if (! validInternalName (name) &&
|
||||
|
@ -388,11 +391,12 @@ bool Att::validMod (const std::string& mod)
|
|||
// The type of an attribute is useful for modifier evaluation.
|
||||
std::string Att::type (const std::string& name) const
|
||||
{
|
||||
if (name == "due" ||
|
||||
if (name == "due" ||
|
||||
name == "until" ||
|
||||
name == "start" ||
|
||||
name == "entry" ||
|
||||
name == "end")
|
||||
name == "end" ||
|
||||
name == "wait")
|
||||
return "date";
|
||||
|
||||
else if (name == "recur")
|
||||
|
|
|
@ -218,6 +218,12 @@ void Config::createDefault (const std::string& home)
|
|||
fprintf (out, "report.recurring.sort=due+,priority-,project+\n"); // TODO i18n
|
||||
fprintf (out, "report.recurring.filter=status:pending parent.any:\n"); // TODO i18n
|
||||
|
||||
fprintf (out, "report.waiting.description=Lists all waiting tasks matching the specified criteria\n"); // TODO i18n
|
||||
fprintf (out, "report.waiting.columns=id,project,priority,wait,age,description\n"); // TODO i18n
|
||||
fprintf (out, "report.waiting.labels=ID,Project,Pri,Wait,Age,Description\n"); // TODO i18n
|
||||
fprintf (out, "report.waiting.sort=wait+,priority-,project+\n"); // TODO i18n
|
||||
fprintf (out, "report.waiting.filter=status:waiting\n"); // TODO i18n
|
||||
|
||||
fclose (out);
|
||||
|
||||
std::cout << "Done." << std::endl; // TODO i18n
|
||||
|
@ -290,6 +296,12 @@ void Config::setDefaults ()
|
|||
set ("report.recurring.labels", "ID,Project,Pri,Due,Recur,Active,Age,Description"); // TODO i18n
|
||||
set ("report.recurring.sort", "due+,priority-,project+"); // TODO i18n
|
||||
set ("report.recurring.filter", "status:pending parent.any:"); // TODO i18n
|
||||
|
||||
set ("report.waiting.description", "Lists all waiting tasks matching the specified criteria"); // TODO i18n
|
||||
set ("report.waiting.columns", "id,project,priority,wait,age,description"); // TODO i18n
|
||||
set ("report.waiting.labels", "ID,Project,Pri,Wait,Age,Description"); // TODO i18n
|
||||
set ("report.waiting.sort", "wait+,priority-,project+"); // TODO i18n
|
||||
set ("report.waiting.filter", "status:waiting"); // TODO i18n
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
14
src/TDB.cpp
14
src/TDB.cpp
|
@ -168,7 +168,9 @@ int TDB::load (std::vector <Task>& tasks, Filter& filter)
|
|||
{
|
||||
++numberStatusClauses;
|
||||
|
||||
if (att->mod () == "" && att->value () == "pending")
|
||||
if (att->mod () == "" &&
|
||||
(att->value () == "pending" ||
|
||||
att->value () == "waiting"))
|
||||
++numberSimpleStatusClauses;
|
||||
}
|
||||
}
|
||||
|
@ -391,6 +393,7 @@ void TDB::upgrade ()
|
|||
int TDB::gc ()
|
||||
{
|
||||
int count = 0;
|
||||
Date now;
|
||||
|
||||
// Set up a second TDB.
|
||||
Filter filter;
|
||||
|
@ -417,6 +420,15 @@ int TDB::gc ()
|
|||
completed.push_back (*task);
|
||||
++count;
|
||||
}
|
||||
else if (s == Task::waiting)
|
||||
{
|
||||
// Wake up tasks that are waiting.
|
||||
Date wait_date (::atoi (task->get ("wait").c_str ()));
|
||||
if (now > wait_date)
|
||||
task->setStatus (Task::pending);
|
||||
|
||||
still_pending.push_back (*task);
|
||||
}
|
||||
else
|
||||
still_pending.push_back (*task);
|
||||
}
|
||||
|
|
14
src/Task.cpp
14
src/Task.cpp
|
@ -93,6 +93,7 @@ Task::status Task::textToStatus (const std::string& input)
|
|||
else if (input == "completed") return Task::completed; // TODO i18n
|
||||
else if (input == "deleted") return Task::deleted; // TODO i18n
|
||||
else if (input == "recurring") return Task::recurring; // TODO i18n
|
||||
else if (input == "waiting") return Task::waiting; // TODO i18n
|
||||
|
||||
return Task::pending;
|
||||
}
|
||||
|
@ -104,6 +105,7 @@ std::string Task::statusToText (Task::status s)
|
|||
else if (s == Task::completed) return "completed"; // TODO i18n
|
||||
else if (s == Task::deleted) return "deleted"; // TODO i18n
|
||||
else if (s == Task::recurring) return "recurring"; // TODO i18n
|
||||
else if (s == Task::waiting) return "waiting"; // TODO i18n
|
||||
|
||||
return "pending";
|
||||
}
|
||||
|
@ -169,9 +171,9 @@ void Task::legacyParse (const std::string& line)
|
|||
set ("uuid", line.substr (0, 36));
|
||||
|
||||
Task::status status = line[37] == '+' ? completed
|
||||
: line[37] == 'X' ? deleted
|
||||
: line[37] == 'r' ? recurring
|
||||
: pending;
|
||||
: line[37] == 'X' ? deleted
|
||||
: line[37] == 'r' ? recurring
|
||||
: pending;
|
||||
|
||||
set ("status", statusToText (status)); // No i18n
|
||||
|
||||
|
@ -226,9 +228,9 @@ void Task::legacyParse (const std::string& line)
|
|||
set ("uuid", line.substr (0, 36));
|
||||
|
||||
Task::status status = line[37] == '+' ? completed
|
||||
: line[37] == 'X' ? deleted
|
||||
: line[37] == 'r' ? recurring
|
||||
: pending;
|
||||
: line[37] == 'X' ? deleted
|
||||
: line[37] == 'r' ? recurring
|
||||
: pending;
|
||||
|
||||
set ("status", statusToText (status)); // No i18n
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ public:
|
|||
std::string composeCSV () const;
|
||||
|
||||
// Status values.
|
||||
enum status {pending, completed, deleted, recurring /* , retired, deferred */};
|
||||
enum status {pending, completed, deleted, recurring, waiting};
|
||||
|
||||
// Public data.
|
||||
int id;
|
||||
|
|
|
@ -60,6 +60,8 @@ std::string handleAdd ()
|
|||
context.task.setStatus (Task::recurring);
|
||||
context.task.set ("mask", "");
|
||||
}
|
||||
else if (context.task.has ("wait"))
|
||||
context.task.setStatus (Task::waiting);
|
||||
else
|
||||
context.task.setStatus (Task::pending);
|
||||
|
||||
|
@ -1216,6 +1218,15 @@ int deltaAttributes (Task& task)
|
|||
att->first != "description" &&
|
||||
att->first != "tags")
|
||||
{
|
||||
// Modifying "wait" changes status.
|
||||
if (att->first == "wait")
|
||||
{
|
||||
if (att->second.value () == "")
|
||||
task.setStatus (Task::pending);
|
||||
else
|
||||
task.setStatus (Task::waiting);
|
||||
}
|
||||
|
||||
if (att->second.value () == "")
|
||||
task.remove (att->first);
|
||||
else
|
||||
|
|
|
@ -368,6 +368,26 @@ std::string handleCustomReport (const std::string& report)
|
|||
table.addCell (row, columnCount, "+");
|
||||
}
|
||||
|
||||
else if (*col == "wait")
|
||||
{
|
||||
table.addColumn (columnLabels[*col] != "" ? columnLabels[*col] : "Wait");
|
||||
table.setColumnWidth (columnCount, Table::minimum);
|
||||
table.setColumnJustification (columnCount, Table::right);
|
||||
|
||||
int row = 0;
|
||||
std::string wait;
|
||||
foreach (task, tasks)
|
||||
{
|
||||
wait = task->get ("wait");
|
||||
if (wait != "")
|
||||
{
|
||||
Date dt (::atoi (wait.c_str ()));
|
||||
wait = dt.toString (context.config.get ("dateformat", "m/d/Y"));
|
||||
table.addCell (row++, columnCount, wait);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Common to all columns.
|
||||
// Add underline.
|
||||
if ((context.config.get (std::string ("color"), true) || context.config.get (std::string ("_forcecolor"), false)) &&
|
||||
|
@ -403,7 +423,8 @@ std::string handleCustomReport (const std::string& report)
|
|||
Table::ascendingPriority :
|
||||
Table::descendingPriority));
|
||||
|
||||
else if (column == "entry" || column == "start" || column == "due")
|
||||
else if (column == "entry" || column == "start" || column == "due" ||
|
||||
column == "wait")
|
||||
table.sortOn (columnIndex[column],
|
||||
(direction == '+' ?
|
||||
Table::ascendingDate :
|
||||
|
|
31
src/edit.cpp
31
src/edit.cpp
|
@ -150,6 +150,7 @@ static std::string formatTask (Task task)
|
|||
<< " Due: " << formatDate (task, "due") << std::endl
|
||||
<< " Until: " << formatDate (task, "until") << std::endl
|
||||
<< " Recur: " << task.get ("recur") << std::endl
|
||||
<< " Wait until: " << task.get ("wait") << std::endl
|
||||
<< " Parent: " << task.get ("parent") << std::endl
|
||||
<< " Foreground color: " << task.get ("fg") << std::endl
|
||||
<< " Background color: " << task.get ("bg") << std::endl
|
||||
|
@ -403,6 +404,36 @@ static void parseTask (Task& task, const std::string& after)
|
|||
}
|
||||
}
|
||||
|
||||
// wait
|
||||
value = findDate (after, "Wait until:");
|
||||
if (value != "")
|
||||
{
|
||||
Date edited (::atoi (value.c_str ()));
|
||||
|
||||
if (task.get ("wait") != "")
|
||||
{
|
||||
Date original (::atoi (task.get ("wait").c_str ()));
|
||||
if (!original.sameDay (edited))
|
||||
{
|
||||
std::cout << "Wait date modified." << std::endl;
|
||||
task.set ("wait", value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Wait date modified." << std::endl;
|
||||
task.set ("wait", value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (task.get ("wait") != "")
|
||||
{
|
||||
std::cout << "Wait date removed." << std::endl;
|
||||
task.remove ("wait");
|
||||
}
|
||||
}
|
||||
|
||||
// parent
|
||||
value = findValue (after, "Parent:");
|
||||
if (value != task.get ("parent"))
|
||||
|
|
|
@ -565,6 +565,7 @@ static std::string importTask_1_6_0 (const std::vector <std::string>& lines)
|
|||
else if (fields[f] == "'recurring'") task.setStatus (Task::recurring);
|
||||
else if (fields[f] == "'deleted'") task.setStatus (Task::deleted);
|
||||
else if (fields[f] == "'completed'") task.setStatus (Task::completed);
|
||||
else if (fields[f] == "'waiting'") task.setStatus (Task::waiting);
|
||||
break;
|
||||
|
||||
case 2: // 'tags'
|
||||
|
@ -1063,6 +1064,7 @@ static std::string importCSV (const std::vector <std::string>& lines)
|
|||
if (value == "recurring") task.setStatus (Task::recurring);
|
||||
else if (value == "deleted") task.setStatus (Task::deleted);
|
||||
else if (value == "completed") task.setStatus (Task::completed);
|
||||
else if (value == "waiting") task.setStatus (Task::waiting);
|
||||
else task.setStatus (Task::pending);
|
||||
}
|
||||
|
||||
|
|
|
@ -347,6 +347,7 @@ void updateRecurrenceMask (
|
|||
mask[index] = (task.getStatus () == Task::pending) ? '-'
|
||||
: (task.getStatus () == Task::completed) ? '+'
|
||||
: (task.getStatus () == Task::deleted) ? 'X'
|
||||
: (task.getStatus () == Task::waiting) ? 'W'
|
||||
: '?';
|
||||
|
||||
it->set ("mask", mask);
|
||||
|
@ -361,6 +362,7 @@ void updateRecurrenceMask (
|
|||
mask += (task.getStatus () == Task::pending) ? '-'
|
||||
: (task.getStatus () == Task::completed) ? '+'
|
||||
: (task.getStatus () == Task::deleted) ? 'X'
|
||||
: (task.getStatus () == Task::waiting) ? 'W'
|
||||
: '?';
|
||||
}
|
||||
|
||||
|
|
|
@ -242,6 +242,7 @@ std::string longUsage ()
|
|||
<< " fg: Foreground color" << "\n"
|
||||
<< " bg: Background color" << "\n"
|
||||
<< " limit: Desired number of rows in report" << "\n"
|
||||
<< " wait: Date until task becomes pending" << "\n"
|
||||
<< "\n"
|
||||
<< "Attribute modifiers improve filters. Supported modifiers are:" << "\n"
|
||||
<< " before (synonyms under, below)" << "\n"
|
||||
|
@ -416,6 +417,15 @@ std::string handleInfo ()
|
|||
}
|
||||
}
|
||||
|
||||
// wait
|
||||
if (task->has ("wait"))
|
||||
{
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 0, "Waiting until");
|
||||
Date dt (::atoi (task->get ("wait").c_str ()));
|
||||
table.addCell (row, 1, dt.toString (context.config.get ("dateformat", "m/d/Y")));
|
||||
}
|
||||
|
||||
// start
|
||||
if (task->has ("start"))
|
||||
{
|
||||
|
@ -539,7 +549,8 @@ std::string handleReportSummary ()
|
|||
std::string project = task->get ("project");
|
||||
++counter[project];
|
||||
|
||||
if (task->getStatus () == Task::pending)
|
||||
if (task->getStatus () == Task::pending ||
|
||||
task->getStatus () == Task::waiting)
|
||||
{
|
||||
++countPending[project];
|
||||
|
||||
|
@ -1646,6 +1657,7 @@ std::string handleReportStats ()
|
|||
int deletedT = 0;
|
||||
int pendingT = 0;
|
||||
int completedT = 0;
|
||||
int waitingT = 0;
|
||||
int taggedT = 0;
|
||||
int annotationsT = 0;
|
||||
int recurringT = 0;
|
||||
|
@ -1662,6 +1674,7 @@ std::string handleReportStats ()
|
|||
if (it->getStatus () == Task::pending) ++pendingT;
|
||||
if (it->getStatus () == Task::completed) ++completedT;
|
||||
if (it->getStatus () == Task::recurring) ++recurringT;
|
||||
if (it->getStatus () == Task::waiting) ++waitingT;
|
||||
|
||||
time_t entry = ::atoi (it->get ("entry").c_str ());
|
||||
if (entry < earliest) earliest = entry;
|
||||
|
@ -1721,6 +1734,10 @@ std::string handleReportStats ()
|
|||
table.addCell (row, 0, "Pending");
|
||||
table.addCell (row, 1, pendingT);
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 0, "Waiting");
|
||||
table.addCell (row, 1, waitingT);
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 0, "Recurring");
|
||||
table.addCell (row, 1, recurringT);
|
||||
|
|
|
@ -76,7 +76,8 @@ void validReportColumns (const std::vector <std::string>& columns)
|
|||
*it != "recurrence_indicator" &&
|
||||
*it != "tag_indicator" &&
|
||||
*it != "description_only" &&
|
||||
*it != "description")
|
||||
*it != "description" &&
|
||||
*it != "wait")
|
||||
bad.push_back (*it);
|
||||
|
||||
if (bad.size ())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue