diff --git a/ChangeLog b/ChangeLog index 01aa3aec1..28869b84c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -98,6 +98,8 @@ Bugs that lack description or entry date (thanks to Nicholas Rabenau). + Fixed bug #1017, which exported invalid JSON when there were no tasks (thanks to Nicholas Rabenau). + + Fixed bug #1022, where dependencies were note released when a blocking task + was completed (thanks to Arkady Grudzinsky). + Fixed bug #1023, which applied default.project and default.priority during modification (thanks to Christoph Lange). diff --git a/NEWS b/NEWS index bda4f3796..3cc18de5f 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,5 @@ -New Features in taskwarrior 2.0.1 +New Features in taskwarrior 2.1.0 - The new 'project.indented' format is available and used in the 'projects' and 'summary' commands. @@ -12,18 +12,19 @@ New Features in taskwarrior 2.0.1 Please refer to the ChangeLog file for full details. There are too many to list here. -New commands in taskwarrior 2.0.1 +New commands in taskwarrior 2.1.0 - New 'ready' report that lists tasks ready for work, sorted by urgency. - New 'udas' command shows UDA details and warnings. - New '_udas' helper command lists UDA names for completion purposes. -New configuration options in taskwarrior 2.0.1 +New configuration options in taskwarrior 2.1.0 - urgency.scheduled.coefficient - color.scheduled + - color.blocking -Newly deprecated features in taskwarrior 2.0.1 +Newly deprecated features in taskwarrior 2.1.0 - None diff --git a/doc/man/taskrc.5.in b/doc/man/taskrc.5.in index 47a81ac71..cfbea5a1e 100644 --- a/doc/man/taskrc.5.in +++ b/doc/man/taskrc.5.in @@ -741,6 +741,9 @@ Task is started, therefore active. .B color.scheduled Task is scheduled, therefore ready for work. .br +.B color.blocking +Task is blocking another in a dependency. +.br .B color.blocked Task is blocked by a dependency. .br @@ -935,7 +938,7 @@ Colors the output of the merge command. .RE .TP -.B rule.precedence.color=due.today,active,blocked,overdue,due,scheduled,keyword.,project.,tag.,recurring,pri,tagged,completed,deleted +.B rule.precedence.color=due.today,active,blocking,blocked,overdue,due,scheduled,keyword.,project.,tag.,recurring,pri,tagged,completed,deleted .RS This setting specifies the precedence of the color rules, from highest to lowest. Note that the prefix 'color.' is omitted (for brevity), and that any diff --git a/src/Config.cpp b/src/Config.cpp index a4450364b..c1ac85ae7 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -207,6 +207,7 @@ std::string Config::_defaults = "color.pri.L=rgb245 # Color of priority:L tasks\n" "color.tagged=rgb031 # Color of tagged tasks\n" "color.blocked=white on color8 # Color of blocked tasks\n" + "color.blocking=white on color7 # Color of blocking tasks\n" "#color.completed=on blue # Color of completed tasks\n" "#color.deleted=on blue # Color of deleted tasks\n" #else @@ -267,7 +268,7 @@ std::string Config::_defaults = "# Here is the rule precedence order, highest to lowest.\n" "# Note that these are just the color rule names, without the leading 'color.'\n" "# and any trailing '.value'.\n" - "rule.precedence.color=due.today,active,blocked,overdue,due,scheduled,keyword.,project.,tag.,recurring,pri.,tagged,completed,deleted\n" + "rule.precedence.color=due.today,active,blocking,blocked,overdue,due,scheduled,keyword.,project.,tag.,recurring,pri.,tagged,completed,deleted\n" "\n" "# Shadow file support\n" "#shadow.file=/tmp/shadow.txt # Location of shadow file\n" diff --git a/src/TDB2.cpp b/src/TDB2.cpp index 6311a2617..c9d556c5e 100644 --- a/src/TDB2.cpp +++ b/src/TDB2.cpp @@ -67,6 +67,7 @@ TF2::TF2 () , _loaded_tasks (false) , _loaded_lines (false) , _has_ids (false) +, _auto_dep_scan (false) { } @@ -311,6 +312,9 @@ void TF2::load_tasks () _U2I[task.get ("uuid")] = task.id; } } + + if (_auto_dep_scan) + dependency_scan (); _loaded_tasks = true; } @@ -382,6 +386,12 @@ void TF2::has_ids () _has_ids = true; } +//////////////////////////////////////////////////////////////////////////////// +void TF2::auto_dep_scan () +{ + _auto_dep_scan = true; +} + //////////////////////////////////////////////////////////////////////////////// // Completely wipe it all clean. void TF2::clear () @@ -391,9 +401,10 @@ void TF2::clear () _loaded_tasks = false; _loaded_lines = false; - // Note that the actual file name, and _has_ids are deliberately not cleared. + // Note that these are deliberately not cleared. //_file._data = ""; //_has_ids = false; + //_auto_dep_scan = false; _tasks.clear (); _added_tasks.clear (); @@ -404,6 +415,49 @@ void TF2::clear () _U2I.clear (); } +//////////////////////////////////////////////////////////////////////////////// +// For any task that has depenencies, follow the chain of dependencies until the +// end. Along the way, update the Task::is_blocked and Task::is_blocking data +// cache. +void TF2::dependency_scan () +{ + // Iterate and modify TDB2 in-place. Don't do this at home. + std::vector ::iterator left; + for (left = _tasks.begin (); + left != _tasks.end (); + ++left) + { + if (left->has ("depends")) + { + std::vector deps; + left->getDependencies (deps); + + std::vector ::iterator d; + for (d = deps.begin (); d != deps.end (); ++d) + { + std::vector ::iterator right; + for (right = _tasks.begin (); + right != _tasks.end (); + ++right) + { + if (right->get ("uuid") == *d) + { + Task::status status = right->getStatus (); + if (status != Task::completed && + status != Task::deleted) + { + left->is_blocked = true; + right->is_blocking = true; + } + + break; + } + } + } + } + } +} + //////////////////////////////////////////////////////////////////////////////// const std::string TF2::dump () { @@ -454,6 +508,10 @@ TDB2::TDB2 () { // Mark the pending file as the only one that has ID numbers. pending.has_ids (); + + // Indicate that dependencies should be automatically scanned on startup, + // setting Task::is_blocked and Task::is_blocking accordingly. + pending.auto_dep_scan (); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/TDB2.h b/src/TDB2.h index e94beef74..26872a018 100644 --- a/src/TDB2.h +++ b/src/TDB2.h @@ -66,15 +66,20 @@ public: int id (const std::string&); void has_ids (); + void auto_dep_scan (); void clear (); const std::string dump (); +private: + void dependency_scan (); + public: bool _read_only; bool _dirty; bool _loaded_tasks; bool _loaded_lines; bool _has_ids; + bool _auto_dep_scan; std::vector _tasks; std::vector _added_tasks; std::vector _modified_tasks; diff --git a/src/Task.cpp b/src/Task.cpp index 70266c5fd..d959ef1a9 100644 --- a/src/Task.cpp +++ b/src/Task.cpp @@ -100,6 +100,8 @@ Task::Task () : id (0) , urgency_value (0.0) , recalc_urgency (true) +, is_blocked (false) +, is_blocking (false) { } @@ -119,6 +121,8 @@ Task& Task::operator= (const Task& other) id = other.id; urgency_value = other.urgency_value; recalc_urgency = other.recalc_urgency; + is_blocked = other.is_blocked; + is_blocking = other.is_blocking; } return *this; @@ -1409,22 +1413,8 @@ float Task::urgency_waiting () const // A task is blocked only if the task it depends upon is pending/waiting. float Task::urgency_blocked () const { - if (has ("depends")) - { - std::vector deps; - getDependencies (deps); - - std::vector ::iterator d; - for (d = deps.begin (); d != deps.end (); ++d) - { - Task t; - if (context.tdb2.get (*d, t) && - (t.getStatus () == Task::pending || t.getStatus () == Task::waiting)) - { - return 1.0; - } - } - } + if (is_blocked) + return 1.0; return 0.0; } @@ -1524,7 +1514,7 @@ float Task::urgency_age () const //////////////////////////////////////////////////////////////////////////////// float Task::urgency_blocking () const { - if (dependencyIsBlocking (*this)) + if (is_blocking) return 1.0; return 0.0; diff --git a/src/Task.h b/src/Task.h index 7f84d5537..a607895bd 100644 --- a/src/Task.h +++ b/src/Task.h @@ -59,6 +59,9 @@ public: float urgency_value; bool recalc_urgency; + bool is_blocked; + bool is_blocking; + // Series of helper functions. static status textToStatus (const std::string&); static std::string statusToText (status); diff --git a/src/commands/CmdShow.cpp b/src/commands/CmdShow.cpp index 5d60065cb..096c18cfb 100644 --- a/src/commands/CmdShow.cpp +++ b/src/commands/CmdShow.cpp @@ -85,6 +85,7 @@ int CmdShow::execute (std::string& output) " color.active" " color.alternate" " color.blocked" + " color.blocking" " color.burndown.done" " color.burndown.pending" " color.burndown.started" diff --git a/src/dependency.cpp b/src/dependency.cpp index c127d0bc3..716cf54b9 100644 --- a/src/dependency.cpp +++ b/src/dependency.cpp @@ -39,28 +39,6 @@ extern Context context; -//////////////////////////////////////////////////////////////////////////////// -// A task is blocked if it depends on tasks that are pending or waiting. -// -// 1 --> 2(pending) = blocked -// 3 --> 4(completed) = not blocked any more -bool dependencyIsBlocked (const Task& task) -{ - std::string depends = task.get ("depends"); - if (depends != "") - { - const std::vector & all = context.tdb2.pending.get_tasks (); - std::vector ::const_iterator it; - for (it = all.begin (); it != all.end (); ++it) - if ((it->getStatus () == Task::pending || - it->getStatus () == Task::waiting) && - depends.find (it->get ("uuid")) != std::string::npos) - return true; - } - - return false; -} - //////////////////////////////////////////////////////////////////////////////// void dependencyGetBlocked (const Task& task, std::vector & blocked) { @@ -76,26 +54,6 @@ void dependencyGetBlocked (const Task& task, std::vector & blocked) blocked.push_back (*it); } - -//////////////////////////////////////////////////////////////////////////////// -// To be a blocking task, there must be at least one other task that depends on -// this task, that is either pending or waiting. -bool dependencyIsBlocking (const Task& task) -{ - std::string uuid = task.get ("uuid"); - - const std::vector & all = context.tdb2.pending.get_tasks (); - std::vector ::const_iterator it; - for (it = all.begin (); it != all.end (); ++it) - if ((it->getStatus () == Task::pending || - it->getStatus () == Task::waiting) && - it->has ("depends") && - it->get ("depends").find (uuid) != std::string::npos) - return true; - - return false; -} - //////////////////////////////////////////////////////////////////////////////// void dependencyGetBlocking (const Task& task, std::vector & blocking) { diff --git a/src/main.h b/src/main.h index 6d35fa26e..10fc6afdc 100644 --- a/src/main.h +++ b/src/main.h @@ -59,9 +59,7 @@ std::string colorizeError (const std::string&); std::string colorizeDebug (const std::string&); // dependency.cpp -bool dependencyIsBlocked (const Task&); void dependencyGetBlocked (const Task&, std::vector &); -bool dependencyIsBlocking (const Task&); void dependencyGetBlocking (const Task&, std::vector &); bool dependencyIsCircular (const Task&); void dependencyChainOnComplete (Task&); diff --git a/src/recur.cpp b/src/recur.cpp index fd1d0cac3..214f72ea2 100644 --- a/src/recur.cpp +++ b/src/recur.cpp @@ -505,12 +505,12 @@ bool nag (Task& task) } // General form is "if there are no more deserving tasks", suppress the nag. - if (isOverdue ) return false; - if (pri == 'H' && !overdue ) return false; - if (pri == 'M' && !overdue && !high ) return false; - if (pri == 'L' && !overdue && !high && !medium ) return false; - if (pri == ' ' && !overdue && !high && !medium && !low ) return false; - if (dependencyIsBlocking (task) && !dependencyIsBlocked (task)) return false; + if (isOverdue ) return false; + if (pri == 'H' && !overdue ) return false; + if (pri == 'M' && !overdue && !high ) return false; + if (pri == 'L' && !overdue && !high && !medium ) return false; + if (pri == ' ' && !overdue && !high && !medium && !low ) return false; + if (task.is_blocking && !task.is_blocked ) return false; // All the excuses are made, all that remains is to nag the user. context.footnote (nagMessage); diff --git a/src/rules.cpp b/src/rules.cpp index b77916912..4d7a6b024 100644 --- a/src/rules.cpp +++ b/src/rules.cpp @@ -27,7 +27,6 @@ #define L10N // Localization complete. -#include #include #include #include @@ -84,85 +83,80 @@ void initializeColorRules () } //////////////////////////////////////////////////////////////////////////////// -static void colorizeBlocked (Task& task, const std::string& rule, Color& c) +static void colorizeBlocked (Task& task, const Color& base, Color& c) { - if (gsColor[rule].nontrivial ()) - if (dependencyIsBlocked (task)) - c.blend (gsColor[rule]); + if (task.is_blocked) + c.blend (base); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeTagged (Task& task, const std::string& rule, Color& c) +static void colorizeBlocking (Task& task, const Color& base, Color& c) { - if (gsColor[rule].nontrivial ()) - if (task.getTagCount ()) - c.blend (gsColor[rule]); + if (task.is_blocking) + c.blend (base); } //////////////////////////////////////////////////////////////////////////////// -static void colorizePriorityL (Task& task, const std::string& rule, Color& c) +static void colorizeTagged (Task& task, const Color& base, Color& c) { - if (gsColor[rule].nontrivial ()) - if (task.get ("priority") == "L") - c.blend (gsColor[rule]); + if (task.getTagCount ()) + c.blend (base); } //////////////////////////////////////////////////////////////////////////////// -static void colorizePriorityM (Task& task, const std::string& rule, Color& c) +static void colorizePriorityL (Task& task, const Color& base, Color& c) { - if (gsColor[rule].nontrivial ()) - if (task.get ("priority") == "M") - c.blend (gsColor[rule]); + if (task.get ("priority") == "L") + c.blend (base); } //////////////////////////////////////////////////////////////////////////////// -static void colorizePriorityH (Task& task, const std::string& rule, Color& c) +static void colorizePriorityM (Task& task, const Color& base, Color& c) { - if (gsColor[rule].nontrivial ()) - if (task.get ("priority") == "H") - c.blend (gsColor[rule]); + if (task.get ("priority") == "M") + c.blend (base); } //////////////////////////////////////////////////////////////////////////////// -static void colorizePriorityNone (Task& task, const std::string& rule, Color& c) +static void colorizePriorityH (Task& task, const Color& base, Color& c) { - if (gsColor[rule].nontrivial ()) - if (task.get ("priority") == "") - c.blend (gsColor[rule]); + if (task.get ("priority") == "H") + c.blend (base); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeActive (Task& task, const std::string& rule, Color& c) +static void colorizePriorityNone (Task& task, const Color& base, Color& c) { - if (gsColor[rule].nontrivial ()) - if (task.has ("start") && - !task.has ("end")) - c.blend (gsColor[rule]); + if (task.get ("priority") == "") + c.blend (base); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeScheduled (Task& task, const std::string& rule, Color& c) +static void colorizeActive (Task& task, const Color& base, Color& c) { - if (gsColor[rule].nontrivial ()) - if (task.has ("scheduled") && - Date (task.get_date ("scheduled")) <= now) - c.blend (gsColor[rule]); + if (task.has ("start") && + !task.has ("end")) + c.blend (base); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeTag (Task& task, const std::string& rule, Color& c) +static void colorizeScheduled (Task& task, const Color& base, Color& c) { - if (gsColor[rule].nontrivial ()) - if (task.hasTag (rule.substr (10))) - c.blend (gsColor[rule]); + if (task.has ("scheduled") && + Date (task.get_date ("scheduled")) <= now) + c.blend (base); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeProject (Task& task, const std::string& rule, Color& c) +static void colorizeTag (Task& task, const std::string& rule, const Color& base, Color& c) { - if (!gsColor[rule].nontrivial ()) - return; + if (task.hasTag (rule.substr (10))) + c.blend (base); +} +//////////////////////////////////////////////////////////////////////////////// +static void colorizeProject (Task& task, const std::string& rule, const Color& base, Color& c) +{ // Observe the case sensitivity setting. bool sensitive = context.config.getBoolean ("search.case.sensitive"); @@ -172,38 +166,33 @@ static void colorizeProject (Task& task, const std::string& rule, Color& c) // Match project names leftmost. if (rule_trunc.length () <= project.length ()) if (compare (rule_trunc, project.substr (0, rule_trunc.length ()), sensitive)) - c.blend (gsColor[rule]); + c.blend (base); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeProjectNone (Task& task, const std::string& rule, Color& c) +static void colorizeProjectNone (Task& task, const Color& base, Color& c) { - if (gsColor[rule].nontrivial ()) - if (task.get ("project") == "") - c.blend (gsColor[rule]); + if (task.get ("project") == "") + c.blend (base); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeTagNone (Task& task, const std::string& rule, Color& c) +static void colorizeTagNone (Task& task, const Color& base, Color& c) { - if (gsColor[rule].nontrivial ()) - if (task.getTagCount () == 0) - c.blend (gsColor[rule]); + if (task.getTagCount () == 0) + c.blend (base); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeKeyword (Task& task, const std::string& rule, Color& c) +static void colorizeKeyword (Task& task, const std::string& rule, const Color& base, Color& c) { - if (!gsColor[rule].nontrivial ()) - return; - // Observe the case sensitivity setting. bool sensitive = context.config.getBoolean ("search.case.sensitive"); // The easiest thing to check is the description, because it is just one // attribute. if (find (task.get ("description"), rule.substr (14), sensitive) != std::string::npos) - c.blend (gsColor[rule]); + c.blend (base); // Failing the description check, look at all annotations, returning on the // first match. @@ -215,7 +204,7 @@ static void colorizeKeyword (Task& task, const std::string& rule, Color& c) if (it->first.substr (0, 11) == "annotation_" && find (it->second, rule.substr (14), sensitive) != std::string::npos) { - c.blend (gsColor[rule]); + c.blend (base); return; } } @@ -223,11 +212,8 @@ static void colorizeKeyword (Task& task, const std::string& rule, Color& c) } //////////////////////////////////////////////////////////////////////////////// -static void colorizeDue (Task& task, const std::string& rule, Color& c) +static void colorizeDue (Task& task, const Color& base, Color& c) { - if (!gsColor[rule].nontrivial ()) - return; - Task::status status = task.getStatus (); if (task.has ("due") && @@ -235,16 +221,13 @@ static void colorizeDue (Task& task, const std::string& rule, Color& c) status != Task::deleted) { if (getDueState (task.get ("due")) == 1) - c.blend (gsColor[rule]); + c.blend (base); } } //////////////////////////////////////////////////////////////////////////////// -static void colorizeDueToday (Task& task, const std::string& rule, Color& c) +static void colorizeDueToday (Task& task, const Color& base, Color& c) { - if (!gsColor[rule].nontrivial ()) - return; - Task::status status = task.getStatus (); if (task.has ("due") && @@ -252,16 +235,13 @@ static void colorizeDueToday (Task& task, const std::string& rule, Color& c) status != Task::deleted) { if (getDueState (task.get ("due")) == 2) - c.blend (gsColor[rule]); + c.blend (base); } } //////////////////////////////////////////////////////////////////////////////// -static void colorizeOverdue (Task& task, const std::string& rule, Color& c) +static void colorizeOverdue (Task& task, const Color& base, Color& c) { - if (!gsColor[rule].nontrivial ()) - return; - Task::status status = task.getStatus (); if (task.has ("due") && @@ -269,32 +249,29 @@ static void colorizeOverdue (Task& task, const std::string& rule, Color& c) status != Task::deleted) { if (getDueState (task.get ("due")) == 3) - c.blend (gsColor[rule]); + c.blend (base); } } //////////////////////////////////////////////////////////////////////////////// -static void colorizeRecurring (Task& task, const std::string& rule, Color& c) +static void colorizeRecurring (Task& task, const Color& base, Color& c) { - if (gsColor[rule].nontrivial ()) - if (task.has ("recur")) - c.blend (gsColor[rule]); + if (task.has ("recur")) + c.blend (base); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeCompleted (Task& task, const std::string& rule, Color& c) +static void colorizeCompleted (Task& task, const Color& base, Color& c) { - if (gsColor[rule].nontrivial ()) - if (task.getStatus () == Task::completed) - c.blend (gsColor[rule]); + if (task.getStatus () == Task::completed) + c.blend (base); } //////////////////////////////////////////////////////////////////////////////// -static void colorizeDeleted (Task& task, const std::string& rule, Color& c) +static void colorizeDeleted (Task& task, const Color& base, Color& c) { - if (gsColor[rule].nontrivial ()) - if (task.getStatus () == Task::completed) - c.blend (gsColor[rule]); + if (task.getStatus () == Task::completed) + c.blend (base); } //////////////////////////////////////////////////////////////////////////////// @@ -314,27 +291,32 @@ void autoColorize (Task& task, Color& c) std::vector ::reverse_iterator r; for (r = gsPrecedence.rbegin (); r != gsPrecedence.rend (); ++r) { - if (*r == "color.blocked") colorizeBlocked (task, *r, c); - else if (*r == "color.tagged") colorizeTagged (task, *r, c); - else if (*r == "color.pri.L") colorizePriorityL (task, *r, c); - else if (*r == "color.pri.M") colorizePriorityM (task, *r, c); - else if (*r == "color.pri.H") colorizePriorityH (task, *r, c); - else if (*r == "color.pri.none") colorizePriorityNone (task, *r, c); - else if (*r == "color.active") colorizeActive (task, *r, c); - else if (*r == "color.scheduled") colorizeScheduled (task, *r, c); - else if (*r == "color.project.none") colorizeProjectNone (task, *r, c); - else if (*r == "color.tag.none") colorizeTagNone (task, *r, c); - else if (*r == "color.due") colorizeDue (task, *r, c); - else if (*r == "color.due.today") colorizeDueToday (task, *r, c); - else if (*r == "color.overdue") colorizeOverdue (task, *r, c); - else if (*r == "color.recurring") colorizeRecurring (task, *r, c); - else if (*r == "color.completed") colorizeCompleted (task, *r, c); - else if (*r == "color.deleted") colorizeDeleted (task, *r, c); + Color base = gsColor[*r]; + if (base.nontrivial ()) + { + if (*r == "color.blocked") colorizeBlocked (task, base, c); + else if (*r == "color.blocking") colorizeBlocking (task, base, c); + else if (*r == "color.tagged") colorizeTagged (task, base, c); + else if (*r == "color.pri.L") colorizePriorityL (task, base, c); + else if (*r == "color.pri.M") colorizePriorityM (task, base, c); + else if (*r == "color.pri.H") colorizePriorityH (task, base, c); + else if (*r == "color.pri.none") colorizePriorityNone (task, base, c); + else if (*r == "color.active") colorizeActive (task, base, c); + else if (*r == "color.scheduled") colorizeScheduled (task, base, c); + else if (*r == "color.project.none") colorizeProjectNone (task, base, c); + else if (*r == "color.tag.none") colorizeTagNone (task, base, c); + else if (*r == "color.due") colorizeDue (task, base, c); + else if (*r == "color.due.today") colorizeDueToday (task, base, c); + else if (*r == "color.overdue") colorizeOverdue (task, base, c); + else if (*r == "color.recurring") colorizeRecurring (task, base, c); + else if (*r == "color.completed") colorizeCompleted (task, base, c); + else if (*r == "color.deleted") colorizeDeleted (task, base, c); - // Wildcards - else if (r->substr (0, 10) == "color.tag.") colorizeTag (task, *r, c); - else if (r->substr (0, 14) == "color.project.") colorizeProject (task, *r, c); - else if (r->substr (0, 14) == "color.keyword.") colorizeKeyword (task, *r, c); + // Wildcards + else if (r->substr (0, 10) == "color.tag.") colorizeTag (task, *r, base, c); + else if (r->substr (0, 14) == "color.project.") colorizeProject (task, *r, base, c); + else if (r->substr (0, 14) == "color.keyword.") colorizeKeyword (task, *r, base, c); + } } } diff --git a/test/special.t b/test/special.t index 8ff3f8d06..4cbc643aa 100755 --- a/test/special.t +++ b/test/special.t @@ -38,6 +38,7 @@ if (open my $fh, '>', 'special.rc') "color.alternate=\n", "color.tagged=\n", "color.pri.H=\n", + "color.completed=\n", "nag=NAG\n", "_forcecolor=1\n"; close $fh; @@ -47,6 +48,7 @@ if (open my $fh, '>', 'special.rc') # Prove that +nocolor suppresses all color for a task. qx{../src/task rc:special.rc add should have no red +nocolor priority:H 2>&1}; qx{../src/task rc:special.rc add should be red +nonag 2>&1}; + my $output = qx{../src/task rc:special.rc ls 2>&1}; like ($output, qr/\s1\s+H\s+should have no red/, 'no red in first task due to +nocolor'); like ($output, qr/\033\[31mshould be red\s+\033\[0m/, 'red in second task');