Feature #481 - color should follow rc order

- Added feature #481, allowing for user control of the color rule order
  of precedence via the 'rule.precedence.color' configuration variable.
- Color rules now obey the rc.search.case.sensitive configuration option.
- The color.keyword.XXX color rule now applies to annotations too.
This commit is contained in:
Paul Beckingham 2010-08-29 13:40:53 -04:00
parent c27097e286
commit 4cd528661a
11 changed files with 442 additions and 276 deletions

View file

@ -28,6 +28,8 @@
changes to the completion percentage when it changes. changes to the completion percentage when it changes.
+ Added feature #478, which uses the colorization rules in the 'info' + Added feature #478, which uses the colorization rules in the 'info'
report. report.
+ Added feature #481, allowing for user control of the color rule order
of precedence via the 'rule.precedence.color' configuration variable.
+ New 'depends' column for custom reports. + New 'depends' column for custom reports.
+ New 'blocked' report for showing blocked tasks. + New 'blocked' report for showing blocked tasks.
+ Improved man pages (thanks to Andy Lester). + Improved man pages (thanks to Andy Lester).
@ -37,6 +39,8 @@
+ The 'tags' command highlights special tags. + The 'tags' command highlights special tags.
+ The 'stats' and 'info' reports not obey color.alternate. + The 'stats' and 'info' reports not obey color.alternate.
+ New fish shell tab completion script (thanks to Mick Koch). + New fish shell tab completion script (thanks to Mick Koch).
+ Color rules now obey the rc.search.case.sensitive configuration option.
+ The color.keyword.XXX color rule now applies to annotations too.
+ Fixed bug #427, preventing the task edit command to parse annotation + Fixed bug #427, preventing the task edit command to parse annotation
dates with spaces. dates with spaces.
+ Fixed bug #433, making task command output more consistent. + Fixed bug #433, making task command output more consistent.

12
NEWS
View file

@ -6,6 +6,9 @@ New Features in taskwarrior 1.9.3
- Now supports durations in dates, such as: - Now supports durations in dates, such as:
$ task ... due:4d $ task ... due:4d
$ task ... due:3wks $ task ... due:3wks
- 'sow', 'som' and 'soy' are now accepted in dates. 'soww' and 'eoww' are
now synonyms for 'sow' and 'eow' (ww = working week) 'socw' and 'eocw'
refer to the calendar week (starting Sunday/Monday and
- Now supports the beginning of the week, month and year in dates. - Now supports the beginning of the week, month and year in dates.
- Now supports 'now' as a date/time. - Now supports 'now' as a date/time.
- Now defines an overdue task as being one second after the due date, - Now defines an overdue task as being one second after the due date,
@ -15,6 +18,7 @@ New Features in taskwarrior 1.9.3
- When completing or modifying a task, the project status is displayed. - When completing or modifying a task, the project status is displayed.
- The 'info' report is now colorized. - The 'info' report is now colorized.
- Certain characters (#, $, @) are now supported for use in tags. - Certain characters (#, $, @) are now supported for use in tags.
- User-controlled color rule precedence.
Please refer to the ChangeLog file for full details. There are too many to Please refer to the ChangeLog file for full details. There are too many to
list here. list here.
@ -31,10 +35,10 @@ New commands in taskwarrior 1.9.3
New configuration options in taskwarrior 1.9.3 New configuration options in taskwarrior 1.9.3
- journal.time, journal.time.start.annotation, journal.time.stop.annotation - journal.time, journal.time.start.annotation, journal.time.stop.annotation
- 'sow', 'som' and 'soy' are now accepted in dates ending Saturday/Sunday).
'soww' and 'eoww' are now synonyms for 'sow' and 'eow' (ww = working week) - Color rule precedence can now be explicitly set with the configuration
'socw' and 'eocw' refer to the calendar week (starting Sunday/Monday and variable rule.precedence.color. Try "task show rule.pre" to show the
ending Saturday/Sunday) default settings.
Newly deprecated features in taskwarrior 1.9.3 Newly deprecated features in taskwarrior 1.9.3

View file

@ -236,6 +236,20 @@ It is possible to create a very colorful mix of rules. With 256-color support,
those colors can be made subtle, and complementary, but without care, this can those colors can be made subtle, and complementary, but without care, this can
be a visual mess. Beware! be a visual mess. Beware!
The precedence for the color rules is determined by the configuration variable
'rule.precedence.color', which by default contains:
due.today,active,blocked,overdue,due,keyword,project,tag,recurring,pri,tagged
These are just the color rules with the 'color.' prefix removed. The rule
'color.due.today' is the highest precedence, and 'color.tagged' is the lowest.
The keyword rule shown here as 'keyword' corresponds to a wildcard pattern,
meaning 'color.keyword.*', or in other words all the keyword rules. Similarly
for the 'color.tag.*' and 'color.project.*' rules.
There is also 'color.project.none', 'color.tag.none' and 'color.pri.none'.
.SH THEMES .SH THEMES
Taskwarrior supports themes. What this really means is that with the ability to Taskwarrior supports themes. What this really means is that with the ability to
include other files into the .taskrc file, different sets of color rules can include other files into the .taskrc file, different sets of color rules can
@ -266,6 +280,10 @@ dark-green-256.theme
dark-blue-256.theme dark-blue-256.theme
.RE .RE
You can also see how the theme will color the various tasks with the command:
$ task color legend
Better yet, create your own, and share it. We will gladly host the theme file Better yet, create your own, and share it. We will gladly host the theme file
on <http://taskwarrior.org>. on <http://taskwarrior.org>.

View file

@ -536,40 +536,50 @@ terminal, can be obtained by running the command:
.B task color .B task color
.RE .RE
.RS .RS
The coloration rules and their defaults are: The coloration rules are:
.RE .RE
.RS .RS
.B color.overdue=bold red .B color.due.today
The color for overdue tasks. Task is due today
.br .br
.B color.due.today=bold magenta .B color.active
The color of tasks due today. Task is started, therefore active.
.br .br
.B color.due=bold yellow .B color.blocked
The color of due tasks. Task is blocked by a dependency.
.br .br
.B color.pri.H=bold .B color.overdue
The color of priority:H tasks. Task is overdue (due some time prior to now).
.br .br
.B color.pri.M=on yellow .B color.due
The color of priority:M tasks. No default value. Task is coming due.
.br .br
.B color.pri.L=on green .B color.project.none
The color of priority:L tasks. No default value. Task does not have an assigned project.
.br .br
.B color.pri.none=white on blue .B color.tag.none
The color of priority: tasks. No default value. Task has no tags.
.br .br
.B color.active=bold cyan .B color.tagged
The color of active tasks. Task has at least one tag.
.br .br
.B color.tagged=yellow .B color.recurring
The color of tagged tasks. Task is recurring.
.br .br
.B color.recurring=on red .B color.pri.H
The color for recurring tasks. Task has priority H.
.br
.B color.pri.M
Task has priority M.
.br
.B color.pri.L
Task has priority L.
.br
.B color.pri.none
Task has no priority.
.RE .RE
.RE .RE
@ -690,6 +700,15 @@ Colors used by the undo command, to indicate the values both before and after
a change that is to be reverted. a change that is to be reverted.
.RE .RE
.TP
.B rule.precedence.color=overdue,tag,project,keyword,active,...
.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
wildcard values (color.tag.XXX) is shortened to 'tag', which places all specific
tag rules at the same precedence, again for brevity.
.RE
.SS SHADOW FILE .SS SHADOW FILE
.TP .TP

View file

@ -123,6 +123,7 @@ std::string Config::defaults =
"color.header=color3 # Color of header messages\n" "color.header=color3 # Color of header messages\n"
"color.footnote=color3 # Color of footnote messages\n" "color.footnote=color3 # Color of footnote messages\n"
"color.debug=color3 # Color of diagnostic output\n" "color.debug=color3 # Color of diagnostic output\n"
"color.alternate=on color233 # Alternate color for line coloring\n"
"\n" "\n"
"color.summary.bar=on rgb141 # Color of summary report progress bar\n" "color.summary.bar=on rgb141 # Color of summary report progress bar\n"
"color.summary.background=on color0 # Color of summary report background\n" "color.summary.background=on color0 # Color of summary report background\n"
@ -142,29 +143,26 @@ std::string Config::defaults =
"color.calendar.holiday=color0 on color11 # Color of public holidays in calendar\n" "color.calendar.holiday=color0 on color11 # Color of public holidays in calendar\n"
"color.calendar.weeknumber=rgb013 # Color of the weeknumbers in calendar\n" "color.calendar.weeknumber=rgb013 # Color of the weeknumbers in calendar\n"
"\n" "\n"
"# The following rules are presented in their order of precedence.\n" "# Here are the color rules.\n"
"# The higher the color rule is up this list, the higher precedence\n" "color.recurring=rgb013 # Color of recur.any: tasks\n"
"# it has in determining the color for the task. Precedence is shown\n" "color.overdue=color9 # Color of overdue tasks\n"
"# in brackets [1]\n" "color.due.today=rgb400 # Color of tasks due today\n"
"color.recurring=rgb013 # [1] Color of recur.any: tasks\n" "color.due=color1 # Color of due tasks\n"
"color.overdue=color9 # [2] Color of overdue tasks\n" "#color.keyword.car=on blue # Color of description.contains:car tasks\n"
"color.due.today=rgb400 # [3] Color of tasks due today\n" "#color.project.garden=on green # Color of project:garden tasks\n"
"color.due=color1 # [4] Color of due tasks\n" "#color.tag.bug=yellow # Color of +bug tasks\n"
"#color.keyword.car=on blue # [5] Color of description.contains:car tasks\n" "color.active=rgb555 on rgb410 # Color of active tasks\n"
"#color.project.garden=on green # [6] Color of project:garden tasks\n" "color.pri.none= # Color of priority: tasks\n"
"#color.tag.bug=yellow # [7] Color of +bug tasks\n" "color.pri.H=rgb255 # Color of priority:H tasks\n"
"color.active=rgb555 on rgb410 # [8] Color of active tasks\n" "color.pri.M=rgb250 # Color of priority:M tasks\n"
"color.pri.none= # [9] Color of priority: tasks\n" "color.pri.L=rgb245 # Color of priority:L tasks\n"
"color.pri.H=rgb255 # [9] Color of priority:H tasks\n" "color.tagged=rgb031 # Color of tagged tasks\n"
"color.pri.M=rgb250 # [9] Color of priority:M tasks\n" "color.blocked=black on white # Color of blocked tasks\n"
"color.pri.L=rgb245 # [9] Color of priority:L tasks\n"
"color.tagged=rgb031 # [10] Color of tagged tasks\n"
"color.blocked=black on white # [11] Color of blocked tasks\n"
"color.alternate=on color233 # [12] Alternate color for line coloring\n"
#else #else
"color.header=yellow # Color of header messages\n" "color.header=yellow # Color of header messages\n"
"color.footnote=yellow # Color of footnote messages\n" "color.footnote=yellow # Color of footnote messages\n"
"color.debug=yellow # Color of diagnostic output\n" "color.debug=yellow # Color of diagnostic output\n"
"color.alternate= # Alternate color for line coloring\n"
"\n" "\n"
"color.summary.bar=on green # Color of summary report progress bar\n" "color.summary.bar=on green # Color of summary report progress bar\n"
"color.summary.background=on black # Color of summary report background\n" "color.summary.background=on black # Color of summary report background\n"
@ -184,26 +182,27 @@ std::string Config::defaults =
"color.calendar.holiday=black on bright yellow # Color of public holidays in calendar\n" "color.calendar.holiday=black on bright yellow # Color of public holidays in calendar\n"
"color.calendar.weeknumber=bold blue # Color of the weeknumbers in calendar\n" "color.calendar.weeknumber=bold blue # Color of the weeknumbers in calendar\n"
"\n" "\n"
"# The following rules are presented in their order of precedence.\n" "# Here are the color rules.\n"
"# The higher the color rule is up this list, the higher precedence\n" "color.recurring=magenta # Color of recur.any: tasks\n"
"# it has in determining the color for the task. Precedence is shown\n" "color.overdue=bold red # Color of overdue tasks\n"
"# in brackets [1]\n" "color.due.today=red # Color of tasks due today\n"
"color.recurring=magenta # [1] Color of recur.any: tasks\n" "color.due=red # Color of due tasks\n"
"color.overdue=bold red # [2] Color of overdue tasks\n" "#color.keyword.car=on blue # Color of description.contains:car tasks\n"
"color.due.today=red # [3] Color of tasks due today\n" "#color.project.garden=on green # Color of project:garden tasks\n"
"color.due=red # [4] Color of due tasks\n" "#color.tag.bug=yellow # Color of +bug tasks\n"
"#color.keyword.car=on blue # [5] Color of description.contains:car tasks\n" "color.active=black on bright green # Color of active tasks\n"
"#color.project.garden=on green # [6] Color of project:garden tasks\n" "color.pri.none= # Color of priority: tasks\n"
"#color.tag.bug=yellow # [7] Color of +bug tasks\n" "color.pri.H=bold white # Color of priority:H tasks\n"
"color.active=black on bright green # [8] Color of active tasks\n" "color.pri.M=white # Color of priority:M tasks\n"
"color.pri.none= # [9] Color of priority: tasks\n" "color.pri.L= # Color of priority:L tasks\n"
"color.pri.H=bold white # [9] Color of priority:H tasks\n" "color.tagged=green # Color of tagged tasks\n"
"color.pri.M=white # [9] Color of priority:M tasks\n" "color.blocked=black on white # Color of blocked tasks\n"
"color.pri.L= # [9] Color of priority:L tasks\n"
"color.tagged=green # [10] Color of tagged tasks\n"
"color.blocked=black on white # [11] Color of blocked tasks\n"
"color.alternate= # [12] Alternate color for line coloring\n"
#endif #endif
"\n"
"# 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,keyword,project,tag,recurring,pri,tagged\n"
"\n" "\n"
"# Shadow file support\n" "# Shadow file support\n"
"#shadow.file=/tmp/shadow.txt # Location of shadow file\n" "#shadow.file=/tmp/shadow.txt # Location of shadow file\n"
@ -395,6 +394,7 @@ std::string Config::defaults =
// //
// In all real use cases, Config::load is called. // In all real use cases, Config::load is called.
Config::Config () Config::Config ()
: original_file ()
{ {
} }

View file

@ -125,8 +125,6 @@ void Context::initialize ()
if (locale != "") if (locale != "")
stringtable.load (location.data + "/strings." + locale); stringtable.load (location.data + "/strings." + locale);
// TODO Handle "--version, -v" right here?
// init TDB. // init TDB.
tdb.clear (); tdb.clear ();
std::vector <std::string> all; std::vector <std::string> all;

View file

@ -744,6 +744,7 @@ int handleShow (std::string &outs)
"import.synonym.id import.synonym.uuid complete.all.projects complete.all.tags " "import.synonym.id import.synonym.uuid complete.all.projects complete.all.tags "
"search.case.sensitive hooks active.indicator tag.indicator recurrence.indicator " "search.case.sensitive hooks active.indicator tag.indicator recurrence.indicator "
"recurrence.limit list.all.projects list.all.tags undo.style verbose " "recurrence.limit list.all.projects list.all.tags undo.style verbose "
"rule.precedence.color "
#ifdef FEATURE_SHELL #ifdef FEATURE_SHELL
"shell.prompt " "shell.prompt "
#endif #endif

View file

@ -36,137 +36,251 @@
extern Context context; extern Context context;
static std::map <std::string, Color> gsColor; static std::map <std::string, Color> gsColor;
static std::vector <std::string> gsPrecedence;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void initializeColorRules () void initializeColorRules ()
{ {
std::vector <std::string> ruleNames; gsColor.clear ();
context.config.all (ruleNames); gsPrecedence.clear ();
foreach (it, ruleNames)
// Load all the configuration values, filter to only the ones that begin with
// "color.", then store name/value in gsColor, and name in rules.
std::vector <std::string> rules;
std::vector <std::string> variables;
context.config.all (variables);
foreach (it, variables)
{ {
if (it->substr (0, 6) == "color.") if (it->substr (0, 6) == "color.")
{ {
Color c (context.config.get (*it)); Color c (context.config.get (*it));
gsColor[*it] = c; gsColor[*it] = c;
rules.push_back (*it);
}
}
// Load the rule.precedence.color list, split it, then autocomplete against
// the 'rules' vector loaded above.
std::vector <std::string> results;
std::vector <std::string> precedence;
split (precedence, context.config.get ("rule.precedence.color"), ',');
foreach (it, precedence)
{
// Add the leading "color." string.
std::string rule = "color." + *it;
autoComplete (rule, rules, results);
foreach (r, results)
gsPrecedence.push_back (*r);
}
}
////////////////////////////////////////////////////////////////////////////////
static void colorizeBlocked (Task& task, const std::string& rule, Color& c)
{
if (gsColor[rule].nontrivial ())
if (task.get ("depends") != "")
c.blend (gsColor[rule]);
}
////////////////////////////////////////////////////////////////////////////////
static void colorizeTagged (Task& task, const std::string& rule, Color& c)
{
if (gsColor[rule].nontrivial ())
if (task.getTagCount ())
c.blend (gsColor[rule]);
}
////////////////////////////////////////////////////////////////////////////////
static void colorizePriorityL (Task& task, const std::string& rule, Color& c)
{
if (gsColor[rule].nontrivial ())
if (task.get ("priority") == "L")
c.blend (gsColor[rule]);
}
////////////////////////////////////////////////////////////////////////////////
static void colorizePriorityM (Task& task, const std::string& rule, Color& c)
{
if (gsColor[rule].nontrivial ())
if (task.get ("priority") == "M")
c.blend (gsColor[rule]);
}
////////////////////////////////////////////////////////////////////////////////
static void colorizePriorityH (Task& task, const std::string& rule, Color& c)
{
if (gsColor[rule].nontrivial ())
if (task.get ("priority") == "H")
c.blend (gsColor[rule]);
}
////////////////////////////////////////////////////////////////////////////////
static void colorizePriorityNone (Task& task, const std::string& rule, Color& c)
{
if (gsColor[rule].nontrivial ())
if (task.get ("priority") == "")
c.blend (gsColor[rule]);
}
////////////////////////////////////////////////////////////////////////////////
static void colorizeActive (Task& task, const std::string& rule, Color& c)
{
Task::status status = task.getStatus ();
if (gsColor[rule].nontrivial () &&
status != Task::completed &&
status != Task::deleted &&
task.has ("start"))
c.blend (gsColor[rule]);
}
////////////////////////////////////////////////////////////////////////////////
static void colorizeTag (Task& task, const std::string& rule, Color& c)
{
if (task.hasTag (rule.substr (10)))
c.blend (gsColor[rule]);
}
////////////////////////////////////////////////////////////////////////////////
static void colorizeProject (Task& task, const std::string& rule, Color& c)
{
// Observe the case sensitivity setting.
bool sensitive = context.config.getBoolean ("search.case.sensitive");
if (compare (task.get ("project"), rule.substr (14), sensitive))
c.blend (gsColor[rule]);
}
////////////////////////////////////////////////////////////////////////////////
static void colorizeProjectNone (Task& task, const std::string& rule, Color& c)
{
if (task.get ("project") == "")
c.blend (gsColor[rule]);
}
////////////////////////////////////////////////////////////////////////////////
static void colorizeTagNone (Task& task, const std::string& rule, Color& c)
{
if (task.getTagCount () == 0)
c.blend (gsColor[rule]);
}
////////////////////////////////////////////////////////////////////////////////
static void colorizeKeyword (Task& task, const std::string& rule, Color& c)
{
// 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]);
// Failing the description check, look at all annotations, returning on the
// first match.
else
{
Task::iterator it;
for (it = task.begin (); it != task.end (); ++it)
{
if (it->first.substr (0, 11) == "annotation_" &&
find (it->second.value (), rule.substr (14), sensitive) != std::string::npos)
{
c.blend (gsColor[rule]);
return;
}
} }
} }
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void autoColorize (Task& task, Color& c) static void colorizeDue (Task& task, const std::string& rule, Color& c)
{ {
// The special tag 'nocolor' overrides all auto colorization.
if (task.hasTag ("nocolor"))
return;
// Note: fg, bg already contain colors specifically assigned via command.
// Note: These rules form a hierarchy - the last rule is King.
Task::status status = task.getStatus (); Task::status status = task.getStatus ();
// Colorization of the blocked.
if (gsColor["color.blocked"].nontrivial ())
if (task.get ("depends") != "")
c.blend (gsColor["color.blocked"]);
// Colorization of the tagged.
if (gsColor["color.tagged"].nontrivial ())
if (task.getTagCount ())
c.blend (gsColor["color.tagged"]);
// Colorization of the low priority.
if (gsColor["color.pri.L"].nontrivial ())
if (task.get ("priority") == "L")
c.blend (gsColor["color.pri.L"]);
// Colorization of the medium priority.
if (gsColor["color.pri.M"].nontrivial ())
if (task.get ("priority") == "M")
c.blend (gsColor["color.pri.M"]);
// Colorization of the high priority.
if (gsColor["color.pri.H"].nontrivial ())
if (task.get ("priority") == "H")
c.blend (gsColor["color.pri.H"]);
// Colorization of the priority-less.
if (gsColor["color.pri.none"].nontrivial ())
if (task.get ("priority") == "")
c.blend (gsColor["color.pri.none"]);
// Colorization of the active, if not completed/deleted.
if (gsColor["color.active"].nontrivial () &&
status != Task::completed &&
status != Task::deleted)
if (task.has ("start"))
c.blend (gsColor["color.active"]);
// Colorization by tag value.
std::map <std::string, Color>::iterator it;
for (it = gsColor.begin (); it != gsColor.end (); ++it)
{
if (it->first.substr (0, 10) == "color.tag.")
{
std::string value = it->first.substr (10);
if (task.hasTag (value))
c.blend (it->second);
}
}
// Colorization by project name.
for (it = gsColor.begin (); it != gsColor.end (); ++it)
{
if (it->first.substr (0, 14) == "color.project.")
{
std::string value = lowerCase (it->first.substr (14));
std::string project = lowerCase (task.get ("project"));
if (project.find (value) == 0)
c.blend (it->second);
}
}
// Colorization by keyword.
for (it = gsColor.begin (); it != gsColor.end (); ++it)
{
if (it->first.substr (0, 14) == "color.keyword.")
{
std::string value = lowerCase (it->first.substr (14));
std::string desc = lowerCase (task.get ("description"));
if (desc.find (value) != std::string::npos)
c.blend (it->second);
}
}
// Colorization of the due and overdue.
if (task.has ("due") && if (task.has ("due") &&
status != Task::completed && status != Task::completed &&
status != Task::deleted) status != Task::deleted)
{ {
std::string due = task.get ("due"); if (getDueState (task.get ("due")) == 1)
switch (getDueState (due)) c.blend (gsColor[rule]);
}
}
////////////////////////////////////////////////////////////////////////////////
static void colorizeDueToday (Task& task, const std::string& rule, Color& c)
{ {
case 1: // imminent Task::status status = task.getStatus ();
c.blend (gsColor["color.due"]);
break;
case 2: // today if (task.has ("due") &&
c.blend (gsColor["color.due.today"]); status != Task::completed &&
break; status != Task::deleted)
{
case 3: // overdue if (getDueState (task.get ("due")) == 2)
c.blend (gsColor["color.overdue"]); c.blend (gsColor[rule]);
break;
case 0: // not due at all
default:
break;
} }
} }
// Colorization of the recurring. ////////////////////////////////////////////////////////////////////////////////
if (gsColor["color.recurring"].nontrivial ()) static void colorizeOverdue (Task& task, const std::string& rule, Color& c)
{
Task::status status = task.getStatus ();
if (task.has ("due") &&
status != Task::completed &&
status != Task::deleted)
{
if (getDueState (task.get ("due")) == 3)
c.blend (gsColor[rule]);
}
}
////////////////////////////////////////////////////////////////////////////////
static void colorizeRecurring (Task& task, const std::string& rule, Color& c)
{
if (gsColor[rule].nontrivial ())
if (task.has ("recur")) if (task.has ("recur"))
c.blend (gsColor["color.recurring"]); c.blend (gsColor[rule]);
}
////////////////////////////////////////////////////////////////////////////////
void autoColorize (Task& task, Color& c)
{
// The special tag 'nocolor' overrides all auto and specific colorization.
if (task.hasTag ("nocolor"))
{
c = Color ();
return;
}
// Note: c already contains colors specifically assigned via command.
// Note: These rules form a hierarchy - the last rule is King, hence the
// reverse iterator.
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.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);
// Wildcards
else if (r->substr (0, 9) == "color.tag") colorizeTag (task, *r, c);
else if (r->substr (0, 13) == "color.project") colorizeProject (task, *r, c);
else if (r->substr (0, 13) == "color.keyword") colorizeKeyword (task, *r, c);
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
## taskwarrior - a command line task list manager. ## taskwarrior - a command line task list manager.
## ##
## Copyright 2006 - 2010, Paul Beckingham. ## Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez.
## All rights reserved. ## All rights reserved.
## ##
## This program is free software; you can redistribute it and/or modify it under ## This program is free software; you can redistribute it and/or modify it under
@ -28,15 +28,18 @@
use strict; use strict;
use warnings; use warnings;
use Test::More tests => 8; use Test::More tests => 9;
# Create the rc file. # Create the rc file.
if (open my $fh, '>', 'color.rc') if (open my $fh, '>', 'color.rc')
{ {
print $fh "data.location=.\n", print $fh "data.location=.\n",
"search.case.sensitive=yes\n",
"color=on\n",
"color.alternate=\n", "color.alternate=\n",
"color.keyword.red=red\n", "color.keyword.red=red\n",
"color.keyword.green=green\n", "color.keyword.green=green\n",
"color.keyword.yellow=yellow\n",
"_forcecolor=1\n"; "_forcecolor=1\n";
close $fh; close $fh;
ok (-r 'color.rc', 'Created color.rc'); ok (-r 'color.rc', 'Created color.rc');
@ -46,11 +49,14 @@ if (open my $fh, '>', 'color.rc')
qx{../task rc:color.rc add nothing}; qx{../task rc:color.rc add nothing};
qx{../task rc:color.rc add red}; qx{../task rc:color.rc add red};
qx{../task rc:color.rc add green}; qx{../task rc:color.rc add green};
qx{../task rc:color.rc add -- annotation};
qx{../task rc:color.rc 4 annotate yellow};
my $output = qx{../task rc:color.rc list}; my $output = qx{../task rc:color.rc list};
like ($output, qr/ (?!<\033\[\d\dm) .* nothing .* (?!>\033\[0m) /x, 'none'); like ($output, qr/ (?!<\033\[\d\dm) .* nothing .* (?!>\033\[0m) /x, 'none');
like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.keyword.red'); like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.keyword.red');
like ($output, qr/ \033\[32m .* green .* \033\[0m /x, 'color.keyword.green'); like ($output, qr/ \033\[32m .* green .* \033\[0m /x, 'color.keyword.green');
like ($output, qr/ \033\[33m .* annotation .* \033\[0m /x, 'color.keyword.yellow (annotation)');
# Cleanup. # Cleanup.
unlink 'pending.data'; unlink 'pending.data';

View file

@ -35,6 +35,7 @@ if (open my $fh, '>', 'color.rc')
{ {
print $fh "data.location=.\n", print $fh "data.location=.\n",
"color.project.x=red\n", "color.project.x=red\n",
"color.project.none=green\n",
"color.alternate=\n", "color.alternate=\n",
"_forcecolor=1\n"; "_forcecolor=1\n";
close $fh; close $fh;
@ -46,7 +47,7 @@ qx{../task rc:color.rc add nothing};
qx{../task rc:color.rc add project:x red}; qx{../task rc:color.rc add project:x red};
my $output = qx{../task rc:color.rc list}; my $output = qx{../task rc:color.rc list};
like ($output, qr/ (?!<\033\[\d\dm) .* nothing .* (?!>\033\[0m) /x, 'none'); like ($output, qr/ \033\[32m .* nothing .* \033\[0m /x, 'color.project.none');
like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.project.red'); like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.project.red');
# Cleanup. # Cleanup.

View file

@ -36,6 +36,7 @@ if (open my $fh, '>', 'color.rc')
print $fh "data.location=.\n", print $fh "data.location=.\n",
"color.tagged=\n", "color.tagged=\n",
"color.alternate=\n", "color.alternate=\n",
"color.tag.none=yellow\n",
"color.tag.red=red\n", "color.tag.red=red\n",
"color.tag.green=green\n", "color.tag.green=green\n",
"_forcecolor=1\n"; "_forcecolor=1\n";
@ -49,7 +50,7 @@ qx{../task rc:color.rc add +red red};
qx{../task rc:color.rc add +green green}; qx{../task rc:color.rc add +green green};
my $output = qx{../task rc:color.rc list}; my $output = qx{../task rc:color.rc list};
like ($output, qr/ (?!<\033\[\d\dm) .* nothing .* (?!>\033\[0m) /x, 'none'); like ($output, qr/ \033\[33m .* nothing .* \033\[0m /x, 'color.tag.none');
like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.tag.red'); like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.tag.red');
like ($output, qr/ \033\[32m .* green .* \033\[0m /x, 'color.tag.green'); like ($output, qr/ \033\[32m .* green .* \033\[0m /x, 'color.tag.green');