Compare commits
157 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6b8b39d8b | ||
|
|
11ee827a0d | ||
|
|
89bbce8661 | ||
|
|
e1a7f61fb1 | ||
|
|
f310924675 | ||
|
|
2fd7f6d681 | ||
|
|
612b872ed4 | ||
|
|
f97955ded8 | ||
|
|
38907ac6d7 | ||
|
|
1da111ad6e | ||
|
|
c7d0b1c21b | ||
|
|
0c775f7998 | ||
|
|
c872e30ef5 | ||
|
|
2c826b6213 | ||
|
|
9d8777ec7d | ||
|
|
ee06280808 | ||
|
|
da8c3c1a16 | ||
|
|
4346f83f6e | ||
|
|
8b045156d0 | ||
|
|
c4e459e8d7 | ||
|
|
77475136b9 | ||
|
|
362b4a5bc9 | ||
|
|
ff14f0a28a | ||
|
|
a6637db232 | ||
|
|
95f07cf363 | ||
|
|
f9035eec70 | ||
|
|
cc5d44ee9d | ||
|
|
3f97bb0663 | ||
|
|
e268b7f71c | ||
|
|
753305a262 | ||
|
|
cec42bb2c4 | ||
|
|
de7f70ad3e | ||
|
|
046f511d66 | ||
|
|
e2e5b4884c | ||
|
|
05243c9e7a | ||
|
|
fd823871f0 | ||
|
|
4087a82402 | ||
|
|
e8da71498d | ||
|
|
4ab665b876 | ||
|
|
6762af8ffd | ||
|
|
407ef39c54 | ||
|
|
de4194479a | ||
|
|
08188fb811 | ||
|
|
cd89e10cfb | ||
|
|
1c736a319d | ||
|
|
72f84b3c3e | ||
|
|
e8443889bb | ||
|
|
e81fdd1975 | ||
|
|
f9c3103264 | ||
|
|
143666aca0 | ||
|
|
f7fc455b62 | ||
|
|
5814432366 | ||
|
|
90c721295a | ||
|
|
5cf33105a3 | ||
|
|
b23bad9a5b | ||
|
|
c61a295df7 | ||
|
|
aec64afc5c | ||
|
|
72ff15ea7a | ||
|
|
fea19e036a | ||
|
|
98391a0c24 | ||
|
|
2975b9244a | ||
|
|
c78be053cb | ||
|
|
708995093b | ||
|
|
7fea1f6a63 | ||
|
|
b67b27f5cd | ||
|
|
07819a1885 | ||
|
|
e03e1ec7b0 | ||
|
|
fb674a5626 | ||
|
|
410a63fe14 | ||
|
|
2cc625f631 | ||
|
|
51a78ab996 | ||
|
|
d7f9b2165c | ||
|
|
d135dc2337 | ||
|
|
57a11a74e1 | ||
|
|
f73281ee30 | ||
|
|
262e42d42b | ||
|
|
99174d66b6 | ||
|
|
a0838474c4 | ||
|
|
3235ac592f | ||
|
|
dcedbb3076 | ||
|
|
e84c5c4a3c | ||
|
|
c4ec5989fe | ||
|
|
a737b0e0c8 | ||
|
|
f2b7780d6b | ||
|
|
1b6faf57c9 | ||
|
|
76c66b8ab1 | ||
|
|
fe84ddcc98 | ||
|
|
0d832a6848 | ||
|
|
a77d4662f8 | ||
|
|
60915cefd4 | ||
|
|
f896d3f160 | ||
|
|
e23243e195 | ||
|
|
5b14fb63d8 | ||
|
|
081f8f5b3c | ||
|
|
06062a96eb | ||
|
|
2f18c512e0 | ||
|
|
7431f0cdd3 | ||
|
|
22f0b1d9fb | ||
|
|
b8187e24ae | ||
|
|
120593887b | ||
|
|
01e5e773eb | ||
|
|
e0fd39db7b | ||
|
|
a39261f82d | ||
|
|
a6b45af0a2 | ||
|
|
daea320564 | ||
|
|
1cbec205f1 | ||
|
|
579232b7ea | ||
|
|
cee8fda236 | ||
|
|
4dda1f0c27 | ||
|
|
0571412da0 | ||
|
|
b4f031e4a7 | ||
|
|
5b1d64960d | ||
|
|
a5fef2cc6b | ||
|
|
8ab3c1cc3c | ||
|
|
2700713c03 | ||
|
|
567bdd98a4 | ||
|
|
25425614b1 | ||
|
|
3b65051e9e | ||
|
|
5f4563af2f | ||
|
|
7e2bd166fa | ||
|
|
41b60f88d3 | ||
|
|
93ec320555 | ||
|
|
c1291dc587 | ||
|
|
57deb83b25 | ||
|
|
e4f5d6579c | ||
|
|
99dc72f26f | ||
|
|
406e648d58 | ||
|
|
db7b2dd9fe | ||
|
|
c31ec6b6a6 | ||
|
|
1a656f0f60 | ||
|
|
5ec0d569a9 | ||
|
|
3979c3283e | ||
|
|
ca795ea281 | ||
|
|
d10e9be500 | ||
|
|
f790df24c5 | ||
|
|
ca933d7f39 | ||
|
|
827bc6204b | ||
|
|
4537d5048e | ||
|
|
74ea5b4ef6 | ||
|
|
cc2220b406 | ||
|
|
7389ce617a | ||
|
|
165001acac | ||
|
|
3d3d788961 | ||
|
|
3c196230dd | ||
|
|
9a350a7dcd | ||
|
|
92579e5531 | ||
|
|
40a538a769 | ||
|
|
b6e4bc966f | ||
|
|
03815967d2 | ||
|
|
7049bf19d9 | ||
|
|
c69c3bb090 | ||
|
|
7238d1f1c9 | ||
|
|
9f82c55c5b | ||
|
|
857f813a24 | ||
|
|
5498986e15 | ||
|
|
eb827603c3 | ||
|
|
b548342acc |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -11,3 +11,4 @@ Makefile
|
||||
configure
|
||||
config.log
|
||||
www.xls
|
||||
*~
|
||||
|
||||
14
AUTHORS
14
AUTHORS
@@ -1,5 +1,5 @@
|
||||
Principal Author:
|
||||
Paul Beckingham, paul@beckingham.net
|
||||
Paul Beckingham
|
||||
|
||||
Contributing Authors:
|
||||
Damian Glenny
|
||||
@@ -8,21 +8,29 @@ Contributing Authors:
|
||||
Stefan Dorn
|
||||
Michael Greb
|
||||
Benjamin Tegarden
|
||||
Chris Pride
|
||||
Richard Querin
|
||||
Federico Hernandez
|
||||
T. Charles Yun
|
||||
David J Patrick
|
||||
P.C. Shyamshankar
|
||||
Johan Friis
|
||||
Steven de Brouwer
|
||||
|
||||
With thanks to:
|
||||
Eugene Kramer
|
||||
Srijith K
|
||||
Richard Querin
|
||||
Bruce Israel
|
||||
Thomas Engel
|
||||
Nishiishii
|
||||
galvanizd
|
||||
Stas Antons
|
||||
Vincent Fleuranceau
|
||||
T. Charles Yun
|
||||
ArchiMark
|
||||
Carlos Yoder
|
||||
Russell Friesenhahn
|
||||
Paolo Marsi
|
||||
Eric Farris
|
||||
Bruce Dillahunty
|
||||
Askme Too
|
||||
|
||||
|
||||
318
ChangeLog
318
ChangeLog
@@ -1,7 +1,93 @@
|
||||
|
||||
------ current release ---------------------------
|
||||
|
||||
1.5.0 (3/15/2009)
|
||||
1.7.0 (5/14/2009)
|
||||
+ Improved the errors when parsing a corrupt or unrecognized pending.data
|
||||
or completed.data file (thanks to T. Charles Yun).
|
||||
+ Added details to the "info" report about recurring tasks (thanks to T.
|
||||
Charles Yun).
|
||||
+ Now writes a sample "defaultwidth" configuration variable to the default
|
||||
.taskrc file (thanks to T. Charles Yun).
|
||||
+ Task allows commands that require an ID to now be given a sequence, which
|
||||
is a set of IDs. This allows commands like "task delete 1 2 5-10,12".
|
||||
+ Fixed bug in the ghistory report, which caused it to only show a new
|
||||
month if a task was added during that month.
|
||||
+ New command "duplicate" which allow existing task(s) to be duplicated,
|
||||
and also have modifications applied (thanks to David J Patrick).
|
||||
+ The "append", and "done" commands now allow modifications to be applied
|
||||
to the task(s) (thanks to David J Patrick).
|
||||
+ Improved word wrapping in various output.
|
||||
+ Fixed bug that added an extra line between header and graph in the
|
||||
ghistory report.
|
||||
+ Added simple 'taskprogram' mailing list subscribe form to the web site.
|
||||
+ For custom reports that define a "limit" to the number of rows of output
|
||||
such as "oldest" and "newest", task allows an override value. For
|
||||
example "task oldest 5" will display the 5 oldest tasks.
|
||||
+ Modified the "stats" report so that it has the same aesthetics as the
|
||||
other reports.
|
||||
+ New "timesheet" command displays tasks completed and started, per week,
|
||||
and can display multiple weeks.
|
||||
+ New tab completion script, task_completion.sh, for bash users, is installed
|
||||
to /usr/local/share/task (thanks to Federico Hernandez).
|
||||
+ Applied patch to allow task to build on Arch Linux (thanks to Johan Friis).
|
||||
+ Applied patch to fix a UUID bug on Solaris 8 (thanks to Steven de Brouwer).
|
||||
+ The task man page is now installed. Try "man task" (thanks to Federico
|
||||
Hernandez and P.C. Shyamshankar).
|
||||
+ Fixed bug that causes task to create a default .task directory, even if
|
||||
data.location specified otherwise (thanks to Federico Hernandez).
|
||||
+ New "edit" command that fires up a text editor (uses 'editor' configuration
|
||||
variable, $VISUAL or $EDITOR environment variable) and allows direct
|
||||
editing of all editable task details.
|
||||
|
||||
------ old releases ------------------------------
|
||||
|
||||
1.6.1 (4/24/2009) 1b6faf57c998617024d0348a87b941a5d2ab2249
|
||||
+ Fixed bug that caused new, first-time .taskrc files to be written without
|
||||
including the custom report labels (thanks to P.C. Shyamshankar).
|
||||
|
||||
1.6.0 (4/12/2009) 06062a96eb57d10dcd7fbe1edf968bb638a0b3a9
|
||||
+ Added support for new "append" command that adds more description text to
|
||||
an existing task.
|
||||
+ Added support for the "weekdays" recurrence, which means a task can recur
|
||||
five times a week, and not on weekends (thanks to Chris Pride).
|
||||
+ UTF8 text is now supported in task project names, tags and descriptions.
|
||||
+ Fixed bug that caused the y/n confirmation on task deletion to ignore the
|
||||
Enter key and fail to re-prompt (thanks to Bruce Dillahunty).
|
||||
+ When the "echo.command" configuration variable is set to "yes", it causes
|
||||
commands that modify tasks to display which task was affected (thanks to
|
||||
Bruce Dillahunty).
|
||||
+ A task can now be annotated with the command "task <id> annotate ...", and
|
||||
a timestamped annotation will appear in reports.
|
||||
+ A 'description_only' column is now available for use in custom reports,
|
||||
and it excludes annotations.
|
||||
+ A task can now be upgraded to a recurring task by adding a recurrence
|
||||
frequency, a due date, and an optional until date.
|
||||
+ When a recurring task is modified, all other instances of the recurring
|
||||
task are also modified.
|
||||
+ Custom reports now support user-specified column labels (thanks to T.
|
||||
Charles Yun).
|
||||
+ Task can now import tasks from a variety of data formats, including task
|
||||
export files from versions 1.4.3 and earlier, versions 1.5.0 and later,
|
||||
todo.sh 2.x, CSV, plain text and task command line. See online docs for
|
||||
full details.
|
||||
+ Export was including 'id' in the column header even though it was not
|
||||
included in the data.
|
||||
+ The task file format has changed slightly. Please back up your task
|
||||
data files before upgrading to 1.6.0.
|
||||
+ Added new column 'recurrence_indicator' that displays an 'R' if the task
|
||||
is a recurring task. This column can be added to any custom report.
|
||||
+ Added new column 'tag_indicator' that displays a '+' if the task
|
||||
has any tags. This column can be added to any custom report.
|
||||
+ Fixed bug where sometimes a task description was concatenated oddly if
|
||||
there was a colon somewhere in the description.
|
||||
+ Fixed bug that caused recurring annual tasks to exhibit a creeping due
|
||||
date, because of an assumption of 365 days per year, which failed to
|
||||
consider leap years (thanks to T. Charles Yun).
|
||||
+ Annotations can now be modified with the substitution commands /from/to/.
|
||||
+ Substitutions can now be made global with /from/to/g and all occurrences
|
||||
of "from" will be replaced with "to".
|
||||
|
||||
1.5.0 (3/15/2009) 87be68e2e83d7bb628be1e5679b16a49a26d3549
|
||||
+ Removed deprecated TUTORIAL file.
|
||||
+ Removed "showage" configuration variable.
|
||||
+ "task stop" can now remove the start time from a started task.
|
||||
@@ -43,17 +129,15 @@
|
||||
+ Fixed bug that prevented the summary report from properly reporting
|
||||
recently completed tasks.
|
||||
|
||||
------ old releases ------------------------------
|
||||
|
||||
1.4.3 (11/1/2008) 8639e9260646c8c9224e0fc47e5d2443b46eecfc
|
||||
+ Fixed misleading task count at bottom on "info" report.
|
||||
+ Added support for a shadow file that contains a plain text task report,
|
||||
with the "shadow.file" and "shadow.command" configuration variables
|
||||
with the "shadow.file" and "shadow.command" configuration variables.
|
||||
The shadow file is automatically updated whenever the task database
|
||||
changes. Useful for integrating with "Samurize"
|
||||
changes. Useful for integrating with "Samurize".
|
||||
+ Task now displays a message whenever a shadow file is updated, if the
|
||||
"shadow.notify" configuration variable is set "on"
|
||||
+ Bug: adding a task with a \n, \r or \f in it now fails properly
|
||||
"shadow.notify" configuration variable is set "on".
|
||||
+ Bug: adding a task with a \n, \r or \f in it now fails properly.
|
||||
+ Removed "usage" command, and support for "command.logging" configuration
|
||||
variable.
|
||||
+ Added documentation for Shadow files.
|
||||
@@ -61,111 +145,111 @@
|
||||
|
||||
1.4.2 (9/18/2008) e7304e86ce9bb80978c7055fd2a9e999619a6fb8
|
||||
+ "task undo" can now retract a "task done" command, provided no reports
|
||||
have been run (and therefore TDB::gc run)
|
||||
have been run (and therefore TDB::gc run).
|
||||
+ Task now correctly sorts on entire strings, instead of just the first
|
||||
character (thanks to Andy Lester)
|
||||
character (thanks to Andy Lester).
|
||||
+ Task now uses dashes (-----) to column underlines when color is disabled
|
||||
(thanks to Vincent Fleuranceau)
|
||||
(thanks to Vincent Fleuranceau).
|
||||
+ Task now allows mixed case attribute names (pri:, PRI:, Pri: ...) and
|
||||
commands (add, ADD, Add ...) (thanks to Vincent Fleuranceau)
|
||||
commands (add, ADD, Add ...) (thanks to Vincent Fleuranceau).
|
||||
+ Task now supports a default project and priority for new tasks, via
|
||||
the new "default.project" and "default.priority" configuration variables
|
||||
(thanks to Vincent Fleuranceau)
|
||||
+ Task supports improved word-wrapping to the terminal width
|
||||
(thanks to Vincent Fleuranceau).
|
||||
+ Task supports improved word-wrapping to the terminal width.
|
||||
+ Task now supports "default.command" configuration variable (for example
|
||||
it could contain "list due:tomorrow") that is the command that is run
|
||||
whenever task is invoked with no arguments.
|
||||
+ Task supports modifying the existing description of a task, with the
|
||||
following syntax: task <id> "new description ...".
|
||||
+ Bug: Now properly supports relative dates in filters (task list due:eom,
|
||||
task list due:tomorrow, task list due:23rd ...)
|
||||
task list due:tomorrow, task list due:23rd ...).
|
||||
+ Bug: Source now properly includes <string.h> in order to build clean
|
||||
using gcc 4.3 (thanks to H. İbrahim Güngör)
|
||||
using gcc 4.3 (thanks to H. İbrahim Güngör).
|
||||
|
||||
1.4.1 (7/18/2008) e080c3168c6064628ab85b21bd859d9875a3a9a7
|
||||
+ Bug: Descriptions can not be altered with "task 123 New description"
|
||||
+ Tweak: For "task calendar" month names are now centered over the month
|
||||
+ Removed TUTORIAL file contents in favor of online version
|
||||
+ Provided Mac .pkg binary
|
||||
+ Bug: Descriptions can not be altered with "task 123 New description".
|
||||
+ Tweak: For "task calendar" month names are now centered over the month.
|
||||
+ Removed TUTORIAL file contents in favor of online version.
|
||||
+ Provided Mac .pkg binary.
|
||||
|
||||
1.4.0 (7/10/2008) 60b7d15a1d22e064acf0974c5d7eabbb57dd8071
|
||||
+ New recurring tasks feature
|
||||
+ New recurring tasks feature.
|
||||
+ "task undelete" can now undelete erroneously deleted tasks, provided no
|
||||
reports have been run (and therefore TDB::gc run)
|
||||
+ Added averages to the "task history" report
|
||||
+ Added ability to override ~/.taskrc with rc:<file>
|
||||
+ Added bar chart history report "task ghistory"
|
||||
+ Added task filtering on all reports
|
||||
+ Automatically shuts off color, curses when output is not a tty
|
||||
+ Supports relative due: dates (tomorrow, wednesday, 23rd, eom ...)
|
||||
+ Supports the ~ character in .taskrc data.location
|
||||
reports have been run (and therefore TDB::gc run).
|
||||
+ Added averages to the "task history" report.
|
||||
+ Added ability to override ~/.taskrc with rc:<file>.
|
||||
+ Added bar chart history report "task ghistory".
|
||||
+ Added task filtering on all reports.
|
||||
+ Automatically shuts off color, curses when output is not a tty.
|
||||
+ Supports relative due: dates (tomorrow, wednesday, 23rd, eom ...).
|
||||
+ Supports the ~ character in .taskrc data.location.
|
||||
+ Allows colons on the description, provided what is to the left of the colon
|
||||
is not a standard attribute name
|
||||
+ Bug: Fixed where Esc[0m sequences were being emitted for no good reason
|
||||
+ Bug: Fixed underlined table headers when color is turned off
|
||||
+ Bug: Adding a blank priority resulted in an assigned garbage value
|
||||
+ Bug: Fixed parsing of date "07/08/2008" when using dateformat "m/d/Y"
|
||||
is not a standard attribute name.
|
||||
+ Bug: Fixed where Esc[0m sequences were being emitted for no good reason.
|
||||
+ Bug: Fixed underlined table headers when color is turned off.
|
||||
+ Bug: Adding a blank priority resulted in an assigned garbage value.
|
||||
+ Bug: Fixed parsing of date "07/08/2008" when using dateformat "m/d/Y".
|
||||
|
||||
1.3.1 (6/21/2008) 3a6de7d9402f2609a773a73b16eff97b14a32869
|
||||
+ New configuration variable, "defaultwidth" that determines the width
|
||||
of tables when ncurses support is not available
|
||||
of tables when ncurses support is not available.
|
||||
+ Bug: "showage" configuration variable should apply to all reports, not
|
||||
just the ones based on "list"
|
||||
just the ones based on "list".
|
||||
+ Bug: Fixed segmentation faults on Ubuntu when the "dateformat"
|
||||
configuration variables was missing. This was a code bug, and should
|
||||
have affected more platforms
|
||||
have affected more platforms.
|
||||
+ Bug: Task now will recreate a missing ~/.taskrc file, OR a missing
|
||||
~/.task directory
|
||||
~/.task directory.
|
||||
|
||||
1.3.0 (6/18/2008) 6673e408a223af98c38779c20b08524042c0edfa
|
||||
+ "task calendar" now displays multiple months per line, adjustable by the
|
||||
"monthsperline" configuration variable. Feature added by Damian Glenny
|
||||
+ "task export" can now filter tasks like the reports
|
||||
+ Factored out code to filter tasks
|
||||
"monthsperline" configuration variable. Feature added by Damian Glenny.
|
||||
+ "task export" can now filter tasks like the reports.
|
||||
+ Factored out code to filter tasks.
|
||||
+ Displays shorter message when a command is entered incorrectly, and the
|
||||
full usage for "task help"
|
||||
+ "task oldest" shows the oldest tasks
|
||||
+ "task newest" shows the newest tasks
|
||||
full usage for "task help".
|
||||
+ "task oldest" shows the oldest tasks.
|
||||
+ "task newest" shows the newest tasks.
|
||||
+ Bug: Segmentation fault when no "dateformat" configuration variable
|
||||
specified
|
||||
specified.
|
||||
+ Bug: Fixed bug whereby if you have more than one task with a due date, 7
|
||||
days gets added to the entry date of task 2..n
|
||||
+ Bug: Fixed bug whereby "1 wks" was being improperly pluralized
|
||||
days gets added to the entry date of task 2..n.
|
||||
+ Bug: Fixed bug whereby "1 wks" was being improperly pluralized.
|
||||
|
||||
1.2.0 (6/13/2008) c393d47cdfe7e197a31e94f4bb764474fa05ad8d
|
||||
+ Bug: "dateformat" configuration variable used to display dates, but
|
||||
not parse them
|
||||
not parse them.
|
||||
+ "task list x" now performs a caseless comparison between "x" and the
|
||||
description
|
||||
+ Task sub projects supported
|
||||
description.
|
||||
+ Task sub projects supported.
|
||||
+ "showage" confguration determines whether "Age" column appears on the
|
||||
"list" and "next" reports
|
||||
+ Improved TUTORIAL
|
||||
"list" and "next" reports.
|
||||
+ Improved TUTORIAL.
|
||||
|
||||
1.1.0 (6/7/2008) 73286e86628725b346db2a25fbcd4bd68efb9b3a
|
||||
+ "blanklines" configuration to stop displaying unnecessary white
|
||||
space and thus work better on small-screen devices
|
||||
+ "dateformat" configuration now determines how dates are formatted
|
||||
+ Better formatting of "task tags" output
|
||||
+ http://www.beckingham.net/task.html home page set up
|
||||
+ Added tags to the "task long" report
|
||||
space and thus work better on small-screen devices.
|
||||
+ "dateformat" configuration now determines how dates are formatted.
|
||||
+ Better formatting of "task tags" output.
|
||||
+ http://www.beckingham.net/task.html home page set up.
|
||||
+ Added tags to the "task long" report.
|
||||
|
||||
1.0.1 (6/4/2008) d216d401217027d93581808fc8944ab7d6b85fb0
|
||||
+ Bug: UUID generator not properly terminating string.
|
||||
+ Bug: srandom/srand not called prior to UUID generation.
|
||||
|
||||
1.0.0 (6/3/2008) f3de5c07118c597091a05c7d7fe8bdeae95474c1
|
||||
+ New movie made, uploaded
|
||||
+ Bug: assertion fails on mobile for t v
|
||||
+ Bug: configure.ac does not properly determine ncurses availability
|
||||
+ Bug: Cannot seem to use the percent character in a task description
|
||||
+ Bug: New installation "task stats" reports newest task 12/31/1969
|
||||
+ Bug: New installation task projects displays header but no data - should short-circuit
|
||||
+ Bug: incorrect color specification in sample .taskrc file
|
||||
+ Bug: when run without arguments, task dumps core on Solaris 10
|
||||
+ "task calendar" now reports all months with due pending tasks
|
||||
+ Added rules for colorization by tag, project and keyword
|
||||
+ Added legend to "task calendar"
|
||||
+ New movie made, uploaded.
|
||||
+ Bug: assertion fails on mobile for t v.
|
||||
+ Bug: configure.ac does not properly determine ncurses availability.
|
||||
+ Bug: Cannot seem to use the percent character in a task description.
|
||||
+ Bug: New installation "task stats" reports newest task 12/31/1969.
|
||||
+ Bug: New installation task projects displays header but no data - should short-circuit.
|
||||
+ Bug: incorrect color specification in sample .taskrc file.
|
||||
+ Bug: when run without arguments, task dumps core on Solaris 10.
|
||||
+ "task calendar" now reports all months with due pending tasks.
|
||||
+ Added rules for colorization by tag, project and keyword.
|
||||
+ Added legend to "task calendar".
|
||||
|
||||
0.9.9 (5/27/2008) 2ecf50032226c91b406f247417a063dc17c8e324
|
||||
+ Autoconf/automake behaving properly.
|
||||
@@ -180,8 +264,8 @@
|
||||
+ Completed documentation.
|
||||
|
||||
0.9.7 (5/24/2008) 25dc4150947a3e612c8118838d04b3bbe68441f7
|
||||
+ Migrated old compiler flags into Makefile.am
|
||||
+ Added ncurses endwin function check to configure.ac
|
||||
+ Migrated old compiler flags into Makefile.am.
|
||||
+ Added ncurses endwin function check to configure.ac.
|
||||
+ Set up structure for AUTHORS file.
|
||||
+ Set up NEWS file, with pleas for feedback.
|
||||
+ Added welcome message to README.
|
||||
@@ -192,31 +276,31 @@
|
||||
+ Removed unnecessary SAMPLE_taskrc, and assorted references.
|
||||
+ Cleaned up ChangeLog.
|
||||
+ Minor mods to standard docs.
|
||||
+ Bumped version to 0.9.7
|
||||
+ Changed some autoconf details
|
||||
+ Corrected comment in T.cpp
|
||||
+ Bumped version to 0.9.7.
|
||||
+ Changed some autoconf details.
|
||||
+ Corrected comment in T.cpp.
|
||||
+ Made unit tests compile and run again.
|
||||
+ Removed tests from distibution.
|
||||
|
||||
0.9.6 (5/13/208)
|
||||
+ Corrected wrong include file in Table.cpp
|
||||
+ Corrected wrong include file in Table.cpp.
|
||||
+ Replaced color management code.
|
||||
+ Improved color rules code.
|
||||
|
||||
0.9.5 (5/12/2008)
|
||||
+ Replaced Table storage with Grid.
|
||||
+ Added Grid.cpp to configure.ac
|
||||
+ Added Makefile to src/.gitignore
|
||||
+ Added Grid.cpp to configure.ac.
|
||||
+ Added Makefile to src/.gitignore.
|
||||
+ Makefile should not be part of the repository.
|
||||
+ Added Grid.cpp
|
||||
+ Added Grid::Cell::operator==
|
||||
+ Added Grid.cpp.
|
||||
+ Added Grid::Cell::operator==.
|
||||
+ ChangeLog file begun.
|
||||
+ Bumped version to 0.9.5 for next release.
|
||||
|
||||
0.9.4 (4/26/2008)
|
||||
+ Integrated new Grid object into build - not yet integrated into Table.
|
||||
+ More .gitignore tweaks.
|
||||
+ Added .gitignore
|
||||
+ Added .gitignore.
|
||||
+ Added more missing files.
|
||||
+ Added all source code.
|
||||
+ Generic OSS files added.
|
||||
@@ -237,29 +321,29 @@
|
||||
+ Consolidated header files, removed unnecessary ones.
|
||||
|
||||
0.9.0 (3/23/2008)
|
||||
+ flat source directory
|
||||
+ autoconf complete
|
||||
+ "task next"
|
||||
+ "task stats"
|
||||
+ "task export"
|
||||
+ Rules-based colorization
|
||||
+ flat source directory.
|
||||
+ autoconf complete.
|
||||
+ "task next".
|
||||
+ "task stats".
|
||||
+ "task export".
|
||||
+ Rules-based colorization.
|
||||
|
||||
0.8.1 (1/28/2008) - 0.8.16 (3/13/2008)
|
||||
+ autoconf conversion (many builds)
|
||||
+ autoconf conversion (many builds).
|
||||
|
||||
0.8.0 Polish (1/25/2008)
|
||||
+ Code cleanup, reorganization
|
||||
+ "task overdue"
|
||||
+ Add "age" column to list and long
|
||||
+ Use 'conf' for build, version tracking
|
||||
+ Add "/from/to/" description editing
|
||||
+ Code cleanup, reorganization.
|
||||
+ "task overdue".
|
||||
+ Add "age" column to list and long.
|
||||
+ Use 'conf' for build, version tracking.
|
||||
+ Add "/from/to/" description editing.
|
||||
|
||||
0.7.0 Multi-user, File handling, atomicity (1/8/2008)
|
||||
+ Clean, publishable API reimplementation
|
||||
+ File locking
|
||||
+ retain deleted tasks
|
||||
+ "task info ID" report showing all metadata
|
||||
+ File format v2, including UUID
|
||||
+ Clean, publishable API reimplementation.
|
||||
+ File locking.
|
||||
+ retain deleted tasks.
|
||||
+ "task info ID" report showing all metadata.
|
||||
+ File format v2, including UUID.
|
||||
|
||||
[Development hiatus while planning for T, TDB API, new features and the future
|
||||
of the project. Seeded to two testers for feedback, suggestions. Development
|
||||
@@ -267,40 +351,40 @@ deliberately stopped to allow extended use of task, allowing command logging and
|
||||
regular usage to determine which features were needed or unnecessary.]
|
||||
|
||||
0.6.0 Reports (12/27/2006)
|
||||
+ "task history"
|
||||
+ "task summary"
|
||||
+ "task calendar"
|
||||
+ due support
|
||||
+ Table sorting
|
||||
+ "task history".
|
||||
+ "task summary".
|
||||
+ "task calendar".
|
||||
+ due support.
|
||||
+ Table sorting.
|
||||
|
||||
0.5.0 Multi-user support (12/10/2006)
|
||||
+ Command logging
|
||||
+ "task usage" report
|
||||
+ Command logging.
|
||||
+ "task usage" report.
|
||||
|
||||
0.4.0 Destructive / modification commands (12/3/2006)
|
||||
+ "task delete" complete
|
||||
+ "task id ..." complete
|
||||
+ "task list ..." synonym for "task find ..."
|
||||
+ "task delete" complete.
|
||||
+ "task id ..." complete.
|
||||
+ "task list ..." synonym for "task find ...".
|
||||
|
||||
0.3.0 Work in progress support (12/3/2006)
|
||||
+ "task start" complete
|
||||
+ "task done" complete
|
||||
+ completed.data support
|
||||
+ "task start" complete.
|
||||
+ "task done" complete.
|
||||
+ completed.data support.
|
||||
|
||||
0.2.0 Neutral commands (12/2/2006)
|
||||
+ "task find" complete
|
||||
+ "task projects" complete
|
||||
+ "task tags" complete
|
||||
+ "task find" complete.
|
||||
+ "task projects" complete.
|
||||
+ "task tags" complete.
|
||||
|
||||
0.1.0 Constructive commands (12/1/2006)
|
||||
+ "task add" complete
|
||||
+ completed.data support
|
||||
+ ~/.taskrc support
|
||||
+ "task add" complete.
|
||||
+ completed.data support.
|
||||
+ ~/.taskrc support.
|
||||
|
||||
0.0.1 Basic infrastructure (11/29/2006)
|
||||
+ Command line parsing
|
||||
+ API layer
|
||||
+ Usage
|
||||
+ Command line parsing.
|
||||
+ API layer.
|
||||
+ Usage.
|
||||
|
||||
------ start -----------------------------------
|
||||
|
||||
|
||||
@@ -18,5 +18,5 @@ included.
|
||||
color.cpp Color support functions.
|
||||
rules.cpp Auto-colorization rules.
|
||||
|
||||
Don't forget, please send bugs, patches to task@beckingham.net
|
||||
Please send bugs, patches to task@beckingham.net
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
SUBDIRS = src
|
||||
EXTRA_DIST = DEVELOPERS
|
||||
|
||||
EXTRA_DIST = task_completion.sh doc/man1/task.1 doc/man5/taskrc.5
|
||||
man1_MANS = doc/man1/task.1
|
||||
man5_MANS = doc/man5/taskrc.5
|
||||
otherdir = $(datadir)/doc/task-1.7.0
|
||||
other_DATA = AUTHORS ChangeLog COPYING INSTALL NEWS README task_completion.sh
|
||||
|
||||
179
Makefile.in
179
Makefile.in
@@ -1,8 +1,8 @@
|
||||
# Makefile.in generated by automake 1.10 from Makefile.am.
|
||||
# Makefile.in generated by automake 1.10.1 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
@@ -13,6 +13,7 @@
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
VPATH = @srcdir@
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
@@ -52,6 +53,20 @@ RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
|
||||
install-pdf-recursive install-ps-recursive install-recursive \
|
||||
installcheck-recursive installdirs-recursive pdf-recursive \
|
||||
ps-recursive uninstall-recursive
|
||||
man1dir = $(mandir)/man1
|
||||
am__installdirs = "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" \
|
||||
"$(DESTDIR)$(otherdir)"
|
||||
man5dir = $(mandir)/man5
|
||||
NROFF = nroff
|
||||
MANS = $(man1_MANS) $(man5_MANS)
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
|
||||
otherDATA_INSTALL = $(INSTALL_DATA)
|
||||
DATA = $(other_DATA)
|
||||
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
|
||||
distclean-recursive maintainer-clean-recursive
|
||||
ETAGS = etags
|
||||
@@ -154,10 +169,15 @@ sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
SUBDIRS = src
|
||||
EXTRA_DIST = DEVELOPERS
|
||||
EXTRA_DIST = task_completion.sh doc/man1/task.1 doc/man5/taskrc.5
|
||||
man1_MANS = doc/man1/task.1
|
||||
man5_MANS = doc/man5/taskrc.5
|
||||
otherdir = $(datadir)/doc/task-1.7.0
|
||||
other_DATA = AUTHORS ChangeLog COPYING INSTALL NEWS README task_completion.sh
|
||||
all: auto.h
|
||||
$(MAKE) $(AM_MAKEFLAGS) all-recursive
|
||||
|
||||
@@ -212,6 +232,113 @@ $(srcdir)/auto.h.in: $(am__configure_deps)
|
||||
|
||||
distclean-hdr:
|
||||
-rm -f auto.h stamp-h1
|
||||
install-man1: $(man1_MANS) $(man_MANS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)"
|
||||
@list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
|
||||
l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
|
||||
for i in $$l2; do \
|
||||
case "$$i" in \
|
||||
*.1*) list="$$list $$i" ;; \
|
||||
esac; \
|
||||
done; \
|
||||
for i in $$list; do \
|
||||
if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
|
||||
else file=$$i; fi; \
|
||||
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
|
||||
case "$$ext" in \
|
||||
1*) ;; \
|
||||
*) ext='1' ;; \
|
||||
esac; \
|
||||
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
|
||||
inst=`echo $$inst | sed -e 's/^.*\///'`; \
|
||||
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
|
||||
echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
|
||||
$(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \
|
||||
done
|
||||
uninstall-man1:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
|
||||
l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
|
||||
for i in $$l2; do \
|
||||
case "$$i" in \
|
||||
*.1*) list="$$list $$i" ;; \
|
||||
esac; \
|
||||
done; \
|
||||
for i in $$list; do \
|
||||
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
|
||||
case "$$ext" in \
|
||||
1*) ;; \
|
||||
*) ext='1' ;; \
|
||||
esac; \
|
||||
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
|
||||
inst=`echo $$inst | sed -e 's/^.*\///'`; \
|
||||
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
|
||||
echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \
|
||||
rm -f "$(DESTDIR)$(man1dir)/$$inst"; \
|
||||
done
|
||||
install-man5: $(man5_MANS) $(man_MANS)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(man5dir)" || $(MKDIR_P) "$(DESTDIR)$(man5dir)"
|
||||
@list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
|
||||
l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
|
||||
for i in $$l2; do \
|
||||
case "$$i" in \
|
||||
*.5*) list="$$list $$i" ;; \
|
||||
esac; \
|
||||
done; \
|
||||
for i in $$list; do \
|
||||
if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
|
||||
else file=$$i; fi; \
|
||||
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
|
||||
case "$$ext" in \
|
||||
5*) ;; \
|
||||
*) ext='5' ;; \
|
||||
esac; \
|
||||
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
|
||||
inst=`echo $$inst | sed -e 's/^.*\///'`; \
|
||||
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
|
||||
echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
|
||||
$(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst"; \
|
||||
done
|
||||
uninstall-man5:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
|
||||
l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
|
||||
for i in $$l2; do \
|
||||
case "$$i" in \
|
||||
*.5*) list="$$list $$i" ;; \
|
||||
esac; \
|
||||
done; \
|
||||
for i in $$list; do \
|
||||
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
|
||||
case "$$ext" in \
|
||||
5*) ;; \
|
||||
*) ext='5' ;; \
|
||||
esac; \
|
||||
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
|
||||
inst=`echo $$inst | sed -e 's/^.*\///'`; \
|
||||
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
|
||||
echo " rm -f '$(DESTDIR)$(man5dir)/$$inst'"; \
|
||||
rm -f "$(DESTDIR)$(man5dir)/$$inst"; \
|
||||
done
|
||||
install-otherDATA: $(other_DATA)
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(otherdir)" || $(MKDIR_P) "$(DESTDIR)$(otherdir)"
|
||||
@list='$(other_DATA)'; for p in $$list; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
f=$(am__strip_dir) \
|
||||
echo " $(otherDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(otherdir)/$$f'"; \
|
||||
$(otherDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(otherdir)/$$f"; \
|
||||
done
|
||||
|
||||
uninstall-otherDATA:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(other_DATA)'; for p in $$list; do \
|
||||
f=$(am__strip_dir) \
|
||||
echo " rm -f '$(DESTDIR)$(otherdir)/$$f'"; \
|
||||
rm -f "$(DESTDIR)$(otherdir)/$$f"; \
|
||||
done
|
||||
|
||||
# This directory's subdirectories are mostly independent; you can cd
|
||||
# into them and run `make' without going through this Makefile.
|
||||
@@ -288,8 +415,8 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
$(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
@@ -314,8 +441,8 @@ TAGS: tags-recursive $(HEADERS) $(SOURCES) auto.h.in $(TAGS_DEPENDENCIES) \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
@@ -325,13 +452,12 @@ ctags: CTAGS
|
||||
CTAGS: ctags-recursive $(HEADERS) $(SOURCES) auto.h.in $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
tags=; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) auto.h.in $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$tags $$unique
|
||||
@@ -402,6 +528,10 @@ dist-bzip2: distdir
|
||||
tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-lzma: distdir
|
||||
tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
|
||||
$(am__remove_distdir)
|
||||
|
||||
dist-tarZ: distdir
|
||||
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
|
||||
$(am__remove_distdir)
|
||||
@@ -428,6 +558,8 @@ distcheck: dist
|
||||
GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
|
||||
*.tar.bz2*) \
|
||||
bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
|
||||
*.tar.lzma*) \
|
||||
unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\
|
||||
*.tar.Z*) \
|
||||
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
|
||||
*.shar.gz*) \
|
||||
@@ -488,9 +620,12 @@ distcleancheck: distclean
|
||||
exit 1; } >&2
|
||||
check-am: all-am
|
||||
check: check-recursive
|
||||
all-am: Makefile auto.h
|
||||
all-am: Makefile $(MANS) $(DATA) auto.h
|
||||
installdirs: installdirs-recursive
|
||||
installdirs-am:
|
||||
for dir in "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(otherdir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-recursive
|
||||
install-exec: install-exec-recursive
|
||||
install-data: install-data-recursive
|
||||
@@ -534,7 +669,7 @@ info: info-recursive
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
install-data-am: install-man install-otherDATA
|
||||
|
||||
install-dvi: install-dvi-recursive
|
||||
|
||||
@@ -544,7 +679,7 @@ install-html: install-html-recursive
|
||||
|
||||
install-info: install-info-recursive
|
||||
|
||||
install-man:
|
||||
install-man: install-man1 install-man5
|
||||
|
||||
install-pdf: install-pdf-recursive
|
||||
|
||||
@@ -570,7 +705,9 @@ ps: ps-recursive
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am:
|
||||
uninstall-am: uninstall-man uninstall-otherDATA
|
||||
|
||||
uninstall-man: uninstall-man1 uninstall-man5
|
||||
|
||||
.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \
|
||||
install-strip
|
||||
@@ -578,17 +715,19 @@ uninstall-am:
|
||||
.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
|
||||
all all-am am--refresh check check-am clean clean-generic \
|
||||
ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \
|
||||
dist-shar dist-tarZ dist-zip distcheck distclean \
|
||||
dist-lzma dist-shar dist-tarZ dist-zip distcheck distclean \
|
||||
distclean-generic distclean-hdr distclean-tags distcleancheck \
|
||||
distdir distuninstallcheck dvi dvi-am html html-am info \
|
||||
info-am install install-am install-data install-data-am \
|
||||
install-dvi install-dvi-am install-exec install-exec-am \
|
||||
install-html install-html-am install-info install-info-am \
|
||||
install-man install-pdf install-pdf-am install-ps \
|
||||
install-ps-am install-strip installcheck installcheck-am \
|
||||
installdirs installdirs-am maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
|
||||
pdf-am ps ps-am tags tags-recursive uninstall uninstall-am
|
||||
install-man install-man1 install-man5 install-otherDATA \
|
||||
install-pdf install-pdf-am install-ps install-ps-am \
|
||||
install-strip installcheck installcheck-am installdirs \
|
||||
installdirs-am maintainer-clean maintainer-clean-generic \
|
||||
mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags \
|
||||
tags-recursive uninstall uninstall-am uninstall-man \
|
||||
uninstall-man1 uninstall-man5 uninstall-otherDATA
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
|
||||
11
NEWS
11
NEWS
@@ -1,4 +1,4 @@
|
||||
Welcome to Task 1.5.0.
|
||||
Welcome to Task 1.7.0.
|
||||
|
||||
Task has been built and tested on the following configurations:
|
||||
|
||||
@@ -9,7 +9,10 @@ Task has been built and tested on the following configurations:
|
||||
- Fedora Core 10
|
||||
- Ubuntu 7 Feisty Fawn
|
||||
- Ubuntu 8 Hardy Heron
|
||||
- Ubunto 8.10 Intrepid Ibex
|
||||
- Ubuntu 8.10 Intrepid Ibex
|
||||
- Ubuntu 9.04 Jaunty Jackalope
|
||||
- Arch Linux
|
||||
- Solaris 8
|
||||
- Solaris 10
|
||||
- Cygwin 1.5.25-14
|
||||
|
||||
@@ -30,5 +33,9 @@ order of increasing effort (to you) and usefulness (to me):
|
||||
will be applied and tested, and a new release will be made. You will be a
|
||||
hero.
|
||||
|
||||
- Another option involves using Github's issue tracker, which can be found
|
||||
at http://github.com/pbeckingham/task/issues which has the advantage that
|
||||
everyone gets to see and track the issue. You will still be a hero.
|
||||
|
||||
Thank you.
|
||||
|
||||
|
||||
8
README
8
README
@@ -14,7 +14,7 @@ Thank you for taking a look at task. Task is a GTD utility featuring:
|
||||
It is intended that features, mainly in the form of reports will be added
|
||||
frequently, with best practices and useful reports evolving from usage patterns.
|
||||
|
||||
Task is scope-limited to GTD functionality only.
|
||||
Task is scope-limited to GTD-like functionality only.
|
||||
|
||||
You may want to watch the old task movie on YouTube:
|
||||
|
||||
@@ -44,7 +44,11 @@ All feedback is welcome, in addition to any bug reports or patches to:
|
||||
|
||||
task@beckingham.net
|
||||
|
||||
Got an idea for an enhancement? Send a message!
|
||||
Or better yet, get involved in the discussion at
|
||||
|
||||
http://groups.google.com/group/taskprogram
|
||||
|
||||
Got an idea for an enhancement? Post a message!
|
||||
|
||||
I have found that task makes me more productive and organized.
|
||||
I hope task can do the same for you.
|
||||
|
||||
44
checklist.txt
Normal file
44
checklist.txt
Normal file
@@ -0,0 +1,44 @@
|
||||
Adding New Command Checklist
|
||||
----------------------------
|
||||
|
||||
- Create new handler in command.cpp or report.cpp.
|
||||
- Add prototype to task.h.
|
||||
- Add call to appropriate section in task.cpp.
|
||||
- Add usage info in task.cpp.
|
||||
- Add command name to list in parse.cpp.
|
||||
- Add unit tests in src/tests.
|
||||
- Add new configuration details to html/config.html.
|
||||
- Add command details to html/advanced.html.
|
||||
- Add description to ChangeLog, with attribution if the idea
|
||||
came from a single user, but not if it came from multiple
|
||||
users.
|
||||
- Add description to html/task.html.
|
||||
|
||||
|
||||
|
||||
Release Checklist
|
||||
-----------------
|
||||
|
||||
- Update "Upcoming Features" document on group
|
||||
- Ensure all unit tests pass on OS X
|
||||
- Ensure clean build on OS X
|
||||
- Make a source package (1)
|
||||
- Ensure clean build on latest Fedora Core from source package
|
||||
- Git clone and rebuild, ensure all unit tests pass
|
||||
- Ensure clean build on latest Ubuntu from source package
|
||||
- Git clone and rebuild, ensure all unit tests pass
|
||||
- Ensure clean build on Windows/Cygwin from source package
|
||||
- Git clone and rebuild, ensure all unit tests pass
|
||||
- Make a new source package (2)
|
||||
- Add actual release date to ChangeLog
|
||||
- Add actual release date to html/task.html
|
||||
- Merge version branch to master
|
||||
- Tag master
|
||||
- Make a new source package (3)
|
||||
- Send source package to package maintainer
|
||||
- Make OS X .pkg package
|
||||
- Wait for all packages
|
||||
- Upload all packages to website
|
||||
- Upload all docs to website
|
||||
- Send announcement to group
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT(task, 1.5.0, bugs@beckingham.net)
|
||||
AC_INIT(task, 1.7.0, bugs@beckingham.net)
|
||||
|
||||
CFLAGS="${CFLAGS=}"
|
||||
CXXFLAGS="${CXXFLAGS=}"
|
||||
@@ -18,7 +18,7 @@ if test "$enable_debug" = "yes"; then
|
||||
CXXFLAGS="$CFLAGS -Wall -pedantic -ggdb3 -DDEBUG"
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
CXXFLAGS="$CFLAGS -O3"
|
||||
CXXFLAGS="$CFLAGS -Wall -pedantic -O3"
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
@@ -45,7 +45,6 @@ AC_SUBST(CFLAGS)
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB(ncurses,initscr)
|
||||
AC_CHECK_LIB(ncurses,endwin)
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
|
||||
382
doc/man1/task.1
Normal file
382
doc/man1/task.1
Normal file
@@ -0,0 +1,382 @@
|
||||
.TH task 1 2009-05-14 "Task 1.7.0" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
task \- A command line todo manager.
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B task [subcommand] [args]
|
||||
|
||||
.SH DESCRIPTION
|
||||
Task is a command line TODO list manager. It maintains a list of tasks that you
|
||||
want to do, allowing you to add/remove, and otherwise manipulate them. Task
|
||||
has a rich list of subcommands that allow you to do various things with it.
|
||||
|
||||
.SH SUBCOMMANDS
|
||||
|
||||
.TP
|
||||
.B add [tags] [attrs] description
|
||||
Adds a new task to the task list.
|
||||
|
||||
.TP
|
||||
.B append [tags] [attrs] description
|
||||
Appends more information to an existing
|
||||
task.
|
||||
|
||||
.TP
|
||||
.B annotate ID description
|
||||
Adds an annotation to an existing task.
|
||||
|
||||
.TP
|
||||
.B completed [tags] [attrs] description
|
||||
Provides a chronological listing of all completed tasks matching specified
|
||||
criteria.
|
||||
|
||||
.TP
|
||||
.B ID [tags] [attrs] [description]
|
||||
Modifies the existing task with provided information.
|
||||
|
||||
.TP
|
||||
.B ID /from/to/
|
||||
Performs one substitution on task description for fixing mistakes.
|
||||
|
||||
.TP
|
||||
.B ID /from/to/g
|
||||
Performs all substitutions on task description for fixing mistakes.
|
||||
|
||||
.TP
|
||||
.B duplicate ID [tags] [attrs] [description]
|
||||
Duplicates the specified task and allows modifications.
|
||||
|
||||
.TP
|
||||
.B delete ID
|
||||
Deletes the specified task from task list.
|
||||
|
||||
.TP
|
||||
.B undelete ID
|
||||
Undeletes the specified task, provided a report has not yet been run.
|
||||
|
||||
.TP
|
||||
.B info ID
|
||||
Shows all data and metadata for the specified task.
|
||||
|
||||
.TP
|
||||
.B start ID
|
||||
Marks the specified task as started.
|
||||
|
||||
.TP
|
||||
.B stop ID
|
||||
Removes the
|
||||
.I start
|
||||
time from the specified task.
|
||||
|
||||
.TP
|
||||
.B done ID [tags] [attrs] [description]
|
||||
Marks the specified task as done.
|
||||
|
||||
.TP
|
||||
.B undo ID
|
||||
Marks the specified task as pending, provided a report has not yet been run.
|
||||
|
||||
.TP
|
||||
.B projects
|
||||
Lists all project names used, and the number of tasks for each.
|
||||
|
||||
.TP
|
||||
.B tags
|
||||
Show a list of all tags used.
|
||||
|
||||
.TP
|
||||
.B summary
|
||||
Shows a report of task status by project.
|
||||
|
||||
.TP
|
||||
.B timesheet [weeks]
|
||||
Shows a weekly report of tasks completed and started.
|
||||
|
||||
.TP
|
||||
.B history
|
||||
Shows a report of task history by month.
|
||||
|
||||
.TP
|
||||
.B ghistory
|
||||
Shows a graphical report of task status by month.
|
||||
|
||||
.TP
|
||||
.B next
|
||||
Shows the most important pending tasks for each project.
|
||||
|
||||
.TP
|
||||
.B calendar
|
||||
Shows a monthly calendar with due tasks marked.
|
||||
|
||||
.TP
|
||||
.B active
|
||||
Shows all tasks that are started but not comleted.
|
||||
|
||||
.TP
|
||||
.B overdue
|
||||
Shows all incomplete tasks that are beyond their due date.
|
||||
|
||||
.TP
|
||||
.B stats
|
||||
Shows task database statistics.
|
||||
|
||||
.TP
|
||||
.B import \fIfile
|
||||
Imports tasks from a variety of formats.
|
||||
|
||||
.TP
|
||||
.B export \fIfile
|
||||
Exports all tasks as a CSV file.
|
||||
|
||||
.TP
|
||||
.B color
|
||||
Displays all possible colors.
|
||||
|
||||
.TP
|
||||
.B version
|
||||
Shows the task version number and current settings in the task configuration
|
||||
file.
|
||||
|
||||
.TP
|
||||
.B help
|
||||
Shows the long usage text.
|
||||
|
||||
.SH REPORT SUBCOMMANDS
|
||||
|
||||
A report is a listing of information from the task database. There are several
|
||||
built-in reports currently in task. The output and sort behaviour of these
|
||||
subcommands can be configured in the configuration file.
|
||||
|
||||
.TP
|
||||
.B ls [tags] [attrs] [description]
|
||||
Provides a minimal listing of tasks with specified criteria.
|
||||
|
||||
.TP
|
||||
.B list [tags] [attrs] [description]
|
||||
Provides a more detailed listing of tasks with specified criteria.
|
||||
|
||||
.TP
|
||||
.B long [tags] [attrs] [description]
|
||||
Provides the most detailed listing of tasks with specified criteria.
|
||||
|
||||
.TP
|
||||
.B newest [tags] [attrs] [description] | newest [limit]
|
||||
Shows the newest tasks with specified criteria.
|
||||
|
||||
.TP
|
||||
.B oldest [tags] [attrs] [description] | oldest [limit]
|
||||
Shows the oldest tasks with specified criteria
|
||||
|
||||
.SH ATTRIBUTES AND METADATA
|
||||
|
||||
.TP
|
||||
.B ID
|
||||
Tasks can be specified uniquely by IDs, which are simply the index of the
|
||||
task in a report. Be careful, as the IDs of tasks may change after a
|
||||
modification to the database. Always run a report to check you have the right
|
||||
ID for a task. IDs can be given to task as a sequence, for example,
|
||||
.br
|
||||
.B
|
||||
task del 1 2 5-10,12
|
||||
|
||||
.TP
|
||||
.B +tag|-tag
|
||||
Tags are arbitrary words associated with a task. Use + to add a tag and - to
|
||||
remove a tag from a task.
|
||||
|
||||
.TP
|
||||
.B project:<project-name>
|
||||
Specify the project to which a task is related to.
|
||||
|
||||
.TP
|
||||
.B priority:H|M|L|N
|
||||
Specify High, Medium, Low and No priority for a task.
|
||||
|
||||
.TP
|
||||
.B due:<due-date>
|
||||
Specify the due-date of a task.
|
||||
|
||||
.TP
|
||||
.B until:<end-date-of-recurrence>
|
||||
Specify the Recurrence end-date of a task.
|
||||
|
||||
.TP
|
||||
.B recur:<frequency>
|
||||
Specify the frequency of recurrence of a task.
|
||||
|
||||
.TP
|
||||
.B fg:<color-spec>
|
||||
Specify foreground color.
|
||||
|
||||
.TP
|
||||
.B bg:<color-spec>
|
||||
Specify background color.
|
||||
|
||||
.TP
|
||||
.B rc:<path>
|
||||
Specify alternate configuration file.
|
||||
|
||||
.SH SPECIFYING DATES AND FREQUENCIES
|
||||
|
||||
.SS DATES
|
||||
Task reads dates from the commandline and displays dates in the
|
||||
reports. The expected and desired date format is determined by the
|
||||
configuration variable
|
||||
.I dateformat
|
||||
in the task configuration file.
|
||||
|
||||
.RS
|
||||
.TP
|
||||
Exact specification
|
||||
task ... due:7/14/2008
|
||||
|
||||
.TP
|
||||
Relative wording
|
||||
task ... due:today
|
||||
.br
|
||||
task ... due:yesterday
|
||||
.br
|
||||
task ... due:tomorrow
|
||||
|
||||
.TP
|
||||
Day number with ordinal
|
||||
task ... due:23rd
|
||||
|
||||
.TP
|
||||
End of week (Friday), month and year
|
||||
task ... due:eow
|
||||
.br
|
||||
task ... due:eom
|
||||
.br
|
||||
task ... due:eoy
|
||||
|
||||
.TP
|
||||
Next occuring weekday
|
||||
task ... due:fri
|
||||
.RE
|
||||
|
||||
.SS FREQUENCIES
|
||||
Recurrence periods. Task supports several ways of specifying the
|
||||
.I frequency
|
||||
of recurring tasks.
|
||||
|
||||
.RS
|
||||
.TP
|
||||
daily, day, 1d, 2d, ...
|
||||
Every day or a number of days.
|
||||
|
||||
.TP
|
||||
weekdays
|
||||
Mondays, Tuesdays, Wednesdays, Thursdays, Fridays and skipping weekend days.
|
||||
|
||||
.TP
|
||||
weekly, 1w, 2w, ...
|
||||
Eery week or a number of weeks.
|
||||
|
||||
.TP
|
||||
biweekly, fortnight
|
||||
Every two weeks.
|
||||
|
||||
.TP
|
||||
quaterly, 1q, 2q, ...
|
||||
Every three months, a quarter, or a number of quaters.
|
||||
|
||||
.TP
|
||||
semiannual
|
||||
Every six months.
|
||||
|
||||
.TP
|
||||
annual, yearly, 1y, 2y, ...
|
||||
Every year or a number of years.
|
||||
|
||||
.TP
|
||||
biannual, biyearly, 2y
|
||||
Every two years.
|
||||
.RE
|
||||
|
||||
|
||||
.SH COMMAND ABBREVIATION
|
||||
All task commands may be abbreviated as long as a unique prefix is used. E.g.
|
||||
|
||||
.RS
|
||||
$ task li
|
||||
.RE
|
||||
|
||||
is an unambiguous abbreviation for
|
||||
|
||||
.RS
|
||||
$ task list
|
||||
.RE
|
||||
|
||||
but
|
||||
|
||||
.RS
|
||||
$ task l
|
||||
.RE
|
||||
|
||||
could be list, ls or long.
|
||||
|
||||
.SH EXAMPLES
|
||||
|
||||
A small section for examples e.g. some stuff from
|
||||
.br
|
||||
http://www.beckingham.net/30second.html
|
||||
.br
|
||||
http://www.beckingham.net/simple.html
|
||||
|
||||
.SH FILES
|
||||
|
||||
.TP
|
||||
~/.taskrc User configuration file.
|
||||
|
||||
.TP
|
||||
~/.task The default directory where task stores its data files. The location
|
||||
can be configured in the configuration file.
|
||||
|
||||
.TP
|
||||
~/.task/pending.data The file that contains the tasks that are not yet done.
|
||||
|
||||
.TP
|
||||
~/.task/completed.data The file that contains the completed "done" tasks.
|
||||
|
||||
.SH "CREDITS & COPYRIGHTS"
|
||||
task was written by P. Beckingham <task@beckingham.net>.
|
||||
.br
|
||||
Copyright (C) 2006 \- 2009 P. Beckingham
|
||||
|
||||
This manpage was originally written by P.C. Shyamshankar, and has been modified
|
||||
and supplemented by Federico Hernandez.
|
||||
|
||||
task is distributed under the GNU General Public License. See
|
||||
http://www.gnu.org/licenses/gpl-2.0.txt for more information.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR taskrc (5)
|
||||
|
||||
For more information regarding task, the following may be referenced:
|
||||
|
||||
.TP
|
||||
<http://www.beckingham.net/task.html>
|
||||
The official site.
|
||||
|
||||
.TP
|
||||
<http://groups.google.com/group/taskprogram>
|
||||
The official mailing list.
|
||||
|
||||
.TP
|
||||
<http://github.com/pbeckingham/task/>
|
||||
The official code repository.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Bugs in task may be reported to the issue-tracker at
|
||||
|
||||
.RS
|
||||
<http://github.com/pbeckingham/task/issues>
|
||||
.RE
|
||||
|
||||
or to the mailing list at
|
||||
|
||||
.RS
|
||||
<http://groups.google.com/group/taskprogram>
|
||||
.RE
|
||||
411
doc/man5/taskrc.5
Normal file
411
doc/man5/taskrc.5
Normal file
@@ -0,0 +1,411 @@
|
||||
.TH taskrc 5 2009-05-14 "Task 1.7.0" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
taskrc \- Configuration file for the task(1) command
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B $HOME/.taskrc
|
||||
.B task rc:<directory-path>/.taskrc
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B task
|
||||
obtains its configuration data from a file called
|
||||
.I .taskrc
|
||||
\&. This file is normally located in the user's home directory:
|
||||
|
||||
.RS
|
||||
$HOME/.taskrc
|
||||
.RE
|
||||
|
||||
The default location can be overriden using the
|
||||
.I rc:
|
||||
attribute when running task:
|
||||
|
||||
.RS
|
||||
$ task rc:<directory-path>/.taskrc
|
||||
.RE
|
||||
|
||||
If
|
||||
.B task
|
||||
is run without an existing configuration file it will ask if it should create a default, sample
|
||||
.I .taskrc
|
||||
file in the user's home directory.
|
||||
|
||||
The task configuration file consists of a series of "assignments" in each line. The "assignments" have the syntax:
|
||||
|
||||
.RS
|
||||
<name-of-configuration-variable>=<value-to-be-set>
|
||||
.RE
|
||||
|
||||
where:
|
||||
.RS
|
||||
.TP
|
||||
<name-of-configuration-variable>
|
||||
is one of the variables described below
|
||||
|
||||
.TP
|
||||
<value-to-be-set>
|
||||
is the value the variable is to be set to.
|
||||
.RE
|
||||
|
||||
and set a configuration variable to a certain value. The equal sign ("=") is used to separate the variable
|
||||
name from the value to be set.
|
||||
|
||||
The hash mark, or pounf sign ("#") is used as a "comment" character. It can be used to annotte the
|
||||
configuration file. It is placed at the beginning of a line and all text after the character to the
|
||||
end of the line is ignored.
|
||||
|
||||
.SH CONFIGURATION VARIABLES
|
||||
Valid variable names and their default values are:
|
||||
|
||||
.TP
|
||||
.B data.location=$HOME/.task
|
||||
This is a path to the directory containing all the task files. By default, it is set up to be ~/.task,
|
||||
for example: /Users/paul/.task
|
||||
|
||||
.TP
|
||||
.B confirmation=yes
|
||||
May be "yes" or "no", and determines whether task will ask for confirmation before deleting a task.
|
||||
|
||||
.TP
|
||||
.B echo.command=yes
|
||||
May be "yes" or "no", and causes task to display the ID and description of any task when you run the start, stop, do, undo, delete and undelete commands. The default value is "yes".
|
||||
|
||||
.TP
|
||||
.B next=2
|
||||
Is a number, defaulting to 2, which is the number of tasks for each project that are shown in the
|
||||
.B task next
|
||||
command.
|
||||
|
||||
.TP
|
||||
.B dateformat=m/d/Y
|
||||
This is a string of characters that define how task formats dates. The default value is: m/d/Y.
|
||||
The string should contain the characters
|
||||
|
||||
.RS
|
||||
m minimal-digit month, for example 1 or 12
|
||||
.br
|
||||
d minimal-digit day, for example 1 or 30
|
||||
.br
|
||||
y two-digit year, for example 09
|
||||
.br
|
||||
D two-digit day, for example 01 or 30
|
||||
.br
|
||||
M two-digit month, for example 01 or 12
|
||||
.br
|
||||
Y four-digit year, for example 2009
|
||||
.RE
|
||||
|
||||
The string may also contain other characters to act as spacers, or formatting. Examples for other
|
||||
variable values:
|
||||
|
||||
.RS
|
||||
.br
|
||||
d/m/Y would output 24/7/2009
|
||||
.br
|
||||
YMD would output 20090724
|
||||
.br
|
||||
m-d-y would output 07-24-09
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B monthsperline=99
|
||||
Determines how many months the "task calendar" command renders across the screen.
|
||||
Defaults to however many will fit. If more months that will fit are specified,
|
||||
task will only show as many that will fit.
|
||||
|
||||
.TP
|
||||
.B defaultwidth=80
|
||||
The width of tables used when ncurses support is not available. Defaults to 80.
|
||||
|
||||
.TP
|
||||
.B curses=on
|
||||
Determines whether task uses ncurses to establish the size of the window you are
|
||||
using, for text wrapping.
|
||||
|
||||
.TP
|
||||
.B due=7
|
||||
This is the number of days into the future that define when a task is considered due,
|
||||
and is colored accordingly. Defaults to 7.
|
||||
|
||||
.TP
|
||||
.B nag=You have higher priority tasks.
|
||||
This may be a string of text, or blank. It is used as a prompt when a task is completed
|
||||
that is not considered high priority. The "task next" command lists important tasks, and
|
||||
completing one of those does not generate this nagging. Default value is: You have higher
|
||||
priority tasks.
|
||||
|
||||
.TP
|
||||
.B locking=on
|
||||
Determines whether task uses file locking when accessing the pending.data and completed.data files.
|
||||
Default to "on". Solaris users who store the task data files on an NFS mount may need to set locking
|
||||
to "off". Note that setting this value to "off" is dangerous. It means that another program may write
|
||||
to the task.pending file when task is attempting to do the same.
|
||||
|
||||
.TP
|
||||
.B editor=vi
|
||||
Specifies which text editor you wish to use for when the
|
||||
.B task edit <ID>
|
||||
command is used. Task will first look for this configuration variable. If found, it is used.
|
||||
Otherwise task will look for the $VISUAL or $EDITOR environment variables, before it defaults
|
||||
to using "vi".
|
||||
|
||||
.TP
|
||||
.B color=on
|
||||
May be "on" or "off". Determines whether task uses color. When "off", task will
|
||||
use dashes (-----) to underline column headings.
|
||||
|
||||
Task has a number of coloration rules. They correspond to a particular attribute
|
||||
of a task, such as it being due, or being active, and specifies the automatic
|
||||
coloring of that task. A list of valid color, depending on your terminal, can be
|
||||
obtained by running the command
|
||||
|
||||
.RS
|
||||
.B task color
|
||||
.RE
|
||||
|
||||
.RS
|
||||
The coloration rules and their defaults are:
|
||||
.RE
|
||||
|
||||
.RS
|
||||
.RS
|
||||
.B color.overdue=bold_red
|
||||
.br
|
||||
.B color.due=bold_yellow
|
||||
.br
|
||||
.B color.pri.H=bold
|
||||
.br
|
||||
.B color.pri.M=on_yellow
|
||||
.br
|
||||
.B color.pri.L=on_green
|
||||
.br
|
||||
.B color.pri.none=white on_blue
|
||||
.br
|
||||
.B color.active=bold_cyan
|
||||
.br
|
||||
.B color.tagged=yellow
|
||||
.br
|
||||
.B color.recurring=on_red
|
||||
.RE
|
||||
.RE
|
||||
|
||||
.RS
|
||||
The value for the coloration rules may be one optional foreground color and one optional
|
||||
color. For example, the value may be
|
||||
.RE
|
||||
|
||||
.RS
|
||||
.RS
|
||||
bold_red on_bright_yellow
|
||||
.RE
|
||||
.RE
|
||||
|
||||
.RS
|
||||
Certain attributes like tags, projects and keywords can also have their own coloration rules.
|
||||
.RE
|
||||
|
||||
.RS
|
||||
.TP
|
||||
.B color.tag.X=yellow
|
||||
Colors any task that has the tag X.
|
||||
|
||||
.TP
|
||||
.B color.project.X=on_green
|
||||
Colors any task assigned to project X.
|
||||
|
||||
.TP
|
||||
.B color.keyword.X=on_blue
|
||||
Colors any task where the description contains X.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B
|
||||
shadow.file=$HOME/.task/shadow.txt
|
||||
If specified, designates a file path that will be autoamtically written to by task,
|
||||
whenever the task database changes. In other words, it is automatically kept up to date.
|
||||
The shadow.command configuration variable is used to determine which report is written
|
||||
to the shadow file. There is no color used in the shadow file. This feature can be useful
|
||||
in maintaining a current file for use by programs like GeekTool, Conky or Samurize.
|
||||
|
||||
.TP
|
||||
.B
|
||||
shadow.command=list
|
||||
This is the command that is run to maintain the shadow file, determined by the
|
||||
.I shadow.file
|
||||
configuration variable. The format is identical to that of
|
||||
.I default.command
|
||||
\&. Please see the corresponding documentation for that command.
|
||||
|
||||
.TP
|
||||
.B
|
||||
shadow.notify=on
|
||||
When this value is set to "on", task will display a message whenever the shadow
|
||||
file is updated by some task command.
|
||||
|
||||
.TP
|
||||
.B
|
||||
default.project=foo
|
||||
Provides a default project name for the
|
||||
.I task add
|
||||
command.
|
||||
|
||||
.TP
|
||||
.B
|
||||
default.priority=M
|
||||
Provides a default priority for the
|
||||
.I task add
|
||||
command.
|
||||
|
||||
.TP
|
||||
.B
|
||||
default.command=list
|
||||
Provides a default command that is run every time task is invoked with no arguments.
|
||||
For example, if set to:
|
||||
|
||||
.RS
|
||||
.RS
|
||||
default.command=list project:foo
|
||||
.RE
|
||||
.RE
|
||||
|
||||
.RS
|
||||
Then task will run the "list project:foo" command if no command is specified. This means that
|
||||
by merely typing
|
||||
.RE
|
||||
|
||||
.RS
|
||||
.RS
|
||||
$ task
|
||||
.br
|
||||
[task list project:foo]
|
||||
.br
|
||||
\&
|
||||
.br
|
||||
ID Project Pri Description
|
||||
1 foo H Design foo
|
||||
2 foo Build foo
|
||||
.RE
|
||||
.RE
|
||||
|
||||
The built in reports can be customized by using the following configuration variables.
|
||||
The output columns, their labels and the sort order can be set using the corresponding
|
||||
variables for each report.
|
||||
|
||||
.TP
|
||||
.B
|
||||
report.long.description
|
||||
Lists all task, all data, matching the specified criteria
|
||||
|
||||
.TP
|
||||
.B
|
||||
report.long.labels=ID,Project,Pri,Added,Started,Due,Recur,Age,Tags,Description
|
||||
.RE
|
||||
.B
|
||||
report.long.columns=id,project,priority,entry,start,due,recur,age,tags,description
|
||||
.B
|
||||
report.long.sort=due+,priority-,project+
|
||||
|
||||
.TP
|
||||
.B
|
||||
report.list.description
|
||||
Lists all tasks matching the specified criteria
|
||||
|
||||
.TP
|
||||
.B
|
||||
report.list.labels=ID,Project,Pri,Due,Active,Age,Description
|
||||
.RE
|
||||
.B
|
||||
report.list.columns=id,project,priority,due,active,age,description
|
||||
.B
|
||||
report.list.sort=due+,priority-,project+
|
||||
|
||||
|
||||
.TP
|
||||
.B
|
||||
report.ls.description
|
||||
Minimal listing of all tasks matching the specified criteria
|
||||
|
||||
.TP
|
||||
.B
|
||||
report.ls.labels=ID,Project,Pri,Description
|
||||
.RE
|
||||
.B
|
||||
report.ls.columns=id,project,priority,description
|
||||
.B
|
||||
report.ls.sort=priority-,project+
|
||||
|
||||
.TP
|
||||
.B
|
||||
report.newest.description
|
||||
Shows the newest tasks
|
||||
|
||||
.TP
|
||||
.B
|
||||
report.newest.labels=ID,Project,Pri,Due,Active,Age,Description
|
||||
.RE
|
||||
.B
|
||||
report.newest.columns=id,project,priority,due,active,age,description
|
||||
.B
|
||||
report.newest.sort=id-
|
||||
.B
|
||||
report.newest.limit=10
|
||||
|
||||
|
||||
.TP
|
||||
.B
|
||||
report.oldest.description
|
||||
Shows the oldest tasks
|
||||
|
||||
.TP
|
||||
.B
|
||||
report.oldest.labels=ID,Project,Pri,Due,Active,Age,Description
|
||||
.RE
|
||||
.B
|
||||
report.oldest.columns=id,project,priority,due,active,age,description
|
||||
.B
|
||||
report.oldest.sort=id+
|
||||
.B
|
||||
report.oldest.limit=10
|
||||
|
||||
|
||||
.SH "CREDITS & COPYRIGHTS"
|
||||
task was written by P. Beckingham <task@beckingham.net>.
|
||||
.br
|
||||
Copyright (C) 2006 \- 2009 P. Beckingham
|
||||
|
||||
This man page was originally written by Federico Hernandez. It is based on the task man page, which
|
||||
was originally written by P.C. Shyamshankar.
|
||||
|
||||
task is distributed under the GNU General Public License. See
|
||||
http://www.gnu.org/licenses/gpl-2.0.txt for more information.
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR task (1)
|
||||
|
||||
For more information regarding task, the following may be referenced:
|
||||
|
||||
.TP
|
||||
<http://www.beckingham.net/task.html>
|
||||
The official site.
|
||||
|
||||
.TP
|
||||
<http://groups.google.com/group/taskprogram>
|
||||
The official mailing list.
|
||||
|
||||
.TP
|
||||
<http://github.com/pbeckingham/task/>
|
||||
The official code repository.
|
||||
|
||||
.SH REPORTING BUGS
|
||||
Bugs in task may be reported to the issue-tracker at
|
||||
|
||||
.RS
|
||||
<http://github.com/pbeckingham/task/issues>
|
||||
.RE
|
||||
|
||||
or to the mailing list at
|
||||
|
||||
.RS
|
||||
<http://groups.google.com/group/taskprogram>
|
||||
.RE
|
||||
@@ -36,5 +36,5 @@ word ::=
|
||||
file ::=
|
||||
id ::= digit+ ;
|
||||
digit ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
|
||||
substitution ::= "/" word+ "/" word* "/" ;
|
||||
substitution ::= "/" word+ "/" word* "/" "g"? ;
|
||||
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="usage.html">Usage</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="troubleshooting.html">Troubleshooting</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="usage.html">Usage</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="troubleshooting.html">Troubleshooting</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
@@ -97,6 +96,37 @@ Car 2 2 wks 25% XXXXXXXXX</code></pre>
|
||||
indicating that percentage.
|
||||
</p>
|
||||
|
||||
<strong>% task <id> append ...</strong>
|
||||
<p>
|
||||
Appends the additional description to an existing task.
|
||||
</p>
|
||||
|
||||
<strong>% task annotate <id> additional note...</strong>
|
||||
<p>
|
||||
Allows an annotation to be attached to an existing task. Each
|
||||
annotation has a time stamp, and when displayed, the annotations
|
||||
are shown under the task description. For example:
|
||||
</p>
|
||||
|
||||
<pre><code>% task add Go to the supermarket
|
||||
% task annotate 1 need milk
|
||||
% task ls
|
||||
|
||||
ID Project Pri Due Active Age Description
|
||||
1 Go to the supermarket
|
||||
3/23/2009 need milk</code></pre>
|
||||
<p>
|
||||
The date of the annotation uses the "dateformat" configuration
|
||||
variable.
|
||||
</p>
|
||||
|
||||
<strong>% task duplicate 1 /foo/bar/g +tag priority:H</strong>
|
||||
<p>
|
||||
This duplicates task 1, then applies the modifications specified,
|
||||
which change all "foo" to "bar" in the description and annotations,
|
||||
adds the tag "tag", and sets the priority to "H".
|
||||
</p>
|
||||
|
||||
<strong>% task delete <id></strong>
|
||||
<p>
|
||||
There are two ways of getting rid of tasks - mark them as done, or
|
||||
@@ -120,6 +150,13 @@ Car 2 2 wks 25% XXXXXXXXX</code></pre>
|
||||
This is how a task is marked as done.
|
||||
</p>
|
||||
|
||||
<strong>% task undo <id></strong>
|
||||
<p>
|
||||
If a task was recently marked as done, and no report has been run, it
|
||||
may be possible to cancel the completed status of the task as though
|
||||
"task done ..." was never run.
|
||||
</p>
|
||||
|
||||
<strong>% task list ...</strong>
|
||||
<p>
|
||||
The list report will show the active status, and age of the task in
|
||||
@@ -188,6 +225,24 @@ Year Month Added Completed Deleted Net
|
||||
number decreased as more task were completed than added.
|
||||
</p>
|
||||
|
||||
<strong>% task ghistory</strong>
|
||||
<p>
|
||||
The ghistory report is a "graphical" version of the history
|
||||
report. It shows a colored bar graph and legend.
|
||||
</p>
|
||||
|
||||
<strong>% task timesheet 2</strong>
|
||||
<p>
|
||||
The timesheet report shows a list of tasks completed and started
|
||||
during a one-week period. In the example above, 2 weeks of tasks
|
||||
are shown.
|
||||
</p>
|
||||
<p>
|
||||
By default, the report starts on a Monday. To override this
|
||||
value, add an entry to your .taskrc file like this:
|
||||
<pre><code>weekstart=Sunday</code></pre>
|
||||
</p>
|
||||
|
||||
<strong>% task calendar</strong>
|
||||
<p>
|
||||
This report shows a calendar of the current month, with any task
|
||||
@@ -246,19 +301,27 @@ ID Project Pri Description
|
||||
12 Errand L Remember to deposit bonus check
|
||||
...</code></pre>
|
||||
|
||||
<strong>% task oldest</strong>
|
||||
<strong>% task oldest [limit]</strong>
|
||||
<p>
|
||||
Lists the oldest tasks. Shows 10 tasks by default, but can be
|
||||
set via the "oldest" configuration variable.
|
||||
Lists the oldest tasks. The number of tasks shown is set by
|
||||
the configuration variable:
|
||||
<pre><code>report.oldest.limit=10</code></pre>
|
||||
This value can be overridden at run time by specifying the
|
||||
number of tasks on the command line:
|
||||
<pre><code>task oldest 5</code></pre>
|
||||
</p>
|
||||
|
||||
<strong>% task newest</strong>
|
||||
<strong>% task newest [limit]</strong>
|
||||
<p>
|
||||
Lists the newest tasks. Shows 10 tasks by default, but can be
|
||||
set via the "newest" configuration variable.
|
||||
Lists the newest tasks. The number of tasks shown is set by
|
||||
the configuration variable:
|
||||
<pre><code>report.newest.limit=10</code></pre>
|
||||
This value can be overridden at run time by specifying the
|
||||
number of tasks on the command line:
|
||||
<pre><code>task newest 5</code></pre>
|
||||
</p>
|
||||
|
||||
<strong>% task /from/to/</strong>
|
||||
<strong>% task <id> /from/to/</strong>
|
||||
<p>
|
||||
If a task has been entered with a typo, it can be easily corrected
|
||||
by this command. For example:
|
||||
@@ -278,7 +341,20 @@ ID Project Pri Description
|
||||
...</code></pre>
|
||||
|
||||
<p>
|
||||
This command makes single corrections to a task description.
|
||||
This command makes a single correction to the first occurrence of
|
||||
"from" in a task description.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If a task is annotated, the annotation can also be modified using
|
||||
this command.
|
||||
</p>
|
||||
|
||||
<strong>% task <id> /from/to/g</strong>
|
||||
<p>
|
||||
The "g" modifier to the substitution command causes every occurrence
|
||||
of "from" to be replaced with "to", in both the description and any
|
||||
annotations.
|
||||
</p>
|
||||
|
||||
<strong>% task tags</strong>
|
||||
@@ -357,6 +433,22 @@ ID Project Pri Description
|
||||
command.
|
||||
</p>
|
||||
|
||||
<strong>% task <id> edit</strong>
|
||||
<p>
|
||||
This command allows you to use your text editor to edit all aspects
|
||||
of a task. The specified task will be written to a file, and your
|
||||
text editor will be invoked. If you modify the task in the text
|
||||
editor, task will update accordingly.
|
||||
</p>
|
||||
<p>
|
||||
Task will first check to see if you have defined a text editor
|
||||
in the 'editor' configuration variable. If not, task will
|
||||
check to see if you defined a text editor in the VISUAL
|
||||
environment variable. If not task will check to see if you
|
||||
defined a text editor in the EDITOR environment variable.
|
||||
If all those fail, task launches vi.
|
||||
</p>
|
||||
|
||||
<strong>% task <id> fg:... bg:...</strong>
|
||||
<p>
|
||||
Not strictly a command, the setting of the fg and bg (foreground
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="usage.html">Usage</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="troubleshooting.html">Troubleshooting</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="usage.html">Usage</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="troubleshooting.html">Troubleshooting</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
@@ -58,6 +57,13 @@
|
||||
confirmation before deleting a task.
|
||||
</dd>
|
||||
|
||||
<dt>echo.command</dt>
|
||||
<dd>
|
||||
May be "yes" or "no", and causes task to display the ID and
|
||||
description of any task when you run the start, stop, do, undo,
|
||||
delete and undelete commands. The default value is "yes".
|
||||
</dd>
|
||||
|
||||
<dt>nag</dt>
|
||||
<dd>
|
||||
This may be a string of text, or blank. It is used as a prompt
|
||||
@@ -179,6 +185,24 @@
|
||||
only show as many that will fit.
|
||||
</dd>
|
||||
|
||||
<dt>weekstart</dt>
|
||||
<dd>
|
||||
The day of the week that represents the first day of the week.
|
||||
Defaults to "Monday".
|
||||
</dd>
|
||||
|
||||
<dt>editor</dt>
|
||||
<dd>
|
||||
Specifies which text editor you wish to use for when the
|
||||
|
||||
<pre><code>task edit <ID></code></pre>
|
||||
|
||||
command is used. Task will first look for this configuration
|
||||
variable. If found, it is used. Otherwise task will look
|
||||
for the VISUAL or EDITOR environment variables, before it
|
||||
defaults to using 'vi'.
|
||||
</dd>
|
||||
|
||||
<dt>defaultwidth</dt>
|
||||
<dd>
|
||||
The width of tables used when ncurses support is not available.
|
||||
@@ -330,6 +354,28 @@ ID Project Pri Description
|
||||
</p>
|
||||
</dd>
|
||||
|
||||
<dt>import.synonym.id</dt>
|
||||
<dt>import.synonym.uuid</dt>
|
||||
<dt>import.synonym.status</dt>
|
||||
<dt>import.synonym.tags</dt>
|
||||
<dt>import.synonym.entry</dt>
|
||||
<dt>import.synonym.start</dt>
|
||||
<dt>import.synonym.due</dt>
|
||||
<dt>import.synonym.recur</dt>
|
||||
<dt>import.synonym.end</dt>
|
||||
<dt>import.synonym.project</dt>
|
||||
<dt>import.synonym.priority</dt>
|
||||
<dt>import.synonym.fg</dt>
|
||||
<dt>import.synonym.bg</dt>
|
||||
<dt>import.synonym.description</dt>
|
||||
<dd>
|
||||
If any of these configuration variables are found, they influence
|
||||
data import by specifying a single additional field name synonym.
|
||||
If a data import is failing because certain column names are not
|
||||
being recognized, then this is how the field mapping can be
|
||||
controlled.
|
||||
</dd>
|
||||
|
||||
<p>
|
||||
Note that the command:
|
||||
</p>
|
||||
@@ -340,6 +386,8 @@ ID Project Pri Description
|
||||
will display the configuration variables found in the .taskrc file,
|
||||
and will warn you of any variables that are not recognized.
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="usage.html">Usage</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="troubleshooting.html">Troubleshooting</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
@@ -88,6 +87,18 @@ report.mine.sort=priority-,project+</pre></code>
|
||||
in a report:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It is also possible to override the default columns names, if
|
||||
the following line is added to your .taskrc file:
|
||||
</p>
|
||||
|
||||
<pre><code>report.mine.labels=ID,Project,Priority,Description of task</code></pre>
|
||||
|
||||
<p>
|
||||
Note that there must be the same number of labels as there are
|
||||
columns to label, and they must appear in the same sequence.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>id
|
||||
<li>uuid
|
||||
@@ -100,7 +111,10 @@ report.mine.sort=priority-,project+</pre></code>
|
||||
<li>active
|
||||
<li>tags
|
||||
<li>recur
|
||||
<li>description_only
|
||||
<li>description
|
||||
<li>tag_indicator
|
||||
<li>recurrence_indicator
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="usage.html">Usage</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="troubleshooting.html">Troubleshooting</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
|
||||
239
html/faq.html
Normal file
239
html/faq.html
Normal file
@@ -0,0 +1,239 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Frequently Asked Questions</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<link rel="stylesheet" href="task.css" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div id="toolbar">
|
||||
<a href="task.html">Home</a>
|
||||
<a href="setup.html">Setup</a>
|
||||
<a href="30second.html">30-second Tutorial</a>
|
||||
<a href="simple.html">Simple</a>
|
||||
<a href="advanced.html">Advanced</a>
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<h2 class="title">Frequently Asked Questions</h2>
|
||||
<div class="content">
|
||||
<p>
|
||||
(Actually, that's a misnomer. These are really Repeatedly Asked
|
||||
Questions.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>
|
||||
Q: When I redirect the output of task to a file, I lose all
|
||||
the colors. How do I fix this?
|
||||
</b>
|
||||
<br />
|
||||
A: Task knows (or thinks it knows) when the output is not going
|
||||
directly to a terminal, and strips out all the color control
|
||||
characters. Prevent this with the following entry in your
|
||||
.taskrc file:
|
||||
<pre><code>_forcecolor=on</code></pre>
|
||||
</p>
|
||||
<hr>
|
||||
|
||||
<p>
|
||||
<b>
|
||||
Q: How do I backup my task data files? Where are they?
|
||||
</b>
|
||||
<br />
|
||||
A: Task writes all pending tasks to the file ~/.task/pending.data
|
||||
and all completed and deleted tasks to ~/.task/completed.data.
|
||||
They are text files, so they can just be copied to another
|
||||
location for safekeeping. Don't forget there is also the
|
||||
~/.taskrc file that contains your task configuration data.
|
||||
To be sure, and to future-proof your backup, consider backing
|
||||
up all the files in the ~/.task directory.
|
||||
</p>
|
||||
<hr>
|
||||
|
||||
<p>
|
||||
<b>
|
||||
Q: How can I separate my work tasks from my home tasks?
|
||||
Specifically, can I keep them completely separate?
|
||||
</b>
|
||||
<br />
|
||||
A: You can do this by creating an alternate .taskrc file,
|
||||
then using shell aliases. Here is are example Bash
|
||||
commands to achieve this:
|
||||
|
||||
<pre><code>% cp ~/.taskrc ~/.taskrc_home
|
||||
% (now edit .taskrc_home to change the value of data.location)
|
||||
% alias wtask="task"
|
||||
% alias htask="task rc:~/.taskrc_home"</code></pre>
|
||||
|
||||
This gives you two commands, 'wtask' and 'htask' that
|
||||
operate using two different sets of task data files.
|
||||
</p>
|
||||
<hr>
|
||||
|
||||
<p>
|
||||
<b>
|
||||
Q: Can I revert to a previous version of task? How?
|
||||
</b>
|
||||
<br />
|
||||
A: Yes, you can revert to a previous version of task,
|
||||
simply by downloading an
|
||||
<a href="versions.html">older version</a> and
|
||||
installing it. If you find a bug in task, then this
|
||||
may be the only way to work around the bug, until a
|
||||
new release is made.
|
||||
</p>
|
||||
<p>
|
||||
Note that it is possible that the task file format will
|
||||
change. For example, the format changed between versions
|
||||
1.5.0 and 1.6.0. Task will automatically upgrade the file
|
||||
but if you need to revert to a previous version of task,
|
||||
there is the file format to consider. This is yet another
|
||||
good reason to back up your task data files!
|
||||
</p>
|
||||
<hr>
|
||||
|
||||
<p>
|
||||
<b>
|
||||
Q: I'm using Ubuntu 9.04, and I want task to word-wrap
|
||||
descriptions. How do I do this?
|
||||
</b>
|
||||
<br />
|
||||
A: You need to install ncurses, by doing this:
|
||||
<code><pre>% sudo apt-get install libncurses5-dev</pre></code>
|
||||
Then you need to rebuild task from scratch, starting with
|
||||
<code><pre>% cd task-X.X.X
|
||||
% ./configure
|
||||
...</pre></code>
|
||||
The result should be a task program that knows the width
|
||||
of the terminal window, and wraps accordingly.
|
||||
</p>
|
||||
<hr>
|
||||
|
||||
<p>
|
||||
<b>
|
||||
Q: How do I build task under Cygwin?
|
||||
</b>
|
||||
<br />
|
||||
A: Task is built the same way everywhere. But under Cygwin, you'll
|
||||
need to make sure you have the following packages available
|
||||
first:
|
||||
|
||||
<ul>
|
||||
<li>gcc
|
||||
<li>make
|
||||
<li>libncurses-devel
|
||||
<li>libncurses8
|
||||
</ul>
|
||||
|
||||
The gcc and make packages allow you to compile the code, and
|
||||
are therefore required, but the ncurses packages are optional.
|
||||
Ncurses will allow task to determine the width of the window, and
|
||||
therefore use the whole width and wrap text accordingly, for a
|
||||
more aesthetically pleasing display.
|
||||
</p>
|
||||
<hr>
|
||||
|
||||
<p>
|
||||
<b>
|
||||
Q: Do colors work under Cygwin?
|
||||
</b>
|
||||
<br />
|
||||
A: They do, but only in a limited way. You can use regular
|
||||
foreground colors (black, red, green ...) and you can
|
||||
regular background colors (on_black, on_red, on_green ...),
|
||||
but underline and bold are not supported.
|
||||
<br />
|
||||
<br />
|
||||
If you run the command:
|
||||
<code><pre>% task colors</pre></code>
|
||||
Task will display all the colors it can use, and you will
|
||||
see which ones you can use.
|
||||
<br />
|
||||
<br />
|
||||
See the <a href="color.html">color</a> documentation for
|
||||
more details on which colors can be used.
|
||||
</p>
|
||||
<hr>
|
||||
|
||||
<!--
|
||||
<p>
|
||||
<b>
|
||||
Q:
|
||||
</b>
|
||||
<br />
|
||||
A:
|
||||
</p>
|
||||
<hr>
|
||||
-->
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<div class="content">
|
||||
<p>
|
||||
Copyright 2006-2009, P. Beckingham. All rights reserved.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td align="right" valign="top" width="200px">
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<script type="text/javascript"><!--
|
||||
google_ad_client = "pub-9709799404235424";
|
||||
/* Task Main */
|
||||
google_ad_slot = "8660617875";
|
||||
google_ad_width = 120;
|
||||
google_ad_height = 600;
|
||||
//-->
|
||||
</script>
|
||||
<script type="text/javascript"
|
||||
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
|
||||
</script>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
var pageTracker = _gat._getTracker("UA-4737637-1");
|
||||
pageTracker._initData();
|
||||
pageTracker._trackPageview();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="usage.html">Usage</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="troubleshooting.html">Troubleshooting</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
|
||||
409
html/git.html
Normal file
409
html/git.html
Normal file
@@ -0,0 +1,409 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>git</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<link rel="stylesheet" href="task.css" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div id="toolbar">
|
||||
<a href="task.html">Home</a>
|
||||
<a href="setup.html">Setup</a>
|
||||
<a href="30second.html">30-second Tutorial</a>
|
||||
<a href="simple.html">Simple</a>
|
||||
<a href="advanced.html">Advanced</a>
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<h2 class="title"><a name="simple">Using git</a></h2>
|
||||
<div class="content">
|
||||
<p>
|
||||
First you need to tell git who you are. These commands will
|
||||
write to ~/.gitconfig, and will be used to identify you when
|
||||
you commit changes. Plus, I like color.
|
||||
</p>
|
||||
|
||||
<pre><code>% git config --global user.name "John Doe"
|
||||
% git config --global user.email "john@doe.com"
|
||||
% git config --global color.ui=always</code></pre>
|
||||
|
||||
<p>
|
||||
Now we will clone the repository, which involves downloading
|
||||
about 2MB of files. Git repositories are very compact. We
|
||||
will clone the repository from github. This takes a minute or
|
||||
so.
|
||||
</p>
|
||||
|
||||
<pre><code>% cd
|
||||
% git clone git://github.com/pbeckingham/task.git task.git
|
||||
% cd task.git</code></pre>
|
||||
|
||||
<p>
|
||||
You just pulled the entire history of task changes since it
|
||||
was uploaded to github. That will be missing about a year and
|
||||
a half of prior changes, which were in Subversion. Let's
|
||||
build task:
|
||||
</p>
|
||||
|
||||
<pre><code>% autoreconf
|
||||
...
|
||||
% ./configure --prefix=/usr/local
|
||||
...
|
||||
% make
|
||||
...</code></pre>
|
||||
|
||||
<p>
|
||||
The task binary will be in the src directory. If you run:
|
||||
</p>
|
||||
|
||||
<pre><code>% sudo make install</code></pre>
|
||||
|
||||
<p>
|
||||
Then task will be copied to /usr/local/bin, according the
|
||||
--prefix argument used above. /usr/local is the default
|
||||
prefix, so that argument wasn't necessary, but illustrates
|
||||
it's use.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Meanwhile, you have just created a local copy of the
|
||||
repository. You can do anything to this copy except push to
|
||||
github. Only the repository owner can push to github, or
|
||||
additional users identified by the owner (with additional
|
||||
monthly github fee). In order to get your changes back to
|
||||
github, they have to go through the owner, either in the form
|
||||
of a patch via email, or by creating your own github account,
|
||||
pushing to you own task repository clone (github calls it a
|
||||
fork), then asking the owner to pull directly from your
|
||||
repository.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You only need to clone once, unless you feel like starting
|
||||
over, or creating additional clones. Ordinarily, you update
|
||||
your local copy by pulling changes from github with:
|
||||
</p>
|
||||
|
||||
<pre><code>% git pull</code></pre>
|
||||
|
||||
<p>
|
||||
Right now, nothing new should be pulled, because you just
|
||||
cloned. Sometimes you'll see changes that have either been
|
||||
made by the owner, or merged in from others, by the owner.
|
||||
Let's take a look at the commit history:
|
||||
</p>
|
||||
|
||||
<pre><code>% git log</code></pre>
|
||||
|
||||
<p>
|
||||
You see a whole series of commits. Each commit is a set of
|
||||
file changes that were made somewhere. Let's look at branches.
|
||||
Try this:
|
||||
</p>
|
||||
|
||||
<pre><code>% git branch
|
||||
* master</code></pre>
|
||||
|
||||
<p>
|
||||
This is telling you that you have only one branch, called
|
||||
master. The asterisk tells you that this is your current
|
||||
branch, which is redundant because you only have one. But
|
||||
there are other branches on github. See those with:
|
||||
</p>
|
||||
|
||||
<pre><code>% git branch -a
|
||||
* master
|
||||
remotes/origin/1.6.1
|
||||
remotes/origin/1.7.0
|
||||
remotes/origin/HEAD -> origin/master
|
||||
remotes/origin/master</code></pre>
|
||||
|
||||
<p>
|
||||
A remote is what git calls another repository. The origin
|
||||
remote is the repository that this clone originated from.
|
||||
This output tells you that there is a 1.6.1 branch on github,
|
||||
a 1.7.0 branch on github, and a master branch on github. It's
|
||||
not obvious, but your local master (the first one shown) is
|
||||
tracking remotes/origin/master, which means changes on the
|
||||
remote will get merged to the local tracking branch on pull.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The convention used by task is to create a new branch whenever
|
||||
work begins on a new version. When that version is released,
|
||||
the branch is merged to master, but retained. At time of
|
||||
writing, 1.6.1 is the currently released version of task, and
|
||||
so remotes/origin/1.6.1 and remotes/origin/master are
|
||||
currently identical, with all new development happening on the
|
||||
1.7.0 branch. When 1.7.0 is released, it will get merged to
|
||||
master, and the 1.6.1 branch will be deleted. Nothing will be
|
||||
lost, because 1.6.1 is already merged to master. Let's look
|
||||
at tags:
|
||||
</p>
|
||||
|
||||
<pre><code>% git tag</code></pre>
|
||||
...
|
||||
v1.4.3
|
||||
v1.5.0
|
||||
v1.6.0
|
||||
v1.6.1
|
||||
|
||||
<p>
|
||||
Those tags are just labels that represent the last commit for
|
||||
that version. You may notice that a change in the tag naming
|
||||
convention, that occurred when the owner realized that git
|
||||
will not allow a tag and a branch of the same name at the same
|
||||
time, so now there is a "v" in the tags.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Let's make a branch called 1.7.0 that tracks changes to
|
||||
remotes/origin/1.7.0. That means you can pull 1.7.0 changes
|
||||
from github into your local branch, to keep up to date.
|
||||
</p>
|
||||
|
||||
<pre><code>% git checkout -b 1.7.0 origin/1.7.0
|
||||
Branch 1.7.0 set up to track remote branch 1.7.0 from origin.
|
||||
Switched to a new branch '1.7.0'
|
||||
|
||||
% git branch -a
|
||||
* 1.7.0
|
||||
master
|
||||
remotes/origin/1.6.1
|
||||
remotes/origin/1.7.0
|
||||
remotes/origin/HEAD -> origin/master
|
||||
remotes/origin/master</code></pre>
|
||||
|
||||
<p>
|
||||
Now you can see that 1.7.0 is your current branch (*). That
|
||||
means you are looking at the 1.7.0 codebase. Let us now
|
||||
assume you intend to make a change, and submit the patch. We
|
||||
will add Solaris 8 as a supported OS. This will affect two
|
||||
files. First check status:
|
||||
</p>
|
||||
|
||||
<pre><code>% git status
|
||||
# On branch 1.7.0
|
||||
nothing to commit (working directory clean)</code></pre>
|
||||
|
||||
<p>
|
||||
No changes. That's what we expect. Now make the changes (any
|
||||
editor will suffice, but assume vi):
|
||||
</p>
|
||||
|
||||
<pre><code>% vi NEWS
|
||||
% vi html/task.html</code></pre>
|
||||
|
||||
<p>
|
||||
Now we expect to see changes. Status says:
|
||||
</p>
|
||||
|
||||
<pre><code>% git status
|
||||
# On branch 1.7.0
|
||||
# Changed but not updated:
|
||||
# (use "git add <file>..." to update what will be committed)
|
||||
# (use "git checkout -- <file>..." to discard changes in working directory)
|
||||
#
|
||||
# modified: NEWS
|
||||
# modified: html/task.html
|
||||
#
|
||||
no changes added to commit (use "git add" and/or "git commit -a")</code></pre>
|
||||
|
||||
<p>
|
||||
Git sees that those two files have changed, but as git states,
|
||||
they are not added to the commit. Git allows you to stage
|
||||
changes, then commit the staged changes - a two-step process
|
||||
that gives you complete control. Git also allows you to
|
||||
commit all changes and bypass the staging, but that's a
|
||||
shortcut that is risky, because you can inadvertently commit
|
||||
things you didn't want to. Let's see what git thinks changed:
|
||||
</p>
|
||||
|
||||
<pre><code>% git diff
|
||||
diff --git a/NEWS b/NEWS
|
||||
index 74adecd..30d4f8f 100644
|
||||
--- a/NEWS
|
||||
+++ b/NEWS
|
||||
@@ -12,6 +12,7 @@ Task has been built and tested on the following configurations:
|
||||
- Ubuntu 8.10 Intrepid Ibex
|
||||
- Ubuntu 9.04 Jaunty Jackalope
|
||||
- Arch Linux
|
||||
+ - Solaris 8
|
||||
- Solaris 10
|
||||
- Cygwin 1.5.25-14
|
||||
|
||||
diff --git a/html/task.html b/html/task.html
|
||||
index 66ee777..a2254f6 100644
|
||||
--- a/html/task.html
|
||||
+++ b/html/task.html
|
||||
@@ -193,6 +193,7 @@
|
||||
<li>Ubuntu 8.10 Intrepid Ibex
|
||||
<li>Ubuntu 9.04 Jaunty Jackalope
|
||||
<li>Arch Linux
|
||||
+ <li>Solaris 8
|
||||
<li>Solaris 10
|
||||
<li>Cygwin 1.5.25-14
|
||||
</ul></code></pre>
|
||||
|
||||
<p>
|
||||
Git has correctly spotted the changes. The "git diff" command
|
||||
always tells you the difference between the last commit and
|
||||
the current state. Now we will stage the two changes:
|
||||
</p>
|
||||
|
||||
<pre><code>% git add NEWS html/task.html
|
||||
% git diff</code></pre>
|
||||
|
||||
<p>
|
||||
No changes are reported. That's because if files are staged,
|
||||
then diff shows the difference between the staged files and
|
||||
the current state. We staged all changes, hence no diff. If
|
||||
we wanted to see the difference between the last commit and
|
||||
the staged files, try this:
|
||||
</p>
|
||||
|
||||
<pre><code>% git diff --cached
|
||||
(same as unstaged diff)</code></pre>
|
||||
|
||||
<p>
|
||||
Now the status shows that the files are staged:
|
||||
</p>
|
||||
|
||||
<pre><code>% git status
|
||||
# On branch 1.7.0
|
||||
# Changes to be committed:
|
||||
# (use "git reset HEAD <file>..." to unstage)
|
||||
#
|
||||
# modified: NEWS
|
||||
# modified: html/task.html
|
||||
#</code></pre>
|
||||
|
||||
<p>
|
||||
Now a commit command will commit the staged files:
|
||||
</p>
|
||||
|
||||
<pre><code>% git commit -m "Added Solaris 8 as a supported platform"
|
||||
[1.7.0 03308eb] Added Solaris 8 as a suported platform
|
||||
2 files changed, 2 insertions(+), 0 deletions(-)</code></pre>
|
||||
|
||||
<p>
|
||||
Now make a patch:
|
||||
</p>
|
||||
|
||||
<pre><code>% git format-patch HEAD^
|
||||
0001-Added-Solaris-8-as-a-supported-platform.patch</code></pre>
|
||||
|
||||
<p>
|
||||
HEAD is a label that means the current head of the branch, or
|
||||
in other words, what was last committed. HEAD^ means the
|
||||
commit before that. HEAD~2 is the one before that, HEAD~3
|
||||
etc. When we say create a patch of HEAD^, it means the same
|
||||
as:
|
||||
</p>
|
||||
|
||||
<pre><code>% git diff HEAD^</code></pre>
|
||||
|
||||
<p>
|
||||
Which means show the difference between the previous commit
|
||||
and the current commit, but the patch has extra identifying
|
||||
information in it. Take a look at that patch file. If you
|
||||
ran:
|
||||
</p>
|
||||
|
||||
<pre><code>% git format-patch HEAD~10</code></pre>
|
||||
|
||||
<p>
|
||||
Git will create 10 patch files, one for each commit. To get
|
||||
the patch applied to the repository, email it to the owner.
|
||||
The owner will then apply the patch with:
|
||||
</p>
|
||||
|
||||
<pre><code>owner> git apply 0001-Added-Solaris-8-as-a-supported-platform.patch</code></pre>
|
||||
|
||||
<p>
|
||||
Then push the changes with:
|
||||
</p>
|
||||
|
||||
<pre><code>owner> git push</code></pre>
|
||||
|
||||
<p>
|
||||
And that makes them available on github, which means in turn
|
||||
that the next time you run:
|
||||
</p>
|
||||
|
||||
<pre><code>% git pull</code></pre>
|
||||
|
||||
<p>
|
||||
Your changes will have come full circle.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<div class="content">
|
||||
<p>
|
||||
Copyright 2006-2009, P. Beckingham. All rights reserved.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td align="right" valign="top" width="200px">
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<script type="text/javascript"><!--
|
||||
google_ad_client = "pub-9709799404235424";
|
||||
/* Task Main */
|
||||
google_ad_slot = "8660617875";
|
||||
google_ad_width = 120;
|
||||
google_ad_height = 600;
|
||||
//-->
|
||||
</script>
|
||||
<script type="text/javascript"
|
||||
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
|
||||
</script>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
var pageTracker = _gat._getTracker("UA-4737637-1");
|
||||
pageTracker._initData();
|
||||
pageTracker._trackPageview();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
157
html/import.html
Normal file
157
html/import.html
Normal file
@@ -0,0 +1,157 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Data Import</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<link rel="stylesheet" href="task.css" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div id="toolbar">
|
||||
<a href="task.html">Home</a>
|
||||
<a href="setup.html">Setup</a>
|
||||
<a href="30second.html">30-second Tutorial</a>
|
||||
<a href="simple.html">Simple</a>
|
||||
<a href="advanced.html">Advanced</a>
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<h2 class="title">Data Import</h2>
|
||||
<div class="content">
|
||||
<p>
|
||||
Tasks can be imported from files with this command:
|
||||
|
||||
<pre><code>% task import file</code></pre>
|
||||
|
||||
A variety of different file types are recognized by task, namely:
|
||||
|
||||
<ul>
|
||||
<li>Tasks exported from task prior to version 1.5.0.
|
||||
<li>Tasks exported from task version 1.5.0 and later. The file
|
||||
format changed with 1.5.0.
|
||||
<li>todo.sh files.
|
||||
<li>CSV files with a variety of recognized column names.
|
||||
<li>Plain text files, with one task listed per line.
|
||||
<li>Task command line format.
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Task makes a good effort to determine which of these formats a
|
||||
file is. It does this by reading the file, and looking for
|
||||
familiar patterns. For example, the easiest files to recognize
|
||||
are those exported from task itself, because they all have a
|
||||
header line that comes in only three variations. Other formats
|
||||
are a little harder to identify, but they all have their own
|
||||
identifying characteristics.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The most complex import is when a CSV file is recognized.
|
||||
Task needs a field header line in order to map columns to task
|
||||
data items. For example, the if the following file is
|
||||
imported:
|
||||
</p>
|
||||
|
||||
<pre><code>number,status,task
|
||||
1,pending,task one
|
||||
2,pending,task two</code></pre>
|
||||
|
||||
<p>
|
||||
Task will map the "number" field to task's "id" field, etc,
|
||||
based on name. Task has a list of synonyms that it uses to
|
||||
map fields, but you can specify your own override with any of
|
||||
the following configuration variables:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>import.synonym.id
|
||||
<li>import.synonym.uuid
|
||||
<li>import.synonym.status
|
||||
<li>import.synonym.tags
|
||||
<li>import.synonym.entry
|
||||
<li>import.synonym.start
|
||||
<li>import.synonym.due
|
||||
<li>import.synonym.recur
|
||||
<li>import.synonym.end
|
||||
<li>import.synonym.project
|
||||
<li>import.synonym.priority
|
||||
<li>import.synonym.fg
|
||||
<li>import.synonym.bg
|
||||
<li>import.synonym.description
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Please note that it is wise to backup your task data files
|
||||
before an import.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<div class="content">
|
||||
<p>
|
||||
Copyright 2006-2009, P. Beckingham. All rights reserved.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td align="right" valign="top" width="200px">
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<script type="text/javascript"><!--
|
||||
google_ad_client = "pub-9709799404235424";
|
||||
/* Task Main */
|
||||
google_ad_slot = "8660617875";
|
||||
google_ad_width = 120;
|
||||
google_ad_height = 600;
|
||||
//-->
|
||||
</script>
|
||||
<script type="text/javascript"
|
||||
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
|
||||
</script>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
var pageTracker = _gat._getTracker("UA-4737637-1");
|
||||
pageTracker._initData();
|
||||
pageTracker._trackPageview();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="usage.html">Usage</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="troubleshooting.html">Troubleshooting</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="usage.html">Usage</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="troubleshooting.html">Troubleshooting</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
@@ -52,7 +51,7 @@
|
||||
generated on a regular basis. Consider the example:
|
||||
</p>
|
||||
|
||||
<pre><code>% task Pay rent due:7/1/2008 recur:monthly</code></pre>
|
||||
<pre><code>% task add Pay rent due:7/1/2008 recur:monthly</code></pre>
|
||||
|
||||
<p>
|
||||
If today's date is 7/10, for example, then that due date is in the past, and
|
||||
@@ -81,7 +80,7 @@ ID Project Pri Due Active Age Description
|
||||
Thursdays instead:
|
||||
</p>
|
||||
|
||||
<pre><code>% task TPS report due:thursday recur:weekly until:8/31/2008</code></pre>
|
||||
<pre><code>% task add TPS report due:thursday recur:weekly until:8/31/2008</code></pre>
|
||||
|
||||
<p>
|
||||
This create a weekly recurring task that expires on 8/31/2008. What this means
|
||||
@@ -101,6 +100,13 @@ Permanently delete task? (y/n) y
|
||||
This is a recurring task. Do you want to delete all pending
|
||||
recurrences of this same task? (y/n) y</code></pre>
|
||||
|
||||
<h4>Modification</h4>
|
||||
<p>
|
||||
When a recurring task is modified, all the other recurring task instances will
|
||||
be modified. For example, if you raise the priority of one of the recurring
|
||||
task instances, all will be modified.
|
||||
</p>
|
||||
|
||||
<h4>Recurrence Periods</h4>
|
||||
<p>
|
||||
In the above examples, the recurrence period was specified as "monthly" and
|
||||
@@ -116,6 +122,13 @@ recurrences of this same task? (y/n) y</code></pre>
|
||||
<td class="table_d">daily, day, 1d, 2d ...</td>
|
||||
<td class="table_d">Every day, or a number of days</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="table_d">weekdays</td>
|
||||
<td class="table_d">
|
||||
Monday, Tuesday, Wednesday, Thursday and Friday,
|
||||
skipping weekend days
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="table_d">weekly, 1w, 2w ...</td>
|
||||
<td class="table_d">Every week, or a number of weeks</td>
|
||||
|
||||
154
html/sequence.html
Normal file
154
html/sequence.html
Normal file
@@ -0,0 +1,154 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Task Usage</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<link rel="stylesheet" href="task.css" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div id="toolbar">
|
||||
<a href="task.html">Home</a>
|
||||
<a href="setup.html">Setup</a>
|
||||
<a href="30second.html">30-second Tutorial</a>
|
||||
<a href="simple.html">Simple</a>
|
||||
<a href="advanced.html">Advanced</a>
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<h1 class="title">ID Sequences</h1>
|
||||
<div class="content">
|
||||
<p>
|
||||
Some task commands require an ID to be specified. For example:
|
||||
</p>
|
||||
|
||||
<pre><code>% task 3 done</code></pre>
|
||||
|
||||
<p>
|
||||
This marks a single task as done. But if you wanted to mark
|
||||
several tasks as done, you could use:
|
||||
</p>
|
||||
|
||||
<pre><code>% task 3,4,5 done</code></pre>
|
||||
|
||||
<p>
|
||||
Which would mark tasks 3, 4 and 5 as all done. In this example,
|
||||
the three IDs are consecutive, which means you could also have
|
||||
entered:
|
||||
</p>
|
||||
|
||||
<pre><code>% task 3-5 done</code></pre>
|
||||
|
||||
<p>
|
||||
Or in a more complex example:
|
||||
</p>
|
||||
|
||||
<pre><code>% task 1,3-5,12 23-25 done</code></pre>
|
||||
|
||||
<p>
|
||||
This would mark tasks 1, 3, 4, 5, 12, 23, 24 and 25 as done.
|
||||
Note that this example uses two sequences, separated by a space.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You must be careful though. Task tries very carefully to do
|
||||
the right thing when it interprets the command line, but must
|
||||
still impose some rules so that it can unambiguously read the
|
||||
command. If you use one or more sequences, then they must
|
||||
appear on the command line adjacent to each other. If they
|
||||
are separated by something else, then task assumes the second
|
||||
and subsequent set is not a sequence. Here is an example
|
||||
of this:
|
||||
</p>
|
||||
|
||||
<pre><code>% task 3 Order part number 4-123</code></pre>
|
||||
|
||||
<p>
|
||||
Clearly the 4-123 is a part number, and not a sequence.
|
||||
Task is being asked to modify the description of task 3 to be
|
||||
"Order part number 4-123". Note that the ID is separated
|
||||
from the part number by something other than a sequence.
|
||||
Here is a bad example that task will misinterpret:
|
||||
</p>
|
||||
|
||||
<pre><code>% task 3 4-123 is back-ordered, try again next week</code></pre>
|
||||
|
||||
<p>
|
||||
The intent here is that task 3 have its description modified to be
|
||||
"40123 is back-ordered, try again next week", but will be
|
||||
misinterpreted as tasks 3, 4, 5, 6 ... 123 will all be modified
|
||||
to have the description "is back-ordered, try again next week".
|
||||
The solution is to quote the whole description:
|
||||
</p>
|
||||
|
||||
<pre><code>% task 3 "4-123 is back-ordered, try again next week"</code></pre>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<div class="content">
|
||||
<p>
|
||||
Copyright 2006-2009, P. Beckingham. All rights reserved.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td align="right" valign="top" width="200px">
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<script type="text/javascript"><!--
|
||||
google_ad_client = "pub-9709799404235424";
|
||||
/* Task Main */
|
||||
google_ad_slot = "8660617875";
|
||||
google_ad_width = 120;
|
||||
google_ad_height = 600;
|
||||
//-->
|
||||
</script>
|
||||
<script type="text/javascript"
|
||||
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
|
||||
</script>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
var pageTracker = _gat._getTracker("UA-4737637-1");
|
||||
pageTracker._initData();
|
||||
pageTracker._trackPageview();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="usage.html">Usage</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="troubleshooting.html">Troubleshooting</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
@@ -40,10 +39,10 @@
|
||||
</p>
|
||||
|
||||
<pre><code>% ls
|
||||
task-1.4.1.tar.gz
|
||||
% gunzip task-1.4.1.tar.gz
|
||||
% tar xf task-1.4.1.tar
|
||||
% cd task-1.4.1
|
||||
task-1.6.0.tar.gz
|
||||
% gunzip task-1.6.0.tar.gz
|
||||
% tar xf task-1.6.0.tar
|
||||
% cd task-1.6.0
|
||||
% ./configure
|
||||
...
|
||||
% make
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="usage.html">Usage</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="troubleshooting.html">Troubleshooting</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
@@ -53,15 +52,18 @@
|
||||
|
||||
<p>
|
||||
To use a shadow file, edit your .taskrc configuration file,
|
||||
and add two entries as shown:
|
||||
and add three entries as shown:
|
||||
</p>
|
||||
|
||||
<pre><code>shadow.file=/path/to/file
|
||||
shadow.command=list pri:H</code></pre>
|
||||
shadow.command=list pri:H
|
||||
shadow.notify=on</code></pre>
|
||||
|
||||
<p>
|
||||
In this example the shadow file contains a report equivalent
|
||||
to running "task list pri:H".
|
||||
to running "task list pri:H". Note that the third entry
|
||||
causes a message to be displayed whenever task updates the
|
||||
shadow file. It is optional.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="usage.html">Usage</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="troubleshooting.html">Troubleshooting</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="usage.html">Usage</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="troubleshooting.html">Troubleshooting</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Task Troubleshooting Guide</title>
|
||||
<title>Tab Completion</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<link rel="stylesheet" href="task.css" type="text/css" />
|
||||
</head>
|
||||
@@ -20,10 +20,9 @@
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="usage.html">Usage</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="troubleshooting.html">Troubleshooting</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
@@ -32,54 +31,24 @@
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<h1 class="title">Task Troubleshooting Guide</h1>
|
||||
<p>
|
||||
Here you will find tips and suggestions for making task behave
|
||||
properly, and bug workarounds.
|
||||
</p>
|
||||
|
||||
<br />
|
||||
<h2 class="title">Segmentation Fault for certain commands</h2>
|
||||
<h2 class="title"><a name="simple">Tab Completion</a></h2>
|
||||
<div class="content">
|
||||
<p>
|
||||
Upgrading task to version 1.1.0, 1.2.0 and 1.3.0 can cause
|
||||
segmentation faults. This is mostly occurring for Ubuntu users,
|
||||
although there is no reason for it to be limited to Ubuntu.
|
||||
There is a Bash tab completion script distributed with task,
|
||||
called task_completion.sh.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Task 1.3.1 fixes this bug, but there is a workaround for users
|
||||
of earlier versions. Add the following line to your ~/.taskrc
|
||||
file:
|
||||
</p>
|
||||
To install it, copy it to your
|
||||
|
||||
<code><pre>dateformat=m/d/Y</pre></code>
|
||||
<code>/etc/bash_completion.d</code>
|
||||
|
||||
<p class="small">
|
||||
The "dateformat" setting is supported in task 1.1.0 and later.
|
||||
</p>
|
||||
</div>
|
||||
directory (in case you want to have it available system-wide)
|
||||
and then
|
||||
|
||||
<br />
|
||||
<h2 class="title">How do I build task under Cygwin?</h2>
|
||||
<div class="content">
|
||||
<p>
|
||||
Task is built the same way everywhere. But under Cygwin, you'll
|
||||
need to make sure you have the following packages available
|
||||
first:
|
||||
<pre><code>source /etc/bash_completion</code></pre>
|
||||
|
||||
<ul>
|
||||
<li>gcc
|
||||
<li>make
|
||||
<li>libncurses-devel
|
||||
<li>libncurses8
|
||||
</ul>
|
||||
|
||||
The gcc and make packages allow you to compile the code, and
|
||||
are therefore required, but the ncurses packages are optional.
|
||||
Ncurses will allow task to determine the width of the window, and
|
||||
therefore use the whole width and wrap text accordingly, for a
|
||||
more aesthetically pleasing display.
|
||||
or source it from your home directory's bashrc files.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
174
html/task.html
174
html/task.html
@@ -20,10 +20,9 @@
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="usage.html">Usage</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="troubleshooting.html">Troubleshooting</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
@@ -50,14 +49,17 @@
|
||||
<li><a href="shell.html">Interacting with the Shell</a>
|
||||
<li><a href="config.html">Configuring Task</a>
|
||||
<li><a href="color.html">Color</a>
|
||||
<li><a href="usage.html">Task Command Usage</a>
|
||||
<li><a href="recur.html">Recurring Tasks</a>
|
||||
<li><a href="date.html">Date Handling</a>
|
||||
<li><a href="troubleshooting.html">Troubleshooting</a>
|
||||
<li><a href="versions.html">Old Versions</a>
|
||||
<li><a href="filter.html">Filters</a>
|
||||
<li><a href="shadow.html">Shadow Files</a>
|
||||
<li><a href="custom.html">Custom Reports</a>
|
||||
<li><a href="import.html">Data Import</a>
|
||||
<li><a href="faq.html">Frequently Asked Questions</a>
|
||||
<li><a href="sequence.html">ID Sequences</a>
|
||||
<li><a href="tab_completion.html">Tab Completion</a>
|
||||
<li><a href="git.html">How to use git and contribute to task</a>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
@@ -70,6 +72,40 @@
|
||||
which illustrates many of task's features.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For the latest news, discussion of proposed task features, and
|
||||
somewhere to voice your opinions, join us at
|
||||
<a href="http://groups.google.com/group/taskprogram">http://groups.google.com/group/taskprogram</a>.
|
||||
|
||||
<table border=0 style="background-color: #fff; padding: 5px;" cellspacing=0>
|
||||
<tr>
|
||||
<td>
|
||||
<img src="http://groups.google.com/groups/img/3nb/groups_bar.gif"
|
||||
height=26 width=132 alt="Google Groups">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-left: 5px">
|
||||
<b>Subscribe to taskprogram</b>
|
||||
</td>
|
||||
</tr>
|
||||
<form action="http://groups.google.com/group/taskprogram/boxsubscribe">
|
||||
<tr>
|
||||
<td style="padding-left: 5px;">
|
||||
Email:
|
||||
<input type=text name=email>
|
||||
<input type=submit name="sub" value="Subscribe">
|
||||
</td>
|
||||
</tr>
|
||||
</form>
|
||||
<tr>
|
||||
<td align=right>
|
||||
<a href="http://groups.google.com/group/taskprogram">Visit this group</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
<h2 class="title">Get the Latest Stable Release</h2>
|
||||
|
||||
@@ -77,95 +113,78 @@
|
||||
<table>
|
||||
<tr>
|
||||
<td>Source:</td>
|
||||
<td><a href="http://www.beckingham.net/task-1.5.0.tar.gz">task-1.5.0.tar.gz</a></td>
|
||||
<td><a href="http://www.beckingham.net/task-1.7.0.tar.gz">task-1.7.0.tar.gz</a></td>
|
||||
</tr>
|
||||
<!--
|
||||
<tr>
|
||||
<td>Mac OS X 10.5 (Leopard) Intel-only:</td>
|
||||
<td><a href="http://www.beckingham.net/task-1.5.0.pkg">task-1.5.0.pkg</a></td>
|
||||
<td><a href="http://www.beckingham.net/task-1.7.0.pkg">task-1.7.0.pkg</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Debian package:
|
||||
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>):
|
||||
Debian:
|
||||
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>):
|
||||
</td>
|
||||
<td><a href="http://www.beckingham.net/task_1.5.0-1_i386.deb">task_1.5.0-1_i386.deb</a></td>
|
||||
<td><a href="http://www.beckingham.net/task_1.7.0-1_i386.deb">task_1.7.0-1_i386.deb</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Red Hat:
|
||||
(Thanks to <a href="http://www.ultrafredde.com">Federico Hernandez</a>):
|
||||
</td>
|
||||
<td><a href="http://www.beckingham.net/task-1.7.0-1.FC10.i386.rpm">task-1.7.0-1.FC10.i386.rpm</a></td>
|
||||
</tr>
|
||||
-->
|
||||
<tr>
|
||||
<td>Git - get the whole source and history:</td>
|
||||
<td><a href="http://github.com/pbeckingham/task">http://github.com/pbeckingham/task</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h4>New in version 1.5.0 (3/15/2009)</h4>
|
||||
<h4>New in version 1.7.0 (5/14/2009)</h4>
|
||||
<ul>
|
||||
<li>Removed deprecated TUTORIAL file.
|
||||
<li>Removed support for the "showage" configuration variable.
|
||||
<li>"task stop" can remove the start time from a started task.
|
||||
<li>"task ghistory" now displays a differently aligned graph, allowing
|
||||
easier comparison by month of tasks added versus completed and deleted.
|
||||
<li>"task version" command now reports unrecognized configuration variables,
|
||||
which may be spelling mistakes or deprecated variables.
|
||||
<li>"configure --enable-debug" now supported to suppress compiler optimization
|
||||
to allow debugging.
|
||||
<li>Allow lower case priorities, and automatically upper case them.
|
||||
<li>Added support for "due" configuration variable which defines the number
|
||||
of days in the future when a task is considered due.
|
||||
<li>Added support for custom reports, comprised of a set of column names and
|
||||
sort order, with optional filtering in the configuration file. This
|
||||
means user-defined reports can be written, and the reports currently
|
||||
in the configuration file can be renamed. Several of task's built in
|
||||
reports have been converted to user-defined reports.
|
||||
<li>New online documentation for custom reports.
|
||||
<li>New algorithm for determining when the "nag" message is displayed.
|
||||
<li>Fixed bug where task hangs with a certain combination of recurring tasks
|
||||
and shadow files.
|
||||
<li>Fixed bug with the task sort algorithm, which led to an unstable sequence
|
||||
when there were only a handful of tasks.
|
||||
<li>Performance enhanced by eliminating unnecessary sorting.
|
||||
<li>Task now has a large (and growing) test suite and bug regression tests
|
||||
to help ensure higher quality releases.
|
||||
<li>Fixed bug that caused large performance hit during table rendering.
|
||||
<li>Fixed bug that concatenated a modified description without spaces.
|
||||
<li>Added new column 'recur' that displays the recurrence period of any
|
||||
recurring tasks. This column can be added to any custom report.
|
||||
<li>Added support for "color.recurring" configuration variable which
|
||||
specifies the color of recurring tasks.
|
||||
<li>Added support for "locking" configuration variable that controls whether
|
||||
file locking is used.
|
||||
<li>Task export feature now includes recurrence information, removes nested
|
||||
quotes, and limits output to pending tasks.
|
||||
<li>Task no longer includes deleted tasks in the summary report (thanks to
|
||||
Benjamin Tegarden).
|
||||
<li>Fixed bug that prevented the summary report from properly reporting
|
||||
recently completed tasks.
|
||||
<li>Improved the errors when parsing a corrupt or unrecognized pending.data
|
||||
or completed.data file (thanks to T. Charles Yun).
|
||||
<li>Added details to the "info" report about recurring tasks (thanks to T.
|
||||
Charles Yun).
|
||||
<li>Now writes a sample "defaultwidth" configuration variable to the default
|
||||
.taskrc file (thanks to T. Charles Yun).
|
||||
<li>Task allows commands that require an ID to now be given a sequence, which
|
||||
is a set of IDs. This allows commands like "task delete 1 2 5-10,12".
|
||||
<li>Fixed bug in the ghistory report, which caused it to only show a new
|
||||
month if a task was added during that month.
|
||||
<li>New command "duplicate" which allows an existing task to be duplicated,
|
||||
and also have modifications applied (thanks to David J Patrick).
|
||||
<li>The "append", and "done" commands now allow modifications to be applied
|
||||
to the task(s) (thanks to David J Patrick).
|
||||
<li>Improved word wrapping in various output.
|
||||
<li>Fixed bug that added an extra line between header and graph in the
|
||||
ghistory report.
|
||||
<li>Added simple 'taskprogram' mailing list subscribe form to the web site.
|
||||
<li>For custom reports that define a "limit" to the number of rows of output
|
||||
such as "oldest" and "newest", task allows an override value. For
|
||||
example "task oldest 5" will display the 5 oldest tasks.
|
||||
<li>Modified the "stats" report so that it has the same aesthetics as the
|
||||
other reports.
|
||||
<li>New "timesheet" command displays tasks completed and started, per week,
|
||||
and can display multiple weeks.
|
||||
<li>New tab completion script, task_completion.sh, for bash users, is installed
|
||||
to /usr/local/share/task (thanks to Federico Hernandez).
|
||||
<li>Applied patch to allow task to build on Arch Linux (thanks to Johan Friis).
|
||||
<li>Applied patch to fix a UUID bug on Solaris 8 (thanks to Steven de Brouwer).
|
||||
<li>The task man page is now installed. Try "man task" (thanks to Federico
|
||||
Hernandez and P.C. Shyamshankar).
|
||||
<li>Fixed bug that causes task to create a default .task directory, even if
|
||||
data.location specified otherwise (thanks to Federico Hernandez).
|
||||
<li>New "edit" command that fires up a text editor (uses 'editor' configuration
|
||||
variable, $VISUAL or $EDITOR environment variable) and allows direct
|
||||
editing of all editable task details.
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
(Find out <a href="versions.html">what was new in prior versions</a>)
|
||||
</p>
|
||||
<!--
|
||||
<h2>Task 1.5.0 Beta</h2>
|
||||
<p>
|
||||
The next version of task is in beta. This means it is approaching the
|
||||
end of the current development and testing cycle, and feedback from
|
||||
a wider audience is needed to find the last bugs. If you would like
|
||||
to help test the next release of task, download the beta source below
|
||||
and install in the usual manner.
|
||||
</p>
|
||||
<p>
|
||||
Please note that beta software may contain significant bugs. If you
|
||||
use this beta release, you should first backup your existing task
|
||||
data files.
|
||||
</p>
|
||||
<p>
|
||||
Refer to the ChangeLog file for details regarding the various fixes
|
||||
and enhancements.
|
||||
</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Source:</td>
|
||||
<td><a href="http://www.beckingham.net/task-1.5.0beta.tar.gz">task-1.5.0beta.tar.gz</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
-->
|
||||
|
||||
<h2>Troubleshooting</h2>
|
||||
<p>
|
||||
Task has been built from source and tested in the following environments:
|
||||
@@ -181,6 +200,9 @@
|
||||
<li>Ubuntu 7 Feisty Fawn
|
||||
<li>Ubuntu 8 Hardy Heron
|
||||
<li>Ubuntu 8.10 Intrepid Ibex
|
||||
<li>Ubuntu 9.04 Jaunty Jackalope
|
||||
<li>Arch Linux
|
||||
<li>Solaris 8
|
||||
<li>Solaris 10
|
||||
<li>Cygwin 1.5.25-14
|
||||
</ul>
|
||||
@@ -193,7 +215,7 @@
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Take a look at the <a href="troubleshooting.html">troubleshooting guide</a>
|
||||
Take a look at the <a href="faq.html">FAQ</a>
|
||||
for tips and workarounds to problems.
|
||||
</p>
|
||||
|
||||
|
||||
151
html/usage.html
151
html/usage.html
@@ -1,151 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Task Usage</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<link rel="stylesheet" href="task.css" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<div id="toolbar">
|
||||
<a href="task.html">Home</a>
|
||||
<a href="setup.html">Setup</a>
|
||||
<a href="30second.html">30-second Tutorial</a>
|
||||
<a href="simple.html">Simple</a>
|
||||
<a href="advanced.html">Advanced</a>
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="usage.html">Usage</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="troubleshooting.html">Troubleshooting</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<h2 class="title"><a name="usage">Command Usage<a></h2>
|
||||
<div class="content">
|
||||
<pre><code>Usage: task
|
||||
task add [tags] [attrs] desc...
|
||||
task completed [tags] [attrs] desc...
|
||||
task ID [tags] [attrs] [desc...]
|
||||
task ID /from/to/
|
||||
task delete ID
|
||||
task undelete ID
|
||||
task info ID
|
||||
task start ID
|
||||
task stop ID
|
||||
task done ID
|
||||
task undo ID
|
||||
task projects
|
||||
task tags
|
||||
task summary
|
||||
task history
|
||||
task ghistory
|
||||
task next
|
||||
task calendar
|
||||
task active
|
||||
task overdue
|
||||
task stats
|
||||
task export
|
||||
task color
|
||||
task version
|
||||
task help
|
||||
task list [tags] [attrs] desc...
|
||||
task long [tags] [attrs] desc...
|
||||
task ls [tags] [attrs] desc...
|
||||
task newest [tags] [attrs] desc...
|
||||
task oldest [tags] [attrs] desc...
|
||||
|
||||
See http://www.beckingham.net/task.html for the latest releases and a full tutorial.
|
||||
|
||||
ID is the numeric identifier displayed by the 'task list' command
|
||||
|
||||
Tags are arbitrary words, any quantity:
|
||||
+tag The + means add the tag
|
||||
-tag The - means remove the tag
|
||||
|
||||
Attributes are:
|
||||
project: Project name
|
||||
priority: Priority
|
||||
due: Due date
|
||||
recur: Recurrence frequency
|
||||
until: Recurrence end date
|
||||
fg: Foreground color
|
||||
bg: Background color
|
||||
rc: Alternate .taskrc file
|
||||
|
||||
Any command or attribute name may be abbreviated if still unique:
|
||||
task list project:Home
|
||||
task li pro:Home
|
||||
|
||||
Some task descriptions need to be escaped because of the shell:
|
||||
task add "quoted ' quote"
|
||||
task add escaped \' quote
|
||||
|
||||
Many characters have special meaning to the shell, including:
|
||||
$ ! ' " ( ) ; \ ` * ? { } [ ] < > | & % # ~</code></pre>
|
||||
<div>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<div class="content">
|
||||
<p>
|
||||
Copyright 2006-2009, P. Beckingham. All rights reserved.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td align="right" valign="top" width="200px">
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<script type="text/javascript"><!--
|
||||
google_ad_client = "pub-9709799404235424";
|
||||
/* Task Main */
|
||||
google_ad_slot = "8660617875";
|
||||
google_ad_width = 120;
|
||||
google_ad_height = 600;
|
||||
//-->
|
||||
</script>
|
||||
<script type="text/javascript"
|
||||
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
|
||||
</script>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
|
||||
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
var pageTracker = _gat._getTracker("UA-4737637-1");
|
||||
pageTracker._initData();
|
||||
pageTracker._trackPageview();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
<a href="shell.html">Shell</a>
|
||||
<a href="config.html">Configuration</a>
|
||||
<a href="color.html">Colors</a>
|
||||
<a href="usage.html">Usage</a>
|
||||
<a href="recur.html">Recurrence</a>
|
||||
<a href="date.html">Date Handling</a>
|
||||
<a href="troubleshooting.html">Troubleshooting</a>
|
||||
<a href="faq.html">FAQ</a>
|
||||
<a href="versions.html">Old Versions</a>
|
||||
<a href="links.html">Task on the Web</a>
|
||||
</div>
|
||||
@@ -36,6 +35,192 @@
|
||||
<br />
|
||||
|
||||
<div class="content">
|
||||
<h4>New in version 1.6.1 (4/24/2009)</h4>
|
||||
<p>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Source:</td>
|
||||
<td><a href="http://www.beckingham.net/task-1.6.1.tar.gz">task-1.6.1.tar.gz</a></td>
|
||||
</tr>
|
||||
<!--
|
||||
<tr>
|
||||
<td>Mac OS X 10.5 (Leopard) Intel-only:</td>
|
||||
<td><a href="http://www.beckingham.net/task-1.6.1.pkg">task-1.6.1.pkg</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Debian:
|
||||
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>):
|
||||
</td>
|
||||
<td><a href="http://www.beckingham.net/task_1.6.1-1_i386.deb">task_1.6.1-1_i386.deb</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Red Hat:
|
||||
(Thanks to <a href="http://www.ultrafredde.com">Federico Hernandez</a>):
|
||||
</td>
|
||||
<td><a href="http://www.beckingham.net/task-1.6.1-1.FC10.i386.rpm">task-1.6.1-1.FC10.i386.rpm</a></td>
|
||||
</tr>
|
||||
-->
|
||||
<tr>
|
||||
<td>Git - get the whole source and history:</td>
|
||||
<td><a href="http://github.com/pbeckingham/task">http://github.com/pbeckingham/task</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<ul>
|
||||
<li>Fixed bug that caused new, first-time .taskrc files to be written without
|
||||
including the custom report labels (thanks to P.C. Shyamshankar).
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<h4>New in version 1.6.0 (4/13/2009)</h4>
|
||||
<p>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Source:</td>
|
||||
<td><a href="http://www.beckingham.net/task-1.6.0.tar.gz">task-1.6.0.tar.gz</a></td>
|
||||
</tr>
|
||||
<!--
|
||||
<tr>
|
||||
<td>Mac OS X 10.5 (Leopard) Intel-only:</td>
|
||||
<td><a href="http://www.beckingham.net/task-1.6.0.pkg">task-1.6.0.pkg</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Debian:
|
||||
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>):
|
||||
</td>
|
||||
<td><a href="http://www.beckingham.net/task_1.6.0-1_i386.deb">task_1.6.0-1_i386.deb</a></td>
|
||||
</tr>
|
||||
-->
|
||||
<tr>
|
||||
<td>
|
||||
Red Hat:
|
||||
(Thanks to <a href="http://www.ultrafredde.com">Federico Hernandez</a>):
|
||||
</td>
|
||||
<td><a href="http://www.beckingham.net/task-1.6.0-1.FC10.i386.rpm">task-1.6.0-1.FC10.i386.rpm</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Git - get the whole source and history:</td>
|
||||
<td><a href="http://github.com/pbeckingham/task">http://github.com/pbeckingham/task</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<ul>
|
||||
<li>Added support for new "append" command that adds more description text to
|
||||
an existing task.
|
||||
<li>Added support for the "weekdays" recurrence, which means a task can recur
|
||||
five times a week, and not on weekends (thanks to Chris Pride).
|
||||
<li>UTF8 text is now supported in task project names, tags and descriptions.
|
||||
<li>Fixed bug that caused the y/n confirmation on task deletion to ignore the
|
||||
Enter key and fail to re-prompt (thanks to Bruce Dillahunty).
|
||||
<li>When the "echo.command" configuration variable is set to "yes", it causes
|
||||
commands that modify tasks to display which task was affected (thanks to
|
||||
Bruce Dillahunty).
|
||||
<li>A task can now be annotated with the command "task <id> annotate ...", and
|
||||
a timestamped annotation will appear in reports.
|
||||
<li>A 'description_only' column is now available for use in custom reports,
|
||||
and it excludes annotations.
|
||||
<li>A task can now be upgraded to a recurring task by adding a recurrence
|
||||
frequency, a due date, and an optional until date.
|
||||
<li>When a recurring task is modified, all other instances of the recurring
|
||||
task are also modified.
|
||||
<li>Custom reports now support user-specified column labels (thanks to T.
|
||||
Charles Yun).
|
||||
<li>Task can now import tasks from a variety of data formats, including task
|
||||
export files from versions 1.4.3 and earlier, versions 1.5.0 and later,
|
||||
todo.sh 2.x, CSV, plain text and task command line. See online docs for
|
||||
full details.
|
||||
<li>Export was including 'id' in the column header even though it was not
|
||||
included in the data.
|
||||
<li>The task file format has changed slightly. Please back up your task
|
||||
data files before upgrading to 1.6.0.
|
||||
<li>Added new column 'recurrence_indicator' that displays an 'R' if the task
|
||||
is a recurring task. This column can be added to any custom report.
|
||||
<li>Added new column 'tag_indicator' that displays a '+' if the task
|
||||
has any tags. This column can be added to any custom report.
|
||||
<li>Fixed bug where sometimes a task description was concatenated oddly if
|
||||
there was a colon somewhere in the description.
|
||||
<li>Fixed bug that caused recurring annual tasks to exhibit a creeping due
|
||||
date, because of an assumption of 365 days per year, which failed to
|
||||
consider leap years (thanks to T. Charles Yun).
|
||||
<li>Annotations can now be modified with the substitution commands /from/to/.
|
||||
<li>Substitutions can now be made global with /from/to/g and all occurrences
|
||||
of "from" will be replaced with "to".
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<h4>New in version 1.5.0 (3/15/2009)</h4>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Source:</td>
|
||||
<td><a href="http://www.beckingham.net/task-1.5.0.tar.gz">task-1.5.0.tar.gz</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mac OS X 10.5 (Leopard) Intel-only:</td>
|
||||
<td><a href="http://www.beckingham.net/task-1.5.0.pkg">task-1.5.0.pkg</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Debian:
|
||||
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>):
|
||||
</td>
|
||||
<td><a href="http://www.beckingham.net/task_1.5.0-1_i386.deb">task_1.5.0-1_i386.deb</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Red Hat:
|
||||
(Thanks to <a href="http://www.ultrafredde.com">Federico Hernandez</a>):
|
||||
</td>
|
||||
<td><a href="http://www.beckingham.net/task-1.5.0-1.i386.rpm">task-1.5.0-1.i386.rpm</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<ul>
|
||||
<li>Removed deprecated TUTORIAL file.
|
||||
<li>Removed support for the "showage" configuration variable.
|
||||
<li>"task stop" can remove the start time from a started task.
|
||||
<li>"task ghistory" now displays a differently aligned graph, allowing
|
||||
easier comparison by month of tasks added versus completed and deleted.
|
||||
<li>"task version" command now reports unrecognized configuration variables,
|
||||
which may be spelling mistakes or deprecated variables.
|
||||
<li>"configure --enable-debug" now supported to suppress compiler optimization
|
||||
to allow debugging.
|
||||
<li>Allow lower case priorities, and automatically upper case them.
|
||||
<li>Added support for "due" configuration variable which defines the number
|
||||
of days in the future when a task is considered due.
|
||||
<li>Added support for custom reports, comprised of a set of column names and
|
||||
sort order, with optional filtering in the configuration file. This
|
||||
means user-defined reports can be written, and the reports currently
|
||||
in the configuration file can be renamed. Several of task's built in
|
||||
reports have been converted to user-defined reports.
|
||||
<li>New online documentation for custom reports.
|
||||
<li>New algorithm for determining when the "nag" message is displayed.
|
||||
<li>Fixed bug where task hangs with a certain combination of recurring tasks
|
||||
and shadow files.
|
||||
<li>Fixed bug with the task sort algorithm, which led to an unstable sequence
|
||||
when there were only a handful of tasks.
|
||||
<li>Performance enhanced by eliminating unnecessary sorting.
|
||||
<li>Task now has a large (and growing) test suite and bug regression tests
|
||||
to help ensure higher quality releases.
|
||||
<li>Fixed bug that caused large performance hit during table rendering.
|
||||
<li>Fixed bug that concatenated a modified description without spaces.
|
||||
<li>Added new column 'recur' that displays the recurrence period of any
|
||||
recurring tasks. This column can be added to any custom report.
|
||||
<li>Added support for "color.recurring" configuration variable which
|
||||
specifies the color of recurring tasks.
|
||||
<li>Added support for "locking" configuration variable that controls whether
|
||||
file locking is used.
|
||||
<li>Task export feature now includes recurrence information, removes nested
|
||||
quotes, and limits output to pending tasks.
|
||||
<li>Task no longer includes deleted tasks in the summary report (thanks to
|
||||
Benjamin Tegarden).
|
||||
<li>Fixed bug that prevented the summary report from properly reporting
|
||||
recently completed tasks.
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<h4>New in version 1.4.3 (11/1/2008)</h4>
|
||||
<a href="http://www.beckingham.net/task-1.4.3.tar.gz">task-1.4.3.tar.gz</a>
|
||||
@@ -47,6 +232,7 @@
|
||||
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<ul>
|
||||
<li>Fixed misleading task count at bottom of "info" report.
|
||||
<li>Added support for a shadow file that contains a plain text task report,
|
||||
|
||||
94
script.txt
94
script.txt
@@ -1,109 +1,109 @@
|
||||
Hello, and welcome to this quick demo of the task program.
|
||||
Hello, and welcome to this quick demo of the task program.
|
||||
|
||||
task add do laundry Let's add some tasks
|
||||
I need to do laundry
|
||||
task add do laundry Let's add some tasks
|
||||
I need to do laundry
|
||||
|
||||
task add project:garage order dumpster Oh yeah, I need to order the dumpster
|
||||
task add project:garage order dumpster Oh yeah, I need to order the dumpster
|
||||
|
||||
task add +phone tell mom i loveher Must call Mom (that "phone" there is a tag - they can
|
||||
be useful for searching and categorizing)
|
||||
task add +phone tell mom i loveher Must call Mom (that "phone" there is a tag - they can
|
||||
be useful for searching and categorizing)
|
||||
task add +phone pro:garage schedule
|
||||
goodwill pickup
|
||||
|
||||
task ad +email pro:garage ask Tom if Notice I can abbreviate commands
|
||||
task ad +email pro:garage ask Tom if Notice I can abbreviate commands
|
||||
he wants that old bkie
|
||||
|
||||
task ls Let's see what we've got
|
||||
Oh, I spelled bike wrong
|
||||
task ls Let's see what we've got
|
||||
Oh, I spelled bike wrong
|
||||
|
||||
task 5 /bkie/bike/
|
||||
task ls That's better
|
||||
task ls That's better
|
||||
|
||||
task 1 pro:home Let's assign projects
|
||||
task 1 pro:home Let's assign projects
|
||||
task 3 pro:home tell mom I love her
|
||||
task ls pro:garage
|
||||
|
||||
task long pro:garage Let's see all the columns
|
||||
task long pro:garage Let's see all the columns
|
||||
|
||||
task list pro:garage There are different ways to list
|
||||
task list pro:garage There are different ways to list
|
||||
|
||||
task lis +phone By tag
|
||||
task li pro:garage +phone By project and tag
|
||||
task l mom By word
|
||||
task lis +phone By tag
|
||||
task li pro:garage +phone By project and tag
|
||||
task l mom By word
|
||||
|
||||
task 1 priority:H Priorities can be High, Medium or Low
|
||||
task 1 priority:H Priorities can be High, Medium or Low
|
||||
task pri:H 3
|
||||
task 1 pri:M
|
||||
task li The list is sorted by priority.
|
||||
task li The list is sorted by priority.
|
||||
|
||||
task 2 pri:L
|
||||
task li
|
||||
|
||||
task done 3 Suppose task 3 is done
|
||||
task li ...and it's gone
|
||||
task done 3 Suppose task 3 is done
|
||||
task li ...and it's gone
|
||||
|
||||
task 2 +phone +mistake Lets add tags
|
||||
task 2 +phone +mistake Lets add tags
|
||||
|
||||
# Oops!
|
||||
task 2 -mistake or remove tags
|
||||
task 2 -mistake or remove tags
|
||||
|
||||
task tags or look at all the tags
|
||||
task tags or look at all the tags
|
||||
|
||||
task info 2 or all the details
|
||||
task info 2 or all the details
|
||||
|
||||
task projects or all the projects
|
||||
task projects or all the projects
|
||||
|
||||
task 3 fg:bold Let's make it colorful
|
||||
task 3 fg:bold Let's make it colorful
|
||||
task 4 fg:bold_green
|
||||
task li
|
||||
task 3 fg:bold_underline_white
|
||||
task li
|
||||
|
||||
task 4 bg:on_bright_red fg:bold_yellow
|
||||
task li Oh that's just nasty - let's get rid of that.
|
||||
task li Oh that's just nasty - let's get rid of that.
|
||||
task 4 bg:
|
||||
task li
|
||||
task 4 fg:
|
||||
task 3 fg:
|
||||
|
||||
task colors There are many combinations to choose from
|
||||
task colors There are many combinations to choose from
|
||||
|
||||
(Slashes!!!)
|
||||
task 1 due:6/8/2008 Let's add a due date
|
||||
task 1 due:6/8/2008 Let's add a due date
|
||||
date
|
||||
|
||||
task li
|
||||
task calendar Notice the due task is in yellow, today is marked cyan
|
||||
task calendar Notice the due task is in yellow, today is marked cyan
|
||||
|
||||
task 1 due:5/20/2008 This is now an overdue task
|
||||
task li and it shows up red
|
||||
task 1 due:5/20/2008 This is now an overdue task
|
||||
task li and it shows up red
|
||||
task overdue
|
||||
task cal
|
||||
|
||||
task export file.csv You can export the tasks to a spreadsheet
|
||||
task export file.csv You can export the tasks to a spreadsheet
|
||||
cat file.csv
|
||||
|
||||
task start 1 Started tasks can be used as reminders
|
||||
of what you are supposed to be doing
|
||||
task start 1 Started tasks can be used as reminders
|
||||
of what you are supposed to be doing
|
||||
|
||||
task active They show up as active
|
||||
task done 1 Let's clear out a couple
|
||||
task active They show up as active
|
||||
task done 1 Let's clear out a couple
|
||||
task li
|
||||
task done 3
|
||||
task active
|
||||
|
||||
task summary Summary shows progress on all projects
|
||||
task summary Summary shows progress on all projects
|
||||
|
||||
task history History shows general activity - how many added,
|
||||
completed etc, by month
|
||||
task history History shows general activity - how many added,
|
||||
completed etc, by month
|
||||
|
||||
task ghistory This report shows a histogram of tasks that were
|
||||
added (in red), completed (in green) and deleted
|
||||
(in yellow), all by month.
|
||||
task ghistory This report shows a histogram of tasks that were
|
||||
added (in red), completed (in green) and deleted
|
||||
(in yellow), all by month.
|
||||
|
||||
And that's it. There are more commands than this
|
||||
covered in the online documentation, but this should give
|
||||
the basic idea.
|
||||
And that's it. There are more commands than this
|
||||
covered in the online documentation, but this should give
|
||||
the basic idea.
|
||||
|
||||
Thank you for watching.
|
||||
Thank you for watching.
|
||||
|
||||
|
||||
@@ -46,23 +46,28 @@ Config::Config ()
|
||||
{
|
||||
(*this)["report.long.description"] = "Lists all task, all data, matching the specified criteria";
|
||||
(*this)["report.long.columns"] = "id,project,priority,entry,start,due,recur,age,tags,description";
|
||||
(*this)["report.long.labels"] = "ID,Project,Pri,Added,Started,Due,Recur,Age,Tags,Description";
|
||||
(*this)["report.long.sort"] = "due+,priority-,project+";
|
||||
|
||||
(*this)["report.list.description"] = "Lists all tasks matching the specified criteria";
|
||||
(*this)["report.list.columns"] = "id,project,priority,due,active,age,description";
|
||||
(*this)["report.list.labels"] = "ID,Project,Pri,Due,Active,Age,Description";
|
||||
(*this)["report.list.sort"] = "due+,priority-,project+";
|
||||
|
||||
(*this)["report.ls.description"] = "Minimal listing of all tasks matching the specified criteria";
|
||||
(*this)["report.ls.columns"] = "id,project,priority,description";
|
||||
(*this)["report.ls.labels"] = "ID,Project,Pri,Description";
|
||||
(*this)["report.ls.sort"] = "priority-,project+";
|
||||
|
||||
(*this)["report.newest.description"] = "Shows the newest tasks";
|
||||
(*this)["report.newest.columns"] = "id,project,priority,due,active,age,description";
|
||||
(*this)["report.newest.labels"] = "ID,Project,Pri,Due,Active,Age,Description";
|
||||
(*this)["report.newest.sort"] = "id-";
|
||||
(*this)["report.newest.limit"] = "10";
|
||||
|
||||
(*this)["report.oldest.description"] = "Shows the oldest tasks";
|
||||
(*this)["report.oldest.columns"] = "id,project,priority,due,active,age,description";
|
||||
(*this)["report.oldest.labels"] = "ID,Project,Pri,Due,Active,Age,Description";
|
||||
(*this)["report.oldest.sort"] = "id+";
|
||||
(*this)["report.oldest.limit"] = "10";
|
||||
}
|
||||
@@ -140,14 +145,17 @@ void Config::createDefault (const std::string& home)
|
||||
{
|
||||
fprintf (out, "data.location=%s\n", dataDir.c_str ());
|
||||
fprintf (out, "confirmation=yes\n");
|
||||
fprintf (out, "echo.command=yes\n");
|
||||
fprintf (out, "next=2\n");
|
||||
fprintf (out, "dateformat=m/d/Y\n");
|
||||
fprintf (out, "#monthsperline=2\n");
|
||||
fprintf (out, "#defaultwidth=80\n");
|
||||
fprintf (out, "curses=on\n");
|
||||
fprintf (out, "color=on\n");
|
||||
fprintf (out, "due=7\n");
|
||||
fprintf (out, "nag=You have higher priority tasks.\n");
|
||||
fprintf (out, "locking=on\n");
|
||||
fprintf (out, "#editor=vi\n");
|
||||
|
||||
fprintf (out, "color.overdue=bold_red\n");
|
||||
fprintf (out, "color.due=bold_yellow\n");
|
||||
@@ -170,29 +178,35 @@ void Config::createDefault (const std::string& home)
|
||||
|
||||
// Custom reports.
|
||||
fprintf (out, "# Fields: id,uuid,project,priority,entry,start,due,recur,age,active,tags,description\n");
|
||||
fprintf (out, "# description_only\n");
|
||||
fprintf (out, "# Description: This report is ...\n");
|
||||
fprintf (out, "# Sort: due+,priority-,project+\n");
|
||||
fprintf (out, "# Filter: pro:x pri:H +bug\n");
|
||||
fprintf (out, "# Limit: 10\n");
|
||||
|
||||
fprintf (out, "report.long.description=Lists all task, all data, matching the specified criteria\n");
|
||||
fprintf (out, "report.long.labels=ID,Project,Pri,Added,Started,Due,Recur,Age,Tags,Description\n");
|
||||
fprintf (out, "report.long.columns=id,project,priority,entry,start,due,recur,age,tags,description\n");
|
||||
fprintf (out, "report.long.sort=due+,priority-,project+\n");
|
||||
|
||||
fprintf (out, "report.list.description=Lists all tasks matching the specified criteria\n");
|
||||
fprintf (out, "report.list.labels=ID,Project,Pri,Due,Active,Age,Description\n");
|
||||
fprintf (out, "report.list.columns=id,project,priority,due,active,age,description\n");
|
||||
fprintf (out, "report.list.sort=due+,priority-,project+\n");
|
||||
|
||||
fprintf (out, "report.ls.description=Minimal listing of all tasks matching the specified criteria\n");
|
||||
fprintf (out, "report.ls.labels=ID,Project,Pri,Description\n");
|
||||
fprintf (out, "report.ls.columns=id,project,priority,description\n");
|
||||
fprintf (out, "report.ls.sort=priority-,project+\n");
|
||||
|
||||
fprintf (out, "report.newest.description=Shows the newest tasks\n");
|
||||
fprintf (out, "report.newest.labels=ID,Project,Pri,Due,Active,Age,Description\n");
|
||||
fprintf (out, "report.newest.columns=id,project,priority,due,active,age,description\n");
|
||||
fprintf (out, "report.newest.sort=id-\n");
|
||||
fprintf (out, "report.newest.limit=10\n");
|
||||
|
||||
fprintf (out, "report.oldest.description=Shows the oldest tasks\n");
|
||||
fprintf (out, "report.oldest.labels=ID,Project,Pri,Due,Active,Age,Description\n");
|
||||
fprintf (out, "report.oldest.columns=id,project,priority,due,active,age,description\n");
|
||||
fprintf (out, "report.oldest.sort=id+\n");
|
||||
fprintf (out, "report.oldest.limit=10\n");
|
||||
@@ -206,6 +220,9 @@ void Config::createDefault (const std::string& home)
|
||||
|
||||
this->load (rcFile);
|
||||
|
||||
// Get the data.location value from the (potentially newly created) .taskrc
|
||||
// file.
|
||||
dataDir = this->get ("data.location", dataDir);
|
||||
if (-1 == access (dataDir.c_str (), F_OK))
|
||||
mkdir (dataDir.c_str (), S_IRWXU);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#ifndef INCLUDED_DATE
|
||||
#define INCLUDED_DATE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
class Date;
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#ifndef INCLUDED_GRID
|
||||
#define INCLUDED_GRID
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
bin_PROGRAMS = task
|
||||
task_SOURCES = Config.cpp Date.cpp T.cpp TDB.cpp Table.cpp Grid.cpp Timer.cpp color.cpp parse.cpp task.cpp command.cpp report.cpp util.cpp text.cpp rules.cpp Config.h Date.h T.h TDB.h Table.h Grid.h Timer.h color.h task.h
|
||||
task_SOURCES = Config.cpp Date.cpp T.cpp TDB.cpp Table.cpp Grid.cpp Timer.cpp color.cpp parse.cpp task.cpp command.cpp edit.cpp report.cpp util.cpp text.cpp rules.cpp import.cpp Config.h Date.h T.h TDB.h Table.h Grid.h Timer.h color.h task.h
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Makefile.in generated by automake 1.10 from Makefile.am.
|
||||
# Makefile.in generated by automake 1.10.1 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
@@ -46,11 +46,11 @@ PROGRAMS = $(bin_PROGRAMS)
|
||||
am_task_OBJECTS = Config.$(OBJEXT) Date.$(OBJEXT) T.$(OBJEXT) \
|
||||
TDB.$(OBJEXT) Table.$(OBJEXT) Grid.$(OBJEXT) Timer.$(OBJEXT) \
|
||||
color.$(OBJEXT) parse.$(OBJEXT) task.$(OBJEXT) \
|
||||
command.$(OBJEXT) report.$(OBJEXT) util.$(OBJEXT) \
|
||||
text.$(OBJEXT) rules.$(OBJEXT)
|
||||
command.$(OBJEXT) edit.$(OBJEXT) report.$(OBJEXT) \
|
||||
util.$(OBJEXT) text.$(OBJEXT) rules.$(OBJEXT) import.$(OBJEXT)
|
||||
task_OBJECTS = $(am_task_OBJECTS)
|
||||
task_LDADD = $(LDADD)
|
||||
DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
|
||||
depcomp = $(SHELL) $(top_srcdir)/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||
@@ -153,9 +153,10 @@ sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
task_SOURCES = Config.cpp Date.cpp T.cpp TDB.cpp Table.cpp Grid.cpp Timer.cpp color.cpp parse.cpp task.cpp command.cpp report.cpp util.cpp text.cpp rules.cpp Config.h Date.h T.h TDB.h Table.h Grid.h Timer.h color.h task.h
|
||||
task_SOURCES = Config.cpp Date.cpp T.cpp TDB.cpp Table.cpp Grid.cpp Timer.cpp color.cpp parse.cpp task.cpp command.cpp edit.cpp report.cpp util.cpp text.cpp rules.cpp import.cpp Config.h Date.h T.h TDB.h Table.h Grid.h Timer.h color.h task.h
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
@@ -231,6 +232,8 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Timer.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/color.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edit.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/import.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/report.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rules.Po@am__quote@
|
||||
@@ -257,8 +260,8 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
$(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
mkid -fID $$unique
|
||||
tags: TAGS
|
||||
|
||||
@@ -270,8 +273,8 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
@@ -281,13 +284,12 @@ ctags: CTAGS
|
||||
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
|
||||
$(TAGS_FILES) $(LISP)
|
||||
tags=; \
|
||||
here=`pwd`; \
|
||||
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | \
|
||||
$(AWK) ' { files[$$0] = 1; } \
|
||||
END { for (i in files) print i; }'`; \
|
||||
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in files) print i; }; }'`; \
|
||||
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$tags $$unique
|
||||
|
||||
255
src/T.cpp
255
src/T.cpp
@@ -25,6 +25,7 @@
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include "task.h"
|
||||
#include "T.h"
|
||||
@@ -36,9 +37,14 @@ T::T ()
|
||||
mUUID = uuid ();
|
||||
mStatus = pending;
|
||||
mId = 0;
|
||||
mSequence.clear ();
|
||||
mTags.clear ();
|
||||
mAttributes.clear ();
|
||||
mDescription = "";
|
||||
mFrom = "";
|
||||
mTo = "";
|
||||
mGlobal = false;
|
||||
mAnnotations.clear ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -54,10 +60,12 @@ T::T (const T& other)
|
||||
mStatus = other.mStatus;
|
||||
mUUID = other.mUUID;
|
||||
mId = other.mId;
|
||||
mSequence = other.mSequence;
|
||||
mDescription = other.mDescription;
|
||||
mTags = other.mTags;
|
||||
mRemoveTags = other.mRemoveTags;
|
||||
mAttributes = other.mAttributes;
|
||||
mAnnotations = other.mAnnotations;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -68,10 +76,12 @@ T& T::operator= (const T& other)
|
||||
mStatus = other.mStatus;
|
||||
mUUID = other.mUUID;
|
||||
mId = other.mId;
|
||||
mSequence = other.mSequence;
|
||||
mDescription = other.mDescription;
|
||||
mTags = other.mTags;
|
||||
mRemoveTags = other.mRemoveTags;
|
||||
mAttributes = other.mAttributes;
|
||||
mAnnotations = other.mAnnotations;
|
||||
}
|
||||
|
||||
return *this;
|
||||
@@ -109,6 +119,12 @@ void T::addRemoveTag (const std::string& tag)
|
||||
mRemoveTags.push_back (tag);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int T::getTagCount () const
|
||||
{
|
||||
return mTags.size ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void T::getTags (std::vector<std::string>& all) const
|
||||
{
|
||||
@@ -230,21 +246,61 @@ void T::removeAttribute (const std::string& name)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void T::getSubstitution (std::string& from, std::string& to) const
|
||||
void T::getSubstitution (
|
||||
std::string& from,
|
||||
std::string& to,
|
||||
bool& global) const
|
||||
{
|
||||
from = mFrom;
|
||||
to = mTo;
|
||||
from = mFrom;
|
||||
to = mTo;
|
||||
global = mGlobal;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void T::setSubstitution (const std::string& from, const std::string& to)
|
||||
void T::setSubstitution (
|
||||
const std::string& from,
|
||||
const std::string& to,
|
||||
bool global)
|
||||
{
|
||||
mFrom = from;
|
||||
mTo = to;
|
||||
mFrom = from;
|
||||
mTo = to;
|
||||
mGlobal = global;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// uuid status [tags] [attributes] description
|
||||
void T::getAnnotations (std::map <time_t, std::string>& all) const
|
||||
{
|
||||
all = mAnnotations;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void T::setAnnotations (const std::map <time_t, std::string>& all)
|
||||
{
|
||||
mAnnotations = all;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void T::addAnnotation (const std::string& description)
|
||||
{
|
||||
std::string sanitized = description;
|
||||
std::replace (sanitized.begin (), sanitized.end (), '"', '\'');
|
||||
std::replace (sanitized.begin (), sanitized.end (), '[', '(');
|
||||
std::replace (sanitized.begin (), sanitized.end (), ']', ')');
|
||||
mAnnotations[time (NULL)] = sanitized;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool T::sequenceContains (int id) const
|
||||
{
|
||||
foreach (seq, mSequence)
|
||||
if (*seq == id)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// uuid status [tags] [attributes] [annotations] description
|
||||
//
|
||||
// uuid \x{8}-\x{4}-\x{4}-\x{4}-\x{12}
|
||||
// status - + X r
|
||||
@@ -282,10 +338,26 @@ const std::string T::compose () const
|
||||
++count;
|
||||
}
|
||||
|
||||
line += "] ";
|
||||
line += "] [";
|
||||
|
||||
// Annotations
|
||||
std::stringstream annotation;
|
||||
bool first = true;
|
||||
foreach (note, mAnnotations)
|
||||
{
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
annotation << " ";
|
||||
|
||||
annotation << note->first << ":\"" << note->second << "\"";
|
||||
}
|
||||
line += annotation.str () + "] ";
|
||||
|
||||
// Description
|
||||
line += mDescription;
|
||||
|
||||
// EOL
|
||||
line += "\n";
|
||||
|
||||
if (line.length () > T_LINE_MAX)
|
||||
@@ -421,10 +493,12 @@ void T::parse (const std::string& line)
|
||||
}
|
||||
else
|
||||
throw std::string ("Line too short");
|
||||
|
||||
mAnnotations.clear ();
|
||||
}
|
||||
break;
|
||||
|
||||
// File format version 2, from 2008.1.1
|
||||
// File format version 2, from 2008.1.1 - 2009.3.23
|
||||
case 2:
|
||||
{
|
||||
if (line.length () > 46) // ^.{36} . \[\] \[\] \n
|
||||
@@ -446,24 +520,24 @@ void T::parse (const std::string& line)
|
||||
if (openAttrBracket != std::string::npos &&
|
||||
closeAttrBracket != std::string::npos)
|
||||
{
|
||||
std::string tags = line.substr (
|
||||
openTagBracket + 1, closeTagBracket - openTagBracket - 1);
|
||||
std::vector <std::string> rawTags;
|
||||
split (mTags, tags, ' ');
|
||||
std::string tags = line.substr (
|
||||
openTagBracket + 1, closeTagBracket - openTagBracket - 1);
|
||||
std::vector <std::string> rawTags;
|
||||
split (mTags, tags, ' ');
|
||||
|
||||
std::string attributes = line.substr (
|
||||
openAttrBracket + 1, closeAttrBracket - openAttrBracket - 1);
|
||||
std::vector <std::string> pairs;
|
||||
split (pairs, attributes, ' ');
|
||||
for (size_t i = 0; i < pairs.size (); ++i)
|
||||
{
|
||||
std::vector <std::string> pair;
|
||||
split (pair, pairs[i], ':');
|
||||
if (pair.size () == 2)
|
||||
mAttributes[pair[0]] = pair[1];
|
||||
}
|
||||
std::string attributes = line.substr (
|
||||
openAttrBracket + 1, closeAttrBracket - openAttrBracket - 1);
|
||||
std::vector <std::string> pairs;
|
||||
split (pairs, attributes, ' ');
|
||||
for (size_t i = 0; i < pairs.size (); ++i)
|
||||
{
|
||||
std::vector <std::string> pair;
|
||||
split (pair, pairs[i], ':');
|
||||
if (pair.size () == 2)
|
||||
mAttributes[pair[0]] = pair[1];
|
||||
}
|
||||
|
||||
mDescription = line.substr (closeAttrBracket + 2, std::string::npos);
|
||||
mDescription = line.substr (closeAttrBracket + 2, std::string::npos);
|
||||
}
|
||||
else
|
||||
throw std::string ("Missing attribute brackets");
|
||||
@@ -473,6 +547,107 @@ void T::parse (const std::string& line)
|
||||
}
|
||||
else
|
||||
throw std::string ("Line too short");
|
||||
|
||||
mAnnotations.clear ();
|
||||
}
|
||||
break;
|
||||
|
||||
// File format version 3, from 2009.3.23
|
||||
case 3:
|
||||
{
|
||||
if (line.length () > 49) // ^.{36} . \[\] \[\] \[\] \n
|
||||
{
|
||||
mUUID = line.substr (0, 36);
|
||||
|
||||
mStatus = line[37] == '+' ? completed
|
||||
: line[37] == 'X' ? deleted
|
||||
: line[37] == 'r' ? recurring
|
||||
: pending;
|
||||
|
||||
size_t openTagBracket = line.find ("[");
|
||||
size_t closeTagBracket = line.find ("]", openTagBracket);
|
||||
if (openTagBracket != std::string::npos &&
|
||||
closeTagBracket != std::string::npos)
|
||||
{
|
||||
size_t openAttrBracket = line.find ("[", closeTagBracket);
|
||||
size_t closeAttrBracket = line.find ("]", openAttrBracket);
|
||||
if (openAttrBracket != std::string::npos &&
|
||||
closeAttrBracket != std::string::npos)
|
||||
{
|
||||
size_t openAnnoBracket = line.find ("[", closeAttrBracket);
|
||||
size_t closeAnnoBracket = line.find ("]", openAnnoBracket);
|
||||
if (openAnnoBracket != std::string::npos &&
|
||||
closeAnnoBracket != std::string::npos)
|
||||
{
|
||||
std::string tags = line.substr (
|
||||
openTagBracket + 1, closeTagBracket - openTagBracket - 1);
|
||||
std::vector <std::string> rawTags;
|
||||
split (mTags, tags, ' ');
|
||||
|
||||
std::string attributes = line.substr (
|
||||
openAttrBracket + 1, closeAttrBracket - openAttrBracket - 1);
|
||||
std::vector <std::string> pairs;
|
||||
split (pairs, attributes, ' ');
|
||||
|
||||
for (size_t i = 0; i < pairs.size (); ++i)
|
||||
{
|
||||
std::vector <std::string> pair;
|
||||
split (pair, pairs[i], ':');
|
||||
if (pair.size () == 2)
|
||||
mAttributes[pair[0]] = pair[1];
|
||||
}
|
||||
|
||||
// Extract and split the annotations, which are of the form:
|
||||
// 1234:"..." 5678:"..."
|
||||
std::string annotations = line.substr (
|
||||
openAnnoBracket + 1, closeAnnoBracket - openAnnoBracket - 1);
|
||||
pairs.clear ();
|
||||
|
||||
std::string::size_type start = 0;
|
||||
std::string::size_type end = 0;
|
||||
do
|
||||
{
|
||||
end = annotations.find ('"', start);
|
||||
if (end != std::string::npos)
|
||||
{
|
||||
end = annotations.find ('"', end + 1);
|
||||
|
||||
if (start != std::string::npos &&
|
||||
end != std::string::npos)
|
||||
{
|
||||
pairs.push_back (annotations.substr (start, end - start + 1));
|
||||
start = end + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (start != std::string::npos &&
|
||||
end != std::string::npos);
|
||||
|
||||
for (size_t i = 0; i < pairs.size (); ++i)
|
||||
{
|
||||
std::string pair = pairs[i];
|
||||
std::string::size_type colon = pair.find (":");
|
||||
if (colon != std::string::npos)
|
||||
{
|
||||
std::string name = pair.substr (0, colon);
|
||||
std::string value = pair.substr (colon + 2, pair.length () - colon - 3);
|
||||
mAnnotations[::atoi (name.c_str ())] = value;
|
||||
}
|
||||
}
|
||||
|
||||
mDescription = line.substr (closeAnnoBracket + 2, std::string::npos);
|
||||
}
|
||||
else
|
||||
throw std::string ("Missing annotation brackets.");
|
||||
}
|
||||
else
|
||||
throw std::string ("Missing attribute brackets.");
|
||||
}
|
||||
else
|
||||
throw std::string ("Missing tag brackets.");
|
||||
}
|
||||
else
|
||||
throw std::string ("Line too short.");
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -512,16 +687,31 @@ int T::determineVersion (const std::string& line)
|
||||
line[23] == '-' &&
|
||||
line[36] == ' ' &&
|
||||
(line[37] == '-' || line[37] == '+' || line[37] == 'X' || line[37] == 'r'))
|
||||
return 2;
|
||||
{
|
||||
// Version 3 looks like:
|
||||
//
|
||||
// uuid status [tags] [attributes] [annotations] description\n
|
||||
//
|
||||
// Scan for the number of [] pairs.
|
||||
std::string::size_type tagAtts = line.find ("] [", 0);
|
||||
std::string::size_type attsAnno = line.find ("] [", tagAtts + 1);
|
||||
std::string::size_type annoDesc = line.find ("] ", attsAnno + 1);
|
||||
if (tagAtts != std::string::npos &&
|
||||
attsAnno != std::string::npos &&
|
||||
annoDesc != std::string::npos)
|
||||
return 3;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Version 3?
|
||||
// Version 4?
|
||||
//
|
||||
// Fortunately, with the hindsight that will come with version 3, the
|
||||
// identifying characteristics of 1 and 2 may be modified such that if 3 has
|
||||
// a UUID followed by a status, then there is still a way to differentiate
|
||||
// between 2 and 3.
|
||||
// Fortunately, with the hindsight that will come with version 4, the
|
||||
// identifying characteristics of 1, 2 and 3 may be modified such that if 4
|
||||
// has a UUID followed by a status, then there is still a way to differentiate
|
||||
// between 2, 3 and 4.
|
||||
//
|
||||
// The danger is that a version 2 binary reads and misinterprets a version 3
|
||||
// The danger is that a version 3 binary reads and misinterprets a version 4
|
||||
// file. This is why it is a good idea to rely on an explicit version
|
||||
// declaration rather than chance positioning.
|
||||
|
||||
@@ -534,6 +724,7 @@ int T::determineVersion (const std::string& line)
|
||||
bool T::validate () const
|
||||
{
|
||||
// TODO Verify until > due
|
||||
// TODO Verify entry < until, due, start, end
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
19
src/T.h
19
src/T.h
@@ -49,22 +49,26 @@ public:
|
||||
void setUUID (const std::string& uuid) { mUUID = uuid; }
|
||||
|
||||
int getId () const { return mId; }
|
||||
void setId (int id) { mId = id; }
|
||||
void setId (int id) { mId = id; mSequence.push_back (id); }
|
||||
std::vector <int> getAllIds () const { return mSequence; }
|
||||
void addId (int id) { if (mId == 0) mId = id; mSequence.push_back (id); }
|
||||
|
||||
status getStatus () const { return mStatus; }
|
||||
void setStatus (status s) { mStatus = s; }
|
||||
|
||||
const std::string getDescription () const { return mDescription; }
|
||||
void setDescription (const std::string& description) { mDescription = description; }
|
||||
int getAnnotationCount () const { return mAnnotations.size (); }
|
||||
|
||||
void getSubstitution (std::string&, std::string&) const;
|
||||
void setSubstitution (const std::string&, const std::string&);
|
||||
void getSubstitution (std::string&, std::string&, bool&) const;
|
||||
void setSubstitution (const std::string&, const std::string&, bool);
|
||||
|
||||
bool hasTag (const std::string&) const;
|
||||
|
||||
void getRemoveTags (std::vector<std::string>&); // SPECIAL
|
||||
void addRemoveTag (const std::string&); // SPECIAL
|
||||
|
||||
int getTagCount () const;
|
||||
void getTags (std::vector<std::string>&) const;
|
||||
void addTag (const std::string&);
|
||||
void addTags (const std::vector <std::string>&);
|
||||
@@ -77,6 +81,11 @@ public:
|
||||
void removeAttribute (const std::string&);
|
||||
void removeAttributes ();
|
||||
|
||||
void getAnnotations (std::map <time_t, std::string>&) const;
|
||||
void setAnnotations (const std::map <time_t, std::string>&);
|
||||
void addAnnotation (const std::string&);
|
||||
bool sequenceContains (int) const;
|
||||
|
||||
const std::string compose () const;
|
||||
const std::string composeCSV ();
|
||||
void parse (const std::string&);
|
||||
@@ -89,13 +98,15 @@ private:
|
||||
status mStatus;
|
||||
std::string mUUID;
|
||||
int mId;
|
||||
std::vector <int> mSequence;
|
||||
std::string mDescription;
|
||||
std::vector<std::string> mTags;
|
||||
std::vector<std::string> mRemoveTags;
|
||||
std::map<std::string, std::string> mAttributes;
|
||||
|
||||
std::string mFrom;
|
||||
std::string mTo;
|
||||
bool mGlobal;
|
||||
std::map <time_t, std::string> mAnnotations;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
129
src/TDB.cpp
129
src/TDB.cpp
@@ -26,6 +26,7 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <sys/file.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
@@ -104,13 +105,27 @@ bool TDB::pendingT (std::vector <T>& all)
|
||||
{
|
||||
mId = 1;
|
||||
|
||||
int line = 1;
|
||||
std::vector <std::string>::iterator it;
|
||||
for (it = lines.begin (); it != lines.end (); ++it)
|
||||
{
|
||||
T t (*it);
|
||||
t.setId (mId++);
|
||||
if (t.getStatus () == T::pending)
|
||||
all.push_back (t);
|
||||
try
|
||||
{
|
||||
T t (*it);
|
||||
t.setId (mId++);
|
||||
if (t.getStatus () == T::pending)
|
||||
all.push_back (t);
|
||||
}
|
||||
|
||||
catch (std::string& e)
|
||||
{
|
||||
std::stringstream more;
|
||||
more << " Line " << line << ", in " << "pending.data";
|
||||
|
||||
throw e + more.str ();
|
||||
}
|
||||
|
||||
++line;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -130,12 +145,26 @@ bool TDB::allPendingT (std::vector <T>& all)
|
||||
{
|
||||
mId = 1;
|
||||
|
||||
int line = 1;
|
||||
std::vector <std::string>::iterator it;
|
||||
for (it = lines.begin (); it != lines.end (); ++it)
|
||||
{
|
||||
T t (*it);
|
||||
t.setId (mId++);
|
||||
all.push_back (t);
|
||||
try
|
||||
{
|
||||
T t (*it);
|
||||
t.setId (mId++);
|
||||
all.push_back (t);
|
||||
}
|
||||
|
||||
catch (std::string& e)
|
||||
{
|
||||
std::stringstream more;
|
||||
more << " Line " << line << ", in " << "pending.data";
|
||||
|
||||
throw e + more.str ();
|
||||
}
|
||||
|
||||
++line;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -152,12 +181,26 @@ bool TDB::completedT (std::vector <T>& all) const
|
||||
std::vector <std::string> lines;
|
||||
if (readLockedFile (mCompletedFile, lines))
|
||||
{
|
||||
int line = 1;
|
||||
std::vector <std::string>::iterator it;
|
||||
for (it = lines.begin (); it != lines.end (); ++it)
|
||||
{
|
||||
T t (*it);
|
||||
if (t.getStatus () != T::deleted)
|
||||
all.push_back (t);
|
||||
try
|
||||
{
|
||||
T t (*it);
|
||||
if (t.getStatus () != T::deleted)
|
||||
all.push_back (t);
|
||||
}
|
||||
|
||||
catch (std::string& e)
|
||||
{
|
||||
std::stringstream more;
|
||||
more << " Line " << line << ", in " << "pending.data";
|
||||
|
||||
throw e + more.str ();
|
||||
}
|
||||
|
||||
++line;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -174,11 +217,25 @@ bool TDB::allCompletedT (std::vector <T>& all) const
|
||||
std::vector <std::string> lines;
|
||||
if (readLockedFile (mCompletedFile, lines))
|
||||
{
|
||||
int line = 1;
|
||||
std::vector <std::string>::iterator it;
|
||||
for (it = lines.begin (); it != lines.end (); ++it)
|
||||
{
|
||||
T t (*it);
|
||||
all.push_back (t);
|
||||
try
|
||||
{
|
||||
T t (*it);
|
||||
all.push_back (t);
|
||||
}
|
||||
|
||||
catch (std::string& e)
|
||||
{
|
||||
std::stringstream more;
|
||||
more << " Line " << line << ", in " << "pending.data";
|
||||
|
||||
throw e + more.str ();
|
||||
}
|
||||
|
||||
++line;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -187,54 +244,6 @@ bool TDB::allCompletedT (std::vector <T>& all) const
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool TDB::deleteT (const T& t)
|
||||
{
|
||||
T task (t);
|
||||
|
||||
std::vector <T> all;
|
||||
allPendingT (all);
|
||||
|
||||
std::vector <T>::iterator it;
|
||||
for (it = all.begin (); it != all.end (); ++it)
|
||||
if (task.getId () == it->getId ())
|
||||
{
|
||||
it->setStatus (T::deleted);
|
||||
|
||||
char endTime[16];
|
||||
sprintf (endTime, "%u", (unsigned int) time (NULL));
|
||||
it->setAttribute ("end", endTime);
|
||||
|
||||
return overwritePending (all);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool TDB::completeT (const T& t)
|
||||
{
|
||||
T task (t);
|
||||
|
||||
std::vector <T> all;
|
||||
allPendingT (all);
|
||||
|
||||
std::vector <T>::iterator it;
|
||||
for (it = all.begin (); it != all.end (); ++it)
|
||||
if (task.getId () == it->getId ())
|
||||
{
|
||||
it->setStatus (T::completed);
|
||||
|
||||
char endTime[16];
|
||||
sprintf (endTime, "%u", (unsigned int) time (NULL));
|
||||
it->setAttribute ("end", endTime);
|
||||
|
||||
return overwritePending (all);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool TDB::addT (const T& t)
|
||||
{
|
||||
|
||||
@@ -43,11 +43,8 @@ public:
|
||||
bool allPendingT (std::vector <T>&);
|
||||
bool completedT (std::vector <T>&) const;
|
||||
bool allCompletedT (std::vector <T>&) const;
|
||||
bool deleteT (const T&);
|
||||
bool completeT (const T&);
|
||||
bool addT (const T&);
|
||||
bool modifyT (const T&);
|
||||
bool logRead (std::vector <std::string>&) const;
|
||||
int gc ();
|
||||
int nextId ();
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ void Table::setRowBg (const int row, const Text::color c)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Table::addCell (const int row, const int col, const std::string& data)
|
||||
{
|
||||
int length = 0;
|
||||
unsigned int length = 0;
|
||||
|
||||
if (mSuppressWS)
|
||||
{
|
||||
@@ -238,7 +238,19 @@ void Table::addCell (const int row, const int col, const std::string& data)
|
||||
data2 = data;
|
||||
|
||||
clean (data2);
|
||||
length = data2.length ();
|
||||
// For multi-line cells, find the longest line.
|
||||
if (data2.find ("\n") != std::string::npos)
|
||||
{
|
||||
length = 0;
|
||||
std::vector <std::string> lines;
|
||||
split (lines, data2, "\n");
|
||||
for (unsigned int i = 0; i < lines.size (); ++i)
|
||||
if (lines[i].length () > length)
|
||||
length = lines[i].length ();
|
||||
}
|
||||
else
|
||||
length = data2.length ();
|
||||
|
||||
mData.add (row, col, data2);
|
||||
}
|
||||
else
|
||||
@@ -248,11 +260,22 @@ void Table::addCell (const int row, const int col, const std::string& data)
|
||||
else
|
||||
mData.add (row, col, data);
|
||||
|
||||
length = data.length ();
|
||||
// For multi-line cells, find the longest line.
|
||||
if (data.find ("\n") != std::string::npos)
|
||||
{
|
||||
length = 0;
|
||||
std::vector <std::string> lines;
|
||||
split (lines, data, "\n");
|
||||
for (unsigned int i = 0; i < lines.size (); ++i)
|
||||
if (lines[i].length () > length)
|
||||
length = lines[i].length ();
|
||||
}
|
||||
else
|
||||
length = data.length ();
|
||||
}
|
||||
|
||||
// Automatically maintain max width.
|
||||
mMaxDataWidth[col] = max (mMaxDataWidth[col], length);
|
||||
mMaxDataWidth[col] = max (mMaxDataWidth[col], (int)length);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -508,9 +531,7 @@ void Table::calculateColumnWidths ()
|
||||
}
|
||||
else
|
||||
{
|
||||
// std::cout << "# insufficient room, considering only flexible columns." << std::endl;
|
||||
|
||||
// The fallback position is to assume no width was specificed, and just
|
||||
// The fallback position is to assume no width was specified, and just
|
||||
// calculate widths accordingly.
|
||||
mTableWidth = 0;
|
||||
calculateColumnWidths ();
|
||||
@@ -782,6 +803,27 @@ void Table::optimize (std::string& output) const
|
||||
Much better.
|
||||
*/
|
||||
|
||||
char patterns[5][16] =
|
||||
{
|
||||
" \n",
|
||||
" \n",
|
||||
" \n",
|
||||
" \n",
|
||||
};
|
||||
|
||||
std::string::size_type trailing;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
do
|
||||
{
|
||||
trailing = output.find (patterns[i]);
|
||||
if (trailing != std::string::npos)
|
||||
output.replace (trailing, strlen (patterns[i]), "\n");
|
||||
}
|
||||
while (trailing != std::string::npos);
|
||||
}
|
||||
|
||||
// std::cout << int ((100 * (start - output.length ()) / start))
|
||||
// << "%" << std::endl;
|
||||
}
|
||||
@@ -1082,6 +1124,7 @@ const std::string Table::render (int maximum /* = 0 */)
|
||||
}
|
||||
}
|
||||
|
||||
optimize (output);
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
768
src/command.cpp
768
src/command.cpp
@@ -28,19 +28,12 @@
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <pwd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "Config.h"
|
||||
#include "Date.h"
|
||||
#include "Table.h"
|
||||
#include "color.h"
|
||||
#include "TDB.h"
|
||||
#include "T.h"
|
||||
#include "task.h"
|
||||
|
||||
#ifdef HAVE_LIBNCURSES
|
||||
@@ -193,42 +186,34 @@ std::string handleTags (TDB& tdb, T& task, Config& conf)
|
||||
std::string handleUndelete (TDB& tdb, T& task, Config& conf)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
std::vector <T> all;
|
||||
tdb.allPendingT (all);
|
||||
filterSequence (all, task);
|
||||
|
||||
int id = task.getId ();
|
||||
std::vector <T>::iterator it;
|
||||
for (it = all.begin (); it != all.end (); ++it)
|
||||
foreach (t, all)
|
||||
{
|
||||
if (it->getId () == id)
|
||||
if (t->getStatus () == T::deleted)
|
||||
{
|
||||
if (it->getStatus () == T::deleted)
|
||||
{
|
||||
if (it->getAttribute ("recur") != "")
|
||||
{
|
||||
out << "Task does not support 'undelete' for recurring tasks." << std::endl;
|
||||
return out.str ();
|
||||
}
|
||||
if (t->getAttribute ("recur") != "")
|
||||
out << "Task does not support 'undo' for recurring tasks.\n";
|
||||
|
||||
T restored (*it);
|
||||
restored.setStatus (T::pending);
|
||||
restored.removeAttribute ("end");
|
||||
tdb.modifyT (restored);
|
||||
t->setStatus (T::pending);
|
||||
t->removeAttribute ("end");
|
||||
tdb.modifyT (*t);
|
||||
|
||||
out << "Task " << id << " successfully undeleted." << std::endl;
|
||||
return out.str ();
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "Task " << id << " is not deleted - therefore cannot undelete." << std::endl;
|
||||
return out.str ();
|
||||
}
|
||||
out << "Task " << t->getId () << " '" << t->getDescription () << "' successfully undeleted.\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "Task " << t->getId () << " '" << t->getDescription () << "' is not deleted - therefore cannot be undeleted.\n";
|
||||
}
|
||||
}
|
||||
|
||||
out << "Task " << id
|
||||
<< " not found - tasks can only be reliably undeleted if the undelete" << std::endl
|
||||
<< "command is run immediately after the errant delete command." << std::endl;
|
||||
out << "\n"
|
||||
<< "Please note that tasks can only be reliably undeleted if the undelete "
|
||||
<< "command is run immediately after the errant delete command."
|
||||
<< std::endl;
|
||||
|
||||
return out.str ();
|
||||
}
|
||||
@@ -242,37 +227,31 @@ std::string handleUndo (TDB& tdb, T& task, Config& conf)
|
||||
|
||||
std::vector <T> all;
|
||||
tdb.allPendingT (all);
|
||||
filterSequence (all, task);
|
||||
|
||||
int id = task.getId ();
|
||||
std::vector <T>::iterator it;
|
||||
for (it = all.begin (); it != all.end (); ++it)
|
||||
foreach (t, all)
|
||||
{
|
||||
if (it->getId () == id)
|
||||
if (t->getStatus () == T::completed)
|
||||
{
|
||||
if (it->getStatus () == T::completed)
|
||||
{
|
||||
if (it->getAttribute ("recur") != "")
|
||||
return std::string ("Task does not support 'undo' for recurring tasks.\n");
|
||||
if (t->getAttribute ("recur") != "")
|
||||
out << "Task does not support 'undo' for recurring tasks.\n";
|
||||
|
||||
T restored (*it);
|
||||
restored.setStatus (T::pending);
|
||||
restored.removeAttribute ("end");
|
||||
tdb.modifyT (restored);
|
||||
t->setStatus (T::pending);
|
||||
t->removeAttribute ("end");
|
||||
tdb.modifyT (*t);
|
||||
|
||||
out << "Task " << id << " successfully undone." << std::endl;
|
||||
return out.str ();
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "Task " << id << " is not done - therefore cannot be undone." << std::endl;
|
||||
return out.str ();
|
||||
}
|
||||
out << "Task " << t->getId () << " '" << t->getDescription () << "' successfully undone." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "Task " << t->getId () << " '" << t->getDescription () << "' is not done - therefore cannot be undone." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
out << "Task " << id
|
||||
<< " not found - tasks can only be reliably undone if the undo" << std::endl
|
||||
<< "command is run immediately after the errant done command." << std::endl;
|
||||
out << std::endl
|
||||
<< "Please note that tasks can only be reliably undone if the undo "
|
||||
<< "command is run immediately after the errant done command."
|
||||
<< std::endl;
|
||||
|
||||
return out.str ();
|
||||
}
|
||||
@@ -283,7 +262,7 @@ std::string handleVersion (Config& conf)
|
||||
std::stringstream out;
|
||||
|
||||
// Determine window size, and set table accordingly.
|
||||
int width = conf.get ("defaultwidth", 80);
|
||||
int width = conf.get ("defaultwidth", (int) 80);
|
||||
#ifdef HAVE_LIBNCURSES
|
||||
if (conf.get ("curses", true))
|
||||
{
|
||||
@@ -367,12 +346,18 @@ std::string handleVersion (Config& conf)
|
||||
|
||||
// Complain about configuration variables that are not recognized.
|
||||
// These are the regular configuration variables.
|
||||
// Note that there is a leading and trailing space.
|
||||
std::string recognized =
|
||||
"blanklines color color.active color.due color.overdue color.pri.H "
|
||||
" blanklines color color.active color.due color.overdue color.pri.H "
|
||||
"color.pri.L color.pri.M color.pri.none color.recurring color.tagged "
|
||||
"confirmation curses data.location dateformat default.command "
|
||||
"default.priority defaultwidth due locking monthsperline nag next project "
|
||||
"shadow.command shadow.file shadow.notify";
|
||||
"default.priority defaultwidth due echo.command locking monthsperline nag "
|
||||
"next project shadow.command shadow.file shadow.notify weekstart editor "
|
||||
"import.synonym.id import.synonym.uuid import.synonym.status "
|
||||
"import.synonym.tags import.synonym.entry import.synonym.start "
|
||||
"import.synonym.due import.synonym.recur import.synonym.end "
|
||||
"import.synonym.project import.synonym.priority import.synonym.fg "
|
||||
"import.synonym.bg import.synonym.description ";
|
||||
|
||||
// This configuration variable is supported, but not documented. It exists
|
||||
// so that unit tests can force color to be on even when the output from task
|
||||
@@ -382,7 +367,10 @@ std::string handleVersion (Config& conf)
|
||||
std::vector <std::string> unrecognized;
|
||||
foreach (i, all)
|
||||
{
|
||||
if (recognized.find (*i) == std::string::npos)
|
||||
// Disallow partial matches by tacking a leading an trailing space on each
|
||||
// variable name.
|
||||
std::string pattern = " " + *i + " ";
|
||||
if (recognized.find (pattern) == std::string::npos)
|
||||
{
|
||||
// These are special configuration variables, because their name is
|
||||
// dynamic.
|
||||
@@ -432,146 +420,220 @@ std::string handleVersion (Config& conf)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleDelete (TDB& tdb, T& task, Config& conf)
|
||||
{
|
||||
if (conf.get ("confirmation") != "yes" || confirm ("Permanently delete task?"))
|
||||
{
|
||||
std::vector <T> all;
|
||||
tdb.allPendingT (all);
|
||||
foreach (t, all)
|
||||
{
|
||||
if (t->getId () == task.getId ())
|
||||
{
|
||||
// Check for the more complex case of a recurring task. If this is a
|
||||
// recurring task, get confirmation to delete them all.
|
||||
std::string parent = t->getAttribute ("parent");
|
||||
if (parent != "")
|
||||
{
|
||||
if (confirm ("This is a recurring task. Do you want to delete all pending recurrences of this same task?"))
|
||||
{
|
||||
// Scan all pending tasks for siblings of this task, and the parent
|
||||
// itself, and delete them.
|
||||
foreach (sibling, all)
|
||||
if (sibling->getAttribute ("parent") == parent ||
|
||||
sibling->getUUID () == parent)
|
||||
tdb.deleteT (*sibling);
|
||||
std::stringstream out;
|
||||
|
||||
return std::string ("");
|
||||
}
|
||||
else
|
||||
std::vector <T> all;
|
||||
tdb.allPendingT (all);
|
||||
filterSequence (all, task);
|
||||
|
||||
// Determine the end date.
|
||||
char endTime[16];
|
||||
sprintf (endTime, "%u", (unsigned int) time (NULL));
|
||||
|
||||
foreach (t, all)
|
||||
{
|
||||
std::stringstream question;
|
||||
question << "Permanently delete task "
|
||||
<< t->getId ()
|
||||
<< " '"
|
||||
<< t->getDescription ()
|
||||
<< "'?";
|
||||
|
||||
if (!conf.get (std::string ("confirmation"), false) || confirm (question.str ()))
|
||||
{
|
||||
// Check for the more complex case of a recurring task. If this is a
|
||||
// recurring task, get confirmation to delete them all.
|
||||
std::string parent = t->getAttribute ("parent");
|
||||
if (parent != "")
|
||||
{
|
||||
if (confirm ("This is a recurring task. Do you want to delete all pending recurrences of this same task?"))
|
||||
{
|
||||
// Scan all pending tasks for siblings of this task, and the parent
|
||||
// itself, and delete them.
|
||||
foreach (sibling, all)
|
||||
{
|
||||
// Update mask in parent.
|
||||
t->setStatus (T::deleted);
|
||||
updateRecurrenceMask (tdb, all, *t);
|
||||
tdb.deleteT (*t);
|
||||
return std::string ("");
|
||||
if (sibling->getAttribute ("parent") == parent ||
|
||||
sibling->getUUID () == parent)
|
||||
{
|
||||
sibling->setStatus (T::deleted);
|
||||
sibling->setAttribute ("end", endTime);
|
||||
tdb.modifyT (*sibling);
|
||||
|
||||
if (conf.get ("echo.command", true))
|
||||
out << "Deleting recurring task "
|
||||
<< sibling->getId ()
|
||||
<< " '"
|
||||
<< sibling->getDescription ()
|
||||
<< "'"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
tdb.deleteT (*t);
|
||||
{
|
||||
// Update mask in parent.
|
||||
t->setStatus (T::deleted);
|
||||
updateRecurrenceMask (tdb, all, *t);
|
||||
|
||||
break; // No point continuing the loop.
|
||||
t->setAttribute ("end", endTime);
|
||||
tdb.modifyT (*t);
|
||||
|
||||
out << "Deleting recurring task "
|
||||
<< t->getId ()
|
||||
<< " '"
|
||||
<< t->getDescription ()
|
||||
<< "'"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
t->setStatus (T::deleted);
|
||||
t->setAttribute ("end", endTime);
|
||||
tdb.modifyT (*t);
|
||||
|
||||
if (conf.get ("echo.command", true))
|
||||
out << "Deleting task "
|
||||
<< t->getId ()
|
||||
<< " '"
|
||||
<< t->getDescription ()
|
||||
<< "'"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
out << "Task not deleted." << std::endl;
|
||||
}
|
||||
else
|
||||
return std::string ("Task not deleted.\n");
|
||||
|
||||
return std::string ("");
|
||||
return out.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleStart (TDB& tdb, T& task, Config& conf)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
std::vector <T> all;
|
||||
tdb.pendingT (all);
|
||||
filterSequence (all, task);
|
||||
|
||||
std::vector <T>::iterator it;
|
||||
for (it = all.begin (); it != all.end (); ++it)
|
||||
foreach (t, all)
|
||||
{
|
||||
if (it->getId () == task.getId ())
|
||||
if (t->getAttribute ("start") == "")
|
||||
{
|
||||
T original (*it);
|
||||
char startTime[16];
|
||||
sprintf (startTime, "%u", (unsigned int) time (NULL));
|
||||
t->setAttribute ("start", startTime);
|
||||
|
||||
if (original.getAttribute ("start") == "")
|
||||
{
|
||||
char startTime[16];
|
||||
sprintf (startTime, "%u", (unsigned int) time (NULL));
|
||||
original.setAttribute ("start", startTime);
|
||||
tdb.modifyT (*t);
|
||||
|
||||
original.setId (task.getId ());
|
||||
tdb.modifyT (original);
|
||||
|
||||
nag (tdb, task, conf);
|
||||
return std::string ("");
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stringstream out;
|
||||
out << "Task " << task.getId () << " already started." << std::endl;
|
||||
return out.str ();
|
||||
}
|
||||
if (conf.get ("echo.command", true))
|
||||
out << "Started "
|
||||
<< t->getId ()
|
||||
<< " '"
|
||||
<< t->getDescription ()
|
||||
<< "'"
|
||||
<< std::endl;
|
||||
nag (tdb, task, conf);
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "Task " << t->getId () << " '" << t->getDescription () << "' already started." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
throw std::string ("Task not found.");
|
||||
return std::string (""); // To satisfy gcc.
|
||||
return out.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleStop (TDB& tdb, T& task, Config& conf)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
std::vector <T> all;
|
||||
tdb.pendingT (all);
|
||||
filterSequence (all, task);
|
||||
|
||||
std::vector <T>::iterator it;
|
||||
for (it = all.begin (); it != all.end (); ++it)
|
||||
foreach (t, all)
|
||||
{
|
||||
if (it->getId () == task.getId ())
|
||||
if (t->getAttribute ("start") != "")
|
||||
{
|
||||
T original (*it);
|
||||
t->removeAttribute ("start");
|
||||
tdb.modifyT (*t);
|
||||
|
||||
if (original.getAttribute ("start") != "")
|
||||
{
|
||||
original.removeAttribute ("start");
|
||||
original.setId (task.getId ());
|
||||
tdb.modifyT (original);
|
||||
|
||||
return std::string ("");
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stringstream out;
|
||||
out << "Task " << task.getId () << " not started." << std::endl;
|
||||
return out.str ();
|
||||
}
|
||||
if (conf.get ("echo.command", true))
|
||||
out << "Stopped " << t->getId () << " '" << t->getDescription () << "'" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "Task " << t->getId () << " '" << t->getDescription () << "' not started." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
throw std::string ("Task not found.");
|
||||
return std::string (""); // To satisfy gcc.
|
||||
return out.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleDone (TDB& tdb, T& task, Config& conf)
|
||||
{
|
||||
int count = 0;
|
||||
std::stringstream out;
|
||||
|
||||
if (!tdb.completeT (task))
|
||||
throw std::string ("Could not mark task as completed.");
|
||||
|
||||
// Now update mask in parent.
|
||||
std::vector <T> all;
|
||||
tdb.allPendingT (all);
|
||||
foreach (t, all)
|
||||
|
||||
std::vector <T> filtered = all;
|
||||
filterSequence (filtered, task);
|
||||
foreach (seq, filtered)
|
||||
{
|
||||
if (t->getId () == task.getId ())
|
||||
if (seq->getStatus () == T::pending)
|
||||
{
|
||||
t->setStatus (T::completed);
|
||||
updateRecurrenceMask (tdb, all, *t);
|
||||
break;
|
||||
// Apply deltas.
|
||||
deltaDescription (*seq, task);
|
||||
deltaTags (*seq, task);
|
||||
deltaAttributes (*seq, task);
|
||||
deltaSubstitutions (*seq, task);
|
||||
|
||||
// Add an end date.
|
||||
char entryTime[16];
|
||||
sprintf (entryTime, "%u", (unsigned int) time (NULL));
|
||||
seq->setAttribute ("end", entryTime);
|
||||
|
||||
// Change status.
|
||||
seq->setStatus (T::completed);
|
||||
|
||||
if (!tdb.modifyT (*seq))
|
||||
throw std::string ("Could not mark task as completed.");
|
||||
|
||||
if (conf.get ("echo.command", true))
|
||||
out << "Completed "
|
||||
<< seq->getId ()
|
||||
<< " '"
|
||||
<< seq->getDescription ()
|
||||
<< "'"
|
||||
<< std::endl;
|
||||
|
||||
updateRecurrenceMask (tdb, all, *seq);
|
||||
nag (tdb, *seq, conf);
|
||||
|
||||
++count;
|
||||
}
|
||||
else
|
||||
out << "Task "
|
||||
<< seq->getId ()
|
||||
<< " '"
|
||||
<< seq->getDescription ()
|
||||
<< "' is not pending"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
nag (tdb, task, conf);
|
||||
if (conf.get ("echo.command", true))
|
||||
out << "Marked "
|
||||
<< count
|
||||
<< " task"
|
||||
<< (count == 1 ? "" : "s")
|
||||
<< " as done"
|
||||
<< std::endl;
|
||||
|
||||
return out.str ();
|
||||
}
|
||||
|
||||
@@ -635,92 +697,159 @@ std::string handleExport (TDB& tdb, T& task, Config& conf)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleModify (TDB& tdb, T& task, Config& conf)
|
||||
{
|
||||
int count = 0;
|
||||
std::stringstream out;
|
||||
std::vector <T> all;
|
||||
tdb.pendingT (all);
|
||||
tdb.allPendingT (all);
|
||||
|
||||
std::vector <T>::iterator it;
|
||||
for (it = all.begin (); it != all.end (); ++it)
|
||||
std::vector <T> filtered = all;
|
||||
filterSequence (filtered, task);
|
||||
foreach (seq, filtered)
|
||||
{
|
||||
if (it->getId () == task.getId ())
|
||||
// Perform some logical consistency checks.
|
||||
if (task.getAttribute ("recur") != "" &&
|
||||
task.getAttribute ("due") == "" &&
|
||||
seq->getAttribute ("due") == "")
|
||||
throw std::string ("You cannot specify a recurring task without a due date.");
|
||||
|
||||
if (task.getAttribute ("until") != "" &&
|
||||
task.getAttribute ("recur") == "" &&
|
||||
seq->getAttribute ("recur") == "")
|
||||
throw std::string ("You cannot specify an until date for a non-recurring task.");
|
||||
|
||||
// Make all changes.
|
||||
foreach (other, all)
|
||||
{
|
||||
T original (*it);
|
||||
|
||||
// A non-zero value forces a file write.
|
||||
int changes = 0;
|
||||
|
||||
// Apply a new description, if any.
|
||||
if (task.getDescription () != "")
|
||||
if (other->getId () == seq->getId () || // Self
|
||||
(seq->getAttribute ("parent") != "" &&
|
||||
seq->getAttribute ("parent") == other->getAttribute ("parent")) || // Sibling
|
||||
other->getUUID () == seq->getAttribute ("parent")) // Parent
|
||||
{
|
||||
original.setDescription (task.getDescription ());
|
||||
++changes;
|
||||
// A non-zero value forces a file write.
|
||||
int changes = 0;
|
||||
|
||||
// Apply other deltas.
|
||||
changes += deltaDescription (*other, task);
|
||||
changes += deltaTags (*other, task);
|
||||
changes += deltaAttributes (*other, task);
|
||||
changes += deltaSubstitutions (*other, task);
|
||||
|
||||
if (changes)
|
||||
tdb.modifyT (*other);
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
// Apply or remove tags, if any.
|
||||
std::vector <std::string> tags;
|
||||
task.getTags (tags);
|
||||
for (unsigned int i = 0; i < tags.size (); ++i)
|
||||
{
|
||||
if (tags[i][0] == '+')
|
||||
original.addTag (tags[i].substr (1, std::string::npos));
|
||||
else
|
||||
original.addTag (tags[i]);
|
||||
|
||||
++changes;
|
||||
}
|
||||
|
||||
task.getRemoveTags (tags);
|
||||
for (unsigned int i = 0; i < tags.size (); ++i)
|
||||
{
|
||||
if (tags[i][0] == '-')
|
||||
original.removeTag (tags[i].substr (1, std::string::npos));
|
||||
else
|
||||
original.removeTag (tags[i]);
|
||||
|
||||
++changes;
|
||||
}
|
||||
|
||||
// Apply or remove attributes, if any.
|
||||
std::map <std::string, std::string> attributes;
|
||||
task.getAttributes (attributes);
|
||||
foreach (i, attributes)
|
||||
{
|
||||
if (i->second == "")
|
||||
original.removeAttribute (i->first);
|
||||
else
|
||||
original.setAttribute (i->first, i->second);
|
||||
|
||||
++changes;
|
||||
}
|
||||
|
||||
std::string from;
|
||||
std::string to;
|
||||
task.getSubstitution (from, to);
|
||||
if (from != "")
|
||||
{
|
||||
std::string description = original.getDescription ();
|
||||
size_t pattern = description.find (from);
|
||||
if (pattern != std::string::npos)
|
||||
{
|
||||
description = description.substr (0, pattern) +
|
||||
to +
|
||||
description.substr (pattern + from.length (), std::string::npos);
|
||||
original.setDescription (description);
|
||||
++changes;
|
||||
}
|
||||
}
|
||||
|
||||
if (changes)
|
||||
{
|
||||
original.setId (task.getId ());
|
||||
tdb.modifyT (original);
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
}
|
||||
}
|
||||
|
||||
throw std::string ("Task not found.");
|
||||
if (conf.get ("echo.command", true))
|
||||
out << "Modified " << count << " task" << (count == 1 ? "" : "s") << std::endl;
|
||||
|
||||
return out.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleAppend (TDB& tdb, T& task, Config& conf)
|
||||
{
|
||||
int count = 0;
|
||||
std::stringstream out;
|
||||
std::vector <T> all;
|
||||
tdb.allPendingT (all);
|
||||
|
||||
std::vector <T> filtered = all;
|
||||
filterSequence (filtered, task);
|
||||
foreach (seq, filtered)
|
||||
{
|
||||
foreach (other, all)
|
||||
{
|
||||
if (other->getId () == seq->getId () || // Self
|
||||
(seq->getAttribute ("parent") != "" &&
|
||||
seq->getAttribute ("parent") == other->getAttribute ("parent")) || // Sibling
|
||||
other->getUUID () == seq->getAttribute ("parent")) // Parent
|
||||
{
|
||||
// A non-zero value forces a file write.
|
||||
int changes = 0;
|
||||
|
||||
// Apply other deltas.
|
||||
changes += deltaAppend (*other, task);
|
||||
changes += deltaTags (*other, task);
|
||||
changes += deltaAttributes (*other, task);
|
||||
|
||||
if (changes)
|
||||
{
|
||||
tdb.modifyT (*other);
|
||||
|
||||
if (conf.get ("echo.command", true))
|
||||
out << "Appended '"
|
||||
<< task.getDescription ()
|
||||
<< "' to task "
|
||||
<< other->getId ()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (conf.get ("echo.command", true))
|
||||
out << "Appended " << count << " task" << (count == 1 ? "" : "s") << std::endl;
|
||||
|
||||
return out.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleDuplicate (TDB& tdb, T& task, Config& conf)
|
||||
{
|
||||
int count = 0;
|
||||
std::stringstream out;
|
||||
std::vector <T> all;
|
||||
tdb.allPendingT (all);
|
||||
|
||||
std::vector <T> filtered = all;
|
||||
filterSequence (filtered, task);
|
||||
foreach (seq, filtered)
|
||||
{
|
||||
if (seq->getStatus () != T::recurring && seq->getAttribute ("parent") == "")
|
||||
{
|
||||
T dup (*seq);
|
||||
dup.setUUID (uuid ()); // Needs a new UUID.
|
||||
|
||||
// Apply deltas.
|
||||
deltaDescription (dup, task);
|
||||
deltaTags (dup, task);
|
||||
deltaAttributes (dup, task);
|
||||
deltaSubstitutions (dup, task);
|
||||
|
||||
// A New task needs a new entry time.
|
||||
char entryTime[16];
|
||||
sprintf (entryTime, "%u", (unsigned int) time (NULL));
|
||||
dup.setAttribute ("entry", entryTime);
|
||||
|
||||
if (!tdb.addT (dup))
|
||||
throw std::string ("Could not create new task.");
|
||||
|
||||
if (conf.get ("echo.command", true))
|
||||
out << "Duplicated "
|
||||
<< seq->getId ()
|
||||
<< " '"
|
||||
<< seq->getDescription ()
|
||||
<< "'"
|
||||
<< std::endl;
|
||||
++count;
|
||||
}
|
||||
else
|
||||
out << "Task "
|
||||
<< seq->getId ()
|
||||
<< " '"
|
||||
<< seq->getDescription ()
|
||||
<< "' is a recurring task, and cannot be duplicated."
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
if (conf.get ("echo.command", true))
|
||||
out << "Duplicated " << count << " task" << (count == 1 ? "" : "s") << std::endl;
|
||||
|
||||
return out.str ();
|
||||
}
|
||||
|
||||
@@ -813,3 +942,192 @@ std::string handleColor (Config& conf)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleAnnotate (TDB& tdb, T& task, Config& conf)
|
||||
{
|
||||
std::stringstream out;
|
||||
std::vector <T> all;
|
||||
tdb.pendingT (all);
|
||||
filterSequence (all, task);
|
||||
|
||||
foreach (t, all)
|
||||
{
|
||||
t->addAnnotation (task.getDescription ());
|
||||
tdb.modifyT (*t);
|
||||
|
||||
if (conf.get ("echo.command", true))
|
||||
out << "Annotated "
|
||||
<< t->getId ()
|
||||
<< " with '"
|
||||
<< t->getDescription ()
|
||||
<< "'"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
T findT (int id, const std::vector <T>& all)
|
||||
{
|
||||
std::vector <T>::const_iterator it;
|
||||
for (it = all.begin (); it != all.end (); ++it)
|
||||
if (id == it->getId ())
|
||||
return *it;
|
||||
|
||||
return T ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int deltaAppend (T& task, T& delta)
|
||||
{
|
||||
if (delta.getDescription () != "")
|
||||
{
|
||||
task.setDescription (
|
||||
task.getDescription () +
|
||||
" " +
|
||||
delta.getDescription ());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int deltaDescription (T& task, T& delta)
|
||||
{
|
||||
if (delta.getDescription () != "")
|
||||
{
|
||||
task.setDescription (delta.getDescription ());
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int deltaTags (T& task, T& delta)
|
||||
{
|
||||
int changes = 0;
|
||||
|
||||
// Apply or remove tags, if any.
|
||||
std::vector <std::string> tags;
|
||||
delta.getTags (tags);
|
||||
for (unsigned int i = 0; i < tags.size (); ++i)
|
||||
{
|
||||
if (tags[i][0] == '+')
|
||||
task.addTag (tags[i].substr (1, std::string::npos));
|
||||
else
|
||||
task.addTag (tags[i]);
|
||||
|
||||
++changes;
|
||||
}
|
||||
|
||||
delta.getRemoveTags (tags);
|
||||
for (unsigned int i = 0; i < tags.size (); ++i)
|
||||
{
|
||||
if (tags[i][0] == '-')
|
||||
task.removeTag (tags[i].substr (1, std::string::npos));
|
||||
else
|
||||
task.removeTag (tags[i]);
|
||||
|
||||
++changes;
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int deltaAttributes (T& task, T& delta)
|
||||
{
|
||||
int changes = 0;
|
||||
|
||||
std::map <std::string, std::string> attributes;
|
||||
delta.getAttributes (attributes);
|
||||
foreach (i, attributes)
|
||||
{
|
||||
if (i->second == "")
|
||||
task.removeAttribute (i->first);
|
||||
else
|
||||
task.setAttribute (i->first, i->second);
|
||||
|
||||
++changes;
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int deltaSubstitutions (T& task, T& delta)
|
||||
{
|
||||
int changes = 0;
|
||||
std::string from;
|
||||
std::string to;
|
||||
bool global;
|
||||
delta.getSubstitution (from, to, global);
|
||||
|
||||
if (from != "")
|
||||
{
|
||||
std::string description = task.getDescription ();
|
||||
size_t pattern;
|
||||
|
||||
if (global)
|
||||
{
|
||||
// Perform all subs on description.
|
||||
while ((pattern = description.find (from)) != std::string::npos)
|
||||
{
|
||||
description.replace (pattern, from.length (), to);
|
||||
++changes;
|
||||
}
|
||||
|
||||
task.setDescription (description);
|
||||
|
||||
// Perform all subs on annotations.
|
||||
std::map <time_t, std::string> annotations;
|
||||
task.getAnnotations (annotations);
|
||||
std::map <time_t, std::string>::iterator it;
|
||||
for (it = annotations.begin (); it != annotations.end (); ++it)
|
||||
{
|
||||
while ((pattern = it->second.find (from)) != std::string::npos)
|
||||
{
|
||||
it->second.replace (pattern, from.length (), to);
|
||||
++changes;
|
||||
}
|
||||
}
|
||||
|
||||
task.setAnnotations (annotations);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Perform first description substitution.
|
||||
if ((pattern = description.find (from)) != std::string::npos)
|
||||
{
|
||||
description.replace (pattern, from.length (), to);
|
||||
task.setDescription (description);
|
||||
++changes;
|
||||
}
|
||||
// Failing that, perform the first annotation substitution.
|
||||
else
|
||||
{
|
||||
std::map <time_t, std::string> annotations;
|
||||
task.getAnnotations (annotations);
|
||||
|
||||
std::map <time_t, std::string>::iterator it;
|
||||
for (it = annotations.begin (); it != annotations.end (); ++it)
|
||||
{
|
||||
if ((pattern = it->second.find (from)) != std::string::npos)
|
||||
{
|
||||
it->second.replace (pattern, from.length (), to);
|
||||
++changes;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
task.setAnnotations (annotations);
|
||||
}
|
||||
}
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
588
src/edit.cpp
Normal file
588
src/edit.cpp
Normal file
@@ -0,0 +1,588 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// task - a command line task list manager.
|
||||
//
|
||||
// Copyright 2006 - 2009, 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
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include "task.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static std::string findValue (
|
||||
const std::string& text,
|
||||
const std::string& name)
|
||||
{
|
||||
std::string::size_type found = text.find (name);
|
||||
if (found != std::string::npos)
|
||||
{
|
||||
std::string::size_type eol = text.find ("\n", found);
|
||||
if (eol != std::string::npos)
|
||||
{
|
||||
std::string value = text.substr (
|
||||
found + name.length (),
|
||||
eol - (found + name.length ()));
|
||||
|
||||
return trim (value, "\t ");
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static std::string findDate (
|
||||
Config& conf,
|
||||
const std::string& text,
|
||||
const std::string& name)
|
||||
{
|
||||
std::string::size_type found = text.find (name);
|
||||
if (found != std::string::npos)
|
||||
{
|
||||
std::string::size_type eol = text.find ("\n", found);
|
||||
if (eol != std::string::npos)
|
||||
{
|
||||
std::string value = trim (text.substr (
|
||||
found + name.length (),
|
||||
eol - (found + name.length ())), "\t ");
|
||||
|
||||
if (value != "")
|
||||
{
|
||||
Date dt (value, conf.get ("dateformat", "m/d/Y"));
|
||||
char epoch [16];
|
||||
sprintf (epoch, "%d", (int)dt.toEpoch ());
|
||||
return std::string (epoch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static std::string formatStatus (T& task)
|
||||
{
|
||||
switch (task.getStatus ())
|
||||
{
|
||||
case T::pending: return "Pending"; break;
|
||||
case T::completed: return "Completed"; break;
|
||||
case T::deleted: return "Deleted"; break;
|
||||
case T::recurring: return "Recurring"; break;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static std::string formatDate (
|
||||
Config& conf,
|
||||
T& task,
|
||||
const std::string& attribute)
|
||||
{
|
||||
std::string value = task.getAttribute (attribute);
|
||||
if (value.length ())
|
||||
{
|
||||
Date dt (::atoi (value.c_str ()));
|
||||
value = dt.toString (conf.get ("dateformat", "m/d/Y"));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static std::string formatTask (Config& conf, T task)
|
||||
{
|
||||
std::stringstream before;
|
||||
before << "# The 'task edit <id>' command allows you to modify all aspects of a task" << std::endl
|
||||
<< "# using a text editor. What is shown below is a representation of the" << std::endl
|
||||
<< "# task in all it's detail. Modify what you wish, and if you save and" << std::endl
|
||||
<< "# quit your editor, task will read this file and try to make sense of" << std::endl
|
||||
<< "# what changed, and apply those changes. If you quit your editor without" << std::endl
|
||||
<< "# saving or making any modifications, task will do nothing." << std::endl
|
||||
<< "#" << std::endl
|
||||
<< "# Lines that begin with # represent data you cannot change, like ID." << std::endl
|
||||
<< "# If you get too 'creative' with your editing, task will dump you back " << std::endl
|
||||
<< "# into the editor to try again." << std::endl
|
||||
<< "#" << std::endl
|
||||
<< "# Should you find yourself in an endless Groundhog Day loop, editing and" << std::endl
|
||||
<< "# editing the same file, just quit the editor without making any changes." << std::endl
|
||||
<< "# Task will notice this and stop the editing." << std::endl
|
||||
<< "#" << std::endl
|
||||
<< "# Name Editable details" << std::endl
|
||||
<< "# ----------------- ----------------------------------------------------" << std::endl
|
||||
<< "# ID: " << task.getId () << std::endl
|
||||
<< "# UUID: " << task.getUUID () << std::endl
|
||||
<< "# Status: " << formatStatus (task) << std::endl
|
||||
<< "# Mask: " << task.getAttribute ("mask") << std::endl
|
||||
<< "# iMask: " << task.getAttribute ("imask") << std::endl
|
||||
<< " Project: " << task.getAttribute ("project") << std::endl
|
||||
<< " Priority: " << task.getAttribute ("priority") << std::endl;
|
||||
|
||||
std::vector <std::string> tags;
|
||||
task.getTags (tags);
|
||||
std::string allTags;
|
||||
join (allTags, " ", tags);
|
||||
before << "# Separate the tags with spaces, like this: tag1 tag2" << std::endl
|
||||
<< " Tags: " << allTags << std::endl
|
||||
<< "# The description field is allowed to wrap and use multiple lines. Task" << std::endl
|
||||
<< "# will combine them." << std::endl
|
||||
<< " Description: " << task.getDescription () << std::endl
|
||||
<< " Created: " << formatDate (conf, task, "entry") << std::endl
|
||||
<< " Started: " << formatDate (conf, task, "start") << std::endl
|
||||
<< " Ended: " << formatDate (conf, task, "end") << std::endl
|
||||
<< " Due: " << formatDate (conf, task, "due") << std::endl
|
||||
<< " Until: " << formatDate (conf, task, "until") << std::endl
|
||||
<< " Recur: " << task.getAttribute ("recur") << std::endl
|
||||
<< " Parent: " << task.getAttribute ("parent") << std::endl
|
||||
<< " Foreground color: " << task.getAttribute ("fg") << std::endl
|
||||
<< " Background color: " << task.getAttribute ("bg") << std::endl
|
||||
<< "# Annotations look like this: <date> <text>, and there can be any number" << std::endl
|
||||
<< "# of them." << std::endl;
|
||||
|
||||
std::map <time_t, std::string> annotations;
|
||||
task.getAnnotations (annotations);
|
||||
foreach (anno, annotations)
|
||||
{
|
||||
Date dt (anno->first);
|
||||
before << " Annotation: " << dt.toString (conf.get ("dateformat", "m/d/Y"))
|
||||
<< " " << anno->second << std::endl;
|
||||
}
|
||||
|
||||
before << " Annotation: " << std::endl
|
||||
<< " Annotation: " << std::endl
|
||||
<< "# End" << std::endl;
|
||||
return before.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static void parseTask (Config& conf, T& task, const std::string& after)
|
||||
{
|
||||
// project
|
||||
std::string value = findValue (after, "Project:");
|
||||
if (task.getAttribute ("project") != value)
|
||||
{
|
||||
if (value != "")
|
||||
{
|
||||
std::cout << "Project modified." << std::endl;
|
||||
task.setAttribute ("project", value);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Project deleted." << std::endl;
|
||||
task.removeAttribute ("project");
|
||||
}
|
||||
}
|
||||
|
||||
// priority
|
||||
value = findValue (after, "Priority:");
|
||||
if (task.getAttribute ("priority") != value)
|
||||
{
|
||||
if (value != "")
|
||||
{
|
||||
if (validPriority (value))
|
||||
{
|
||||
std::cout << "Priority modified." << std::endl;
|
||||
task.setAttribute ("priority", value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Priority deleted." << std::endl;
|
||||
task.removeAttribute ("priority");
|
||||
}
|
||||
}
|
||||
|
||||
// tags
|
||||
value = findValue (after, "Tags:");
|
||||
std::vector <std::string> tags;
|
||||
split (tags, value, ' ');
|
||||
task.removeTags ();
|
||||
task.addTags (tags);
|
||||
|
||||
// description.
|
||||
value = findValue (after, "Description: ");
|
||||
if (task.getDescription () != value)
|
||||
{
|
||||
if (value != "")
|
||||
{
|
||||
std::cout << "Description modified." << std::endl;
|
||||
task.setDescription (value);
|
||||
}
|
||||
else
|
||||
throw std::string ("Cannot remove description.");
|
||||
}
|
||||
|
||||
// entry
|
||||
value = findDate (conf, after, "Created:");
|
||||
if (value != "")
|
||||
{
|
||||
Date edited (::atoi (value.c_str ()));
|
||||
|
||||
Date original (::atoi (task.getAttribute ("entry").c_str ()));
|
||||
if (!original.sameDay (edited))
|
||||
{
|
||||
std::cout << "Creation date modified." << std::endl;
|
||||
task.setAttribute ("entry", value);
|
||||
}
|
||||
}
|
||||
else
|
||||
throw std::string ("Cannot remove creation date");
|
||||
|
||||
// start
|
||||
value = findDate (conf, after, "Started:");
|
||||
if (value != "")
|
||||
{
|
||||
Date edited (::atoi (value.c_str ()));
|
||||
|
||||
if (task.getAttribute ("start") != "")
|
||||
{
|
||||
Date original (::atoi (task.getAttribute ("start").c_str ()));
|
||||
if (!original.sameDay (edited))
|
||||
{
|
||||
std::cout << "Start date modified." << std::endl;
|
||||
task.setAttribute ("start", value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Start date modified." << std::endl;
|
||||
task.setAttribute ("start", value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (task.getAttribute ("start") != "")
|
||||
{
|
||||
std::cout << "Start date removed." << std::endl;
|
||||
task.removeAttribute ("start");
|
||||
}
|
||||
}
|
||||
|
||||
// end
|
||||
value = findDate (conf, after, "Ended:");
|
||||
if (value != "")
|
||||
{
|
||||
Date edited (::atoi (value.c_str ()));
|
||||
|
||||
if (task.getAttribute ("end") != "")
|
||||
{
|
||||
Date original (::atoi (task.getAttribute ("end").c_str ()));
|
||||
if (!original.sameDay (edited))
|
||||
{
|
||||
std::cout << "Done date modified." << std::endl;
|
||||
task.setAttribute ("end", value);
|
||||
}
|
||||
}
|
||||
else if (task.getStatus () != T::deleted)
|
||||
throw std::string ("Cannot set a done date on a pending task.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (task.getAttribute ("end") != "")
|
||||
{
|
||||
std::cout << "Done date removed." << std::endl;
|
||||
task.setStatus (T::pending);
|
||||
task.removeAttribute ("end");
|
||||
}
|
||||
}
|
||||
|
||||
// due
|
||||
value = findDate (conf, after, "Due:");
|
||||
if (value != "")
|
||||
{
|
||||
Date edited (::atoi (value.c_str ()));
|
||||
|
||||
if (task.getAttribute ("due") != "")
|
||||
{
|
||||
Date original (::atoi (task.getAttribute ("due").c_str ()));
|
||||
if (!original.sameDay (edited))
|
||||
{
|
||||
std::cout << "Due date modified." << std::endl;
|
||||
task.setAttribute ("due", value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Due date modified." << std::endl;
|
||||
task.setAttribute ("due", value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (task.getAttribute ("due") != "")
|
||||
{
|
||||
if (task.getStatus () == T::recurring ||
|
||||
task.getAttribute ("parent") != "")
|
||||
{
|
||||
std::cout << "Cannot remove a due date from a recurring task." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Due date removed." << std::endl;
|
||||
task.removeAttribute ("due");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// until
|
||||
value = findDate (conf, after, "Until:");
|
||||
if (value != "")
|
||||
{
|
||||
Date edited (::atoi (value.c_str ()));
|
||||
|
||||
if (task.getAttribute ("until") != "")
|
||||
{
|
||||
Date original (::atoi (task.getAttribute ("until").c_str ()));
|
||||
if (!original.sameDay (edited))
|
||||
{
|
||||
std::cout << "Until date modified." << std::endl;
|
||||
task.setAttribute ("until", value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Until date modified." << std::endl;
|
||||
task.setAttribute ("until", value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (task.getAttribute ("until") != "")
|
||||
{
|
||||
std::cout << "Until date removed." << std::endl;
|
||||
task.removeAttribute ("until");
|
||||
}
|
||||
}
|
||||
|
||||
// recur
|
||||
value = findValue (after, "Recur:");
|
||||
if (value != task.getAttribute ("recur"))
|
||||
{
|
||||
if (value != "")
|
||||
{
|
||||
if (validDuration (value))
|
||||
{
|
||||
std::cout << "Recurrence modified." << std::endl;
|
||||
if (task.getAttribute ("due") != "")
|
||||
{
|
||||
task.setAttribute ("recur", value);
|
||||
task.setStatus (T::recurring);
|
||||
}
|
||||
else
|
||||
throw std::string ("A recurring task must have a due date.");
|
||||
}
|
||||
else
|
||||
throw std::string ("Not a valid recurrence duration.");
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Recurrence removed." << std::endl;
|
||||
task.setStatus (T::pending);
|
||||
task.removeAttribute ("recur");
|
||||
task.removeAttribute ("until");
|
||||
task.removeAttribute ("mask");
|
||||
task.removeAttribute ("imask");
|
||||
}
|
||||
}
|
||||
|
||||
// parent
|
||||
value = findValue (after, "Parent:");
|
||||
if (value != task.getAttribute ("parent"))
|
||||
{
|
||||
if (value != "")
|
||||
{
|
||||
std::cout << "Parent UUID modified." << std::endl;
|
||||
task.setAttribute ("parent", value);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Parent UUID removed." << std::endl;
|
||||
task.removeAttribute ("parent");
|
||||
}
|
||||
}
|
||||
|
||||
// fg
|
||||
value = findValue (after, "Foreground color:");
|
||||
if (value != task.getAttribute ("fg"))
|
||||
{
|
||||
if (value != "")
|
||||
{
|
||||
std::cout << "Foreground color modified." << std::endl;
|
||||
task.setAttribute ("fg", value);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Foreground color removed." << std::endl;
|
||||
task.removeAttribute ("fg");
|
||||
}
|
||||
}
|
||||
|
||||
// bg
|
||||
value = findValue (after, "Background color:");
|
||||
if (value != task.getAttribute ("bg"))
|
||||
{
|
||||
if (value != "")
|
||||
{
|
||||
std::cout << "Background color modified." << std::endl;
|
||||
task.setAttribute ("bg", value);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Background color removed." << std::endl;
|
||||
task.removeAttribute ("bg");
|
||||
}
|
||||
}
|
||||
|
||||
// Annotations
|
||||
std::map <time_t, std::string> annotations;
|
||||
std::string::size_type found = 0;
|
||||
while ((found = after.find ("Annotation:", found)) != std::string::npos)
|
||||
{
|
||||
found += 11;
|
||||
|
||||
std::string::size_type eol = after.find ("\n", found);
|
||||
if (eol != std::string::npos)
|
||||
{
|
||||
std::string value = trim (after.substr (
|
||||
found,
|
||||
eol - found), "\t ");
|
||||
|
||||
std::string::size_type gap = value.find (" ");
|
||||
if (gap != std::string::npos)
|
||||
{
|
||||
Date when (value.substr (0, gap));
|
||||
std::string text = trim (value.substr (gap, std::string::npos), "\t ");
|
||||
annotations[when.toEpoch ()] = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task.setAnnotations (annotations);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introducing the Silver Bullet. This feature is the catch-all fixative for
|
||||
// various other ills. This is like opening up the hood and going in with a
|
||||
// wrench. To be used sparingly.
|
||||
std::string handleEdit (TDB& tdb, T& task, Config& conf)
|
||||
{
|
||||
std::stringstream out;
|
||||
std::vector <T> all;
|
||||
tdb.allPendingT (all);
|
||||
|
||||
filterSequence (all, task);
|
||||
foreach (seq, all)
|
||||
{
|
||||
// Check for file permissions.
|
||||
std::string dataLocation = expandPath (conf.get ("data.location"));
|
||||
if (access (dataLocation.c_str (), X_OK))
|
||||
throw std::string ("Your data.location directory is not writable.");
|
||||
|
||||
// Create a temp file name in data.location.
|
||||
std::stringstream pattern;
|
||||
pattern << dataLocation << "/task." << seq->getId () << ".XXXXXX";
|
||||
char cpattern [PATH_MAX];
|
||||
strcpy (cpattern, pattern.str ().c_str ());
|
||||
mkstemp (cpattern);
|
||||
char* file = cpattern;
|
||||
|
||||
// Format the contents, T -> text, write to a file.
|
||||
std::string before = formatTask (conf, *seq);
|
||||
spit (file, before);
|
||||
|
||||
// Determine correct editor: .taskrc:editor > $VISUAL > $EDITOR > vi
|
||||
std::string editor = conf.get ("editor", "");
|
||||
char* peditor = getenv ("VISUAL");
|
||||
if (editor == "" && peditor) editor = std::string (peditor);
|
||||
peditor = getenv ("EDITOR");
|
||||
if (editor == "" && peditor) editor = std::string (peditor);
|
||||
if (editor == "") editor = "vi";
|
||||
|
||||
// Complete the command line.
|
||||
editor += " ";
|
||||
editor += file;
|
||||
|
||||
ARE_THESE_REALLY_HARMFUL:
|
||||
// Launch the editor.
|
||||
std::cout << "Launching '" << editor << "' now..." << std::endl;
|
||||
system (editor.c_str ());
|
||||
std::cout << "Editing complete." << std::endl;
|
||||
|
||||
// Slurp file.
|
||||
std::string after;
|
||||
slurp (file, after, false);
|
||||
|
||||
// TODO Remove this debugging code.
|
||||
//spit ("./before", before);
|
||||
//spit ("./after", after);
|
||||
|
||||
// Update seq based on what can be parsed back out of the file, but only
|
||||
// if changes were made.
|
||||
if (before != after)
|
||||
{
|
||||
std::cout << "Edits were detected." << std::endl;
|
||||
std::string problem = "";
|
||||
bool oops = false;
|
||||
|
||||
try
|
||||
{
|
||||
parseTask (conf, *seq, after);
|
||||
tdb.modifyT (*seq);
|
||||
}
|
||||
|
||||
catch (std::string& e)
|
||||
{
|
||||
problem = e;
|
||||
oops = true;
|
||||
}
|
||||
|
||||
if (oops)
|
||||
{
|
||||
std::cout << "Error: " << problem << std::endl;
|
||||
|
||||
// Preserve the edits.
|
||||
before = after;
|
||||
spit (file, before);
|
||||
|
||||
if (confirm ("Task couldn't handle your edits. Would you like to try again?"))
|
||||
goto ARE_THESE_REALLY_HARMFUL;
|
||||
}
|
||||
}
|
||||
else
|
||||
std::cout << "No edits were detected." << std::endl;
|
||||
|
||||
// Cleanup.
|
||||
unlink (file);
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
1203
src/import.cpp
Normal file
1203
src/import.cpp
Normal file
File diff suppressed because it is too large
Load Diff
153
src/parse.cpp
153
src/parse.cpp
@@ -116,19 +116,25 @@ static const char* attributes[] =
|
||||
"",
|
||||
};
|
||||
|
||||
// Alphabetical please.
|
||||
static const char* commands[] =
|
||||
{
|
||||
"active",
|
||||
"add",
|
||||
"append",
|
||||
"annotate",
|
||||
"calendar",
|
||||
"colors",
|
||||
"completed",
|
||||
"delete",
|
||||
"done",
|
||||
"duplicate",
|
||||
"edit",
|
||||
"export",
|
||||
"help",
|
||||
"history",
|
||||
"ghistory",
|
||||
"import",
|
||||
"info",
|
||||
"next",
|
||||
"overdue",
|
||||
@@ -138,6 +144,7 @@ static const char* commands[] =
|
||||
"stop",
|
||||
"summary",
|
||||
"tags",
|
||||
"timesheet",
|
||||
"undelete",
|
||||
"undo",
|
||||
"version",
|
||||
@@ -188,7 +195,6 @@ void guess (const std::string& type, std::vector<std::string>& options, std::str
|
||||
candidate = matches[0];
|
||||
|
||||
else if (0 == matches.size ())
|
||||
// throw std::string ("Unrecognized ") + type + " '" + candidate + "'";
|
||||
candidate = "";
|
||||
|
||||
else
|
||||
@@ -233,7 +239,7 @@ bool validDate (std::string& date, Config& conf)
|
||||
{
|
||||
Date test (date, conf.get ("dateformat", "m/d/Y"));
|
||||
|
||||
char epoch[12];
|
||||
char epoch[16];
|
||||
sprintf (epoch, "%d", (int) test.toEpoch ());
|
||||
date = epoch;
|
||||
|
||||
@@ -297,6 +303,9 @@ static bool validAttribute (
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static bool validId (const std::string& input)
|
||||
{
|
||||
if (input.length () == 0)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < input.length (); ++i)
|
||||
if (!::isdigit (input[i]))
|
||||
return false;
|
||||
@@ -304,6 +313,58 @@ static bool validId (const std::string& input)
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 1,2-4,6
|
||||
static bool validSequence (
|
||||
const std::string& input,
|
||||
std::vector <int>& ids)
|
||||
{
|
||||
std::vector <std::string> ranges;
|
||||
split (ranges, input, ',');
|
||||
|
||||
std::vector <std::string>::iterator it;
|
||||
for (it = ranges.begin (); it != ranges.end (); ++it)
|
||||
{
|
||||
std::vector <std::string> range;
|
||||
split (range, *it, '-');
|
||||
|
||||
switch (range.size ())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
if (! validId (range[0]))
|
||||
return false;
|
||||
|
||||
int id = ::atoi (range[0].c_str ());
|
||||
ids.push_back (id);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
if (! validId (range[0]) ||
|
||||
! validId (range[1]))
|
||||
return false;
|
||||
|
||||
int low = ::atoi (range[0].c_str ());
|
||||
int high = ::atoi (range[1].c_str ());
|
||||
if (low >= high)
|
||||
return false;
|
||||
|
||||
for (int i = low; i <= high; ++i)
|
||||
ids.push_back (i);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ids.size () ? true : false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static bool validTag (const std::string& input)
|
||||
{
|
||||
@@ -346,7 +407,8 @@ static bool validCommand (std::string& input)
|
||||
static bool validSubstitution (
|
||||
std::string& input,
|
||||
std::string& from,
|
||||
std::string& to)
|
||||
std::string& to,
|
||||
bool& global)
|
||||
{
|
||||
size_t first = input.find ('/');
|
||||
if (first != std::string::npos)
|
||||
@@ -360,10 +422,17 @@ static bool validSubstitution (
|
||||
if (first == 0 &&
|
||||
first < second &&
|
||||
second < third &&
|
||||
third == input.length () - 1)
|
||||
(third == input.length () - 1 ||
|
||||
third == input.length () - 2))
|
||||
{
|
||||
from = input.substr (first + 1, second - first - 1);
|
||||
to = input.substr (second + 1, third - second - 1);
|
||||
|
||||
global = false;
|
||||
if (third == input.length () - 2 &&
|
||||
input.find ('g', third + 1) != std::string::npos)
|
||||
global = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -380,15 +449,23 @@ bool validDuration (std::string& input)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Token Distinguishing characteristic
|
||||
// ------- -----------------------------
|
||||
// command first positional
|
||||
// id \d+
|
||||
// description default, accumulate
|
||||
// substitution /\w+/\w*/
|
||||
// tags [-+]\w+
|
||||
// attributes \w+:.+
|
||||
// Token EBNF
|
||||
// ------- ----------------------------------
|
||||
// command first non-id recognized argument
|
||||
//
|
||||
// substitution ::= "/" from "/" to "/g"
|
||||
// | "/" from "/" to "/" ;
|
||||
//
|
||||
// tags ::= "+" word
|
||||
// | "-" word ;
|
||||
//
|
||||
// attributes ::= word ":" value
|
||||
// | word ":"
|
||||
//
|
||||
// sequence ::= \d+ "," sequence
|
||||
// | \d+ "-" \d+ ;
|
||||
//
|
||||
// description (whatever isn't one of the above)
|
||||
void parse (
|
||||
std::vector <std::string>& args,
|
||||
std::string& command,
|
||||
@@ -397,6 +474,9 @@ void parse (
|
||||
{
|
||||
command = "";
|
||||
|
||||
bool foundSequence = false;
|
||||
bool foundSomethingAfterSequence = false;
|
||||
|
||||
std::string descCandidate = "";
|
||||
for (size_t i = 0; i < args.size (); ++i)
|
||||
{
|
||||
@@ -409,16 +489,25 @@ void parse (
|
||||
size_t colon; // Pointer to colon in argument.
|
||||
std::string from;
|
||||
std::string to;
|
||||
bool global;
|
||||
std::vector <int> sequence;
|
||||
|
||||
// An id is the first argument found that contains all digits.
|
||||
if (lowerCase (command) != "add" && // "add" doesn't require an ID
|
||||
task.getId () == 0 &&
|
||||
validId (arg))
|
||||
task.setId (::atoi (arg.c_str ()));
|
||||
if (lowerCase (command) != "add" && // "add" doesn't require an ID
|
||||
validSequence (arg, sequence) &&
|
||||
! foundSomethingAfterSequence)
|
||||
{
|
||||
foundSequence = true;
|
||||
foreach (id, sequence)
|
||||
task.addId (*id);
|
||||
}
|
||||
|
||||
// Tags begin with + or - and contain arbitrary text.
|
||||
else if (validTag (arg))
|
||||
{
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
if (arg[0] == '+')
|
||||
task.addTag (arg.substr (1, std::string::npos));
|
||||
else if (arg[0] == '-')
|
||||
@@ -429,6 +518,9 @@ void parse (
|
||||
// value.
|
||||
else if ((colon = arg.find (":")) != std::string::npos)
|
||||
{
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
std::string name = lowerCase (arg.substr (0, colon));
|
||||
std::string value = arg.substr (colon + 1, std::string::npos);
|
||||
|
||||
@@ -441,18 +533,28 @@ void parse (
|
||||
// If it is not a valid attribute, then allow the argument as part of
|
||||
// the description.
|
||||
else
|
||||
{
|
||||
if (descCandidate.length ())
|
||||
descCandidate += " ";
|
||||
descCandidate += arg;
|
||||
}
|
||||
}
|
||||
|
||||
// Substitution of description text.
|
||||
else if (validSubstitution (arg, from, to))
|
||||
else if (validSubstitution (arg, from, to, global))
|
||||
{
|
||||
task.setSubstitution (from, to);
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
task.setSubstitution (from, to, global);
|
||||
}
|
||||
|
||||
// Command.
|
||||
else if (command == "")
|
||||
{
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
std::string l = lowerCase (arg);
|
||||
if (isCommand (l) && validCommand (l))
|
||||
command = l;
|
||||
@@ -460,28 +562,23 @@ void parse (
|
||||
{
|
||||
if (descCandidate.length ())
|
||||
descCandidate += " ";
|
||||
descCandidate += std::string (arg);
|
||||
descCandidate += arg;
|
||||
}
|
||||
}
|
||||
|
||||
// Anything else is just considered description.
|
||||
else
|
||||
{
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
if (descCandidate.length ())
|
||||
descCandidate += " ";
|
||||
descCandidate += std::string (arg);
|
||||
descCandidate += arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (task.getAttribute ("recur") != "" &&
|
||||
task.getAttribute ("due") == "")
|
||||
throw std::string ("You cannot specify a recurring task without a due date.");
|
||||
|
||||
if (task.getAttribute ("until") != "" &&
|
||||
task.getAttribute ("recur") == "")
|
||||
throw std::string ("You cannot specify an until date for a non-recurring task.");
|
||||
|
||||
if (validDescription (descCandidate))
|
||||
task.setDescription (descCandidate);
|
||||
}
|
||||
|
||||
742
src/report.cpp
742
src/report.cpp
File diff suppressed because it is too large
Load Diff
131
src/task.cpp
131
src/task.cpp
@@ -52,7 +52,7 @@ static std::string shortUsage (Config& conf)
|
||||
{
|
||||
std::stringstream out;
|
||||
Table table;
|
||||
int width = conf.get ("defaultwidth", 80);
|
||||
int width = conf.get ("defaultwidth", (int) 80);
|
||||
#ifdef HAVE_LIBNCURSES
|
||||
if (conf.get ("curses", true))
|
||||
{
|
||||
@@ -84,6 +84,14 @@ static std::string shortUsage (Config& conf)
|
||||
table.addCell (row, 1, "task add [tags] [attrs] desc...");
|
||||
table.addCell (row, 2, "Adds a new task");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task append [tags] [attrs] desc...");
|
||||
table.addCell (row, 2, "Appends more description to an existing task");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task annotate ID desc...");
|
||||
table.addCell (row, 2, "Adds an annotation to an existing task");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task completed [tags] [attrs] desc...");
|
||||
table.addCell (row, 2, "Chronological listing of all completed tasks matching the specified criteria");
|
||||
@@ -94,7 +102,19 @@ static std::string shortUsage (Config& conf)
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task ID /from/to/");
|
||||
table.addCell (row, 2, "Perform the substitution on the desc, for fixing mistakes");
|
||||
table.addCell (row, 2, "Performs one substitution on the task description, for fixing mistakes");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task ID /from/to/g");
|
||||
table.addCell (row, 2, "Performs all substitutions on the task description, for fixing mistakes");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task edit ID");
|
||||
table.addCell (row, 2, "Launches an editor to let you modify all aspects of a task directly, therefore it is to be used carefully");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task duplicate ID [tags] [attrs] [desc...]");
|
||||
table.addCell (row, 2, "Duplicates the specified task, and allows modifications");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task delete ID");
|
||||
@@ -117,7 +137,7 @@ static std::string shortUsage (Config& conf)
|
||||
table.addCell (row, 2, "Removes the 'start' time from a task");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task done ID");
|
||||
table.addCell (row, 1, "task done ID [tags] [attrs] [desc...]");
|
||||
table.addCell (row, 2, "Marks the specified task as completed");
|
||||
|
||||
row = table.addRow ();
|
||||
@@ -136,6 +156,10 @@ static std::string shortUsage (Config& conf)
|
||||
table.addCell (row, 1, "task summary");
|
||||
table.addCell (row, 2, "Shows a report of task status by project");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task timesheet [weeks]");
|
||||
table.addCell (row, 2, "Shows a weekly report of tasks completed and started");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task history");
|
||||
table.addCell (row, 2, "Shows a report of task history, by month");
|
||||
@@ -164,6 +188,10 @@ static std::string shortUsage (Config& conf)
|
||||
table.addCell (row, 1, "task stats");
|
||||
table.addCell (row, 2, "Shows task database statistics");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task import");
|
||||
table.addCell (row, 2, "Imports tasks from a variety of formats");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task export");
|
||||
table.addCell (row, 2, "Exports all tasks as a CSV file");
|
||||
@@ -198,7 +226,8 @@ static std::string shortUsage (Config& conf)
|
||||
<< std::endl
|
||||
<< "See http://www.beckingham.net/task.html for the latest releases and a "
|
||||
<< "full tutorial. New releases containing fixes and enhancements are "
|
||||
<< "made frequently."
|
||||
<< "made frequently. Join in the discussion of task, present and future, "
|
||||
<< "at http://groups.google.com/group/taskprogram"
|
||||
<< std::endl
|
||||
<< std::endl;
|
||||
|
||||
@@ -210,7 +239,13 @@ static std::string longUsage (Config& conf)
|
||||
{
|
||||
std::stringstream out;
|
||||
out << shortUsage (conf)
|
||||
<< "ID is the numeric identifier displayed by the 'task list' command." << "\n"
|
||||
<< "ID is the numeric identifier displayed by the 'task list' command. "
|
||||
<< "You can specify multiple IDs for task commands, and multiple tasks "
|
||||
<< "will be affected. To specify multiple IDs make sure you use one "
|
||||
<< "of these forms:" << "\n"
|
||||
<< " task delete 1,2,3" << "\n"
|
||||
<< " task info 1-3" << "\n"
|
||||
<< " task pri:H 1,2-5,19" << "\n"
|
||||
<< "\n"
|
||||
<< "Tags are arbitrary words, any quantity:" << "\n"
|
||||
<< " +tag The + means add the tag" << "\n"
|
||||
@@ -319,7 +354,7 @@ int main (int argc, char** argv)
|
||||
|
||||
catch (std::string& error)
|
||||
{
|
||||
std::cerr << error << std::endl;
|
||||
std::cout << error << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -440,7 +475,13 @@ void handleRecurrence (TDB& tdb, std::vector <T>& tasks)
|
||||
<< " ("
|
||||
<< trim (t->getDescription ())
|
||||
<< ") is past its 'until' date, and has be deleted" << std::endl;
|
||||
tdb.deleteT (*t);
|
||||
|
||||
// Determine the end date.
|
||||
char endTime[16];
|
||||
sprintf (endTime, "%u", (unsigned int) time (NULL));
|
||||
t->setAttribute ("end", endTime);
|
||||
t->setStatus (T::deleted);
|
||||
tdb.modifyT (*t);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -561,6 +602,18 @@ Date getNextRecurrence (Date& current, std::string& period)
|
||||
return Date (m, d, y);
|
||||
}
|
||||
|
||||
if (period == "weekdays")
|
||||
{
|
||||
int dow = current.dayOfWeek ();
|
||||
int days;
|
||||
|
||||
if (dow == 5) days = 3;
|
||||
else if (dow == 6) days = 2;
|
||||
else days = 1;
|
||||
|
||||
return current + (days * 86400);
|
||||
}
|
||||
|
||||
if (isdigit (period[0]) && period[period.length () - 1] == 'm')
|
||||
{
|
||||
std::string numeric = period.substr (0, period.length () - 1);
|
||||
@@ -650,6 +703,19 @@ Date getNextRecurrence (Date& current, std::string& period)
|
||||
return Date (m, d, y);
|
||||
}
|
||||
|
||||
else if (period == "annual" ||
|
||||
period == "yearly")
|
||||
{
|
||||
y += 1;
|
||||
|
||||
// If the due data just happens to be 2/29 in a leap year, then simply
|
||||
// incrementing y is going to create an invalid date.
|
||||
if (m == 2 && d == 29)
|
||||
d = 28;
|
||||
|
||||
return Date (m, d, y);
|
||||
}
|
||||
|
||||
// If the period is an 'easy' one, add it to current, and we're done.
|
||||
int days = convertDuration (period);
|
||||
return current + (days * 86400);
|
||||
@@ -743,12 +809,12 @@ void updateShadowFile (TDB& tdb, Config& conf)
|
||||
|
||||
catch (std::string& error)
|
||||
{
|
||||
std::cout << error << std::endl;
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
|
||||
catch (...)
|
||||
{
|
||||
std::cout << "Unknown error." << std::endl;
|
||||
std::cerr << "Unknown error." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -800,31 +866,36 @@ std::string runTaskCommand (
|
||||
std::string out;
|
||||
|
||||
// Read-only commands with no side effects.
|
||||
if (command == "export") { out = handleExport (tdb, task, conf); }
|
||||
else if (command == "projects") { out = handleProjects (tdb, task, conf); }
|
||||
else if (command == "tags") { out = handleTags (tdb, task, conf); }
|
||||
else if (command == "info") { out = handleInfo (tdb, task, conf); }
|
||||
else if (command == "stats") { out = handleReportStats (tdb, task, conf); }
|
||||
else if (command == "history") { out = handleReportHistory (tdb, task, conf); }
|
||||
else if (command == "ghistory") { out = handleReportGHistory (tdb, task, conf); }
|
||||
else if (command == "calendar") { out = handleReportCalendar (tdb, task, conf); }
|
||||
else if (command == "summary") { out = handleReportSummary (tdb, task, conf); }
|
||||
else if (command == "colors") { out = handleColor ( conf); }
|
||||
else if (command == "version") { out = handleVersion ( conf); }
|
||||
else if (command == "help") { out = longUsage ( conf); }
|
||||
if (command == "export") { out = handleExport (tdb, task, conf); }
|
||||
else if (command == "projects") { out = handleProjects (tdb, task, conf); }
|
||||
else if (command == "tags") { out = handleTags (tdb, task, conf); }
|
||||
else if (command == "info") { out = handleInfo (tdb, task, conf); }
|
||||
else if (command == "stats") { out = handleReportStats (tdb, task, conf); }
|
||||
else if (command == "history") { out = handleReportHistory (tdb, task, conf); }
|
||||
else if (command == "ghistory") { out = handleReportGHistory (tdb, task, conf); }
|
||||
else if (command == "calendar") { out = handleReportCalendar (tdb, task, conf); }
|
||||
else if (command == "summary") { out = handleReportSummary (tdb, task, conf); }
|
||||
else if (command == "timesheet") { out = handleReportTimesheet (tdb, task, conf); }
|
||||
else if (command == "colors") { out = handleColor ( conf); }
|
||||
else if (command == "version") { out = handleVersion ( conf); }
|
||||
else if (command == "help") { out = longUsage ( conf); }
|
||||
|
||||
// Commands that cause updates.
|
||||
else if (command == "" && task.getId ()) { cmdMod = true; out = handleModify (tdb, task, conf); }
|
||||
else if (command == "add") { cmdMod = true; out = handleAdd (tdb, task, conf); }
|
||||
else if (command == "done") { cmdMod = true; out = handleDone (tdb, task, conf); }
|
||||
else if (command == "undelete") { cmdMod = true; out = handleUndelete (tdb, task, conf); }
|
||||
else if (command == "delete") { cmdMod = true; out = handleDelete (tdb, task, conf); }
|
||||
else if (command == "start") { cmdMod = true; out = handleStart (tdb, task, conf); }
|
||||
else if (command == "stop") { cmdMod = true; out = handleStop (tdb, task, conf); }
|
||||
else if (command == "undo") { cmdMod = true; out = handleUndo (tdb, task, conf); }
|
||||
else if (command == "" && task.getId ()) { cmdMod = true; out = handleModify (tdb, task, conf); }
|
||||
else if (command == "add") { cmdMod = true; out = handleAdd (tdb, task, conf); }
|
||||
else if (command == "append") { cmdMod = true; out = handleAppend (tdb, task, conf); }
|
||||
else if (command == "annotate") { cmdMod = true; out = handleAnnotate (tdb, task, conf); }
|
||||
else if (command == "done") { cmdMod = true; out = handleDone (tdb, task, conf); }
|
||||
else if (command == "undelete") { cmdMod = true; out = handleUndelete (tdb, task, conf); }
|
||||
else if (command == "delete") { cmdMod = true; out = handleDelete (tdb, task, conf); }
|
||||
else if (command == "start") { cmdMod = true; out = handleStart (tdb, task, conf); }
|
||||
else if (command == "stop") { cmdMod = true; out = handleStop (tdb, task, conf); }
|
||||
else if (command == "undo") { cmdMod = true; out = handleUndo (tdb, task, conf); }
|
||||
else if (command == "import") { cmdMod = true; out = handleImport (tdb, task, conf); }
|
||||
else if (command == "duplicate") { cmdMod = true; out = handleDuplicate (tdb, task, conf); }
|
||||
else if (command == "edit") { cmdMod = true; out = handleEdit (tdb, task, conf); }
|
||||
|
||||
// Command that display IDs and therefore need TDB::gc first.
|
||||
|
||||
else if (command == "completed") { if (gc) gcMod = tdb.gc (); out = handleCompleted (tdb, task, conf); }
|
||||
else if (command == "next") { if (gc) gcMod = tdb.gc (); out = handleReportNext (tdb, task, conf); }
|
||||
else if (command == "active") { if (gc) gcMod = tdb.gc (); out = handleReportActive (tdb, task, conf); }
|
||||
|
||||
75
src/task.h
75
src/task.h
@@ -57,6 +57,7 @@ for (typeof (c) *foreach_p = & (c); \
|
||||
void parse (std::vector <std::string>&, std::string&, T&, Config&);
|
||||
bool validPriority (const std::string&);
|
||||
bool validDate (std::string&, Config&);
|
||||
bool validDuration (std::string&);
|
||||
void loadCustomReports (Config&);
|
||||
bool isCustomReport (const std::string&);
|
||||
void allCustomReports (std::vector <std::string>&);
|
||||
@@ -75,6 +76,7 @@ std::string runTaskCommand (std::vector <std::string>&, TDB&, Config&, bool gc =
|
||||
|
||||
// command.cpp
|
||||
std::string handleAdd (TDB&, T&, Config&);
|
||||
std::string handleAppend (TDB&, T&, Config&);
|
||||
std::string handleExport (TDB&, T&, Config&);
|
||||
std::string handleDone (TDB&, T&, Config&);
|
||||
std::string handleModify (TDB&, T&, Config&);
|
||||
@@ -87,8 +89,20 @@ std::string handleStart (TDB&, T&, Config&);
|
||||
std::string handleStop (TDB&, T&, Config&);
|
||||
std::string handleUndo (TDB&, T&, Config&);
|
||||
std::string handleColor (Config&);
|
||||
std::string handleAnnotate (TDB&, T&, Config&);
|
||||
std::string handleDuplicate (TDB&, T&, Config&);
|
||||
T findT (int, const std::vector <T>&);
|
||||
int deltaAppend (T&, T&);
|
||||
int deltaDescription (T&, T&);
|
||||
int deltaTags (T&, T&);
|
||||
int deltaAttributes (T&, T&);
|
||||
int deltaSubstitutions (T&, T&);
|
||||
|
||||
// edit.cpp
|
||||
std::string handleEdit (TDB&, T&, Config&);
|
||||
|
||||
// report.cpp
|
||||
void filterSequence (std::vector<T>&, T&);
|
||||
void filter (std::vector<T>&, T&);
|
||||
std::string handleInfo (TDB&, T&, Config&);
|
||||
std::string handleCompleted (TDB&, T&, Config&);
|
||||
@@ -100,18 +114,18 @@ std::string handleReportCalendar (TDB&, T&, Config&);
|
||||
std::string handleReportActive (TDB&, T&, Config&);
|
||||
std::string handleReportOverdue (TDB&, T&, Config&);
|
||||
std::string handleReportStats (TDB&, T&, Config&);
|
||||
std::string handleReportTimesheet (TDB&, T&, Config&);
|
||||
|
||||
std::string handleCustomReport (TDB&, T&, Config&, const std::string&);
|
||||
void validReportColumns (const std::vector <std::string>&);
|
||||
void validSortColumns (const std::vector <std::string>&, const std::vector <std::string>&);
|
||||
|
||||
// util.cpp
|
||||
bool confirm (const std::string&);
|
||||
// text.cpp
|
||||
void wrapText (std::vector <std::string>&, const std::string&, const int);
|
||||
std::string trimLeft (const std::string& in, const std::string& t = " ");
|
||||
std::string trimRight (const std::string& in, const std::string& t = " ");
|
||||
std::string trim (const std::string& in, const std::string& t = " ");
|
||||
void extractParagraphs (const std::string&, std::vector<std::string>&);
|
||||
std::string unquoteText (const std::string&);
|
||||
void extractLine (std::string&, std::string&, int);
|
||||
void split (std::vector<std::string>&, const std::string&, const char);
|
||||
void split (std::vector<std::string>&, const std::string&, const std::string&);
|
||||
@@ -119,12 +133,15 @@ void join (std::string&, const std::string&, const std::vector<std::string>&);
|
||||
std::string commify (const std::string&);
|
||||
std::string lowerCase (const std::string&);
|
||||
std::string upperCase (const std::string&);
|
||||
const char* optionalBlankLine (Config&);
|
||||
|
||||
// util.cpp
|
||||
bool confirm (const std::string&);
|
||||
void delay (float);
|
||||
int autoComplete (const std::string&, const std::vector<std::string>&, std::vector<std::string>&);
|
||||
void formatTimeDeltaDays (std::string&, time_t);
|
||||
std::string formatSeconds (time_t);
|
||||
int autoComplete (const std::string&, const std::vector<std::string>&, std::vector<std::string>&);
|
||||
const std::string uuid ();
|
||||
const char* optionalBlankLine (Config&);
|
||||
int convertDuration (const std::string&);
|
||||
std::string expandPath (const std::string&);
|
||||
|
||||
@@ -137,8 +154,56 @@ std::string expandPath (const std::string&);
|
||||
int flock (int, int);
|
||||
#endif
|
||||
|
||||
bool slurp (const std::string&, std::vector <std::string>&, bool trimLines = false);
|
||||
bool slurp (const std::string&, std::string&, bool trimLines = false);
|
||||
void spit (const std::string&, const std::string&);
|
||||
|
||||
// rules.cpp
|
||||
void initializeColorRules (Config&);
|
||||
void autoColorize (T&, Text::color&, Text::color&, Config&);
|
||||
|
||||
// import.cpp
|
||||
std::string handleImport (TDB&, T&, Config&);
|
||||
|
||||
// list template
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <class T> void listDiff (
|
||||
const T& left, const T& right, T& leftOnly, T& rightOnly)
|
||||
{
|
||||
leftOnly.clear ();
|
||||
rightOnly.clear ();
|
||||
|
||||
for (unsigned int l = 0; l < left.size (); ++l)
|
||||
{
|
||||
bool found = false;
|
||||
for (unsigned int r = 0; r < right.size (); ++r)
|
||||
{
|
||||
if (left[l] == right[r])
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
leftOnly.push_back (left[l]);
|
||||
}
|
||||
|
||||
for (unsigned int r = 0; r < right.size (); ++r)
|
||||
{
|
||||
bool found = false;
|
||||
for (unsigned int l = 0; l < left.size (); ++l)
|
||||
{
|
||||
if (left[l] == right[r])
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
rightOnly.push_back (right[r]);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
4
src/tests/.gitignore
vendored
4
src/tests/.gitignore
vendored
@@ -3,4 +3,6 @@ t.benchmark.t
|
||||
tdb.t
|
||||
date.t
|
||||
duration.t
|
||||
|
||||
text.t
|
||||
autocomplete.t
|
||||
parse.t
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
PROJECT = t.t tdb.t date.t duration.t t.benchmark.t
|
||||
PROJECT = t.t tdb.t date.t duration.t t.benchmark.t text.t autocomplete.t \
|
||||
parse.t
|
||||
CFLAGS = -I. -I.. -Wall -pedantic -ggdb3 -fno-rtti
|
||||
LFLAGS = -L/usr/local/lib
|
||||
OBJECTS = ../TDB.o ../T.o ../parse.o ../text.o ../Date.o ../util.o ../Config.o
|
||||
@@ -32,3 +33,12 @@ duration.t: duration.t.o $(OBJECTS) test.o
|
||||
t.benchmark.t: t.benchmark.t.o $(OBJECTS) test.o
|
||||
g++ t.benchmark.t.o $(OBJECTS) test.o $(LFLAGS) -o t.benchmark.t
|
||||
|
||||
text.t: text.t.o $(OBJECTS) test.o
|
||||
g++ text.t.o $(OBJECTS) test.o $(LFLAGS) -o text.t
|
||||
|
||||
autocomplete.t: autocomplete.t.o $(OBJECTS) test.o
|
||||
g++ autocomplete.t.o $(OBJECTS) test.o $(LFLAGS) -o autocomplete.t
|
||||
|
||||
parse.t: parse.t.o $(OBJECTS) test.o
|
||||
g++ parse.t.o $(OBJECTS) test.o $(LFLAGS) -o parse.t
|
||||
|
||||
|
||||
74
src/tests/annotate.t
Executable file
74
src/tests/annotate.t
Executable file
@@ -0,0 +1,74 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 8;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'annotate.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"report.r.description=r\n",
|
||||
"report.r.columns=id,description\n",
|
||||
"report.r.sort=id+\n";
|
||||
close $fh;
|
||||
ok (-r 'annotate.rc', 'Created annotate.rc');
|
||||
}
|
||||
|
||||
# Add two tasks, annotate one twice.
|
||||
qx{../task rc:annotate.rc add one};
|
||||
qx{../task rc:annotate.rc add two};
|
||||
qx{../task rc:annotate.rc annotate 1 foo};
|
||||
sleep 2;
|
||||
qx{../task rc:annotate.rc annotate 1 bar};
|
||||
my $output = qx{../task rc:annotate.rc r};
|
||||
|
||||
# ID Description
|
||||
# -- -------------------------------
|
||||
# 1 one
|
||||
# 3/24/2009 foo
|
||||
# 3/24/2009 bar
|
||||
# 2 two
|
||||
#
|
||||
# 2 tasks
|
||||
like ($output, qr/1 one/, 'task 1');
|
||||
like ($output, qr/2 two/, 'task 2');
|
||||
like ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} foo/ms, 'first annotation');
|
||||
like ($output, qr/foo.+\d{1,2}\/\d{1,2}\/\d{4} bar/ms, 'second annotation');
|
||||
like ($output, qr/2 tasks/, 'count');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'annotate.rc';
|
||||
ok (!-r 'annotate.rc', 'Removed annotate.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
55
src/tests/append.t
Executable file
55
src/tests/append.t
Executable file
@@ -0,0 +1,55 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 4;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'append.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'append.rc', 'Created append.rc');
|
||||
}
|
||||
|
||||
# Add a task, then append more decsription.
|
||||
qx{../task rc:append.rc add foo};
|
||||
qx{../task rc:append.rc 1 append bar};
|
||||
my $output = qx{../task rc:append.rc info 1};
|
||||
like ($output, qr/Description\s+foo\sbar\n/, 'append worked');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'append.rc';
|
||||
ok (!-r 'append.rc', 'Removed append.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
63
src/tests/autocomplete.t.cpp
Normal file
63
src/tests/autocomplete.t.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// task - a command line task list manager.
|
||||
//
|
||||
// Copyright 2006 - 2009, 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
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include <iostream>
|
||||
#include <test.h>
|
||||
#include <../task.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (8);
|
||||
|
||||
std::vector <std::string> options;
|
||||
options.push_back ("abc");
|
||||
options.push_back ("abcd");
|
||||
options.push_back ("abcde");
|
||||
options.push_back ("bcdef");
|
||||
options.push_back ("cdefg");
|
||||
|
||||
std::vector <std::string> matches;
|
||||
int result = autoComplete ("", options, matches);
|
||||
t.is (result, 0, "no match on empty string");
|
||||
|
||||
result = autoComplete ("x", options, matches);
|
||||
t.is (result, 0, "no match on wrong string");
|
||||
|
||||
result = autoComplete ("abcd", options, matches);
|
||||
t.is (result, 1, "exact match on 'abcd'");
|
||||
t.is (matches[0], "abcd", "exact match on 'abcd'");
|
||||
|
||||
result = autoComplete ("ab", options, matches);
|
||||
t.is (result, 3, "partial match on 'ab'");
|
||||
t.is (matches[0], "abc", "partial match on 'abc'");
|
||||
t.is (matches[1], "abcd", "partial match on 'abcd'");
|
||||
t.is (matches[2], "abcde", "partial match on 'abcde'");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
79
src/tests/bug.annual.t
Executable file
79
src/tests/bug.annual.t
Executable file
@@ -0,0 +1,79 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 13;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'annual.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'annual.rc', 'Created annual.rc');
|
||||
}
|
||||
|
||||
# If a task is added with a due date ten years ago, with an annual recurrence,
|
||||
# then the synthetic tasks in between then and now have a due date that creeps.
|
||||
#
|
||||
# ID Project Pri Due Active Age Description
|
||||
# -- ------- --- ---------- ------ --- -----------
|
||||
# 2 1/1/2000 - foo
|
||||
# 3 12/31/2000 - foo
|
||||
# 4 12/31/2001 - foo
|
||||
# 5 12/31/2002 - foo
|
||||
# 6 12/31/2003 - foo
|
||||
# 7 12/30/2004 - foo
|
||||
# 8 12/30/2005 - foo
|
||||
# 9 12/30/2006 - foo
|
||||
# 10 12/30/2007 - foo
|
||||
# 11 12/29/2008 - foo
|
||||
# 12 12/29/2009 - foo
|
||||
|
||||
qx{../task rc:annual.rc add foo due:1/1/2000 recur:annual until:1/1/2009};
|
||||
my $output = qx{../task rc:annual.rc list};
|
||||
like ($output, qr/2\s+1\/1\/2000\s+- foo/, 'synthetic 1 no creep');
|
||||
like ($output, qr/3\s+1\/1\/2001\s+- foo/, 'synthetic 2 no creep');
|
||||
like ($output, qr/4\s+1\/1\/2002\s+- foo/, 'synthetic 3 no creep');
|
||||
like ($output, qr/5\s+1\/1\/2003\s+- foo/, 'synthetic 4 no creep');
|
||||
like ($output, qr/6\s+1\/1\/2004\s+- foo/, 'synthetic 5 no creep');
|
||||
like ($output, qr/7\s+1\/1\/2005\s+- foo/, 'synthetic 6 no creep');
|
||||
like ($output, qr/8\s+1\/1\/2006\s+- foo/, 'synthetic 7 no creep');
|
||||
like ($output, qr/9\s+1\/1\/2007\s+- foo/, 'synthetic 8 no creep');
|
||||
like ($output, qr/10\s+1\/1\/2008\s+- foo/, 'synthetic 9 no creep');
|
||||
like ($output, qr/11\s+1\/1\/2009\s+- foo/, 'synthetic 10 no creep');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'annual.rc';
|
||||
ok (!-r 'annual.rc', 'Removed annual.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 5;
|
||||
use Test::More tests => 6;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'bug_concat.rc')
|
||||
@@ -47,7 +47,6 @@ if (open my $fh, '>', 'bug_concat.rc')
|
||||
# Thisisanewdescription
|
||||
|
||||
qx{../task rc:bug_concat.rc add This is the original text};
|
||||
|
||||
my $output = qx{../task rc:bug_concat.rc info 1};
|
||||
like ($output, qr/Description\s+This is the original text\n/, 'original correct');
|
||||
|
||||
@@ -55,6 +54,18 @@ qx{../task rc:bug_concat.rc 1 This is the modified text};
|
||||
$output = qx{../task rc:bug_concat.rc info 1};
|
||||
like ($output, qr/Description\s+This is the modified text\n/, 'modified correct');
|
||||
|
||||
# When a task is added like this:
|
||||
#
|
||||
# % task add aaa bbb:ccc ddd
|
||||
#
|
||||
# The description is concatenated thus:
|
||||
#
|
||||
# aaabbb:ccc ddd
|
||||
|
||||
qx{../task rc:bug_concat.rc add aaa bbb:ccc ddd};
|
||||
$output = qx{../task rc:bug_concat.rc info 2};
|
||||
like ($output, qr/Description\s+aaa bbb:ccc ddd\n/, 'properly concatenated');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
109
src/tests/confirmation.t
Executable file
109
src/tests/confirmation.t
Executable file
@@ -0,0 +1,109 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 26;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'confirm.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"confirmation=yes\n";
|
||||
close $fh;
|
||||
ok (-r 'confirm.rc', 'Created confirm.rc');
|
||||
}
|
||||
|
||||
# Create the response file.
|
||||
if (open my $fh, '>', 'response.txt')
|
||||
{
|
||||
print $fh "\n\nn\n";
|
||||
close $fh;
|
||||
ok (-r 'response.txt', 'Created response.txt');
|
||||
}
|
||||
|
||||
qx{../task rc:confirm.rc add foo} for 1 .. 10;
|
||||
|
||||
# Test the various forms of "yes".
|
||||
my $output = qx{echo "yes" | ../task rc:confirm.rc del 1};
|
||||
like ($output, qr/Permanently delete task 1 'foo'\? \(y\/n\)/, 'confirmation - yes works');
|
||||
unlike ($output, qr/Task not deleted\./, 'confirmation - yes works');
|
||||
|
||||
$output = qx{echo "ye" | ../task rc:confirm.rc del 2};
|
||||
like ($output, qr/Permanently delete task 2 'foo'\? \(y\/n\)/, 'confirmation - ye works');
|
||||
unlike ($output, qr/Task not deleted\./, 'confirmation - ye works');
|
||||
|
||||
$output = qx{echo "y" | ../task rc:confirm.rc del 3};
|
||||
like ($output, qr/Permanently delete task 3 'foo'\? \(y\/n\)/, 'confirmation - y works');
|
||||
unlike ($output, qr/Task not deleted\./, 'confirmation - y works');
|
||||
|
||||
$output = qx{echo "YES" | ../task rc:confirm.rc del 4};
|
||||
like ($output, qr/Permanently delete task 4 'foo'\? \(y\/n\)/, 'confirmation - YES works');
|
||||
unlike ($output, qr/Task not deleted\./, 'confirmation - YES works');
|
||||
|
||||
$output = qx{echo "YE" | ../task rc:confirm.rc del 5};
|
||||
like ($output, qr/Permanently delete task 5 'foo'\? \(y\/n\)/, 'confirmation - YE works');
|
||||
unlike ($output, qr/Task not deleted\./, 'confirmation - YE works');
|
||||
|
||||
$output = qx{echo "Y" | ../task rc:confirm.rc del 6};
|
||||
like ($output, qr/Permanently delete task 6 'foo'\? \(y\/n\)/, 'confirmation - Y works');
|
||||
unlike ($output, qr/Task not deleted\./, 'confirmation - Y works');
|
||||
|
||||
# Test the various forms of "no".
|
||||
$output = qx{echo "no" | ../task rc:confirm.rc del 7};
|
||||
like ($output, qr/Permanently delete task 7 'foo'\? \(y\/n\)/, 'confirmation - no works');
|
||||
like ($output, qr/Task not deleted\./, 'confirmation - no works');
|
||||
|
||||
$output = qx{echo "n" | ../task rc:confirm.rc del 7};
|
||||
like ($output, qr/Permanently delete task 7 'foo'\? \(y\/n\)/, 'confirmation - n works');
|
||||
like ($output, qr/Task not deleted\./, 'confirmation - n works');
|
||||
|
||||
$output = qx{echo "NO" | ../task rc:confirm.rc del 7};
|
||||
like ($output, qr/Permanently delete task 7 'foo'\? \(y\/n\)/, 'confirmation - NO works');
|
||||
like ($output, qr/Task not deleted\./, 'confirmation - NO works');
|
||||
|
||||
$output = qx{echo "N" | ../task rc:confirm.rc del 7};
|
||||
like ($output, qr/Permanently delete task 7 'foo'\? \(y\/n\)/, 'confirmation - N works');
|
||||
like ($output, qr/Task not deleted\./, 'confirmation - N works');
|
||||
|
||||
# Test newlines.
|
||||
$output = qx{cat response.txt | ../task rc:confirm.rc del 7};
|
||||
like ($output, qr/(Permanently delete task 7 'foo'\? \(y\/n\)) \1 \1/, 'confirmation - \n re-prompt works');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'response.txt';
|
||||
ok (!-r 'response.txt', 'Removed response.txt');
|
||||
|
||||
unlink 'confirm.rc';
|
||||
ok (!-r 'confirm.rc', 'Removed confirm.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
61
src/tests/custom.recur_ind.t
Executable file
61
src/tests/custom.recur_ind.t
Executable file
@@ -0,0 +1,61 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 6;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'custom.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"report.foo.description=DESC\n",
|
||||
"report.foo.columns=id,recurrence_indicator\n",
|
||||
"report.foo.labels=ID,R\n",
|
||||
"report.foo.sort=id+\n";
|
||||
close $fh;
|
||||
ok (-r 'custom.rc', 'Created custom.rc');
|
||||
}
|
||||
|
||||
# Generate the usage screen, and locate the custom report on it.
|
||||
qx{../task rc:custom.rc add foo due:tomorrow recur:weekly};
|
||||
qx{../task rc:custom.rc add bar};
|
||||
my $output = qx{../task rc:custom.rc foo 2>&1};
|
||||
like ($output, qr/ID R/, 'Recurrence indicator heading');
|
||||
like ($output, qr/3\s+R/, 'Recurrence indicator t1');
|
||||
unlike ($output, qr/2\s+R/, 'No recurrence indicator t2');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'custom.rc';
|
||||
ok (!-r 'custom.rc', 'Removed custom.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
61
src/tests/custom.tag_ind.t
Executable file
61
src/tests/custom.tag_ind.t
Executable file
@@ -0,0 +1,61 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 6;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'custom.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"report.foo.description=DESC\n",
|
||||
"report.foo.columns=id,tag_indicator\n",
|
||||
"report.foo.labels=ID,T\n",
|
||||
"report.foo.sort=id+\n";
|
||||
close $fh;
|
||||
ok (-r 'custom.rc', 'Created custom.rc');
|
||||
}
|
||||
|
||||
# Generate the usage screen, and locate the custom report on it.
|
||||
qx{../task rc:custom.rc add foo +tag};
|
||||
qx{../task rc:custom.rc add bar};
|
||||
my $output = qx{../task rc:custom.rc foo 2>&1};
|
||||
like ($output, qr/ID T/, 'Tag indicator heading');
|
||||
like ($output, qr/1\s+\+/, 'Tag indicator t1');
|
||||
unlike ($output, qr/2\s+\+/, 'No tag indicator t2');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'custom.rc';
|
||||
ok (!-r 'custom.rc', 'Removed custom.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
@@ -33,7 +33,8 @@ use Test::More tests => 16;
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'undelete.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
print $fh "data.location=.\n",
|
||||
"echo.command=no\n";
|
||||
close $fh;
|
||||
ok (-r 'undelete.rc', 'Created undelete.rc');
|
||||
}
|
||||
@@ -56,7 +57,7 @@ like ($output, qr/^No matches/, 'No matches');
|
||||
ok (-r 'completed.data', 'completed.data created');
|
||||
|
||||
$output = qx{../task rc:undelete.rc undelete 1};
|
||||
like ($output, qr/reliably undeleted/, 'can only be reliable undeleted...');
|
||||
like ($output, qr/Task 1 not found/, 'Task 1 not found');
|
||||
|
||||
$output = qx{../task rc:undelete.rc info 1};
|
||||
like ($output, qr/No matches./, 'no matches');
|
||||
|
||||
@@ -37,17 +37,18 @@ if (open my $fh, '>', 'due.rc')
|
||||
"due=4\n",
|
||||
"color=on\n",
|
||||
"color.due=red\n",
|
||||
"_forcecolor=on\n";
|
||||
"_forcecolor=on\n",
|
||||
"dateformat=m/d/Y\n";
|
||||
close $fh;
|
||||
ok (-r 'due.rc', 'Created due.rc');
|
||||
}
|
||||
|
||||
# Add a task that is almost due, and one that is just due.
|
||||
my ($d, $m, $y) = (localtime (time + 3 * 86_400))[3..5];
|
||||
my $just = sprintf ("%d/%02d/%d", $m + 1, $d, $y + 1900);
|
||||
my $just = sprintf ("%d/%d/%d", $m + 1, $d, $y + 1900);
|
||||
|
||||
($d, $m, $y) = (localtime (time + 5 * 86_400))[3..5];
|
||||
my $almost = sprintf ("%d/%02d/%d", $m + 1, $d, $y + 1900);
|
||||
my $almost = sprintf ("%d/%d/%d", $m + 1, $d, $y + 1900);
|
||||
|
||||
qx{../task rc:due.rc add one due:$just};
|
||||
qx{../task rc:due.rc add two due:$almost};
|
||||
|
||||
66
src/tests/duplicate.t
Executable file
66
src/tests/duplicate.t
Executable file
@@ -0,0 +1,66 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 11;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'dup.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'dup.rc', 'Created dup.rc');
|
||||
}
|
||||
|
||||
# Test the duplicate command.
|
||||
qx{../task rc:dup.rc add foo};
|
||||
qx{../task rc:dup.rc duplicate 1};
|
||||
my $output = qx{../task rc:dup.rc info 2};
|
||||
like ($output, qr/ID\s+2/, 'duplicate new id');
|
||||
like ($output, qr/Status\s+Pending/, 'duplicate same status');
|
||||
like ($output, qr/Description\s+foo/, 'duplicate same description');
|
||||
|
||||
# Test the en passant modification while duplicating.
|
||||
qx{../task rc:dup.rc duplicate 1 priority:H /foo/FOO/ +tag};
|
||||
$output = qx{../task rc:dup.rc info 3};
|
||||
like ($output, qr/ID\s+3/, 'duplicate new id');
|
||||
like ($output, qr/Status\s+Pending/, 'duplicate same status');
|
||||
like ($output, qr/Description\s+FOO/, 'duplicate modified description');
|
||||
like ($output, qr/Priority\s+H/, 'duplicate added priority');
|
||||
like ($output, qr/Tags\s+tag/, 'duplicate added tag');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'dup.rc';
|
||||
ok (!-r 'dup.rc', 'Removed dup.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
@@ -42,6 +42,7 @@ int main (int argc, char** argv)
|
||||
|
||||
std::string d;
|
||||
d = "daily"; t.is (convertDuration (d), 1, "duration daily = 1");
|
||||
d = "weekdays"; t.is (convertDuration (d), 1, "duration weekdays = 1");
|
||||
d = "day"; t.is (convertDuration (d), 1, "duration day = 1");
|
||||
d = "0d"; t.is (convertDuration (d), 0, "duration 0d = 0");
|
||||
d = "1d"; t.is (convertDuration (d), 1, "duration 1d = 1");
|
||||
@@ -53,7 +54,6 @@ int main (int argc, char** argv)
|
||||
d = "sennight"; t.is (convertDuration (d), 7, "duration sennight = 7");
|
||||
d = "biweekly"; t.is (convertDuration (d), 14, "duration biweekly = 14");
|
||||
d = "fortnight"; t.is (convertDuration (d), 14, "duration fortnight = 14");
|
||||
d = "week"; t.is (convertDuration (d), 7, "duration week = 7");
|
||||
d = "0w"; t.is (convertDuration (d), 0, "duration 0w = 0");
|
||||
d = "1w"; t.is (convertDuration (d), 7, "duration 1w = 7");
|
||||
d = "7w"; t.is (convertDuration (d), 49, "duration 7w = 49");
|
||||
|
||||
64
src/tests/enpassant.t
Executable file
64
src/tests/enpassant.t
Executable file
@@ -0,0 +1,64 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 11;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'enp.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'enp.rc', 'Created enp.rc');
|
||||
}
|
||||
|
||||
# Test the en passant feature.
|
||||
qx{../task rc:enp.rc add foo};
|
||||
qx{../task rc:enp.rc add foo bar};
|
||||
qx{../task rc:enp.rc do 1,2 /foo/FOO/ pri:H +tag};
|
||||
my $output = qx{../task rc:enp.rc info 1};
|
||||
like ($output, qr/Status\s+Completed/, 'en passant 1 status change');
|
||||
like ($output, qr/Description\s+FOO/, 'en passant 1 description change');
|
||||
like ($output, qr/Priority\s+H/, 'en passant 1 description change');
|
||||
like ($output, qr/Tags\s+tag/, 'en passant 1 description change');
|
||||
$output = qx{../task rc:enp.rc info 2};
|
||||
like ($output, qr/Status\s+Completed/, 'en passant 2 status change');
|
||||
like ($output, qr/Description\s+FOO bar/, 'en passant 2 description change');
|
||||
like ($output, qr/Priority\s+H/, 'en passant 2 description change');
|
||||
like ($output, qr/Tags\s+tag/, 'en passant 2 description change');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'enp.rc';
|
||||
ok (!-r 'enp.rc', 'Removed enp.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
70
src/tests/import.143.t
Executable file
70
src/tests/import.143.t
Executable file
@@ -0,0 +1,70 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 8;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'import.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'import.rc', 'Created import.rc');
|
||||
}
|
||||
|
||||
# Create import file.
|
||||
if (open my $fh, '>', 'import.txt')
|
||||
{
|
||||
print $fh "'id','status','tags','entry','start','due','end','project','priority','fg','bg','description'\n",
|
||||
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,'A','M',,,'foo bar'\n",
|
||||
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,'A','M',,,'foo, bar'\n",
|
||||
"\n";
|
||||
close $fh;
|
||||
ok (-r 'import.txt', 'Created sample import data');
|
||||
}
|
||||
|
||||
my $output = qx{../task rc:import.rc import import.txt};
|
||||
is ($output, "Imported 2 tasks successfully, with 0 errors.\n", 'no errors');
|
||||
|
||||
$output = qx{../task rc:import.rc list};
|
||||
like ($output, qr/1.+A.+M.+foo bar/, 't1');
|
||||
like ($output, qr/2.+A.+M.+foo, bar/, 't2');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'import.txt';
|
||||
ok (!-r 'import.txt', 'Removed import.txt');
|
||||
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'import.rc';
|
||||
ok (!-r 'import.rc', 'Removed import.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
70
src/tests/import.150.t
Executable file
70
src/tests/import.150.t
Executable file
@@ -0,0 +1,70 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 8;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'import.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'import.rc', 'Created import.rc');
|
||||
}
|
||||
|
||||
# Create import file.
|
||||
if (open my $fh, '>', 'import.txt')
|
||||
{
|
||||
print $fh "'id','uuid','status','tags','entry','start','due','recur','end','project','priority','fg','bg','description'\n",
|
||||
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,,'A','M',,,'foo bar'\n",
|
||||
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,,'A','M',,,'foo, bar'\n",
|
||||
"\n";
|
||||
close $fh;
|
||||
ok (-r 'import.txt', 'Created sample import data');
|
||||
}
|
||||
|
||||
my $output = qx{../task rc:import.rc import import.txt};
|
||||
is ($output, "Imported 2 tasks successfully, with 0 errors.\n", 'no errors');
|
||||
|
||||
$output = qx{../task rc:import.rc list};
|
||||
like ($output, qr/1.+A.+M.+foo bar/, 't1');
|
||||
like ($output, qr/2.+A.+M.+foo, bar/, 't2');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'import.txt';
|
||||
ok (!-r 'import.txt', 'Removed import.txt');
|
||||
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'import.rc';
|
||||
ok (!-r 'import.rc', 'Removed import.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
70
src/tests/import.160.t
Executable file
70
src/tests/import.160.t
Executable file
@@ -0,0 +1,70 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 8;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'import.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'import.rc', 'Created import.rc');
|
||||
}
|
||||
|
||||
# Create import file.
|
||||
if (open my $fh, '>', 'import.txt')
|
||||
{
|
||||
print $fh "'uuid','status','tags','entry','start','due','recur','end','project','priority','fg','bg','description'\n",
|
||||
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,,'A','M',,,'foo bar'\n",
|
||||
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,,'A','M',,,'foo, bar'\n",
|
||||
"\n";
|
||||
close $fh;
|
||||
ok (-r 'import.txt', 'Created sample import data');
|
||||
}
|
||||
|
||||
my $output = qx{../task rc:import.rc import import.txt};
|
||||
is ($output, "Imported 2 tasks successfully, with 0 errors.\n", 'no errors');
|
||||
|
||||
$output = qx{../task rc:import.rc list};
|
||||
like ($output, qr/1.+A.+M.+foo bar/, 't1');
|
||||
like ($output, qr/2.+A.+M.+foo, bar/, 't2');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'import.txt';
|
||||
ok (!-r 'import.txt', 'Removed import.txt');
|
||||
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'import.rc';
|
||||
ok (!-r 'import.rc', 'Removed import.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
69
src/tests/import.cmd.t
Executable file
69
src/tests/import.cmd.t
Executable file
@@ -0,0 +1,69 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 8;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'import.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'import.rc', 'Created import.rc');
|
||||
}
|
||||
|
||||
# Create import file.
|
||||
if (open my $fh, '>', 'import.txt')
|
||||
{
|
||||
print $fh "This is a test priority:H project:A\n",
|
||||
"Another task\n",
|
||||
"\n";
|
||||
close $fh;
|
||||
ok (-r 'import.txt', 'Created sample import data');
|
||||
}
|
||||
|
||||
my $output = qx{../task rc:import.rc import import.txt};
|
||||
is ($output, "Imported 2 tasks successfully, with 0 errors.\n", 'no errors');
|
||||
|
||||
$output = qx{../task rc:import.rc list};
|
||||
like ($output, qr/1.+A.+H.+This is a test/, 't1');
|
||||
like ($output, qr/2.+Another task/, 't2');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'import.txt';
|
||||
ok (!-r 'import.txt', 'Removed import.txt');
|
||||
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'import.rc';
|
||||
ok (!-r 'import.rc', 'Removed import.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
70
src/tests/import.csv.t
Executable file
70
src/tests/import.csv.t
Executable file
@@ -0,0 +1,70 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 8;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'import.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'import.rc', 'Created import.rc');
|
||||
}
|
||||
|
||||
# Create import file.
|
||||
if (open my $fh, '>', 'import.txt')
|
||||
{
|
||||
print $fh "'id','priority','description'\n",
|
||||
"1,H,'this is a test'\n",
|
||||
"2,,'another task'\n",
|
||||
"\n";
|
||||
close $fh;
|
||||
ok (-r 'import.txt', 'Created sample import data');
|
||||
}
|
||||
|
||||
my $output = qx{../task rc:import.rc import import.txt};
|
||||
is ($output, "Imported 2 tasks successfully, with 0 errors.\n", 'no errors');
|
||||
|
||||
$output = qx{../task rc:import.rc list};
|
||||
like ($output, qr/1.+H.+this is a test/, 't1');
|
||||
like ($output, qr/2.+another task/, 't2');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'import.txt';
|
||||
ok (!-r 'import.txt', 'Removed import.txt');
|
||||
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'import.rc';
|
||||
ok (!-r 'import.rc', 'Removed import.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
76
src/tests/import.todo.t
Executable file
76
src/tests/import.todo.t
Executable file
@@ -0,0 +1,76 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 10;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'import.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'import.rc', 'Created import.rc');
|
||||
}
|
||||
|
||||
# Create import file.
|
||||
if (open my $fh, '>', 'import.txt')
|
||||
{
|
||||
print $fh "x 2009-03-25 Walk the dog +project \@context\n",
|
||||
"This is a test +project \@context\n",
|
||||
"(A) A prioritized task\n",
|
||||
"\n";
|
||||
close $fh;
|
||||
ok (-r 'import.txt', 'Created sample import data');
|
||||
}
|
||||
|
||||
my $output = qx{../task rc:import.rc import import.txt};
|
||||
is ($output, "Imported 3 tasks successfully, with 0 errors.\n", 'no errors');
|
||||
|
||||
$output = qx{../task rc:import.rc list};
|
||||
like ($output, qr/1.+project.+This is a test/, 't1');
|
||||
like ($output, qr/2.+H.+A prioritized task/, 't2');
|
||||
|
||||
$output = qx{../task rc:import.rc completed};
|
||||
like ($output, qr/3\/25\/2009.+Walk the dog/, 't3');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'import.txt';
|
||||
ok (!-r 'import.txt', 'Removed import.txt');
|
||||
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'completed.data';
|
||||
ok (!-r 'completed.data', 'Removed completed.data');
|
||||
|
||||
unlink 'import.rc';
|
||||
ok (!-r 'import.rc', 'Removed import.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
71
src/tests/import.txt.t
Executable file
71
src/tests/import.txt.t
Executable file
@@ -0,0 +1,71 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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, '>', 'import.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'import.rc', 'Created import.rc');
|
||||
}
|
||||
|
||||
# Create import file.
|
||||
if (open my $fh, '>', 'import.txt')
|
||||
{
|
||||
print $fh "Get milk, bread\n",
|
||||
"Order cake\n",
|
||||
"Clean house\n",
|
||||
"\n";
|
||||
close $fh;
|
||||
ok (-r 'import.txt', 'Created sample import data');
|
||||
}
|
||||
|
||||
my $output = qx{../task rc:import.rc import import.txt};
|
||||
is ($output, "Imported 3 tasks successfully, with 0 errors.\n", 'no errors');
|
||||
|
||||
$output = qx{../task rc:import.rc list};
|
||||
like ($output, qr/1.+Get milk, bread/, 't1');
|
||||
like ($output, qr/2.+Order cake/, 't2');
|
||||
like ($output, qr/3.+Clean house/, 't3');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'import.txt';
|
||||
ok (!-r 'import.txt', 'Removed import.txt');
|
||||
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'import.rc';
|
||||
ok (!-r 'import.rc', 'Removed import.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
66
src/tests/label.t
Executable file
66
src/tests/label.t
Executable file
@@ -0,0 +1,66 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 8;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'custom.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"report.foo.description=DESC\n",
|
||||
"report.foo.labels=ID,DESCRIPTION\n",
|
||||
"report.foo.columns=id,description\n",
|
||||
"report.foo.sort=id+\n",
|
||||
"report.foo.filter=project:A\n";
|
||||
close $fh;
|
||||
ok (-r 'custom.rc', 'Created custom.rc');
|
||||
}
|
||||
|
||||
# Generate the usage screen, and locate the custom report on it.
|
||||
my $output = qx{../task rc:custom.rc usage};
|
||||
like ($output, qr/task foo \[tags\] \[attrs\] desc\.\.\.\s+DESC\n/m, 'report.foo');
|
||||
|
||||
qx{../task rc:custom.rc add project:A one};
|
||||
qx{../task rc:custom.rc add two};
|
||||
$output = qx{../task rc:custom.rc foo};
|
||||
like ($output, qr/ID/, 'custom label for id column');
|
||||
like ($output, qr/DESCRIPTION/, 'custom label for description column');
|
||||
like ($output, qr/one/, 'custom filter included');
|
||||
unlike ($output, qr/two/, 'custom filter excluded');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'custom.rc';
|
||||
ok (!-r 'custom.rc', 'Removed custom.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
@@ -47,12 +47,12 @@ my $setup = "../task rc:nag.rc add due:yesterday one;"
|
||||
. "../task rc:nag.rc add six;";
|
||||
qx{$setup};
|
||||
|
||||
like (qx{../task rc:nag.rc do 6}, qr/NAG/, 'do pri: -> nag');
|
||||
like (qx{../task rc:nag.rc do 5}, qr/NAG/, 'do pri:L -> nag');
|
||||
like (qx{../task rc:nag.rc do 4}, qr/NAG/, 'do pri:M-> nag');
|
||||
like (qx{../task rc:nag.rc do 3}, qr/NAG/, 'do pri:H-> nag');
|
||||
like (qx{../task rc:nag.rc do 2}, qr/NAG/, 'do due:tomorrow -> nag');
|
||||
ok (qx{../task rc:nag.rc do 1} !~ qr/NAG/, 'do due:yesterday -> no nag');
|
||||
like (qx{../task rc:nag.rc do 6}, qr/NAG/, 'do pri: -> nag');
|
||||
like (qx{../task rc:nag.rc do 5}, qr/NAG/, 'do pri:L -> nag');
|
||||
like (qx{../task rc:nag.rc do 4}, qr/NAG/, 'do pri:M-> nag');
|
||||
like (qx{../task rc:nag.rc do 3}, qr/NAG/, 'do pri:H-> nag');
|
||||
like (qx{../task rc:nag.rc do 2}, qr/NAG/, 'do due:tomorrow -> nag');
|
||||
unlike (qx{../task rc:nag.rc do 1}, qr/NAG/, 'do due:yesterday -> no nag');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 25;
|
||||
use Test::More tests => 55;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'oldest.rc')
|
||||
@@ -39,10 +39,23 @@ if (open my $fh, '>', 'oldest.rc')
|
||||
}
|
||||
|
||||
# Add 11 tasks. Oldest should show 1-10, newest should show 2-11.
|
||||
diag ("Adding 11 tasks - takes 10 seconds");
|
||||
diag ("Adding 3 tasks - takes 2 seconds");
|
||||
qx{../task rc:oldest.rc add one; sleep 1};
|
||||
qx{../task rc:oldest.rc add two; sleep 1};
|
||||
qx{../task rc:oldest.rc add three; sleep 1};
|
||||
my $output = qx{../task rc:oldest.rc oldest};
|
||||
like ($output, qr/one/, 'oldest: one');
|
||||
like ($output, qr/two/, 'oldest: two');
|
||||
like ($output, qr/three/, 'oldest: three');
|
||||
like ($output, qr/one.*two.*three/ms, 'oldest: sort');
|
||||
|
||||
$output = qx{../task rc:oldest.rc newest};
|
||||
like ($output, qr/three/, 'newest: three');
|
||||
like ($output, qr/two/, 'newest: two');
|
||||
like ($output, qr/one/, 'newest: one');
|
||||
like ($output, qr/three.*two.*one/ms, 'newest: sort');
|
||||
|
||||
diag ("Adding 8 tasks - takes 7 seconds");
|
||||
qx{../task rc:oldest.rc add four; sleep 1};
|
||||
qx{../task rc:oldest.rc add five; sleep 1};
|
||||
qx{../task rc:oldest.rc add six; sleep 1};
|
||||
@@ -52,31 +65,57 @@ qx{../task rc:oldest.rc add nine; sleep 1};
|
||||
qx{../task rc:oldest.rc add ten; sleep 1};
|
||||
qx{../task rc:oldest.rc add eleven};
|
||||
|
||||
my $output = qx{../task rc:oldest.rc oldest};
|
||||
like ($output, qr/one/, 'oldest: one');
|
||||
like ($output, qr/two/, 'oldest: two');
|
||||
like ($output, qr/three/, 'oldest: three');
|
||||
like ($output, qr/four/, 'oldest: four');
|
||||
like ($output, qr/five/, 'oldest: five');
|
||||
like ($output, qr/six/, 'oldest: six');
|
||||
like ($output, qr/seven/, 'oldest: seven');
|
||||
like ($output, qr/eight/, 'oldest: eight');
|
||||
like ($output, qr/nine/, 'oldest: nine');
|
||||
like ($output, qr/ten/, 'oldest: ten');
|
||||
$output = qx{../task rc:oldest.rc oldest};
|
||||
like ($output, qr/one/, 'oldest: one');
|
||||
like ($output, qr/two/, 'oldest: two');
|
||||
like ($output, qr/three/, 'oldest: three');
|
||||
like ($output, qr/four/, 'oldest: four');
|
||||
like ($output, qr/five/, 'oldest: five');
|
||||
like ($output, qr/six/, 'oldest: six');
|
||||
like ($output, qr/seven/, 'oldest: seven');
|
||||
like ($output, qr/eight/, 'oldest: eight');
|
||||
like ($output, qr/nine/, 'oldest: nine');
|
||||
like ($output, qr/ten/, 'oldest: ten');
|
||||
unlike ($output, qr/eleven/, 'no: eleven');
|
||||
|
||||
$output = qx{../task rc:oldest.rc oldest 3};
|
||||
like ($output, qr/one/, 'oldest: one');
|
||||
like ($output, qr/two/, 'oldest: two');
|
||||
like ($output, qr/three/, 'oldest: three');
|
||||
unlike ($output, qr/four/, 'no: four');
|
||||
unlike ($output, qr/five/, 'no: five');
|
||||
unlike ($output, qr/six/, 'no: six');
|
||||
unlike ($output, qr/seven/, 'no: seven');
|
||||
unlike ($output, qr/eight/, 'no: eight');
|
||||
unlike ($output, qr/nine/, 'no: nine');
|
||||
unlike ($output, qr/ten/, 'no: ten');
|
||||
unlike ($output, qr/eleven/, 'no: eleven');
|
||||
|
||||
$output = qx{../task rc:oldest.rc newest};
|
||||
unlike ($output, qr/one/, 'no: one');
|
||||
like ($output, qr/two/, 'newest: two');
|
||||
like ($output, qr/three/, 'newest: three');
|
||||
like ($output, qr/four/, 'newest: four');
|
||||
like ($output, qr/five/, 'newest: five');
|
||||
like ($output, qr/six/, 'newest: six');
|
||||
like ($output, qr/seven/, 'newest: seven');
|
||||
like ($output, qr/eight/, 'newest: eight');
|
||||
like ($output, qr/nine/, 'newest: nine');
|
||||
like ($output, qr/ten/, 'newest: ten');
|
||||
like ($output, qr/eleven/, 'newest: eleven');
|
||||
unlike ($output, qr/one/, 'no: one');
|
||||
like ($output, qr/two/, 'newest: two');
|
||||
like ($output, qr/three/, 'newest: three');
|
||||
like ($output, qr/four/, 'newest: four');
|
||||
like ($output, qr/five/, 'newest: five');
|
||||
like ($output, qr/six/, 'newest: six');
|
||||
like ($output, qr/seven/, 'newest: seven');
|
||||
like ($output, qr/eight/, 'newest: eight');
|
||||
like ($output, qr/nine/, 'newest: nine');
|
||||
like ($output, qr/ten/, 'newest: ten');
|
||||
like ($output, qr/eleven/, 'newest: eleven');
|
||||
|
||||
$output = qx{../task rc:oldest.rc newest 3};
|
||||
unlike ($output, qr/one/, 'no: one');
|
||||
unlike ($output, qr/two/, 'no: two');
|
||||
unlike ($output, qr/three/, 'no: three');
|
||||
unlike ($output, qr/four/, 'no: four');
|
||||
unlike ($output, qr/five/, 'no: five');
|
||||
unlike ($output, qr/six/, 'no: six');
|
||||
unlike ($output, qr/seven/, 'no: seven');
|
||||
unlike ($output, qr/eight/, 'no: eight');
|
||||
like ($output, qr/nine/, 'newest: nine');
|
||||
like ($output, qr/ten/, 'newest: ten');
|
||||
like ($output, qr/eleven/, 'newest: eleven');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
|
||||
134
src/tests/parse.t.cpp
Normal file
134
src/tests/parse.t.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// task - a command line task list manager.
|
||||
//
|
||||
// Copyright 2006 - 2009, 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
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include <iostream>
|
||||
#include "task.h"
|
||||
#include "test.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (18);
|
||||
|
||||
std::vector <std::string> args;
|
||||
std::string command;
|
||||
|
||||
Config conf;
|
||||
conf.set ("dateformat", "m/d/Y");
|
||||
|
||||
{
|
||||
T task;
|
||||
split (args, "add foo", ' ');
|
||||
parse (args, command, task, conf);
|
||||
t.is (command, "add", "(1) command found");
|
||||
t.is (task.getId (), 0, "(1) zero id on add");
|
||||
t.is (task.getDescription (), "foo", "(1) correct description");
|
||||
}
|
||||
|
||||
{
|
||||
T task;
|
||||
split (args, "delete 1,3-5,7", ' ');
|
||||
parse (args, command, task, conf);
|
||||
std::vector <int> sequence = task.getAllIds ();
|
||||
t.is (sequence.size (), (size_t)5, "(2) sequence length");
|
||||
if (sequence.size () == 5)
|
||||
{
|
||||
t.is (sequence[0], 1, "(2) sequence[0] == 1");
|
||||
t.is (sequence[1], 3, "(2) sequence[1] == 3");
|
||||
t.is (sequence[2], 4, "(2) sequence[2] == 4");
|
||||
t.is (sequence[3], 5, "(2) sequence[3] == 5");
|
||||
t.is (sequence[4], 7, "(2) sequence[4] == 7");
|
||||
}
|
||||
else
|
||||
{
|
||||
t.fail ("(2) sequence[0] == 1");
|
||||
t.fail ("(2) sequence[1] == 3");
|
||||
t.fail ("(2) sequence[2] == 4");
|
||||
t.fail ("(2) sequence[3] == 5");
|
||||
t.fail ("(2) sequence[4] == 7");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
T task;
|
||||
split (args, "delete 1,2 3,4", ' ');
|
||||
parse (args, command, task, conf);
|
||||
std::vector <int> sequence = task.getAllIds ();
|
||||
t.is (sequence.size (), (size_t)4, "(3) sequence length");
|
||||
if (sequence.size () == 4)
|
||||
{
|
||||
t.is (sequence[0], 1, "(3) sequence[0] == 1");
|
||||
t.is (sequence[1], 2, "(3) sequence[1] == 2");
|
||||
t.is (sequence[2], 3, "(3) sequence[2] == 3");
|
||||
t.is (sequence[3], 4, "(3) sequence[3] == 4");
|
||||
}
|
||||
else
|
||||
{
|
||||
t.fail ("(3) sequence[0] == 1");
|
||||
t.fail ("(3) sequence[1] == 2");
|
||||
t.fail ("(3) sequence[2] == 3");
|
||||
t.fail ("(3) sequence[3] == 4");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
T task;
|
||||
split (args, "1 There are 7 days in a week", ' ');
|
||||
parse (args, command, task, conf);
|
||||
std::vector <int> sequence = task.getAllIds ();
|
||||
t.is (sequence.size (), (size_t)1, "(4) sequence length");
|
||||
if (sequence.size () == 1)
|
||||
{
|
||||
t.is (sequence[0], 1, "(4) sequence[0] == 1");
|
||||
}
|
||||
else
|
||||
{
|
||||
t.fail ("(4) sequence[0] == 1");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
T task;
|
||||
args.clear ();
|
||||
args.push_back ("1");
|
||||
args.push_back ("4-123 is back-ordered");
|
||||
parse (args, command, task, conf);
|
||||
std::vector <int> sequence = task.getAllIds ();
|
||||
t.is (sequence.size (), (size_t)1, "(5) sequence length");
|
||||
if (sequence.size () == 1)
|
||||
{
|
||||
t.is (sequence[0], 1, "(5) sequence[0] == 1");
|
||||
}
|
||||
else
|
||||
{
|
||||
t.fail ("(5) sequence[0] == 1");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 6;
|
||||
use Test::More tests => 5;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'recur.rc')
|
||||
@@ -54,9 +54,6 @@ $output = qx{../task rc:recur.rc desc};
|
||||
like ($output, qr/second .* third .* first/msx, 'weekly 3d daily');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'shadow.txt';
|
||||
ok (!-r 'shadow.txt', 'Removed shadow.txt');
|
||||
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
|
||||
64
src/tests/recur.weekdays.t
Executable file
64
src/tests/recur.weekdays.t
Executable file
@@ -0,0 +1,64 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 7;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'recur.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'recur.rc', 'Created recur.rc');
|
||||
}
|
||||
|
||||
# Create a few recurring tasks, and test the sort order of the recur column.
|
||||
qx{../task rc:recur.rc add due:friday recur:weekdays one};
|
||||
my $output = qx{../task rc:recur.rc list};
|
||||
like ($output, qr/one/, 'recur weekdays');
|
||||
|
||||
$output = qx{../task rc:recur.rc info 1};
|
||||
like ($output, qr/Status\s+Recurring/, 'task is recurring');
|
||||
like ($output, qr/Recurrence\s+weekdays/, 'task recurs every weekday');
|
||||
|
||||
qx{../task rc:recur.rc do 1};
|
||||
$output = qx{../task rc:recur.rc list};
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'completed.data';
|
||||
ok (!-r 'completed.data', 'Removed completed.data');
|
||||
|
||||
unlink 'recur.rc';
|
||||
ok (!-r 'recur.rc', 'Removed recur.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
125
src/tests/sequence.t
Executable file
125
src/tests/sequence.t
Executable file
@@ -0,0 +1,125 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 27;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'seq.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'seq.rc', 'Created seq.rc');
|
||||
}
|
||||
|
||||
# Test sequences in done/undo
|
||||
qx{../task rc:seq.rc add one mississippi};
|
||||
qx{../task rc:seq.rc add two mississippi};
|
||||
qx{../task rc:seq.rc do 1,2};
|
||||
my $output = qx{../task rc:seq.rc info 1};
|
||||
like ($output, qr/Status\s+Completed/, 'sequence do 1');
|
||||
$output = qx{../task rc:seq.rc info 2};
|
||||
like ($output, qr/Status\s+Completed/, 'sequence do 2');
|
||||
qx{../task rc:seq.rc undo 1,2};
|
||||
$output = qx{../task rc:seq.rc info 1};
|
||||
like ($output, qr/Status\s+Pending/, 'sequence undo 1');
|
||||
$output = qx{../task rc:seq.rc info 2};
|
||||
like ($output, qr/Status\s+Pending/, 'sequence undo 2');
|
||||
|
||||
# Test sequences in delete/undelete
|
||||
qx{../task rc:seq.rc delete 1,2};
|
||||
$output = qx{../task rc:seq.rc info 1};
|
||||
like ($output, qr/Status\s+Deleted/, 'sequence delete 1');
|
||||
$output = qx{../task rc:seq.rc info 2};
|
||||
like ($output, qr/Status\s+Deleted/, 'sequence delete 2');
|
||||
qx{../task rc:seq.rc undelete 1,2};
|
||||
$output = qx{../task rc:seq.rc info 1};
|
||||
like ($output, qr/Status\s+Pending/, 'sequence undelete 1');
|
||||
$output = qx{../task rc:seq.rc info 2};
|
||||
like ($output, qr/Status\s+Pending/, 'sequence undelete 2');
|
||||
|
||||
# Test sequences in start/stop
|
||||
qx{../task rc:seq.rc start 1,2};
|
||||
$output = qx{../task rc:seq.rc info 1};
|
||||
like ($output, qr/Start/, 'sequence start 1');
|
||||
$output = qx{../task rc:seq.rc info 2};
|
||||
like ($output, qr/Start/, 'sequence start 2');
|
||||
qx{../task rc:seq.rc stop 1,2};
|
||||
$output = qx{../task rc:seq.rc info 1};
|
||||
unlike ($output, qr/Start/, 'sequence stop 1');
|
||||
$output = qx{../task rc:seq.rc info 2};
|
||||
unlike ($output, qr/Start/, 'sequence stop 2');
|
||||
|
||||
# Test sequences in modify
|
||||
qx{../task rc:seq.rc 1,2 +tag};
|
||||
$output = qx{../task rc:seq.rc info 1};
|
||||
like ($output, qr/Tags\s+tag/, 'sequence modify 1');
|
||||
$output = qx{../task rc:seq.rc info 2};
|
||||
like ($output, qr/Tags\s+tag/, 'sequence modify 2');
|
||||
qx{../task rc:seq.rc 1,2 -tag};
|
||||
$output = qx{../task rc:seq.rc info 1};
|
||||
unlike ($output, qr/Tags\s+tag/, 'sequence unmodify 1');
|
||||
$output = qx{../task rc:seq.rc info 2};
|
||||
unlike ($output, qr/Tags\s+tag/, 'sequence unmodify 2');
|
||||
|
||||
# Test sequences in substitutions
|
||||
qx{../task rc:seq.rc 1,2 /miss/Miss/};
|
||||
$output = qx{../task rc:seq.rc info 1};
|
||||
like ($output, qr/Description\s+one Miss/, 'sequence substitution 1');
|
||||
$output = qx{../task rc:seq.rc info 2};
|
||||
like ($output, qr/Description\s+two Miss/, 'sequence substitution 2');
|
||||
|
||||
# Test sequences in info
|
||||
$output = qx{../task rc:seq.rc info 1,2};
|
||||
like ($output, qr/Description\s+one Miss/, 'sequence info 1');
|
||||
like ($output, qr/Description\s+two Miss/, 'sequence info 2');
|
||||
|
||||
# Test sequences in duplicate
|
||||
qx{../task rc:seq.rc duplicate 1,2 pri:H};
|
||||
$output = qx{../task rc:seq.rc info 3};
|
||||
like ($output, qr/Priority\s+H/, 'sequence duplicate 1');
|
||||
$output = qx{../task rc:seq.rc info 4};
|
||||
like ($output, qr/Priority\s+H/, 'sequence duplicate 2');
|
||||
|
||||
# Test sequences in annotate
|
||||
qx{../task rc:seq.rc annotate 1,2 note};
|
||||
$output = qx{../task rc:seq.rc info 1};
|
||||
like ($output, qr/\d+\/\d+\/\d+ note/, 'sequence annotate 1');
|
||||
$output = qx{../task rc:seq.rc info 2};
|
||||
like ($output, qr/\d+\/\d+\/\d+ note/, 'sequence annotate 2');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'seq.rc';
|
||||
ok (!-r 'seq.rc', 'Removed seq.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
79
src/tests/substitute.t
Executable file
79
src/tests/substitute.t
Executable file
@@ -0,0 +1,79 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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, '>', 'subst.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'subst.rc', 'Created subst.rc');
|
||||
}
|
||||
|
||||
# Test the substitution command.
|
||||
qx{../task rc:subst.rc add foo foo foo};
|
||||
qx{../task rc:subst.rc 1 /foo/FOO/};
|
||||
my $output = qx{../task rc:subst.rc info 1};
|
||||
like ($output, qr/FOO foo foo/, 'substitution in description');
|
||||
|
||||
qx{../task rc:subst.rc 1 /foo/FOO/g};
|
||||
$output = qx{../task rc:subst.rc info 1};
|
||||
like ($output, qr/FOO FOO FOO/, 'global substitution in description');
|
||||
|
||||
# Test the substitution command on annotations.
|
||||
qx{../task rc:subst.rc annotate 1 bar bar bar};
|
||||
qx{../task rc:subst.rc 1 /bar/BAR/};
|
||||
$output = qx{../task rc:subst.rc info 1};
|
||||
like ($output, qr/BAR bar bar/, 'substitution in annotation');
|
||||
|
||||
qx{../task rc:subst.rc 1 /bar/BAR/g};
|
||||
$output = qx{../task rc:subst.rc info 1};
|
||||
like ($output, qr/BAR BAR BAR/, 'global substitution in annotation');
|
||||
|
||||
qx{../task rc:subst.rc 1 /FOO/aaa/};
|
||||
qx{../task rc:subst.rc 1 /FOO/bbb/};
|
||||
qx{../task rc:subst.rc 1 /FOO/ccc/};
|
||||
$output = qx{../task rc:subst.rc info 1};
|
||||
like ($output, qr/aaa bbb ccc/, 'individual successive substitution in description');
|
||||
|
||||
qx{../task rc:subst.rc 1 /bbb//};
|
||||
$output = qx{../task rc:subst.rc info 1};
|
||||
like ($output, qr/aaa ccc/, 'word deletion in description');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'subst.rc';
|
||||
ok (!-r 'subst.rc', 'Removed subst.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
@@ -31,11 +31,11 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest test (5);
|
||||
UnitTest test (10);
|
||||
|
||||
T t;
|
||||
std::string s = t.compose ();
|
||||
test.is ((int)s.length (), 46, "T::T (); T::compose ()");
|
||||
test.is ((int)s.length (), 49, "T::T (); T::compose ()");
|
||||
test.diag (s);
|
||||
|
||||
t.setStatus (T::completed);
|
||||
@@ -53,12 +53,42 @@ int main (int argc, char** argv)
|
||||
test.is (s[37], 'r', "T::setStatus (recurring)");
|
||||
test.diag (s);
|
||||
|
||||
// Round trip test.
|
||||
std::string sample = "00000000-0000-0000-0000-000000000000 - [] [] Sample";
|
||||
T t2;
|
||||
t2.parse (sample);
|
||||
sample += "\n";
|
||||
test.is (t2.compose (), sample, "T::parse -> T::compose round trip");
|
||||
std::string format3 = "00000000-0000-0000-0000-000000000000 - [] [] [] Sample\n";
|
||||
|
||||
// Format 1 Round trip test.
|
||||
std::string sample = "[] [] Sample";
|
||||
T tf1;
|
||||
tf1.parse (sample);
|
||||
test.is (tf1.compose ().substr (36, std::string::npos),
|
||||
format3.substr (36, std::string::npos),
|
||||
"T::parse format 1 -> T::compose round trip");
|
||||
|
||||
// Format 2 Round trip test.
|
||||
sample = "00000000-0000-0000-0000-000000000000 - [] [] Sample";
|
||||
T tf2;
|
||||
tf2.parse (sample);
|
||||
test.is (tf2.compose (), format3, "T::parse format 2 -> T::compose round trip");
|
||||
|
||||
// Format 3 Round trip test.
|
||||
sample = "00000000-0000-0000-0000-000000000000 - [] [] [] Sample";
|
||||
T tf3;
|
||||
tf3.parse (sample);
|
||||
test.is (tf3.compose (), format3, "T::parse format 3 -> T::compose round trip");
|
||||
|
||||
// b10b3236-70d8-47bb-840a-b4c430758fb6 - [foo] [bar:baz] [1237865996:'woof'] sample\n
|
||||
// ....:....|....:....|....:....|....:....|....:....|....:....|....:....|....:....|....:....|
|
||||
// ^ ^ ^
|
||||
// 0 36 66
|
||||
t.setStatus (T::pending);
|
||||
t.addTag ("foo");
|
||||
t.setAttribute ("bar", "baz");
|
||||
t.addAnnotation ("woof");
|
||||
t.setDescription ("sample");
|
||||
std::string format = t.compose ();
|
||||
test.is (format.substr (36, 20), " - [foo] [bar:baz] [", "compose tag, attribute");
|
||||
test.is (format.substr (66, 16), ":\"woof\"] sample\n", "compose annotation");
|
||||
test.is (t.getAnnotationCount (), 1, "annotation count");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,8 @@ int main (int argc, char** argv)
|
||||
// TODO Modify task.
|
||||
|
||||
// Complete task.
|
||||
t.ok (tdb.completeT (t1), "TDB::completeT t1");;
|
||||
t1.setStatus (T::completed);
|
||||
t.ok (tdb.modifyT (t1), "TDB::modifyT (completed) t1");;
|
||||
t.ok (tdb.pendingT (all), "TDB::pendingT read db");
|
||||
t.is ((int) all.size (), 0, "empty db");
|
||||
t.ok (tdb.allPendingT (all), "TDB::allPendingT read db");
|
||||
@@ -105,7 +106,8 @@ int main (int argc, char** argv)
|
||||
t.ok (tdb.addT (t2), "TDB::addT t2");
|
||||
|
||||
// Delete task.
|
||||
t.ok (tdb.deleteT (t2), "TDB::deleteT t2");
|
||||
t2.setStatus (T::deleted);
|
||||
t.ok (tdb.modifyT (t2), "TDB::modifyT (deleted) t2");
|
||||
|
||||
// GC the files.
|
||||
t.is (tdb.gc (), 1, "1 <- TDB::gc");
|
||||
|
||||
234
src/tests/text.t.cpp
Normal file
234
src/tests/text.t.cpp
Normal file
@@ -0,0 +1,234 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// task - a command line task list manager.
|
||||
//
|
||||
// Copyright 2006 - 2009, 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
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include <iostream>
|
||||
#include "task.h"
|
||||
#include "test.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (94);
|
||||
|
||||
// void wrapText (std::vector <std::string>& lines, const std::string& text, const int width)
|
||||
std::string text = "This is a test of the line wrapping code.";
|
||||
std::vector <std::string> lines;
|
||||
wrapText (lines, text, 10);
|
||||
t.is (lines.size (), (size_t) 5, "wrapText 'This is a test of the line wrapping code.' -> total 5 lines");
|
||||
t.is (lines[0], "This is a", "wrapText line 0 -> 'This is a'");
|
||||
t.is (lines[1], "test of", "wrapText line 1 -> 'test of'");
|
||||
t.is (lines[2], "the line", "wrapText line 2 -> 'the line'");
|
||||
t.is (lines[3], "wrapping", "wrapText line 3 -> 'wrapping'");
|
||||
t.is (lines[4], "code.", "wrapText line 4 -> 'code.'");
|
||||
|
||||
#ifdef NOPE
|
||||
// void wrapText (std::vector <std::string>& lines, const std::string& text, const int width)
|
||||
text = "This ☺ is a test of utf8 line extraction.";
|
||||
lines.clear ();
|
||||
wrapText (lines, text, 7);
|
||||
t.is (lines.size (), (size_t) 7, "wrapText 'This ☺ is a test of utf8 line extraction.' -> total 7 lines");
|
||||
t.is (lines[0], "This ☺", "wrapText line 0 -> 'This ☺'");
|
||||
t.is (lines[1], "is a", "wrapText line 1 -> 'is a'");
|
||||
t.is (lines[2], "test of", "wrapText line 2 -> 'test of'");
|
||||
t.is (lines[3], "utf8", "wrapText line 3 -> 'utf8'");
|
||||
t.is (lines[4], "line", "wrapText line 4 -> 'line'");
|
||||
t.is (lines[5], "extrac-", "wrapText line 5 -> 'extrac-'");
|
||||
t.is (lines[6], "tion.", "wrapText line 6 -> 'tion.'");
|
||||
|
||||
// void extractLine (std::string& text, std::string& line, int length)
|
||||
text = "This ☺ is a test of utf8 line extraction.";
|
||||
#endif
|
||||
std::string line;
|
||||
#ifdef NOPE
|
||||
extractLine (text, line, 7);
|
||||
t.is (line, "line 1", "extractLine 7 'This ☺ is a test of utf8 line extraction.' -> 'This ☺'");
|
||||
#endif
|
||||
|
||||
// void extractLine (std::string& text, std::string& line, int length)
|
||||
text = "line 1\nlengthy second line that exceeds width";
|
||||
extractLine (text, line, 10);
|
||||
t.is (line, "line 1", "extractLine 10 'line 1\\nlengthy second line that exceeds width' -> 'line 1'");
|
||||
|
||||
extractLine (text, line, 10);
|
||||
t.is (line, "lengthy", "extractLine 10 'lengthy second line that exceeds width' -> 'lengthy'");
|
||||
|
||||
extractLine (text, line, 10);
|
||||
t.is (line, "second", "extractLine 10 'second line that exceeds width' -> 'second'");
|
||||
|
||||
extractLine (text, line, 10);
|
||||
t.is (line, "line that", "extractLine 10 'line that exceeds width' -> 'line that'");
|
||||
|
||||
extractLine (text, line, 10);
|
||||
t.is (line, "exceeds", "extractLine 10 'exceeds width' -> 'exceeds'");
|
||||
|
||||
extractLine (text, line, 10);
|
||||
t.is (line, "width", "extractLine 10 'width' -> 'width'");
|
||||
|
||||
extractLine (text, line, 10);
|
||||
t.is (line, "", "extractLine 10 '' -> ''");
|
||||
|
||||
// void split (std::vector<std::string>& results, const std::string& input, const char delimiter)
|
||||
std::vector <std::string> items;
|
||||
std::string unsplit = "";
|
||||
split (items, unsplit, '-');
|
||||
t.is (items.size (), (size_t) 0, "split '' '-' -> 0 items");
|
||||
|
||||
unsplit = "a";
|
||||
split (items, unsplit, '-');
|
||||
t.is (items.size (), (size_t) 1, "split 'a' '-' -> 1 item");
|
||||
t.is (items[0], "a", "split 'a' '-' -> 'a'");
|
||||
|
||||
unsplit = "-";
|
||||
split (items, unsplit, '-');
|
||||
t.is (items.size (), (size_t) 2, "split '-' '-' -> '' ''");
|
||||
t.is (items[0], "", "split '-' '-' -> [0] ''");
|
||||
t.is (items[1], "", "split '-' '-' -> [1] ''");
|
||||
|
||||
unsplit = "-a-bc-def";
|
||||
split (items, unsplit, '-');
|
||||
t.is (items.size (), (size_t) 4, "split '-a-bc-def' '-' -> '' 'a' 'bc' 'def'");
|
||||
t.is (items[0], "", "split '-a-bc-def' '-' -> [0] ''");
|
||||
t.is (items[1], "a", "split '-a-bc-def' '-' -> [1] 'a'");
|
||||
t.is (items[2], "bc", "split '-a-bc-def' '-' -> [2] 'bc'");
|
||||
t.is (items[3], "def", "split '-a-bc-def' '-' -> [3] 'def'");
|
||||
|
||||
// void split (std::vector<std::string>& results, const std::string& input, const std::string& delimiter)
|
||||
unsplit = "";
|
||||
split (items, unsplit, "--");
|
||||
t.is (items.size (), (size_t) 0, "split '' '--' -> 0 items");
|
||||
|
||||
unsplit = "a";
|
||||
split (items, unsplit, "--");
|
||||
t.is (items.size (), (size_t) 1, "split 'a' '--' -> 1 item");
|
||||
t.is (items[0], "a", "split 'a' '-' -> 'a'");
|
||||
|
||||
unsplit = "--";
|
||||
split (items, unsplit, "--");
|
||||
t.is (items.size (), (size_t) 2, "split '-' '--' -> '' ''");
|
||||
t.is (items[0], "", "split '-' '-' -> [0] ''");
|
||||
t.is (items[1], "", "split '-' '-' -> [1] ''");
|
||||
|
||||
unsplit = "--a--bc--def";
|
||||
split (items, unsplit, "--");
|
||||
t.is (items.size (), (size_t) 4, "split '-a-bc-def' '--' -> '' 'a' 'bc' 'def'");
|
||||
t.is (items[0], "", "split '-a-bc-def' '--' -> [0] ''");
|
||||
t.is (items[1], "a", "split '-a-bc-def' '--' -> [1] 'a'");
|
||||
t.is (items[2], "bc", "split '-a-bc-def' '--' -> [2] 'bc'");
|
||||
t.is (items[3], "def", "split '-a-bc-def' '--' -> [3] 'def'");
|
||||
|
||||
// void join (std::string& result, const std::string& separator, const std::vector<std::string>& items)
|
||||
std::vector <std::string> unjoined;
|
||||
std::string joined;
|
||||
|
||||
join (joined, "", unjoined);
|
||||
t.is (joined.length (), (size_t) 0, "join -> length 0");
|
||||
t.is (joined, "", "join -> ''");
|
||||
|
||||
unjoined.push_back ("");
|
||||
unjoined.push_back ("a");
|
||||
unjoined.push_back ("bc");
|
||||
unjoined.push_back ("def");
|
||||
join (joined, "", unjoined);
|
||||
t.is (joined.length (), (size_t) 6, "join '' 'a' 'bc' 'def' -> length 6");
|
||||
t.is (joined, "abcdef", "join '' 'a' 'bc' 'def' -> 'abcdef'");
|
||||
|
||||
join (joined, "-", unjoined);
|
||||
t.is (joined.length (), (size_t) 9, "join '' - 'a' - 'bc' - 'def' -> length 9");
|
||||
t.is (joined, "-a-bc-def", "join '' - 'a' - 'bc' - 'def' -> '-a-bc-def'");
|
||||
|
||||
// std::string trimLeft (const std::string& in, const std::string& t /*= " "*/)
|
||||
t.is (trimLeft (""), "", "trimLeft '' -> ''");
|
||||
t.is (trimLeft ("", " \t"), "", "trimLeft '' -> ''");
|
||||
t.is (trimLeft ("xxx"), "xxx", "trimLeft 'xxx' -> 'xxx'");
|
||||
t.is (trimLeft ("xxx", " \t"), "xxx", "trimLeft 'xxx' -> 'xxx'");
|
||||
t.is (trimLeft (" \t xxx \t "), "\t xxx \t ", "trimLeft ' \\t xxx \\t ' -> '\\t xxx \\t '");
|
||||
t.is (trimLeft (" \t xxx \t ", " \t"), "xxx \t ", "trimLeft ' \\t xxx \\t ' -> 'xxx \\t '");
|
||||
|
||||
// std::string trimRight (const std::string& in, const std::string& t /*= " "*/)
|
||||
t.is (trimRight (""), "", "trimRight '' -> ''");
|
||||
t.is (trimRight ("", " \t"), "", "trimRight '' -> ''");
|
||||
t.is (trimRight ("xxx"), "xxx", "trimRight 'xxx' -> 'xxx'");
|
||||
t.is (trimRight ("xxx", " \t"), "xxx", "trimRight 'xxx' -> 'xxx'");
|
||||
t.is (trimRight (" \t xxx \t "), " \t xxx \t", "trimRight ' \\t xxx \\t ' -> ' \\t xxx \\t'");
|
||||
t.is (trimRight (" \t xxx \t ", " \t"), " \t xxx", "trimRight ' \\t xxx \\t ' -> ' \\t xxx'");
|
||||
|
||||
// std::string trim (const std::string& in, const std::string& t /*= " "*/)
|
||||
t.is (trim (""), "", "trim '' -> ''");
|
||||
t.is (trim ("", " \t"), "", "trim '' -> ''");
|
||||
t.is (trim ("xxx"), "xxx", "trim 'xxx' -> 'xxx'");
|
||||
t.is (trim ("xxx", " \t"), "xxx", "trim 'xxx' -> 'xxx'");
|
||||
t.is (trim (" \t xxx \t "), "\t xxx \t", "trim ' \\t xxx \\t ' -> '\\t xxx \\t'");
|
||||
t.is (trim (" \t xxx \t ", " \t"), "xxx", "trim ' \\t xxx \\t ' -> 'xxx'");
|
||||
|
||||
// std::string unquoteText (const std::string& text)
|
||||
t.is (unquoteText (""), "", "unquoteText '' -> ''");
|
||||
t.is (unquoteText ("x"), "x", "unquoteText 'x' -> 'x'");
|
||||
t.is (unquoteText ("'x"), "'x", "unquoteText ''x' -> ''x'");
|
||||
t.is (unquoteText ("x'"), "x'", "unquoteText 'x'' -> 'x''");
|
||||
t.is (unquoteText ("\"x"), "\"x", "unquoteText '\"x' -> '\"x'");
|
||||
t.is (unquoteText ("x\""), "x\"", "unquoteText 'x\"' -> 'x\"'");
|
||||
t.is (unquoteText ("''"), "", "unquoteText '''' -> ''");
|
||||
t.is (unquoteText ("'''"), "'", "unquoteText ''''' -> '''");
|
||||
t.is (unquoteText ("\"\""), "", "unquoteText '\"\"' -> ''");
|
||||
t.is (unquoteText ("\"\"\""), "\"", "unquoteText '\"\"\"' -> '\"'");
|
||||
t.is (unquoteText ("''''"), "''", "unquoteText '''''' -> ''''");
|
||||
t.is (unquoteText ("\"\"\"\""), "\"\"", "unquoteText '\"\"\"\"' -> '\"\"'");
|
||||
t.is (unquoteText ("'\"\"'"), "\"\"", "unquoteText '''\"\"' -> '\"\"'");
|
||||
t.is (unquoteText ("\"''\""), "''", "unquoteText '\"''\"' -> ''''");
|
||||
t.is (unquoteText ("'x'"), "x", "unquoteText ''x'' -> 'x'");
|
||||
t.is (unquoteText ("\"x\""), "x", "unquoteText '\"x\"' -> 'x'");
|
||||
|
||||
// std::string commify (const std::string& data)
|
||||
t.is (commify (""), "", "commify '' -> ''");
|
||||
t.is (commify ("1"), "1", "commify '1' -> '1'");
|
||||
t.is (commify ("12"), "12", "commify '12' -> '12'");
|
||||
t.is (commify ("123"), "123", "commify '123' -> '123'");
|
||||
t.is (commify ("1234"), "1,234", "commify '1234' -> '1,234'");
|
||||
t.is (commify ("12345"), "12,345", "commify '12345' -> '12,345'");
|
||||
t.is (commify ("123456"), "123,456", "commify '123456' -> '123,456'");
|
||||
t.is (commify ("1234567"), "1,234,567", "commify '1234567' -> '1,234,567'");
|
||||
t.is (commify ("12345678"), "12,345,678", "commify '12345678' -> '12,345,678'");
|
||||
t.is (commify ("123456789"), "123,456,789", "commify '123456789' -> '123,456,789'");
|
||||
t.is (commify ("1234567890"), "1,234,567,890", "commify '1234567890' -> '1,234,567,890'");
|
||||
|
||||
t.is (commify ("pre"), "pre", "commify 'pre' -> 'pre'");
|
||||
t.is (commify ("pre1234"), "pre1,234", "commify 'pre1234' -> 'pre1,234'");
|
||||
t.is (commify ("1234post"), "1,234post", "commify '1234post' -> '1,234post'");
|
||||
t.is (commify ("pre1234post"), "pre1,234post", "commify 'pre1234post' -> 'pre1,234post'");
|
||||
|
||||
// std::string lowerCase (const std::string& input)
|
||||
t.is (lowerCase (""), "", "lowerCase '' -> ''");
|
||||
t.is (lowerCase ("pre01_:POST"), "pre01_:post", "lowerCase 'pre01_:POST' -> 'pre01_:post'");
|
||||
|
||||
// std::string upperCase (const std::string& input)
|
||||
t.is (upperCase (""), "", "upperCase '' -> ''");
|
||||
t.is (upperCase ("pre01_:POST"), "PRE01_:POST", "upperCase 'pre01_:POST' -> 'PRE01_:POST'");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -33,7 +33,8 @@ use Test::More tests => 15;
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'undo.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
print $fh "data.location=.\n",
|
||||
"echo.command=no\n";
|
||||
close $fh;
|
||||
ok (-r 'undo.rc', 'Created undo.rc');
|
||||
}
|
||||
@@ -55,8 +56,8 @@ $output = qx{../task rc:undo.rc do 1; ../task rc:undo.rc list};
|
||||
like ($output, qr/^No matches/, 'No matches');
|
||||
|
||||
$output = qx{../task rc:undo.rc undo 1; ../task rc:undo.rc info 1};
|
||||
like ($output, qr/Task 1 not found/, 'task not found');
|
||||
like ($output, qr/reliably undone/, 'can only be reliable undone...');
|
||||
like ($output, qr/Task 1 not found/, 'Task 1 not found');
|
||||
like ($output, qr/No matches/, 'No matches');
|
||||
|
||||
# Cleanup.
|
||||
ok (-r 'pending.data', 'Need to remove pending.data');
|
||||
|
||||
80
src/tests/utf8.t
Executable file
80
src/tests/utf8.t
Executable file
@@ -0,0 +1,80 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2009, 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 => 6;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'utf8.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'utf8.rc', 'Created utf8.rc');
|
||||
}
|
||||
|
||||
# Add a task with UTF8 in the description.
|
||||
qx{../task rc:utf8.rc add Çirçös};
|
||||
qx{../task rc:utf8.rc add Hello world ☺};
|
||||
qx{../task rc:utf8.rc add ¥£€$¢₡₢₣₤₥₦₧₨₩₪₫₭₮₯};
|
||||
qx{../task rc:utf8.rc add Pchnąć w tę łódź jeża lub ośm skrzyń fig};
|
||||
qx{../task rc:utf8.rc add ๏ เป็นมนุษย์สุดประเสริฐเลิศคุณค่า};
|
||||
qx{../task rc:utf8.rc add イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム};
|
||||
qx{../task rc:utf8.rc add いろはにほへとちりぬるを};
|
||||
qx{../task rc:utf8.rc add D\\'fhuascail Íosa, Úrmhac na hÓighe Beannaithe, pór Éava agus Ádhaimh};
|
||||
qx{../task rc:utf8.rc add Árvíztűrő tükörfúrógép};
|
||||
qx{../task rc:utf8.rc add Kæmi ný öxi hér ykist þjófum nú bæði víl og ádrepa};
|
||||
qx{../task rc:utf8.rc add Sævör grét áðan því úlpan var ónýt};
|
||||
qx{../task rc:utf8.rc add Quizdeltagerne spiste jordbær med fløde, mens cirkusklovnen Wolther spillede på xylofon.};
|
||||
qx{../task rc:utf8.rc add Falsches Üben von Xylophonmusik quält jeden größeren Zwerg};
|
||||
qx{../task rc:utf8.rc add Zwölf Boxkämpfer jagten Eva quer über den Sylter Deich};
|
||||
qx{../task rc:utf8.rc add Heizölrückstoßabdämpfung};
|
||||
qx{../task rc:utf8.rc add Γαζέες καὶ μυρτιὲς δὲν θὰ βρῶ πιὰ στὸ χρυσαφὶ ξέφωτο};
|
||||
qx{../task rc:utf8.rc add Ξεσκεπάζω τὴν ψυχοφθόρα βδελυγμία};
|
||||
|
||||
my $output = qx{../task rc:utf8.rc ls};
|
||||
diag ($output);
|
||||
like ($output, qr/17/, 'all 17 tasks shown');
|
||||
|
||||
qx{../task rc:utf8.rc add project:Çirçös utf8 in project};
|
||||
$output = qx{../task rc:utf8.rc ls project:Çirçös};
|
||||
like ($output, qr/Çirçös.+utf8 in project/, 'utf8 in project works');
|
||||
|
||||
qx{../task rc:utf8.rc add utf8 in tag +☺};
|
||||
$output = qx{../task rc:utf8.rc ls +☺};
|
||||
like ($output, qr/utf8 in tag/, 'utf8 in tag works');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'utf8.rc';
|
||||
ok (!-r 'utf8.rc', 'Removed utf8.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
39
src/text.cpp
39
src/text.cpp
@@ -104,28 +104,6 @@ void join (
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void extractParagraphs (const std::string& input, std::vector<std::string>& output)
|
||||
{
|
||||
std::string copy = input;
|
||||
while (1)
|
||||
{
|
||||
size_t so = copy.find ("<p>");
|
||||
size_t eo = copy.find ("</p>");
|
||||
|
||||
if (so == std::string::npos && eo == std::string::npos)
|
||||
break;
|
||||
|
||||
std::string extract = trim (copy.substr (so + 3, eo - so - 3));
|
||||
copy = copy.substr (eo + 4, std::string::npos);
|
||||
output.push_back (extract);
|
||||
}
|
||||
|
||||
// There were no paragraphs.
|
||||
if (!output.size ())
|
||||
output.push_back (input);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string trimLeft (const std::string& in, const std::string& t /*= " "*/)
|
||||
{
|
||||
@@ -149,12 +127,19 @@ std::string trim (const std::string& in, const std::string& t /*= " "*/)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Remove enclosing balanced quotes. Assumes trimmed text.
|
||||
void unquoteText (std::string& text)
|
||||
std::string unquoteText (const std::string& input)
|
||||
{
|
||||
char quote = text[0];
|
||||
if (quote == '\'' || quote == '"')
|
||||
if (text[text.length () - 1] == quote)
|
||||
text = text.substr (1, text.length () - 3);
|
||||
std::string output = input;
|
||||
|
||||
if (output.length () > 1)
|
||||
{
|
||||
char quote = output[0];
|
||||
if ((quote == '\'' || quote == '"') &&
|
||||
output[output.length () - 1] == quote)
|
||||
return output.substr (1, output.length () - 2);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
143
src/util.cpp
143
src/util.cpp
@@ -25,6 +25,7 @@
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sys/types.h>
|
||||
@@ -41,17 +42,28 @@
|
||||
#include "../auto.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Uses std::getline, because std::cin eats leading whitespace, and that means
|
||||
// that if a newline is entered, std::cin eats it and never returns from the
|
||||
// "std::cin >> answer;" line, but it does disply the newline. This way, with
|
||||
// std::getline, the newline can be detected, and the prompt re-written.
|
||||
bool confirm (const std::string& question)
|
||||
{
|
||||
std::cout << question << " (y/n) ";
|
||||
std::string answer;
|
||||
std::cin >> answer;
|
||||
|
||||
answer = trim (answer);
|
||||
if (answer == "y" || answer == "Y")
|
||||
return true;
|
||||
do
|
||||
{
|
||||
std::cout << question << " (y/n) ";
|
||||
std::getline (std::cin, answer);
|
||||
answer = lowerCase (trim (answer));
|
||||
if (answer == "\n") std::cout << "newline\n";
|
||||
}
|
||||
while (answer != "y" &&
|
||||
answer != "ye" &&
|
||||
answer != "yes" &&
|
||||
answer != "n" &&
|
||||
answer != "no");
|
||||
|
||||
return false;
|
||||
return (answer == "y" || answer == "ye" || answer == "yes") ? true : false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -84,19 +96,31 @@ void formatTimeDeltaDays (std::string& output, time_t delta)
|
||||
if (days > 365)
|
||||
sprintf (formatted, "%.1f yrs", (days / 365.2422));
|
||||
else if (days > 84)
|
||||
sprintf (formatted, "%1d mth%s", (int) (days / 30.6), ((int) (days / 30.6) == 1 ? "" : "s"));
|
||||
sprintf (formatted, "%1d mth%s",
|
||||
(int) (days / 30.6),
|
||||
((int) (days / 30.6) == 1 ? "" : "s"));
|
||||
else if (days > 13)
|
||||
sprintf (formatted, "%d wk%s", (int) (days / 7.0), ((int) (days / 7.0) == 1 ? "" : "s"));
|
||||
sprintf (formatted, "%d wk%s",
|
||||
(int) (days / 7.0),
|
||||
((int) (days / 7.0) == 1 ? "" : "s"));
|
||||
else if (days > 5.0)
|
||||
sprintf (formatted, "%d day%s", (int) days, ((int) days == 1 ? "" : "s"));
|
||||
sprintf (formatted, "%d day%s",
|
||||
(int) days,
|
||||
((int) days == 1 ? "" : "s"));
|
||||
else if (days > 1.0)
|
||||
sprintf (formatted, "%.1f days", days);
|
||||
else if (days * 24 > 1.0)
|
||||
sprintf (formatted, "%d hr%s", (int) (days * 24.0), ((int) (days * 24.0) == 1 ? "" : "s"));
|
||||
sprintf (formatted, "%d hr%s",
|
||||
(int) (days * 24.0),
|
||||
((int) (days * 24.0) == 1 ? "" : "s"));
|
||||
else if (days * 24 * 60 > 1)
|
||||
sprintf (formatted, "%d min%s", (int) (days * 24 * 60), ((int) (days * 24 * 60) == 1 ? "" : "s"));
|
||||
sprintf (formatted, "%d min%s",
|
||||
(int) (days * 24 * 60),
|
||||
((int) (days * 24 * 60) == 1 ? "" : "s"));
|
||||
else if (days * 24 * 60 * 60 > 1)
|
||||
sprintf (formatted, "%d sec%s", (int) (days * 24 * 60 * 60), ((int) (days * 24 * 60 * 60) == 1 ? "" : "s"));
|
||||
sprintf (formatted, "%d sec%s",
|
||||
(int) (days * 24 * 60 * 60),
|
||||
((int) (days * 24 * 60 * 60) == 1 ? "" : "s"));
|
||||
else
|
||||
strcpy (formatted, "-");
|
||||
|
||||
@@ -112,19 +136,31 @@ std::string formatSeconds (time_t delta)
|
||||
if (days > 365)
|
||||
sprintf (formatted, "%.1f yrs", (days / 365.2422));
|
||||
else if (days > 84)
|
||||
sprintf (formatted, "%1d mth%s", (int) (days / 30.6), ((int) (days / 30.6) == 1 ? "" : "s"));
|
||||
sprintf (formatted, "%1d mth%s",
|
||||
(int) (days / 30.6),
|
||||
((int) (days / 30.6) == 1 ? "" : "s"));
|
||||
else if (days > 13)
|
||||
sprintf (formatted, "%d wk%s", (int) (days / 7.0), ((int) (days / 7.0) == 1 ? "" : "s"));
|
||||
sprintf (formatted, "%d wk%s",
|
||||
(int) (days / 7.0),
|
||||
((int) (days / 7.0) == 1 ? "" : "s"));
|
||||
else if (days > 5.0)
|
||||
sprintf (formatted, "%d day%s", (int) days, ((int) days == 1 ? "" : "s"));
|
||||
sprintf (formatted, "%d day%s",
|
||||
(int) days,
|
||||
((int) days == 1 ? "" : "s"));
|
||||
else if (days > 1.0)
|
||||
sprintf (formatted, "%.1f days", days);
|
||||
else if (days * 24 > 1.0)
|
||||
sprintf (formatted, "%d hr%s", (int) (days * 24.0), ((int) (days * 24) == 1 ? "" : "s"));
|
||||
sprintf (formatted, "%d hr%s",
|
||||
(int) (days * 24.0),
|
||||
((int) (days * 24) == 1 ? "" : "s"));
|
||||
else if (days * 24 * 60 > 1)
|
||||
sprintf (formatted, "%d min%s", (int) (days * 24 * 60), ((int) (days * 24 * 60) == 1 ? "" : "s"));
|
||||
sprintf (formatted, "%d min%s",
|
||||
(int) (days * 24 * 60),
|
||||
((int) (days * 24 * 60) == 1 ? "" : "s"));
|
||||
else if (days * 24 * 60 * 60 > 1)
|
||||
sprintf (formatted, "%d sec%s", (int) (days * 24 * 60 * 60), ((int) (days * 24 * 60 * 60) == 1 ? "" : "s"));
|
||||
sprintf (formatted, "%d sec%s",
|
||||
(int) (days * 24 * 60 * 60),
|
||||
((int) (days * 24 * 60 * 60) == 1 ? "" : "s"));
|
||||
else
|
||||
strcpy (formatted, "-");
|
||||
|
||||
@@ -172,9 +208,12 @@ const std::string uuid ()
|
||||
{
|
||||
uuid_t id;
|
||||
uuid_generate (id);
|
||||
char buffer[100];
|
||||
char buffer[100] = {0};
|
||||
uuid_unparse_lower (id, buffer);
|
||||
|
||||
// Bug found by Steven de Brouwer.
|
||||
buffer[36] = '\0';
|
||||
|
||||
return std::string (buffer);
|
||||
}
|
||||
|
||||
@@ -235,6 +274,7 @@ const std::string uuid ()
|
||||
id[33] = randomHexDigit ();
|
||||
id[34] = randomHexDigit ();
|
||||
id[35] = randomHexDigit ();
|
||||
id[36] = '\0';
|
||||
|
||||
return id;
|
||||
}
|
||||
@@ -251,6 +291,7 @@ int convertDuration (const std::string& input)
|
||||
supported.push_back ("daily");
|
||||
supported.push_back ("day");
|
||||
supported.push_back ("weekly");
|
||||
supported.push_back ("weekdays");
|
||||
supported.push_back ("sennight");
|
||||
supported.push_back ("biweekly");
|
||||
supported.push_back ("fortnight");
|
||||
@@ -269,6 +310,7 @@ int convertDuration (const std::string& input)
|
||||
std::string found = matches[0];
|
||||
|
||||
if (found == "daily" || found == "day") return 1;
|
||||
else if (found == "weekdays") return 1;
|
||||
else if (found == "weekly" || found == "sennight") return 7;
|
||||
else if (found == "biweekly" || found == "fortnight") return 14;
|
||||
else if (found == "monthly") return 30;
|
||||
@@ -367,3 +409,66 @@ int flock (int fd, int operation)
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool slurp (
|
||||
const std::string& file,
|
||||
std::vector <std::string>& contents,
|
||||
bool trimLines /* = false */)
|
||||
{
|
||||
contents.clear ();
|
||||
|
||||
std::ifstream in (file.c_str ());
|
||||
if (in.good ())
|
||||
{
|
||||
std::string line;
|
||||
while (getline (in, line))
|
||||
{
|
||||
if (trimLines) line = trim (line);
|
||||
contents.push_back (line);
|
||||
}
|
||||
|
||||
in.close ();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool slurp (
|
||||
const std::string& file,
|
||||
std::string& contents,
|
||||
bool trimLines /* = false */)
|
||||
{
|
||||
contents = "";
|
||||
|
||||
std::ifstream in (file.c_str ());
|
||||
if (in.good ())
|
||||
{
|
||||
std::string line;
|
||||
while (getline (in, line))
|
||||
{
|
||||
if (trimLines) line = trim (line);
|
||||
contents += line + "\n";
|
||||
}
|
||||
|
||||
in.close ();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void spit (const std::string& file, const std::string& contents)
|
||||
{
|
||||
std::ofstream out (file.c_str ());
|
||||
if (out.good ())
|
||||
{
|
||||
out << contents;
|
||||
out.close ();
|
||||
}
|
||||
else
|
||||
throw std::string ("Could not write file '") + file + "'";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1 +1 @@
|
||||
<pkgref spec="1.12" uuid="C71026FD-E252-42CD-89C3-2F6F087AAF17"><config><identifier>com.beckingham.task142.task.pkg</identifier><version/><description></description><post-install type="none"/><requireAuthorization/><installFrom>/Users/paul/task.git/binary/task</installFrom><installTo mod="true" relocatable="true">/usr/local/bin</installTo><flags><followSymbolicLinks/></flags><packageStore type="internal"></packageStore><mod>parent</mod><mod>locationType</mod><mod>relocatable</mod><mod>version</mod><mod>installTo.path</mod><mod>installTo</mod></config><contents><file-list>01task-contents.xml</file-list><filter>/CVS$</filter><filter>/\.svn$</filter><filter>/\.cvsignore$</filter><filter>/\.cvspass$</filter><filter>/\.DS_Store$</filter></contents></pkgref>
|
||||
<pkgref spec="1.12" uuid="C71026FD-E252-42CD-89C3-2F6F087AAF17"><config><identifier>com.beckingham.task143.task.pkg</identifier><version></version><description></description><post-install type="none"/><requireAuthorization/><installFrom>/Users/paul/task.git/binary/task</installFrom><installTo mod="true" relocatable="true">/usr/local/bin</installTo><flags><followSymbolicLinks/></flags><packageStore type="internal"></packageStore><mod>parent</mod><mod>locationType</mod><mod>relocatable</mod><mod>version</mod><mod>installTo.path</mod><mod>installTo</mod></config><contents><file-list>01task-contents.xml</file-list><filter>/CVS$</filter><filter>/\.svn$</filter><filter>/\.cvsignore$</filter><filter>/\.cvspass$</filter><filter>/\.DS_Store$</filter></contents></pkgref>
|
||||
@@ -1 +1 @@
|
||||
<pkmkdoc spec="1.12"><properties><title>Task 1.4.2</title><build>/Users/paul/Documents/task-1.4.2.pkg</build><organization>com.beckingham</organization><userSees ui="easy"/><min-target os="3"/><domain anywhere="true" system="true"/></properties><distribution><versions min-spec="1.000000"/><scripts></scripts></distribution><contents><choice title="task" id="choice0" starts_selected="true" starts_enabled="true" starts_hidden="false"><pkgref id="com.beckingham.task142.task.pkg"/><choice-reqs><requirement id="tosv" operator="ge" value="'10.5.0'" selected="no" enabled="no" hidden="unchanged" startSelected="unchanged" startEnabled="unchanged" startHidden="unchanged"/></choice-reqs></choice></contents><resources bg-scale="none" bg-align="topleft"><locale lang="en"><resource mod="true" type="license">/Users/paul/task.git/binary/COPYING.txt</resource><resource mod="true" type="readme">/Users/paul/task.git/binary/README.txt</resource></locale></resources><flags/><item type="file">01task.xml</item><mod>properties.title</mod><mod>properties.anywhereDomain</mod><mod>properties.systemDomain</mod></pkmkdoc>
|
||||
<pkmkdoc spec="1.12"><properties><title>Task 1.4.3</title><build>/Users/paul/Desktop/task-1.4.3.pkg</build><organization>com.beckingham</organization><userSees ui="easy"/><min-target os="3"/><domain anywhere="true" system="true"/></properties><distribution><versions min-spec="1.000000"/><scripts></scripts></distribution><contents><choice title="task" id="choice0" starts_selected="true" starts_enabled="true" starts_hidden="false"><pkgref id="com.beckingham.task143.task.pkg"/><choice-reqs><requirement id="tosv" operator="ge" value="'10.5.0'" selected="no" enabled="no" hidden="unchanged" startSelected="unchanged" startEnabled="unchanged" startHidden="unchanged"/></choice-reqs></choice></contents><resources bg-scale="none" bg-align="topleft"><locale lang="en"><resource mod="true" type="license">/Users/paul/task.git/binary/COPYING.txt</resource><resource mod="true" type="readme">/Users/paul/task.git/binary/README.txt</resource></locale></resources><flags/><item type="file">01task.xml</item><mod>properties.title</mod><mod>properties.systemDomain</mod><mod>properties.anywhereDomain</mod></pkmkdoc>
|
||||
56
task_completion.sh
Normal file
56
task_completion.sh
Normal file
@@ -0,0 +1,56 @@
|
||||
#
|
||||
# bash completion support for task 1.7.0-2
|
||||
# Copyright (C) 2009 Federico Hernandez <ultrafredde@gmail.com>
|
||||
# Distributed under the GNU General Public License, version 2.0
|
||||
#
|
||||
# The routines will do completion of:
|
||||
#
|
||||
# *) task subcommands
|
||||
# *) local and remote tag names
|
||||
#
|
||||
# To use these routines:
|
||||
#
|
||||
# 1) Copy this file to somewhere (e.g. ~/.task-completion.sh).
|
||||
# 2) Added the following line to your .bashrc:
|
||||
# source ~/.task-completion.sh
|
||||
#
|
||||
# OR
|
||||
#
|
||||
# 3) Copy the file to /etc/bash_complettion.d
|
||||
# 4) source /etc/bash_completion
|
||||
#
|
||||
# To submit patches/bug reports:
|
||||
#
|
||||
# *) Send them to the mailing list:
|
||||
#
|
||||
# taskprogram@googlegroups.com
|
||||
#
|
||||
# *) CC the all patchesi/bug reports to:
|
||||
#
|
||||
# Federico Hernandez <ultrafredde@gmail.com>
|
||||
#
|
||||
|
||||
_task()
|
||||
{
|
||||
local cur prev opts base
|
||||
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
|
||||
opts="active add annotate append calendar color completed delete done duplicate edit export ghistory help history import info list long ls newest next oldest overdue projects start stats stop summary tags timesheet undelete undo version"
|
||||
|
||||
case "${prev}" in
|
||||
ls|list|long)
|
||||
if [[ ${cur} == +* ]] ; then
|
||||
local tags=$( task tags | egrep -v 'tags|^$'|sed 's/^/+/' )
|
||||
COMPREPLY=( $(compgen -W "${tags}" -- ${cur}) )
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
||||
return 0
|
||||
}
|
||||
complete -F _task task
|
||||
Reference in New Issue
Block a user