mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
Bug #1022
- Fixed bug #1022, where dependencies were note released when a blocking task was completed (thanks to Arkady Grudzinsky). - The Task object now caches ::is_blocked and ::is_blocking Booleans that are determined on pending.data load. - Simplified and sped up color rule processing using cached values, reducing the number of map lookups, and removed loop invariants when the rules are not defined. - Simplified urgency calculations given the cached values for blocked/blocking. - On load, pending.data is scanned for accurate blocked/blocking status determination. - Obsoleted and removed complex single-task dependency calculations. - Sped up 'nag' processing by using cached values.. - Modified the 'show' command to consider color.blocking to be valid. - Added default config value for color.blocking, and included it in the precedence list ahead of blocked, as it is more important. - Updated taskrc.5 man page to include the new color.blocking rule, and its place in the rule precedence.
This commit is contained in:
parent
02053f7300
commit
79e2c591f1
14 changed files with 182 additions and 178 deletions
|
@ -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).
|
||||
|
||||
|
|
9
NEWS
9
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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
60
src/TDB2.cpp
60
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 <Task>::iterator left;
|
||||
for (left = _tasks.begin ();
|
||||
left != _tasks.end ();
|
||||
++left)
|
||||
{
|
||||
if (left->has ("depends"))
|
||||
{
|
||||
std::vector <std::string> deps;
|
||||
left->getDependencies (deps);
|
||||
|
||||
std::vector <std::string>::iterator d;
|
||||
for (d = deps.begin (); d != deps.end (); ++d)
|
||||
{
|
||||
std::vector <Task>::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 ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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 <Task> _tasks;
|
||||
std::vector <Task> _added_tasks;
|
||||
std::vector <Task> _modified_tasks;
|
||||
|
|
24
src/Task.cpp
24
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 <std::string> deps;
|
||||
getDependencies (deps);
|
||||
|
||||
std::vector <std::string>::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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 <Task>& all = context.tdb2.pending.get_tasks ();
|
||||
std::vector <Task>::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 <Task>& blocked)
|
||||
{
|
||||
|
@ -76,26 +54,6 @@ void dependencyGetBlocked (const Task& task, std::vector <Task>& 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 <Task>& all = context.tdb2.pending.get_tasks ();
|
||||
std::vector <Task>::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 <Task>& blocking)
|
||||
{
|
||||
|
|
|
@ -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 <Task>&);
|
||||
bool dependencyIsBlocking (const Task&);
|
||||
void dependencyGetBlocking (const Task&, std::vector <Task>&);
|
||||
bool dependencyIsCircular (const Task&);
|
||||
void dependencyChainOnComplete (Task&);
|
||||
|
|
|
@ -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);
|
||||
|
|
190
src/rules.cpp
190
src/rules.cpp
|
@ -27,7 +27,6 @@
|
|||
|
||||
#define L10N // Localization complete.
|
||||
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
#include <Context.h>
|
||||
#include <Date.h>
|
||||
|
@ -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 <std::string>::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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue