Merge branch '1.9.3' of tasktools.org:task into 1.9.3

Conflicts:
	src/Config.cpp
This commit is contained in:
Johannes Schlatow
2010-09-02 01:53:25 +02:00
27 changed files with 663 additions and 338 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.
@@ -57,6 +61,8 @@
and overdue. and overdue.
+ Fixed bug #459, which showed a confusing message when 'limit:page' was + Fixed bug #459, which showed a confusing message when 'limit:page' was
used, with few tasks. used, with few tasks.
+ Fixed bug #461, in which the filter 'due:today' failed, but 'due.is:today'
worked.
+ Fixed bug #466, which gave the wrong error message when a custom report + Fixed bug #466, which gave the wrong error message when a custom report
was missing a direction indicator for the sort order. was missing a direction indicator for the sort order.
+ Fixed bug #470, which caused task to not support the color 'none'. + Fixed bug #470, which caused task to not support the color 'none'.
@@ -67,6 +73,7 @@
+ Fixed problem with the 'undo' command not observing the rc.color or the + Fixed problem with the 'undo' command not observing the rc.color or the
rc._forcecolor settings. rc._forcecolor settings.
+ Fixed problem with extra blank line in the ghistory reports. + Fixed problem with extra blank line in the ghistory reports.
+ Fixed a precision problem with average age on the summary report.
+ Clarified the documentation regarding the project name (taskwarrior) and + Clarified the documentation regarding the project name (taskwarrior) and
the program name (task). the program name (task).

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

@@ -537,39 +537,50 @@ terminal, can be obtained by running the command:
.RE .RE
.RS .RS
The coloration rules and their defaults are: Note that no default values are listed here - the defaults now correspond to the
dark-256.theme (Linux) and dark-16.theme (other) theme values.
The coloration rules are as follows:
.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 +701,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

@@ -60,6 +60,8 @@ color.pri.H=bold white
color.pri.M=white color.pri.M=white
color.pri.L= color.pri.L=
color.tagged=green color.tagged=green
color.blocked=black on white # placeholder color color.blocked=black on white
color.project.none=
color.tag.none=
color.alternate= color.alternate=

View File

@@ -60,6 +60,8 @@ color.pri.H=color255
color.pri.M=color250 color.pri.M=color250
color.pri.L=color245 color.pri.L=color245
color.tagged=rgb031 color.tagged=rgb031
color.blocked=black on white # placeholder color color.blocked=on gray4
color.project.none=
color.tag.none=
color.alternate=on color233 color.alternate=on color233

View File

@@ -60,6 +60,8 @@ color.pri.H=rgb035
color.pri.M=rgb025 color.pri.M=rgb025
color.pri.L=rgb015 color.pri.L=rgb015
color.tagged=color246 color.tagged=color246
color.blocked=black on white # placeholder color color.blocked=on gray4
color.project.none=
color.tag.none=
color.alternate=on color233 color.alternate=on color233

View File

@@ -60,6 +60,8 @@ color.pri.H=rgb050
color.pri.M=rgb030 color.pri.M=rgb030
color.pri.L=rgb010 color.pri.L=rgb010
color.tagged=color246 color.tagged=color246
color.blocked=black on white # placeholder color color.blocked=on gray4
color.project.none=
color.tag.none=
color.alternate=on color233 color.alternate=on color233

View File

@@ -60,6 +60,8 @@ color.pri.H=rgb500
color.pri.M=rgb400 color.pri.M=rgb400
color.pri.L=rgb300 color.pri.L=rgb300
color.tagged=color246 color.tagged=color246
color.blocked=black on white # placeholder color color.blocked=on gray4
color.project.none=
color.tag.none=
color.alternate=on color233 color.alternate=on color233

View File

@@ -60,6 +60,8 @@ color.pri.H=bold black
color.pri.M=black color.pri.M=black
color.pri.L= color.pri.L=
color.tagged=green color.tagged=green
color.blocked=black on white # placeholder color color.blocked=black on white
color.project.none=
color.tag.none=
color.alternate= color.alternate=

View File

@@ -59,6 +59,8 @@ color.pri.H=color232
color.pri.M=color237 color.pri.M=color237
color.pri.L=color242 color.pri.L=color242
color.tagged=rgb020 color.tagged=rgb020
color.blocked=black on white # placeholder color color.blocked=on gray4
color.project.none=
color.tag.none=
color.alternate=on color254 color.alternate=on color254

View File

