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

@@ -415,7 +415,7 @@ bool Att::validNameValue (
"\" is not a valid status. Use 'pending', 'completed', 'deleted', 'recurring' or 'waiting'."; "\" is not a valid status. Use 'pending', 'completed', 'deleted', 'recurring' or 'waiting'.";
} }
else if (! validInternalName (name) && else if (! validInternalName (name) &&
! validModifiableName (name)) ! validModifiableName (name))
throw std::string ("'") + name + "' is not a recognized attribute."; throw std::string ("'") + name + "' is not a recognized attribute.";
@@ -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

@@ -59,172 +59,175 @@ std::string Config::defaults =
"\n" "\n"
"# Files\n" "# Files\n"
"data.location=~/.task\n" "data.location=~/.task\n"
"locking=on # Use file-level locking\n" "locking=on # Use file-level locking\n"
"\n" "\n"
"# Terminal\n" "# Terminal\n"
"curses=on # Use ncurses library to determine terminal width\n" "curses=on # Use ncurses library to determine terminal width\n"
"defaultwidth=80 # Without ncurses, assumed width\n" "defaultwidth=80 # Without ncurses, assumed width\n"
"#editor=vi # Preferred text editor\n" "#editor=vi # Preferred text editor\n"
"\n" "\n"
"# Miscellaneous\n" "# Miscellaneous\n"
"verbose=yes # Provide extra feedback\n" "verbose=yes # Provide extra feedback\n"
"confirmation=yes # Confirmation on delete, big changes\n" "confirmation=yes # Confirmation on delete, big changes\n"
"echo.command=yes # Details on command just run\n" "echo.command=yes # Details on command just run\n"
"annotations=full # Level of verbosity for annotations: full, sparse or none\n" "annotations=full # Level of verbosity for annotations: full, sparse or none\n"
"next=2 # How many tasks per project in next report\n" "next=2 # How many tasks per project in next report\n"
"bulk=2 # > 2 tasks considered 'a lot', for confirmation\n" "bulk=2 # > 2 tasks considered 'a lot', for confirmation\n"
"nag=You have higher priority tasks. # Nag message to keep you honest\n" // TODO "nag=You have higher priority tasks. # Nag message to keep you honest\n" // TODO
"search.case.sensitive=yes # Setting to no allows case insensitive searches\n" "search.case.sensitive=yes # Setting to no allows case insensitive searches\n"
"active.indicator=* # What to show as an active task indicator\n" "active.indicator=* # What to show as an active task indicator\n"
"tag.indicator=+ # What to show as a tag indicator\n" "tag.indicator=+ # What to show as a tag indicator\n"
"recurrence.indicator=R # What to show as a task recurrence indicator\n" "recurrence.indicator=R # What to show as a task recurrence indicator\n"
"recurrence.limit=1 # Number of future recurring pending tasks\n" "recurrence.limit=1 # Number of future recurring pending tasks\n"
"undo.style=side # Undo style - can be 'side', or 'diff'\n" "undo.style=side # Undo style - can be 'side', or 'diff'\n"
"merge.autopush=ask # Push database to remote origin after merge: yes, no, ask\n" "merge.autopush=ask # Push database to remote origin after merge: yes, no, ask\n"
"\n" "\n"
"# Dates\n" "# Dates\n"
"dateformat=m/d/Y # Preferred input and display date format\n" "dateformat=m/d/Y # Preferred input and display date format\n"
"dateformat.holiday=YMD # Preferred input date format for holidays\n" "dateformat.holiday=YMD # Preferred input date format for holidays\n"
"dateformat.report=m/d/Y # Preferred display date format for reports\n" "dateformat.report=m/d/Y # Preferred display date format for reports\n"
"dateformat.annotation=m/d/Y # Preferred display date format for reports\n" "dateformat.annotation=m/d/Y # Preferred display date format for reports\n"
"weekstart=Sunday # Sunday or Monday only\n" "weekstart=Sunday # Sunday or Monday only\n"
"displayweeknumber=yes # Show week numbers on calendar\n" "displayweeknumber=yes # Show week numbers on calendar\n"
"due=7 # Task is considered due in 7 days\n" "due=7 # Task is considered due in 7 days\n"
"\n" "\n"
"# Calendar controls\n" "# Calendar controls\n"
"calendar.legend=yes # Display the legend on calendar\n" "calendar.legend=yes # Display the legend on calendar\n"
"calendar.details=sparse # Calendar shows information for tasks w/due dates: full, sparse or none\n" "calendar.details=sparse # Calendar shows information for tasks w/due dates: full, sparse or none\n"
"calendar.details.report=list # Report to use when showing task information in cal\n" "calendar.details.report=list # Report to use when showing task information in cal\n"
"calendar.holidays=none # Show public holidays on calendar:full, sparse or none\n" "calendar.holidays=none # Show public holidays on calendar:full, sparse or none\n"
"#monthsperline=3 # Number of calendar months on a line\n" "#monthsperline=3 # Number of calendar months on a line\n"
"\n" "\n"
"# Journal controls\n" "# Journal controls\n"
"journal.time=no # Record start/stop commands as annotation\n" "journal.time=no # Record start/stop commands as annotation\n"
"journal.time.start.annotation=Started task # Annotation description for the start journal entry\n" "journal.time.start.annotation=Started task # Annotation description for the start journal entry\n"
"journal.time.stop.annotation=Stopped task # Annotation description for the stop journal entry\n" "journal.time.stop.annotation=Stopped task # Annotation description for the stop journal entry\n"
"\n" "\n"
"# Urgency Coefficients\n" "# Urgency Coefficients\n"
"urgency.next.coefficient=10.0 # Urgency coefficients for 'next' special tag\n" "urgency.next.coefficient=10.0 # Urgency coefficients for 'next' special tag\n"
"urgency.blocking.coefficient=9.0 # Urgency coefficients for blocking tasks\n" "urgency.blocking.coefficient=9.0 # Urgency coefficients for blocking tasks\n"
"urgency.blocked.coefficient=8.0 # Urgency coefficients for blocked tasks\n" "urgency.blocked.coefficient=8.0 # Urgency coefficients for blocked tasks\n"
"urgency.due.coefficient=7.0 # Urgency coefficients for due dates\n" "urgency.due.coefficient=7.0 # Urgency coefficients for due dates\n"
"urgency.priority.coefficient=6.0 # Urgency coefficients for priorities\n" "urgency.priority.coefficient=6.0 # Urgency coefficients for priorities\n"
"urgency.waiting.coefficient=5.0 # Urgency coefficients for waiting status\n" "urgency.waiting.coefficient=5.0 # Urgency coefficients for waiting status\n"
"urgency.active.coefficient=4.0 # Urgency coefficients for active tasks\n" "urgency.active.coefficient=4.0 # Urgency coefficients for active tasks\n"
"urgency.project.coefficient=3.0 # Urgency coefficients for projects\n" "urgency.project.coefficient=3.0 # Urgency coefficients for projects\n"
"urgency.tags.coefficient=2.0 # Urgency coefficients for tags\n" "urgency.tags.coefficient=2.0 # Urgency coefficients for tags\n"
"urgency.annotations.coefficient=1.0 # Urgency coefficients for annotations\n" "urgency.annotations.coefficient=1.0 # Urgency coefficients for annotations\n"
"\n" "\n"
"#urgency.user.project.foo.coefficient=5.0 # Urgency coefficients for 'foo' project\n" "#urgency.user.project.foo.coefficient=5.0 # Urgency coefficients for 'foo' project\n"
"#urgency.user.tag.foo.coefficient=5.0 # Urgency coefficients for 'foo' tag\n" "#urgency.user.tag.foo.coefficient=5.0 # Urgency coefficients for 'foo' tag\n"
"\n" "\n"
"# Color controls.\n" "# Color controls.\n"
"color=on # Enable color\n" "color=on # Enable color\n"
#ifdef LINUX #ifdef LINUX
"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"
"\n" "\n"
"color.history.add=color0 on rgb500 # Color of added tasks in ghistory report\n" "color.history.add=color0 on rgb500 # Color of added tasks in ghistory report\n"
"color.history.done=color0 on rgb050 # Color of completed tasks in ghistory report\n" "color.history.done=color0 on rgb050 # Color of completed tasks in ghistory report\n"
"color.history.delete=color0 on rgb550 # Color of deleted tasks in ghistory report\n" "color.history.delete=color0 on rgb550 # Color of deleted tasks in ghistory report\n"
"\n" "\n"
"color.undo.before=color1 # Color of values before a change\n" "color.undo.before=color1 # Color of values before a change\n"
"color.undo.after=color2 # Color of values after a change\n" "color.undo.after=color2 # Color of values after a change\n"
"\n" "\n"
"color.calendar.today=color15 on rgb013 # Color of today in calendar\n" "color.calendar.today=color15 on rgb013 # Color of today in calendar\n"
"color.calendar.due=color0 on color1 # Color of days with due tasks in calendar\n" "color.calendar.due=color0 on color1 # Color of days with due tasks in calendar\n"
"color.calendar.due.today=color15 on color1 # Color of today with due tasks in calendar\n" "color.calendar.due.today=color15 on color1 # Color of today with due tasks in calendar\n"
"color.calendar.overdue=color0 on color9 # Color of days with overdue tasks in calendar\n" "color.calendar.overdue=color0 on color9 # Color of days with overdue tasks in calendar\n"
"color.calendar.weekend=color235 # Color of weekend days in calendar\n" "color.calendar.weekend=color235 # Color of weekend days in calendar\n"
"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"
"\n" "\n"
"color.history.add=black on red # Color of added tasks in ghistory report\n" "color.history.add=black on red # Color of added tasks in ghistory report\n"
"color.history.done=black on green # Color of completed tasks in ghistory report\n" "color.history.done=black on green # Color of completed tasks in ghistory report\n"
"color.history.delete=black on yellow # Color of deleted tasks in ghistory report\n" "color.history.delete=black on yellow # Color of deleted tasks in ghistory report\n"
"\n" "\n"
"color.undo.before=red # Color of values before a change\n" "color.undo.before=red # Color of values before a change\n"
"color.undo.after=green # Color of values after a change\n" "color.undo.after=green # Color of values after a change\n"
"\n" "\n"
"color.calendar.today=bold white on bright blue # Color of today in calendar\n" "color.calendar.today=bold white on bright blue # Color of today in calendar\n"
"color.calendar.due=white on red # Color of days with due tasks in calendar\n" "color.calendar.due=white on red # Color of days with due tasks in calendar\n"
"color.calendar.due.today=bold white on red # Color of today with due tasks in calendar\n" "color.calendar.due.today=bold white on red # Color of today with due tasks in calendar\n"
"color.calendar.overdue=black on bright red # Color of days with overdue tasks in calendar\n" "color.calendar.overdue=black on bright red # Color of days with overdue tasks in calendar\n"
"color.calendar.weekend=white on bright black # Color of weekend days in calendar\n" "color.calendar.weekend=white on bright black # Color of weekend days in calendar\n"
"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"
"#shadow.command=list # Task command for shadow file\n" "#shadow.command=list # Task command for shadow file\n"
"#shadow.notify=on # Footnote when updated\n" "#shadow.notify=on # Footnote when updated\n"
"\n" "\n"
"#default.project=foo # Default project for 'add' command\n" "#default.project=foo # Default project for 'add' command\n"
"#default.priority=M # Default priority for 'add' command\n" "#default.priority=M # Default priority for 'add' command\n"
"default.command=list # When no arguments are specified\n" "default.command=list # When no arguments are specified\n"
"\n" "\n"
"_forcecolor=no # Forces color to be on, even for non TTY output\n" "_forcecolor=no # Forces color to be on, even for non TTY output\n"
"blanklines=true # Use more whitespace in output\n" "blanklines=true # Use more whitespace in output\n"
"complete.all.projects=no # Include old project names in '_projects' command\n" "complete.all.projects=no # Include old project names in '_projects' command\n"
"complete.all.tags=no # Include old tag names in '_ags' command\n" "complete.all.tags=no # Include old tag names in '_ags' command\n"
"list.all.projects=no # Include old project names in 'projects' command\n" "list.all.projects=no # Include old project names in 'projects' command\n"
"list.all.tags=no # Include old tag names in 'tags' command\n" "list.all.tags=no # Include old tag names in 'tags' command\n"
"debug=no # Display diagnostics\n" "debug=no # Display diagnostics\n"
"hooks=off # Hook system master switch\n" "hooks=off # Hook system master switch\n"
"fontunderline=yes # Uses underlines rather than -------\n" "fontunderline=yes # Uses underlines rather than -------\n"
"shell.prompt=task> # Prompt used by the shell command\n" "shell.prompt=task> # Prompt used by the shell command\n"
"\n" "\n"
"# Import heuristics - alternate names for fields (comma-separated list of names)\n" "# Import heuristics - alternate names for fields (comma-separated list of names)\n"
"#import.synonym.bg=?\n" "#import.synonym.bg=?\n"
@@ -243,14 +246,14 @@ std::string Config::defaults =
"#import.synonym.uuid=?\n" "#import.synonym.uuid=?\n"
"\n" "\n"
"# Export Controls\n" "# Export Controls\n"
"export.ical.class=PRIVATE # Could be PUBLIC, PRIVATE or CONFIDENTIAL\n" "export.ical.class=PRIVATE # Could be PUBLIC, PRIVATE or CONFIDENTIAL\n"
"\n" "\n"
"# Aliases - alternate names for commands\n" "# Aliases - alternate names for commands\n"
"alias.rm=delete # Alias for the delete command\n" "alias.rm=delete # Alias for the delete command\n"
"alias.history=history.monthly # Prefer monthly over annual history reports\n" "alias.history=history.monthly # Prefer monthly over annual history reports\n"
"alias.ghistory=ghistory.monthly # Prefer monthly graphical over annual history reports\n" "alias.ghistory=ghistory.monthly # Prefer monthly graphical over annual history reports\n"
"alias.export=export.yaml # Prefer YAML over CSV or iCal export\n" "alias.export=export.yaml # Prefer YAML over CSV or iCal export\n"
"alias.export.vcalendar=export.ical # They are the same\n" "alias.export.vcalendar=export.ical # They are the same\n"
"\n" "\n"
"# Fields: id, uuid, project, priority, priority_long, entry, start, end, due\n" "# Fields: id, uuid, project, priority, priority_long, entry, start, end, due\n"
"# countdown, countdown_compact, age, age_compact, active, tags,\n" "# countdown, countdown_compact, age, age_compact, active, tags,\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;
out << "# dependencyNag "
<< task.id if (task.has ("depends"))
<< " " {
<< task.get ("uuid") out << "# dependencyNag "
<< "\n"; << task.id
<< " "
<< task.get ("uuid")
<< "\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,49 +470,45 @@ int handleInfo (std::string &outs)
} }
} }
if (task->getStatus () == Task::recurring || // recur
task->has ("parent")) if (task->has ("recur"))
{ {
// recur row = table.addRow ();
if (task->has ("recur")) table.addCell (row, 0, "Recurrence");
{ value = task->get ("recur");
row = table.addRow (); context.hooks.trigger ("format-recur", "recur", value);
table.addCell (row, 0, "Recurrence"); table.addCell (row, 1, value);
value = task->get ("recur"); }
context.hooks.trigger ("format-recur", "recur", value);
table.addCell (row, 1, value);
}
// until // until
if (task->has ("until")) if (task->has ("until"))
{ {
row = table.addRow (); row = table.addRow ();
table.addCell (row, 0, "Recur until"); table.addCell (row, 0, "Recur until");
Date dt (atoi (task->get ("until").c_str ())); Date dt (atoi (task->get ("until").c_str ()));
std::string format = context.config.get ("reportdateformat"); std::string format = context.config.get ("reportdateformat");
if (format == "") if (format == "")
format = context.config.get ("dateformat"); format = context.config.get ("dateformat");
std::string until = getDueDate (*task, format); std::string until = getDueDate (*task, format);
table.addCell (row, 1, until); table.addCell (row, 1, until);
} }
// 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"));
} }
if (task->has ("parent"))
{
// parent // parent
if (task->has ("parent")) row = table.addRow ();
{ table.addCell (row, 0, "Parent task");
row = table.addRow (); table.addCell (row, 1, task->get ("parent"));
table.addCell (row, 0, "Parent task");
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]);
{ }
case 1: // imminent }
c.blend (gsColor["color.due"]);
break;
case 2: // today ////////////////////////////////////////////////////////////////////////////////
c.blend (gsColor["color.due.today"]); static void colorizeDueToday (Task& task, const std::string& rule, Color& c)
break; {
Task::status status = task.getStatus ();
case 3: // overdue if (task.has ("due") &&
c.blend (gsColor["color.overdue"]); status != Task::completed &&
break; status != Task::deleted)
{
if (getDueState (task.get ("due")) == 2)
c.blend (gsColor[rule]);
}
}
case 0: // not due at all ////////////////////////////////////////////////////////////////////////////////
default: static void colorizeOverdue (Task& task, const std::string& rule, Color& c)
break; {
} 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"))
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;
} }
// Colorization of the recurring. // Note: c already contains colors specifically assigned via command.
if (gsColor["color.recurring"].nontrivial ()) // Note: These rules form a hierarchy - the last rule is King, hence the
if (task.has ("recur")) // reverse iterator.
c.blend (gsColor["color.recurring"]); 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';