@@ -438,11 +438,11 @@ bool Att::validMod (const std::string& mod)
std::string Att::type (const std::string& name) const std::string Att::type (const std::string& name) const
{ {
if (name == "due" || if (name == "due" ||
name == "wait" ||
name == "until" || name == "until" ||
name == "start" || name == "start" ||
name == "entry" || name == "entry" ||
name == "end" || name == "end")
name == "wait")
return "date"; return "date";
else if (name == "recur") else if (name == "recur")
@@ -542,16 +542,17 @@ bool Att::match (const Att& other) const
if (mMod == "") if (mMod == "")
{ {
// Exact matches on dates should only compare m/d/y, not h:m:s. This allows // Exact matches on dates should only compare m/d/y, not h:m:s. This allows
// Comapisons like "task list due:today" (bug #405). // comparisons like "task list due:today" (bug #405).
std::string which = type (mName); std::string which = type (mName);
if (which == "date") if (which == "date")
{ {
if (other.mValue == "")
return false;
Date left (mValue); Date left (mValue);
Date right (other.mValue); Date right (other.mValue);
if (left.year () != right.year () || if (! left.sameDay (right))
left.month () != right.month () ||
left.day () != right.day ())
return false; return false;
} }
else else

View File

@@ -124,6 +124,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"
@@ -143,29 +144,28 @@ 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.project.none= # Color of tasks with no project\n"
"#color.keyword.car=on blue # [5] Color of description.contains:car tasks\n" "#color.tag.bug=yellow # Color of +bug tasks\n"
"#color.project.garden=on green # [6] Color of project:garden tasks\n" "#color.tag.none= # Color of tag-less tasks\n"
"#color.tag.bug=yellow # [7] Color of +bug tasks\n" "color.active=rgb555 on rgb410 # Color of active tasks\n"
"color.active=rgb555 on rgb410 # [8] Color of active tasks\n" "color.pri.none= # Color of priority: tasks\n"
"color.pri.none= # [9] Color of priority: tasks\n" "color.pri.H=rgb255 # Color of priority:H tasks\n"
"color.pri.H=rgb255 # [9] Color of priority:H tasks\n" "color.pri.M=rgb250 # Color of priority:M tasks\n"
"color.pri.M=rgb250 # [9] Color of priority:M tasks\n" "color.pri.L=rgb245 # Color of priority:L tasks\n"
"color.pri.L=rgb245 # [9] Color of priority:L tasks\n" "color.tagged=rgb031 # Color of tagged tasks\n"
"color.tagged=rgb031 # [10] Color of tagged tasks\n" "color.blocked=black on white # Color of blocked 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"
@@ -185,26 +185,29 @@ 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.project.none= # Color of tasks with no project\n"
"#color.keyword.car=on blue # [5] Color of description.contains:car tasks\n" "#color.tag.bug=yellow # Color of +bug tasks\n"
"#color.project.garden=on green # [6] Color of project:garden tasks\n" "#color.tag.none= # Color of tag-less tasks\n"
"#color.tag.bug=yellow # [7] Color of +bug tasks\n" "color.active=black on bright green # Color of active tasks\n"
"color.active=black on bright green # [8] Color of active tasks\n" "color.pri.none= # Color of priority: tasks\n"
"color.pri.none= # [9] Color of priority: tasks\n" "color.pri.H=bold white # Color of priority:H tasks\n"
"color.pri.H=bold white # [9] Color of priority:H tasks\n" "color.pri.M=white # Color of priority:M tasks\n"
"color.pri.M=white # [9] Color of priority:M tasks\n" "color.pri.L= # Color of priority:L tasks\n"
"color.pri.L= # [9] Color of priority:L tasks\n" "color.tagged=green # Color of tagged tasks\n"
"color.tagged=green # [10] Color of tagged tasks\n" "color.blocked=black on white # Color of blocked 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"
@@ -396,6 +399,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

@@ -812,6 +812,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
@@ -2032,7 +2033,7 @@ int handleColor (std::string &outs)
// actual colors. // actual colors.
if (*item != "_forcecolor" && if (*item != "_forcecolor" &&
*item != "color" && *item != "color" &&
item->find ("color") != std::string::npos) item->find ("color") == 0)
{ {
int row = table.addRow (); int row = table.addRow ();
table.addCell (row, 0, *item); table.addCell (row, 0, *item);

View File

@@ -154,11 +154,15 @@ bool dependencyChainBroken (Task& task)
std::string dependencyNag (Task& task) std::string dependencyNag (Task& task)
{ {
std::stringstream out; std::stringstream out;
if (task.has ("depends"))
{
out << "# dependencyNag " out << "# dependencyNag "
<< task.id << task.id
<< " " << " "
<< task.get ("uuid") << task.get ("uuid")
<< "\n"; << "\n";
}
return out.str (); return out.str ();
} }

View File

@@ -114,6 +114,8 @@ void handleRecurrence ()
sprintf (indexMask, "%u", (unsigned int) i); sprintf (indexMask, "%u", (unsigned int) i);
rec.set ("imask", indexMask); // Store index into mask. rec.set ("imask", indexMask); // Store index into mask.
rec.remove ("mask"); // Remove the mask of the parent.
// Add the new task to the vector, for immediate use. // Add the new task to the vector, for immediate use.
modified.push_back (rec); modified.push_back (rec);

View File

@@ -470,9 +470,6 @@ int handleInfo (std::string &outs)
} }
} }
if (task->getStatus () == Task::recurring ||
task->has ("parent"))
{
// recur // recur
if (task->has ("recur")) if (task->has ("recur"))
{ {
@@ -499,20 +496,19 @@ int handleInfo (std::string &outs)
} }
// mask // mask
if (task->has ("mask")) if (task->getStatus () == Task::recurring)
{ {
row = table.addRow (); row = table.addRow ();
table.addCell (row, 0, "Mask"); table.addCell (row, 0, "Mask");
table.addCell (row, 1, task->get ("mask")); table.addCell (row, 1, task->get ("mask"));
} }
// parent
if (task->has ("parent")) if (task->has ("parent"))
{ {
// parent
row = table.addRow (); row = table.addRow ();
table.addCell (row, 0, "Parent task"); table.addCell (row, 0, "Parent task");
table.addCell (row, 1, task->get ("parent")); table.addCell (row, 1, task->get ("parent"));
}
// imask // imask
row = table.addRow (); row = table.addRow ();
@@ -759,7 +755,7 @@ int handleReportSummary (std::string &outs)
table.addCell (row, 0, (i->first == "" ? "(none)" : i->first)); table.addCell (row, 0, (i->first == "" ? "(none)" : i->first));
table.addCell (row, 1, countPending[i->first]); table.addCell (row, 1, countPending[i->first]);
if (counter[i->first]) if (counter[i->first])
table.addCell (row, 2, Duration ((int) sumEntry[i->first] / counter[i->first]).format ()); table.addCell (row, 2, Duration ((int) (sumEntry[i->first] / (double)counter[i->first])).format ());
int c = countCompleted[i->first]; int c = countCompleted[i->first];
int p = countPending[i->first]; int p = countPending[i->first];

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

@@ -28,7 +28,7 @@
use strict; use strict;
use warnings; use warnings;
use Test::More tests => 13; use Test::More tests => 40;
# Create the rc file. # Create the rc file.
if (open my $fh, '>', 'bug.rc') if (open my $fh, '>', 'bug.rc')
@@ -59,6 +59,67 @@ $output = qx{../task rc:bug.rc long -\@strange};
like ($output, qr/one/, '+ordinary implicitly included'); like ($output, qr/one/, '+ordinary implicitly included');
unlike ($output, qr/two/, '@strange explicitly excluded'); unlike ($output, qr/two/, '@strange explicitly excluded');
# Bug #XXX - '-t1 -t2' doesn't seem to work, when @ characters are involved.
unlink 'pending.data';
qx{../task rc:bug.rc add one +t1};
qx{../task rc:bug.rc add two +t2};
qx{../task rc:bug.rc add three +t3};
my $output = qx{../task rc:bug.rc list -t1};
unlike ($output, qr/one/, 'Single: no t1');
like ($output, qr/two/, 'Single: yes t2');
like ($output, qr/three/, 'Single: yes t3');
$output = qx{../task rc:bug.rc list -t1 -t2};
unlike ($output, qr/one/, 'Double: no t1');
unlike ($output, qr/two/, 'Double: no t2');
like ($output, qr/three/, 'Double: yes t3');
$output = qx{../task rc:bug.rc list -t1 -t2 -t3};
unlike ($output, qr/one/, 'Triple: no t1');
unlike ($output, qr/two/, 'Triple: no t2');
unlike ($output, qr/three/, 'Triple: no t3');
# Once again, with @ characters.
qx{../task rc:bug.rc 1 +\@1};
qx{../task rc:bug.rc 2 +\@2};
qx{../task rc:bug.rc 3 +\@3};
$output = qx{../task rc:bug.rc list -\@1};
unlike ($output, qr/one/, 'Single: no @1');
like ($output, qr/two/, 'Single: yes @2');
like ($output, qr/three/, 'Single: yes @3');
$output = qx{../task rc:bug.rc list -\@1 -\@2};
unlike ($output, qr/one/, 'Double: no @1');
unlike ($output, qr/two/, 'Double: no @2');
like ($output, qr/three/, 'Double: yes @3');
$output = qx{../task rc:bug.rc list -\@1 -\@2 -\@3};
unlike ($output, qr/one/, 'Triple: no @1');
unlike ($output, qr/two/, 'Triple: no @2');
unlike ($output, qr/three/, 'Triple: no @3');
# Once again, with @ characters and punctuation.
qx{../task rc:bug.rc 1 +\@foo.1};
qx{../task rc:bug.rc 2 +\@foo.2};
qx{../task rc:bug.rc 3 +\@foo.3};
$output = qx{../task rc:bug.rc list -\@foo.1};
unlike ($output, qr/one/, 'Single: no @foo.1');
like ($output, qr/two/, 'Single: yes @foo.2');
like ($output, qr/three/, 'Single: yes @foo.3');
$output = qx{../task rc:bug.rc list -\@foo.1 -\@foo.2};
unlike ($output, qr/one/, 'Double: no @foo.1');
unlike ($output, qr/two/, 'Double: no @foo.2');
like ($output, qr/three/, 'Double: yes @foo.3');
$output = qx{../task rc:bug.rc list -\@foo.1 -\@foo.2 -\@foo.3};
unlike ($output, qr/one/, 'Triple: no @foo.1');
unlike ($output, qr/two/, 'Triple: no @foo.2');
unlike ($output, qr/three/, 'Triple: no @foo.3');
# Cleanup. # Cleanup.
unlink 'pending.data'; unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data'); ok (!-r 'pending.data', 'Removed pending.data');

66
src/tests/bug.485.x Executable file
View File

@@ -0,0 +1,66 @@
#! /usr/bin/perl
################################################################################
## taskwarrior - a command line task list manager.
##
## Copyright 2006 - 2010, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 9;
# Create the rc file.
if (open my $fh, '>', 'bug.rc')
{
print $fh "data.location=.\n";
close $fh;
ok (-r 'bug.rc', 'Created bug.rc');
}
# Bug #485 - 'task list recur:month' doesn't list monthly tasks
qx{../task rc:bug.rc add one due:tomorrow recur:monthly};
qx{../task rc:bug.rc add two due:tomorrow recur:month};
my $output = qx{../task rc:bug.rc list recur:monthly};
like ($output, qr/one/, 'monthly -> monthly');
like ($output, qr/two/, 'month -> monthly');
$output = qx{../task rc:bug.rc list recur:month};
like ($output, qr/one/, 'monthly -> month');
like ($output, qr/two/, 'month -> month');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'completed.data';
ok (!-r 'completed.data', 'Removed completed.data');
unlink 'undo.data';
ok (!-r 'undo.data', 'Removed undo.data');
unlink 'bug.rc';
ok (!-r 'bug.rc', 'Removed bug.rc');
exit 0;

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');

View File

@@ -28,7 +28,7 @@
use strict; use strict;
use warnings; use warnings;
use Test::More tests => 7; use Test::More tests => 9;
# Create the rc file. # Create the rc file.
if (open my $fh, '>', 'due.rc') if (open my $fh, '>', 'due.rc')
@@ -57,6 +57,13 @@ my $output = qx{../task rc:due.rc list};
like ($output, qr/\[31m.+$just.+\[0m/, 'one marked due'); like ($output, qr/\[31m.+$just.+\[0m/, 'one marked due');
like ($output, qr/\s+$almost\s+/, 'two not marked due'); like ($output, qr/\s+$almost\s+/, 'two not marked due');
qx{../task rc:due.rc add three due:today};
$output = qx{../task rc:due.rc list due:today};
like ($output, qr/three/, 'due:today works as a filter');
$output = qx{../task rc:due.rc list due.is:today};
like ($output, qr/three/, 'due.is:today works as a filter');
# Cleanup. # Cleanup.
unlink 'pending.data'; unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data'); ok (!-r 'pending.data', 'Removed pending.data');

View File

@@ -71,8 +71,8 @@ qx{../task rc:wait.rc add wait:tomorrow tomorrow};
$output = qx{../task rc:wait.rc ls}; $output = qx{../task rc:wait.rc ls};
unlike ($output, qr/tomorrow/ms, 'waiting task invisible'); unlike ($output, qr/tomorrow/ms, 'waiting task invisible');
$output = qx{../task rc:wait.rc ls wait:tomorrow}; $output = qx{../task rc:wait.rc all status:waiting wait:tomorrow};
like ($output, qr/tomorrow/ms, 'waiting task visible when specifically asked for it'); like ($output, qr/tomorrow/ms, 'waiting task visible when specifically queried');
# Cleanup. # Cleanup.
unlink 'pending.data'; unlink 'pending.data';