Compare commits
106 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a13989f18e | ||
|
|
97bb07a617 | ||
|
|
01d0d036a4 | ||
|
|
7de5b22f1c | ||
|
|
cb635c0d6f | ||
|
|
111e9f893d | ||
|
|
f96d2e6609 | ||
|
|
8a930653a4 | ||
|
|
bc46888bcd | ||
|
|
67fd7e2faa | ||
|
|
9f96ab28ce | ||
|
|
a66f59a7e1 | ||
|
|
24e1522e32 | ||
|
|
f5bc5dfd0f | ||
|
|
82702bffdc | ||
|
|
1a05224816 | ||
|
|
e4f7bda430 | ||
|
|
38ca8c8fb5 | ||
|
|
ad9c89b9fb | ||
|
|
25db00e97d | ||
|
|
b3f3261190 | ||
|
|
6efd3299fe | ||
|
|
844c980bce | ||
|
|
ce99cbf2d4 | ||
|
|
5fb349ca9b | ||
|
|
00041dce41 | ||
|
|
d6631767b5 | ||
|
|
0c4f83377a | ||
|
|
a45d6b459f | ||
|
|
d77a790f21 | ||
|
|
5ecbd85020 | ||
|
|
6428b026ba | ||
|
|
716ed39695 | ||
|
|
c650edd4f9 | ||
|
|
484c31f0e4 | ||
|
|
d00b57ec65 | ||
|
|
724e9b8113 | ||
|
|
356519e58f | ||
|
|
213a7a519b | ||
|
|
d7c446f010 | ||
|
|
14508742f1 | ||
|
|
6ea6c79375 | ||
|
|
426eac97aa | ||
|
|
7f99d39d19 | ||
|
|
623f8d869e | ||
|
|
b2eb9c3265 | ||
|
|
688233b3a4 | ||
|
|
12cdee9809 | ||
|
|
66fcdfe01f | ||
|
|
0f7cf1cd52 | ||
|
|
007c194c8c | ||
|
|
ff18241f6f | ||
|
|
9477660e02 | ||
|
|
1f8f4c631d | ||
|
|
05fd9278a6 | ||
|
|
f1a0b842dc | ||
|
|
cd59f7f510 | ||
|
|
6a1a1cd70f | ||
|
|
3c2987f53f | ||
|
|
2ab1df77df | ||
|
|
abf31a6b35 | ||
|
|
b6d320d311 | ||
|
|
cd648270ab | ||
|
|
2161ffac2c | ||
|
|
4f4a32b405 | ||
|
|
99bce308e6 | ||
|
|
916b8641b3 | ||
|
|
2f85941d37 | ||
|
|
f3f4ae15eb | ||
|
|
5e53226eb8 | ||
|
|
2c7552222a | ||
|
|
8572080677 | ||
|
|
ba87499eca | ||
|
|
fbe24b3fda | ||
|
|
5e55166617 | ||
|
|
bcd5524563 | ||
|
|
bb19361956 | ||
|
|
78d092c588 | ||
|
|
3da3d3f99d | ||
|
|
e2b240fd06 | ||
|
|
ee6ab69023 | ||
|
|
74e13670d0 | ||
|
|
d37c798dbc | ||
|
|
c93db168f3 | ||
|
|
52c029d4d9 | ||
|
|
c9360ad9c4 | ||
|
|
51e5a18384 | ||
|
|
f1368d6ac6 | ||
|
|
70e6f4f9f6 | ||
|
|
2bfd220714 | ||
|
|
3214c1f02a | ||
|
|
297f48a07c | ||
|
|
ea067acb52 | ||
|
|
8a70b78d71 | ||
|
|
e368043fb8 | ||
|
|
3ef6aa9f8e | ||
|
|
8cd8c4753b | ||
|
|
24085e0960 | ||
|
|
d92e80e289 | ||
|
|
fcbc8a2ee2 | ||
|
|
336a4dea01 | ||
|
|
67ffd07312 | ||
|
|
b2ad305f23 | ||
|
|
fa34f47f8a | ||
|
|
9a47e2b748 | ||
|
|
60d6cd62c8 |
6
AUTHORS
6
AUTHORS
@@ -22,6 +22,9 @@ The following submitted code, packages or analysis, and deserve special thanks:
|
||||
Alexander Neumann
|
||||
Emil Sköldberg
|
||||
Johannes Schlatow
|
||||
Michal Josífko
|
||||
Ed Neville
|
||||
Kevin Owens
|
||||
|
||||
Thanks to the following, who submitted detailed bug reports and excellent suggestions:
|
||||
Eugene Kramer
|
||||
@@ -30,7 +33,6 @@ Thanks to the following, who submitted detailed bug reports and excellent sugges
|
||||
Thomas Engel
|
||||
Nishiishii
|
||||
galvanizd
|
||||
Stas Antons
|
||||
Vincent Fleuranceau
|
||||
ArchiMark
|
||||
Carlos Yoder
|
||||
@@ -48,4 +50,6 @@ Thanks to the following, who submitted detailed bug reports and excellent sugges
|
||||
Juergen Daubert
|
||||
Rich Mintz
|
||||
Seneca Cunningham
|
||||
Dirk Deimeke
|
||||
Michelle Crane
|
||||
|
||||
|
||||
66
ChangeLog
66
ChangeLog
@@ -1,7 +1,69 @@
|
||||
|
||||
------ current release ---------------------------
|
||||
|
||||
1.9.1 (5/22/2010)
|
||||
1.9.2 (7/10/2010)
|
||||
+ Added feature #320, so the command "task 123" is interpreted as an implicit
|
||||
"task info 123" command (thanks to John Florian).
|
||||
+ Added feature #326, allowing tasks to be added in the completed state, by
|
||||
using the 'log' command in place of 'add' (thanks to Cory Donnelly).
|
||||
+ Added features #36 and #37, providing annual versions of the 'history' and
|
||||
'ghistory' command as 'history.annual' and 'ghistory.annual'.
|
||||
+ Added feature #363 supporting iCalendar/vcalendar (RFC-2445, RFC-5545,
|
||||
RFC-5546) export via the 'export.ical' command.
|
||||
+ Added feature #390, an extra dateformat for annotations (thanks to Cory
|
||||
Donnelly).
|
||||
+ Added feature #407, a new 'task show' command to display the current
|
||||
configuration settings or just the ones matching a search string.
|
||||
'task config' is now only used to set new configuration values.
|
||||
+ Added feature #298, supporting a configurable number of future recurring
|
||||
tasks that are generated.
|
||||
+ Added feature #412, which allows the 'projects' and 'tags' commands to be
|
||||
list all used projects/tags, not just the ones used in current pending tasks.
|
||||
Controlled by the 'list.all.projects' and 'list.all.tags' configuration
|
||||
variables (thanks to Dirk Deimeke).
|
||||
+ Added feature #415, which supports displaying just a single page of tasks,
|
||||
by specifying either 'limit:page' to a command, or 'report.xxx.limit:page'
|
||||
in a report specification (thanks to T. Charles Yun).
|
||||
+ Improvements to the man pages (thanks to T. Charles Yun).
|
||||
+ Modified the 'next' report to only display one page, by default.
|
||||
+ Added feature #408, making it possible to delete annotations with the new
|
||||
denotate command and the provided description (thanks to Dirk Deimeke).
|
||||
+ Added support for more varied durations when specifying recurring tasks,
|
||||
such as '3 mths' or '24 hrs'.
|
||||
+ The ghistory graph bars can now be colored with 'color.history.add',
|
||||
'color.history.done' and 'color.history.delete' configuration variables.
|
||||
+ Added feature #156, so that task supports both a 'side' and 'diff' style
|
||||
of undo.
|
||||
+ Distribution now includes 7 theme files, for 16- and 256-color terminals.
|
||||
+ Task now defaults to using the equivalent to the dark-16.theme.
|
||||
+ Fixed bug #406 so that task now includes command aliases in the _commands
|
||||
helper command used by shell completion scripts.
|
||||
+ Fixed bug #211 - it was unclear which commands modify a task description.
|
||||
+ Fixed bug #411, clarifying that the 'projects' command only lists projects
|
||||
for which there are pending tasks (thanks to Dirk Deimeke).
|
||||
+ Fixed bug #414, that caused filtering on the presence or absence of tags
|
||||
containing Unicode characters to fail (thanks to Michal Josífko).
|
||||
+ Fixed bug #416, which caused sorting on a date to fail if the year was not
|
||||
included in the dateformat (thanks to Michelle Crane).
|
||||
+ Fixed bug #417, which caused sorting on countdown and age fields to be
|
||||
wrong (thanks to Michell Crane).
|
||||
+ Fixed bug #418, which caused the attribute modifier 'due.before' to fail
|
||||
if the year was not included in the dateformat (thanks to Michelle Crane).
|
||||
+ Fixed bug #132, which failed to set a sort order so that active tasks sort
|
||||
higher than inactive tasks, all things being equal.
|
||||
+ Fixed bug #405, which incorrectly compared dates on tasks created by
|
||||
versions earlier than 1.9.1 to those created by 1.9.1 or later (thanks to
|
||||
Ivo Jimenez).
|
||||
+ Fixed bug #420, missing 'ID' from help text (thanks to Ed Neville).
|
||||
+ Fixed bug that prevented 'task list priority.above:L' from working.
|
||||
+ Fixed bug that miscalculated terminal width for the ghistory.annual
|
||||
report.
|
||||
+ Fixed wording (support issue #383) when modifying a recurring task (thanks
|
||||
to T. Charles Yun).
|
||||
|
||||
------ old releases ------------------------------
|
||||
|
||||
1.9.1 (5/22/2010) 60a99725b858be134ad538cb7c1a32c98de70e67
|
||||
+ Summary report bar colors can now be specified with color.summary.bar
|
||||
and color.summary.background configuration variables.
|
||||
+ The 'edit' command now conveniently fills in the current date for new
|
||||
@@ -24,8 +86,6 @@
|
||||
+ Fixed bug #395 that prevented the upgrade of a pending task to a
|
||||
recurring task (thanks to T. Charles Yun).
|
||||
|
||||
------ old releases ------------------------------
|
||||
|
||||
1.9.0 (2/22/2010) dd758f8b33de110a633e2ff3ebdac73232b8ff44
|
||||
+ Added feature #283 that makes it possible to control the verbosity
|
||||
of the output of annotations.
|
||||
|
||||
@@ -20,5 +20,5 @@ i18ndir = $(docdir)
|
||||
nobase_dist_i18n_DATA = i18n/strings.de-DE i18n/strings.en-US i18n/strings.es-ES i18n/strings.fr-FR i18n/strings.nl-NL i18n/strings.sv-SE i18n/tips.de-DE i18n/tips.en-US i18n/tips.sv-SE
|
||||
|
||||
rcfiledir = $(docdir)/rc
|
||||
dist_rcfile_DATA = doc/rc/holidays-US.rc doc/rc/holidays-SE.rc doc/rc/dark-16.theme doc/rc/dark-256.theme doc/rc/light-16.theme doc/rc/light-256.theme
|
||||
dist_rcfile_DATA = doc/rc/holidays-US.rc doc/rc/holidays-SE.rc doc/rc/dark-16.theme doc/rc/dark-256.theme doc/rc/light-16.theme doc/rc/light-256.theme doc/rc/dark-blue-256.theme doc/rc/dark-green-256.theme doc/rc/dark-red-256.theme
|
||||
|
||||
|
||||
30
NEWS
30
NEWS
@@ -1,21 +1,15 @@
|
||||
|
||||
New Features in task 1.9
|
||||
New Features in task 1.9.2
|
||||
|
||||
- 256-color support
|
||||
- Support for coloring alternate lines of output. Remember that old green
|
||||
and white fan-fold printer paper?
|
||||
- Supports nested .taskrc files with the new "include" statement"
|
||||
- New columns that include the time as well as date
|
||||
- New attribute modifiers
|
||||
- New date format for reports
|
||||
- Improved .taskrc validation
|
||||
- Improved calendar report with custom coloring and optional task details output
|
||||
- Holidays are now supported in the calendar report
|
||||
- Ability to use multiple, similar filter terms, like:
|
||||
task list project.not:foo project.not:bar
|
||||
- Ability to do case-sensitive or case-insensitive search for keywords, and
|
||||
substitutions in the description and annotations.
|
||||
- Task is now part of Debian
|
||||
- New 'log' command to add tasks that are already completed.
|
||||
- New annual history and ghistory command variations.
|
||||
- Alias support in shell completion scripts.
|
||||
- New iCalendar/vcalendar export format (RFC-2445, RFC-5545, RFC-5546).
|
||||
- New 'show' command to display configuration settings.
|
||||
- New 'denotate' command to delete annotations.
|
||||
- New 16-color and 256-color themes included.
|
||||
- New limit:page filter to show only one page of tasks.
|
||||
- Performance enhancements.
|
||||
|
||||
Please refer to the ChangeLog file for full details. There are too many to
|
||||
list here.
|
||||
@@ -23,8 +17,8 @@ New Features in task 1.9
|
||||
Task has been built and tested on the following configurations:
|
||||
|
||||
* OS X 10.6 Snow Leopard and 10.5 Leopard
|
||||
* Fedora 12 Constantine and 11 Leonidas
|
||||
* Ubuntu 9.10 Karmic Koala and 9.04 Jaunty Jackalope
|
||||
* Fedora 13 Goddard, 12 Constantine
|
||||
* Ubuntu 10.04 Lucid Lynx, 9.10 Karmic Koala
|
||||
* Debian Sid
|
||||
* Slackware 12.2
|
||||
* Arch Linux
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT(task, 1.9.1, support@taskwarrior.org)
|
||||
AC_INIT(task, 1.9.2, support@taskwarrior.org)
|
||||
|
||||
|
||||
# Source type.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.TH task-color 5 2010-05-22 "task 1.9.1" "User Manuals"
|
||||
.TH task-color 5 2010-05-22 "task 1.9.2" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
task-color \- A color tutorial for the task(1) command line todo manager.
|
||||
@@ -234,9 +234,30 @@ be included.
|
||||
To get a good idea of what a color theme looks like, try adding this entry to
|
||||
your .taskrc file:
|
||||
|
||||
include /usr/local/share/doc/task/themes/dark-256.theme
|
||||
.RS
|
||||
include /usr/local/share/doc/task/rc/dark-256.theme
|
||||
.RE
|
||||
|
||||
Better yet, create your own, and share it.
|
||||
You can use any of the standard task themes:
|
||||
|
||||
.RS
|
||||
light-16.theme
|
||||
.br
|
||||
light-256.theme
|
||||
.br
|
||||
dark-16.theme
|
||||
.br
|
||||
dark-256.theme
|
||||
.br
|
||||
dark-red-256.theme
|
||||
.br
|
||||
dark-green-256.theme
|
||||
.br
|
||||
dark-blue-256.theme
|
||||
.RE
|
||||
|
||||
Better yet, create your own, and share it. We will gladly host the theme file
|
||||
on <http://taskwarrior.org>.
|
||||
|
||||
.SH "CREDITS & COPYRIGHTS"
|
||||
task was written by P. Beckingham <paul@beckingham.net>.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.TH task-faq 5 2010-05-22 "task 1.9.1" "User Manuals"
|
||||
.TH task-faq 5 2010-05-22 "task 1.9.2" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
task-faq \- A FAQ for the task(1) command line todo manager.
|
||||
@@ -12,6 +12,108 @@ has a rich list of commands that allow you to do various things with it.
|
||||
Welcome to the task FAQ. If you have would like to see a question answered
|
||||
here, please send us a note at <support@taskwarrior.org>.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.TP
|
||||
.B Q: When I redirect the output of task to a file, I lose all the colors. How do I fix this?
|
||||
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. This is based on
|
||||
the assumption that the color control codes are not wanted in the file. Prevent
|
||||
this with the following entry in your .taskrc file:
|
||||
|
||||
_forcecolor=on
|
||||
|
||||
.TP
|
||||
.B Q: How do I backup my task data files? Where are they?
|
||||
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.
|
||||
|
||||
.TP
|
||||
.B Q: How can I separate my work tasks from my home tasks? Specifically, can I keep them completely separate?
|
||||
A: You can do this by creating an alternate .taskrc file, then using shell
|
||||
aliases. Here are example Bash commands to achieve this:
|
||||
|
||||
% cp ~/.taskrc ~/.taskrc_home
|
||||
% (now edit .taskrc_home to change the value of data.location)
|
||||
% alias wtask="task"
|
||||
% alias htask="task rc:~/.taskrc_home"
|
||||
|
||||
This gives you two commands, 'wtask' and 'htask' that operate using two
|
||||
different sets of task data files.
|
||||
|
||||
.TP
|
||||
.B Q: Can I revert to a previous version of task? How?
|
||||
A: Yes, you can revert to a previous version of task, simply by downloading an
|
||||
older version and installing it. If you find a bug in task, then this may be the
|
||||
only way to work around the bug, until a patch release is made.
|
||||
|
||||
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!
|
||||
|
||||
.TP
|
||||
.B Q: I'm using Ubuntu 9.04, and I want task to word-wrap descriptions. How do I do this?
|
||||
A: You need to install ncurses, by doing this:
|
||||
|
||||
% sudo apt-get install libncurses5-dev
|
||||
|
||||
Then you need to rebuild task from scratch, starting with
|
||||
|
||||
% cd task-X.X.X
|
||||
% ./configure
|
||||
...
|
||||
|
||||
The result should be a task program that knows the width of the terminal window,
|
||||
and wraps accordingly.
|
||||
|
||||
Note that there are binary packages that all include this capability.
|
||||
|
||||
.TP
|
||||
.B Q: How do I build task under Cygwin?
|
||||
A: Task is built the same way everywhere. But under Cygwin, you'll need to make
|
||||
sure you have the following packages available first:
|
||||
|
||||
gcc
|
||||
make
|
||||
libncurses-devel
|
||||
libncurses8
|
||||
|
||||
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.
|
||||
|
||||
Note that there are binary packages that all include this capability.
|
||||
|
||||
.TP
|
||||
.B Q: Do colors work under Cygwin?
|
||||
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.
|
||||
|
||||
If you run the command:
|
||||
|
||||
% task colors
|
||||
|
||||
Task will display all the colors it can use, and you will see which ones you can use.
|
||||
|
||||
See the 'man task-color' for more details on which colors can be used.
|
||||
|
||||
.TP
|
||||
.B Q: Where does task store the data?
|
||||
By default, task creates a .taskrc file in your home directory and populates it
|
||||
@@ -161,6 +263,29 @@ Some of you may be familiar with DeMorgan's laws of formal logic that relate
|
||||
the AND and OR operators in terms of each other via negation, which can be used
|
||||
to construct task filters.
|
||||
|
||||
.TP
|
||||
.B Q: How do I delete an annotation?
|
||||
Task now has a 'denotate' command to remove annotations. First here is an
|
||||
example task:
|
||||
|
||||
$ task add Original task
|
||||
$ task 1 annotate foo
|
||||
$ task 1 annotate bar
|
||||
$ task 1 annotate foo bar
|
||||
|
||||
Now to delete the first annotation, use:
|
||||
|
||||
$ task 1 denotate foo
|
||||
|
||||
This takes the fragment 'foo' and compares it to each of the annotations. In
|
||||
this example, it will remove the first annotation, not the third, because it is
|
||||
an exact match. If there are no exact matches, it will remove the first
|
||||
non-exact match:
|
||||
|
||||
$ task 1 denotate ar
|
||||
|
||||
This will remove the second annotation - the first non-exact match.
|
||||
|
||||
.SH "CREDITS & COPYRIGHTS"
|
||||
task was written by P. Beckingham <paul@beckingham.net>.
|
||||
.br
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.TH task-tutorial 5 2010-05-22 "task 1.9.1" "User Manuals"
|
||||
.TH task-tutorial 5 2010-05-22 "task 1.9.2" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
task-tutorial \- A tutorial for the task(1) command line todo manager.
|
||||
@@ -358,6 +358,15 @@ To remove a tag from a task, use the minus sign:
|
||||
$ task 3 \-john
|
||||
.RE
|
||||
|
||||
To add a task that you have already completed, use the log command:
|
||||
.br
|
||||
.RS
|
||||
$ task log Notify postal service
|
||||
.RE
|
||||
|
||||
This is equivalent to first adding a new task, then marking that new task
|
||||
as done. It is simple a shortcut.
|
||||
|
||||
.SH Advanced usage of task
|
||||
Advanced examples of the usage of task can be found at the official site at
|
||||
<http://taskwarrior.org>
|
||||
|
||||
264
doc/man/task.1
264
doc/man/task.1
@@ -1,4 +1,4 @@
|
||||
.TH task 1 2010-05-22 "task 1.9.1" "User Manuals"
|
||||
.TH task 1 2010-05-22 "task 1.9.2" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
task \- A command line todo manager.
|
||||
@@ -11,6 +11,14 @@ 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.
|
||||
|
||||
At the core, task is a list processing program. You add text and additional
|
||||
related parameters and task redisplays the information in a nice way. It turns
|
||||
into a todo list program when you add due dates and recurrence. It turns into an
|
||||
organized todo list program when you add priorities, tags (one word descriptors),
|
||||
project groups, etc. Task turns into an organized to do list program when you
|
||||
modify the configuration file to have the output displayed the way you want to
|
||||
see it.
|
||||
|
||||
.SH SUBCOMMANDS
|
||||
|
||||
.TP
|
||||
@@ -18,17 +26,148 @@ has a rich list of subcommands that allow you to do various things with it.
|
||||
Adds a new task to the task list.
|
||||
|
||||
.TP
|
||||
.B append [tags] [attrs] description
|
||||
Appends information to an existing task.
|
||||
|
||||
.TP
|
||||
.B prepend [tags] [attrs] description
|
||||
Prepends information to an existing task.
|
||||
.B log [tags] [attrs] description
|
||||
Adds a new task that is already completed, to the task list.
|
||||
|
||||
.TP
|
||||
.B annotate ID description
|
||||
Adds an annotation to an existing task.
|
||||
|
||||
.TP
|
||||
.B denotate ID description
|
||||
Deletes an annotation for the specified task. If the provided description matches an
|
||||
annotation exactly, the corresponding annotation is deleted. If the provided description
|
||||
matches annotations partly, the first partly matched annotation is deleted.
|
||||
|
||||
.TP
|
||||
.B info ID
|
||||
Shows all data and metadata for the specified task.
|
||||
|
||||
.TP
|
||||
.B ID
|
||||
With an ID but no specific command, task runs the "info" command.
|
||||
|
||||
.TP
|
||||
.B undo
|
||||
Reverts the most recent action.
|
||||
|
||||
.TP
|
||||
.B shell
|
||||
Launches an interactive shell with all the task commands available.
|
||||
|
||||
.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 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 projects
|
||||
Lists all project names that are currently used by pending tasks, 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. Alias to history.monthly.
|
||||
|
||||
.TP
|
||||
.B history.annual
|
||||
Shows a report of task history by year.
|
||||
|
||||
.TP
|
||||
.B ghistory
|
||||
Shows a graphical report of task status by month. Alias to ghistory.monthly.
|
||||
|
||||
.TP
|
||||
.B ghistory.annual
|
||||
Shows a graphical report of task status by year.
|
||||
|
||||
.TP
|
||||
.B calendar [ y | due [y] | month year [y] | year ]
|
||||
Shows a monthly calendar with due tasks marked.
|
||||
|
||||
.TP
|
||||
.B stats
|
||||
Shows task database statistics.
|
||||
|
||||
.TP
|
||||
.B import \fIfile
|
||||
Imports tasks from a variety of formats.
|
||||
|
||||
.TP
|
||||
.B export
|
||||
Exports all tasks in CSV format. This command is an alias to the export.csv command.
|
||||
Redirect the output to a file, if you wish to save it, or pipe it to another command.
|
||||
|
||||
.TP
|
||||
.B export.ical
|
||||
Exports all tasks in iCalendar format.
|
||||
Redirect the output to a file, if you wish to save it, or pipe it to another command.
|
||||
|
||||
.TP
|
||||
.B color [sample]
|
||||
Displays all possible colors, or a sample.
|
||||
|
||||
.TP
|
||||
.B version
|
||||
Shows the task version number
|
||||
|
||||
.TP
|
||||
.B help
|
||||
Shows the long usage text.
|
||||
|
||||
.TP
|
||||
.B show [all | substring]"
|
||||
Shows all the current settings in the task configuration file. If a substring
|
||||
is specified just the settings containing that substring will be displayed.
|
||||
|
||||
.TP
|
||||
.B config [name [value | '']]
|
||||
Add, modify and remove settings directly in the task configuration.
|
||||
This command either modifies the 'name' setting with a new value of 'value',
|
||||
or adds a new entry that is equivalent to 'name=value':
|
||||
|
||||
task config name value
|
||||
|
||||
This command sets a blank value. This has the effect of suppressing any
|
||||
default value:
|
||||
|
||||
task config name ''
|
||||
|
||||
Finally, this command removes any 'name=...' entry from the .taskrc file:
|
||||
|
||||
task config name
|
||||
|
||||
.SH MODIFYING SUBCOMMANDS
|
||||
|
||||
.TP
|
||||
.B ID [tags] [attrs] [description]
|
||||
Modifies the existing task with provided information.
|
||||
@@ -47,108 +186,12 @@ Launches an editor to let you modify all aspects of a task directly.
|
||||
Use carefully.
|
||||
|
||||
.TP
|
||||
.B undo
|
||||
Reverts the most recent action.
|
||||
.B append [tags] [attrs] description
|
||||
Appends information to an existing task.
|
||||
|
||||
.TP
|
||||
.B shell
|
||||
Launches an interactive shell with all the task commands available.
|
||||
|
||||
.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 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 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 calendar [ y | due [y] | month year [y] | year ]
|
||||
Shows a monthly calendar with due tasks marked.
|
||||
|
||||
.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 [sample]
|
||||
Displays all possible colors, or a sample.
|
||||
|
||||
.TP
|
||||
.B version
|
||||
Shows the task version number
|
||||
|
||||
.TP
|
||||
.B config [name [value | '']]
|
||||
Shows the current settings in the task configuration file. Also supports
|
||||
directly modifying the .taskrc file. This command either modifies
|
||||
the 'name' setting with a new value of 'value', or adds a new entry that
|
||||
is equivalent to 'name=value':
|
||||
|
||||
task config name value
|
||||
|
||||
This command sets a blank value. This has the effect of suppressing any
|
||||
default value:
|
||||
|
||||
task config name ''
|
||||
|
||||
Finally, this command removes any 'name=...' entry from the .taskrc file:
|
||||
|
||||
task config name
|
||||
|
||||
.TP
|
||||
.B help
|
||||
Shows the long usage text.
|
||||
.B prepend [tags] [attrs] description
|
||||
Prepends information to an existing task.
|
||||
|
||||
.SH REPORT SUBCOMMANDS
|
||||
|
||||
@@ -258,7 +301,10 @@ Specifies background color.
|
||||
|
||||
.TP
|
||||
.B limit:<number-of-rows>
|
||||
Specifies the desired number of rows a report should have.
|
||||
Specifies the desired number of tasks a report should show, if a positive
|
||||
integer is given. The value 'page' may also be used, and will limit the
|
||||
report output to as many lines of text as will fit on screen. This defaults
|
||||
to 25 lines, if ncurses is not installed or enabled.
|
||||
|
||||
.TP
|
||||
.B wait:<wait-date>
|
||||
@@ -470,6 +516,8 @@ Copyright (C) 2006 \- 2010 P. Beckingham
|
||||
This man page was originally written by P.C. Shyamshankar, and has been modified
|
||||
and supplemented by Federico Hernandez.
|
||||
|
||||
Thank also to T. Charles Yun.
|
||||
|
||||
task is distributed under the GNU General Public License. See
|
||||
http://www.gnu.org/licenses/gpl-2.0.txt for more information.
|
||||
|
||||
|
||||
115
doc/man/taskrc.5
115
doc/man/taskrc.5
@@ -1,4 +1,4 @@
|
||||
.TH taskrc 5 2010-05-22 "task 1.9.1" "User Manuals"
|
||||
.TH taskrc 5 2010-05-22 "task 1.9.2" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
taskrc \- Configuration file for the task(1) command
|
||||
@@ -111,6 +111,18 @@ include <path/to/the/configuration/file/to/be/included>
|
||||
|
||||
By using include files you can divide your main configuration file into several ones containing just the relevant configuration data like colors, etc.
|
||||
|
||||
There are two excellent uses of includes in your .taskrc, shown here:
|
||||
|
||||
.RS
|
||||
include /usr/local/share/doc/task/rc/holidays-US.rc
|
||||
.br
|
||||
include /usr/local/share/doc/task/rc/dark-16.theme
|
||||
.RE
|
||||
|
||||
This includes two standard files that are distributed with task, which define a
|
||||
set of US holidays, and set up a 16-color theme for task to use, to color the
|
||||
reports and calendar.
|
||||
|
||||
.SH CONFIGURATION VARIABLES
|
||||
Valid variable names and their default values are:
|
||||
|
||||
@@ -212,12 +224,24 @@ May be yes or no, and determines whether the tab completion scripts consider all
|
||||
the project names you have used, or just the ones used in active tasks. The
|
||||
default value is "no".
|
||||
|
||||
.TP
|
||||
.B list.all.projects=yes
|
||||
May be yes or no, and determines whether 'projects' command lists all the project
|
||||
names you have used, or just the ones used in active tasks. The default value is
|
||||
"no".
|
||||
|
||||
.TP
|
||||
.B complete.all.tags=yes
|
||||
May be yes or no, and determines whether the tab completion scripts consider all
|
||||
the tag names you have used, or just the ones used in active tasks. The default
|
||||
value is "no".
|
||||
|
||||
.TP
|
||||
.B list.all.tags=yes
|
||||
May be yes or no, and determines whether the 'tags' command lists all the tag
|
||||
names you have used, or just the ones used in active tasks. The default value is
|
||||
"no".
|
||||
|
||||
.TP
|
||||
.B search.case.sensitive=yes
|
||||
May be yes or no, and determines whether keyword lookup and substitutions on the
|
||||
@@ -261,6 +285,19 @@ The character or string to show in the tag_indicator column. Defaults to +.
|
||||
.B recurrence.indicator=R
|
||||
The character or string to show in the recurrence_indicator column. Defaults to R.
|
||||
|
||||
.TP
|
||||
.B recurrence.limit=1
|
||||
The number of future recurring tasks to show. Defaults to 1. For example, if a
|
||||
weekly recurring task is added with a due date of tomorrow, and recurrence.limit
|
||||
is set to 2, then a report will list 2 pending recurring tasks, one for tomorrow,
|
||||
and one for a week from tomorrow.
|
||||
|
||||
.TP
|
||||
.B undo.style=side
|
||||
When the 'undo' command is run, task presents a before and after comparison of the
|
||||
data. This can be in either the 'side' style, which compares values side-by-side
|
||||
in a table, or 'diff' style, which uses a format similar to the 'diff' command.
|
||||
|
||||
.TP
|
||||
.B debug=off
|
||||
Task has a debug mode that causes diagnostic output to be displayed. Typically
|
||||
@@ -273,7 +310,8 @@ way.
|
||||
.B alias.rm=delete
|
||||
Task supports command aliases. This alias provides an alternate name (rm) for
|
||||
the delete command. You can use aliases to provide alternate names for any of
|
||||
task's commands.
|
||||
task's commands. Several commands you may use are actually aliases - 'history',
|
||||
for example, or 'export'.
|
||||
|
||||
.SS DATES
|
||||
|
||||
@@ -284,6 +322,8 @@ task's commands.
|
||||
.TP
|
||||
.B dateformat.holiday=YMD
|
||||
.TP
|
||||
.B dateformat.annotation=m/d/Y
|
||||
.TP
|
||||
.B report.X.dateformat=m/d/Y
|
||||
This is a string of characters that define how task formats date values. The
|
||||
precedence order for the configuration variable is report.X.dateformat then
|
||||
@@ -318,6 +358,12 @@ b short name of month, for example Jan or Aug
|
||||
B long name of month, for example January or August
|
||||
.br
|
||||
V weeknumber, for example 03 or 37
|
||||
.br
|
||||
H two-digit hour, for example 03 or 11
|
||||
.br
|
||||
N two-digit minutes, for example 05 or 42
|
||||
.br
|
||||
S two-digit seconds, for example 07 or 47
|
||||
.RE
|
||||
.RE
|
||||
|
||||
@@ -427,6 +473,16 @@ holiday.eastersunday.date=easter
|
||||
.RE
|
||||
.RE
|
||||
|
||||
Note that the task distribution contains example holiday files that can be
|
||||
included like this:
|
||||
|
||||
.RS
|
||||
.RS
|
||||
.br
|
||||
include /usr/local/share/doc/task/rc/holidays-US.rc
|
||||
.RE
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B monthsperline=3
|
||||
Determines how many months the "task calendar" command renders across the
|
||||
@@ -444,6 +500,7 @@ use dashes (-----) to underline column headings.
|
||||
.B fontunderline=on
|
||||
Determines if font underlines or ASCII dashes should be used to underline
|
||||
headers, even when color is enabled.
|
||||
.RE
|
||||
|
||||
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
|
||||
@@ -458,7 +515,6 @@ terminal, can be obtained by running the command:
|
||||
The coloration rules and their defaults are:
|
||||
.RE
|
||||
|
||||
.RS
|
||||
.RS
|
||||
.B color.overdue=bold red
|
||||
The color for overdue tasks.
|
||||
@@ -500,82 +556,113 @@ nothing, for example:
|
||||
.RE
|
||||
.RE
|
||||
|
||||
.RS
|
||||
See the task-color(5) man pages for color details.
|
||||
.RE
|
||||
|
||||
.RS
|
||||
Certain attributes like tags, projects and keywords can have their own
|
||||
coloration rules.
|
||||
.RE
|
||||
|
||||
.RS
|
||||
.TP
|
||||
.B color.tag.X=yellow
|
||||
Colors any task that has the tag X.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B color.project.X=on green
|
||||
Colors any task assigned to project X.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B color.keyword.X=on blue
|
||||
Colors any task where the description or any annotation contains X.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B color.header=green
|
||||
Colors any of the messages printed prior to the report output.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B color.footnote=green
|
||||
Colors any of the messages printed last.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B color.summary.bar=on green
|
||||
Colors the summary progress bar. Should include both a foreground and a
|
||||
background color.
|
||||
Colors the summary progress bar. Should consist of a background color.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B color.summary.background=on black
|
||||
Colors the summary progress bar. Should include at least a background color.
|
||||
Colors the summary progress bar. Should consist of a background color.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B color.calendar.today=black on cyan
|
||||
Color of today in calendar.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B color.calendar.due=black on green
|
||||
Color of days with due tasks in calendar.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B color.calendar.due.today=black on magenta
|
||||
Color of today with due tasks in calendar.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B color.calendar.overdue=black on red
|
||||
Color of days with overdue tasks in calendar.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B color.calendar.weekend=bright white on black
|
||||
Color of weekend days in calendar.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B color.calendar.holiday=black on bright yellow
|
||||
Color of holidays in calendar.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B color.calendar.weeknumber=black on white
|
||||
Color of weeknumbers in calendar.
|
||||
.RE
|
||||
|
||||
.RS
|
||||
It is possible to apply a specific color to every other task in a report,
|
||||
which can make it easier to visually separate tasks. This is especially
|
||||
useful when tasks are displayed over multiple lines due to long descriptions
|
||||
or annotations.
|
||||
.TP
|
||||
.B color.alternate=on rgb253
|
||||
Color of alternate tasks.
|
||||
This is to apply a specific color to every other task in a report,
|
||||
which can make it easier to visually separate tasks. This is especially
|
||||
useful when tasks are displayed over multiple lines due to long descriptions
|
||||
or annotations.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B color.history.add=on red
|
||||
.RE
|
||||
.br
|
||||
.B color.history.done=on green
|
||||
.RE
|
||||
.br
|
||||
.B color.history.delete=on yellow
|
||||
.RS
|
||||
Colors the bars on the ghistory report graphs. Defaults to red, green and
|
||||
yellow bars.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B color.undo.before=red
|
||||
.RE
|
||||
.br
|
||||
.B color.undo.after=green
|
||||
.RS
|
||||
Colors used by the undo command, to indicate the values both before and after
|
||||
a change that is to be reverted.
|
||||
.RE
|
||||
|
||||
.SS SHADOW FILE
|
||||
|
||||
@@ -1 +1,37 @@
|
||||
# Sample task 1.9 (or later) color theme
|
||||
# Sample task 1.9 (or later) dark 16-color theme
|
||||
|
||||
color=on
|
||||
color.header=yellow
|
||||
color.footnote=yellow
|
||||
color.debug=yellow
|
||||
|
||||
color.summary.bar=on green
|
||||
color.summary.background=on black
|
||||
|
||||
color.history.add=black on red
|
||||
color.history.done=black on green
|
||||
color.history.delete=black on yellow
|
||||
|
||||
color.undo.before=red
|
||||
color.undo.after=green
|
||||
|
||||
color.calendar.today=bold white on bright blue
|
||||
color.calendar.due=white on red
|
||||
color.calendar.due.today=bold white on red
|
||||
color.calendar.overdue=black on bright red
|
||||
color.calendar.weekend=white on bright black
|
||||
color.calendar.holiday=black on bright yellow
|
||||
color.calendar.weeknumber=bold blue
|
||||
|
||||
color.recurring=magenta
|
||||
color.overdue=bold red
|
||||
color.due.today=red
|
||||
color.due=red
|
||||
color.active=black on bright green
|
||||
color.pri.none=
|
||||
color.pri.H=bold white
|
||||
color.pri.M=white
|
||||
color.pri.L=
|
||||
color.tagged=green
|
||||
color.alternate=
|
||||
|
||||
|
||||
@@ -1 +1,37 @@
|
||||
# Sample task 1.9 (or later) color theme
|
||||
# Sample task 1.9 (or later) dark 256-color theme
|
||||
|
||||
color=on
|
||||
color.header=color3
|
||||
color.footnote=color3
|
||||
color.debug=color3
|
||||
|
||||
color.summary.bar=on rgb141
|
||||
color.summary.background=on color0
|
||||
|
||||
color.history.add=color0 on rgb500
|
||||
color.history.done=color0 on rgb050
|
||||
color.history.delete=color0 on rgb550
|
||||
|
||||
color.undo.before=color1
|
||||
color.undo.after=color2
|
||||
|
||||
color.calendar.today=color15 on rgb013
|
||||
color.calendar.due=color0 on color1
|
||||
color.calendar.due.today=color15 on color1
|
||||
color.calendar.overdue=color0 on color9
|
||||
color.calendar.weekend=on color235
|
||||
color.calendar.holiday=color0 on color11
|
||||
color.calendar.weeknumber=rgb013
|
||||
|
||||
color.recurring=rgb013
|
||||
color.overdue=color9
|
||||
color.due.today=rgb400
|
||||
color.due=color1
|
||||
color.active=rgb555 on rgb410
|
||||
color.pri.none=
|
||||
color.pri.H=color255
|
||||
color.pri.M=color250
|
||||
color.pri.L=color245
|
||||
color.tagged=rgb031
|
||||
color.alternate=on color233
|
||||
|
||||
|
||||
37
doc/rc/dark-blue-256.theme
Normal file
37
doc/rc/dark-blue-256.theme
Normal file
@@ -0,0 +1,37 @@
|
||||
# Sample task 1.9 (or later) dark 256-color theme, featuring blue.
|
||||
|
||||
color=on
|
||||
color.header=rgb013
|
||||
color.footnote=rgb013
|
||||
color.debug=rgb013
|
||||
|
||||
color.summary.bar=on rgb003
|
||||
color.summary.background=on color0
|
||||
|
||||
color.history.add=color0 on rgb015
|
||||
color.history.done=color0 on rgb025
|
||||
color.history.delete=color0 on rgb035
|
||||
|
||||
color.undo.before=rgb013
|
||||
color.undo.after=rgb035
|
||||
|
||||
color.calendar.today=color0 on rgb115
|
||||
color.calendar.due=color0 on color249
|
||||
color.calendar.due.today=color0 on color252
|
||||
color.calendar.overdue=color0 on color255
|
||||
color.calendar.weekend=on color235
|
||||
color.calendar.holiday=color255 on rgb013
|
||||
color.calendar.weeknumber=rgb015
|
||||
|
||||
color.recurring=rgb115
|
||||
color.overdue=color255
|
||||
color.due.today=color252
|
||||
color.due=color249
|
||||
color.active=rgb045 on rgb015
|
||||
color.pri.none=
|
||||
color.pri.H=rgb035
|
||||
color.pri.M=rgb025
|
||||
color.pri.L=rgb015
|
||||
color.tagged=color246
|
||||
color.alternate=on color233
|
||||
|
||||
37
doc/rc/dark-green-256.theme
Normal file
37
doc/rc/dark-green-256.theme
Normal file
@@ -0,0 +1,37 @@
|
||||
# Sample task 1.9 (or later) dark 256-color theme, featuring green.
|
||||
|
||||
color=on
|
||||
color.header=rgb031
|
||||
color.footnote=rgb031
|
||||
color.debug=rgb031
|
||||
|
||||
color.summary.bar=on rgb030
|
||||
color.summary.background=on color0
|
||||
|
||||
color.history.add=color0 on rgb010
|
||||
color.history.done=color0 on rgb030
|
||||
color.history.delete=color0 on rgb050
|
||||
|
||||
color.undo.before=rgb031
|
||||
color.undo.after=rgb053
|
||||
|
||||
color.calendar.today=color0 on rgb151
|
||||
color.calendar.due=color0 on color249
|
||||
color.calendar.due.today=color0 on color225
|
||||
color.calendar.overdue=color0 on color255
|
||||
color.calendar.weekend=on color235
|
||||
color.calendar.holiday=rgb151 on rgb020
|
||||
color.calendar.weeknumber=rgb010
|
||||
|
||||
color.recurring=rgb151
|
||||
color.overdue=color255
|
||||
color.due.today=color252
|
||||
color.due=color249
|
||||
color.active=rgb050 on rgb010
|
||||
color.pri.none=
|
||||
color.pri.H=rgb050
|
||||
color.pri.M=rgb030
|
||||
color.pri.L=rgb010
|
||||
color.tagged=color246
|
||||
color.alternate=on color233
|
||||
|
||||
37
doc/rc/dark-red-256.theme
Normal file
37
doc/rc/dark-red-256.theme
Normal file
@@ -0,0 +1,37 @@
|
||||
# Sample task 1.9 (or later) dark 256-color theme, featuring red.
|
||||
|
||||
color=on
|
||||
color.header=rgb100
|
||||
color.footnote=rgb100
|
||||
color.debug=rgb100
|
||||
|
||||
color.summary.bar=on rgb300
|
||||
color.summary.background=on color0
|
||||
|
||||
color.history.add=color0 on rgb100
|
||||
color.history.done=color0 on rgb300
|
||||
color.history.delete=color0 on rgb500
|
||||
|
||||
color.undo.before=rgb301
|
||||
color.undo.after=rgb503
|
||||
|
||||
color.calendar.today=color0 on rgb511
|
||||
color.calendar.due=color0 on color249
|
||||
color.calendar.due.today=color0 on color252
|
||||
color.calendar.overdue=color0 on color255
|
||||
color.calendar.weekend=on color235
|
||||
color.calendar.holiday=rgb522 on rgb300
|
||||
color.calendar.weeknumber=rgb100
|
||||
|
||||
color.recurring=rgb511
|
||||
color.overdue=color255
|
||||
color.due.today=color252
|
||||
color.due=color249
|
||||
color.active=rgb500 on rgb100
|
||||
color.pri.none=
|
||||
color.pri.H=rgb500
|
||||
color.pri.M=rgb400
|
||||
color.pri.L=rgb300
|
||||
color.tagged=color246
|
||||
color.alternate=on color233
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
calendar.holidays=sparse
|
||||
|
||||
holiday.nyårsdagen.name=Nyårsdagen
|
||||
holiday.nyårsdagen.date=20100101
|
||||
holiday.trettondedagjul.name=Trettondedag jul
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
calendar.holidays=sparse
|
||||
|
||||
holiday.newyearsday.name=New Years Day
|
||||
holiday.newyearsday.date=20100101
|
||||
holiday.martinlutherkingday.name=Martin Luther King Day
|
||||
|
||||
@@ -1 +1,37 @@
|
||||
# Sample task 1.9 (or later) color theme
|
||||
# Sample task 1.9 (or later) light 16-color theme
|
||||
|
||||
color=on
|
||||
color.header=blue
|
||||
color.footnote=blue
|
||||
color.debug=blue
|
||||
|
||||
color.summary.bar=on green
|
||||
color.summary.background=on black
|
||||
|
||||
color.history.add=black on red
|
||||
color.history.done=black on green
|
||||
color.history.delete=black on yellow
|
||||
|
||||
color.undo.before=red
|
||||
color.undo.after=green
|
||||
|
||||
color.calendar.today=black on bright blue
|
||||
color.calendar.due=white on red
|
||||
color.calendar.due.today=bold white on red
|
||||
color.calendar.overdue=black on bright red
|
||||
color.calendar.weekend=white on bright black
|
||||
color.calendar.holiday=black on yellow
|
||||
color.calendar.weeknumber=bold blue
|
||||
|
||||
color.recurring=blue
|
||||
color.overdue=bold red
|
||||
color.due.today=red
|
||||
color.due=red
|
||||
color.active=black on green
|
||||
color.pri.none=
|
||||
color.pri.H=bold black
|
||||
color.pri.M=black
|
||||
color.pri.L=
|
||||
color.tagged=green
|
||||
color.alternate=
|
||||
|
||||
|
||||
@@ -1 +1,37 @@
|
||||
# Sample task 1.9 (or later) color theme
|
||||
# Sample task 1.9 (or later) light 256-color theme
|
||||
|
||||
color=on
|
||||
color.header=color4
|
||||
color.footnote=color4
|
||||
color.debug=color4
|
||||
|
||||
color.summary.bar=on rgb141
|
||||
color.summary.background=on color0
|
||||
|
||||
color.history.add=color0 on rgb500
|
||||
color.history.done=color0 on rgb050
|
||||
color.history.delete=color0 on rgb550
|
||||
|
||||
color.undo.before=color1
|
||||
color.undo.after=color2
|
||||
|
||||
color.calendar.today=color15 on rgb013
|
||||
color.calendar.due=color0 on color9
|
||||
color.calendar.due.today=color15 on color1
|
||||
color.calendar.overdue=color0 on color1
|
||||
color.calendar.weekend=on color253
|
||||
color.calendar.holiday=color0 on color3
|
||||
color.calendar.weeknumber=rgb013
|
||||
|
||||
color.recurring=rgb013
|
||||
color.overdue=color1
|
||||
color.due.today=rgb400
|
||||
color.due=color9
|
||||
color.active=rgb555 on rgb520
|
||||
color.pri.none=
|
||||
color.pri.H=color232
|
||||
color.pri.M=color237
|
||||
color.pri.L=color242
|
||||
color.tagged=rgb020
|
||||
color.alternate=on color254
|
||||
|
||||
|
||||
@@ -40,10 +40,9 @@
|
||||
208 done
|
||||
209 duplicate
|
||||
210 edit
|
||||
211 export
|
||||
|
||||
212 help
|
||||
213 history
|
||||
214 ghistory
|
||||
|
||||
215 import
|
||||
216 info
|
||||
217 prepend
|
||||
@@ -55,10 +54,12 @@
|
||||
223 summary
|
||||
224 tags
|
||||
225 timesheet
|
||||
|
||||
226 log
|
||||
227 undo
|
||||
228 version
|
||||
229 shell
|
||||
230 config
|
||||
231 show
|
||||
|
||||
# 3xx Attributes - must be sequential
|
||||
300 project
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: task
|
||||
Version: 1.8.1
|
||||
Version: 1.9.1
|
||||
Release: 1%{?dist}
|
||||
Summary: A command-line to do list manager
|
||||
|
||||
@@ -17,7 +17,7 @@ support for GTD functionality and includes the
|
||||
following features: tags, colorful tabular output,
|
||||
reports and graphs, lots of manipulation commands,
|
||||
low-level API, abbreviations for all commands and
|
||||
options, multiuser file locking, recurring tasks.
|
||||
options, multi-user file locking, recurring tasks.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
@@ -40,15 +40,37 @@ rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%doc AUTHORS ChangeLog COPYING NEWS README scripts i18n
|
||||
%doc AUTHORS ChangeLog COPYING NEWS README scripts i18n doc/rc
|
||||
%{_bindir}/task
|
||||
%{_mandir}/man1/task.1.gz
|
||||
%{_mandir}/man5/taskrc.5.gz
|
||||
%{_mandir}/man5/task-tutorial.5.gz
|
||||
%{_mandir}/man5/task-color.5.gz
|
||||
%{_mandir}/man5/task-faq.5.gz
|
||||
%config(noreplace) %{_sysconfdir}/bash_completion.d
|
||||
|
||||
|
||||
%changelog
|
||||
* Mon May 22 2010 Federico Hernandez <ultrafredde@gmail.com> - 1.9.1-1
|
||||
Intial RPM for task beta release 1.9.1
|
||||
* Mon Feb 22 2010 Federico Hernandez <ultrafredde@gmail.com> - 1.9.0-1
|
||||
Intial RPM for task beta release 1.9.0
|
||||
* Mon Feb 15 2010 Federico Hernandez <ultrafredde@gmail.com> - 1.9.0.beta3-1
|
||||
Intial RPM for task beta release 1.9.0.beta3
|
||||
* Mon Feb 08 2010 Federico Hernandez <ultrafredde@gmail.com> - 1.9.0.beta2-1
|
||||
Intial RPM for task beta release 1.9.0.beta2
|
||||
* Wed Feb 03 2010 Federico Hernandez <ultrafredde@gmail.com> - 1.9.0.beta1-1
|
||||
Intial RPM for task beta release 1.9.0.beta1
|
||||
* Sat Dec 05 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.8.5-2
|
||||
Fixed wrong ChangeLog file
|
||||
* Sat Dec 05 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.8.5-1
|
||||
Intial RPM for task bugfix release 1.8.5
|
||||
* Tue Nov 17 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.8.4-1
|
||||
Intial RPM for task bugfix release 1.8.4
|
||||
* Wed Oct 21 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.8.3-1
|
||||
Intial RPM for task bugfix release 1.8.3
|
||||
* Mon Sep 07 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.8.2-1
|
||||
Intial RPM for task bugfix release 1.8.2
|
||||
* Thu Aug 20 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.8.1-1
|
||||
Intial RPM for task bugfix release 1.8.1
|
||||
* Tue Jul 21 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.8.0-1
|
||||
@@ -60,12 +82,12 @@ rm -rf $RPM_BUILD_ROOT
|
||||
* Tue Jul 07 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.8.0.beta1-1
|
||||
Intial RPM for task beta release 1.8.0.beta1
|
||||
* Tue Jun 08 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.7.1-2
|
||||
- Fixed inclusion of manpages.
|
||||
Fixed inclusion of manpages.
|
||||
* Tue Jun 08 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.7.1-1
|
||||
- Initial RPM for bugfix release 1.7.1.
|
||||
- Updated references to new project homepage in spec file.
|
||||
Initial RPM for bugfix release 1.7.1.
|
||||
Updated references to new project homepage in spec file.
|
||||
* Tue May 19 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.7.0-2
|
||||
- Changed license to GPLv2+ and removed Requires macro.
|
||||
- See https://bugzilla.redhat.com/show_bug.cgi?id=501498
|
||||
Changed license to GPLv2+ and removed Requires macro.
|
||||
See https://bugzilla.redhat.com/show_bug.cgi?id=501498
|
||||
* Tue May 19 2009 Federico Hernandez <ultrafredde@gmail.com> - 1.7.0-1
|
||||
- Initial RPM.
|
||||
Initial RPM.
|
||||
|
||||
BIN
package-config/osx/OSX-packaging.pdf
Normal file
BIN
package-config/osx/OSX-packaging.pdf
Normal file
Binary file not shown.
278
package-config/osx/README
Normal file
278
package-config/osx/README
Normal file
@@ -0,0 +1,278 @@
|
||||
How to make an OSX package
|
||||
--------------------------
|
||||
|
||||
Note: This is being written from the OSX 10.6 perspective, and may therefore
|
||||
contain steps that are different for 10.5, although I don't recall any
|
||||
actual differences.
|
||||
|
||||
|
||||
0. Philosophy
|
||||
|
||||
Only Fredde tags releases. We only make builds from tagged commits. We
|
||||
only release builds that build cleanly without errors or warnings. We only
|
||||
release builds that pass 100% of the unit tests.
|
||||
|
||||
|
||||
1. Prerequisites
|
||||
|
||||
You will need an Intel Mac, running OSX 10.5 or later.
|
||||
You will need to install the Developer Tools, which are found on your OSX DVD.
|
||||
You will need git installed, version 1.5 or later. See http://git-scm.com
|
||||
You will need autotools installed. See http://www.gnu.org/software/autoconf
|
||||
|
||||
2. Get the code
|
||||
|
||||
2.1 Clone the task git repository. It is important that this is a throwaway
|
||||
clone of the repository, because we will do (locally) destructive things
|
||||
to it.
|
||||
|
||||
$ git clone git://tasktools.org/task.git ~/task-package.git
|
||||
...
|
||||
$ cd ~/task-package.git
|
||||
|
||||
2.2 Making sure you have the right version of the code. This assumes you are
|
||||
building task 1.9.2, but any version number is interchangeable. Check out
|
||||
the correct branch, and make sure it is sitting at the correct commit, via
|
||||
a tag. Note that while 1.9.2 is a branch name, v1.9.2 is a tag name.
|
||||
|
||||
$ git checkout 1.9.2
|
||||
$ git reset --hard v1.9.2
|
||||
|
||||
If there is an error in this step, stop, capture the output, and report the
|
||||
errors.
|
||||
|
||||
3. Build task
|
||||
|
||||
3.1 First build the task binary. Note the "-j 2" tells make to use both cores
|
||||
in your dual-core Intel CPU, which means faster compiles. If you own a quad
|
||||
core Mac, use "-j 4". If you own a single core Mac, just type "make".
|
||||
|
||||
$ autoreconf -f
|
||||
$ ./configure
|
||||
...
|
||||
|
||||
If any errors are reported, stop, capture the output, and report the errors.
|
||||
|
||||
$ make -j 2
|
||||
|
||||
If there are any errors, or there are any warnings generated by the compiler
|
||||
stop, capture the output, and report the problem. You'll need to watch as
|
||||
it builds.
|
||||
|
||||
4. Build the test suite
|
||||
|
||||
4.1 The test suite exists to prove that we do not break task features from one
|
||||
release to the next. While this is not a perfect solution, it has saved us
|
||||
many times from releasing code that is inferior.
|
||||
|
||||
The first step is to modify the test suite Makefile to remove the Lua line.
|
||||
This is because we do not yet have dynamic detection of the Lua library for
|
||||
the unit tests.
|
||||
|
||||
$ cd ~/task-package.git/src/tests
|
||||
$ vi Makefile
|
||||
|
||||
Any text editor will do, but look for this line (line 5):
|
||||
|
||||
LFLAGS = -L/usr/local/lib -lncurses -llua
|
||||
|
||||
and change it to:
|
||||
|
||||
LFLAGS = -L/usr/local/lib -lncurses
|
||||
|
||||
Now build the unit tests:
|
||||
|
||||
$ make -j 2
|
||||
...
|
||||
|
||||
4.2 Run all the unit tests.
|
||||
|
||||
$ ./run_all
|
||||
Skipping benchmarks
|
||||
|
||||
Pass: 4241
|
||||
Fail: 0
|
||||
Skipped: 0
|
||||
Runtime: 86
|
||||
|
||||
The output should look something like this, with 0 failed, and 0 skipped
|
||||
tests. If there are any failures or skips, stop and mailed the log file,
|
||||
named 'all.log' to Paul & Fredde.
|
||||
|
||||
5. Assemble the parts
|
||||
|
||||
5.1 There is a script that copies all the necessary files (binary, man pages
|
||||
etc) in the right place, ready for packaging. Run this:
|
||||
|
||||
$ cd ~/task-package.git/package-config/osx
|
||||
$ ./update
|
||||
|
||||
6. Adjust the package details
|
||||
|
||||
6.1 Launch the package manager.
|
||||
|
||||
$ open -a /Developer/Applications/Utilies/PackageManager.app
|
||||
|
||||
6.2 Close the 'Untitled' window that opens - we will be using a different
|
||||
file. Note that PackageManager is still running - it just has no windows.
|
||||
|
||||
6.3 Using the File -> Open menu, open the file
|
||||
|
||||
~/task-package.git/package-config/osx/task.pmdoc
|
||||
|
||||
<figure 1>
|
||||
|
||||
This is the file from the last time a package was created. It needs some
|
||||
adjustments. Start by clicking on the "Task x.x.x Distribution" with a
|
||||
package icon in the top left part of the window.
|
||||
|
||||
6.4 Click on the "Configuration" button/tab.
|
||||
|
||||
- Change the "Title" to "Task 1.9.2"
|
||||
- Change the "Description" to "Task 1.9.2 install for Snow Leopard"
|
||||
|
||||
<figure 2>
|
||||
|
||||
6.5 Click on "Edit Interface..."
|
||||
|
||||
There are 5 radio buttons on the left hand side - we will visit each and
|
||||
make changes. Click on "Background", make sure it matches the figure.
|
||||
|
||||
<figure 3>
|
||||
|
||||
Click on "Introduction", make sure it matches the figure.
|
||||
|
||||
<figure 4>
|
||||
|
||||
Click on "Read Me", and on the right hand side, under "Read Me Panel", click
|
||||
on "File" and select the file:
|
||||
|
||||
/Users/<your-account>/task-package.git/package-config/osx/README.txt
|
||||
|
||||
<figure 5>
|
||||
|
||||
Click on "License", and on the right hand side, under "License Panel", click
|
||||
on "File" and select the file:
|
||||
|
||||
/Users/<your-account>/task-package.git/package-config/osx/COPYING.txt
|
||||
|
||||
<figure 6>
|
||||
|
||||
Click on "Finish Up", and make sure it matches the figure.
|
||||
|
||||
<figure 7>
|
||||
|
||||
Close the Interface Editor window (it saves automatically).
|
||||
|
||||
6.6 Back in the "task.pmdoc" window, click on the "Requirements" tab/button,
|
||||
then click on the "+" button, and add a requirement rule as shown in the
|
||||
figure. The minimum system should be 10.5.0 or 10.6.0, depending on which
|
||||
package is being built.
|
||||
|
||||
<figure 8>
|
||||
|
||||
6.7 Click on the "Actions" tab/button and make sure it matches the figure.
|
||||
|
||||
<figure 9>
|
||||
|
||||
6.8 Click on the triangle next to the "local" item in the "Contents" vertical
|
||||
bar on the left to expand and show a folder called "local", with the path
|
||||
"/usr/local", but click on the "local" next to the blue radio button, not
|
||||
the one next to the folder. Then click on the "Configuration" tab/button.
|
||||
|
||||
- Change the "Choice Name" to "local"
|
||||
- Leave the "Identifier" alone - it is automatic
|
||||
- Make sure "Selected" and "Enabled" are checked, but "Hidden" is not
|
||||
|
||||
<figure 10>
|
||||
|
||||
6.9 Click on the "Requirements" tab/button and make sure it is all blank.
|
||||
|
||||
<figure 11>
|
||||
|
||||
6.10 Click on the blue folder on the left, which is labelled "local", and has
|
||||
a path of "/usr/local". Click on the "Configuration" tab/button.
|
||||
|
||||
- Change the "Install" to /Users/<your-account>/task-package.git/package-config/osx/local
|
||||
- Make sure the "Destination" is "/usr/local"
|
||||
- Make sure "Allow custom location" is checked
|
||||
- Make sure the "Package Identifier is "com.beckingham.task192.local.pkg"
|
||||
- Make sure the "Package Version" is 1.0. If you needed to make a
|
||||
subsequent OSX package, *for the same version of task*, then this number
|
||||
would be increased to show OSX that this package supersedes the earlier
|
||||
one
|
||||
- Make sure "Restart Action" is "None"
|
||||
- Make sure "Require admin authentication" is checked
|
||||
- Make sure "PAckage Location" is "Self-Contained"
|
||||
|
||||
<figure 12>
|
||||
|
||||
6.11 Click on the "Contents" tab/button.
|
||||
|
||||
- Click on all the triangles in the "local" folder to expand all directories
|
||||
- Make sure "Include root in package is not checked"
|
||||
- Click on the "Apply Recommendations" button
|
||||
|
||||
Make sure it matches the figure.
|
||||
|
||||
<figure 13>
|
||||
|
||||
6.12 Click on the "Components" tab/button, make sure it is all blank.
|
||||
|
||||
6.13 Click on the "Scripts" tab/button, make sure it is all blank.
|
||||
|
||||
7. Building the package
|
||||
|
||||
7.1 Click on the "Build" hammer icon to build the package.
|
||||
|
||||
Provide a filename of "task-1.9.1-sl.pkg" for Snow Leopard (10.6), or
|
||||
"task-1.9.2.pkg" for Leopard (10.5), and save it somewhere, for example the
|
||||
Desktop.
|
||||
|
||||
All should succeed. You can click on the "Return" button to end the build
|
||||
phase, and you can quit PackageManager, but make sure you save the changes
|
||||
you made, because you may need to go through the whole process again, if there
|
||||
is an emergency change, or the package is somehow corrupt.
|
||||
|
||||
<figure 14>
|
||||
|
||||
8. Test the package
|
||||
|
||||
8.1 Double-click on the package you just created, and install task. You
|
||||
should see the README file in the UI, and the COPYING file on another
|
||||
page. It should succeed.
|
||||
|
||||
<figure 14>
|
||||
<figure 15>
|
||||
<figure 16>
|
||||
<figure 17>
|
||||
<figure 18>
|
||||
<figure 19>
|
||||
<figure 20>
|
||||
<figure 21>
|
||||
|
||||
8.2 Run the following commands to test the installation
|
||||
|
||||
$ /usr/local/bin/task version
|
||||
|
||||
task 1.9.2 built for darwin-ncurses
|
||||
Copyright (C) 2006 - 2010 P. Beckingham, F. Hernandez.
|
||||
|
||||
Task may be copied only under the terms of the GNU General Public License,
|
||||
which may be found in the task source kit.
|
||||
|
||||
Documentation for task can be found using 'man task', 'man taskrc', 'man
|
||||
task-tutorial', 'man task-color', 'man task-faq' or at http://taskwarrior.org
|
||||
|
||||
$ man task
|
||||
...
|
||||
...
|
||||
task 1.9.2 2010-05-22 task 1.9.2
|
||||
|
||||
The man page should list 1.9.2 as the version number, but the date will be
|
||||
different.
|
||||
|
||||
9. Email the package to Fredde.
|
||||
|
||||
---
|
||||
|
||||
@@ -1 +1 @@
|
||||
<pkg-contents spec="1.12"><f n="local" o="root" g="staff" p="16877" pt="/Users/paul/task-1.9.0.git/package-config/osx/local" m="false" t="file"><f n="bin" o="root" g="wheel" p="16877"><f n="task" o="root" g="wheel" p="33261"><mod>mode</mod><mod>owner</mod></f><mod>owner</mod></f><f n="share" o="root" g="wheel" p="16877"><f n="doc" o="root" g="wheel" p="16877"><f n="task" o="root" g="wheel" p="16877"><f n="AUTHORS" o="root" g="wheel" p="33188"><mod>mode</mod><mod>owner</mod></f><f n="ChangeLog" o="root" g="wheel" p="33188"><mod>mode</mod><mod>owner</mod></f><f n="COPYING" o="root" g="wheel" p="33188"><mod>mode</mod><mod>owner</mod></f><f n="NEWS" o="root" g="wheel" p="33188"><mod>mode</mod><mod>owner</mod></f><f n="README" o="root" g="wheel" p="33188"><mod>mode</mod><mod>owner</mod></f><f n="scripts" o="root" g="wheel" p="16877"><f n="bash" o="root" g="wheel" p="16877"><f n="task_completion.sh" o="root" g="wheel" p="33188"><mod>owner</mod><mod>mode</mod><mod>group</mod></f><mod>mode</mod><mod>owner</mod></f><f n="vim" o="root" g="wheel" p="16877"><f n="ftdetect" o="root" g="wheel" p="16877"><f n="task.vim" o="root" g="wheel" p="33188"><mod>mode</mod></f><mod>mode</mod></f><f n="README" o="root" g="wheel" p="33188"><mod>mode</mod></f><f n="syntax" o="root" g="wheel" p="16877"><f n="taskdata.vim" o="root" g="wheel" p="33188"><mod>mode</mod></f><f n="taskedit.vim" o="root" g="wheel" p="33188"><mod>mode</mod></f><f n="taskrc.vim" o="root" g="wheel" p="33188"><mod>mode</mod></f><mod>mode</mod></f><mod>mode</mod></f><f n="zsh" o="root" g="wheel" p="16877"><f n="_task" o="root" g="wheel" p="33188"><mod>mode</mod></f><mod>mode</mod></f><mod>mode</mod><mod>owner</mod></f><mod>mode</mod><mod>owner</mod></f><mod>mode</mod><mod>owner</mod></f><f n="man" o="root" g="wheel" p="16877"><f n="man1" o="root" g="wheel" p="16877"><f n="task.1" o="root" g="wheel" p="33188"><mod>mode</mod></f><mod>mode</mod></f><f n="man5" o="root" g="wheel" p="16877"><f n="task-color.5" o="root" g="wheel" p="33188"><mod>mode</mod></f><f n="task-faq.5" o="root" g="wheel" p="33188"><mod>mode</mod></f><f n="task-tutorial.5" o="root" g="wheel" p="33188"><mod>mode</mod></f><f n="taskrc.5" o="root" g="wheel" p="33188"><mod>mode</mod></f><mod>mode</mod></f><mod>mode</mod></f><mod>mode</mod><mod>owner</mod></f><mod>owner</mod></f></pkg-contents>
|
||||
<pkg-contents spec="1.12"><f n="local" o="root" g="wheel" p="16877" pt="/Users/paul/task-1.9.1.git/package-config/osx/local" m="false" t="file"><f n="bin" o="root" g="wheel" p="16877"><f n="task" o="root" g="wheel" p="33261"/></f><f n="share" o="root" g="wheel" p="16877"><f n="doc" o="root" g="wheel" p="16877"><f n="task" o="root" g="wheel" p="16877"><f n="AUTHORS" o="root" g="wheel" p="33188"/><f n="ChangeLog" o="root" g="wheel" p="33188"/><f n="COPYING" o="root" g="wheel" p="33188"/><f n="NEWS" o="root" g="wheel" p="33188"/><f n="README" o="root" g="wheel" p="33188"/><f n="scripts" o="root" g="wheel" p="16877"><f n="bash" o="root" g="wheel" p="16877"><f n="task_completion.sh" o="root" g="wheel" p="33188"/></f><f n="vim" o="root" g="wheel" p="16877"><f n="ftdetect" o="root" g="wheel" p="16877"><f n="task.vim" o="root" g="wheel" p="33188"/></f><f n="README" o="root" g="wheel" p="33188"/><f n="syntax" o="root" g="wheel" p="16877"><f n="taskdata.vim" o="root" g="wheel" p="33188"/><f n="taskedit.vim" o="root" g="wheel" p="33188"/><f n="taskrc.vim" o="root" g="wheel" p="33188"/></f></f><f n="zsh" o="root" g="wheel" p="16877"><f n="_task" o="root" g="wheel" p="33188"/></f></f></f></f><f n="man" o="root" g="wheel" p="17917"><f n="man1" o="root" g="wheel" p="17901"><f n="task.1" o="root" g="wheel" p="33188"/><mod>group</mod><mod>owner</mod></f><f n="man5" o="root" g="wheel" p="17901"><f n="task-color.5" o="root" g="wheel" p="33188"/><f n="task-faq.5" o="root" g="wheel" p="33188"/><f n="task-tutorial.5" o="root" g="wheel" p="33188"/><f n="taskrc.5" o="root" g="wheel" p="33188"/><mod>group</mod><mod>owner</mod></f><mod>group</mod><mod>owner</mod></f></f><mod>group</mod><mod>owner</mod></f></pkg-contents>
|
||||
@@ -1 +1 @@
|
||||
<pkgref spec="1.12" uuid="3BCF9CAB-ED33-4182-AC52-29B9F8FF9B87"><config><identifier>com.beckingham.task190.local.pkg</identifier><version>2.0</version><description></description><post-install type="none"/><requireAuthorization/><installFrom>/Users/paul/task-1.9.0.git/package-config/osx/local</installFrom><installTo mod="true" relocatable="true">/usr/local</installTo><flags><followSymbolicLinks/></flags><packageStore type="internal"></packageStore><mod>installTo.path</mod><mod>version</mod><mod>parent</mod><mod>installTo</mod><mod>relocatable</mod></config><contents><file-list>01local-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="B93940C5-2C4F-47D6-8038-3D24062FBC85"><config><identifier>com.beckingham.task191.local.pkg</identifier><version>1.0</version><description/><post-install type="none"/><requireAuthorization/><installFrom>/Users/paul/task-1.9.1.git/package-config/osx/local</installFrom><installTo mod="true" relocatable="true">/usr/local</installTo><flags><followSymbolicLinks/></flags><packageStore type="internal"/><mod>installTo.path</mod><mod>identifier</mod><mod>parent</mod><mod>installTo</mod><mod>relocatable</mod></config><contents><file-list>01local-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.9.0</title><build>/Users/paul/Desktop/task-1.9.0-sl.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><description>Task 1.9.0 install for Snow Leopard.</description><contents><choice title="local" id="choice36" starts_selected="true" starts_enabled="true" starts_hidden="false"><pkgref id="com.beckingham.task190.local.pkg"/></choice></contents><resources bg-scale="proportional" bg-align="center"><locale lang="en"><resource mod="true" type="license">/Users/paul/task-1.9.0.git/package-config/osx/COPYING.txt</resource><resource mod="true" type="welcome">/Users/paul/task-1.9.0.git/package-config/osx/README.txt</resource></locale></resources><requirements><requirement id="tosv" operator="ge" value="'10.6.0'"><message>Task requires Mac OSX 10.6.0 (Snow Leopard) or later.</message></requirement></requirements><flags/><item type="file">01local.xml</item><mod>properties.title</mod><mod>properties.customizeOption</mod><mod>description</mod><mod>properties.anywhereDomain</mod><mod>properties.systemDomain</mod></pkmkdoc>
|
||||
<pkmkdoc spec="1.12"><properties><title>Task 1.9.1</title><build>/Users/paul/Desktop/task-1.9.1-sl.pkg</build><organization>com.beckingham</organization><userSees ui="both"/><min-target os="3"/><domain anywhere="true" system="true"/></properties><distribution><versions min-spec="1.000000"/><scripts></scripts></distribution><description>Task 1.9.1 install for Snow Leopard.</description><contents><choice title="local" id="choice37" starts_selected="true" starts_enabled="true" starts_hidden="false"><pkgref id="com.beckingham.task191.local.pkg"/></choice></contents><resources bg-scale="proportional" bg-align="center"><locale lang="en"><resource mod="true" type="license">/Users/paul/task-1.9.1.git/package-config/osx/COPYING.txt</resource><resource mod="true" type="readme">/Users/paul/task-1.9.1.git/package-config/osx/README.txt</resource></locale></resources><requirements><requirement id="tosv" operator="ge" value="'10.6.0'"><message>Task requires Mac OSX 10.6.0 (Snow Leopard) or later.</message></requirement></requirements><flags/><item type="file">01local.xml</item><mod>properties.title</mod><mod>properties.customizeOption</mod><mod>description</mod><mod>properties.anywhereDomain</mod><mod>properties.systemDomain</mod></pkmkdoc>
|
||||
@@ -5,6 +5,7 @@ mkdir -p local/share/doc/task/scripts/bash
|
||||
mkdir -p local/share/doc/task/scripts/vim/ftdetect
|
||||
mkdir -p local/share/doc/task/scripts/vim/syntax
|
||||
mkdir -p local/share/doc/task/scripts/zsh
|
||||
mkdir -p local/share/doc/task/rc
|
||||
mkdir -p local/share/man/man1
|
||||
mkdir -p local/share/man/man5
|
||||
|
||||
@@ -25,6 +26,9 @@ cp ../../scripts/vim/ftdetect/* local/share/doc/task/scripts/vim/ftdetect
|
||||
cp ../../scripts/vim/syntax/* local/share/doc/task/scripts/vim/syntax
|
||||
cp ../../scripts/zsh/* local/share/doc/task/scripts/zsh
|
||||
|
||||
cp ../../doc/rc/*.theme local/share/doc/task/rc
|
||||
cp ../../doc/rc/holidays* local/share/doc/task/rc
|
||||
|
||||
cp ../../doc/man/*.1 local/share/man/man1
|
||||
cp ../../doc/man/*.5 local/share/man/man5
|
||||
|
||||
|
||||
@@ -1,3 +1,39 @@
|
||||
task (1.9.1-2ubuntu1) lucid; urgency=low
|
||||
|
||||
* Initial deb package for task release 1.9.1 on lucid lynx
|
||||
|
||||
-- Federico Hernandez <ultrafredde@gmail.com> Sun, 23 May 2010 00:24:42 +0200
|
||||
|
||||
task (1.9.0-2ubuntu1) lucid; urgency=low
|
||||
|
||||
* Initial deb package for task release 1.9.0 on lucid lynx
|
||||
|
||||
-- Federico Hernandez <ultrafredde@gmail.com> Sat, 15 May 2010 11:02:17 +0200
|
||||
|
||||
task (1.9.0-1ubuntu1) karmic; urgency=low
|
||||
|
||||
* Initial deb package for task beta release 1.9.0 on karmic koala
|
||||
|
||||
-- Federico Hernandez <ultrafredde@gmail.com> Mon, 22 Feb 2010 22:08:41 +0100
|
||||
|
||||
task (1.9.0-1ubuntu1~beta3) karmic; urgency=low
|
||||
|
||||
* Initial deb package for task beta release 1.9.0.beta3 on karmic koala
|
||||
|
||||
-- Federico Hernandez <ultrafredde@gmail.com> Tue, 16 Feb 2010 00:29:31 +0100
|
||||
|
||||
task (1.9.0-1ubuntu1~beta2) karmic; urgency=low
|
||||
|
||||
* Initial deb package for task beta release 1.9.0.beta2 on karmic koala
|
||||
|
||||
-- Federico Hernandez <ultrafredde@gmail.com> Mon, 08 Feb 2010 22:09:41 +0100
|
||||
|
||||
task (1.9.0-1ubuntu1~beta1) karmic; urgency=low
|
||||
|
||||
* Initial deb package for task beta release 1.9.0.beta1 on karmic koala
|
||||
|
||||
-- Federico Hernandez <ultrafredde@gmail.com> Wed, 03 Feb 2010 23:51:08 +0100
|
||||
|
||||
task (1.8.5-1ubuntu2) karmic; urgency=low
|
||||
|
||||
* Fixed wrong ChangeLog file
|
||||
|
||||
@@ -3,13 +3,13 @@ Section: utils
|
||||
Priority: optional
|
||||
Maintainer: Federico Hernandez <ultrafredde@gmail.com>
|
||||
XSBC-Original-Maintainer: Federico Hernandez <ultrafredde@gmail.com>
|
||||
Build-Depends: debhelper (>= 7), autotools-dev, libncurses5-dev
|
||||
Standards-Version: 3.8.3
|
||||
Build-Depends: cdbs, debhelper (>= 7), autotools-dev, libncurses5-dev
|
||||
Standards-Version: 3.8.4
|
||||
Homepage: http://taskwarrior.org
|
||||
|
||||
Package: task
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: A command-line to do list manager
|
||||
Task is a command-line to do list manager. It has
|
||||
support for GTD functionality and includes the
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
This package was debianized by:
|
||||
|
||||
Federico Hernandez <ultrafredde@gmail.com> on Sat, 05 Dec 2009 23:58:36 +0100
|
||||
Federico Hernandez <ultrafredde@gmail.com> on Sun, 23 May 2010 00:24:42 +0200
|
||||
|
||||
It was downloaded from:
|
||||
|
||||
@@ -26,13 +26,18 @@ Upstream Authors:
|
||||
Steven de Brouwer
|
||||
Pietro Cerutti
|
||||
Cory Donnelly
|
||||
Alexander Neumann
|
||||
Emil Sköldberg
|
||||
Johannes Schlatow
|
||||
|
||||
Copyright:
|
||||
|
||||
Copyright 2006 - 2010, Paul Beckingham
|
||||
Copyright 2009 - 2010 Federico Hernandez
|
||||
Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez
|
||||
Copyright 2009 - 2010 John Florian
|
||||
Copyright 2009 P.C. Shyamshankar
|
||||
Copyright © 1994–2008 Lua.org, PUC-Rio
|
||||
|
||||
License:
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
scripts
|
||||
i18n
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
config.status: configure
|
||||
dh_testdir
|
||||
./configure $(CROSS) --prefix=/usr --docdir=$(DATADIR)/doc/task
|
||||
./configure $(CROSS) --prefix=/usr
|
||||
|
||||
build: build-stamp
|
||||
|
||||
@@ -31,9 +31,7 @@ binary-arch: install
|
||||
dh_installchangelogs
|
||||
dh_installdocs
|
||||
dh_installman
|
||||
dh_installexamples
|
||||
install -D -m644 scripts/bash/task_completion.sh $(CURDIR)/debian/task/etc/bash_completion.d/task
|
||||
rm -rf $(CURDIR)/debian/task/usr/share/doc/task-1.8.5
|
||||
dh_strip
|
||||
dh_compress
|
||||
dh_fixperms
|
||||
|
||||
1
package-config/ubuntu/debian/source/format
Normal file
1
package-config/ubuntu/debian/source/format
Normal file
@@ -0,0 +1 @@
|
||||
1.0
|
||||
@@ -1,3 +1,5 @@
|
||||
# Compulsory line, this is a version 3 file
|
||||
version=3
|
||||
|
||||
http://taskwarrior.org/download/task-(.*)\.tar\.gz
|
||||
|
||||
# the main taskwarrior download website
|
||||
http://taskwarrior.org/wiki/taskwarrior/Download http://www.taskwarrior.org/download/task-(.*)\.tar\.gz
|
||||
|
||||
1
src/.gitignore
vendored
1
src/.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
*.o
|
||||
Makefile.in
|
||||
*_test
|
||||
|
||||
45
src/API.cpp
45
src/API.cpp
@@ -188,28 +188,35 @@ static int api_task_get_footnote_messages ()
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static int api_task_get_debug_messages ()
|
||||
{
|
||||
return {}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
-- Records additional messages, for subsequent display.
|
||||
static int api_task_header_message (text)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static int api_task_footnote_message (text)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static int api_task_debug_message (text)
|
||||
static int api_task_get_debug_messages (lua_State* L)
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static int api_task_header_message (lua_State* L)
|
||||
{
|
||||
std::string message = luaL_checkstring (L, 1);
|
||||
context.header (message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static int api_task_footnote_message (lua_State* L)
|
||||
{
|
||||
std::string message = luaL_checkstring (L, 1);
|
||||
context.footnote (message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static int api_task_debug_message (lua_State* L)
|
||||
{
|
||||
std::string message = luaL_checkstring (L, 1);
|
||||
context.debug (message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Causes the shell or interactive mode task to exit. Ordinarily this does not
|
||||
// occur.
|
||||
@@ -542,10 +549,10 @@ void API::initialize ()
|
||||
lua_pushcfunction (L, api_task_get_header_messages); lua_setglobal (L, "task_get_header_messages");
|
||||
lua_pushcfunction (L, api_task_get_footnote_messages); lua_setglobal (L, "task_get_footnote_messages");
|
||||
lua_pushcfunction (L, api_task_get_debug_messages); lua_setglobal (L, "task_get_debug_messages");
|
||||
*/
|
||||
lua_pushcfunction (L, api_task_header_message); lua_setglobal (L, "task_header_message");
|
||||
lua_pushcfunction (L, api_task_footnote_message); lua_setglobal (L, "task_footnote_message");
|
||||
lua_pushcfunction (L, api_task_debug_message); lua_setglobal (L, "task_debug_message");
|
||||
*/
|
||||
lua_pushcfunction (L, api_task_exit); lua_setglobal (L, "task_exit");
|
||||
/*
|
||||
lua_pushcfunction (L, api_task_inhibit_further_hooks); lua_setglobal (L, "task_inhibit_further_hooks");
|
||||
|
||||
105
src/Att.cpp
105
src/Att.cpp
@@ -50,6 +50,7 @@ static const char* internalNames[] =
|
||||
"limit",
|
||||
"status",
|
||||
"description",
|
||||
// Note that annotations are not listed.
|
||||
};
|
||||
|
||||
static const char* modifiableNames[] =
|
||||
@@ -154,6 +155,14 @@ Att& Att::operator= (const Att& other)
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Att::operator== (const Att& other) const
|
||||
{
|
||||
return mName == other.mName &&
|
||||
mMod == other.mMod &&
|
||||
mValue == other.mValue;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Att::~Att ()
|
||||
{
|
||||
@@ -344,8 +353,8 @@ bool Att::validNameValue (
|
||||
|
||||
else if (name == "limit")
|
||||
{
|
||||
if (value == "" || !digitsOnly (value))
|
||||
throw std::string ("The '") + name + "' attribute must be an integer.";
|
||||
if (value == "" || (value != "page" && !digitsOnly (value)))
|
||||
throw std::string ("The '") + name + "' attribute must be an integer, or the value 'page'.";
|
||||
}
|
||||
|
||||
else if (name == "status")
|
||||
@@ -405,6 +414,9 @@ std::string Att::type (const std::string& name) const
|
||||
else if (name == "limit")
|
||||
return "number";
|
||||
|
||||
else if (name == "priority")
|
||||
return "priority";
|
||||
|
||||
else
|
||||
return "text";
|
||||
}
|
||||
@@ -492,8 +504,24 @@ bool Att::match (const Att& other) const
|
||||
// If there are no mods, just perform a straight compare on value.
|
||||
if (mMod == "")
|
||||
{
|
||||
if (!compare (mValue, other.mValue, (bool) case_sensitive))
|
||||
return false;
|
||||
// Exact matches on dates should only compare m/d/y, not h:m:s. This allows
|
||||
// Comapisons like "task list due:today" (bug #405).
|
||||
std::string which = type (mName);
|
||||
if (which == "date")
|
||||
{
|
||||
Date left (mValue);
|
||||
Date right (other.mValue);
|
||||
|
||||
if (left.year () != right.year () ||
|
||||
left.month () != right.month () ||
|
||||
left.day () != right.day ())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!compare (mValue, other.mValue, (bool) case_sensitive))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// has = contains as a substring.
|
||||
@@ -588,6 +616,14 @@ bool Att::match (const Att& other) const
|
||||
if (mValue <= other.mValue)
|
||||
return false;
|
||||
}
|
||||
else if (which == "priority")
|
||||
{
|
||||
if (mValue == "" ||
|
||||
other.mValue == "H" ||
|
||||
mValue == other.mValue ||
|
||||
(mValue == "L" && other.mValue == "M"))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// after = over = above = >
|
||||
@@ -618,6 +654,14 @@ bool Att::match (const Att& other) const
|
||||
if (mValue >= other.mValue)
|
||||
return false;
|
||||
}
|
||||
else if (which == "priority")
|
||||
{
|
||||
if (mValue == "H" ||
|
||||
other.mValue == "" ||
|
||||
mValue == other.mValue ||
|
||||
(mValue == "M" && other.mValue == "L"))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// word = contains as a substring, with word boundaries.
|
||||
@@ -715,6 +759,19 @@ int Att::value_int () const
|
||||
return atoi (mValue.c_str ());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Att::allNames (std::vector <std::string>& all)
|
||||
{
|
||||
all.clear ();
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < NUM_INTERNAL_NAMES; ++i)
|
||||
all.push_back (internalNames[i]);
|
||||
|
||||
for (i = 0; i < NUM_MODIFIABLE_NAMES; ++i)
|
||||
all.push_back (modifiableNames[i]);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Att::value_int (int value)
|
||||
{
|
||||
@@ -744,12 +801,9 @@ void Att::dequote (std::string& value) const
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Encode values prior to serialization.
|
||||
// \t -> &tab;
|
||||
// ' -> &squot;
|
||||
// " -> &dquot;
|
||||
// , -> ,
|
||||
// [ -> &open;
|
||||
// ] -> &close;
|
||||
// : -> :
|
||||
void Att::encode (std::string& value) const
|
||||
{
|
||||
std::string::size_type i;
|
||||
@@ -757,23 +811,14 @@ void Att::encode (std::string& value) const
|
||||
while ((i = value.find ('\t')) != std::string::npos)
|
||||
value.replace (i, 1, "&tab;"); // no i18n
|
||||
|
||||
while ((i = value.find ('\'')) != std::string::npos)
|
||||
value.replace (i, 1, "&squot;"); // no i18n
|
||||
|
||||
while ((i = value.find ('"')) != std::string::npos)
|
||||
value.replace (i, 1, "&dquot;"); // no i18n
|
||||
|
||||
while ((i = value.find (',')) != std::string::npos)
|
||||
value.replace (i, 1, ","); // no i18n
|
||||
|
||||
while ((i = value.find ('[')) != std::string::npos)
|
||||
value.replace (i, 1, "&open;"); // no i18n
|
||||
|
||||
while ((i = value.find (']')) != std::string::npos)
|
||||
value.replace (i, 1, "&close;"); // no i18n
|
||||
|
||||
while ((i = value.find (':')) != std::string::npos)
|
||||
value.replace (i, 1, ":"); // no i18n
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -789,28 +834,32 @@ void Att::decode (std::string& value) const
|
||||
{
|
||||
std::string::size_type i;
|
||||
|
||||
while ((i = value.find ("&tab;")) != std::string::npos) // no i18n
|
||||
// Supported encodings.
|
||||
while ((i = value.find ("&tab;")) != std::string::npos)
|
||||
value.replace (i, 5, "\t");
|
||||
|
||||
while ((i = value.find ("&dquot;")) != std::string::npos) // no i18n
|
||||
while ((i = value.find ("&dquot;")) != std::string::npos)
|
||||
value.replace (i, 7, "\"");
|
||||
|
||||
while ((i = value.find ("&squot;")) != std::string::npos) // no i18n
|
||||
value.replace (i, 7, "'");
|
||||
|
||||
while ((i = value.find (""")) != std::string::npos) // no i18n
|
||||
while ((i = value.find (""")) != std::string::npos)
|
||||
value.replace (i, 6, "\"");
|
||||
|
||||
while ((i = value.find (",")) != std::string::npos) // no i18n
|
||||
value.replace (i, 7, ",");
|
||||
|
||||
while ((i = value.find ("&open;")) != std::string::npos) // no i18n
|
||||
while ((i = value.find ("&open;")) != std::string::npos)
|
||||
value.replace (i, 6, "[");
|
||||
|
||||
while ((i = value.find ("&close;")) != std::string::npos) // no i18n
|
||||
while ((i = value.find ("&close;")) != std::string::npos)
|
||||
value.replace (i, 7, "]");
|
||||
|
||||
while ((i = value.find (":")) != std::string::npos) // no i18n
|
||||
// Support for deprecated encodings. These cannot be removed or old files
|
||||
// will not be parsable. Not just old files - completed.data can contain
|
||||
// tasks formatted/encoded using these.
|
||||
while ((i = value.find ("&squot;")) != std::string::npos)
|
||||
value.replace (i, 7, "'");
|
||||
|
||||
while ((i = value.find (",")) != std::string::npos)
|
||||
value.replace (i, 7, ",");
|
||||
|
||||
while ((i = value.find (":")) != std::string::npos)
|
||||
value.replace (i, 7, ":");
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
Att (const std::string&, int);
|
||||
Att (const Att&);
|
||||
Att& operator= (const Att&);
|
||||
bool operator== (const Att&) const;
|
||||
~Att ();
|
||||
|
||||
bool valid (const std::string&) const;
|
||||
@@ -69,6 +70,8 @@ public:
|
||||
int value_int () const;
|
||||
void value_int (int);
|
||||
|
||||
static void allNames (std::vector <std::string>&);
|
||||
|
||||
private:
|
||||
void enquote (std::string&) const;
|
||||
void dequote (std::string&) const;
|
||||
|
||||
115
src/Cmd.cpp
115
src/Cmd.cpp
@@ -105,41 +105,51 @@ void Cmd::load ()
|
||||
{
|
||||
if (commands.size () == 0)
|
||||
{
|
||||
// Commands whose names are not localized.
|
||||
commands.push_back ("_projects");
|
||||
commands.push_back ("_tags");
|
||||
commands.push_back ("_commands");
|
||||
commands.push_back ("_ids");
|
||||
commands.push_back ("_config");
|
||||
commands.push_back ("_version");
|
||||
commands.push_back (context.stringtable.get (CMD_ADD, "add"));
|
||||
commands.push_back (context.stringtable.get (CMD_APPEND, "append"));
|
||||
commands.push_back (context.stringtable.get (CMD_ANNOTATE, "annotate"));
|
||||
commands.push_back (context.stringtable.get (CMD_CALENDAR, "calendar"));
|
||||
commands.push_back (context.stringtable.get (CMD_COLORS, "colors"));
|
||||
commands.push_back (context.stringtable.get (CMD_CONFIG, "config"));
|
||||
commands.push_back (context.stringtable.get (CMD_DELETE, "delete"));
|
||||
commands.push_back (context.stringtable.get (CMD_DONE, "done"));
|
||||
commands.push_back (context.stringtable.get (CMD_DUPLICATE, "duplicate"));
|
||||
commands.push_back (context.stringtable.get (CMD_EDIT, "edit"));
|
||||
commands.push_back (context.stringtable.get (CMD_EXPORT, "export"));
|
||||
commands.push_back (context.stringtable.get (CMD_HELP, "help"));
|
||||
commands.push_back (context.stringtable.get (CMD_HISTORY, "history"));
|
||||
commands.push_back (context.stringtable.get (CMD_GHISTORY, "ghistory"));
|
||||
commands.push_back (context.stringtable.get (CMD_IMPORT, "import"));
|
||||
commands.push_back (context.stringtable.get (CMD_INFO, "info"));
|
||||
commands.push_back (context.stringtable.get (CMD_PREPEND, "prepend"));
|
||||
commands.push_back (context.stringtable.get (CMD_PROJECTS, "projects"));
|
||||
commands.push_back ("_merge");
|
||||
commands.push_back ("export.csv");
|
||||
commands.push_back ("export.ical");
|
||||
commands.push_back ("history.monthly");
|
||||
commands.push_back ("history.annual");
|
||||
commands.push_back ("ghistory.monthly");
|
||||
commands.push_back ("ghistory.annual");
|
||||
|
||||
// Commands whose names are localized.
|
||||
commands.push_back (context.stringtable.get (CMD_ADD, "add"));
|
||||
commands.push_back (context.stringtable.get (CMD_APPEND, "append"));
|
||||
commands.push_back (context.stringtable.get (CMD_ANNOTATE, "annotate"));
|
||||
commands.push_back (context.stringtable.get (CMD_DENOTATE, "denotate"));
|
||||
commands.push_back (context.stringtable.get (CMD_CALENDAR, "calendar"));
|
||||
commands.push_back (context.stringtable.get (CMD_COLORS, "colors"));
|
||||
commands.push_back (context.stringtable.get (CMD_CONFIG, "config"));
|
||||
commands.push_back (context.stringtable.get (CMD_SHOW, "show"));
|
||||
commands.push_back (context.stringtable.get (CMD_DELETE, "delete"));
|
||||
commands.push_back (context.stringtable.get (CMD_DONE, "done"));
|
||||
commands.push_back (context.stringtable.get (CMD_DUPLICATE, "duplicate"));
|
||||
commands.push_back (context.stringtable.get (CMD_EDIT, "edit"));
|
||||
commands.push_back (context.stringtable.get (CMD_HELP, "help"));
|
||||
commands.push_back (context.stringtable.get (CMD_IMPORT, "import"));
|
||||
commands.push_back (context.stringtable.get (CMD_INFO, "info"));
|
||||
commands.push_back (context.stringtable.get (CMD_LOG, "log"));
|
||||
commands.push_back (context.stringtable.get (CMD_PREPEND, "prepend"));
|
||||
commands.push_back (context.stringtable.get (CMD_PROJECTS, "projects"));
|
||||
#ifdef FEATURE_SHELL
|
||||
commands.push_back (context.stringtable.get (CMD_SHELL, "shell"));
|
||||
commands.push_back (context.stringtable.get (CMD_SHELL, "shell"));
|
||||
#endif
|
||||
commands.push_back (context.stringtable.get (CMD_START, "start"));
|
||||
commands.push_back (context.stringtable.get (CMD_STATS, "stats"));
|
||||
commands.push_back (context.stringtable.get (CMD_STOP, "stop"));
|
||||
commands.push_back (context.stringtable.get (CMD_SUMMARY, "summary"));
|
||||
commands.push_back (context.stringtable.get (CMD_TAGS, "tags"));
|
||||
commands.push_back (context.stringtable.get (CMD_TIMESHEET, "timesheet"));
|
||||
commands.push_back (context.stringtable.get (CMD_UNDO, "undo"));
|
||||
commands.push_back (context.stringtable.get (CMD_VERSION, "version"));
|
||||
commands.push_back (context.stringtable.get (CMD_START, "start"));
|
||||
commands.push_back (context.stringtable.get (CMD_STATS, "stats"));
|
||||
commands.push_back (context.stringtable.get (CMD_STOP, "stop"));
|
||||
commands.push_back (context.stringtable.get (CMD_SUMMARY, "summary"));
|
||||
commands.push_back (context.stringtable.get (CMD_TAGS, "tags"));
|
||||
commands.push_back (context.stringtable.get (CMD_TIMESHEET, "timesheet"));
|
||||
commands.push_back (context.stringtable.get (CMD_UNDO, "undo"));
|
||||
commands.push_back (context.stringtable.get (CMD_VERSION, "version"));
|
||||
|
||||
// Now load the custom reports.
|
||||
std::vector <std::string> all;
|
||||
@@ -189,27 +199,31 @@ void Cmd::allCommands (std::vector <std::string>& all) const
|
||||
// Commands that do not directly modify the data files.
|
||||
bool Cmd::isReadOnlyCommand ()
|
||||
{
|
||||
if (command == "_projects" ||
|
||||
command == "_tags" ||
|
||||
command == "_commands" ||
|
||||
command == "_ids" ||
|
||||
command == "_config" ||
|
||||
command == "_version" ||
|
||||
command == context.stringtable.get (CMD_CALENDAR, "calendar") ||
|
||||
command == context.stringtable.get (CMD_COLORS, "colors") ||
|
||||
command == context.stringtable.get (CMD_CONFIG, "config") ||
|
||||
command == context.stringtable.get (CMD_EXPORT, "export") ||
|
||||
command == context.stringtable.get (CMD_HELP, "help") ||
|
||||
command == context.stringtable.get (CMD_HISTORY, "history") ||
|
||||
command == context.stringtable.get (CMD_GHISTORY, "ghistory") ||
|
||||
command == context.stringtable.get (CMD_INFO, "info") ||
|
||||
command == context.stringtable.get (CMD_PROJECTS, "projects") ||
|
||||
command == context.stringtable.get (CMD_SHELL, "shell") ||
|
||||
command == context.stringtable.get (CMD_STATS, "stats") ||
|
||||
command == context.stringtable.get (CMD_SUMMARY, "summary") ||
|
||||
command == context.stringtable.get (CMD_TAGS, "tags") ||
|
||||
command == context.stringtable.get (CMD_TIMESHEET, "timesheet") ||
|
||||
command == context.stringtable.get (CMD_VERSION, "version") ||
|
||||
if (command == "_projects" ||
|
||||
command == "_tags" ||
|
||||
command == "_commands" ||
|
||||
command == "_ids" ||
|
||||
command == "_config" ||
|
||||
command == "_version" ||
|
||||
command == "export.csv" ||
|
||||
command == "export.ical" ||
|
||||
command == "history.monthly" ||
|
||||
command == "history.annual" ||
|
||||
command == "ghistory.monthly" ||
|
||||
command == "ghistory.annual" ||
|
||||
command == context.stringtable.get (CMD_CALENDAR, "calendar") ||
|
||||
command == context.stringtable.get (CMD_COLORS, "colors") ||
|
||||
command == context.stringtable.get (CMD_CONFIG, "config") ||
|
||||
command == context.stringtable.get (CMD_SHOW, "show") ||
|
||||
command == context.stringtable.get (CMD_HELP, "help") ||
|
||||
command == context.stringtable.get (CMD_INFO, "info") ||
|
||||
command == context.stringtable.get (CMD_PROJECTS, "projects") ||
|
||||
command == context.stringtable.get (CMD_SHELL, "shell") ||
|
||||
command == context.stringtable.get (CMD_STATS, "stats") ||
|
||||
command == context.stringtable.get (CMD_SUMMARY, "summary") ||
|
||||
command == context.stringtable.get (CMD_TAGS, "tags") ||
|
||||
command == context.stringtable.get (CMD_TIMESHEET, "timesheet") ||
|
||||
command == context.stringtable.get (CMD_VERSION, "version") ||
|
||||
validCustom (command))
|
||||
return true;
|
||||
|
||||
@@ -220,14 +234,17 @@ bool Cmd::isReadOnlyCommand ()
|
||||
// Commands that directly modify the data files.
|
||||
bool Cmd::isWriteCommand ()
|
||||
{
|
||||
if (command == context.stringtable.get (CMD_ADD, "add") ||
|
||||
if (command == "_merge" ||
|
||||
command == context.stringtable.get (CMD_ADD, "add") ||
|
||||
command == context.stringtable.get (CMD_APPEND, "append") ||
|
||||
command == context.stringtable.get (CMD_ANNOTATE, "annotate") ||
|
||||
command == context.stringtable.get (CMD_DENOTATE, "denotate") ||
|
||||
command == context.stringtable.get (CMD_DELETE, "delete") ||
|
||||
command == context.stringtable.get (CMD_DONE, "done") ||
|
||||
command == context.stringtable.get (CMD_DUPLICATE, "duplicate") ||
|
||||
command == context.stringtable.get (CMD_EDIT, "edit") ||
|
||||
command == context.stringtable.get (CMD_IMPORT, "import") ||
|
||||
command == context.stringtable.get (CMD_LOG, "log") ||
|
||||
command == context.stringtable.get (CMD_PREPEND, "prepend") ||
|
||||
command == context.stringtable.get (CMD_START, "start") ||
|
||||
command == context.stringtable.get (CMD_STOP, "stop") ||
|
||||
|
||||
208
src/Config.cpp
208
src/Config.cpp
@@ -57,91 +57,148 @@ std::string Config::defaults =
|
||||
"\n"
|
||||
"# Files\n"
|
||||
"data.location=~/.task\n"
|
||||
"locking=on # Use file-level locking\n"
|
||||
"locking=on # Use file-level locking\n"
|
||||
"\n"
|
||||
"# Terminal\n"
|
||||
"curses=on # Use ncurses library to determine terminal width\n"
|
||||
"defaultwidth=80 # Without ncurses, assumed width\n"
|
||||
"#editor=vi # Preferred text editor\n"
|
||||
"curses=on # Use ncurses library to determine terminal width\n"
|
||||
"defaultwidth=80 # Without ncurses, assumed width\n"
|
||||
"#editor=vi # Preferred text editor\n"
|
||||
"\n"
|
||||
"# Miscellaneous\n"
|
||||
"confirmation=yes # Confirmation on delete, big changes\n"
|
||||
"echo.command=yes # Details on command just run\n"
|
||||
"annotations=full # Level of verbosity for annotations: full, sparse or none\n"
|
||||
"next=2 # How many tasks per project in next report\n"
|
||||
"bulk=2 # > 2 tasks considered 'a lot', for confirmation\n"
|
||||
"nag=You have higher priority tasks. # Nag message to keep you honest\n" // TODO
|
||||
"search.case.sensitive=yes # Setting to no allows case insensitive searches\n"
|
||||
"active.indicator=* # What to show as an active task indicator\n"
|
||||
"tag.indicator=+ # What to show as a tag indicator\n"
|
||||
"recurrence.indicator=R # What to show as a task recurrence indicator\n"
|
||||
"confirmation=yes # Confirmation on delete, big changes\n"
|
||||
"echo.command=yes # Details on command just run\n"
|
||||
"annotations=full # Level of verbosity for annotations: full, sparse or none\n"
|
||||
"next=2 # How many tasks per project in next report\n"
|
||||
"bulk=2 # > 2 tasks considered 'a lot', for confirmation\n"
|
||||
"nag=You have higher priority tasks. # Nag message to keep you honest\n" // TODO
|
||||
"search.case.sensitive=yes # Setting to no allows case insensitive searches\n"
|
||||
"active.indicator=* # What to show as an active task indicator\n"
|
||||
"tag.indicator=+ # What to show as a tag indicator\n"
|
||||
"recurrence.indicator=R # What to show as a task recurrence indicator\n"
|
||||
"recurrence.limit=1 # Number of future recurring pending tasks\n"
|
||||
"undo.style=side # Undo style - can be 'side', or 'diff'\n"
|
||||
"\n"
|
||||
"# Dates\n"
|
||||
"dateformat=m/d/Y # Preferred input and display date format\n"
|
||||
"dateformat.holiday=YMD # Preferred input date format for holidays\n"
|
||||
"dateformat.report=m/d/Y # Preferred display date format for repors\n"
|
||||
"weekstart=Sunday # Sunday or Monday only\n"
|
||||
"displayweeknumber=yes # Show week numbers on calendar\n"
|
||||
"due=7 # Task is considered due in 7 days\n"
|
||||
"dateformat=m/d/Y # Preferred input and display date format\n"
|
||||
"dateformat.holiday=YMD # Preferred input date format for holidays\n"
|
||||
"dateformat.report=m/d/Y # Preferred display date format for reports\n"
|
||||
"dateformat.annotation=m/d/Y # Preferred display date format for reports\n"
|
||||
"weekstart=Sunday # Sunday or Monday only\n"
|
||||
"displayweeknumber=yes # Show week numbers on calendar\n"
|
||||
"due=7 # Task is considered due in 7 days\n"
|
||||
"\n"
|
||||
"# Calendar controls\n"
|
||||
"calendar.legend=yes # Display the legend on calendar\n"
|
||||
"calendar.details=sparse # Calendar shows information for tasks w/due dates: full, sparse or none\n"
|
||||
"calendar.details.report=list # Report to use when showing task information in cal\n"
|
||||
"calendar.holidays=none # Show public holidays on calendar:full, sparse or none\n"
|
||||
"#monthsperline=3 # Number of calendar months on a line\n"
|
||||
"calendar.legend=yes # Display the legend on calendar\n"
|
||||
"calendar.details=sparse # Calendar shows information for tasks w/due dates: full, sparse or none\n"
|
||||
"calendar.details.report=list # Report to use when showing task information in cal\n"
|
||||
"calendar.holidays=none # Show public holidays on calendar:full, sparse or none\n"
|
||||
"#monthsperline=3 # Number of calendar months on a line\n"
|
||||
"\n"
|
||||
"# Color controls.\n"
|
||||
"color=on # Enable color\n"
|
||||
"#color.header=bold green # Color of header messages\n"
|
||||
"#color.footnote=bold green # Color of footnote messages\n"
|
||||
"color.summary.bar=on green # Color of summary report progress bar\n"
|
||||
"color.summary.background=on black # Color of summary report background\n"
|
||||
"color.calendar.today=black on cyan # Color of today in calendar\n"
|
||||
"color.calendar.due=black on green # Color of days with due tasks in calendar\n"
|
||||
"color.calendar.due.today=black on magenta # Color of today with due tasks in calendar\n"
|
||||
"color.calendar.overdue=black on red # Color of days with overdue tasks in calendar\n"
|
||||
"color.calendar.weekend=bright white on black # Color of weekend days in calendar\n"
|
||||
"color.calendar.holiday=black on bright yellow # Color of public holidays in calendar\n"
|
||||
"color.calendar.weeknumber=black on white # Color of the weeknumbers in calendar\n"
|
||||
"#color.debug=magenta # Color of diagnostic output\n"
|
||||
#ifdef LINUX
|
||||
"color.header=color3 # Color of header messages\n"
|
||||
"color.footnote=color3 # Color of footnote messages\n"
|
||||
"color.debug=color3 # Color of diagnostic output\n"
|
||||
"\n"
|
||||
"color.summary.bar=on rgb141 # Color of summary report progress bar\n"
|
||||
"color.summary.background=on color0 # Color of summary report background\n"
|
||||
"\n"
|
||||
"color.history.add=color0 on rgb500 # Color of added tasks in ghistory report\n"
|
||||
"color.history.done=color0 on rgb050 # Color of completed tasks in ghistory report\n"
|
||||
"color.history.delete=color0 on rgb550 # Color of deleted tasks in ghistory report\n"
|
||||
"\n"
|
||||
"color.undo.before=color1 # Color of values before a change\n"
|
||||
"color.undo.after=color2 # Color of values after a change\n"
|
||||
"\n"
|
||||
"color.calendar.today=color15 on rgb013 # Color of today in calendar\n"
|
||||
"color.calendar.due=color0 on color1 # Color of days with due tasks in calendar\n"
|
||||
"color.calendar.due.today=color15 on color1 # Color of today with due tasks in calendar\n"
|
||||
"color.calendar.overdue=color0 on color9 # Color of days with overdue tasks in calendar\n"
|
||||
"color.calendar.weekend=color235 # Color of weekend days in calendar\n"
|
||||
"color.calendar.holiday=color0 on color11 # Color of public holidays in calendar\n"
|
||||
"color.calendar.weeknumber=rgb013 # Color of the weeknumbers in calendar\n"
|
||||
"\n"
|
||||
"# The following rules are presented in their order of precedence.\n"
|
||||
"# The higher the color rule is up this list, the higher precedence\n"
|
||||
"# it has in determining the color for the task. Precedence is shown\n"
|
||||
"# in brackets [1]\n"
|
||||
"#color.recurring=on red # [1] Color of recur.any: tasks\n"
|
||||
"color.overdue=bold red # [2] Color of overdue tasks\n"
|
||||
"color.due.today=bold magenta # [3] Color of tasks due today\n"
|
||||
"color.due=bold yellow # [4] Color of due tasks\n"
|
||||
"#color.keyword.car=on blue # [5] Color of description.contains:car tasks\n"
|
||||
"#color.project.garden=on green # [6] Color of project:garden tasks\n"
|
||||
"#color.tag.bug=yellow # [7] Color of +bug tasks\n"
|
||||
"color.active=bold cyan # [8] Color of active tasks\n"
|
||||
"#color.pri.none=white on blue # [9] Color of priority: tasks\n"
|
||||
"color.pri.H=bold # [9] Color of priority:H tasks\n"
|
||||
"#color.pri.M=on yellow # [9] Color of priority:M tasks\n"
|
||||
"#color.pri.L=on green # [9] Color of priority:L tasks\n"
|
||||
"color.tagged=yellow # [10] Color of tagged tasks\n"
|
||||
"#color.alternate=on rgb253 # [11] Alternate color for line coloring\n"
|
||||
"color.recurring=rgb013 # [1] Color of recur.any: tasks\n"
|
||||
"color.overdue=color9 # [2] Color of overdue tasks\n"
|
||||
"color.due.today=rgb400 # [3] Color of tasks due today\n"
|
||||
"color.due=color1 # [4] Color of due tasks\n"
|
||||
"#color.keyword.car=on blue # [5] Color of description.contains:car tasks\n"
|
||||
"#color.project.garden=on green # [6] Color of project:garden tasks\n"
|
||||
"#color.tag.bug=yellow # [7] Color of +bug tasks\n"
|
||||
"color.active=rgb555 on rgb410 # [8] Color of active tasks\n"
|
||||
"color.pri.none= # [9] Color of priority: tasks\n"
|
||||
"color.pri.H=rgb255 # [9] Color of priority:H tasks\n"
|
||||
"color.pri.M=rgb250 # [9] Color of priority:M tasks\n"
|
||||
"color.pri.L=rgb245 # [9] Color of priority:L tasks\n"
|
||||
"color.tagged=rgb031 # [10] Color of tagged tasks\n"
|
||||
"color.alternate=on color233 # [11] Alternate color for line coloring\n"
|
||||
#else
|
||||
"color.header=yellow # Color of header messages\n"
|
||||
"color.footnote=yellow # Color of footnote messages\n"
|
||||
"color.debug=yellow # Color of diagnostic output\n"
|
||||
"\n"
|
||||
"color.summary.bar=on green # Color of summary report progress bar\n"
|
||||
"color.summary.background=on black # Color of summary report background\n"
|
||||
"\n"
|
||||
"color.history.add=black on red # Color of added tasks in ghistory report\n"
|
||||
"color.history.done=black on green # Color of completed tasks in ghistory report\n"
|
||||
"color.history.delete=black on yellow # Color of deleted tasks in ghistory report\n"
|
||||
"\n"
|
||||
"color.undo.before=red # Color of values before a change\n"
|
||||
"color.undo.after=green # Color of values after a change\n"
|
||||
"\n"
|
||||
"color.calendar.today=bold white on bright blue # Color of today in calendar\n"
|
||||
"color.calendar.due=white on red # Color of days with due tasks in calendar\n"
|
||||
"color.calendar.due.today=bold white on red # Color of today with due tasks in calendar\n"
|
||||
"color.calendar.overdue=black on bright red # Color of days with overdue tasks in calendar\n"
|
||||
"color.calendar.weekend=white on bright black # Color of weekend days in calendar\n"
|
||||
"color.calendar.holiday=black on bright yellow # Color of public holidays in calendar\n"
|
||||
"color.calendar.weeknumber=bold blue # Color of the weeknumbers in calendar\n"
|
||||
"\n"
|
||||
"# The following rules are presented in their order of precedence.\n"
|
||||
"# The higher the color rule is up this list, the higher precedence\n"
|
||||
"# it has in determining the color for the task. Precedence is shown\n"
|
||||
"# in brackets [1]\n"
|
||||
"color.recurring=magenta # [1] Color of recur.any: tasks\n"
|
||||
"color.overdue=bold red # [2] Color of overdue tasks\n"
|
||||
"color.due.today=red # [3] Color of tasks due today\n"
|
||||
"color.due=red # [4] Color of due tasks\n"
|
||||
"#color.keyword.car=on blue # [5] Color of description.contains:car tasks\n"
|
||||
"#color.project.garden=on green # [6] Color of project:garden tasks\n"
|
||||
"#color.tag.bug=yellow # [7] Color of +bug tasks\n"
|
||||
"color.active=black on bright green # [8] Color of active tasks\n"
|
||||
"color.pri.none= # [9] Color of priority: tasks\n"
|
||||
"color.pri.H=bold white # [9] Color of priority:H tasks\n"
|
||||
"color.pri.M=white # [9] Color of priority:M tasks\n"
|
||||
"color.pri.L= # [9] Color of priority:L tasks\n"
|
||||
"color.tagged=green # [10] Color of tagged tasks\n"
|
||||
"color.alternate= # [11] Alternate color for line coloring\n"
|
||||
#endif
|
||||
"\n"
|
||||
"# Shadow file support\n"
|
||||
"#shadow.file=/tmp/shadow.txt # Location of shadow file\n"
|
||||
"#shadow.command=list # Task command for shadow file\n"
|
||||
"#shadow.notify=on # Footnote when updated\n"
|
||||
"#shadow.file=/tmp/shadow.txt # Location of shadow file\n"
|
||||
"#shadow.command=list # Task command for shadow file\n"
|
||||
"#shadow.notify=on # Footnote when updated\n"
|
||||
"\n"
|
||||
"#default.project=foo # Default project for 'add' command\n"
|
||||
"#default.priority=M # Default priority for 'add' command\n"
|
||||
"default.command=list # When no arguments are specified\n"
|
||||
"#default.project=foo # Default project for 'add' command\n"
|
||||
"#default.priority=M # Default priority for 'add' command\n"
|
||||
"default.command=list # When no arguments are specified\n"
|
||||
"\n"
|
||||
"_forcecolor=no # Forces color to be on, even for non TTY output\n"
|
||||
"blanklines=true # Use more whitespace in output\n"
|
||||
"complete.all.projects=no # Include old project names in 'projects' command\n" // TODO
|
||||
"complete.all.tags=no # Include old tag names in 'tags' command\n" // TODO
|
||||
"debug=no # Display diagnostics\n"
|
||||
"hooks=off # Hook system master switch\n"
|
||||
"fontunderline=yes # Uses underlines rather than -------\n"
|
||||
"shell.prompt=task> # Prompt used by the shell command\n" // TODO
|
||||
"_forcecolor=no # Forces color to be on, even for non TTY output\n"
|
||||
"blanklines=true # Use more whitespace in output\n"
|
||||
"complete.all.projects=no # Include old project names in '_projects' command\n"
|
||||
"complete.all.tags=no # Include old tag names in '_ags' command\n"
|
||||
"list.all.projects=no # Include old project names in 'projects' command\n"
|
||||
"list.all.tags=no # Include old tag names in 'tags' command\n"
|
||||
"debug=no # Display diagnostics\n"
|
||||
"hooks=off # Hook system master switch\n"
|
||||
"fontunderline=yes # Uses underlines rather than -------\n"
|
||||
"shell.prompt=task> # Prompt used by the shell command\n"
|
||||
"\n"
|
||||
"# Import heuristics - alternate names for fields (comma-separated list of names)\n"
|
||||
"#import.synonym.bg=?\n"
|
||||
@@ -159,8 +216,15 @@ std::string Config::defaults =
|
||||
"#import.synonym.tags=?\n"
|
||||
"#import.synonym.uuid=?\n"
|
||||
"\n"
|
||||
"# Export Controls\n"
|
||||
"export.ical.class=PRIVATE # Could be PUBLIC, PRIVATE or CONFIDENTIAL\n"
|
||||
"\n"
|
||||
"# Aliases - alternate names for commands\n"
|
||||
"alias.rm=delete # Alias for the delete command\n"
|
||||
"alias.rm=delete # Alias for the delete command\n"
|
||||
"alias.history=history.monthly # Prefer monthly over annual history reports\n"
|
||||
"alias.ghistory=ghistory.monthly # Prefer monthly graphical over annual history reports\n"
|
||||
"alias.export=export.csv # Prefer CSV over iCal export\n"
|
||||
"alias.export.vcalendar=export.ical # They are the same\n"
|
||||
"\n"
|
||||
"# Fields: id,uuid,project,priority,priority_long,entry,entry_time,\n" // TODO
|
||||
"# start,entry_time,due,recur,recurrence_indicator,age,\n" // TODO
|
||||
@@ -184,7 +248,7 @@ std::string Config::defaults =
|
||||
"report.list.description=Lists all tasks matching the specified criteria\n"
|
||||
"report.list.columns=id,project,priority,due,active,age,description\n"
|
||||
"report.list.labels=ID,Project,Pri,Due,Active,Age,Description\n"
|
||||
"report.list.sort=due+,priority-,project+\n"
|
||||
"report.list.sort=due+,priority-,active-,project+\n"
|
||||
"report.list.filter=status:pending\n"
|
||||
"#report.list.dateformat=m/d/Y\n"
|
||||
"#report.list.annotations=full\n"
|
||||
@@ -229,7 +293,7 @@ std::string Config::defaults =
|
||||
"report.overdue.description=Lists overdue tasks matching the specified criteria\n"
|
||||
"report.overdue.columns=id,project,priority,due,active,age,description\n"
|
||||
"report.overdue.labels=ID,Project,Pri,Due,Active,Age,Description\n"
|
||||
"report.overdue.sort=due+,priority-,project+\n"
|
||||
"report.overdue.sort=due+,priority-,active-,project+\n"
|
||||
"report.overdue.filter=status:pending due.before:today\n"
|
||||
"#report.overdue.dateformat=m/d/Y\n"
|
||||
"#report.overdue.annotations=full\n"
|
||||
@@ -256,7 +320,7 @@ std::string Config::defaults =
|
||||
"report.recurring.description=Lists recurring tasks matching the specified criteria\n"
|
||||
"report.recurring.columns=id,project,priority,due,recur,active,age,description\n"
|
||||
"report.recurring.labels=ID,Project,Pri,Due,Recur,Active,Age,Description\n"
|
||||
"report.recurring.sort=due+,priority-,project+\n"
|
||||
"report.recurring.sort=due+,priority-,active-,project+\n"
|
||||
"report.recurring.filter=status:pending parent.any:\n"
|
||||
"#report.recurring.dateformat=m/d/Y\n"
|
||||
"#report.recurring.annotations=full\n"
|
||||
@@ -274,7 +338,7 @@ std::string Config::defaults =
|
||||
"report.all.description=Lists all tasks matching the specified criteria\n"
|
||||
"report.all.columns=id,project,priority,due,active,age,description\n"
|
||||
"report.all.labels=ID,Project,Pri,Due,Active,Age,Description\n"
|
||||
"report.all.sort=due+,priority-,project+\n"
|
||||
"report.all.sort=due+,priority-,active-,project+\n"
|
||||
"#report.all.dateformat=m/d/Y\n"
|
||||
"#report.all.annotations=full\n"
|
||||
"\n"
|
||||
@@ -282,8 +346,8 @@ std::string Config::defaults =
|
||||
"report.next.description=Lists the most urgent tasks\n"
|
||||
"report.next.columns=id,project,priority,due,active,age,description\n"
|
||||
"report.next.labels=ID,Project,Pri,Due,Active,Age,Description\n"
|
||||
"report.next.sort=due+,priority-,project+\n"
|
||||
"report.next.filter=status:pending\n"
|
||||
"report.next.sort=due+,priority-,active-,project+\n"
|
||||
"report.next.filter=status:pending limit:page\n"
|
||||
"#report.next.dateformat=m/d/Y\n"
|
||||
"#report.next.annotations=full\n"
|
||||
"\n";
|
||||
|
||||
164
src/Context.cpp
164
src/Context.cpp
@@ -205,52 +205,59 @@ int Context::dispatch (std::string &out)
|
||||
hooks.trigger ("pre-dispatch");
|
||||
|
||||
// TODO Just look at this thing. It cries out for a dispatch table.
|
||||
if (cmd.command == "projects") { rc = handleProjects (out); }
|
||||
else if (cmd.command == "tags") { rc = handleTags (out); }
|
||||
else if (cmd.command == "colors") { rc = handleColor (out); }
|
||||
else if (cmd.command == "version") { rc = handleVersion (out); }
|
||||
else if (cmd.command == "config") { rc = handleConfig (out); }
|
||||
else if (cmd.command == "help") { rc = longUsage (out); }
|
||||
else if (cmd.command == "stats") { rc = handleReportStats (out); }
|
||||
else if (cmd.command == "info") { rc = handleInfo (out); }
|
||||
else if (cmd.command == "history") { rc = handleReportHistory (out); }
|
||||
else if (cmd.command == "ghistory") { rc = handleReportGHistory (out); }
|
||||
else if (cmd.command == "summary") { rc = handleReportSummary (out); }
|
||||
else if (cmd.command == "calendar") { rc = handleReportCalendar (out); }
|
||||
else if (cmd.command == "timesheet") { rc = handleReportTimesheet (out); }
|
||||
else if (cmd.command == "add") { rc = handleAdd (out); }
|
||||
else if (cmd.command == "append") { rc = handleAppend (out); }
|
||||
else if (cmd.command == "prepend") { rc = handlePrepend (out); }
|
||||
else if (cmd.command == "annotate") { rc = handleAnnotate (out); }
|
||||
else if (cmd.command == "done") { rc = handleDone (out); }
|
||||
else if (cmd.command == "delete") { rc = handleDelete (out); }
|
||||
else if (cmd.command == "start") { rc = handleStart (out); }
|
||||
else if (cmd.command == "stop") { rc = handleStop (out); }
|
||||
else if (cmd.command == "export") { rc = handleExport (out); }
|
||||
else if (cmd.command == "import") { rc = handleImport (out); }
|
||||
else if (cmd.command == "duplicate") { rc = handleDuplicate (out); }
|
||||
else if (cmd.command == "edit") { rc = handleEdit (out); }
|
||||
if (cmd.command == "projects") { rc = handleProjects (out); }
|
||||
else if (cmd.command == "tags") { rc = handleTags (out); }
|
||||
else if (cmd.command == "colors") { rc = handleColor (out); }
|
||||
else if (cmd.command == "version") { rc = handleVersion (out); }
|
||||
else if (cmd.command == "config") { rc = handleConfig (out); }
|
||||
else if (cmd.command == "show") { rc = handleShow (out); }
|
||||
else if (cmd.command == "help") { rc = longUsage (out); }
|
||||
else if (cmd.command == "stats") { rc = handleReportStats (out); }
|
||||
else if (cmd.command == "info") { rc = handleInfo (out); }
|
||||
else if (cmd.command == "history.monthly") { rc = handleReportHistoryMonthly (out); }
|
||||
else if (cmd.command == "history.annual") { rc = handleReportHistoryAnnual (out); }
|
||||
else if (cmd.command == "ghistory.monthly") { rc = handleReportGHistoryMonthly (out); }
|
||||
else if (cmd.command == "ghistory.annual") { rc = handleReportGHistoryAnnual (out); }
|
||||
else if (cmd.command == "summary") { rc = handleReportSummary (out); }
|
||||
else if (cmd.command == "calendar") { rc = handleReportCalendar (out); }
|
||||
else if (cmd.command == "timesheet") { rc = handleReportTimesheet (out); }
|
||||
else if (cmd.command == "add") { rc = handleAdd (out); }
|
||||
else if (cmd.command == "log") { rc = handleLog (out); }
|
||||
else if (cmd.command == "append") { rc = handleAppend (out); }
|
||||
else if (cmd.command == "prepend") { rc = handlePrepend (out); }
|
||||
else if (cmd.command == "annotate") { rc = handleAnnotate (out); }
|
||||
else if (cmd.command == "denotate") { rc = handleDenotate (out); }
|
||||
else if (cmd.command == "done") { rc = handleDone (out); }
|
||||
else if (cmd.command == "delete") { rc = handleDelete (out); }
|
||||
else if (cmd.command == "start") { rc = handleStart (out); }
|
||||
else if (cmd.command == "stop") { rc = handleStop (out); }
|
||||
else if (cmd.command == "export.csv") { rc = handleExportCSV (out); }
|
||||
else if (cmd.command == "export.ical") { rc = handleExportiCal (out); }
|
||||
else if (cmd.command == "import") { rc = handleImport (out); }
|
||||
else if (cmd.command == "duplicate") { rc = handleDuplicate (out); }
|
||||
else if (cmd.command == "edit") { rc = handleEdit (out); }
|
||||
#ifdef FEATURE_SHELL
|
||||
else if (cmd.command == "shell") { handleShell ( ); }
|
||||
else if (cmd.command == "shell") { handleShell ( ); }
|
||||
#endif
|
||||
else if (cmd.command == "undo") { handleUndo ( ); }
|
||||
else if (cmd.command == "_projects") { rc = handleCompletionProjects (out); }
|
||||
else if (cmd.command == "_tags") { rc = handleCompletionTags (out); }
|
||||
else if (cmd.command == "_commands") { rc = handleCompletionCommands (out); }
|
||||
else if (cmd.command == "_ids") { rc = handleCompletionIDs (out); }
|
||||
else if (cmd.command == "_config") { rc = handleCompletionConfig (out); }
|
||||
else if (cmd.command == "_version") { rc = handleCompletionVersion (out); }
|
||||
else if (cmd.command == "undo") { handleUndo ( ); }
|
||||
else if (cmd.command == "_merge") { handleMerge (out); }
|
||||
else if (cmd.command == "_projects") { rc = handleCompletionProjects (out); }
|
||||
else if (cmd.command == "_tags") { rc = handleCompletionTags (out); }
|
||||
else if (cmd.command == "_commands") { rc = handleCompletionCommands (out); }
|
||||
else if (cmd.command == "_ids") { rc = handleCompletionIDs (out); }
|
||||
else if (cmd.command == "_config") { rc = handleCompletionConfig (out); }
|
||||
else if (cmd.command == "_version") { rc = handleCompletionVersion (out); }
|
||||
else if (cmd.command == "" &&
|
||||
sequence.size ()) { rc = handleModify (out); }
|
||||
sequence.size ()) { rc = handleModify (out); }
|
||||
|
||||
// Command that display IDs and therefore need TDB::gc first.
|
||||
else if (cmd.command == "next") { if (!inShadow) tdb.gc (); rc = handleReportNext (out); }
|
||||
else if (cmd.validCustom (cmd.command)) { if (!inShadow) tdb.gc (); rc = handleCustomReport (cmd.command, out); }
|
||||
else if (cmd.command == "next") { if (!inShadow) tdb.gc (); rc = handleReportNext (out); }
|
||||
else if (cmd.validCustom (cmd.command)) { if (!inShadow) tdb.gc (); rc = handleCustomReport (cmd.command, out); }
|
||||
|
||||
// If the command is not recognized, display usage.
|
||||
else { hooks.trigger ("pre-usage-command");
|
||||
rc = shortUsage (out);
|
||||
hooks.trigger ("post-usage-command"); }
|
||||
else { hooks.trigger ("pre-usage-command");
|
||||
rc = shortUsage (out);
|
||||
hooks.trigger ("post-usage-command"); }
|
||||
|
||||
// Only update the shadow file if such an update was not suppressed (shadow),
|
||||
if (cmd.isWriteCommand () && !inShadow)
|
||||
@@ -269,17 +276,15 @@ void Context::shadow ()
|
||||
{
|
||||
inShadow = true; // Prevents recursion in case shadow command writes.
|
||||
|
||||
// TODO Reinstate these checks.
|
||||
/*
|
||||
// Check for silly shadow file settings.
|
||||
if (shadowFile == dataLocation + "/pending.data")
|
||||
std::string dataLocation = config.get ("data.location");
|
||||
if (shadowFile.data == dataLocation + "/pending.data")
|
||||
throw std::string ("Configuration variable 'shadow.file' is set to "
|
||||
"overwrite your pending tasks. Please change it.");
|
||||
|
||||
if (shadowFile == dataLocation + "/completed.data")
|
||||
if (shadowFile.data == dataLocation + "/completed.data")
|
||||
throw std::string ("Configuration variable 'shadow.file' is set to "
|
||||
"overwrite your completed tasks. Please change it.");
|
||||
*/
|
||||
|
||||
std::string oldCurses = config.get ("curses");
|
||||
std::string oldColor = config.get ("color");
|
||||
@@ -526,6 +531,7 @@ void Context::parse (
|
||||
bool terminated = false;
|
||||
bool foundSequence = false;
|
||||
bool foundSomethingAfterSequence = false;
|
||||
bool foundNonSequence = false;
|
||||
|
||||
foreach (arg, parseArgs)
|
||||
{
|
||||
@@ -540,7 +546,7 @@ void Context::parse (
|
||||
|
||||
// Sequence
|
||||
// Note: "add" doesn't require an ID
|
||||
else if (parseCmd.command != "add" &&
|
||||
else if (parseCmd.command != "add" &&
|
||||
! foundSomethingAfterSequence &&
|
||||
parseSequence.valid (*arg))
|
||||
{
|
||||
@@ -558,6 +564,8 @@ void Context::parse (
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
foundNonSequence = true;
|
||||
|
||||
if (arg->find (',') != std::string::npos)
|
||||
throw stringtable.get (TAGS_NO_COMMA,
|
||||
"Tags are not permitted to contain commas.");
|
||||
@@ -575,6 +583,8 @@ void Context::parse (
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
foundNonSequence = true;
|
||||
|
||||
if (arg->find (',') != std::string::npos)
|
||||
throw stringtable.get (TAGS_NO_COMMA,
|
||||
"Tags are not permitted to contain commas.");
|
||||
@@ -589,6 +599,8 @@ void Context::parse (
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
foundNonSequence = true;
|
||||
|
||||
attribute.parse (*arg);
|
||||
|
||||
// There has to be a better way. And it starts with a fresh coffee.
|
||||
@@ -618,6 +630,8 @@ void Context::parse (
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
foundNonSequence = true;
|
||||
|
||||
if (descCandidate.length ())
|
||||
descCandidate += " ";
|
||||
descCandidate += *arg;
|
||||
@@ -630,6 +644,8 @@ void Context::parse (
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
foundNonSequence = true;
|
||||
|
||||
debug ("parse subst '" + *arg + "'");
|
||||
parseSubst.parse (*arg);
|
||||
}
|
||||
@@ -643,6 +659,8 @@ void Context::parse (
|
||||
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
foundNonSequence = true;
|
||||
}
|
||||
|
||||
// Anything else is just considered description.
|
||||
@@ -651,6 +669,8 @@ void Context::parse (
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
foundNonSequence = true;
|
||||
|
||||
if (descCandidate.length ())
|
||||
descCandidate += " ";
|
||||
descCandidate += *arg;
|
||||
@@ -675,6 +695,8 @@ void Context::parse (
|
||||
debug ("parse description '" + descCandidate + "'");
|
||||
parseTask.set ("description", descCandidate);
|
||||
|
||||
foundNonSequence = true;
|
||||
|
||||
// Now convert the description to a filter on each word, if necessary.
|
||||
if (parseCmd.isReadOnlyCommand ())
|
||||
{
|
||||
@@ -701,31 +723,43 @@ void Context::parse (
|
||||
|
||||
// If no command was specified, and there were no command line arguments
|
||||
// then invoke the default command.
|
||||
if (parseCmd.command == "" && parseArgs.size () == 0)
|
||||
if (parseCmd.command == "")
|
||||
{
|
||||
// Apply overrides, if any.
|
||||
std::string defaultCommand = config.get ("default.command");
|
||||
if (defaultCommand != "")
|
||||
if (parseArgs.size () == 0)
|
||||
{
|
||||
// Add on the overrides.
|
||||
defaultCommand += " " + file_override + " " + var_overrides;
|
||||
// Apply overrides, if any.
|
||||
std::string defaultCommand = config.get ("default.command");
|
||||
if (defaultCommand != "")
|
||||
{
|
||||
// Add on the overrides.
|
||||
defaultCommand += " " + file_override + " " + var_overrides;
|
||||
|
||||
// Stuff the command line.
|
||||
args.clear ();
|
||||
split (args, defaultCommand, ' ');
|
||||
header ("[task " + trim (defaultCommand) + "]");
|
||||
// Stuff the command line.
|
||||
args.clear ();
|
||||
split (args, defaultCommand, ' ');
|
||||
header ("[task " + trim (defaultCommand) + "]");
|
||||
|
||||
// Reinitialize the context and recurse.
|
||||
file_override = "";
|
||||
var_overrides = "";
|
||||
footnotes.clear ();
|
||||
initialize ();
|
||||
parse (args, cmd, task, sequence, subst, filter);
|
||||
// Reinitialize the context and recurse.
|
||||
file_override = "";
|
||||
var_overrides = "";
|
||||
footnotes.clear ();
|
||||
initialize ();
|
||||
parse (args, cmd, task, sequence, subst, filter);
|
||||
}
|
||||
else
|
||||
throw stringtable.get (
|
||||
CMD_MISSING,
|
||||
"You must specify a command, or a task ID to modify");
|
||||
}
|
||||
|
||||
// If the command "task 123" is entered, but with no modifier arguments,
|
||||
// then the actual command is assumed to be "info".
|
||||
else if (!foundNonSequence &&
|
||||
(parseTask.id != 0 || parseSequence.size () != 0))
|
||||
{
|
||||
std::cout << "No command - assuming 'info'." << std::endl;
|
||||
parseCmd.command = "info";
|
||||
}
|
||||
else
|
||||
throw stringtable.get (
|
||||
CMD_MISSING,
|
||||
"You must specify a command, or a task ID to modify");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ public:
|
||||
void shadow (); // shadow file update
|
||||
|
||||
int getWidth (); // determine terminal width
|
||||
int getHeight (); // determine terminal height
|
||||
|
||||
void header (const std::string&); // Header message sink
|
||||
void footnote (const std::string&); // Footnote message sink
|
||||
@@ -93,7 +94,6 @@ public:
|
||||
std::vector <std::string> tagRemovals;
|
||||
Hooks hooks;
|
||||
|
||||
private:
|
||||
std::vector <std::string> headers;
|
||||
std::vector <std::string> footnotes;
|
||||
std::vector <std::string> debugMessages;
|
||||
|
||||
30
src/Date.cpp
30
src/Date.cpp
@@ -25,6 +25,7 @@
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
@@ -85,7 +86,7 @@ Date::Date (const std::string& mdy, const std::string& format /* = "m/d/Y" */)
|
||||
{
|
||||
int month = 0;
|
||||
int day = 0;
|
||||
int year = 0;
|
||||
int year = -1; // So we can check later.
|
||||
int hour = 0;
|
||||
int minute = 0;
|
||||
int second = 0;
|
||||
@@ -331,6 +332,14 @@ Date::Date (const std::string& mdy, const std::string& format /* = "m/d/Y" */)
|
||||
}
|
||||
}
|
||||
|
||||
// Default the year to the current year, for formats that lack Y/y.
|
||||
if (year == -1)
|
||||
{
|
||||
time_t now = time (NULL);
|
||||
struct tm* default_year = localtime (&now);
|
||||
year = default_year->tm_year + 1900;
|
||||
}
|
||||
|
||||
if (i < mdy.length ())
|
||||
throw std::string ("\"") + mdy + "\" is not a valid date in " + format + " format.";
|
||||
|
||||
@@ -375,6 +384,25 @@ std::string Date::toEpochString ()
|
||||
return epoch.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 19980119T070000Z = YYYYMMDDThhmmssZ
|
||||
std::string Date::toISO ()
|
||||
{
|
||||
struct tm* t = gmtime (&mT);
|
||||
|
||||
std::stringstream iso;
|
||||
iso << std::setw (4) << std::setfill ('0') << t->tm_year + 1900
|
||||
<< std::setw (2) << std::setfill ('0') << t->tm_mon + 1
|
||||
<< std::setw (2) << std::setfill ('0') << t->tm_mday
|
||||
<< "T"
|
||||
<< std::setw (2) << std::setfill ('0') << t->tm_hour
|
||||
<< std::setw (2) << std::setfill ('0') << t->tm_min
|
||||
<< std::setw (2) << std::setfill ('0') << t->tm_sec
|
||||
<< "Z";
|
||||
|
||||
return iso.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Date::toEpoch (time_t& epoch)
|
||||
{
|
||||
|
||||
@@ -47,6 +47,7 @@ public:
|
||||
void toEpoch (time_t&);
|
||||
time_t toEpoch ();
|
||||
std::string toEpochString ();
|
||||
std::string toISO ();
|
||||
void toMDY (int&, int&, int&);
|
||||
const std::string toString (const std::string& format = "m/d/Y") const;
|
||||
const std::string toStringWithTime (const std::string& format = "m/d/Y") const;
|
||||
|
||||
245
src/Duration.cpp
245
src/Duration.cpp
@@ -29,20 +29,32 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "text.h"
|
||||
#include "util.h"
|
||||
#include "Duration.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Duration::Duration ()
|
||||
: mDays (0)
|
||||
: mSecs (0)
|
||||
, mNegative (false)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Duration::Duration (time_t input)
|
||||
{
|
||||
mDays = input;
|
||||
if (input < 0)
|
||||
{
|
||||
mSecs = -input;
|
||||
mNegative = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mSecs = input;
|
||||
mNegative = false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -54,27 +66,101 @@ Duration::Duration (const std::string& input)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Duration::operator time_t ()
|
||||
{
|
||||
return mDays;
|
||||
return mSecs;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Duration::operator std::string ()
|
||||
{
|
||||
std::stringstream s;
|
||||
s << mDays;
|
||||
s << (mNegative ? -mSecs : mSecs);
|
||||
return s.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Duration& Duration::operator= (const Duration& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
mSecs = other.mSecs;
|
||||
mNegative = other.mNegative;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Duration::format () const
|
||||
{
|
||||
char formatted[24];
|
||||
float days = (float) mSecs / 86400.0;
|
||||
|
||||
if (mSecs >= 86400 * 365)
|
||||
sprintf (formatted, "%s%.1f yrs", (mNegative ? "-" : ""), (days / 365));
|
||||
else if (mSecs > 86400 * 84)
|
||||
sprintf (formatted, "%s%1d mth%s",
|
||||
(mNegative ? "-" : ""), (int) (float) (days / 30.6),
|
||||
((int) (float) (days / 30.6) == 1 ? "" : "s"));
|
||||
else if (mSecs > 86400 * 13)
|
||||
sprintf (formatted, "%s%d wk%s",
|
||||
(mNegative ? "-" : ""), (int) (float) (days / 7.0),
|
||||
((int) (float) (days / 7.0) == 1 ? "" : "s"));
|
||||
else if (mSecs >= 86400)
|
||||
sprintf (formatted, "%s%d day%s",
|
||||
(mNegative ? "-" : ""), (int) days,
|
||||
((int) days == 1 ? "" : "s"));
|
||||
else if (mSecs >= 3600)
|
||||
sprintf (formatted, "%s%d hr%s",
|
||||
(mNegative ? "-" : ""), (int) (float) (mSecs / 3600),
|
||||
((int) (float) (mSecs / 3600) == 1 ? "" : "s"));
|
||||
else if (mSecs >= 60)
|
||||
sprintf (formatted, "%s%d min%s",
|
||||
(mNegative ? "-" : ""), (int) (float) (mSecs / 60),
|
||||
((int) (float) (mSecs / 60) == 1 ? "" : "s"));
|
||||
else if (mSecs >= 1)
|
||||
sprintf (formatted, "%s%d sec%s",
|
||||
(mNegative ? "-" : ""), (int) mSecs,
|
||||
((int) mSecs == 1 ? "" : "s"));
|
||||
else
|
||||
strcpy (formatted, "-"); // no i18n
|
||||
|
||||
return std::string (formatted);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Duration::formatCompact () const
|
||||
{
|
||||
char formatted[24];
|
||||
float days = (float) mSecs / 86400.0;
|
||||
|
||||
if (mSecs >= 86400 * 365) sprintf (formatted, "%s%.1fy", (mNegative ? "-" : ""), (days / 365));
|
||||
else if (mSecs >= 86400 * 84) sprintf (formatted, "%s%1dmo", (mNegative ? "-" : ""), (int) (float) (days / 30.6));
|
||||
else if (mSecs >= 86400 * 13) sprintf (formatted, "%s%dwk", (mNegative ? "-" : ""), (int) (float) (days / 7.0));
|
||||
else if (mSecs >= 86400) sprintf (formatted, "%s%dd", (mNegative ? "-" : ""), (int) days);
|
||||
else if (mSecs >= 3600) sprintf (formatted, "%s%dh", (mNegative ? "-" : ""), (int) (float) (mSecs / 3600));
|
||||
else if (mSecs >= 60) sprintf (formatted, "%s%dm", (mNegative ? "-" : ""), (int) (float) (mSecs / 60));
|
||||
else if (mSecs >= 1) sprintf (formatted, "%s%ds", (mNegative ? "-" : ""), (int) mSecs);
|
||||
else strcpy (formatted, "-");
|
||||
|
||||
return std::string (formatted);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Duration::operator< (const Duration& other)
|
||||
{
|
||||
return mDays < other.mDays;
|
||||
long left = (long) ( mNegative ? -mSecs : mSecs);
|
||||
long right = (long) (other.mNegative ? -other.mSecs : other.mSecs);
|
||||
|
||||
return left < right;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Duration::operator> (const Duration& other)
|
||||
{
|
||||
return mDays > other.mDays;
|
||||
long left = (long) ( mNegative ? -mSecs : mSecs);
|
||||
long right = (long) (other.mNegative ? -other.mSecs : other.mSecs);
|
||||
|
||||
return left > right;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -108,22 +194,52 @@ bool Duration::valid (const std::string& input) const
|
||||
if (autoComplete (lower_input, supported, matches) == 1)
|
||||
return true;
|
||||
|
||||
// Support \d+ d|w|m|q|y
|
||||
// Verify all digits followed by d, w, m, q, or y.
|
||||
unsigned int length = lower_input.length ();
|
||||
for (unsigned int i = 0; i < length; ++i)
|
||||
// Support \s+ -? \d+ \s? s|secs?|m|mins?|h|hrs?|d|days?|wks?|mo|mths?|y|yrs?|-
|
||||
// Note: Does not support a sign character. That must be external to
|
||||
// Duration.
|
||||
Nibbler n (lower_input);
|
||||
int value;
|
||||
|
||||
n.skipAll (' ');
|
||||
n.skip ('-');
|
||||
|
||||
if (n.getUnsignedInt (value))
|
||||
{
|
||||
if (! isdigit (lower_input[i]) &&
|
||||
i == length - 1)
|
||||
{
|
||||
std::string type = lower_input.substr (length - 1);
|
||||
if (type == "d" || // TODO i18n
|
||||
type == "w" || // TODO i18n
|
||||
type == "m" || // TODO i18n
|
||||
type == "q" || // TODO i18n
|
||||
type == "y") // TODO i18n
|
||||
return true;
|
||||
}
|
||||
n.skipAll (' ');
|
||||
|
||||
if (n.getLiteral ("yrs") && n.depleted ()) return true;
|
||||
else if (n.getLiteral ("yr") && n.depleted ()) return true;
|
||||
else if (n.getLiteral ("y") && n.depleted ()) return true;
|
||||
|
||||
else if (n.getLiteral ("qtrs") && n.depleted ()) return true;
|
||||
else if (n.getLiteral ("qtr") && n.depleted ()) return true;
|
||||
else if (n.getLiteral ("q") && n.depleted ()) return true;
|
||||
|
||||
else if (n.getLiteral ("mths") && n.depleted ()) return true;
|
||||
else if (n.getLiteral ("mth") && n.depleted ()) return true;
|
||||
else if (n.getLiteral ("mo") && n.depleted ()) return true;
|
||||
|
||||
else if (n.getLiteral ("wks") && n.depleted ()) return true;
|
||||
else if (n.getLiteral ("wk") && n.depleted ()) return true;
|
||||
else if (n.getLiteral ("w") && n.depleted ()) return true;
|
||||
|
||||
else if (n.getLiteral ("days") && n.depleted ()) return true;
|
||||
else if (n.getLiteral ("day") && n.depleted ()) return true;
|
||||
else if (n.getLiteral ("d") && n.depleted ()) return true;
|
||||
|
||||
else if (n.getLiteral ("hrs") && n.depleted ()) return true;
|
||||
else if (n.getLiteral ("hr") && n.depleted ()) return true;
|
||||
else if (n.getLiteral ("h") && n.depleted ()) return true;
|
||||
|
||||
else if (n.getLiteral ("mins") && n.depleted ()) return true;
|
||||
else if (n.getLiteral ("min") && n.depleted ()) return true;
|
||||
else if (n.getLiteral ("m") && n.depleted ()) return true;
|
||||
|
||||
else if (n.getLiteral ("secs") && n.depleted ()) return true;
|
||||
else if (n.getLiteral ("sec") && n.depleted ()) return true;
|
||||
else if (n.getLiteral ("s") && n.depleted ()) return true;
|
||||
|
||||
else if (n.getLiteral ("-") && n.depleted ()) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -156,43 +272,72 @@ void Duration::parse (const std::string& input)
|
||||
{
|
||||
std::string found = matches[0];
|
||||
|
||||
if (found == "daily" || found == "day") mDays = 1; // TODO i18n
|
||||
else if (found == "weekdays") mDays = 1; // TODO i18n
|
||||
else if (found == "weekly" || found == "sennight") mDays = 7; // TODO i18n
|
||||
else if (found == "biweekly" || found == "fortnight") mDays = 14; // TODO i18n
|
||||
else if (found == "monthly") mDays = 30; // TODO i18n
|
||||
else if (found == "bimonthly") mDays = 61; // TODO i18n
|
||||
else if (found == "quarterly") mDays = 91; // TODO i18n
|
||||
else if (found == "semiannual") mDays = 183; // TODO i18n
|
||||
else if (found == "yearly" || found == "annual") mDays = 365; // TODO i18n
|
||||
else if (found == "biannual" || found == "biyearly") mDays = 730; // TODO i18n
|
||||
if (found == "daily" || found == "day") mSecs = 86400 * 1; // TODO i18n
|
||||
else if (found == "weekdays") mSecs = 86400 * 1; // TODO i18n
|
||||
else if (found == "weekly" || found == "sennight") mSecs = 86400 * 7; // TODO i18n
|
||||
else if (found == "biweekly" || found == "fortnight") mSecs = 86400 * 14; // TODO i18n
|
||||
else if (found == "monthly") mSecs = 86400 * 30; // TODO i18n
|
||||
else if (found == "bimonthly") mSecs = 86400 * 61; // TODO i18n
|
||||
else if (found == "quarterly") mSecs = 86400 * 91; // TODO i18n
|
||||
else if (found == "semiannual") mSecs = 86400 * 183; // TODO i18n
|
||||
else if (found == "yearly" || found == "annual") mSecs = 86400 * 365; // TODO i18n
|
||||
else if (found == "biannual" || found == "biyearly") mSecs = 86400 * 730; // TODO i18n
|
||||
}
|
||||
|
||||
// Support \d+ d|w|m|q|y
|
||||
// Support -? \d+ \s? s|secs?|m|mins?|h|hrs?|d|days?|wks?|mo|mths?|y|yrs?|-
|
||||
// Note: Does not support a sign character. That must be external to
|
||||
// Duration.
|
||||
else
|
||||
{
|
||||
// Verify all digits followed by d, w, m, q, or y.
|
||||
unsigned int length = lower_input.length ();
|
||||
for (unsigned int i = 0; i < length; ++i)
|
||||
{
|
||||
if (! isdigit (lower_input[i]) &&
|
||||
i == length - 1)
|
||||
{
|
||||
int number = atoi (lower_input.substr (0, i).c_str ());
|
||||
Nibbler n (lower_input);
|
||||
|
||||
switch (lower_input[length - 1])
|
||||
{
|
||||
case 'd': mDays = number * 1; break; // TODO i18n
|
||||
case 'w': mDays = number * 7; break; // TODO i18n
|
||||
case 'm': mDays = number * 30; break; // TODO i18n
|
||||
case 'q': mDays = number * 91; break; // TODO i18n
|
||||
case 'y': mDays = number * 365; break; // TODO i18n
|
||||
}
|
||||
}
|
||||
n.skipAll (' ');
|
||||
mNegative = false;
|
||||
if (n.skip ('-'))
|
||||
mNegative = true;
|
||||
|
||||
int value;
|
||||
if (n.getUnsignedInt (value))
|
||||
{
|
||||
n.skipAll (' ');
|
||||
|
||||
if (n.getLiteral ("yrs") && n.depleted ()) mSecs = value * 86400 * 365;
|
||||
else if (n.getLiteral ("yr") && n.depleted ()) mSecs = value * 86400 * 365;
|
||||
else if (n.getLiteral ("y") && n.depleted ()) mSecs = value * 86400 * 365;
|
||||
|
||||
else if (n.getLiteral ("qtrs") && n.depleted ()) mSecs = value * 86400 * 91;
|
||||
else if (n.getLiteral ("qtr") && n.depleted ()) mSecs = value * 86400 * 91;
|
||||
else if (n.getLiteral ("q") && n.depleted ()) mSecs = value * 86400 * 91;
|
||||
|
||||
else if (n.getLiteral ("mths") && n.depleted ()) mSecs = value * 86400 * 30;
|
||||
else if (n.getLiteral ("mth") && n.depleted ()) mSecs = value * 86400 * 30;
|
||||
else if (n.getLiteral ("mo") && n.depleted ()) mSecs = value * 86400 * 30;
|
||||
|
||||
else if (n.getLiteral ("wks") && n.depleted ()) mSecs = value * 86400 * 7;
|
||||
else if (n.getLiteral ("wk") && n.depleted ()) mSecs = value * 86400 * 7;
|
||||
else if (n.getLiteral ("w") && n.depleted ()) mSecs = value * 86400 * 7;
|
||||
|
||||
else if (n.getLiteral ("days") && n.depleted ()) mSecs = value * 86400;
|
||||
else if (n.getLiteral ("day") && n.depleted ()) mSecs = value * 86400;
|
||||
else if (n.getLiteral ("d") && n.depleted ()) mSecs = value * 86400;
|
||||
|
||||
else if (n.getLiteral ("hrs") && n.depleted ()) mSecs = value * 3600;
|
||||
else if (n.getLiteral ("hr") && n.depleted ()) mSecs = value * 3600;
|
||||
else if (n.getLiteral ("h") && n.depleted ()) mSecs = value * 3600;
|
||||
|
||||
else if (n.getLiteral ("mins") && n.depleted ()) mSecs = value * 60;
|
||||
else if (n.getLiteral ("min") && n.depleted ()) mSecs = value * 60;
|
||||
else if (n.getLiteral ("m") && n.depleted ()) mSecs = value * 60;
|
||||
|
||||
else if (n.getLiteral ("secs") && n.depleted ()) mSecs = value;
|
||||
else if (n.getLiteral ("sec") && n.depleted ()) mSecs = value;
|
||||
else if (n.getLiteral ("s") && n.depleted ()) mSecs = value;
|
||||
|
||||
else if (n.getLiteral ("-") && n.depleted ()) mSecs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (mDays == 0)
|
||||
if (mSecs == 0)
|
||||
throw std::string ("The duration '") + input + "' was not recognized."; // TODO i18n
|
||||
}
|
||||
|
||||
|
||||
@@ -38,16 +38,21 @@ public:
|
||||
Duration (const std::string&); // Parse
|
||||
bool operator< (const Duration&);
|
||||
bool operator> (const Duration&);
|
||||
Duration& operator= (const Duration&);
|
||||
~Duration (); // Destructor
|
||||
|
||||
operator time_t ();
|
||||
operator std::string ();
|
||||
|
||||
std::string format () const;
|
||||
std::string formatCompact () const;
|
||||
|
||||
bool valid (const std::string&) const;
|
||||
void parse (const std::string&);
|
||||
|
||||
private:
|
||||
time_t mDays;
|
||||
time_t mSecs;
|
||||
bool mNegative;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -280,6 +280,7 @@ bool Hooks::validProgramEvent (const std::string& event)
|
||||
event == "pre-shell-prompt" || event == "post-shell-prompt" ||
|
||||
event == "pre-add-command" || event == "post-add-command" ||
|
||||
event == "pre-annotate-command" || event == "post-annotate-command" ||
|
||||
event == "pre-denotate-command" || event == "post-denotate-command" ||
|
||||
event == "pre-append-command" || event == "post-append-command" ||
|
||||
event == "pre-calendar-command" || event == "post-calendar-command" ||
|
||||
event == "pre-color-command" || event == "post-color-command" ||
|
||||
|
||||
@@ -4,13 +4,14 @@ task_SOURCES = API.cpp Att.cpp Cmd.cpp Color.cpp Config.cpp Context.cpp \
|
||||
Date.cpp Directory.cpp Duration.cpp File.cpp Filter.cpp \
|
||||
Grid.cpp Hooks.cpp Keymap.cpp Location.cpp Nibbler.cpp \
|
||||
Path.cpp Permission.cpp Record.cpp Sequence.cpp \
|
||||
StringTable.cpp Subst.cpp TDB.cpp Table.cpp Task.cpp Timer.cpp \
|
||||
command.cpp custom.cpp edit.cpp import.cpp interactive.cpp \
|
||||
main.cpp recur.cpp report.cpp rules.cpp text.cpp util.cpp \
|
||||
API.h Att.h Cmd.h Color.h Config.h Context.h Date.h \
|
||||
Directory.h Duration.h File.h Filter.h Grid.h Hooks.h Keymap.h \
|
||||
Location.h Nibbler.h Path.h Permission.h Record.h Sequence.h \
|
||||
StringTable.h Subst.h TDB.h Table.h Task.h Timer.h i18n.h \
|
||||
main.h text.h util.h
|
||||
StringTable.cpp Subst.cpp TDB.cpp Table.cpp Task.cpp \
|
||||
Taskmod.cpp Timer.cpp command.cpp custom.cpp edit.cpp \
|
||||
export.cpp import.cpp interactive.cpp main.cpp recur.cpp \
|
||||
report.cpp rules.cpp rx.cpp text.cpp util.cpp API.h Att.h \
|
||||
Cmd.h Color.h Config.h Context.h Date.h Directory.h Duration.h \
|
||||
File.h Filter.h Grid.h Hooks.h Keymap.h Location.h Nibbler.h \
|
||||
Path.h Permission.h Record.h Sequence.h StringTable.h Subst.h \
|
||||
TDB.h Table.h Task.h Taskmod.h Timer.h i18n.h main.h text.h \
|
||||
util.h rx.h
|
||||
task_CPPFLAGS=$(LUA_CFLAGS)
|
||||
task_LDFLAGS=$(LUA_LFLAGS)
|
||||
|
||||
318
src/Nibbler.cpp
318
src/Nibbler.cpp
@@ -1,7 +1,7 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// task - a command line task list manager.
|
||||
//
|
||||
// Copyright 2006 - 2010, Paul Beckingham.
|
||||
// Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -26,19 +26,26 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "Nibbler.h"
|
||||
#include "rx.h"
|
||||
|
||||
const char* c_digits = "0123456789";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Nibbler::Nibbler ()
|
||||
: mInput ("")
|
||||
, mLength (0)
|
||||
, mCursor (0)
|
||||
, mSaved (0)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Nibbler::Nibbler (const char* input)
|
||||
: mInput (input)
|
||||
, mLength (strlen (input))
|
||||
, mCursor (0)
|
||||
{
|
||||
}
|
||||
@@ -46,6 +53,7 @@ Nibbler::Nibbler (const char* input)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Nibbler::Nibbler (const std::string& input)
|
||||
: mInput (input)
|
||||
, mLength (input.length ())
|
||||
, mCursor (0)
|
||||
{
|
||||
}
|
||||
@@ -54,6 +62,7 @@ Nibbler::Nibbler (const std::string& input)
|
||||
Nibbler::Nibbler (const Nibbler& other)
|
||||
{
|
||||
mInput = other.mInput;
|
||||
mLength = other.mLength;
|
||||
mCursor = other.mCursor;
|
||||
}
|
||||
|
||||
@@ -63,6 +72,7 @@ Nibbler& Nibbler::operator= (const Nibbler& other)
|
||||
if (this != &other)
|
||||
{
|
||||
mInput = other.mInput;
|
||||
mLength = other.mLength;
|
||||
mCursor = other.mCursor;
|
||||
}
|
||||
|
||||
@@ -75,10 +85,10 @@ Nibbler::~Nibbler ()
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Extract up until the next c, or EOS.
|
||||
// Extract up until the next c (but not including) or EOS.
|
||||
bool Nibbler::getUntil (char c, std::string& result)
|
||||
{
|
||||
if (mCursor < mInput.length ())
|
||||
if (mCursor < mLength)
|
||||
{
|
||||
std::string::size_type i = mInput.find (c, mCursor);
|
||||
if (i != std::string::npos)
|
||||
@@ -89,7 +99,7 @@ bool Nibbler::getUntil (char c, std::string& result)
|
||||
else
|
||||
{
|
||||
result = mInput.substr (mCursor);
|
||||
mCursor = mInput.length ();
|
||||
mCursor = mLength;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -101,7 +111,7 @@ bool Nibbler::getUntil (char c, std::string& result)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::getUntil (const std::string& terminator, std::string& result)
|
||||
{
|
||||
if (mCursor < mInput.length ())
|
||||
if (mCursor < mLength)
|
||||
{
|
||||
std::string::size_type i = mInput.find (terminator, mCursor);
|
||||
if (i != std::string::npos)
|
||||
@@ -112,7 +122,37 @@ bool Nibbler::getUntil (const std::string& terminator, std::string& result)
|
||||
else
|
||||
{
|
||||
result = mInput.substr (mCursor);
|
||||
mCursor = mInput.length ();
|
||||
mCursor = mLength;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::getUntilRx (const std::string& regex, std::string& result)
|
||||
{
|
||||
if (mCursor < mLength)
|
||||
{
|
||||
std::string modified_regex;
|
||||
if (regex[0] != '(')
|
||||
modified_regex = "(" + regex + ")";
|
||||
else
|
||||
modified_regex = regex;
|
||||
|
||||
std::vector <int> start;
|
||||
std::vector <int> end;
|
||||
if (regexMatch (start, end, mInput.substr (mCursor), modified_regex, true))
|
||||
{
|
||||
result = mInput.substr (mCursor, start[0]);
|
||||
mCursor += start[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
result = mInput.substr (mCursor);
|
||||
mCursor = mLength;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -124,7 +164,7 @@ bool Nibbler::getUntil (const std::string& terminator, std::string& result)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::getUntilOneOf (const std::string& chars, std::string& result)
|
||||
{
|
||||
if (mCursor < mInput.length ())
|
||||
if (mCursor < mLength)
|
||||
{
|
||||
std::string::size_type i = mInput.find_first_of (chars, mCursor);
|
||||
if (i != std::string::npos)
|
||||
@@ -135,7 +175,7 @@ bool Nibbler::getUntilOneOf (const std::string& chars, std::string& result)
|
||||
else
|
||||
{
|
||||
result = mInput.substr (mCursor);
|
||||
mCursor = mInput.length ();
|
||||
mCursor = mLength;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -145,63 +185,24 @@ bool Nibbler::getUntilOneOf (const std::string& chars, std::string& result)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::skipN (const int quantity /* = 1 */)
|
||||
bool Nibbler::getUntilWS (std::string& result)
|
||||
{
|
||||
if (mCursor >= mInput.length ())
|
||||
return false;
|
||||
|
||||
if (mCursor <= mInput.length () - quantity)
|
||||
{
|
||||
mCursor += quantity;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return this->getUntilOneOf (" \t\r\n\f", result);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::skip (char c)
|
||||
bool Nibbler::getUntilEOL (std::string& result)
|
||||
{
|
||||
if (mCursor < mInput.length () &&
|
||||
mInput[mCursor] == c)
|
||||
{
|
||||
++mCursor;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return getUntil ('\n', result);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::skipAll (char c)
|
||||
bool Nibbler::getUntilEOS (std::string& result)
|
||||
{
|
||||
std::string::size_type i = mCursor;
|
||||
while (i < mInput.length () && mInput[i] == c)
|
||||
++i;
|
||||
|
||||
if (i != mCursor)
|
||||
if (mCursor < mLength)
|
||||
{
|
||||
mCursor = i;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::skipAllOneOf (const std::string& chars)
|
||||
{
|
||||
if (mCursor < mInput.length ())
|
||||
{
|
||||
std::string::size_type i = mInput.find_first_not_of (chars, mCursor);
|
||||
if (i == mCursor)
|
||||
return false;
|
||||
|
||||
if (i == std::string::npos)
|
||||
mCursor = mInput.length (); // Yes, off the end.
|
||||
else
|
||||
mCursor = i;
|
||||
|
||||
result = mInput.substr (mCursor);
|
||||
mCursor = mLength;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -211,22 +212,16 @@ bool Nibbler::skipAllOneOf (const std::string& chars)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::getQuoted (char c, std::string& result)
|
||||
{
|
||||
std::string::size_type start = mCursor;
|
||||
if (start < mInput.length () && mInput[start] == c)
|
||||
std::string::size_type backup = mCursor;
|
||||
|
||||
if (skip (c) &&
|
||||
getUntil (c, result) &&
|
||||
skip (c))
|
||||
{
|
||||
++start;
|
||||
if (start < mInput.length ())
|
||||
{
|
||||
std::string::size_type end = mInput.find (c, start);
|
||||
if (end != std::string::npos)
|
||||
{
|
||||
result = mInput.substr (start, end - start);
|
||||
mCursor = end + 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
mCursor = backup;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -235,7 +230,7 @@ bool Nibbler::getInt (int& result)
|
||||
{
|
||||
std::string::size_type i = mCursor;
|
||||
|
||||
if (i < mInput.length ())
|
||||
if (i < mLength)
|
||||
{
|
||||
if (mInput[i] == '-')
|
||||
++i;
|
||||
@@ -243,7 +238,8 @@ bool Nibbler::getInt (int& result)
|
||||
++i;
|
||||
}
|
||||
|
||||
while (i < mInput.length () && isdigit (mInput[i]))
|
||||
// TODO Potential for use of find_first_not_of
|
||||
while (i < mLength && isdigit (mInput[i]))
|
||||
++i;
|
||||
|
||||
if (i > mCursor)
|
||||
@@ -260,7 +256,8 @@ bool Nibbler::getInt (int& result)
|
||||
bool Nibbler::getUnsignedInt (int& result)
|
||||
{
|
||||
std::string::size_type i = mCursor;
|
||||
while (i < mInput.length () && isdigit (mInput[i]))
|
||||
// TODO Potential for use of find_first_not_of
|
||||
while (i < mLength && isdigit (mInput[i]))
|
||||
++i;
|
||||
|
||||
if (i > mCursor)
|
||||
@@ -274,31 +271,188 @@ bool Nibbler::getUnsignedInt (int& result)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::getUntilEOL (std::string& result)
|
||||
bool Nibbler::getLiteral (const std::string& literal)
|
||||
{
|
||||
return getUntil ('\n', result);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::getUntilEOS (std::string& result)
|
||||
{
|
||||
if (mCursor < mInput.length ())
|
||||
if (mCursor < mLength &&
|
||||
mInput.find (literal, mCursor) == mCursor)
|
||||
{
|
||||
result = mInput.substr (mCursor);
|
||||
mCursor = mInput.length ();
|
||||
mCursor += literal.length ();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::getRx (const std::string& regex, std::string& result)
|
||||
{
|
||||
if (mCursor < mLength)
|
||||
{
|
||||
// Regex may be anchored to the beginning and include capturing parentheses,
|
||||
// otherwise they are added.
|
||||
std::string modified_regex;
|
||||
if (regex.substr (0, 2) != "^(")
|
||||
modified_regex = "^(" + regex + ")";
|
||||
else
|
||||
modified_regex = regex;
|
||||
|
||||
std::vector <std::string> results;
|
||||
if (regexMatch (results, mInput.substr (mCursor), modified_regex, true))
|
||||
{
|
||||
result = results[0];
|
||||
mCursor += result.length ();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::skipN (const int quantity /* = 1 */)
|
||||
{
|
||||
if (mCursor < mLength &&
|
||||
mCursor <= mLength - quantity)
|
||||
{
|
||||
mCursor += quantity;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::skip (char c)
|
||||
{
|
||||
if (mCursor < mLength &&
|
||||
mInput[mCursor] == c)
|
||||
{
|
||||
++mCursor;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::skipAll (char c)
|
||||
{
|
||||
if (mCursor < mLength)
|
||||
{
|
||||
std::string::size_type i = mInput.find_first_not_of (c, mCursor);
|
||||
if (i == mCursor)
|
||||
return false;
|
||||
|
||||
if (i == std::string::npos)
|
||||
mCursor = mLength; // Yes, off the end.
|
||||
else
|
||||
mCursor = i;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::skipWS ()
|
||||
{
|
||||
return this->skipAllOneOf (" \t\n\r\f");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::skipRx (const std::string& regex)
|
||||
{
|
||||
if (mCursor < mLength)
|
||||
{
|
||||
// Regex may be anchored to the beginning and include capturing parentheses,
|
||||
// otherwise they are added.
|
||||
std::string modified_regex;
|
||||
if (regex.substr (0, 2) != "^(")
|
||||
modified_regex = "^(" + regex + ")";
|
||||
else
|
||||
modified_regex = regex;
|
||||
|
||||
std::vector <std::string> results;
|
||||
if (regexMatch (results, mInput.substr (mCursor), modified_regex, true))
|
||||
{
|
||||
mCursor += results[0].length ();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::skipAllOneOf (const std::string& chars)
|
||||
{
|
||||
if (mCursor < mLength)
|
||||
{
|
||||
std::string::size_type i = mInput.find_first_not_of (chars, mCursor);
|
||||
if (i == mCursor)
|
||||
return false;
|
||||
|
||||
if (i == std::string::npos)
|
||||
mCursor = mLength; // Yes, off the end.
|
||||
else
|
||||
mCursor = i;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Peeks ahead - does not move cursor.
|
||||
char Nibbler::next ()
|
||||
{
|
||||
if (mCursor < mLength)
|
||||
return mInput[mCursor];
|
||||
|
||||
return '\0';
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Peeks ahead - does not move cursor.
|
||||
std::string Nibbler::next (const int quantity)
|
||||
{
|
||||
if ( mCursor < mLength &&
|
||||
(unsigned) quantity <= mLength &&
|
||||
mCursor <= mLength - quantity)
|
||||
return mInput.substr (mCursor, quantity);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Nibbler::save ()
|
||||
{
|
||||
mSaved = mCursor;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Nibbler::restore ()
|
||||
{
|
||||
mCursor = mSaved;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Nibbler::depleted ()
|
||||
{
|
||||
if (mCursor >= mInput.length ())
|
||||
if (mCursor >= mLength)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Nibbler::dump ()
|
||||
{
|
||||
return std::string ("Nibbler ‹")
|
||||
+ mInput.substr (mCursor)
|
||||
+ "›";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// task - a command line task list manager.
|
||||
//
|
||||
// Copyright 2006 - 2010, Paul Beckingham.
|
||||
// Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez.
|
||||
// All rights reserved.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify it under
|
||||
@@ -41,21 +41,40 @@ public:
|
||||
|
||||
bool getUntil (char, std::string&);
|
||||
bool getUntil (const std::string&, std::string&);
|
||||
bool getUntilRx (const std::string&, std::string&);
|
||||
bool getUntilOneOf (const std::string&, std::string&);
|
||||
bool getUntilWS (std::string&);
|
||||
bool getUntilEOL (std::string&);
|
||||
bool getUntilEOS (std::string&);
|
||||
|
||||
bool getQuoted (char, std::string&);
|
||||
bool getInt (int&);
|
||||
bool getUnsignedInt (int&);
|
||||
bool getLiteral (const std::string&);
|
||||
bool getRx (const std::string&, std::string&);
|
||||
|
||||
bool skipN (const int quantity = 1);
|
||||
bool skip (char);
|
||||
bool skipAll (char);
|
||||
bool skipAllOneOf (const std::string&);
|
||||
bool getQuoted (char, std::string&);
|
||||
bool getInt (int&);
|
||||
bool getUnsignedInt (int&i);
|
||||
bool getUntilEOL (std::string&);
|
||||
bool getUntilEOS (std::string&);
|
||||
bool skipWS ();
|
||||
bool skipRx (const std::string&);
|
||||
|
||||
char next ();
|
||||
std::string next (const int quantity);
|
||||
|
||||
void save ();
|
||||
void restore ();
|
||||
|
||||
bool depleted ();
|
||||
|
||||
std::string dump ();
|
||||
|
||||
private:
|
||||
std::string mInput;
|
||||
std::string::size_type mLength;
|
||||
std::string::size_type mCursor;
|
||||
std::string::size_type mSaved;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
974
src/TDB.cpp
974
src/TDB.cpp
File diff suppressed because it is too large
Load Diff
@@ -62,6 +62,7 @@ public:
|
||||
int gc (); // Clean up pending
|
||||
int nextId ();
|
||||
void undo ();
|
||||
void merge (const std::string&);
|
||||
|
||||
private:
|
||||
FILE* openAndLock (const std::string&);
|
||||
@@ -75,11 +76,9 @@ private:
|
||||
int mId;
|
||||
|
||||
std::vector <Task> mPending; // Contents of pending.data
|
||||
|
||||
std::vector <Task> mCompleted; // Contents of pending.data
|
||||
std::vector <Task> mNew; // Uncommitted new tasks
|
||||
std::vector <Task> mModified; // Uncommitted modified tasks
|
||||
|
||||
// TODO Need cache of raw file contents to preserve comments.
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
304
src/Table.cpp
304
src/Table.cpp
@@ -63,7 +63,6 @@ Table::Table ()
|
||||
, mDashedUnderline (false)
|
||||
, mTablePadding (0)
|
||||
, mTableWidth (0)
|
||||
, mSuppressWS (false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -72,14 +71,6 @@ Table::~Table ()
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
void Table::setTableColor (const Color& c)
|
||||
{
|
||||
mColor["table"] = c;
|
||||
}
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Table::setTableAlternateColor (const Color& c)
|
||||
{
|
||||
@@ -123,17 +114,6 @@ int Table::addColumn (const std::string& col)
|
||||
return mColumns.size () - 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TODO Obsolete - this call is not used. Consider removal.
|
||||
/*
|
||||
void Table::setColumnColor (int column, const Color& c)
|
||||
{
|
||||
char id[12];
|
||||
sprintf (id, "col:%d", column);
|
||||
mColor[id] = c;
|
||||
}
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Table::setColumnUnderline (int column)
|
||||
{
|
||||
@@ -199,50 +179,23 @@ void Table::addCell (const int row, const int col, const std::string& data)
|
||||
{
|
||||
unsigned int length = 0;
|
||||
|
||||
if (mSuppressWS)
|
||||
if (mCommify.find (col) != mCommify.end ())
|
||||
mData.add (row, col, commify (data));
|
||||
else
|
||||
mData.add (row, col, data);
|
||||
|
||||
// For multi-line cells, find the longest line.
|
||||
if (data.find ("\n") != std::string::npos)
|
||||
{
|
||||
std::string data2;
|
||||
if (mCommify.find (col) != mCommify.end ())
|
||||
data2 = commify (data);
|
||||
else
|
||||
data2 = data;
|
||||
|
||||
clean (data2);
|
||||
// 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);
|
||||
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
|
||||
{
|
||||
if (mCommify.find (col) != mCommify.end ())
|
||||
mData.add (row, col, commify (data));
|
||||
else
|
||||
mData.add (row, col, data);
|
||||
|
||||
// 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 ();
|
||||
}
|
||||
length = data.length ();
|
||||
|
||||
// Automatically maintain max width.
|
||||
mMaxDataWidth[col] = max (mMaxDataWidth[col], (int)length);
|
||||
@@ -358,30 +311,6 @@ Color Table::getColor (const int index, const int row, const int col)
|
||||
return c;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TODO Obsolete - this is not used. Consider removal.
|
||||
Color Table::getHeaderColor (int col)
|
||||
{
|
||||
// Color defaults to trivial.
|
||||
Color c;
|
||||
|
||||
/*
|
||||
std::map <std::string, Color>::iterator i;
|
||||
char id[24];
|
||||
|
||||
// Blend with a table color, if specified.
|
||||
if ((i = mColor.find ("table")) != mColor.end ())
|
||||
c.blend (i->second);
|
||||
|
||||
// Blend with a column color, if specified.
|
||||
sprintf (id, "col:%d", col);
|
||||
if ((i = mColor.find (id)) != mColor.end ())
|
||||
c.blend (i->second);
|
||||
*/
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Color Table::getHeaderUnderline (int col)
|
||||
{
|
||||
@@ -526,31 +455,24 @@ const std::string Table::formatHeader (
|
||||
{
|
||||
assert (width > 0);
|
||||
|
||||
Color c = getHeaderColor (col);
|
||||
std::string data = mColumns[col];
|
||||
c.blend (getHeaderUnderline (col));
|
||||
Color c = getHeaderUnderline (col);
|
||||
int gap = width - strippedLength (data);
|
||||
|
||||
std::string pad = "";
|
||||
std::string intraPad = "";
|
||||
std::string preJust = "";
|
||||
std::string attrOn = "";
|
||||
std::string attrOff = "";
|
||||
std::string pad = std::string (padding, ' ');
|
||||
|
||||
// TODO When the following is replaced by:
|
||||
// std::string postJust = std::string (gap, ' ');
|
||||
// two unit tests fail.
|
||||
std::string postJust = "";
|
||||
|
||||
for (int i = 0; i < padding; ++i)
|
||||
pad += " ";
|
||||
|
||||
// Place the value within the available space - justify.
|
||||
int gap = width - data.length ();
|
||||
|
||||
for (int i = 0; i < gap; ++i)
|
||||
postJust += " ";
|
||||
|
||||
std::string intraPad = "";
|
||||
if (col < (signed) mColumns.size () - 1)
|
||||
for (int i = 0; i < getIntraPadding (); ++i)
|
||||
intraPad += " ";
|
||||
intraPad = std::string (getIntraPadding (), ' ');
|
||||
|
||||
return c.colorize (pad + preJust + data + postJust + pad) + intraPad;
|
||||
return c.colorize (pad + data + postJust + pad) + intraPad;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -575,25 +497,15 @@ const std::string Table::formatHeaderDashedUnderline (
|
||||
{
|
||||
assert (width > 0);
|
||||
|
||||
Color c = getHeaderColor (col);
|
||||
c.blend (getHeaderUnderline (col));
|
||||
Color c = getHeaderUnderline (col);
|
||||
|
||||
std::string data = "";
|
||||
for (int i = 0; i < width; ++i)
|
||||
data += '-';
|
||||
|
||||
std::string pad = "";
|
||||
std::string data = std::string (width, '-');
|
||||
std::string pad = std::string (padding, ' ');
|
||||
std::string intraPad = "";
|
||||
std::string attrOn = "";
|
||||
std::string attrOff = "";
|
||||
|
||||
for (int i = 0; i < padding; ++i)
|
||||
pad += " ";
|
||||
|
||||
// Place the value within the available space - justify.
|
||||
if (col < (signed) mColumns.size () - 1)
|
||||
for (int i = 0; i < getIntraPadding (); ++i)
|
||||
intraPad += " ";
|
||||
intraPad = std::string (getIntraPadding (), ' ');
|
||||
|
||||
return c.colorize (pad + data + pad) + intraPad;
|
||||
}
|
||||
@@ -614,15 +526,11 @@ void Table::formatCell (
|
||||
just justification = getJustification (row, col);
|
||||
std::string data = getCell (row, col);
|
||||
|
||||
std::string pad = "";
|
||||
std::string pad = std::string (padding, ' ');
|
||||
std::string intraPad = "";
|
||||
|
||||
for (int i = 0; i < padding; ++i)
|
||||
pad += " ";
|
||||
|
||||
if (col < (signed) mColumns.size () - 1)
|
||||
for (int i = 0; i < getIntraPadding (); ++i)
|
||||
intraPad += " ";
|
||||
intraPad = std::string (getIntraPadding (), ' ');
|
||||
|
||||
// Break the text into chunks of width characters.
|
||||
std::string preJust;
|
||||
@@ -638,39 +546,26 @@ void Table::formatCell (
|
||||
postJust = "";
|
||||
|
||||
if (justification == left)
|
||||
for (int i = 0; i < gap; ++i)
|
||||
postJust += " ";
|
||||
postJust = std::string (gap, ' ');
|
||||
|
||||
else if (justification == right)
|
||||
for (int i = 0; i < gap; ++i)
|
||||
preJust += " ";
|
||||
preJust = std::string (gap, ' ');
|
||||
|
||||
else if (justification == center)
|
||||
{
|
||||
for (int i = 0; i < gap / 2; ++i)
|
||||
preJust += " ";
|
||||
|
||||
for (size_t i = 0; i < gap - preJust.length (); ++i)
|
||||
postJust += " ";
|
||||
preJust = std::string (gap / 2, ' ');
|
||||
postJust = std::string (gap - preJust.length (), ' ');
|
||||
}
|
||||
|
||||
lines.push_back (c.colorize (pad + preJust + chunks[chunk] + postJust + pad + intraPad));
|
||||
}
|
||||
|
||||
// The blank is used to vertically pad cells that have blank lines.
|
||||
pad = "";
|
||||
for (int i = 0; i < width; ++i)
|
||||
pad += " ";
|
||||
pad = std::string (width, ' ');
|
||||
|
||||
blank = c.colorize (pad + intraPad);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Table::suppressWS ()
|
||||
{
|
||||
mSuppressWS = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Table::setDateFormat (const std::string& dateFormat)
|
||||
{
|
||||
@@ -695,79 +590,6 @@ int Table::columnCount ()
|
||||
return mColumns.size ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Removes extraneous output characters, such as:
|
||||
// - removal of redundant color codes:
|
||||
// ^[[31mName^[[0m ^[[31mValue^[[0m -> ^[[31mName Value^[[0m
|
||||
//
|
||||
// This method is a work in progress.
|
||||
void Table::optimize (std::string& output) const
|
||||
{
|
||||
// int start = output.length ();
|
||||
|
||||
/*
|
||||
Well, how about that!
|
||||
|
||||
The benchmark.t unit test adds a 1000 tasks, fiddles with some of them, then
|
||||
runs a series of reports. The results are timed, and look like this:
|
||||
|
||||
1000 tasks added in 3 seconds
|
||||
600 tasks altered in 32 seconds
|
||||
'task ls' in 26 seconds
|
||||
'task list' in 17 seconds
|
||||
'task list pri:H' in 19 seconds
|
||||
'task list +tag' in 0 seconds
|
||||
'task list project_A' in 0 seconds
|
||||
'task long' in 29 seconds
|
||||
'task completed' in 2 seconds
|
||||
'task history' in 0 seconds
|
||||
'task ghistory' in 0 seconds
|
||||
|
||||
This performance is terrible. To identify the worst offender, Various Timer
|
||||
objects were added in Table::render, assuming that table sorting is the major
|
||||
bottleneck. But no, it is Table::optimize that is the problem. After
|
||||
commenting out this method, the results are now:
|
||||
|
||||
1000 tasks added in 3 seconds
|
||||
600 tasks altered in 29 seconds
|
||||
'task ls' in 0 seconds
|
||||
'task list' in 0 seconds
|
||||
'task list pri:H' in 1 seconds
|
||||
'task list +tag' in 0 seconds
|
||||
'task list project_A' in 0 seconds
|
||||
'task long' in 0 seconds
|
||||
'task completed' in 0 seconds
|
||||
'task history' in 0 seconds
|
||||
'task ghistory' in 0 seconds
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Combsort11, with O(n log n) average, O(n log n) worst case performance.
|
||||
//
|
||||
@@ -999,35 +821,13 @@ void Table::sort (std::vector <int>& order)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Table::clean (std::string& value)
|
||||
{
|
||||
size_t start = 0;
|
||||
size_t pos;
|
||||
while ((pos = value.find ('\t', start)) != std::string::npos)
|
||||
{
|
||||
value.replace (pos, 1, " ");
|
||||
start = pos; // Not pos + 1, because we have a destructive operation, and
|
||||
// this is ultimately safer.
|
||||
}
|
||||
|
||||
while ((pos = value.find ('\r', start)) != std::string::npos)
|
||||
{
|
||||
value.replace (pos, 1, " ");
|
||||
start = pos;
|
||||
}
|
||||
|
||||
while ((pos = value.find ('\n', start)) != std::string::npos)
|
||||
{
|
||||
value.replace (pos, 1, " ");
|
||||
start = pos;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
const std::string Table::render (int maximum /* = 0 */)
|
||||
const std::string Table::render (int maxrows /* = 0 */, int maxlines /* = 0 */)
|
||||
{
|
||||
Timer t ("Table::render");
|
||||
|
||||
// May not exceed maxlines, if non-zero.
|
||||
int renderedlines = 0;
|
||||
|
||||
calculateColumnWidths ();
|
||||
|
||||
// Print column headers in column order.
|
||||
@@ -1048,8 +848,12 @@ const std::string Table::render (int maximum /* = 0 */)
|
||||
}
|
||||
|
||||
output += "\n";
|
||||
++renderedlines;
|
||||
if (underline.length ())
|
||||
{
|
||||
output += underline + "\n";
|
||||
++renderedlines;
|
||||
}
|
||||
|
||||
// Determine row order, according to sort options.
|
||||
std::vector <int> order;
|
||||
@@ -1060,14 +864,17 @@ const std::string Table::render (int maximum /* = 0 */)
|
||||
if (mSortColumns.size ())
|
||||
sort (order);
|
||||
|
||||
// If a non-zero maximum is specified, then it limits the number of rows of
|
||||
// If a non-zero maxrows is specified, then it limits the number of rows of
|
||||
// the table that are rendered.
|
||||
int limit = mRows;
|
||||
if (maximum != 0)
|
||||
limit = min (maximum, mRows);
|
||||
int limitrows = mRows;
|
||||
if (maxrows != 0)
|
||||
limitrows = min (maxrows, mRows);
|
||||
|
||||
// If a non-zero maxlines is specified, then it limits the number of lines
|
||||
// of output from the table that are rendered.
|
||||
|
||||
// Print all rows.
|
||||
for (int row = 0; row < limit; ++row)
|
||||
for (int row = 0; row < limitrows; ++row)
|
||||
{
|
||||
std::vector <std::vector <std::string> > columns;
|
||||
std::vector <std::string> blanks;
|
||||
@@ -1105,6 +912,11 @@ const std::string Table::render (int maximum /* = 0 */)
|
||||
// Trim right.
|
||||
output.erase (output.find_last_not_of (" ") + 1);
|
||||
output += "\n";
|
||||
|
||||
++renderedlines;
|
||||
|
||||
if (maxlines != 0 && renderedlines >= maxlines)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1113,9 +925,11 @@ const std::string Table::render (int maximum /* = 0 */)
|
||||
output.erase (output.find_last_not_of (" ") + 1);
|
||||
output += "\n";
|
||||
}
|
||||
|
||||
if (maxlines != 0 && renderedlines >= maxlines)
|
||||
break;
|
||||
}
|
||||
|
||||
optimize (output);
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
11
src/Table.h
11
src/Table.h
@@ -57,8 +57,6 @@ public:
|
||||
Table (const Table&);
|
||||
Table& operator= (const Table&);
|
||||
|
||||
// TODO Obsolete - this is not used. Consider removal.
|
||||
// void setTableColor (const Color&);
|
||||
void setTableAlternateColor (const Color&);
|
||||
void setTablePadding (int);
|
||||
void setTableIntraPadding (int);
|
||||
@@ -66,8 +64,6 @@ public:
|
||||
void setTableDashedUnderline ();
|
||||
|
||||
int addColumn (const std::string&);
|
||||
// TODO Obsolete - this is not used. Consider removal.
|
||||
// void setColumnColor (int, const Color&);
|
||||
void setColumnUnderline (int);
|
||||
void setColumnPadding (int, int);
|
||||
void setColumnWidth (int, int);
|
||||
@@ -86,18 +82,16 @@ public:
|
||||
void addCell (int, int, double);
|
||||
void setCellColor (int, int, const Color&);
|
||||
|
||||
void suppressWS ();
|
||||
void setDateFormat (const std::string&);
|
||||
void setReportName (const std::string&);
|
||||
|
||||
int rowCount ();
|
||||
int columnCount ();
|
||||
const std::string render (int maximum = 0);
|
||||
const std::string render (int maxrows = 0, int maxlines = 0);
|
||||
|
||||
private:
|
||||
std::string getCell (const int, const int);
|
||||
Color getColor (const int, const int, const int);
|
||||
Color getHeaderColor (const int);
|
||||
Color getHeaderUnderline (const int);
|
||||
int getPadding (const int);
|
||||
int getIntraPadding ();
|
||||
@@ -108,8 +102,6 @@ private:
|
||||
const std::string formatHeaderDashedUnderline (const int, const int, const int);
|
||||
void formatCell (const int, const int, const int, const int, const int, std::vector <std::string>&, std::string&);
|
||||
void sort (std::vector <int>&);
|
||||
void clean (std::string&);
|
||||
void optimize (std::string&) const;
|
||||
|
||||
private:
|
||||
std::vector <std::string> mColumns;
|
||||
@@ -137,7 +129,6 @@ private:
|
||||
std::map <int, order> mSortOrder;
|
||||
|
||||
// Misc...
|
||||
bool mSuppressWS;
|
||||
std::string mDateFormat;
|
||||
std::string mReportName;
|
||||
};
|
||||
|
||||
20
src/Task.cpp
20
src/Task.cpp
@@ -78,25 +78,9 @@ bool Task::operator== (const Task& other)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Attempt an FF4 parse first, using Record::parse, and in the event of an error
|
||||
// try a legacy parse (F3, FF2). Note that FF1 is no longer supported.
|
||||
Task::Task (const std::string& input)
|
||||
{
|
||||
std::string copy;
|
||||
if (input[input.length () - 1] == '\n')
|
||||
copy = input.substr (0, input.length () - 1);
|
||||
else
|
||||
copy = input;
|
||||
|
||||
try
|
||||
{
|
||||
Record::parse (copy);
|
||||
}
|
||||
|
||||
catch (std::string& e)
|
||||
{
|
||||
legacyParse (copy);
|
||||
}
|
||||
parse (input);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -149,6 +133,8 @@ void Task::setStatus (Task::status status)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Attempt an FF4 parse first, using Record::parse, and in the event of an error
|
||||
// try a legacy parse (F3, FF2). Note that FF1 is no longer supported.
|
||||
void Task::parse (const std::string& line)
|
||||
{
|
||||
std::string copy;
|
||||
|
||||
183
src/Taskmod.cpp
Normal file
183
src/Taskmod.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// task - a command line task list manager.
|
||||
//
|
||||
// Copyright 2006 - 2010, Paul Beckingham, Johannes Schlatow.
|
||||
// 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 <sstream>
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
#include "Taskmod.h"
|
||||
|
||||
Taskmod::Taskmod()
|
||||
{
|
||||
timestamp = 0;
|
||||
bAfterSet = false;
|
||||
bBeforeSet = false;
|
||||
}
|
||||
|
||||
Taskmod::Taskmod(const Taskmod& other)
|
||||
{
|
||||
this->before = other.before;
|
||||
this->after = other.after;
|
||||
this->timestamp = other.timestamp;
|
||||
this->bAfterSet = other.bAfterSet;
|
||||
this->bBeforeSet = other.bBeforeSet;
|
||||
}
|
||||
|
||||
Taskmod::~Taskmod()
|
||||
{
|
||||
}
|
||||
|
||||
// OPERATORS
|
||||
bool Taskmod::operator< (const Taskmod &compare)
|
||||
{
|
||||
return (timestamp < compare.getTimestamp());
|
||||
}
|
||||
|
||||
bool Taskmod::operator> (const Taskmod &compare)
|
||||
{
|
||||
return (timestamp > compare.getTimestamp());
|
||||
}
|
||||
|
||||
bool Taskmod::operator== (const Taskmod& compare)
|
||||
{
|
||||
return ( (compare.after == this->after)
|
||||
&& (compare.before == this->before)
|
||||
&& (compare.timestamp == this->timestamp) );
|
||||
}
|
||||
|
||||
bool Taskmod::operator!= (const Taskmod& compare)
|
||||
{
|
||||
return !this->operator ==(compare);
|
||||
}
|
||||
|
||||
Taskmod& Taskmod::operator= (const Taskmod& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
this->before = other.before;
|
||||
this->after = other.after;
|
||||
this->timestamp = other.timestamp;
|
||||
this->bAfterSet = other.bAfterSet;
|
||||
this->bBeforeSet = other.bBeforeSet;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// HELPER
|
||||
void Taskmod::reset(long timestamp)
|
||||
{
|
||||
this->bAfterSet = false;
|
||||
this->bBeforeSet = false;
|
||||
this->timestamp = timestamp;
|
||||
}
|
||||
|
||||
bool Taskmod::isNew()
|
||||
{
|
||||
return !bBeforeSet;
|
||||
}
|
||||
|
||||
bool Taskmod::issetAfter()
|
||||
{
|
||||
return bAfterSet;
|
||||
}
|
||||
|
||||
bool Taskmod::issetBefore()
|
||||
{
|
||||
return bBeforeSet;
|
||||
}
|
||||
|
||||
bool Taskmod::isValid()
|
||||
{
|
||||
return (timestamp > 0) && (bAfterSet);
|
||||
}
|
||||
|
||||
std::string Taskmod::getUuid()
|
||||
{
|
||||
if (!bAfterSet) {
|
||||
throw std::string("Taskmod::getUuid(): Task object not initialized");
|
||||
}
|
||||
|
||||
return after.get("uuid");
|
||||
}
|
||||
|
||||
std::string Taskmod::toString()
|
||||
{
|
||||
assert(bAfterSet);
|
||||
|
||||
std::stringstream stream;
|
||||
stream << "time " << timestamp << "\n";
|
||||
|
||||
if (bBeforeSet) {
|
||||
stream << "old " << before.composeF4();
|
||||
}
|
||||
|
||||
stream << "new " << after.composeF4();
|
||||
stream << "---\n";
|
||||
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
// SETTER
|
||||
void Taskmod::setAfter(const Task& after)
|
||||
{
|
||||
this->after = after;
|
||||
bAfterSet = true;
|
||||
}
|
||||
|
||||
void Taskmod::setBefore(const Task& before)
|
||||
{
|
||||
this->before = before;
|
||||
bBeforeSet = true;
|
||||
}
|
||||
|
||||
void Taskmod::setTimestamp(long timestamp)
|
||||
{
|
||||
this->timestamp = timestamp;
|
||||
}
|
||||
|
||||
// GETTER
|
||||
Task& Taskmod::getAfter()
|
||||
{
|
||||
return after;
|
||||
}
|
||||
|
||||
Task& Taskmod::getBefore()
|
||||
{
|
||||
return before;
|
||||
}
|
||||
|
||||
long Taskmod::getTimestamp() const
|
||||
{
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
std::string Taskmod::getTimeStr() const
|
||||
{
|
||||
std::stringstream sstream;
|
||||
sstream << timestamp;
|
||||
return sstream.str();
|
||||
}
|
||||
|
||||
77
src/Taskmod.h
Normal file
77
src/Taskmod.h
Normal file
@@ -0,0 +1,77 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// task - a command line task list manager.
|
||||
//
|
||||
// Copyright 2006 - 2010, Paul Beckingham, Johannes Schlatow.
|
||||
// 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
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef INCLUDED_TASKMOD
|
||||
#define INCLUDED_TASKMOD
|
||||
|
||||
#include <string>
|
||||
#include <Task.h>
|
||||
|
||||
class Taskmod {
|
||||
|
||||
public:
|
||||
Taskmod();
|
||||
Taskmod(const Taskmod& other);
|
||||
~Taskmod();
|
||||
|
||||
// operators
|
||||
bool operator< (const Taskmod& compare);
|
||||
bool operator> (const Taskmod& compare);
|
||||
bool operator== (const Taskmod& compare);
|
||||
bool operator!= (const Taskmod& compare);
|
||||
Taskmod& operator= (const Taskmod& other);
|
||||
|
||||
// helper
|
||||
void reset(long timestamp=0);
|
||||
bool isNew();
|
||||
bool issetBefore();
|
||||
bool issetAfter();
|
||||
bool isValid();
|
||||
|
||||
std::string getUuid();
|
||||
std::string toString();
|
||||
|
||||
// setter
|
||||
void setAfter(const Task& after);
|
||||
void setBefore(const Task& before);
|
||||
void setTimestamp(long timestamp);
|
||||
|
||||
// getter
|
||||
Task& getAfter();
|
||||
Task& getBefore();
|
||||
long getTimestamp() const;
|
||||
std::string getTimeStr() const;
|
||||
|
||||
protected:
|
||||
Task after;
|
||||
Task before;
|
||||
long timestamp;
|
||||
bool bAfterSet;
|
||||
bool bBeforeSet;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
529
src/command.cpp
529
src/command.cpp
@@ -123,6 +123,62 @@ int handleAdd (std::string &outs)
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int handleLog (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (context.hooks.trigger ("pre-log-command"))
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
context.task.setStatus (Task::completed);
|
||||
context.task.set ("uuid", uuid ());
|
||||
context.task.setEntry ();
|
||||
|
||||
// Add an end date.
|
||||
char entryTime[16];
|
||||
sprintf (entryTime, "%u", (unsigned int) time (NULL));
|
||||
context.task.set ("end", entryTime);
|
||||
|
||||
// Recurring tasks get a special status.
|
||||
if (context.task.has ("recur"))
|
||||
throw std::string ("You cannot log recurring tasks.");
|
||||
|
||||
if (context.task.has ("wait"))
|
||||
throw std::string ("You cannot log waiting tasks.");
|
||||
|
||||
// Override with default.project, if not specified.
|
||||
if (context.task.get ("project") == "")
|
||||
context.task.set ("project", context.config.get ("default.project"));
|
||||
|
||||
// Override with default.priority, if not specified.
|
||||
if (context.task.get ("priority") == "")
|
||||
{
|
||||
std::string defaultPriority = context.config.get ("default.priority");
|
||||
if (Att::validNameValue ("priority", "", defaultPriority))
|
||||
context.task.set ("priority", defaultPriority);
|
||||
}
|
||||
|
||||
// Include tags.
|
||||
foreach (tag, context.tagAdditions)
|
||||
context.task.addTag (*tag);
|
||||
|
||||
// Only valid tasks can be added.
|
||||
context.task.validate ();
|
||||
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
context.tdb.add (context.task);
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
outs = out.str ();
|
||||
context.hooks.trigger ("post-log-command");
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int handleProjects (std::string &outs)
|
||||
{
|
||||
@@ -131,11 +187,15 @@ int handleProjects (std::string &outs)
|
||||
if (context.hooks.trigger ("pre-projects-command"))
|
||||
{
|
||||
std::stringstream out;
|
||||
context.filter.push_back (Att ("status", "pending"));
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
int quantity = context.tdb.loadPending (tasks, context.filter);
|
||||
int quantity;
|
||||
if (context.config.getBoolean ("list.all.projects"))
|
||||
quantity = context.tdb.load (tasks, context.filter);
|
||||
else
|
||||
quantity = context.tdb.loadPending (tasks, context.filter);
|
||||
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
@@ -262,11 +322,14 @@ int handleTags (std::string &outs)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
context.filter.push_back (Att ("status", "pending"));
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
int quantity = context.tdb.loadPending (tasks, context.filter);
|
||||
int quantity = 0;
|
||||
if (context.config.getBoolean ("list.all.tags"))
|
||||
quantity += context.tdb.load (tasks, context.filter);
|
||||
else
|
||||
quantity += context.tdb.loadPending (tasks, context.filter);
|
||||
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
@@ -368,8 +431,15 @@ int handleCompletionTags (std::string &outs)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int handleCompletionCommands (std::string &outs)
|
||||
{
|
||||
// Get a list of all commands.
|
||||
std::vector <std::string> commands;
|
||||
context.cmd.allCommands (commands);
|
||||
|
||||
// Concatenate a list of all aliases.
|
||||
foreach (name, context.aliases)
|
||||
commands.push_back (name->first);
|
||||
|
||||
// Sort alphabetically.
|
||||
std::sort (commands.begin (), commands.end ());
|
||||
|
||||
std::stringstream out;
|
||||
@@ -446,6 +516,25 @@ void handleUndo ()
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void handleMerge (std::string& outs)
|
||||
{
|
||||
if (context.hooks.trigger ("pre-merge-command"))
|
||||
{
|
||||
std::string file = trim (context.task.get ("description"));
|
||||
if (file.length () > 0)
|
||||
{
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
context.tdb.merge (file);
|
||||
context.tdb.unlock ();
|
||||
|
||||
context.hooks.trigger ("post-merge-command");
|
||||
}
|
||||
else
|
||||
throw std::string ("You must specify a file to merge.");
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int handleVersion (std::string &outs)
|
||||
{
|
||||
@@ -538,7 +627,7 @@ int handleVersion (std::string &outs)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int handleConfig (std::string &outs)
|
||||
int handleShow (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
@@ -551,114 +640,9 @@ int handleConfig (std::string &outs)
|
||||
std::vector <std::string> args;
|
||||
split (args, context.task.get ("description"), ' ');
|
||||
|
||||
// Support:
|
||||
// task config name value # set name to value
|
||||
// task config name "" # set name to blank
|
||||
// task config name # remove name
|
||||
if (args.size () > 0)
|
||||
{
|
||||
std::string name = args[0];
|
||||
std::string value = "";
|
||||
if (args.size () > 1)
|
||||
throw std::string ("The show command takes zero or one option.");
|
||||
|
||||
if (args.size () > 1)
|
||||
{
|
||||
for (unsigned int i = 1; i < args.size (); ++i)
|
||||
{
|
||||
if (i > 1)
|
||||
value += " ";
|
||||
|
||||
value += args[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (name != "")
|
||||
{
|
||||
bool change = false;
|
||||
|
||||
// Read .taskrc (or equivalent)
|
||||
std::string contents;
|
||||
File::read (context.config.original_file, contents);
|
||||
|
||||
// task config name value
|
||||
// task config name ""
|
||||
if (args.size () > 1 ||
|
||||
context.args[context.args.size () - 1] == "")
|
||||
{
|
||||
// Find existing entry & overwrite
|
||||
std::string::size_type pos = contents.find (name + "=");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
std::string::size_type eol = contents.find_first_of ("\r\f\n", pos);
|
||||
if (eol == std::string::npos)
|
||||
throw std::string ("Cannot find EOL after entry '") + name + "'";
|
||||
|
||||
if (confirm (std::string ("Are you sure you want to change the value of '")
|
||||
+ name
|
||||
+ "' from '"
|
||||
+ context.config.get(name)
|
||||
+ "' to '"
|
||||
+ value + "'?"))
|
||||
{
|
||||
contents = contents.substr (0, pos)
|
||||
+ name + "=" + value
|
||||
+ contents.substr (eol);
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Not found, so append instead.
|
||||
else
|
||||
{
|
||||
if (confirm (std::string ("Are you sure you want to add '") + name + "' with a value of '" + value + "'?"))
|
||||
{
|
||||
contents = contents
|
||||
+ "\n"
|
||||
+ name + "=" + value
|
||||
+ "\n";
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// task config name
|
||||
else
|
||||
{
|
||||
// Remove name
|
||||
std::string::size_type pos = contents.find (name + "=");
|
||||
if (pos == std::string::npos)
|
||||
throw std::string ("No entry named '") + name + "' found";
|
||||
|
||||
std::string::size_type eol = contents.find_first_of ("\r\f\n", pos);
|
||||
if (eol == std::string::npos)
|
||||
throw std::string ("Cannot find EOL after entry '") + name + "'";
|
||||
|
||||
if (confirm (std::string ("Are you sure you want to remove '") + name + "'?"))
|
||||
{
|
||||
contents = contents.substr (0, pos) + contents.substr (eol + 1);
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Write .taskrc (or equivalent)
|
||||
if (change)
|
||||
{
|
||||
File::write (context.config.original_file, contents);
|
||||
out << "Config file "
|
||||
<< context.config.original_file.data
|
||||
<< " modified."
|
||||
<< std::endl;
|
||||
}
|
||||
else
|
||||
out << "No changes made." << std::endl;
|
||||
}
|
||||
else
|
||||
throw std::string ("Specify the name of a config variable to modify.");
|
||||
|
||||
outs = out.str ();
|
||||
return rc;
|
||||
}
|
||||
|
||||
// No arguments - display config values instead.
|
||||
int width = context.getWidth ();
|
||||
|
||||
std::vector <std::string> all;
|
||||
@@ -674,14 +658,17 @@ int handleConfig (std::string &outs)
|
||||
"color.recurring color.tagged color.footnote color.header color.debug "
|
||||
"color.alternate color.calendar.today color.calendar.due color.calendar.due.today "
|
||||
"color.calendar.overdue color.calendar.weekend color.calendar.holiday "
|
||||
"color.calendar.weeknumber confirmation curses data.location dateformat "
|
||||
"dateformat.holiday dateformat.report debug default.command "
|
||||
"default.priority default.project defaultwidth due locale "
|
||||
"displayweeknumber echo.command fontunderline locking monthsperline nag "
|
||||
"color.calendar.weeknumber color.summary.background color.summary.bar "
|
||||
"color.history.add color.history.done color.history.delete color.undo.before "
|
||||
"color.undo.after confirmation curses data.location dateformat dateformat.holiday "
|
||||
"dateformat.report dateformat.annotation debug default.command "
|
||||
"default.priority default.project defaultwidth due locale displayweeknumber "
|
||||
"export.ical.class echo.command fontunderline locking monthsperline nag "
|
||||
"next project shadow.command shadow.file shadow.notify weekstart editor "
|
||||
"import.synonym.id import.synonym.uuid complete.all.projects "
|
||||
"complete.all.tags search.case.sensitive hooks active.indicator tag.indicator "
|
||||
"recurrence.indicator "
|
||||
"recurrence.indicator recurrence.limit list.all.projects list.all.tags "
|
||||
"undo.style "
|
||||
#ifdef FEATURE_SHELL
|
||||
"shell.prompt "
|
||||
#endif
|
||||
@@ -740,22 +727,36 @@ int handleConfig (std::string &outs)
|
||||
table.sortOn (0, Table::ascendingCharacter);
|
||||
|
||||
Color error ("bold white on red");
|
||||
|
||||
std::string section;
|
||||
|
||||
if (args.size () == 1)
|
||||
section = args[0];
|
||||
|
||||
if (section == "all")
|
||||
section = "";
|
||||
|
||||
foreach (i, all)
|
||||
{
|
||||
std::string value = context.config.get (*i);
|
||||
int row = table.addRow ();
|
||||
table.addCell (row, 0, *i);
|
||||
table.addCell (row, 1, value);
|
||||
std::string::size_type loc = i->find (section, 0);
|
||||
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
if (std::find (unrecognized.begin (), unrecognized.end (), *i) != unrecognized.end ())
|
||||
table.setRowColor (row, error);
|
||||
if (loc != std::string::npos)
|
||||
{
|
||||
int row = table.addRow ();
|
||||
table.addCell (row, 0, *i);
|
||||
table.addCell (row, 1, context.config.get (*i));
|
||||
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
if (std::find (unrecognized.begin (), unrecognized.end (), *i) != unrecognized.end ())
|
||||
table.setRowColor (row, error);
|
||||
}
|
||||
}
|
||||
|
||||
Color bold ("bold");
|
||||
|
||||
out << std::endl
|
||||
<< table.render ()
|
||||
<< (table.rowCount () == 0 ? "No matching configuration variables\n" : "")
|
||||
<< std::endl;
|
||||
|
||||
// Display the unrecognized variables.
|
||||
@@ -891,6 +892,131 @@ int handleConfig (std::string &outs)
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int handleConfig (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (context.hooks.trigger ("pre-config-command"))
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
// Obtain the arguments from the description. That way, things like '--'
|
||||
// have already been handled.
|
||||
std::vector <std::string> args;
|
||||
split (args, context.task.get ("description"), ' ');
|
||||
|
||||
// Support:
|
||||
// task config name value # set name to value
|
||||
// task config name "" # set name to blank
|
||||
// task config name # remove name
|
||||
if (args.size () > 0)
|
||||
{
|
||||
std::string name = args[0];
|
||||
std::string value = "";
|
||||
|
||||
if (args.size () > 1)
|
||||
{
|
||||
for (unsigned int i = 1; i < args.size (); ++i)
|
||||
{
|
||||
if (i > 1)
|
||||
value += " ";
|
||||
|
||||
value += args[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (name != "")
|
||||
{
|
||||
bool change = false;
|
||||
|
||||
// Read .taskrc (or equivalent)
|
||||
std::string contents;
|
||||
File::read (context.config.original_file, contents);
|
||||
|
||||
// task config name value
|
||||
// task config name ""
|
||||
if (args.size () > 1 ||
|
||||
context.args[context.args.size () - 1] == "")
|
||||
{
|
||||
// Find existing entry & overwrite
|
||||
std::string::size_type pos = contents.find (name + "=");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
std::string::size_type eol = contents.find_first_of ("\r\f\n", pos);
|
||||
if (eol == std::string::npos)
|
||||
throw std::string ("Cannot find EOL after entry '") + name + "'";
|
||||
|
||||
if (confirm (std::string ("Are you sure you want to change the value of '")
|
||||
+ name
|
||||
+ "' from '"
|
||||
+ context.config.get(name)
|
||||
+ "' to '"
|
||||
+ value + "'?"))
|
||||
{
|
||||
contents = contents.substr (0, pos)
|
||||
+ name + "=" + value
|
||||
+ contents.substr (eol);
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Not found, so append instead.
|
||||
else
|
||||
{
|
||||
if (confirm (std::string ("Are you sure you want to add '") + name + "' with a value of '" + value + "'?"))
|
||||
{
|
||||
contents = contents
|
||||
+ "\n"
|
||||
+ name + "=" + value
|
||||
+ "\n";
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// task config name
|
||||
else
|
||||
{
|
||||
// Remove name
|
||||
std::string::size_type pos = contents.find (name + "=");
|
||||
if (pos == std::string::npos)
|
||||
throw std::string ("No entry named '") + name + "' found";
|
||||
|
||||
std::string::size_type eol = contents.find_first_of ("\r\f\n", pos);
|
||||
if (eol == std::string::npos)
|
||||
throw std::string ("Cannot find EOL after entry '") + name + "'";
|
||||
|
||||
if (confirm (std::string ("Are you sure you want to remove '") + name + "'?"))
|
||||
{
|
||||
contents = contents.substr (0, pos) + contents.substr (eol + 1);
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Write .taskrc (or equivalent)
|
||||
if (change)
|
||||
{
|
||||
File::write (context.config.original_file, contents);
|
||||
out << "Config file "
|
||||
<< context.config.original_file.data
|
||||
<< " modified."
|
||||
<< std::endl;
|
||||
}
|
||||
else
|
||||
out << "No changes made." << std::endl;
|
||||
}
|
||||
else
|
||||
throw std::string ("Specify the name of a config variable to modify.");
|
||||
outs = out.str ();
|
||||
context.hooks.trigger ("post-config-command");
|
||||
}
|
||||
else
|
||||
throw std::string ("Specify the name of a config variable to modify.");
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int handleDelete (std::string &outs)
|
||||
{
|
||||
@@ -1243,59 +1369,6 @@ int handleDone (std::string &outs)
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int handleExport (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (context.hooks.trigger ("pre-export-command"))
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
// Deliberately no 'id'.
|
||||
out << "'uuid',"
|
||||
<< "'status',"
|
||||
<< "'tags',"
|
||||
<< "'entry',"
|
||||
<< "'start',"
|
||||
<< "'due',"
|
||||
<< "'recur',"
|
||||
<< "'end',"
|
||||
<< "'project',"
|
||||
<< "'priority',"
|
||||
<< "'fg',"
|
||||
<< "'bg',"
|
||||
<< "'description'"
|
||||
<< "\n";
|
||||
|
||||
int count = 0;
|
||||
|
||||
// Get all the tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
handleRecurrence ();
|
||||
context.tdb.load (tasks, context.filter);
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
foreach (task, tasks)
|
||||
{
|
||||
context.hooks.trigger ("pre-display", *task);
|
||||
|
||||
if (task->getStatus () != Task::recurring)
|
||||
{
|
||||
out << task->composeCSV ().c_str ();
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
outs = out.str ();
|
||||
context.hooks.trigger ("post-export-command");
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int handleModify (std::string &outs)
|
||||
{
|
||||
@@ -1351,7 +1424,7 @@ int handleModify (std::string &outs)
|
||||
std::cout << "Task "
|
||||
<< task->id
|
||||
<< " is a recurring task, and all other instances of this"
|
||||
<< " task may be modified."
|
||||
<< " task will be modified."
|
||||
<< std::endl;
|
||||
|
||||
Task before (*other);
|
||||
@@ -1971,6 +2044,104 @@ int handleAnnotate (std::string &outs)
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int handleDenotate (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (context.hooks.trigger ("pre-denotate-command"))
|
||||
{
|
||||
if (!context.task.has ("description"))
|
||||
throw std::string ("Description needed to delete an annotation.");
|
||||
|
||||
if (context.sequence.size () == 0)
|
||||
throw std::string ("A task ID is needed to delete an annotation.");
|
||||
|
||||
bool sensitive = context.config.getBoolean ("search.case.sensitive");
|
||||
|
||||
std::stringstream out;
|
||||
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
Filter filter;
|
||||
context.tdb.loadPending (tasks, filter);
|
||||
|
||||
context.filter.applySequence (tasks, context.sequence);
|
||||
|
||||
Permission permission;
|
||||
if (context.sequence.size () > (size_t) context.config.getInteger ("bulk"))
|
||||
permission.bigSequence ();
|
||||
|
||||
foreach (task, tasks)
|
||||
{
|
||||
Task before (*task);
|
||||
std::string desc = context.task.get ("description");
|
||||
std::vector <Att> annotations;
|
||||
task->getAnnotations (annotations);
|
||||
|
||||
if (annotations.size () == 0)
|
||||
throw std::string ("The specified task has no annotations that can be deleted.");
|
||||
|
||||
std::vector <Att>::iterator i;
|
||||
std::string anno;
|
||||
bool match = false;;
|
||||
for (i = annotations.begin (); i != annotations.end (); ++i)
|
||||
{
|
||||
anno = i->value ();
|
||||
if (anno == desc)
|
||||
{
|
||||
match = true;
|
||||
annotations.erase (i);
|
||||
task->setAnnotations (annotations);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match)
|
||||
{
|
||||
for (i = annotations.begin (); i != annotations.end (); ++i)
|
||||
{
|
||||
anno = i->value ();
|
||||
std::string::size_type loc = find (anno, desc, sensitive);
|
||||
|
||||
if (loc != std::string::npos)
|
||||
{
|
||||
match = true;
|
||||
annotations.erase (i);
|
||||
task->setAnnotations (annotations);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (taskDiff (before, *task))
|
||||
{
|
||||
if (permission.confirmed (before, taskDifferences (before, *task) + "Proceed with change?"))
|
||||
{
|
||||
context.tdb.update (*task);
|
||||
if (context.config.getBoolean ("echo.command"))
|
||||
out << "Found annotation '"
|
||||
<< anno
|
||||
<< "' and deleted it."
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
out << "Did not find any matching annotation to be deleted for '"
|
||||
<< desc
|
||||
<< "'."
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
outs = out.str ();
|
||||
context.hooks.trigger ("post-denotate-command");
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int deltaAppend (Task& task)
|
||||
{
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
|
||||
#include "Context.h"
|
||||
#include "Date.h"
|
||||
#include "Duration.h"
|
||||
#include "Table.h"
|
||||
#include "text.h"
|
||||
#include "util.h"
|
||||
@@ -434,10 +435,7 @@ int runCustomReport (
|
||||
if (due.length ())
|
||||
{
|
||||
Date dt (::atoi (due.c_str ()));
|
||||
time_t cntdwn = (time_t) (now - dt);
|
||||
countdown = formatSeconds ( cntdwn < 0 ? cntdwn * -1 : cntdwn );
|
||||
if ( cntdwn < 0 )
|
||||
countdown = std::string("-") + countdown;
|
||||
countdown = Duration (now - dt).format ();
|
||||
context.hooks.trigger ("format-countdown", "countdown", countdown);
|
||||
table.addCell (row, columnCount, countdown);
|
||||
}
|
||||
@@ -459,10 +457,7 @@ int runCustomReport (
|
||||
if (due.length ())
|
||||
{
|
||||
Date dt (::atoi (due.c_str ()));
|
||||
time_t cntdwn = (time_t) (now - dt);
|
||||
countdown = formatSecondsCompact ( cntdwn < 0 ? cntdwn * -1 : cntdwn );
|
||||
if ( cntdwn < 0 )
|
||||
countdown = std::string("-") + countdown;
|
||||
countdown = Duration (now - dt).formatCompact ();
|
||||
context.hooks.trigger ("format-countdown_compact", "countdown_compact", countdown);
|
||||
table.addCell (row, columnCount, countdown);
|
||||
}
|
||||
@@ -484,7 +479,7 @@ int runCustomReport (
|
||||
if (created.length ())
|
||||
{
|
||||
Date dt (::atoi (created.c_str ()));
|
||||
age = formatSeconds ((time_t) (now - dt));
|
||||
age = Duration (now - dt).format ();
|
||||
context.hooks.trigger ("format-age", "age", age);
|
||||
table.addCell (row, columnCount, age);
|
||||
}
|
||||
@@ -506,7 +501,8 @@ int runCustomReport (
|
||||
if (created.length ())
|
||||
{
|
||||
Date dt (::atoi (created.c_str ()));
|
||||
age = formatSecondsCompact ((time_t) (now - dt));
|
||||
age = Duration (now - dt).formatCompact ();
|
||||
|
||||
context.hooks.trigger ("format-age_compact", "age_compact", age);
|
||||
table.addCell (row, columnCount, age);
|
||||
}
|
||||
@@ -683,12 +679,18 @@ int runCustomReport (
|
||||
Table::ascendingDueDate :
|
||||
Table::descendingDueDate));
|
||||
|
||||
else if (column == "recur")
|
||||
else if (column == "recur" || column == "age" || column == "age_compact")
|
||||
table.sortOn (columnIndex[column],
|
||||
(direction == '+' ?
|
||||
Table::ascendingPeriod :
|
||||
Table::descendingPeriod));
|
||||
|
||||
else if (column == "countdown" || column == "countdown_compact")
|
||||
table.sortOn (columnIndex[column],
|
||||
(direction == '+' ?
|
||||
Table::descendingPeriod : // Yes, these are flipped.
|
||||
Table::ascendingPeriod)); // Yes, these are flipped.
|
||||
|
||||
else
|
||||
table.sortOn (columnIndex[column],
|
||||
(direction == '+' ?
|
||||
@@ -715,23 +717,37 @@ int runCustomReport (
|
||||
table.setTableAlternateColor (alternate);
|
||||
}
|
||||
|
||||
// Limit the number of rows according to the report definition.
|
||||
int maximum = context.config.getInteger (std::string ("report.") + report + ".limit");
|
||||
// Report output can be limited by rows or lines.
|
||||
int maxrows = 0;
|
||||
int maxlines = 0;
|
||||
getLimits (report, maxrows, maxlines);
|
||||
|
||||
// If the custom report has a defined limit, then allow a numeric override.
|
||||
// This is an integer specified as a filter (limit:10).
|
||||
if (context.task.has ("limit"))
|
||||
maximum = atoi (context.task.get ("limit").c_str ());
|
||||
// Adjust for fluff in the output.
|
||||
if (maxlines)
|
||||
maxlines -= (context.config.getBoolean ("blanklines") ? 2 : 0)
|
||||
+ 1
|
||||
+ context.headers.size ()
|
||||
+ context.footnotes.size ();
|
||||
|
||||
std::stringstream out;
|
||||
if (table.rowCount ())
|
||||
{
|
||||
out << optionalBlankLine ()
|
||||
<< table.render (maximum)
|
||||
<< table.render (maxrows, maxlines)
|
||||
<< optionalBlankLine ()
|
||||
<< table.rowCount ()
|
||||
<< (table.rowCount () == 1 ? " task" : " tasks")
|
||||
<< std::endl;
|
||||
else {
|
||||
<< (table.rowCount () == 1 ? " task" : " tasks");
|
||||
|
||||
if (maxrows)
|
||||
out << ", " << maxrows << " shown";
|
||||
|
||||
if (maxlines)
|
||||
out << ", truncated to " << maxlines-1 << " lines";
|
||||
|
||||
out << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "No matches."
|
||||
<< std::endl;
|
||||
rc = 1;
|
||||
@@ -813,3 +829,44 @@ void validSortColumns (
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// A value of zero mean unlimited.
|
||||
// A value of 'page' means however many screen lines there are.
|
||||
// A value of a positive integer is a row limit.
|
||||
void getLimits (const std::string& report, int& rows, int& lines)
|
||||
{
|
||||
rows = 0;
|
||||
lines = 0;
|
||||
|
||||
int screenheight = 0;
|
||||
|
||||
// If a report has a stated limit, use it.
|
||||
if (report != "")
|
||||
{
|
||||
std::string name = "report." + report + ".limit";
|
||||
if (context.config.get (name) == "page")
|
||||
lines = screenheight = context.getHeight ();
|
||||
else
|
||||
rows = context.config.getInteger (name);
|
||||
}
|
||||
|
||||
// If the custom report has a defined limit, then allow a numeric override.
|
||||
// This is an integer specified as a filter (limit:10).
|
||||
if (context.task.has ("limit"))
|
||||
{
|
||||
if (context.task.get ("limit") == "page")
|
||||
{
|
||||
if (screenheight == 0)
|
||||
screenheight = context.getHeight ();
|
||||
|
||||
rows = 0;
|
||||
lines = screenheight;
|
||||
}
|
||||
else
|
||||
{
|
||||
rows = atoi (context.task.get ("limit").c_str ());
|
||||
lines = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -164,13 +164,12 @@ static std::string formatTask (Task task)
|
||||
foreach (anno, annotations)
|
||||
{
|
||||
Date dt (::atoi (anno->name ().substr (11).c_str ()));
|
||||
before << " Annotation: " << dt.toString (context.config.get ("dateformat"))
|
||||
before << " Annotation: " << dt.toString (context.config.get ("dateformat.annotation"))
|
||||
<< " " << anno->value () << std::endl;
|
||||
}
|
||||
|
||||
Date now;
|
||||
before << " Annotation: " << now.toString (context.config.get ("dateformat")) << " " << std::endl
|
||||
<< " Annotation: " << now.toString (context.config.get ("dateformat")) << " " << std::endl
|
||||
before << " Annotation: " << now.toString (context.config.get ("dateformat.annotation")) << " " << std::endl
|
||||
<< "# End" << std::endl;
|
||||
|
||||
return before.str ();
|
||||
@@ -503,7 +502,7 @@ static void parseTask (Task& task, const std::string& after)
|
||||
std::string::size_type gap = value.find (" ");
|
||||
if (gap != std::string::npos)
|
||||
{
|
||||
Date when (value.substr (0, gap), context.config.get ("dateformat"));
|
||||
Date when (value.substr (0, gap), context.config.get ("dateformat.annotation"));
|
||||
|
||||
// This guarantees that if more than one annotation has the same date,
|
||||
// that the seconds will be different, thus unique, thus not squashed.
|
||||
|
||||
230
src/export.cpp
Normal file
230
src/export.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// task - a command line task list manager.
|
||||
//
|
||||
// Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez.
|
||||
// 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 <stdlib.h>
|
||||
|
||||
#include "Att.h"
|
||||
#include "text.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "../auto.h"
|
||||
|
||||
extern Context context;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int handleExportCSV (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (context.hooks.trigger ("pre-export-command"))
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
// Deliberately no 'id'.
|
||||
out << "'uuid',"
|
||||
<< "'status',"
|
||||
<< "'tags',"
|
||||
<< "'entry',"
|
||||
<< "'start',"
|
||||
<< "'due',"
|
||||
<< "'recur',"
|
||||
<< "'end',"
|
||||
<< "'project',"
|
||||
<< "'priority',"
|
||||
<< "'fg',"
|
||||
<< "'bg',"
|
||||
<< "'description'"
|
||||
<< "\n";
|
||||
|
||||
int count = 0;
|
||||
|
||||
// Get all the tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
handleRecurrence ();
|
||||
context.tdb.load (tasks, context.filter);
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
foreach (task, tasks)
|
||||
{
|
||||
context.hooks.trigger ("pre-display", *task);
|
||||
|
||||
if (task->getStatus () != Task::recurring)
|
||||
{
|
||||
out << task->composeCSV ().c_str ();
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
outs = out.str ();
|
||||
context.hooks.trigger ("post-export-command");
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// http://tools.ietf.org/html/rfc5545
|
||||
//
|
||||
// Note: Recurring tasks could be included in more detail.
|
||||
int handleExportiCal (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (context.hooks.trigger ("pre-export-command"))
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
out << "BEGIN:VCALENDAR\n"
|
||||
<< "VERSION:2.0\n"
|
||||
<< "PRODID:-//GBF//" << PACKAGE_STRING << "//EN\n";
|
||||
|
||||
int count = 0;
|
||||
|
||||
// Get all the tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
handleRecurrence ();
|
||||
context.tdb.load (tasks, context.filter);
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
foreach (task, tasks)
|
||||
{
|
||||
context.hooks.trigger ("pre-display", *task);
|
||||
|
||||
if (task->getStatus () != Task::recurring)
|
||||
{
|
||||
out << "BEGIN:VTODO\n";
|
||||
|
||||
// Required UID:20070313T123432Z-456553@example.com
|
||||
out << "UID:" << task->get ("uuid") << "\n";
|
||||
|
||||
// Required DTSTAMP:20070313T123432Z
|
||||
Date entry (atoi (task->get ("entry").c_str ()));
|
||||
out << "DTSTAMP:" << entry.toISO () << "\n";
|
||||
|
||||
// Optional DTSTART:20070514T110000Z
|
||||
if (task->has ("start"))
|
||||
{
|
||||
Date start (atoi (task->get ("start").c_str ()));
|
||||
out << "DTSTART:" << start.toISO () << "\n";
|
||||
}
|
||||
|
||||
// Optional DUE:20070709T130000Z
|
||||
if (task->has ("due"))
|
||||
{
|
||||
Date due (atoi (task->get ("due").c_str ()));
|
||||
out << "DUE:" << due.toISO () << "\n";
|
||||
}
|
||||
|
||||
// Optional COMPLETED:20070707T100000Z
|
||||
if (task->has ("end") && task->getStatus () == Task::completed)
|
||||
{
|
||||
Date end (atoi (task->get ("end").c_str ()));
|
||||
out << "COMPLETED:" << end.toISO () << "\n";
|
||||
}
|
||||
|
||||
out << "SUMMARY:" << task->get ("description") << "\n";
|
||||
|
||||
// Optional CLASS:PUBLIC/PRIVATE/CONFIDENTIAL
|
||||
std::string classification = context.config.get ("export.ical.class");
|
||||
if (classification == "")
|
||||
classification = "PRIVATE";
|
||||
out << "CLASS:" << classification << "\n";
|
||||
|
||||
// Optional multiple CATEGORIES:FAMILY,FINANCE
|
||||
if (task->getTagCount () > 0)
|
||||
{
|
||||
std::vector <std::string> tags;
|
||||
task->getTags (tags);
|
||||
std::string all;
|
||||
join (all, ",", tags);
|
||||
out << "CATEGORIES:" << all << "\n";
|
||||
}
|
||||
|
||||
// Optional PRIORITY:
|
||||
// 1-4 H
|
||||
// 5 M
|
||||
// 6-9 L
|
||||
if (task->has ("priority"))
|
||||
{
|
||||
out << "PRIORITY:";
|
||||
std::string priority = task->get ("priority");
|
||||
|
||||
if (priority == "H") out << "1";
|
||||
else if (priority == "M") out << "5";
|
||||
else out << "9";
|
||||
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
// Optional STATUS:NEEDS-ACTION/IN-PROCESS/COMPLETED/CANCELLED
|
||||
out << "STATUS:";
|
||||
Task::status stat = task->getStatus ();
|
||||
if (stat == Task::pending || stat == Task::waiting)
|
||||
{
|
||||
if (task->has ("start"))
|
||||
out << "IN-PROCESS";
|
||||
else
|
||||
out << "NEEDS-ACTION";
|
||||
}
|
||||
else if (stat == Task::completed)
|
||||
{
|
||||
out << "COMPLETED";
|
||||
}
|
||||
else if (stat == Task::deleted)
|
||||
{
|
||||
out << "CANCELLED";
|
||||
}
|
||||
out << "\n";
|
||||
|
||||
// Optional COMMENT:annotation1
|
||||
// Optional COMMENT:annotation2
|
||||
std::vector <Att> annotations;
|
||||
task->getAnnotations (annotations);
|
||||
foreach (anno, annotations)
|
||||
out << "COMMENT:" << anno->value () << "\n";
|
||||
|
||||
out << "END:VTODO\n";
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
out << "END:VCALENDAR\n";
|
||||
|
||||
outs = out.str ();
|
||||
context.hooks.trigger ("post-export-command");
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -77,10 +77,10 @@
|
||||
#define CMD_DONE 208
|
||||
#define CMD_DUPLICATE 209
|
||||
#define CMD_EDIT 210
|
||||
#define CMD_EXPORT 211
|
||||
#define CMD_DENOTATE 211
|
||||
|
||||
#define CMD_HELP 212
|
||||
#define CMD_HISTORY 213
|
||||
#define CMD_GHISTORY 214
|
||||
|
||||
#define CMD_IMPORT 215
|
||||
#define CMD_INFO 216
|
||||
#define CMD_PREPEND 217
|
||||
@@ -92,11 +92,12 @@
|
||||
#define CMD_SUMMARY 223
|
||||
#define CMD_TAGS 224
|
||||
#define CMD_TIMESHEET 225
|
||||
|
||||
#define CMD_LOG 226
|
||||
#define CMD_UNDO 227
|
||||
#define CMD_VERSION 228
|
||||
#define CMD_SHELL 229
|
||||
#define CMD_CONFIG 230
|
||||
#define CMD_SHOW 231
|
||||
|
||||
// 3xx Attributes
|
||||
#define ATT_PROJECT 300
|
||||
|
||||
@@ -127,13 +127,13 @@ static fileType determineFileType (const std::vector <std::string>& lines)
|
||||
// +project
|
||||
if (words[w].length () > 1 &&
|
||||
words[w][0] == '+' &&
|
||||
isalnum (words[w][1]))
|
||||
!isspace (words[w][1]))
|
||||
return todo_sh_2_0;
|
||||
|
||||
// @context
|
||||
if (words[w].length () > 1 &&
|
||||
words[w][0] == '@' &&
|
||||
isalnum (words[w][1]))
|
||||
!isspace (words[w][1]))
|
||||
return todo_sh_2_0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,3 +167,36 @@ int Context::getWidth ()
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int Context::getHeight ()
|
||||
{
|
||||
// Determine window size, and set table accordingly.
|
||||
int height = 25; // TODO Is there a better number?
|
||||
|
||||
#ifdef HAVE_LIBNCURSES
|
||||
if (config.getBoolean ("curses"))
|
||||
{
|
||||
#ifdef FEATURE_NCURSES_COLS
|
||||
initscr ();
|
||||
height = LINES;
|
||||
#else
|
||||
WINDOW* w = initscr ();
|
||||
height = w->_maxy + 1;
|
||||
#endif
|
||||
endwin ();
|
||||
|
||||
std::stringstream out;
|
||||
out << "Context::getHeight: ncurses determined height of " << height << " characters";
|
||||
debug (out.str ());
|
||||
}
|
||||
else
|
||||
debug ("Context::getHeight: ncurses available but disabled.");
|
||||
#else
|
||||
std::stringstream out;
|
||||
out << "Context::getHeight: no ncurses, using height of " << height << " characters";
|
||||
debug (out.str ());
|
||||
#endif
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
16
src/main.h
16
src/main.h
@@ -56,9 +56,9 @@ bool nag (Task&);
|
||||
|
||||
// command.cpp
|
||||
int handleAdd (std::string &);
|
||||
int handleLog (std::string &);
|
||||
int handleAppend (std::string &);
|
||||
int handlePrepend (std::string &);
|
||||
int handleExport (std::string &);
|
||||
int handleDone (std::string &);
|
||||
int handleModify (std::string &);
|
||||
int handleProjects (std::string &);
|
||||
@@ -71,13 +71,16 @@ int handleCompletionConfig (std::string &);
|
||||
int handleCompletionVersion (std::string &);
|
||||
int handleVersion (std::string &);
|
||||
int handleConfig (std::string &);
|
||||
int handleShow (std::string &);
|
||||
int handleDelete (std::string &);
|
||||
int handleStart (std::string &);
|
||||
int handleStop (std::string &);
|
||||
int handleColor (std::string &);
|
||||
int handleAnnotate (std::string &);
|
||||
int handleDenotate (std::string &);
|
||||
int handleDuplicate (std::string &);
|
||||
void handleUndo ();
|
||||
void handleMerge (std::string&);
|
||||
#ifdef FEATURE_SHELL
|
||||
void handleShell ();
|
||||
#endif
|
||||
@@ -97,8 +100,10 @@ int longUsage (std::string &);
|
||||
int handleInfo (std::string &);
|
||||
int handleReportSummary (std::string &);
|
||||
int handleReportNext (std::string &);
|
||||
int handleReportHistory (std::string &);
|
||||
int handleReportGHistory (std::string &);
|
||||
int handleReportHistoryMonthly (std::string &);
|
||||
int handleReportHistoryAnnual (std::string &);
|
||||
int handleReportGHistoryMonthly (std::string &);
|
||||
int handleReportGHistoryAnnual (std::string &);
|
||||
int handleReportCalendar (std::string &);
|
||||
int handleReportStats (std::string &);
|
||||
int handleReportTimesheet (std::string &);
|
||||
@@ -113,6 +118,7 @@ int runCustomReport (const std::string&, const std::string&,
|
||||
std::string&);
|
||||
void validReportColumns (const std::vector <std::string>&);
|
||||
void validSortColumns (const std::vector <std::string>&, const std::vector <std::string>&);
|
||||
void getLimits (const std::string&, int&, int&);
|
||||
|
||||
// rules.cpp
|
||||
void initializeColorRules ();
|
||||
@@ -124,6 +130,10 @@ std::string colorizeDebug (const std::string&);
|
||||
// import.cpp
|
||||
int handleImport (std::string&);
|
||||
|
||||
// export.cpp
|
||||
int handleExportCSV (std::string &);
|
||||
int handleExportiCal (std::string &);
|
||||
|
||||
// list template
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <class T> bool listDiff (const T& left, const T& right)
|
||||
|
||||
@@ -156,6 +156,8 @@ bool generateDueDates (Task& parent, std::vector <Date>& allDue)
|
||||
specificEnd = true;
|
||||
}
|
||||
|
||||
int recurrence_limit = context.config.getInteger ("recurrence.limit");
|
||||
int recurrence_counter = 0;
|
||||
Date now;
|
||||
for (Date i = due; ; i = getNextRecurrence (i, recur))
|
||||
{
|
||||
@@ -175,6 +177,9 @@ bool generateDueDates (Task& parent, std::vector <Date>& allDue)
|
||||
}
|
||||
|
||||
if (i > now)
|
||||
++recurrence_counter;
|
||||
|
||||
if (recurrence_counter >= recurrence_limit)
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -318,11 +323,11 @@ Date getNextRecurrence (Date& current, std::string& period)
|
||||
}
|
||||
|
||||
// If the period is an 'easy' one, add it to current, and we're done.
|
||||
int days = 0;
|
||||
try { Duration du (period); days = du; }
|
||||
catch (...) { days = 0; }
|
||||
int secs = 0;
|
||||
try { Duration du (period); secs = du; }
|
||||
catch (...) { secs = 0; }
|
||||
|
||||
return current + (days * 86400);
|
||||
return current + secs;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
508
src/report.cpp
508
src/report.cpp
@@ -39,6 +39,7 @@
|
||||
#include "Directory.h"
|
||||
#include "File.h"
|
||||
#include "Date.h"
|
||||
#include "Duration.h"
|
||||
#include "Table.h"
|
||||
#include "text.h"
|
||||
#include "util.h"
|
||||
@@ -78,17 +79,25 @@ int shortUsage (std::string &outs)
|
||||
table.addCell (row, 2, "Adds a new task.");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task append [tags] [attrs] desc...");
|
||||
table.addCell (row, 1, "task log [tags] [attrs] desc...");
|
||||
table.addCell (row, 2, "Adds a new task that is already completed.");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task append ID [tags] [attrs] desc...");
|
||||
table.addCell (row, 2, "Appends more description to an existing task.");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task prepend [tags] [attrs] desc...");
|
||||
table.addCell (row, 1, "task prepend ID [tags] [attrs] desc...");
|
||||
table.addCell (row, 2, "Prepends 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 denotate ID desc...");
|
||||
table.addCell (row, 2, "Deletes an annotation of an existing task.");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task ID [tags] [attrs] [desc...]");
|
||||
table.addCell (row, 2, "Modifies the existing task with provided arguments.");
|
||||
@@ -100,6 +109,10 @@ int shortUsage (std::string &outs)
|
||||
"substitutions for all matching text, not just the "
|
||||
"first occurrence.");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task ID");
|
||||
table.addCell (row, 2, "Specifying an ID without a command invokes the 'info' command.");
|
||||
|
||||
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.");
|
||||
@@ -156,11 +169,19 @@ int shortUsage (std::string &outs)
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task history");
|
||||
table.addCell (row, 2, "Shows a report of task history, by month.");
|
||||
table.addCell (row, 2, "Shows a report of task history, by month. Alias to history.monthly.");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task history.annual");
|
||||
table.addCell (row, 2, "Shows a report of task history, by year.");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task ghistory");
|
||||
table.addCell (row, 2, "Shows a graphical report of task history, by month.");
|
||||
table.addCell (row, 2, "Shows a graphical report of task history, by month. Alias to ghistory.monthly.");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task ghistory.annual");
|
||||
table.addCell (row, 2, "Shows a graphical report of task history, by year.");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task calendar [due|month year|year]");
|
||||
@@ -176,7 +197,11 @@ int shortUsage (std::string &outs)
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task export");
|
||||
table.addCell (row, 2, "Lists all tasks in CSV format.");
|
||||
table.addCell (row, 2, "Lists all tasks in CSV format. Alias to export.csv");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task export.ical");
|
||||
table.addCell (row, 2, "Lists all tasks in iCalendar format.");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task color [sample]");
|
||||
@@ -186,9 +211,13 @@ int shortUsage (std::string &outs)
|
||||
table.addCell (row, 1, "task version");
|
||||
table.addCell (row, 2, "Shows the task version number.");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task show [all | substring]");
|
||||
table.addCell (row, 2, "Shows the entire task configuration variables or the ones containing substring.");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task config [name [value | '']]");
|
||||
table.addCell (row, 2, "Shows the task configuration, or can add, modify and remove settings.");
|
||||
table.addCell (row, 2, "Add, modify and remove settings in the task configuration.");
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 1, "task help");
|
||||
@@ -255,7 +284,7 @@ int longUsage (std::string &outs)
|
||||
<< " until: Recurrence end date" << "\n"
|
||||
<< " fg: Foreground color" << "\n"
|
||||
<< " bg: Background color" << "\n"
|
||||
<< " limit: Desired number of rows in report" << "\n"
|
||||
<< " limit: Desired number of rows in report, or 'page'" << "\n"
|
||||
<< " wait: Date until task becomes pending" << "\n"
|
||||
<< "\n"
|
||||
<< "Attribute modifiers improve filters. Supported modifiers are:" << "\n"
|
||||
@@ -521,7 +550,7 @@ int handleInfo (std::string &outs)
|
||||
if (created.length ())
|
||||
{
|
||||
Date dt (atoi (created.c_str ()));
|
||||
age = formatSeconds ((time_t) (now - dt));
|
||||
age = Duration (now - dt).format ();
|
||||
}
|
||||
|
||||
context.hooks.trigger ("format-entry", "entry", entry);
|
||||
@@ -667,11 +696,7 @@ int handleReportSummary (std::string &outs)
|
||||
table.addCell (row, 0, (i->first == "" ? "(none)" : i->first));
|
||||
table.addCell (row, 1, countPending[i->first]);
|
||||
if (counter[i->first])
|
||||
{
|
||||
std::string age;
|
||||
age = formatSeconds ((time_t) (sumEntry[i->first] / counter[i->first]));
|
||||
table.addCell (row, 2, age);
|
||||
}
|
||||
table.addCell (row, 2, Duration ((int) sumEntry[i->first] / counter[i->first]).format ());
|
||||
|
||||
int c = countCompleted[i->first];
|
||||
int p = countPending[i->first];
|
||||
@@ -681,24 +706,13 @@ int handleReportSummary (std::string &outs)
|
||||
std::string subbar;
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
{
|
||||
for (int b = 0; b < completedBar; ++b)
|
||||
subbar += " ";
|
||||
|
||||
bar += bar_color.colorize (subbar);
|
||||
subbar = "";
|
||||
|
||||
for (int b = 0; b < barWidth - completedBar; ++b)
|
||||
subbar += " ";
|
||||
|
||||
bar += bg_color.colorize (subbar);
|
||||
bar += bar_color.colorize (std::string ( completedBar, ' '));
|
||||
bar += bg_color.colorize (std::string (barWidth - completedBar, ' '));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int b = 0; b < completedBar; ++b)
|
||||
bar += "=";
|
||||
|
||||
for (int b = 0; b < barWidth - completedBar; ++b)
|
||||
bar += " ";
|
||||
bar += std::string ( completedBar, '=')
|
||||
+ std::string (barWidth - completedBar, ' ');
|
||||
}
|
||||
table.addCell (row, 4, bar);
|
||||
|
||||
@@ -819,7 +833,25 @@ time_t monthlyEpoch (const std::string& date)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handleReportHistory (std::string &outs)
|
||||
time_t yearlyEpoch (const std::string& date)
|
||||
{
|
||||
// Convert any date in epoch form to m/d/y, then convert back
|
||||
// to epoch form for the date 1/1/y.
|
||||
if (date.length ())
|
||||
{
|
||||
Date d1 (atoi (date.c_str ()));
|
||||
int m, d, y;
|
||||
d1.toMDY (m, d, y);
|
||||
Date d2 (1, 1, y);
|
||||
time_t epoch;
|
||||
d2.toEpoch (epoch);
|
||||
return epoch;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handleReportHistoryMonthly (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
@@ -986,7 +1018,171 @@ int handleReportHistory (std::string &outs)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int handleReportGHistory (std::string &outs)
|
||||
int handleReportHistoryAnnual (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (context.hooks.trigger ("pre-history-command"))
|
||||
{
|
||||
std::map <time_t, int> groups; // Represents any month with data
|
||||
std::map <time_t, int> addedGroup; // Additions by month
|
||||
std::map <time_t, int> completedGroup; // Completions by month
|
||||
std::map <time_t, int> deletedGroup; // Deletions by month
|
||||
|
||||
// Scan the pending tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
handleRecurrence ();
|
||||
context.tdb.load (tasks, context.filter);
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
foreach (task, tasks)
|
||||
{
|
||||
time_t epoch = yearlyEpoch (task->get ("entry"));
|
||||
groups[epoch] = 0;
|
||||
|
||||
// Every task has an entry date.
|
||||
if (addedGroup.find (epoch) != addedGroup.end ())
|
||||
addedGroup[epoch] = addedGroup[epoch] + 1;
|
||||
else
|
||||
addedGroup[epoch] = 1;
|
||||
|
||||
// All deleted tasks have an end date.
|
||||
if (task->getStatus () == Task::deleted)
|
||||
{
|
||||
epoch = yearlyEpoch (task->get ("end"));
|
||||
groups[epoch] = 0;
|
||||
|
||||
if (deletedGroup.find (epoch) != deletedGroup.end ())
|
||||
deletedGroup[epoch] = deletedGroup[epoch] + 1;
|
||||
else
|
||||
deletedGroup[epoch] = 1;
|
||||
}
|
||||
|
||||
// All completed tasks have an end date.
|
||||
else if (task->getStatus () == Task::completed)
|
||||
{
|
||||
epoch = yearlyEpoch (task->get ("end"));
|
||||
groups[epoch] = 0;
|
||||
|
||||
if (completedGroup.find (epoch) != completedGroup.end ())
|
||||
completedGroup[epoch] = completedGroup[epoch] + 1;
|
||||
else
|
||||
completedGroup[epoch] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Now build the table.
|
||||
Table table;
|
||||
table.setDateFormat (context.config.get ("dateformat"));
|
||||
table.addColumn ("Year");
|
||||
table.addColumn ("Added");
|
||||
table.addColumn ("Completed");
|
||||
table.addColumn ("Deleted");
|
||||
table.addColumn ("Net");
|
||||
|
||||
if ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor")) &&
|
||||
context.config.getBoolean ("fontunderline"))
|
||||
{
|
||||
table.setColumnUnderline (0);
|
||||
table.setColumnUnderline (1);
|
||||
table.setColumnUnderline (2);
|
||||
table.setColumnUnderline (3);
|
||||
table.setColumnUnderline (4);
|
||||
}
|
||||
else
|
||||
table.setTableDashedUnderline ();
|
||||
|
||||
table.setColumnJustification (1, Table::right);
|
||||
table.setColumnJustification (2, Table::right);
|
||||
table.setColumnJustification (3, Table::right);
|
||||
table.setColumnJustification (4, Table::right);
|
||||
|
||||
int totalAdded = 0;
|
||||
int totalCompleted = 0;
|
||||
int totalDeleted = 0;
|
||||
|
||||
int priorYear = 0;
|
||||
int row = 0;
|
||||
foreach (i, groups)
|
||||
{
|
||||
row = table.addRow ();
|
||||
|
||||
totalAdded += addedGroup [i->first];
|
||||
totalCompleted += completedGroup [i->first];
|
||||
totalDeleted += deletedGroup [i->first];
|
||||
|
||||
Date dt (i->first);
|
||||
int m, d, y;
|
||||
dt.toMDY (m, d, y);
|
||||
|
||||
if (y != priorYear)
|
||||
{
|
||||
table.addCell (row, 0, y);
|
||||
priorYear = y;
|
||||
}
|
||||
|
||||
int net = 0;
|
||||
|
||||
if (addedGroup.find (i->first) != addedGroup.end ())
|
||||
{
|
||||
table.addCell (row, 1, addedGroup[i->first]);
|
||||
net +=addedGroup[i->first];
|
||||
}
|
||||
|
||||
if (completedGroup.find (i->first) != completedGroup.end ())
|
||||
{
|
||||
table.addCell (row, 2, completedGroup[i->first]);
|
||||
net -= completedGroup[i->first];
|
||||
}
|
||||
|
||||
if (deletedGroup.find (i->first) != deletedGroup.end ())
|
||||
{
|
||||
table.addCell (row, 3, deletedGroup[i->first]);
|
||||
net -= deletedGroup[i->first];
|
||||
}
|
||||
|
||||
table.addCell (row, 4, net);
|
||||
if ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor")) && net)
|
||||
table.setCellColor (row, 4, net > 0 ? Color (Color::red) :
|
||||
Color (Color::green));
|
||||
}
|
||||
|
||||
if (table.rowCount ())
|
||||
{
|
||||
table.addRow ();
|
||||
row = table.addRow ();
|
||||
|
||||
table.addCell (row, 0, "Average");
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
table.setRowColor (row, Color (Color::nocolor, Color::nocolor, false, true, false));
|
||||
table.addCell (row, 1, totalAdded / (table.rowCount () - 2));
|
||||
table.addCell (row, 2, totalCompleted / (table.rowCount () - 2));
|
||||
table.addCell (row, 3, totalDeleted / (table.rowCount () - 2));
|
||||
table.addCell (row, 4, (totalAdded - totalCompleted - totalDeleted) / (table.rowCount () - 2));
|
||||
}
|
||||
|
||||
std::stringstream out;
|
||||
if (table.rowCount ())
|
||||
out << optionalBlankLine ()
|
||||
<< table.render ()
|
||||
<< std::endl;
|
||||
else
|
||||
{
|
||||
out << "No tasks." << std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
outs = out.str ();
|
||||
context.hooks.trigger ("post-history-command");
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int handleReportGHistoryMonthly (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
@@ -1059,9 +1255,9 @@ int handleReportGHistory (std::string &outs)
|
||||
else
|
||||
table.setTableDashedUnderline ();
|
||||
|
||||
Color color_added (Color::black, Color::red);
|
||||
Color color_completed (Color::black, Color::green);
|
||||
Color color_deleted (Color::black, Color::yellow);
|
||||
Color color_add (context.config.get ("color.history.add"));
|
||||
Color color_done (context.config.get ("color.history.done"));
|
||||
Color color_delete (context.config.get ("color.history.delete"));
|
||||
|
||||
// Determine the longest line, and the longest "added" line.
|
||||
int maxAddedLine = 0;
|
||||
@@ -1140,12 +1336,11 @@ int handleReportGHistory (std::string &outs)
|
||||
dBar = " " + dBar;
|
||||
}
|
||||
|
||||
while (bar.length () < leftOffset - aBar.length ())
|
||||
bar += " ";
|
||||
bar += std::string (leftOffset - aBar.length (), ' ');
|
||||
|
||||
bar += color_added.colorize (aBar);
|
||||
bar += color_completed.colorize (cBar);
|
||||
bar += color_deleted.colorize (dBar);
|
||||
bar += color_add.colorize (aBar);
|
||||
bar += color_done.colorize (cBar);
|
||||
bar += color_delete.colorize (dBar);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1153,9 +1348,7 @@ int handleReportGHistory (std::string &outs)
|
||||
std::string cBar = ""; while (cBar.length () < completedBar) cBar += "X";
|
||||
std::string dBar = ""; while (dBar.length () < deletedBar) dBar += "-";
|
||||
|
||||
while (bar.length () < leftOffset - aBar.length ())
|
||||
bar += " ";
|
||||
|
||||
bar += std::string (leftOffset - aBar.length (), ' ');
|
||||
bar += aBar + cBar + dBar;
|
||||
}
|
||||
|
||||
@@ -1172,11 +1365,214 @@ int handleReportGHistory (std::string &outs)
|
||||
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
out << "Legend: "
|
||||
<< color_added.colorize ("added")
|
||||
<< color_add.colorize ("added")
|
||||
<< ", "
|
||||
<< color_completed.colorize ("completed")
|
||||
<< color_done.colorize ("completed")
|
||||
<< ", "
|
||||
<< color_deleted.colorize ("deleted")
|
||||
<< color_delete.colorize ("deleted")
|
||||
<< optionalBlankLine ()
|
||||
<< std::endl;
|
||||
else
|
||||
out << "Legend: + added, X completed, - deleted" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
out << "No tasks." << std::endl;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
outs = out.str ();
|
||||
context.hooks.trigger ("post-ghistory-command");
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int handleReportGHistoryAnnual (std::string &outs)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (context.hooks.trigger ("pre-ghistory-command"))
|
||||
{
|
||||
std::map <time_t, int> groups; // Represents any month with data
|
||||
std::map <time_t, int> addedGroup; // Additions by month
|
||||
std::map <time_t, int> completedGroup; // Completions by month
|
||||
std::map <time_t, int> deletedGroup; // Deletions by month
|
||||
|
||||
// Scan the pending tasks.
|
||||
std::vector <Task> tasks;
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
handleRecurrence ();
|
||||
context.tdb.load (tasks, context.filter);
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
foreach (task, tasks)
|
||||
{
|
||||
time_t epoch = yearlyEpoch (task->get ("entry"));
|
||||
groups[epoch] = 0;
|
||||
|
||||
// Every task has an entry date.
|
||||
if (addedGroup.find (epoch) != addedGroup.end ())
|
||||
addedGroup[epoch] = addedGroup[epoch] + 1;
|
||||
else
|
||||
addedGroup[epoch] = 1;
|
||||
|
||||
// All deleted tasks have an end date.
|
||||
if (task->getStatus () == Task::deleted)
|
||||
{
|
||||
epoch = yearlyEpoch (task->get ("end"));
|
||||
groups[epoch] = 0;
|
||||
|
||||
if (deletedGroup.find (epoch) != deletedGroup.end ())
|
||||
deletedGroup[epoch] = deletedGroup[epoch] + 1;
|
||||
else
|
||||
deletedGroup[epoch] = 1;
|
||||
}
|
||||
|
||||
// All completed tasks have an end date.
|
||||
else if (task->getStatus () == Task::completed)
|
||||
{
|
||||
epoch = yearlyEpoch (task->get ("end"));
|
||||
groups[epoch] = 0;
|
||||
|
||||
if (completedGroup.find (epoch) != completedGroup.end ())
|
||||
completedGroup[epoch] = completedGroup[epoch] + 1;
|
||||
else
|
||||
completedGroup[epoch] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int widthOfBar = context.getWidth () - 5; // 5 == strlen ("2008 ")
|
||||
|
||||
// Now build the table.
|
||||
Table table;
|
||||
table.setDateFormat (context.config.get ("dateformat"));
|
||||
table.addColumn ("Year");
|
||||
table.addColumn ("Number Added/Completed/Deleted");
|
||||
|
||||
if ((context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor")) &&
|
||||
context.config.getBoolean ("fontunderline"))
|
||||
{
|
||||
table.setColumnUnderline (0);
|
||||
}
|
||||
else
|
||||
table.setTableDashedUnderline ();
|
||||
|
||||
Color color_add (context.config.get ("color.history.add"));
|
||||
Color color_done (context.config.get ("color.history.done"));
|
||||
Color color_delete (context.config.get ("color.history.delete"));
|
||||
|
||||
// Determine the longest line, and the longest "added" line.
|
||||
int maxAddedLine = 0;
|
||||
int maxRemovedLine = 0;
|
||||
foreach (i, groups)
|
||||
{
|
||||
if (completedGroup[i->first] + deletedGroup[i->first] > maxRemovedLine)
|
||||
maxRemovedLine = completedGroup[i->first] + deletedGroup[i->first];
|
||||
|
||||
if (addedGroup[i->first] > maxAddedLine)
|
||||
maxAddedLine = addedGroup[i->first];
|
||||
}
|
||||
|
||||
int maxLine = maxAddedLine + maxRemovedLine;
|
||||
if (maxLine > 0)
|
||||
{
|
||||
unsigned int leftOffset = (widthOfBar * maxAddedLine) / maxLine;
|
||||
|
||||
int totalAdded = 0;
|
||||
int totalCompleted = 0;
|
||||
int totalDeleted = 0;
|
||||
|
||||
int priorYear = 0;
|
||||
int row = 0;
|
||||
foreach (i, groups)
|
||||
{
|
||||
row = table.addRow ();
|
||||
|
||||
totalAdded += addedGroup[i->first];
|
||||
totalCompleted += completedGroup[i->first];
|
||||
totalDeleted += deletedGroup[i->first];
|
||||
|
||||
Date dt (i->first);
|
||||
int m, d, y;
|
||||
dt.toMDY (m, d, y);
|
||||
|
||||
if (y != priorYear)
|
||||
{
|
||||
table.addCell (row, 0, y);
|
||||
priorYear = y;
|
||||
}
|
||||
|
||||
unsigned int addedBar = (widthOfBar * addedGroup[i->first]) / maxLine;
|
||||
unsigned int completedBar = (widthOfBar * completedGroup[i->first]) / maxLine;
|
||||
unsigned int deletedBar = (widthOfBar * deletedGroup[i->first]) / maxLine;
|
||||
|
||||
std::string bar = "";
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
{
|
||||
char number[24];
|
||||
std::string aBar = "";
|
||||
if (addedGroup[i->first])
|
||||
{
|
||||
sprintf (number, "%d", addedGroup[i->first]);
|
||||
aBar = number;
|
||||
while (aBar.length () < addedBar)
|
||||
aBar = " " + aBar;
|
||||
}
|
||||
|
||||
std::string cBar = "";
|
||||
if (completedGroup[i->first])
|
||||
{
|
||||
sprintf (number, "%d", completedGroup[i->first]);
|
||||
cBar = number;
|
||||
while (cBar.length () < completedBar)
|
||||
cBar = " " + cBar;
|
||||
}
|
||||
|
||||
std::string dBar = "";
|
||||
if (deletedGroup[i->first])
|
||||
{
|
||||
sprintf (number, "%d", deletedGroup[i->first]);
|
||||
dBar = number;
|
||||
while (dBar.length () < deletedBar)
|
||||
dBar = " " + dBar;
|
||||
}
|
||||
|
||||
bar += std::string (leftOffset - aBar.length (), ' ');
|
||||
bar += color_add.colorize (aBar);
|
||||
bar += color_done.colorize (cBar);
|
||||
bar += color_delete.colorize (dBar);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string aBar = ""; while (aBar.length () < addedBar) aBar += "+";
|
||||
std::string cBar = ""; while (cBar.length () < completedBar) cBar += "X";
|
||||
std::string dBar = ""; while (dBar.length () < deletedBar) dBar += "-";
|
||||
|
||||
bar += std::string (leftOffset - aBar.length (), ' ');
|
||||
bar += aBar + cBar + dBar;
|
||||
}
|
||||
|
||||
table.addCell (row, 1, bar);
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream out;
|
||||
if (table.rowCount ())
|
||||
{
|
||||
out << optionalBlankLine ()
|
||||
<< table.render ()
|
||||
<< std::endl;
|
||||
|
||||
if (context.config.getBoolean ("color") || context.config.getBoolean ("_forcecolor"))
|
||||
out << "Legend: "
|
||||
<< color_add.colorize ("added")
|
||||
<< ", "
|
||||
<< color_done.colorize ("completed")
|
||||
<< ", "
|
||||
<< color_delete.colorize ("deleted")
|
||||
<< optionalBlankLine ()
|
||||
<< std::endl;
|
||||
else
|
||||
@@ -1578,15 +1974,15 @@ std::string renderMonths (
|
||||
case 1: // imminent
|
||||
cellColor.blend (color_due);
|
||||
break;
|
||||
|
||||
|
||||
case 2: // today
|
||||
cellColor.blend (color_duetoday);
|
||||
break;
|
||||
|
||||
|
||||
case 3: // overdue
|
||||
cellColor.blend (color_overdue);
|
||||
break;
|
||||
|
||||
|
||||
case 0: // not due at all
|
||||
default:
|
||||
break;
|
||||
@@ -1595,7 +1991,7 @@ std::string renderMonths (
|
||||
}
|
||||
}
|
||||
}
|
||||
table.setCellColor (row, thisCol, cellColor);
|
||||
table.setCellColor (row, thisCol, cellColor);
|
||||
}
|
||||
|
||||
// Check for end of week, and...
|
||||
@@ -1902,6 +2298,7 @@ int handleReportCalendar (std::string &outs)
|
||||
holTable.addCell (row, 1, holName);
|
||||
}
|
||||
}
|
||||
|
||||
out << optionalBlankLine ()
|
||||
<< holTable.render ()
|
||||
<< std::endl;
|
||||
@@ -2100,35 +2497,35 @@ int handleReportStats (std::string &outs)
|
||||
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 0, "Task used for");
|
||||
table.addCell (row, 1, formatSeconds (latest - earliest));
|
||||
table.addCell (row, 1, Duration (latest - earliest).format ());
|
||||
}
|
||||
|
||||
if (totalT)
|
||||
{
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 0, "Task added every");
|
||||
table.addCell (row, 1, formatSeconds ((latest - earliest) / totalT));
|
||||
table.addCell (row, 1, Duration (((latest - earliest) / totalT)).format ());
|
||||
}
|
||||
|
||||
if (completedT)
|
||||
{
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 0, "Task completed every");
|
||||
table.addCell (row, 1, formatSeconds ((latest - earliest) / completedT));
|
||||
table.addCell (row, 1, Duration ((latest - earliest) / completedT).format ());
|
||||
}
|
||||
|
||||
if (deletedT)
|
||||
{
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 0, "Task deleted every");
|
||||
table.addCell (row, 1, formatSeconds ((latest - earliest) / deletedT));
|
||||
table.addCell (row, 1, Duration ((latest - earliest) / deletedT).format ());
|
||||
}
|
||||
|
||||
if (pendingT || completedT)
|
||||
{
|
||||
row = table.addRow ();
|
||||
table.addCell (row, 0, "Average time pending");
|
||||
table.addCell (row, 1, formatSeconds ((int) ((daysPending / (pendingT + completedT)) * 86400)));
|
||||
table.addCell (row, 1, Duration ((int) ((daysPending / (pendingT + completedT)) * 86400)).format ());
|
||||
}
|
||||
|
||||
if (totalT)
|
||||
@@ -2355,7 +2752,10 @@ std::string getFullDescription (Task& task, const std::string& report)
|
||||
foreach (anno, annotations)
|
||||
{
|
||||
Date dt (atoi (anno->name ().substr (11).c_str ()));
|
||||
std::string when = dt.toString (context.config.get ("dateformat"));
|
||||
std::string format = context.config.get ("dateformat.annotation");
|
||||
if (format == "")
|
||||
format = context.config.get ("dateformat");
|
||||
std::string when = dt.toString (format);
|
||||
desc += "\n" + when + " " + anno->value ();
|
||||
}
|
||||
}
|
||||
|
||||
136
src/rx.cpp
Normal file
136
src/rx.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// task - a command line task list manager.
|
||||
//
|
||||
// Copyright 2010, Paul Beckingham, Federico Hernandez.
|
||||
// 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 <stdlib.h>
|
||||
#include <regex.h>
|
||||
#include "rx.h"
|
||||
|
||||
//#define _POSIX_C_SOURCE 1
|
||||
#define MAX_MATCHES 8
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool regexMatch (
|
||||
const std::string& in,
|
||||
const std::string& pattern,
|
||||
bool caseSensitive /* = true */)
|
||||
{
|
||||
regex_t r = {0};
|
||||
int result;
|
||||
if ((result = regcomp (&r, pattern.c_str (),
|
||||
REG_EXTENDED | REG_NOSUB | REG_NEWLINE |
|
||||
(caseSensitive ? 0 : REG_ICASE))) == 0)
|
||||
{
|
||||
if ((result = regexec (&r, in.c_str (), 0, NULL, 0)) == 0)
|
||||
{
|
||||
regfree (&r);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (result == REG_NOMATCH)
|
||||
return false;
|
||||
}
|
||||
|
||||
char message[256];
|
||||
regerror (result, &r, message, 256);
|
||||
throw std::string (message);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool regexMatch (
|
||||
std::vector<std::string>& out,
|
||||
const std::string& in,
|
||||
const std::string& pattern,
|
||||
bool caseSensitive /* = true */)
|
||||
{
|
||||
regex_t r = {0};
|
||||
int result;
|
||||
if ((result = regcomp (&r, pattern.c_str (),
|
||||
REG_EXTENDED | REG_NEWLINE |
|
||||
(caseSensitive ? 0 : REG_ICASE))) == 0)
|
||||
{
|
||||
regmatch_t rm[MAX_MATCHES];
|
||||
if ((result = regexec (&r, in.c_str (), MAX_MATCHES, rm, 0)) == 0)
|
||||
{
|
||||
for (unsigned int i = 1; i < 1 + r.re_nsub; ++i)
|
||||
out.push_back (in.substr (rm[i].rm_so, rm[i].rm_eo - rm[i].rm_so));
|
||||
|
||||
regfree (&r);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (result == REG_NOMATCH)
|
||||
return false;
|
||||
}
|
||||
|
||||
char message[256];
|
||||
regerror (result, &r, message, 256);
|
||||
throw std::string (message);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool regexMatch (
|
||||
std::vector <int>& start,
|
||||
std::vector <int>& end,
|
||||
const std::string& in,
|
||||
const std::string& pattern,
|
||||
bool caseSensitive /* = true */)
|
||||
{
|
||||
regex_t r = {0};
|
||||
int result;
|
||||
if ((result = regcomp (&r, pattern.c_str (),
|
||||
REG_EXTENDED | REG_NEWLINE |
|
||||
(caseSensitive ? 0 : REG_ICASE))) == 0)
|
||||
{
|
||||
regmatch_t rm[MAX_MATCHES];
|
||||
if ((result = regexec (&r, in.c_str (), MAX_MATCHES, rm, 0)) == 0)
|
||||
{
|
||||
for (unsigned int i = 1; i < 1 + r.re_nsub; ++i)
|
||||
{
|
||||
start.push_back (rm[i].rm_so);
|
||||
end.push_back (rm[i].rm_eo);
|
||||
}
|
||||
|
||||
regfree (&r);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (result == REG_NOMATCH)
|
||||
return false;
|
||||
}
|
||||
|
||||
char message[256];
|
||||
regerror (result, &r, message, 256);
|
||||
throw std::string (message);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
39
src/rx.h
Normal file
39
src/rx.h
Normal file
@@ -0,0 +1,39 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// task - a command line task list manager.
|
||||
//
|
||||
// Copyright 2010, Paul Beckingham, Federico Hernandez.
|
||||
// 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
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDED_RX
|
||||
#define INCLuDED_RX
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
bool regexMatch (const std::string&, const std::string&, bool caseSensitive = true);
|
||||
bool regexMatch (std::vector<std::string>&, const std::string&, const std::string&, bool caseSensitive = true);
|
||||
bool regexMatch (std::vector<int>&, std::vector<int>&, const std::string&, const std::string&, bool caseSensitive = true);
|
||||
|
||||
#endif
|
||||
|
||||
1
src/tests/.gitignore
vendored
1
src/tests/.gitignore
vendored
@@ -21,4 +21,5 @@ path.t
|
||||
file.t
|
||||
directory.t
|
||||
grid.t
|
||||
rx.t
|
||||
*.log
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
PROJECT = t.t tdb.t date.t duration.t t.benchmark.t text.t autocomplete.t \
|
||||
config.t seq.t att.t stringtable.t record.t nibbler.t subst.t filt.t \
|
||||
cmd.t util.t color.t list.t path.t file.t directory.t grid.t
|
||||
cmd.t util.t color.t list.t path.t file.t directory.t grid.t rx.t
|
||||
CFLAGS = -I. -I.. -I../.. -Wall -pedantic -ggdb3 -fno-rtti
|
||||
LFLAGS = -L/usr/local/lib -lncurses -llua
|
||||
OBJECTS = ../t-TDB.o ../t-Task.o ../t-text.o ../t-Date.o ../t-Table.o \
|
||||
@@ -9,8 +9,9 @@ OBJECTS = ../t-TDB.o ../t-Task.o ../t-text.o ../t-Date.o ../t-Table.o \
|
||||
../t-Nibbler.o ../t-Location.o ../t-Filter.o ../t-Context.o \
|
||||
../t-Keymap.o ../t-command.o ../t-interactive.o ../t-report.o \
|
||||
../t-Grid.o ../t-Color.o ../t-rules.o ../t-recur.o ../t-custom.o \
|
||||
../t-import.o ../t-edit.o ../t-Timer.o ../t-Permission.o ../t-Path.o \
|
||||
../t-File.o ../t-Directory.o ../t-Hooks.o ../t-API.o
|
||||
../t-export.o ../t-import.o ../t-edit.o ../t-Timer.o \
|
||||
../t-Permission.o ../t-Path.o ../t-File.o ../t-Directory.o \
|
||||
../t-Hooks.o ../t-API.o ../t-rx.o ../t-Taskmod.o
|
||||
|
||||
all: $(PROJECT)
|
||||
|
||||
@@ -95,3 +96,6 @@ directory.t: directory.t.o $(OBJECTS) test.o
|
||||
grid.t: grid.t.o $(OBJECTS) test.o
|
||||
g++ grid.t.o $(OBJECTS) test.o $(LFLAGS) -o grid.t
|
||||
|
||||
rx.t: rx.t.o $(OBJECTS) test.o
|
||||
g++ rx.t.o $(OBJECTS) test.o $(LFLAGS) -o rx.t
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 37;
|
||||
use Test::More tests => 50;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'annotate.rc')
|
||||
@@ -77,16 +77,17 @@ my $output = qx{../task rc:annotate.rc rrr};
|
||||
# 4 four
|
||||
#
|
||||
# 4 tasks
|
||||
|
||||
like ($output, qr/1 one/, 'task 1');
|
||||
like ($output, qr/2 two/, 'task 2');
|
||||
like ($output, qr/3 three/, 'task 3');
|
||||
like ($output, qr/4 four/, 'task 4');
|
||||
like ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} foo1/ms, 'first annotation task 1');
|
||||
like ($output, qr/foo1.+\d{1,2}\/\d{1,2}\/\d{4} foo2/ms, 'second annotation task 1');
|
||||
like ($output, qr/foo2.+\d{1,2}\/\d{1,2}\/\d{4} foo3/ms, 'third annotation task 1');
|
||||
like ($output, qr/two.+\d{1,2}\/\d{1,2}\/\d{4} bar1/ms, 'first annotation task 2');
|
||||
like ($output, qr/bar1.+\d{1,2}\/\d{1,2}\/\d{4} bar2/ms, 'second annotation task 2');
|
||||
like ($output, qr/three.+\d{1,2}\/\d{1,2}\/\d{4} baz1/ms,'first annotation task 3');
|
||||
like ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} foo1/ms, 'full - first annotation task 1');
|
||||
like ($output, qr/foo1.+\d{1,2}\/\d{1,2}\/\d{4} foo2/ms, 'full - second annotation task 1');
|
||||
like ($output, qr/foo2.+\d{1,2}\/\d{1,2}\/\d{4} foo3/ms, 'full - third annotation task 1');
|
||||
like ($output, qr/two.+\d{1,2}\/\d{1,2}\/\d{4} bar1/ms, 'full - first annotation task 2');
|
||||
like ($output, qr/bar1.+\d{1,2}\/\d{1,2}\/\d{4} bar2/ms, 'full - second annotation task 2');
|
||||
like ($output, qr/three.+\d{1,2}\/\d{1,2}\/\d{4} baz1/ms,'full - first annotation task 3');
|
||||
like ($output, qr/4 tasks/, 'count');
|
||||
|
||||
$output = qx{../task rc:annotate.rc rc.annotations:sparse rrr};
|
||||
@@ -94,12 +95,12 @@ like ($output, qr/1 \+one/, 'task 1');
|
||||
like ($output, qr/2 \+two/, 'task 2');
|
||||
like ($output, qr/3 three/, 'task 3');
|
||||
like ($output, qr/4 four/, 'task 4');
|
||||
unlike ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} foo1/ms, 'first annotation task 1');
|
||||
unlike ($output, qr/foo1.+\d{1,2}\/\d{1,2}\/\d{4} foo2/ms, 'second annotation task 1');
|
||||
like ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} foo3/ms, 'third annotation task 1');
|
||||
unlike ($output, qr/two.+\d{1,2}\/\d{1,2}\/\d{4} bar1/ms, 'first annotation task 2');
|
||||
like ($output, qr/two.+\d{1,2}\/\d{1,2}\/\d{4} bar2/ms, 'second annotation task 2');
|
||||
like ($output, qr/three.+\d{1,2}\/\d{1,2}\/\d{4} baz1/ms, 'third annotation task 3');
|
||||
unlike ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} foo1/ms, 'sparse - first annotation task 1');
|
||||
unlike ($output, qr/foo1.+\d{1,2}\/\d{1,2}\/\d{4} foo2/ms, 'sparse - second annotation task 1');
|
||||
like ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} foo3/ms, 'sparse - third annotation task 1');
|
||||
unlike ($output, qr/two.+\d{1,2}\/\d{1,2}\/\d{4} bar1/ms, 'sparse - first annotation task 2');
|
||||
like ($output, qr/two.+\d{1,2}\/\d{1,2}\/\d{4} bar2/ms, 'sparse - second annotation task 2');
|
||||
like ($output, qr/three.+\d{1,2}\/\d{1,2}\/\d{4} baz1/ms, 'sparse - third annotation task 3');
|
||||
like ($output, qr/4 tasks/, 'count');
|
||||
|
||||
$output = qx{../task rc:annotate.rc rc.annotations:none rrr};
|
||||
@@ -107,12 +108,39 @@ like ($output, qr/1 \+one/, 'task 1');
|
||||
like ($output, qr/2 \+two/, 'task 2');
|
||||
like ($output, qr/3 \+three/, 'task 3');
|
||||
like ($output, qr/4 four/, 'task 4');
|
||||
unlike ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} foo1/ms, 'first annotation task 1');
|
||||
unlike ($output, qr/foo1.+\d{1,2}\/\d{1,2}\/\d{4} foo2/ms, 'second annotation task 1');
|
||||
unlike ($output, qr/foo2.+\d{1,2}\/\d{1,2}\/\d{4} foo3/ms, 'third annotation task 1');
|
||||
unlike ($output, qr/two.+\d{1,2}\/\d{1,2}\/\d{4} bar1/ms, 'first annotation task 2');
|
||||
unlike ($output, qr/bar1.+\d{1,2}\/\d{1,2}\/\d{4} bar2/ms, 'second annotation task 2');
|
||||
unlike ($output, qr/three.+\d{1,2}\/\d{1,2}\/\d{4} baz1/ms, 'third annotation task 3');
|
||||
unlike ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} foo1/ms, 'none - first annotation task 1');
|
||||
unlike ($output, qr/foo1.+\d{1,2}\/\d{1,2}\/\d{4} foo2/ms, 'none - second annotation task 1');
|
||||
unlike ($output, qr/foo2.+\d{1,2}\/\d{1,2}\/\d{4} foo3/ms, 'none - third annotation task 1');
|
||||
unlike ($output, qr/two.+\d{1,2}\/\d{1,2}\/\d{4} bar1/ms, 'none - first annotation task 2');
|
||||
unlike ($output, qr/bar1.+\d{1,2}\/\d{1,2}\/\d{4} bar2/ms, 'none - second annotation task 2');
|
||||
unlike ($output, qr/three.+\d{1,2}\/\d{1,2}\/\d{4} baz1/ms, 'none - third annotation task 3');
|
||||
like ($output, qr/4 tasks/, 'count');
|
||||
|
||||
if (open my $fh, '>', 'annotate2.rc')
|
||||
{
|
||||
# Note: Use 'rrr' to guarantee a unique report name. Using 'r' conflicts
|
||||
# with 'recurring'.
|
||||
print $fh "data.location=.\n",
|
||||
"confirmation=off\n",
|
||||
"report.rrr.description=rrr\n",
|
||||
"report.rrr.columns=id,description\n",
|
||||
"report.rrr.sort=id+\n",
|
||||
"dateformat.annotation=yMD HNS\n";
|
||||
close $fh;
|
||||
ok (-r 'annotate2.rc', 'Created annotate2.rc');
|
||||
}
|
||||
|
||||
$output = qx{../task rc:annotate2.rc rrr};
|
||||
like ($output, qr/1 one/, 'task 1');
|
||||
like ($output, qr/2 two/, 'task 2');
|
||||
like ($output, qr/3 three/, 'task 3');
|
||||
like ($output, qr/4 four/, 'task 4');
|
||||
like ($output, qr/one.+\d{1,6} \d{1,6} foo1/ms, 'dateformat - first annotation task 1');
|
||||
like ($output, qr/foo1.+\d{1,6} \d{1,6} foo2/ms, 'dateformat - second annotation task 1');
|
||||
like ($output, qr/foo2.+\d{1,6} \d{1,6} foo3/ms, 'dateformat - third annotation task 1');
|
||||
like ($output, qr/two.+\d{1,6} \d{1,6} bar1/ms, 'dateformat - first annotation task 2');
|
||||
like ($output, qr/bar1.+\d{1,6} \d{1,6} bar2/ms, 'dateformat - second annotation task 2');
|
||||
like ($output, qr/three.+\d{1,6} \d{1,6} baz1/ms,'dateformat - first annotation task 3');
|
||||
like ($output, qr/4 tasks/, 'count');
|
||||
|
||||
# Cleanup.
|
||||
@@ -124,6 +152,8 @@ ok (!-r 'undo.data', 'Removed undo.data');
|
||||
|
||||
unlink 'annotate.rc';
|
||||
ok (!-r 'annotate.rc', 'Removed annotate.rc');
|
||||
unlink 'annotate2.rc';
|
||||
ok (!-r 'annotatei2.rc', 'Removed annotate2.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
|
||||
@@ -27,13 +27,14 @@
|
||||
#include <Context.h>
|
||||
#include <Att.h>
|
||||
#include <test.h>
|
||||
#include <algorithm>
|
||||
|
||||
Context context;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (97);
|
||||
UnitTest t (99);
|
||||
|
||||
Att a;
|
||||
t.notok (a.valid ("name"), "Att::valid name -> fail");
|
||||
@@ -77,7 +78,7 @@ int main (int argc, char** argv)
|
||||
a5.value ("\"");
|
||||
t.is (a5.composeF4 (), "name:\"&dquot;\"", "Att::composeF4 encoded \"");
|
||||
a5.value ("\t\",[]:");
|
||||
t.is (a5.composeF4 (), "name:\"&tab;&dquot;,&open;&close;:\"", "Att::composeF4 fully encoded \\t\",[]:");
|
||||
t.is (a5.composeF4 (), "name:\"&tab;&dquot;,&open;&close;:\"", "Att::composeF4 fully encoded \\t\",[]:");
|
||||
|
||||
Att a6 ("name", 6);
|
||||
t.is (a6.value_int (), 6, "Att::value_int get");
|
||||
@@ -187,8 +188,8 @@ int main (int argc, char** argv)
|
||||
|
||||
n = Nibbler ("name:\"&tab;",&open;&close;:\"");
|
||||
a7.parse (n);
|
||||
t.is (a7.composeF4 (), "name:\"&tab;&dquot;,&open;&close;:\"",
|
||||
"Att::parse (name:\"&tab;",&open;&close;:\")");
|
||||
t.is (a7.composeF4 (), "name:\"&tab;&dquot;,&open;&close;:\"",
|
||||
"Att::parse (name:\"&tab;",&open;&close;:\")");
|
||||
|
||||
n = Nibbler ("total gibberish");
|
||||
good = true;
|
||||
@@ -289,6 +290,16 @@ int main (int argc, char** argv)
|
||||
t.ok (Att::validModifiableName ("until"), "modifiable until");
|
||||
t.ok (Att::validModifiableName ("wait"), "modifiable wait");
|
||||
|
||||
// Att::allNames
|
||||
std::vector <std::string> all;
|
||||
Att::allNames (all);
|
||||
|
||||
std::vector <std::string>::iterator it;
|
||||
it = std::find (all.begin (), all.end (), "uuid");
|
||||
t.ok (it != all.end (), "internal name 'uuid' found in Att::allNames");
|
||||
it = std::find (all.begin (), all.end (), "project");
|
||||
t.ok (it != all.end (), "modifiable name 'project' found in Att::allNames");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ sub report
|
||||
$data{'Context::initialize'},
|
||||
$data{'Context::parse'},
|
||||
$data{'TDB::loadPending'},
|
||||
$data{'TDB::loadCompleted'},
|
||||
$data{'TDB::loadCompleted'} || 0,
|
||||
$data{'TDB::gc'},
|
||||
$data{'TDB::commit'},
|
||||
$data{'Table::render'};
|
||||
|
||||
73
src/tests/bug.414.t
Executable file
73
src/tests/bug.414.t
Executable file
@@ -0,0 +1,73 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2010, Paul Beckingham.
|
||||
## All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free Software
|
||||
## Foundation; either version 2 of the License, or (at your option) any later
|
||||
## version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
## details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along with
|
||||
## this program; if not, write to the
|
||||
##
|
||||
## Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor,
|
||||
## Boston, MA
|
||||
## 02110-1301
|
||||
## USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 9;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'bug.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'bug.rc', 'Created bug.rc');
|
||||
}
|
||||
|
||||
# Bug #414: Tags filtering not working with unicode characters
|
||||
|
||||
# Add a task with a UTF-8 tag.
|
||||
qx{../task rc:bug.rc add one +osobní};
|
||||
my $output = qx{../task rc:bug.rc ls +osobní};
|
||||
like ($output, qr/one/, 'found UTF8 tag osobní');
|
||||
|
||||
$output = qx{../task rc:bug.rc ls -osobní};
|
||||
unlike ($output, qr/one/, 'not found UTF8 tag osobní');
|
||||
|
||||
# And a different one
|
||||
qx{../task rc:bug.rc add two +föo};
|
||||
$output = qx{../task rc:bug.rc ls +föo};
|
||||
like ($output, qr/two/, 'found UTF8 tag föo');
|
||||
|
||||
$output = qx{../task rc:bug.rc ls -föo};
|
||||
unlike ($output, qr/two/, 'not found UTF8 tag föo');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'completed.data';
|
||||
ok (!-r 'completed.data', 'Removed completed.data');
|
||||
|
||||
unlink 'undo.data';
|
||||
ok (!-r 'undo.data', 'Removed undo.data');
|
||||
|
||||
unlink 'bug.rc';
|
||||
ok (!-r 'bug.rc', 'Removed bug.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
66
src/tests/bug.417.t
Executable file
66
src/tests/bug.417.t
Executable file
@@ -0,0 +1,66 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2010, Paul Beckingham.
|
||||
## All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free Software
|
||||
## Foundation; either version 2 of the License, or (at your option) any later
|
||||
## version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
## details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along with
|
||||
## this program; if not, write to the
|
||||
##
|
||||
## Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor,
|
||||
## Boston, MA
|
||||
## 02110-1301
|
||||
## USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 7;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'bug.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'bug.rc', 'Created bug.rc');
|
||||
}
|
||||
|
||||
# Bug #417: Sorting by countdown_compact not working
|
||||
qx{../task rc:bug.rc add due:yesterday before};
|
||||
qx{../task rc:bug.rc add due:today now};
|
||||
qx{../task rc:bug.rc add due:tomorrow after};
|
||||
|
||||
my $output = qx{../task rc:bug.rc rc.report.long.sort:countdown+ long};
|
||||
like ($output, qr/before.+now.+after/ms, 'rc.report.long.sort:countdown+ works');
|
||||
|
||||
$output = qx{../task rc:bug.rc rc.report.long.sort:countdown- long};
|
||||
like ($output, qr/after.+now.+before/ms, 'rc.report.long.sort:countdown- works');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'completed.data';
|
||||
ok (!-r 'completed.data', 'Removed completed.data');
|
||||
|
||||
unlink 'undo.data';
|
||||
ok (!-r 'undo.data', 'Removed undo.data');
|
||||
|
||||
unlink 'bug.rc';
|
||||
ok (!-r 'bug.rc', 'Removed bug.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
96
src/tests/bug.418.t
Executable file
96
src/tests/bug.418.t
Executable file
@@ -0,0 +1,96 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2010, Paul Beckingham.
|
||||
## All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free Software
|
||||
## Foundation; either version 2 of the License, or (at your option) any later
|
||||
## version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
## details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along with
|
||||
## this program; if not, write to the
|
||||
##
|
||||
## Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor,
|
||||
## Boston, MA
|
||||
## 02110-1301
|
||||
## USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 23;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'bug.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"dateformat=m/d/Y\n",
|
||||
"report.foo.description=Sample\n",
|
||||
"report.foo.columns=id,due,description\n",
|
||||
"report.foo.labels=ID,Due,Description\n",
|
||||
"report.foo.sort=due+\n",
|
||||
"report.foo.filter=status:pending\n",
|
||||
"report.foo.dateformat=MD\n";
|
||||
close $fh;
|
||||
ok (-r 'bug.rc', 'Created bug.rc');
|
||||
}
|
||||
|
||||
# Bug #418: due.before:eow not working
|
||||
# - with dateformat is MD
|
||||
qx{../task rc:bug.rc add one due:6/28/2010};
|
||||
qx{../task rc:bug.rc add two due:6/29/2010};
|
||||
qx{../task rc:bug.rc add three due:6/30/2010};
|
||||
qx{../task rc:bug.rc add four due:7/1/2010};
|
||||
qx{../task rc:bug.rc add five due:7/2/2010};
|
||||
qx{../task rc:bug.rc add six due:7/3/2010};
|
||||
qx{../task rc:bug.rc add seven due:7/4/2010};
|
||||
qx{../task rc:bug.rc add eight due:7/5/2010};
|
||||
qx{../task rc:bug.rc add nine due:7/6/2010};
|
||||
|
||||
my $output = qx{../task rc:bug.rc foo};
|
||||
like ($output, qr/one/ms, 'task 1 listed');
|
||||
like ($output, qr/two/ms, 'task 2 listed');
|
||||
like ($output, qr/three/ms, 'task 3 listed');
|
||||
like ($output, qr/four/ms, 'task 4 listed');
|
||||
like ($output, qr/five/ms, 'task 5 listed');
|
||||
like ($output, qr/six/ms, 'task 6 listed');
|
||||
like ($output, qr/seven/ms, 'task 7 listed');
|
||||
like ($output, qr/eight/ms, 'task 8 listed');
|
||||
like ($output, qr/nine/ms, 'task 9 listed');
|
||||
|
||||
$output = qx{../task rc:bug.rc foo due.before:7/2/2010};
|
||||
like ($output, qr/one/ms, 'task 1 listed');
|
||||
like ($output, qr/two/ms, 'task 2 listed');
|
||||
like ($output, qr/three/ms, 'task 3 listed');
|
||||
like ($output, qr/four/ms, 'task 4 listed');
|
||||
unlike ($output, qr/five/ms, 'task 5 not listed');
|
||||
unlike ($output, qr/six/ms, 'task 6 not listed');
|
||||
unlike ($output, qr/seven/ms, 'task 7 not listed');
|
||||
unlike ($output, qr/eight/ms, 'task 8 not listed');
|
||||
unlike ($output, qr/nine/ms, 'task 9 not listed');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'completed.data';
|
||||
ok (!-r 'completed.data', 'Removed completed.data');
|
||||
|
||||
unlink 'undo.data';
|
||||
ok (!-r 'undo.data', 'Removed undo.data');
|
||||
|
||||
unlink 'bug.rc';
|
||||
ok (!-r 'bug.rc', 'Removed bug.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
@@ -75,61 +75,61 @@ Confirmed:
|
||||
=cut
|
||||
|
||||
my $output = qx{../task rc:period.rc add daily due:tomorrow recur:daily};
|
||||
unlike ($output, qr/was not recignized/, 'recur:daily');
|
||||
unlike ($output, qr/was not recognized/, 'recur:daily');
|
||||
|
||||
$output = qx{../task rc:period.rc add day due:tomorrow recur:day};
|
||||
unlike ($output, qr/was not recignized/, 'recur:day');
|
||||
unlike ($output, qr/was not recognized/, 'recur:day');
|
||||
|
||||
$output = qx{../task rc:period.rc add weekly due:tomorrow recur:weekly};
|
||||
unlike ($output, qr/was not recignized/, 'recur:weekly');
|
||||
unlike ($output, qr/was not recognized/, 'recur:weekly');
|
||||
|
||||
$output = qx{../task rc:period.rc add sennight due:tomorrow recur:sennight};
|
||||
unlike ($output, qr/was not recignized/, 'recur:sennight');
|
||||
unlike ($output, qr/was not recognized/, 'recur:sennight');
|
||||
|
||||
$output = qx{../task rc:period.rc add biweekly due:tomorrow recur:biweekly};
|
||||
unlike ($output, qr/was not recignized/, 'recur:biweekly');
|
||||
unlike ($output, qr/was not recognized/, 'recur:biweekly');
|
||||
|
||||
$output = qx{../task rc:period.rc add fortnight due:tomorrow recur:fortnight};
|
||||
unlike ($output, qr/was not recignized/, 'recur:fortnight');
|
||||
unlike ($output, qr/was not recognized/, 'recur:fortnight');
|
||||
|
||||
$output = qx{../task rc:period.rc add monthly due:tomorrow recur:monthly};
|
||||
unlike ($output, qr/was not recignized/, 'recur:monthly');
|
||||
unlike ($output, qr/was not recognized/, 'recur:monthly');
|
||||
|
||||
$output = qx{../task rc:period.rc add quarterly due:tomorrow recur:quarterly};
|
||||
unlike ($output, qr/was not recignized/, 'recur:quarterly');
|
||||
unlike ($output, qr/was not recognized/, 'recur:quarterly');
|
||||
|
||||
$output = qx{../task rc:period.rc add semiannual due:tomorrow recur:semiannual};
|
||||
unlike ($output, qr/was not recignized/, 'recur:semiannual');
|
||||
unlike ($output, qr/was not recognized/, 'recur:semiannual');
|
||||
|
||||
$output = qx{../task rc:period.rc add bimonthly due:tomorrow recur:bimonthly};
|
||||
unlike ($output, qr/was not recignized/, 'recur:bimonthly');
|
||||
unlike ($output, qr/was not recognized/, 'recur:bimonthly');
|
||||
|
||||
$output = qx{../task rc:period.rc add biannual due:tomorrow recur:biannual};
|
||||
unlike ($output, qr/was not recignized/, 'recur:biannual');
|
||||
unlike ($output, qr/was not recognized/, 'recur:biannual');
|
||||
|
||||
$output = qx{../task rc:period.rc add biyearly due:tomorrow recur:biyearly};
|
||||
unlike ($output, qr/was not recignized/, 'recur:biyearly');
|
||||
unlike ($output, qr/was not recognized/, 'recur:biyearly');
|
||||
|
||||
$output = qx{../task rc:period.rc add annual due:tomorrow recur:annual};
|
||||
unlike ($output, qr/was not recignized/, 'recur:annual');
|
||||
unlike ($output, qr/was not recognized/, 'recur:annual');
|
||||
|
||||
$output = qx{../task rc:period.rc add yearly due:tomorrow recur:yearly};
|
||||
unlike ($output, qr/was not recignized/, 'recur:yearly');
|
||||
unlike ($output, qr/was not recognized/, 'recur:yearly');
|
||||
|
||||
$output = qx{../task rc:period.rc add 2d due:tomorrow recur:2d};
|
||||
unlike ($output, qr/was not recignized/, 'recur:2m');
|
||||
unlike ($output, qr/was not recognized/, 'recur:2d');
|
||||
|
||||
$output = qx{../task rc:period.rc add 2w due:tomorrow recur:2w};
|
||||
unlike ($output, qr/was not recignized/, 'recur:2q');
|
||||
unlike ($output, qr/was not recognized/, 'recur:2w');
|
||||
|
||||
$output = qx{../task rc:period.rc add 2m due:tomorrow recur:2m};
|
||||
unlike ($output, qr/was not recignized/, 'recur:2d');
|
||||
$output = qx{../task rc:period.rc add 2m due:tomorrow recur:2mo};
|
||||
unlike ($output, qr/was not recognized/, 'recur:2m');
|
||||
|
||||
$output = qx{../task rc:period.rc add 2q due:tomorrow recur:2q};
|
||||
unlike ($output, qr/was not recignized/, 'recur:2w');
|
||||
unlike ($output, qr/was not recognized/, 'recur:2q');
|
||||
|
||||
$output = qx{../task rc:period.rc add 2y due:tomorrow recur:2y};
|
||||
unlike ($output, qr/was not recignized/, 'recur:2y');
|
||||
unlike ($output, qr/was not recognized/, 'recur:2y');
|
||||
|
||||
# Verify that the recurring task instances get created. One of each.
|
||||
$output = qx{../task rc:period.rc list};
|
||||
|
||||
@@ -47,11 +47,11 @@ qx{../task rc:summary.rc add project:A three};
|
||||
qx{../task rc:summary.rc do 1};
|
||||
qx{../task rc:summary.rc delete 2};
|
||||
my $output = qx{../task rc:summary.rc summary};
|
||||
like ($output, qr/A\s+1\s+-\s+50%/, 'summary correctly shows 50% before report');
|
||||
like ($output, qr/A\s+1\s+(?:-|\d\ssecs?)\s+50%/, 'summary correctly shows 50% before report');
|
||||
|
||||
qx{../task rc:summary.rc list};
|
||||
$output = qx{../task rc:summary.rc summary};
|
||||
like ($output, qr/A\s+1\s+-\s+50%/, 'summary correctly shows 50% after report');
|
||||
like ($output, qr/A\s+1\s+(?:-|\d\ssecs?)\s+50%/, 'summary correctly shows 50% after report');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
|
||||
@@ -38,6 +38,11 @@ if (open my $fh, '>', 'cal.rc')
|
||||
print $fh "data.location=.\n",
|
||||
"dateformat=YMD\n",
|
||||
"color=on\n",
|
||||
"color.calendar.today=black on cyan\n",
|
||||
"color.calendar.due=black on green\n",
|
||||
"color.calendar.weeknumber=black on white\n",
|
||||
"color.calendar.overdue=black on red\n",
|
||||
"color.calendar.weekend=white on bright black\n",
|
||||
"confirmation=no\n";
|
||||
close $fh;
|
||||
ok (-r 'cal.rc', 'Created cal.rc');
|
||||
@@ -52,14 +57,14 @@ my $nextmonth = $months[($nmon+1) % 12];
|
||||
my $year = $nyear + 1900;
|
||||
my $nextyear = $nyear + 1901;
|
||||
|
||||
if ( $day <= 9)
|
||||
if ($day <= 9)
|
||||
{
|
||||
$day = " ".$day;
|
||||
}
|
||||
|
||||
# task cal and task cal y
|
||||
my $output = qx{../task rc:cal.rc rc._forcecolor:on cal};
|
||||
if ( $wday == 6 || $wday == 0)
|
||||
if ($wday == 6 || $wday == 0)
|
||||
{
|
||||
like ($output, qr/\[30;106m$day/, 'Current day is highlighted');
|
||||
}
|
||||
@@ -72,17 +77,17 @@ $output = qx{../task rc:cal.rc add zero};
|
||||
unlike ($output, qr/\[41m\d+/, 'No overdue tasks are present');
|
||||
unlike ($output, qr/\[43m\d+/, 'No due tasks are present');
|
||||
$output = qx{../task rc:cal.rc rc.weekstart:Sunday cal};
|
||||
like ($output, qr/Su Mo Tu/, 'Week starts on Sunday');
|
||||
like ($output, qr/Su Mo Tu/, 'Week starts on Sunday');
|
||||
$output = qx{../task rc:cal.rc rc.weekstart:Monday cal};
|
||||
like ($output, qr/Fr Sa Su/, 'Week starts on Monday');
|
||||
like ($output, qr/Fr Sa Su/, 'Week starts on Monday');
|
||||
$output = qx{../task rc:cal.rc cal y};
|
||||
like ($output, qr/$month\S*?\s+?$year/, 'Current month and year are displayed');
|
||||
if ( $month eq "Jan")
|
||||
if ($month eq "Jan")
|
||||
{
|
||||
$nextyear = $nextyear - 1;
|
||||
}
|
||||
like ($output, qr/$prevmonth\S*?\s+?$nextyear/, 'Month and year one year ahead are displayed');
|
||||
if ( $month eq "Jan")
|
||||
if ($month eq "Jan")
|
||||
{
|
||||
$nextyear = $nextyear + 1;
|
||||
}
|
||||
@@ -151,6 +156,9 @@ if (open my $fh, '>', 'details.rc')
|
||||
"calendar.details.report=list\n",
|
||||
"calendar.holidays=full\n",
|
||||
"color=on\n",
|
||||
"color.alternate=\n",
|
||||
"color.calendar.weekend=\n",
|
||||
"color.calendar.holiday=black on bright yellow\n",
|
||||
"confirmation=no\n",
|
||||
"holiday.AAAA.name=AAAA\n",
|
||||
"holiday.AAAA.date=20150101\n",
|
||||
|
||||
@@ -33,7 +33,7 @@ Context context;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (78);
|
||||
UnitTest t (86);
|
||||
|
||||
// Without Context::initialize, there is no set of defaults loaded into
|
||||
// Context::Config.
|
||||
@@ -57,21 +57,33 @@ int main (int argc, char** argv)
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand completed");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand completed");
|
||||
|
||||
cmd.command = "export";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand export");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand export");
|
||||
cmd.command = "export.csv";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand export.csv");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand export.csv");
|
||||
|
||||
cmd.command = "export.ical";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand export.ical");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand export.ical");
|
||||
|
||||
cmd.command = "help";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand help");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand help");
|
||||
|
||||
cmd.command = "history";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand history");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand history");
|
||||
cmd.command = "history.monthly";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand history.monthly");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand history.monthly");
|
||||
|
||||
cmd.command = "ghistory";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand ghistory");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand ghistory");
|
||||
cmd.command = "history.annual";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand history.annual");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand history.annual");
|
||||
|
||||
cmd.command = "ghistory.monthly";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand ghistory.monthly");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand ghistory.monthly");
|
||||
|
||||
cmd.command = "ghistory.annual";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand ghistory.annual");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand ghistory.annual");
|
||||
|
||||
cmd.command = "info";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand info");
|
||||
@@ -121,6 +133,10 @@ int main (int argc, char** argv)
|
||||
t.notok (cmd.isReadOnlyCommand (), "not isReadOnlyCommand add");
|
||||
t.ok (cmd.isWriteCommand (), "isWriteCommand add");
|
||||
|
||||
cmd.command = "log";
|
||||
t.notok (cmd.isReadOnlyCommand (), "not isReadOnlyCommand log");
|
||||
t.ok (cmd.isWriteCommand (), "isWriteCommand log");
|
||||
|
||||
cmd.command = "append";
|
||||
t.notok (cmd.isReadOnlyCommand (), "not isReadOnlyCommand append");
|
||||
t.ok (cmd.isWriteCommand (), "isWriteCommand append");
|
||||
|
||||
@@ -41,7 +41,7 @@ if (open my $fh, '>', 'color.rc')
|
||||
}
|
||||
|
||||
# Test the add command.
|
||||
my $output = qx{../task rc:color.rc config};
|
||||
my $output = qx{../task rc:color.rc show};
|
||||
like ($output, qr/that use deprecated underscores/ms, 'Deprecated color detected');
|
||||
|
||||
# Cleanup.
|
||||
|
||||
@@ -34,6 +34,7 @@ use Test::More tests => 7;
|
||||
if (open my $fh, '>', 'color.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"color.alternate=\n",
|
||||
"color.keyword.red=red\n",
|
||||
"color.keyword.green=green\n",
|
||||
"_forcecolor=1\n";
|
||||
|
||||
@@ -38,6 +38,7 @@ if (open my $fh, '>', 'color.rc')
|
||||
"color.pri.M=green\n",
|
||||
"color.pri.L=blue\n",
|
||||
"color.pri.none=yellow\n",
|
||||
"color.alternate=\n",
|
||||
"_forcecolor=1\n";
|
||||
close $fh;
|
||||
ok (-r 'color.rc', 'Created color.rc');
|
||||
|
||||
@@ -35,6 +35,7 @@ if (open my $fh, '>', 'color.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"color.project.x=red\n",
|
||||
"color.alternate=\n",
|
||||
"_forcecolor=1\n";
|
||||
close $fh;
|
||||
ok (-r 'color.rc', 'Created color.rc');
|
||||
|
||||
@@ -34,6 +34,8 @@ use Test::More tests => 7;
|
||||
if (open my $fh, '>', 'color.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"color.tagged=\n",
|
||||
"color.alternate=\n",
|
||||
"color.tag.red=red\n",
|
||||
"color.tag.green=green\n",
|
||||
"_forcecolor=1\n";
|
||||
|
||||
@@ -35,6 +35,7 @@ if (open my $fh, '>', 'color.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"color.tagged=red\n",
|
||||
"color.alternate=\n",
|
||||
"_forcecolor=1\n";
|
||||
close $fh;
|
||||
ok (-r 'color.rc', 'Created color.rc');
|
||||
|
||||
@@ -40,7 +40,7 @@ if (open my $fh, '>', 'obsolete.rc')
|
||||
}
|
||||
|
||||
# Test the add command.
|
||||
my $output = qx{../task rc:obsolete.rc config};
|
||||
my $output = qx{../task rc:obsolete.rc show};
|
||||
|
||||
like ($output, qr/Your .taskrc file contains these unrecognized variables:\n/,
|
||||
'unsupported configuration variable');
|
||||
|
||||
@@ -34,7 +34,7 @@ Context context;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (143);
|
||||
UnitTest t (144);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -150,6 +150,9 @@ int main (int argc, char** argv)
|
||||
Date fromEpoch (epoch.toEpoch ());
|
||||
t.is (fromEpoch.toString (), epoch.toString (), "ctor (time_t)");
|
||||
|
||||
Date iso (1000000000);
|
||||
t.is (iso.toISO (), "20010909T014640Z", "1,000,000,000 -> 20010909T014640Z");
|
||||
|
||||
// Date parsing.
|
||||
Date fromString1 ("1/1/2008");
|
||||
t.is (fromString1.month (), 1, "ctor (std::string) -> m");
|
||||
|
||||
70
src/tests/datesort.t
Executable file
70
src/tests/datesort.t
Executable file
@@ -0,0 +1,70 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2010, Paul Beckingham.
|
||||
## All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free Software
|
||||
## Foundation; either version 2 of the License, or (at your option) any later
|
||||
## version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
## details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along with
|
||||
## this program; if not, write to the
|
||||
##
|
||||
## Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor,
|
||||
## Boston, MA
|
||||
## 02110-1301
|
||||
## USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 6;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'datesort.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"dateformat=YMD\n",
|
||||
"report.small_list.description=Small list\n",
|
||||
"report.small_list.columns=due,description\n",
|
||||
"report.small_list.labels=Due,Description\n",
|
||||
"report.small_list.sort=due+\n",
|
||||
"report.small_list.filter=status:pending\n",
|
||||
"report.small_list.dateformat=MD\n";
|
||||
|
||||
close $fh;
|
||||
ok (-r 'datesort.rc', 'Created datesort.rc');
|
||||
}
|
||||
|
||||
qx{../task rc:datesort.rc add two due:20100201};
|
||||
qx{../task rc:datesort.rc add one due:20100101};
|
||||
qx{../task rc:datesort.rc add three due:20100301};
|
||||
|
||||
my $output = qx{../task rc:datesort.rc small_list};
|
||||
like ($output, qr/one.+two.+three/ms, 'Sorting by due+ with format MD works');
|
||||
|
||||
$output = qx{../task rc:datesort.rc rc.report.small_list.sort=due- small_list};
|
||||
like ($output, qr/three.+two.+one/ms, 'Sorting by due- with format MD works');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'undo.data';
|
||||
ok (!-r 'undo.data', 'Removed undo.data');
|
||||
|
||||
unlink 'datesort.rc';
|
||||
ok (!-r 'datesort.rc', 'Removed datesort.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
119
src/tests/denotate.t
Executable file
119
src/tests/denotate.t
Executable file
@@ -0,0 +1,119 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2010, Paul Beckingham.
|
||||
## All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free Software
|
||||
## Foundation; either version 2 of the License, or (at your option) any later
|
||||
## version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
## details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along with
|
||||
## this program; if not, write to the
|
||||
##
|
||||
## Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor,
|
||||
## Boston, MA
|
||||
## 02110-1301
|
||||
## USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 29;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'denotate.rc')
|
||||
{
|
||||
# Note: Use 'rrr' to guarantee a unique report name. Using 'r' conflicts
|
||||
# with 'recurring'.
|
||||
print $fh "data.location=.\n",
|
||||
"confirmation=off\n",
|
||||
"report.rrr.description=rrr\n",
|
||||
"report.rrr.columns=id,description\n",
|
||||
"report.rrr.sort=id+\n";
|
||||
close $fh;
|
||||
ok (-r 'denotate.rc', 'Created denotate.rc');
|
||||
}
|
||||
|
||||
# Add four tasks, annotate one three times, one twice, one just once and one none.
|
||||
qx{../task rc:denotate.rc add one};
|
||||
qx{../task rc:denotate.rc annotate 1 Ernie};
|
||||
sleep 1;
|
||||
qx{../task rc:denotate.rc annotate 1 Bert};
|
||||
sleep 1;
|
||||
qx{../task rc:denotate.rc annotate 1 Bibo};
|
||||
sleep 1;
|
||||
qx{../task rc:denotate.rc annotate 1 Kermit the frog};
|
||||
sleep 1;
|
||||
qx{../task rc:denotate.rc annotate 1 Kermit the frog};
|
||||
sleep 1;
|
||||
qx{../task rc:denotate.rc annotate 1 Kermit};
|
||||
sleep 1;
|
||||
qx{../task rc:denotate.rc annotate 1 Kermit and Miss Piggy};
|
||||
|
||||
my $output = qx{../task rc:denotate.rc rrr};
|
||||
|
||||
like ($output, qr/1 one/, 'task 1');
|
||||
like ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} Ernie/ms, 'first annotation');
|
||||
like ($output, qr/Ernie.+\d{1,2}\/\d{1,2}\/\d{4} Bert/ms, 'second annotation');
|
||||
like ($output, qr/Bert.+\d{1,2}\/\d{1,2}\/\d{4} Bibo/ms, 'third annotation');
|
||||
like ($output, qr/Bibo.+\d{1,2}\/\d{1,2}\/\d{4} Kermit the frog/ms, 'fourth annotation');
|
||||
like ($output, qr/frog.+\d{1,2}\/\d{1,2}\/\d{4} Kermit the frog/ms, 'fifth annotation');
|
||||
like ($output, qr/frog.+\d{1,2}\/\d{1,2}\/\d{4} Kermit/ms, 'sixth annotation');
|
||||
like ($output, qr/Kermit.+\d{1,2}\/\d{1,2}\/\d{4} Kermit and Miss Piggy/ms, 'seventh annotation');
|
||||
like ($output, qr/1 task/, 'count');
|
||||
|
||||
qx{../task rc:denotate.rc denotate 1 Ernie};
|
||||
$output = qx{../task rc:denotate.rc rrr};
|
||||
unlike ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} Ernie/ms, 'Delete annotation');
|
||||
like ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} Bert/ms, 'Bert now first annotationt');
|
||||
|
||||
qx{../task rc:denotate.rc denotate 1 Bi};
|
||||
$output = qx{../task rc:denotate.rc rrr};
|
||||
unlike ($output, qr/Bert.+\d{1,2}\/\d{1,2}\/\d{4} Bibo/ms, 'Delete partial match');
|
||||
like ($output, qr/Bert.+\d{1,2}\/\d{1,2}\/\d{4} Kermit the frog/ms, 'Kermit the frog now second annotation');
|
||||
|
||||
qx{../task rc:denotate.rc denotate 1 BErt};
|
||||
$output = qx{../task rc:denotate.rc rrr};
|
||||
like ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} Bert/ms, 'Denotate is case sensitive');
|
||||
like ($output, qr/Bert.+\d{1,2}\/\d{1,2}\/\d{4} Kermit the frog/ms, 'Kermit the frog still second annoation');
|
||||
|
||||
qx{../task rc:denotate.rc denotate 1 Kermit};
|
||||
$output = qx{../task rc:denotate.rc rrr};
|
||||
like ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} Bert/ms, 'Exact match deletion - Bert');
|
||||
like ($output, qr/Bert.+\d{1,2}\/\d{1,2}\/\d{4} Kermit the frog/ms, 'Exact match deletion - Kermit the frog');
|
||||
like ($output, qr/frog.+\d{1,2}\/\d{1,2}\/\d{4} Kermit the frog/ms, 'Exact match deletion - Kermit the frog');
|
||||
like ($output, qr/frog.+\d{1,2}\/\d{1,2}\/\d{4} Kermit and Miss Piggy/ms, 'Exact match deletion - Kermit and Miss Piggy');
|
||||
|
||||
qx{../task rc:denotate.rc denotate 1 Kermit the};
|
||||
$output = qx{../task rc:denotate.rc rrr};
|
||||
like ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} Bert/ms, 'Delete just one annotation - Bert');
|
||||
like ($output, qr/Bert.+\d{1,2}\/\d{1,2}\/\d{4} Kermit the frog/ms, 'Delete just one annotation - Kermit the frog');
|
||||
like ($output, qr/frog.+\d{1,2}\/\d{1,2}\/\d{4} Kermit and Miss Piggy/ms, 'Delete just one annotation - Kermit and Miss Piggy');
|
||||
|
||||
qx{../task rc:denotate.rc denotate 1 Kermit a};
|
||||
$output = qx{../task rc:denotate.rc rrr};
|
||||
like ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} Bert/ms, 'Delete partial match - Bert');
|
||||
like ($output, qr/Bert.+\d{1,2}\/\d{1,2}\/\d{4} Kermit the frog/ms, 'Delete partial match - Kermit the frog');
|
||||
unlike ($output, qr/frog.+\d{1,2}\/\d{1,2}\/\d{4} Kermit and Miss Piggy/ms, 'Delete partial match - Kermit and Miss Piggy');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'undo.data';
|
||||
ok (!-r 'undo.data', 'Removed undo.data');
|
||||
|
||||
unlink 'denotate.rc';
|
||||
ok (!-r 'denotate.rc', 'Removed denotate.rc');
|
||||
|
||||
exit 0;
|
||||
@@ -37,6 +37,7 @@ if (open my $fh, '>', 'due.rc')
|
||||
"due=4\n",
|
||||
"color=on\n",
|
||||
"color.due=red\n",
|
||||
"color.alternate=\n",
|
||||
"_forcecolor=on\n",
|
||||
"dateformat=m/d/Y\n";
|
||||
close $fh;
|
||||
|
||||
@@ -41,55 +41,664 @@ Context context;
|
||||
|
||||
int convertDuration (const std::string& input)
|
||||
{
|
||||
try { Duration d (input); return (int) d; }
|
||||
try { Duration d (input); return ((int) d) / 86400; }
|
||||
catch (...) {}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (35);
|
||||
UnitTest t (577);
|
||||
|
||||
Duration d;
|
||||
t.ok (d.valid ("daily"), "duration daily = 1");
|
||||
t.ok (d.valid ("weekdays"), "duration weekdays = 1");
|
||||
t.ok (d.valid ("day"), "duration day = 1");
|
||||
t.ok (d.valid ("0d"), "duration 0d = 0");
|
||||
t.ok (d.valid ("1d"), "duration 1d = 1");
|
||||
t.ok (d.valid ("7d"), "duration 7d = 7");
|
||||
t.ok (d.valid ("10d"), "duration 10d = 10");
|
||||
t.ok (d.valid ("100d"), "duration 100d = 100");
|
||||
|
||||
t.ok (d.valid ("weekly"), "duration weekly = 7");
|
||||
t.ok (d.valid ("sennight"), "duration sennight = 7");
|
||||
t.ok (d.valid ("biweekly"), "duration biweekly = 14");
|
||||
t.ok (d.valid ("fortnight"), "duration fortnight = 14");
|
||||
t.ok (d.valid ("0w"), "duration 0w = 0");
|
||||
t.ok (d.valid ("1w"), "duration 1w = 7");
|
||||
t.ok (d.valid ("7w"), "duration 7w = 49");
|
||||
t.ok (d.valid ("10w"), "duration 10w = 70");
|
||||
t.ok (d.valid ("100w"), "duration 100w = 700");
|
||||
// std::string format ();
|
||||
d = Duration (0); t.is (d.format (), "-", "0 -> -");
|
||||
d = Duration (1); t.is (d.format (), "1 sec", "1 -> 1 sec");
|
||||
d = Duration (2); t.is (d.format (), "2 secs", "2 -> 2 secs");
|
||||
d = Duration (59); t.is (d.format (), "59 secs", "59 -> 59 secs");
|
||||
d = Duration (60); t.is (d.format (), "1 min", "60 -> 1 min");
|
||||
d = Duration (119); t.is (d.format (), "1 min", "119 -> 1 min");
|
||||
d = Duration (120); t.is (d.format (), "2 mins", "120 -> 2 mins");
|
||||
d = Duration (121); t.is (d.format (), "2 mins", "121 -> 2 mins");
|
||||
d = Duration (3599); t.is (d.format (), "59 mins", "3599 -> 59 mins");
|
||||
d = Duration (3600); t.is (d.format (), "1 hr", "3600 -> 1 hr");
|
||||
d = Duration (3601); t.is (d.format (), "1 hr", "3601 -> 1 hr");
|
||||
d = Duration (86399); t.is (d.format (), "23 hrs", "86399 -> 23 hrs");
|
||||
d = Duration (86400); t.is (d.format (), "1 day", "86400 -> 1 day");
|
||||
d = Duration (86401); t.is (d.format (), "1 day", "86401 -> 1 day");
|
||||
d = Duration (14 * 86400 - 1); t.is (d.format (), "1 wk", "14 days - 1 sec -> 1 wk");
|
||||
d = Duration (14 * 86400); t.is (d.format (), "2 wks", "14 days -> 2 wks");
|
||||
d = Duration (14 * 86400 + 1); t.is (d.format (), "2 wks", "14 days + 1 sec -> 2 wks");
|
||||
d = Duration (85 * 86400 - 1); t.is (d.format (), "2 mths", "85 days - 1 sec -> 2 mths");
|
||||
d = Duration (85 * 86400); t.is (d.format (), "2 mths", "85 days -> 2 mths");
|
||||
d = Duration (85 * 86400 + 1); t.is (d.format (), "2 mths", "85 days + 1 sec -> 2 mths");
|
||||
d = Duration (365 * 86400 - 1); t.is (d.format (), "11 mths", "365 days - 1 sec -> 11 mths");
|
||||
d = Duration (365 * 86400); t.is (d.format (), "1.0 yrs", "365 days -> 1.0 yrs");
|
||||
d = Duration (365 * 86400 + 1); t.is (d.format (), "1.0 yrs", "365 days + 1 sec -> 1.0 yrs");
|
||||
|
||||
t.notok (d.valid ("woof"), "duration woof = fail");
|
||||
// std::string formatCompact ();
|
||||
d = Duration (0), t.is (d.formatCompact (), "-", "0 -> -");
|
||||
d = Duration (1), t.is (d.formatCompact (), "1s", "1 -> 1s");
|
||||
d = Duration (2), t.is (d.formatCompact (), "2s", "2 -> 2s");
|
||||
d = Duration (59), t.is (d.formatCompact (), "59s", "59 -> 59s");
|
||||
d = Duration (60), t.is (d.formatCompact (), "1m", "60 -> 1m");
|
||||
d = Duration (119), t.is (d.formatCompact (), "1m", "119 -> 1m");
|
||||
d = Duration (120), t.is (d.formatCompact (), "2m", "120 -> 2m");
|
||||
d = Duration (121), t.is (d.formatCompact (), "2m", "121 -> 2m");
|
||||
d = Duration (3599), t.is (d.formatCompact (), "59m", "3599 -> 59m");
|
||||
d = Duration (3600), t.is (d.formatCompact (), "1h", "3600 -> 1h");
|
||||
d = Duration (3601), t.is (d.formatCompact (), "1h", "3601 -> 1h");
|
||||
d = Duration (86399), t.is (d.formatCompact (), "23h", "86399 -> 23h");
|
||||
d = Duration (86400), t.is (d.formatCompact (), "1d", "86400 -> 1d");
|
||||
d = Duration (86401), t.is (d.formatCompact (), "1d", "86401 -> 1d");
|
||||
d = Duration (14 * 86400 - 1), t.is (d.formatCompact (), "1wk", "14 days - 1 sec -> 1wk");
|
||||
d = Duration (14 * 86400), t.is (d.formatCompact (), "2wk", "14 days -> 2wk");
|
||||
d = Duration (14 * 86400 + 1), t.is (d.formatCompact (), "2wk", "14 days + 1 sec -> 2wk");
|
||||
d = Duration (85 * 86400 - 1), t.is (d.formatCompact (), "2mo", "85 days - 1 sec -> 2mo");
|
||||
d = Duration (85 * 86400), t.is (d.formatCompact (), "2mo", "85 days -> 2mo");
|
||||
d = Duration (85 * 86400 + 1), t.is (d.formatCompact (), "2mo", "85 days + 1 sec -> 2mo");
|
||||
d = Duration (365 * 86400 - 1), t.is (d.formatCompact (), "11mo", "365 days - 1 sec -> 11mo");
|
||||
d = Duration (365 * 86400), t.is (d.formatCompact (), "1.0y", "365 days -> 1.0y");
|
||||
d = Duration (365 * 86400 + 1), t.is (d.formatCompact (), "1.0y", "365 days + 1 sec -> 1.0y");
|
||||
|
||||
t.is (convertDuration ("daily"), 1, "duration daily = 1");
|
||||
t.is (convertDuration ("weekdays"), 1, "duration weekdays = 1");
|
||||
t.is (convertDuration ("day"), 1, "duration day = 1");
|
||||
t.is (convertDuration ("0d"), 0, "duration 0d = 0");
|
||||
t.is (convertDuration ("1d"), 1, "duration 1d = 1");
|
||||
t.is (convertDuration ("7d"), 7, "duration 7d = 7");
|
||||
t.is (convertDuration ("10d"), 10, "duration 10d = 10");
|
||||
t.is (convertDuration ("100d"), 100, "duration 100d = 100");
|
||||
// Iterate for a whole year. Why? Just to see where the boundaries are,
|
||||
// so that changes can be made with some reference point.
|
||||
d = Duration ( 1*86400), t.is (d.formatCompact (), "1d", "1*86400 -> 1d");
|
||||
d = Duration ( 2*86400), t.is (d.formatCompact (), "2d", "2*86400 -> 2d");
|
||||
d = Duration ( 3*86400), t.is (d.formatCompact (), "3d", "3*86400 -> 3d");
|
||||
d = Duration ( 4*86400), t.is (d.formatCompact (), "4d", "4*86400 -> 4d");
|
||||
d = Duration ( 5*86400), t.is (d.formatCompact (), "5d", "5*86400 -> 5d");
|
||||
d = Duration ( 6*86400), t.is (d.formatCompact (), "6d", "6*86400 -> 6d");
|
||||
d = Duration ( 7*86400), t.is (d.formatCompact (), "7d", "7*86400 -> 7d");
|
||||
d = Duration ( 8*86400), t.is (d.formatCompact (), "8d", "8*86400 -> 8d");
|
||||
d = Duration ( 9*86400), t.is (d.formatCompact (), "9d", "9*86400 -> 9d");
|
||||
d = Duration ( 10*86400), t.is (d.formatCompact (), "10d", "10*86400 -> 10d");
|
||||
|
||||
t.is (convertDuration ("weekly"), 7, "duration weekly = 7");
|
||||
t.is (convertDuration ("sennight"), 7, "duration sennight = 7");
|
||||
t.is (convertDuration ("biweekly"), 14, "duration biweekly = 14");
|
||||
t.is (convertDuration ("fortnight"), 14, "duration fortnight = 14");
|
||||
t.is (convertDuration ("0w"), 0, "duration 0w = 0");
|
||||
t.is (convertDuration ("1w"), 7, "duration 1w = 7");
|
||||
t.is (convertDuration ("7w"), 49, "duration 7w = 49");
|
||||
t.is (convertDuration ("10w"), 70, "duration 10w = 70");
|
||||
t.is (convertDuration ("100w"), 700, "duration 100w = 700");
|
||||
d = Duration ( 11*86400), t.is (d.formatCompact (), "11d", "11*86400 -> 11d");
|
||||
d = Duration ( 12*86400), t.is (d.formatCompact (), "12d", "12*86400 -> 12d");
|
||||
d = Duration ( 13*86400), t.is (d.formatCompact (), "1wk", "13*86400 -> 1wk");
|
||||
d = Duration ( 14*86400), t.is (d.formatCompact (), "2wk", "14*86400 -> 2wk");
|
||||
d = Duration ( 15*86400), t.is (d.formatCompact (), "2wk", "15*86400 -> 2wk");
|
||||
d = Duration ( 16*86400), t.is (d.formatCompact (), "2wk", "16*86400 -> 2wk");
|
||||
d = Duration ( 17*86400), t.is (d.formatCompact (), "2wk", "17*86400 -> 2wk");
|
||||
d = Duration ( 18*86400), t.is (d.formatCompact (), "2wk", "18*86400 -> 2wk");
|
||||
d = Duration ( 19*86400), t.is (d.formatCompact (), "2wk", "19*86400 -> 2wk");
|
||||
d = Duration ( 20*86400), t.is (d.formatCompact (), "2wk", "20*86400 -> 2wk");
|
||||
|
||||
d = Duration ( 21*86400), t.is (d.formatCompact (), "3wk", "21*86400 -> 3wk");
|
||||
d = Duration ( 22*86400), t.is (d.formatCompact (), "3wk", "22*86400 -> 3wk");
|
||||
d = Duration ( 23*86400), t.is (d.formatCompact (), "3wk", "23*86400 -> 3wk");
|
||||
d = Duration ( 24*86400), t.is (d.formatCompact (), "3wk", "24*86400 -> 3wk");
|
||||
d = Duration ( 25*86400), t.is (d.formatCompact (), "3wk", "25*86400 -> 3wk");
|
||||
d = Duration ( 26*86400), t.is (d.formatCompact (), "3wk", "26*86400 -> 3wk");
|
||||
d = Duration ( 27*86400), t.is (d.formatCompact (), "3wk", "27*86400 -> 3wk");
|
||||
d = Duration ( 28*86400), t.is (d.formatCompact (), "4wk", "28*86400 -> 4wk");
|
||||
d = Duration ( 29*86400), t.is (d.formatCompact (), "4wk", "29*86400 -> 4wk");
|
||||
d = Duration ( 30*86400), t.is (d.formatCompact (), "4wk", "30*86400 -> 4wk");
|
||||
|
||||
d = Duration ( 31*86400), t.is (d.formatCompact (), "4wk", "31*86400 -> 4wk");
|
||||
d = Duration ( 32*86400), t.is (d.formatCompact (), "4wk", "32*86400 -> 4wk");
|
||||
d = Duration ( 33*86400), t.is (d.formatCompact (), "4wk", "33*86400 -> 4wk");
|
||||
d = Duration ( 34*86400), t.is (d.formatCompact (), "4wk", "34*86400 -> 4wk");
|
||||
d = Duration ( 35*86400), t.is (d.formatCompact (), "5wk", "35*86400 -> 5wk");
|
||||
d = Duration ( 36*86400), t.is (d.formatCompact (), "5wk", "36*86400 -> 5wk");
|
||||
d = Duration ( 37*86400), t.is (d.formatCompact (), "5wk", "37*86400 -> 5wk");
|
||||
d = Duration ( 38*86400), t.is (d.formatCompact (), "5wk", "38*86400 -> 5wk");
|
||||
d = Duration ( 39*86400), t.is (d.formatCompact (), "5wk", "39*86400 -> 5wk");
|
||||
d = Duration ( 40*86400), t.is (d.formatCompact (), "5wk", "40*86400 -> 5wk");
|
||||
|
||||
d = Duration ( 41*86400), t.is (d.formatCompact (), "5wk", "41*86400 -> 5wk");
|
||||
d = Duration ( 42*86400), t.is (d.formatCompact (), "6wk", "42*86400 -> 6wk");
|
||||
d = Duration ( 43*86400), t.is (d.formatCompact (), "6wk", "43*86400 -> 6wk");
|
||||
d = Duration ( 44*86400), t.is (d.formatCompact (), "6wk", "44*86400 -> 6wk");
|
||||
d = Duration ( 45*86400), t.is (d.formatCompact (), "6wk", "45*86400 -> 6wk");
|
||||
d = Duration ( 46*86400), t.is (d.formatCompact (), "6wk", "46*86400 -> 6wk");
|
||||
d = Duration ( 47*86400), t.is (d.formatCompact (), "6wk", "47*86400 -> 6wk");
|
||||
d = Duration ( 48*86400), t.is (d.formatCompact (), "6wk", "48*86400 -> 6wk");
|
||||
d = Duration ( 49*86400), t.is (d.formatCompact (), "7wk", "49*86400 -> 7wk");
|
||||
d = Duration ( 50*86400), t.is (d.formatCompact (), "7wk", "50*86400 -> 7wk");
|
||||
|
||||
d = Duration ( 51*86400), t.is (d.formatCompact (), "7wk", "51*86400 -> 7wk");
|
||||
d = Duration ( 52*86400), t.is (d.formatCompact (), "7wk", "52*86400 -> 7wk");
|
||||
d = Duration ( 53*86400), t.is (d.formatCompact (), "7wk", "53*86400 -> 7wk");
|
||||
d = Duration ( 54*86400), t.is (d.formatCompact (), "7wk", "54*86400 -> 7wk");
|
||||
d = Duration ( 55*86400), t.is (d.formatCompact (), "7wk", "55*86400 -> 7wk");
|
||||
d = Duration ( 56*86400), t.is (d.formatCompact (), "8wk", "56*86400 -> 8wk");
|
||||
d = Duration ( 57*86400), t.is (d.formatCompact (), "8wk", "57*86400 -> 8wk");
|
||||
d = Duration ( 58*86400), t.is (d.formatCompact (), "8wk", "58*86400 -> 8wk");
|
||||
d = Duration ( 59*86400), t.is (d.formatCompact (), "8wk", "59*86400 -> 8wk");
|
||||
d = Duration ( 60*86400), t.is (d.formatCompact (), "8wk", "60*86400 -> 8wk");
|
||||
|
||||
d = Duration ( 61*86400), t.is (d.formatCompact (), "8wk", "61*86400 -> 8wk");
|
||||
d = Duration ( 62*86400), t.is (d.formatCompact (), "8wk", "62*86400 -> 8wk");
|
||||
d = Duration ( 63*86400), t.is (d.formatCompact (), "9wk", "63*86400 -> 9wk");
|
||||
d = Duration ( 64*86400), t.is (d.formatCompact (), "9wk", "64*86400 -> 9wk");
|
||||
d = Duration ( 65*86400), t.is (d.formatCompact (), "9wk", "65*86400 -> 9wk");
|
||||
d = Duration ( 66*86400), t.is (d.formatCompact (), "9wk", "66*86400 -> 9wk");
|
||||
d = Duration ( 67*86400), t.is (d.formatCompact (), "9wk", "67*86400 -> 9wk");
|
||||
d = Duration ( 68*86400), t.is (d.formatCompact (), "9wk", "68*86400 -> 9wk");
|
||||
d = Duration ( 69*86400), t.is (d.formatCompact (), "9wk", "69*86400 -> 9wk");
|
||||
d = Duration ( 70*86400), t.is (d.formatCompact (), "10wk", "70*86400 -> 10wk");
|
||||
|
||||
d = Duration ( 71*86400), t.is (d.formatCompact (), "10wk", "71*86400 -> 10wk");
|
||||
d = Duration ( 72*86400), t.is (d.formatCompact (), "10wk", "72*86400 -> 10wk");
|
||||
d = Duration ( 73*86400), t.is (d.formatCompact (), "10wk", "73*86400 -> 10wk");
|
||||
d = Duration ( 74*86400), t.is (d.formatCompact (), "10wk", "74*86400 -> 10wk");
|
||||
d = Duration ( 75*86400), t.is (d.formatCompact (), "10wk", "75*86400 -> 10wk");
|
||||
d = Duration ( 76*86400), t.is (d.formatCompact (), "10wk", "76*86400 -> 10wk");
|
||||
d = Duration ( 77*86400), t.is (d.formatCompact (), "11wk", "77*86400 -> 11wk");
|
||||
d = Duration ( 78*86400), t.is (d.formatCompact (), "11wk", "78*86400 -> 11wk");
|
||||
d = Duration ( 79*86400), t.is (d.formatCompact (), "11wk", "79*86400 -> 11wk");
|
||||
d = Duration ( 80*86400), t.is (d.formatCompact (), "11wk", "80*86400 -> 11wk");
|
||||
|
||||
d = Duration ( 81*86400), t.is (d.formatCompact (), "11wk", "81*86400 -> 11wk");
|
||||
d = Duration ( 82*86400), t.is (d.formatCompact (), "11wk", "82*86400 -> 11wk");
|
||||
d = Duration ( 83*86400), t.is (d.formatCompact (), "11wk", "83*86400 -> 11wk");
|
||||
d = Duration ( 84*86400), t.is (d.formatCompact (), "2mo", "84*86400 -> 2mo");
|
||||
d = Duration ( 85*86400), t.is (d.formatCompact (), "2mo", "85*86400 -> 2mo");
|
||||
d = Duration ( 86*86400), t.is (d.formatCompact (), "2mo", "86*86400 -> 2mo");
|
||||
d = Duration ( 87*86400), t.is (d.formatCompact (), "2mo", "87*86400 -> 2mo");
|
||||
d = Duration ( 88*86400), t.is (d.formatCompact (), "2mo", "88*86400 -> 2mo");
|
||||
d = Duration ( 89*86400), t.is (d.formatCompact (), "2mo", "89*86400 -> 2mo");
|
||||
d = Duration ( 90*86400), t.is (d.formatCompact (), "2mo", "90*86400 -> 2mo");
|
||||
|
||||
d = Duration ( 91*86400), t.is (d.formatCompact (), "2mo", "91*86400 -> 2mo");
|
||||
d = Duration ( 92*86400), t.is (d.formatCompact (), "3mo", "92*86400 -> 3mo");
|
||||
d = Duration ( 93*86400), t.is (d.formatCompact (), "3mo", "93*86400 -> 3mo");
|
||||
d = Duration ( 94*86400), t.is (d.formatCompact (), "3mo", "94*86400 -> 3mo");
|
||||
d = Duration ( 95*86400), t.is (d.formatCompact (), "3mo", "95*86400 -> 3mo");
|
||||
d = Duration ( 96*86400), t.is (d.formatCompact (), "3mo", "96*86400 -> 3mo");
|
||||
d = Duration ( 97*86400), t.is (d.formatCompact (), "3mo", "97*86400 -> 3mo");
|
||||
d = Duration ( 98*86400), t.is (d.formatCompact (), "3mo", "98*86400 -> 3mo");
|
||||
d = Duration ( 99*86400), t.is (d.formatCompact (), "3mo", "99*86400 -> 3mo");
|
||||
d = Duration (100*86400), t.is (d.formatCompact (), "3mo", "100*86400 -> 3mo");
|
||||
|
||||
d = Duration (101*86400), t.is (d.formatCompact (), "3mo", "101*86400 -> 3mo");
|
||||
d = Duration (102*86400), t.is (d.formatCompact (), "3mo", "102*86400 -> 3mo");
|
||||
d = Duration (103*86400), t.is (d.formatCompact (), "3mo", "103*86400 -> 3mo");
|
||||
d = Duration (104*86400), t.is (d.formatCompact (), "3mo", "104*86400 -> 3mo");
|
||||
d = Duration (105*86400), t.is (d.formatCompact (), "3mo", "105*86400 -> 3mo");
|
||||
d = Duration (106*86400), t.is (d.formatCompact (), "3mo", "106*86400 -> 3mo");
|
||||
d = Duration (107*86400), t.is (d.formatCompact (), "3mo", "107*86400 -> 3mo");
|
||||
d = Duration (108*86400), t.is (d.formatCompact (), "3mo", "108*86400 -> 3mo");
|
||||
d = Duration (109*86400), t.is (d.formatCompact (), "3mo", "109*86400 -> 3mo");
|
||||
d = Duration (110*86400), t.is (d.formatCompact (), "3mo", "110*86400 -> 3mo");
|
||||
|
||||
d = Duration (111*86400), t.is (d.formatCompact (), "3mo", "111*86400 -> 3mo");
|
||||
d = Duration (112*86400), t.is (d.formatCompact (), "3mo", "112*86400 -> 3mo");
|
||||
d = Duration (113*86400), t.is (d.formatCompact (), "3mo", "113*86400 -> 3mo");
|
||||
d = Duration (114*86400), t.is (d.formatCompact (), "3mo", "114*86400 -> 3mo");
|
||||
d = Duration (115*86400), t.is (d.formatCompact (), "3mo", "115*86400 -> 3mo");
|
||||
d = Duration (116*86400), t.is (d.formatCompact (), "3mo", "116*86400 -> 3mo");
|
||||
d = Duration (117*86400), t.is (d.formatCompact (), "3mo", "117*86400 -> 3mo");
|
||||
d = Duration (118*86400), t.is (d.formatCompact (), "3mo", "118*86400 -> 3mo");
|
||||
d = Duration (119*86400), t.is (d.formatCompact (), "3mo", "119*86400 -> 3mo");
|
||||
d = Duration (120*86400), t.is (d.formatCompact (), "3mo", "120*86400 -> 3mo");
|
||||
|
||||
d = Duration (121*86400), t.is (d.formatCompact (), "3mo", "121*86400 -> 3mo");
|
||||
d = Duration (122*86400), t.is (d.formatCompact (), "3mo", "122*86400 -> 3mo");
|
||||
d = Duration (123*86400), t.is (d.formatCompact (), "4mo", "123*86400 -> 4mo");
|
||||
d = Duration (124*86400), t.is (d.formatCompact (), "4mo", "124*86400 -> 4mo");
|
||||
d = Duration (125*86400), t.is (d.formatCompact (), "4mo", "125*86400 -> 4mo");
|
||||
d = Duration (126*86400), t.is (d.formatCompact (), "4mo", "126*86400 -> 4mo");
|
||||
d = Duration (127*86400), t.is (d.formatCompact (), "4mo", "127*86400 -> 4mo");
|
||||
d = Duration (128*86400), t.is (d.formatCompact (), "4mo", "128*86400 -> 4mo");
|
||||
d = Duration (129*86400), t.is (d.formatCompact (), "4mo", "129*86400 -> 4mo");
|
||||
d = Duration (130*86400), t.is (d.formatCompact (), "4mo", "130*86400 -> 4mo");
|
||||
|
||||
d = Duration (131*86400), t.is (d.formatCompact (), "4mo", "131*86400 -> 4mo");
|
||||
d = Duration (132*86400), t.is (d.formatCompact (), "4mo", "132*86400 -> 4mo");
|
||||
d = Duration (133*86400), t.is (d.formatCompact (), "4mo", "133*86400 -> 4mo");
|
||||
d = Duration (134*86400), t.is (d.formatCompact (), "4mo", "134*86400 -> 4mo");
|
||||
d = Duration (135*86400), t.is (d.formatCompact (), "4mo", "135*86400 -> 4mo");
|
||||
d = Duration (136*86400), t.is (d.formatCompact (), "4mo", "136*86400 -> 4mo");
|
||||
d = Duration (137*86400), t.is (d.formatCompact (), "4mo", "137*86400 -> 4mo");
|
||||
d = Duration (138*86400), t.is (d.formatCompact (), "4mo", "138*86400 -> 4mo");
|
||||
d = Duration (139*86400), t.is (d.formatCompact (), "4mo", "139*86400 -> 4mo");
|
||||
d = Duration (140*86400), t.is (d.formatCompact (), "4mo", "140*86400 -> 4mo");
|
||||
|
||||
d = Duration (141*86400), t.is (d.formatCompact (), "4mo", "141*86400 -> 4mo");
|
||||
d = Duration (142*86400), t.is (d.formatCompact (), "4mo", "142*86400 -> 4mo");
|
||||
d = Duration (143*86400), t.is (d.formatCompact (), "4mo", "143*86400 -> 4mo");
|
||||
d = Duration (144*86400), t.is (d.formatCompact (), "4mo", "144*86400 -> 4mo");
|
||||
d = Duration (145*86400), t.is (d.formatCompact (), "4mo", "145*86400 -> 4mo");
|
||||
d = Duration (146*86400), t.is (d.formatCompact (), "4mo", "146*86400 -> 4mo");
|
||||
d = Duration (147*86400), t.is (d.formatCompact (), "4mo", "147*86400 -> 4mo");
|
||||
d = Duration (148*86400), t.is (d.formatCompact (), "4mo", "148*86400 -> 4mo");
|
||||
d = Duration (149*86400), t.is (d.formatCompact (), "4mo", "149*86400 -> 4mo");
|
||||
d = Duration (150*86400), t.is (d.formatCompact (), "4mo", "150*86400 -> 4mo");
|
||||
|
||||
d = Duration (151*86400), t.is (d.formatCompact (), "4mo", "151*86400 -> 4mo");
|
||||
d = Duration (152*86400), t.is (d.formatCompact (), "4mo", "152*86400 -> 4mo");
|
||||
d = Duration (153*86400), t.is (d.formatCompact (), "5mo", "153*86400 -> 5mo");
|
||||
d = Duration (154*86400), t.is (d.formatCompact (), "5mo", "154*86400 -> 5mo");
|
||||
d = Duration (155*86400), t.is (d.formatCompact (), "5mo", "155*86400 -> 5mo");
|
||||
d = Duration (156*86400), t.is (d.formatCompact (), "5mo", "156*86400 -> 5mo");
|
||||
d = Duration (157*86400), t.is (d.formatCompact (), "5mo", "157*86400 -> 5mo");
|
||||
d = Duration (158*86400), t.is (d.formatCompact (), "5mo", "158*86400 -> 5mo");
|
||||
d = Duration (159*86400), t.is (d.formatCompact (), "5mo", "159*86400 -> 5mo");
|
||||
d = Duration (160*86400), t.is (d.formatCompact (), "5mo", "160*86400 -> 5mo");
|
||||
|
||||
d = Duration (161*86400), t.is (d.formatCompact (), "5mo", "161*86400 -> 5mo");
|
||||
d = Duration (162*86400), t.is (d.formatCompact (), "5mo", "162*86400 -> 5mo");
|
||||
d = Duration (163*86400), t.is (d.formatCompact (), "5mo", "163*86400 -> 5mo");
|
||||
d = Duration (164*86400), t.is (d.formatCompact (), "5mo", "164*86400 -> 5mo");
|
||||
d = Duration (165*86400), t.is (d.formatCompact (), "5mo", "165*86400 -> 5mo");
|
||||
d = Duration (166*86400), t.is (d.formatCompact (), "5mo", "166*86400 -> 5mo");
|
||||
d = Duration (167*86400), t.is (d.formatCompact (), "5mo", "167*86400 -> 5mo");
|
||||
d = Duration (168*86400), t.is (d.formatCompact (), "5mo", "168*86400 -> 5mo");
|
||||
d = Duration (169*86400), t.is (d.formatCompact (), "5mo", "169*86400 -> 5mo");
|
||||
d = Duration (170*86400), t.is (d.formatCompact (), "5mo", "170*86400 -> 5mo");
|
||||
|
||||
d = Duration (171*86400), t.is (d.formatCompact (), "5mo", "171*86400 -> 5mo");
|
||||
d = Duration (172*86400), t.is (d.formatCompact (), "5mo", "172*86400 -> 5mo");
|
||||
d = Duration (173*86400), t.is (d.formatCompact (), "5mo", "173*86400 -> 5mo");
|
||||
d = Duration (174*86400), t.is (d.formatCompact (), "5mo", "174*86400 -> 5mo");
|
||||
d = Duration (175*86400), t.is (d.formatCompact (), "5mo", "175*86400 -> 5mo");
|
||||
d = Duration (176*86400), t.is (d.formatCompact (), "5mo", "176*86400 -> 5mo");
|
||||
d = Duration (177*86400), t.is (d.formatCompact (), "5mo", "177*86400 -> 5mo");
|
||||
d = Duration (178*86400), t.is (d.formatCompact (), "5mo", "178*86400 -> 5mo");
|
||||
d = Duration (179*86400), t.is (d.formatCompact (), "5mo", "179*86400 -> 5mo");
|
||||
d = Duration (180*86400), t.is (d.formatCompact (), "5mo", "180*86400 -> 5mo");
|
||||
|
||||
d = Duration (181*86400), t.is (d.formatCompact (), "5mo", "181*86400 -> 5mo");
|
||||
d = Duration (182*86400), t.is (d.formatCompact (), "5mo", "182*86400 -> 5mo");
|
||||
d = Duration (183*86400), t.is (d.formatCompact (), "5mo", "183*86400 -> 5mo");
|
||||
d = Duration (184*86400), t.is (d.formatCompact (), "6mo", "184*86400 -> 6mo");
|
||||
d = Duration (185*86400), t.is (d.formatCompact (), "6mo", "185*86400 -> 6mo");
|
||||
d = Duration (186*86400), t.is (d.formatCompact (), "6mo", "186*86400 -> 6mo");
|
||||
d = Duration (187*86400), t.is (d.formatCompact (), "6mo", "187*86400 -> 6mo");
|
||||
d = Duration (188*86400), t.is (d.formatCompact (), "6mo", "188*86400 -> 6mo");
|
||||
d = Duration (189*86400), t.is (d.formatCompact (), "6mo", "189*86400 -> 6mo");
|
||||
d = Duration (190*86400), t.is (d.formatCompact (), "6mo", "190*86400 -> 6mo");
|
||||
|
||||
d = Duration (191*86400), t.is (d.formatCompact (), "6mo", "191*86400 -> 6mo");
|
||||
d = Duration (192*86400), t.is (d.formatCompact (), "6mo", "192*86400 -> 6mo");
|
||||
d = Duration (193*86400), t.is (d.formatCompact (), "6mo", "193*86400 -> 6mo");
|
||||
d = Duration (194*86400), t.is (d.formatCompact (), "6mo", "194*86400 -> 6mo");
|
||||
d = Duration (195*86400), t.is (d.formatCompact (), "6mo", "195*86400 -> 6mo");
|
||||
d = Duration (196*86400), t.is (d.formatCompact (), "6mo", "196*86400 -> 6mo");
|
||||
d = Duration (197*86400), t.is (d.formatCompact (), "6mo", "197*86400 -> 6mo");
|
||||
d = Duration (198*86400), t.is (d.formatCompact (), "6mo", "198*86400 -> 6mo");
|
||||
d = Duration (199*86400), t.is (d.formatCompact (), "6mo", "199*86400 -> 6mo");
|
||||
d = Duration (200*86400), t.is (d.formatCompact (), "6mo", "200*86400 -> 6mo");
|
||||
|
||||
d = Duration (201*86400), t.is (d.formatCompact (), "6mo", "201*86400 -> 6mo");
|
||||
d = Duration (202*86400), t.is (d.formatCompact (), "6mo", "202*86400 -> 6mo");
|
||||
d = Duration (203*86400), t.is (d.formatCompact (), "6mo", "203*86400 -> 6mo");
|
||||
d = Duration (204*86400), t.is (d.formatCompact (), "6mo", "204*86400 -> 6mo");
|
||||
d = Duration (205*86400), t.is (d.formatCompact (), "6mo", "205*86400 -> 6mo");
|
||||
d = Duration (206*86400), t.is (d.formatCompact (), "6mo", "206*86400 -> 6mo");
|
||||
d = Duration (207*86400), t.is (d.formatCompact (), "6mo", "207*86400 -> 6mo");
|
||||
d = Duration (208*86400), t.is (d.formatCompact (), "6mo", "208*86400 -> 6mo");
|
||||
d = Duration (209*86400), t.is (d.formatCompact (), "6mo", "209*86400 -> 6mo");
|
||||
d = Duration (210*86400), t.is (d.formatCompact (), "6mo", "210*86400 -> 6mo");
|
||||
|
||||
d = Duration (211*86400), t.is (d.formatCompact (), "6mo", "211*86400 -> 6mo");
|
||||
d = Duration (212*86400), t.is (d.formatCompact (), "6mo", "212*86400 -> 6mo");
|
||||
d = Duration (213*86400), t.is (d.formatCompact (), "6mo", "213*86400 -> 6mo");
|
||||
d = Duration (214*86400), t.is (d.formatCompact (), "6mo", "214*86400 -> 6mo");
|
||||
d = Duration (215*86400), t.is (d.formatCompact (), "7mo", "215*86400 -> 7mo");
|
||||
d = Duration (216*86400), t.is (d.formatCompact (), "7mo", "216*86400 -> 7mo");
|
||||
d = Duration (217*86400), t.is (d.formatCompact (), "7mo", "217*86400 -> 7mo");
|
||||
d = Duration (218*86400), t.is (d.formatCompact (), "7mo", "218*86400 -> 7mo");
|
||||
d = Duration (219*86400), t.is (d.formatCompact (), "7mo", "219*86400 -> 7mo");
|
||||
d = Duration (220*86400), t.is (d.formatCompact (), "7mo", "220*86400 -> 7mo");
|
||||
|
||||
d = Duration (221*86400), t.is (d.formatCompact (), "7mo", "221*86400 -> 7mo");
|
||||
d = Duration (222*86400), t.is (d.formatCompact (), "7mo", "222*86400 -> 7mo");
|
||||
d = Duration (223*86400), t.is (d.formatCompact (), "7mo", "223*86400 -> 7mo");
|
||||
d = Duration (224*86400), t.is (d.formatCompact (), "7mo", "224*86400 -> 7mo");
|
||||
d = Duration (225*86400), t.is (d.formatCompact (), "7mo", "225*86400 -> 7mo");
|
||||
d = Duration (226*86400), t.is (d.formatCompact (), "7mo", "226*86400 -> 7mo");
|
||||
d = Duration (227*86400), t.is (d.formatCompact (), "7mo", "227*86400 -> 7mo");
|
||||
d = Duration (228*86400), t.is (d.formatCompact (), "7mo", "228*86400 -> 7mo");
|
||||
d = Duration (229*86400), t.is (d.formatCompact (), "7mo", "229*86400 -> 7mo");
|
||||
d = Duration (230*86400), t.is (d.formatCompact (), "7mo", "230*86400 -> 7mo");
|
||||
|
||||
d = Duration (231*86400), t.is (d.formatCompact (), "7mo", "231*86400 -> 7mo");
|
||||
d = Duration (232*86400), t.is (d.formatCompact (), "7mo", "232*86400 -> 7mo");
|
||||
d = Duration (233*86400), t.is (d.formatCompact (), "7mo", "233*86400 -> 7mo");
|
||||
d = Duration (234*86400), t.is (d.formatCompact (), "7mo", "234*86400 -> 7mo");
|
||||
d = Duration (235*86400), t.is (d.formatCompact (), "7mo", "235*86400 -> 7mo");
|
||||
d = Duration (236*86400), t.is (d.formatCompact (), "7mo", "236*86400 -> 7mo");
|
||||
d = Duration (237*86400), t.is (d.formatCompact (), "7mo", "237*86400 -> 7mo");
|
||||
d = Duration (238*86400), t.is (d.formatCompact (), "7mo", "238*86400 -> 7mo");
|
||||
d = Duration (239*86400), t.is (d.formatCompact (), "7mo", "239*86400 -> 7mo");
|
||||
d = Duration (240*86400), t.is (d.formatCompact (), "7mo", "240*86400 -> 7mo");
|
||||
|
||||
d = Duration (241*86400), t.is (d.formatCompact (), "7mo", "241*86400 -> 7mo");
|
||||
d = Duration (242*86400), t.is (d.formatCompact (), "7mo", "242*86400 -> 7mo");
|
||||
d = Duration (243*86400), t.is (d.formatCompact (), "7mo", "243*86400 -> 7mo");
|
||||
d = Duration (244*86400), t.is (d.formatCompact (), "7mo", "244*86400 -> 7mo");
|
||||
d = Duration (245*86400), t.is (d.formatCompact (), "8mo", "245*86400 -> 8mo");
|
||||
d = Duration (246*86400), t.is (d.formatCompact (), "8mo", "246*86400 -> 8mo");
|
||||
d = Duration (247*86400), t.is (d.formatCompact (), "8mo", "247*86400 -> 8mo");
|
||||
d = Duration (248*86400), t.is (d.formatCompact (), "8mo", "248*86400 -> 8mo");
|
||||
d = Duration (249*86400), t.is (d.formatCompact (), "8mo", "249*86400 -> 8mo");
|
||||
d = Duration (250*86400), t.is (d.formatCompact (), "8mo", "250*86400 -> 8mo");
|
||||
|
||||
d = Duration (251*86400), t.is (d.formatCompact (), "8mo", "251*86400 -> 8mo");
|
||||
d = Duration (252*86400), t.is (d.formatCompact (), "8mo", "252*86400 -> 8mo");
|
||||
d = Duration (253*86400), t.is (d.formatCompact (), "8mo", "253*86400 -> 8mo");
|
||||
d = Duration (254*86400), t.is (d.formatCompact (), "8mo", "254*86400 -> 8mo");
|
||||
d = Duration (255*86400), t.is (d.formatCompact (), "8mo", "255*86400 -> 8mo");
|
||||
d = Duration (256*86400), t.is (d.formatCompact (), "8mo", "256*86400 -> 8mo");
|
||||
d = Duration (257*86400), t.is (d.formatCompact (), "8mo", "257*86400 -> 8mo");
|
||||
d = Duration (258*86400), t.is (d.formatCompact (), "8mo", "258*86400 -> 8mo");
|
||||
d = Duration (259*86400), t.is (d.formatCompact (), "8mo", "259*86400 -> 8mo");
|
||||
d = Duration (260*86400), t.is (d.formatCompact (), "8mo", "260*86400 -> 8mo");
|
||||
|
||||
d = Duration (261*86400), t.is (d.formatCompact (), "8mo", "261*86400 -> 8mo");
|
||||
d = Duration (262*86400), t.is (d.formatCompact (), "8mo", "262*86400 -> 8mo");
|
||||
d = Duration (263*86400), t.is (d.formatCompact (), "8mo", "263*86400 -> 8mo");
|
||||
d = Duration (264*86400), t.is (d.formatCompact (), "8mo", "264*86400 -> 8mo");
|
||||
d = Duration (265*86400), t.is (d.formatCompact (), "8mo", "265*86400 -> 8mo");
|
||||
d = Duration (266*86400), t.is (d.formatCompact (), "8mo", "266*86400 -> 8mo");
|
||||
d = Duration (267*86400), t.is (d.formatCompact (), "8mo", "267*86400 -> 8mo");
|
||||
d = Duration (268*86400), t.is (d.formatCompact (), "8mo", "268*86400 -> 8mo");
|
||||
d = Duration (269*86400), t.is (d.formatCompact (), "8mo", "269*86400 -> 8mo");
|
||||
d = Duration (270*86400), t.is (d.formatCompact (), "8mo", "270*86400 -> 8mo");
|
||||
|
||||
d = Duration (271*86400), t.is (d.formatCompact (), "8mo", "271*86400 -> 8mo");
|
||||
d = Duration (272*86400), t.is (d.formatCompact (), "8mo", "272*86400 -> 8mo");
|
||||
d = Duration (273*86400), t.is (d.formatCompact (), "8mo", "273*86400 -> 8mo");
|
||||
d = Duration (274*86400), t.is (d.formatCompact (), "8mo", "274*86400 -> 8mo");
|
||||
d = Duration (275*86400), t.is (d.formatCompact (), "8mo", "275*86400 -> 8mo");
|
||||
d = Duration (276*86400), t.is (d.formatCompact (), "9mo", "276*86400 -> 9mo");
|
||||
d = Duration (277*86400), t.is (d.formatCompact (), "9mo", "277*86400 -> 9mo");
|
||||
d = Duration (278*86400), t.is (d.formatCompact (), "9mo", "278*86400 -> 9mo");
|
||||
d = Duration (279*86400), t.is (d.formatCompact (), "9mo", "279*86400 -> 9mo");
|
||||
d = Duration (280*86400), t.is (d.formatCompact (), "9mo", "280*86400 -> 9mo");
|
||||
|
||||
d = Duration (281*86400), t.is (d.formatCompact (), "9mo", "281*86400 -> 9mo");
|
||||
d = Duration (282*86400), t.is (d.formatCompact (), "9mo", "282*86400 -> 9mo");
|
||||
d = Duration (283*86400), t.is (d.formatCompact (), "9mo", "283*86400 -> 9mo");
|
||||
d = Duration (284*86400), t.is (d.formatCompact (), "9mo", "284*86400 -> 9mo");
|
||||
d = Duration (285*86400), t.is (d.formatCompact (), "9mo", "285*86400 -> 9mo");
|
||||
d = Duration (286*86400), t.is (d.formatCompact (), "9mo", "286*86400 -> 9mo");
|
||||
d = Duration (287*86400), t.is (d.formatCompact (), "9mo", "287*86400 -> 9mo");
|
||||
d = Duration (288*86400), t.is (d.formatCompact (), "9mo", "288*86400 -> 9mo");
|
||||
d = Duration (289*86400), t.is (d.formatCompact (), "9mo", "289*86400 -> 9mo");
|
||||
d = Duration (290*86400), t.is (d.formatCompact (), "9mo", "290*86400 -> 9mo");
|
||||
|
||||
d = Duration (291*86400), t.is (d.formatCompact (), "9mo", "291*86400 -> 9mo");
|
||||
d = Duration (292*86400), t.is (d.formatCompact (), "9mo", "292*86400 -> 9mo");
|
||||
d = Duration (293*86400), t.is (d.formatCompact (), "9mo", "293*86400 -> 9mo");
|
||||
d = Duration (294*86400), t.is (d.formatCompact (), "9mo", "294*86400 -> 9mo");
|
||||
d = Duration (295*86400), t.is (d.formatCompact (), "9mo", "295*86400 -> 9mo");
|
||||
d = Duration (296*86400), t.is (d.formatCompact (), "9mo", "296*86400 -> 9mo");
|
||||
d = Duration (297*86400), t.is (d.formatCompact (), "9mo", "297*86400 -> 9mo");
|
||||
d = Duration (298*86400), t.is (d.formatCompact (), "9mo", "298*86400 -> 9mo");
|
||||
d = Duration (299*86400), t.is (d.formatCompact (), "9mo", "299*86400 -> 9mo");
|
||||
d = Duration (300*86400), t.is (d.formatCompact (), "9mo", "300*86400 -> 9mo");
|
||||
|
||||
d = Duration (301*86400), t.is (d.formatCompact (), "9mo", "301*86400 -> 9mo");
|
||||
d = Duration (302*86400), t.is (d.formatCompact (), "9mo", "302*86400 -> 9mo");
|
||||
d = Duration (303*86400), t.is (d.formatCompact (), "9mo", "303*86400 -> 9mo");
|
||||
d = Duration (304*86400), t.is (d.formatCompact (), "9mo", "304*86400 -> 9mo");
|
||||
d = Duration (305*86400), t.is (d.formatCompact (), "9mo", "305*86400 -> 9mo");
|
||||
d = Duration (306*86400), t.is (d.formatCompact (), "10mo", "306*86400 -> 10mo");
|
||||
d = Duration (307*86400), t.is (d.formatCompact (), "10mo", "307*86400 -> 10mo");
|
||||
d = Duration (308*86400), t.is (d.formatCompact (), "10mo", "308*86400 -> 10mo");
|
||||
d = Duration (309*86400), t.is (d.formatCompact (), "10mo", "309*86400 -> 10mo");
|
||||
d = Duration (310*86400), t.is (d.formatCompact (), "10mo", "310*86400 -> 10mo");
|
||||
|
||||
d = Duration (311*86400), t.is (d.formatCompact (), "10mo", "311*86400 -> 10mo");
|
||||
d = Duration (312*86400), t.is (d.formatCompact (), "10mo", "312*86400 -> 10mo");
|
||||
d = Duration (313*86400), t.is (d.formatCompact (), "10mo", "313*86400 -> 10mo");
|
||||
d = Duration (314*86400), t.is (d.formatCompact (), "10mo", "314*86400 -> 10mo");
|
||||
d = Duration (315*86400), t.is (d.formatCompact (), "10mo", "315*86400 -> 10mo");
|
||||
d = Duration (316*86400), t.is (d.formatCompact (), "10mo", "316*86400 -> 10mo");
|
||||
d = Duration (317*86400), t.is (d.formatCompact (), "10mo", "317*86400 -> 10mo");
|
||||
d = Duration (318*86400), t.is (d.formatCompact (), "10mo", "318*86400 -> 10mo");
|
||||
d = Duration (319*86400), t.is (d.formatCompact (), "10mo", "319*86400 -> 10mo");
|
||||
d = Duration (320*86400), t.is (d.formatCompact (), "10mo", "320*86400 -> 10mo");
|
||||
|
||||
d = Duration (321*86400), t.is (d.formatCompact (), "10mo", "321*86400 -> 10mo");
|
||||
d = Duration (322*86400), t.is (d.formatCompact (), "10mo", "322*86400 -> 10mo");
|
||||
d = Duration (323*86400), t.is (d.formatCompact (), "10mo", "323*86400 -> 10mo");
|
||||
d = Duration (324*86400), t.is (d.formatCompact (), "10mo", "324*86400 -> 10mo");
|
||||
d = Duration (325*86400), t.is (d.formatCompact (), "10mo", "325*86400 -> 10mo");
|
||||
d = Duration (326*86400), t.is (d.formatCompact (), "10mo", "326*86400 -> 10mo");
|
||||
d = Duration (327*86400), t.is (d.formatCompact (), "10mo", "327*86400 -> 10mo");
|
||||
d = Duration (328*86400), t.is (d.formatCompact (), "10mo", "328*86400 -> 10mo");
|
||||
d = Duration (329*86400), t.is (d.formatCompact (), "10mo", "329*86400 -> 10mo");
|
||||
d = Duration (330*86400), t.is (d.formatCompact (), "10mo", "330*86400 -> 10mo");
|
||||
|
||||
d = Duration (331*86400), t.is (d.formatCompact (), "10mo", "331*86400 -> 10mo");
|
||||
d = Duration (332*86400), t.is (d.formatCompact (), "10mo", "332*86400 -> 10mo");
|
||||
d = Duration (333*86400), t.is (d.formatCompact (), "10mo", "333*86400 -> 10mo");
|
||||
d = Duration (334*86400), t.is (d.formatCompact (), "10mo", "334*86400 -> 10mo");
|
||||
d = Duration (335*86400), t.is (d.formatCompact (), "10mo", "335*86400 -> 10mo");
|
||||
d = Duration (336*86400), t.is (d.formatCompact (), "10mo", "336*86400 -> 10mo");
|
||||
d = Duration (337*86400), t.is (d.formatCompact (), "11mo", "337*86400 -> 11mo");
|
||||
d = Duration (338*86400), t.is (d.formatCompact (), "11mo", "338*86400 -> 11mo");
|
||||
d = Duration (339*86400), t.is (d.formatCompact (), "11mo", "339*86400 -> 11mo");
|
||||
d = Duration (340*86400), t.is (d.formatCompact (), "11mo", "340*86400 -> 11mo");
|
||||
|
||||
d = Duration (341*86400), t.is (d.formatCompact (), "11mo", "341*86400 -> 11mo");
|
||||
d = Duration (342*86400), t.is (d.formatCompact (), "11mo", "342*86400 -> 11mo");
|
||||
d = Duration (343*86400), t.is (d.formatCompact (), "11mo", "343*86400 -> 11mo");
|
||||
d = Duration (344*86400), t.is (d.formatCompact (), "11mo", "344*86400 -> 11mo");
|
||||
d = Duration (345*86400), t.is (d.formatCompact (), "11mo", "345*86400 -> 11mo");
|
||||
d = Duration (346*86400), t.is (d.formatCompact (), "11mo", "346*86400 -> 11mo");
|
||||
d = Duration (347*86400), t.is (d.formatCompact (), "11mo", "347*86400 -> 11mo");
|
||||
d = Duration (348*86400), t.is (d.formatCompact (), "11mo", "348*86400 -> 11mo");
|
||||
d = Duration (349*86400), t.is (d.formatCompact (), "11mo", "349*86400 -> 11mo");
|
||||
d = Duration (350*86400), t.is (d.formatCompact (), "11mo", "350*86400 -> 11mo");
|
||||
|
||||
d = Duration (351*86400), t.is (d.formatCompact (), "11mo", "351*86400 -> 11mo");
|
||||
d = Duration (352*86400), t.is (d.formatCompact (), "11mo", "352*86400 -> 11mo");
|
||||
d = Duration (353*86400), t.is (d.formatCompact (), "11mo", "353*86400 -> 11mo");
|
||||
d = Duration (354*86400), t.is (d.formatCompact (), "11mo", "354*86400 -> 11mo");
|
||||
d = Duration (355*86400), t.is (d.formatCompact (), "11mo", "355*86400 -> 11mo");
|
||||
d = Duration (356*86400), t.is (d.formatCompact (), "11mo", "356*86400 -> 11mo");
|
||||
d = Duration (357*86400), t.is (d.formatCompact (), "11mo", "357*86400 -> 11mo");
|
||||
d = Duration (358*86400), t.is (d.formatCompact (), "11mo", "358*86400 -> 11mo");
|
||||
d = Duration (359*86400), t.is (d.formatCompact (), "11mo", "359*86400 -> 11mo");
|
||||
d = Duration (360*86400), t.is (d.formatCompact (), "11mo", "360*86400 -> 11mo");
|
||||
|
||||
d = Duration (361*86400), t.is (d.formatCompact (), "11mo", "361*86400 -> 11mo");
|
||||
d = Duration (362*86400), t.is (d.formatCompact (), "11mo", "362*86400 -> 11mo");
|
||||
d = Duration (363*86400), t.is (d.formatCompact (), "11mo", "363*86400 -> 11mo");
|
||||
d = Duration (364*86400), t.is (d.formatCompact (), "11mo", "364*86400 -> 11mo");
|
||||
d = Duration (365*86400), t.is (d.formatCompact (), "1.0y", "365*86400 -> 1.0y");
|
||||
|
||||
t.ok (d.valid ("daily"), "valid duration daily = 1");
|
||||
t.ok (d.valid ("day"), "valid duration day = 1");
|
||||
t.ok (d.valid ("weekly"), "valid duration weekly = 7");
|
||||
t.ok (d.valid ("weekdays"), "valid duration weekdays = 1");
|
||||
t.ok (d.valid ("sennight"), "valid duration sennight = 7");
|
||||
t.ok (d.valid ("biweekly"), "valid duration biweekly = 14");
|
||||
t.ok (d.valid ("fortnight"), "valid duration fortnight = 14");
|
||||
t.ok (d.valid ("monthly"), "valid duration monthly = 30");
|
||||
t.ok (d.valid ("bimonthly"), "valid duration bimonthly = 61");
|
||||
t.ok (d.valid ("quarterly"), "valid duration quarterly = 91");
|
||||
t.ok (d.valid ("annual"), "valid duration annual = 365");
|
||||
t.ok (d.valid ("yearly"), "valid duration yearly = 365");
|
||||
t.ok (d.valid ("semiannual"), "valid duration semiannual = 183");
|
||||
t.ok (d.valid ("biannual"), "valid duration biannual = 730");
|
||||
t.ok (d.valid ("biyearly"), "valid duration biyearly = 730");
|
||||
|
||||
t.ok (d.valid ("0 yrs"), "valid duration 0 yrs = 0");
|
||||
t.ok (d.valid ("0 yr"), "valid duration 0 yr = 0");
|
||||
t.ok (d.valid ("0y"), "valid duration 0y = 0");
|
||||
t.ok (d.valid ("1 yrs"), "valid duration 1 yrs = 365");
|
||||
t.ok (d.valid ("1 yr"), "valid duration 1 yr = 365");
|
||||
t.ok (d.valid ("1y"), "valid duration 1y = 365");
|
||||
t.ok (d.valid ("10 yrs"), "valid duration 10 yrs = 3650");
|
||||
t.ok (d.valid ("10 yr"), "valid duration 10 yr = 3650");
|
||||
t.ok (d.valid ("10y"), "valid duration 10y = 3650");
|
||||
|
||||
t.ok (d.valid ("0 qtrs"), "valid duration 0 qtrs = 0");
|
||||
t.ok (d.valid ("0 qtr"), "valid duration 0 qtr = 0");
|
||||
t.ok (d.valid ("0q"), "valid duration 0q = 0");
|
||||
t.ok (d.valid ("1 qtrs"), "valid duration 1 qtrs = 91");
|
||||
t.ok (d.valid ("1 qtr"), "valid duration 1 qtr = 91");
|
||||
t.ok (d.valid ("1q"), "valid duration 1q = 91");
|
||||
t.ok (d.valid ("10 qtrs"), "valid duration 10 qtrs = 910");
|
||||
t.ok (d.valid ("10 qtr"), "valid duration 10 qtr = 910");
|
||||
t.ok (d.valid ("10q"), "valid duration 10q = 910");
|
||||
|
||||
t.ok (d.valid ("0 mths"), "valid duration 0 mths = 0");
|
||||
t.ok (d.valid ("0 mth"), "valid duration 0 mth = 0");
|
||||
t.ok (d.valid ("0mo"), "valid duration 0mo = 0");
|
||||
t.ok (d.valid ("1 mths"), "valid duration 1 mths = 30");
|
||||
t.ok (d.valid ("1 mth"), "valid duration 1 mth = 30");
|
||||
t.ok (d.valid ("1mo"), "valid duration 1mo = 30");
|
||||
t.ok (d.valid ("10 mths"), "valid duration 10 mths = 300");
|
||||
t.ok (d.valid ("10 mth"), "valid duration 10 mth = 300");
|
||||
t.ok (d.valid ("10mo"), "valid duration 10mo = 300");
|
||||
|
||||
t.ok (d.valid ("0 wks"), "valid duration 0 wks = 0");
|
||||
t.ok (d.valid ("0 wk"), "valid duration 0 wk = 0");
|
||||
t.ok (d.valid ("0w"), "valid duration 0w = 0");
|
||||
t.ok (d.valid ("1 wks"), "valid duration 1 wks = 7");
|
||||
t.ok (d.valid ("1 wk"), "valid duration 1 wk = 7");
|
||||
t.ok (d.valid ("1w"), "valid duration 1w = 7");
|
||||
t.ok (d.valid ("10 wks"), "valid duration 10 wks = 70");
|
||||
t.ok (d.valid ("10 wk"), "valid duration 10 wk = 70");
|
||||
t.ok (d.valid ("10w"), "valid duration 10w = 70");
|
||||
|
||||
t.ok (d.valid ("0 days"), "valid duration 0 days = 0");
|
||||
t.ok (d.valid ("0 day"), "valid duration 0 day = 0");
|
||||
t.ok (d.valid ("0d"), "valid duration 0d = 0");
|
||||
t.ok (d.valid ("1 days"), "valid duration 1 days = 1");
|
||||
t.ok (d.valid ("1 day"), "valid duration 1 day = 1");
|
||||
t.ok (d.valid ("1d"), "valid duration 1d = 1");
|
||||
t.ok (d.valid ("10 days"), "valid duration 10 days = 10");
|
||||
t.ok (d.valid ("10 day"), "valid duration 10 day = 10");
|
||||
t.ok (d.valid ("10d"), "valid duration 10d = 10");
|
||||
|
||||
t.ok (d.valid ("0 hrs"), "valid duration 0 hrs = 0");
|
||||
t.ok (d.valid ("0 hr"), "valid duration 0 hr = 0");
|
||||
t.ok (d.valid ("0h"), "valid duration 0h = 0");
|
||||
t.ok (d.valid ("1 hrs"), "valid duration 1 hrs = 0");
|
||||
t.ok (d.valid ("1 hr"), "valid duration 1 hr = 0");
|
||||
t.ok (d.valid ("1h"), "valid duration 1h = 0");
|
||||
t.ok (d.valid ("10 hrs"), "valid duration 10 hrs = 0");
|
||||
t.ok (d.valid ("10 hr"), "valid duration 10 hr = 0");
|
||||
t.ok (d.valid ("10h"), "valid duration 10h = 0");
|
||||
|
||||
t.ok (d.valid ("0 mins"), "valid duration 0 mins = 0");
|
||||
t.ok (d.valid ("0 min"), "valid duration 0 min");
|
||||
t.ok (d.valid ("0m"), "valid duration 0m = 0");
|
||||
t.ok (d.valid ("1 mins"), "valid duration 1 mins = 0");
|
||||
t.ok (d.valid ("1 min"), "valid duration 1 min = 0");
|
||||
t.ok (d.valid ("1m"), "valid duration 1m = 0");
|
||||
t.ok (d.valid ("10 mins"), "valid duration 10 mins = 0");
|
||||
t.ok (d.valid ("10 min"), "valid duration 10 min = 0");
|
||||
t.ok (d.valid ("10m"), "valid duration 10m = 0");
|
||||
|
||||
t.ok (d.valid ("0 secs"), "valid duration 0 secs = 0");
|
||||
t.ok (d.valid ("0 sec"), "valid duration 0 sec = 0");
|
||||
t.ok (d.valid ("0s"), "valid duration 0s = 0");
|
||||
t.ok (d.valid ("1 secs"), "valid duration 1 secs = 0");
|
||||
t.ok (d.valid ("1 sec"), "valid duration 1 sec = 0");
|
||||
t.ok (d.valid ("1s"), "valid duration 1s = 0");
|
||||
t.ok (d.valid ("10 secs"), "valid duration 10 secs = 0");
|
||||
t.ok (d.valid ("10 sec"), "valid duration 10 sec = 0");
|
||||
t.ok (d.valid ("10s"), "valid duration 10s = 0");
|
||||
|
||||
t.notok (d.valid ("woof"), "valid duration woof = fail");
|
||||
|
||||
t.is (convertDuration ("daily"), 1, "valid duration daily = 1");
|
||||
t.is (convertDuration ("day"), 1, "valid duration day = 1");
|
||||
t.is (convertDuration ("weekly"), 7, "valid duration weekly = 7");
|
||||
t.is (convertDuration ("weekdays"), 1, "valid duration weekdays = 1");
|
||||
t.is (convertDuration ("sennight"), 7, "valid duration sennight = 7");
|
||||
t.is (convertDuration ("biweekly"), 14, "valid duration biweekly = 14");
|
||||
t.is (convertDuration ("fortnight"), 14, "valid duration fortnight = 14");
|
||||
t.is (convertDuration ("monthly"), 30, "valid duration monthly = 30");
|
||||
t.is (convertDuration ("bimonthly"), 61, "valid duration bimonthly = 61");
|
||||
t.is (convertDuration ("quarterly"), 91, "valid duration quarterly = 91");
|
||||
t.is (convertDuration ("annual"), 365, "valid duration annual = 365");
|
||||
t.is (convertDuration ("yearly"), 365, "valid duration yearly = 365");
|
||||
t.is (convertDuration ("semiannual"), 183, "valid duration semiannual = 183");
|
||||
t.is (convertDuration ("biannual"), 730, "valid duration biannual = 730");
|
||||
t.is (convertDuration ("biyearly"), 730, "valid duration biyearly = 730");
|
||||
|
||||
t.is (convertDuration ("0 yrs"), 0, "valid duration 0 yrs = 0");
|
||||
t.is (convertDuration ("0 yr"), 0, "valid duration 0 yr = 0");
|
||||
t.is (convertDuration ("0y"), 0, "valid duration 0y = 0");
|
||||
t.is (convertDuration ("1 yrs"), 365, "valid duration 1 yrs = 365");
|
||||
t.is (convertDuration ("1 yr"), 365, "valid duration 1 yr = 365");
|
||||
t.is (convertDuration ("1y"), 365, "valid duration 1y = 365");
|
||||
t.is (convertDuration ("10 yrs"), 3650, "valid duration 10 yrs = 3650");
|
||||
t.is (convertDuration ("10 yr"), 3650, "valid duration 10 yr = 3650");
|
||||
t.is (convertDuration ("10y"), 3650, "valid duration 10y = 3650");
|
||||
|
||||
t.is (convertDuration ("0 qtrs"), 0, "valid duration 0 qtrs = 0");
|
||||
t.is (convertDuration ("0 qtr"), 0, "valid duration 0 qtr = 0");
|
||||
t.is (convertDuration ("0q"), 0, "valid duration 0q = 0");
|
||||
t.is (convertDuration ("1 qtrs"), 91, "valid duration 1 qtrs = 91");
|
||||
t.is (convertDuration ("1 qtr"), 91, "valid duration 1 qtr = 91");
|
||||
t.is (convertDuration ("1q"), 91, "valid duration 1q = 91");
|
||||
t.is (convertDuration ("10 qtrs"), 910, "valid duration 10 qtrs = 910");
|
||||
t.is (convertDuration ("10 qtr"), 910, "valid duration 10 qtr = 910");
|
||||
t.is (convertDuration ("10q"), 910, "valid duration 10q = 910");
|
||||
|
||||
t.is (convertDuration ("0 mths"), 0, "valid duration 0 mths = 0");
|
||||
t.is (convertDuration ("0 mth"), 0, "valid duration 0 mth = 0");
|
||||
t.is (convertDuration ("0mo"), 0, "valid duration 0mo = 0");
|
||||
t.is (convertDuration ("1 mths"), 30, "valid duration 1 mths = 30");
|
||||
t.is (convertDuration ("1 mth"), 30, "valid duration 1 mth = 30");
|
||||
t.is (convertDuration ("1mo"), 30, "valid duration 1mo = 30");
|
||||
t.is (convertDuration ("10 mths"), 300, "valid duration 10 mths = 300");
|
||||
t.is (convertDuration ("10 mth"), 300, "valid duration 10 mth = 300");
|
||||
t.is (convertDuration ("10mo"), 300, "valid duration 10mo = 300");
|
||||
|
||||
t.is (convertDuration ("0 wks"), 0, "valid duration 0 wks = 0");
|
||||
t.is (convertDuration ("0 wk"), 0, "valid duration 0 wk = 0");
|
||||
t.is (convertDuration ("0w"), 0, "valid duration 0w = 0");
|
||||
t.is (convertDuration ("1 wks"), 7, "valid duration 1 wks = 7");
|
||||
t.is (convertDuration ("1 wk"), 7, "valid duration 1 wk = 7");
|
||||
t.is (convertDuration ("1w"), 7, "valid duration 1w = 7");
|
||||
t.is (convertDuration ("10 wks"), 70, "valid duration 10 wks = 70");
|
||||
t.is (convertDuration ("10 wk"), 70, "valid duration 10 wk = 70");
|
||||
t.is (convertDuration ("10w"), 70, "valid duration 10w = 70");
|
||||
|
||||
t.is (convertDuration ("0 days"), 0, "valid duration 0 days = 0");
|
||||
t.is (convertDuration ("0 day"), 0, "valid duration 0 day = 0");
|
||||
t.is (convertDuration ("0d"), 0, "valid duration 0d = 0");
|
||||
t.is (convertDuration ("1 days"), 1, "valid duration 1 days = 1");
|
||||
t.is (convertDuration ("1 day"), 1, "valid duration 1 day = 1");
|
||||
t.is (convertDuration ("1d"), 1, "valid duration 1d = 1");
|
||||
t.is (convertDuration ("10 days"), 10, "valid duration 10 days = 10");
|
||||
t.is (convertDuration ("10 day"), 10, "valid duration 10 day = 10");
|
||||
t.is (convertDuration ("10d"), 10, "valid duration 10d = 10");
|
||||
|
||||
try
|
||||
{
|
||||
Duration left, right;
|
||||
|
||||
// operator<
|
||||
left = Duration ("1sec"); right = Duration ("2secs"); t.ok (left < right, "duration 1sec < 2secs");
|
||||
left = Duration ("-2secs"); right = Duration ("-1sec"); t.ok (left < right, "duration -2secs < -1sec");
|
||||
left = Duration ("1sec"); right = Duration ("1min"); t.ok (left < right, "duration 1sec < 1min");
|
||||
left = Duration ("1min"); right = Duration ("1hr"); t.ok (left < right, "duration 1min < 1hr");
|
||||
left = Duration ("1hr"); right = Duration ("1d"); t.ok (left < right, "duration 1hr < 1d");
|
||||
left = Duration ("1d"); right = Duration ("1w"); t.ok (left < right, "duration 1d < 1w");
|
||||
left = Duration ("1w"); right = Duration ("1mo"); t.ok (left < right, "duration 1w < 1mo");
|
||||
left = Duration ("1mo"); right = Duration ("1q"); t.ok (left < right, "duration 1mo < 1q");
|
||||
left = Duration ("1q"); right = Duration ("1y"); t.ok (left < right, "duration 1q < 1y");
|
||||
|
||||
// operator>
|
||||
left = Duration ("2secs"); right = Duration ("1sec"); t.ok (left > right, "2sec > 1secs");
|
||||
left = Duration ("-1sec"); right = Duration ("-2secs"); t.ok (left > right, "-1secs > -2sec");
|
||||
left = Duration ("1min"); right = Duration ("1sec"); t.ok (left > right, "1min > 1sec");
|
||||
left = Duration ("1hr"); right = Duration ("1min"); t.ok (left > right, "1hr > 1min");
|
||||
left = Duration ("1d"); right = Duration ("1hr"); t.ok (left > right, "1d > 1hr");
|
||||
left = Duration ("1w"); right = Duration ("1d"); t.ok (left > right, "1w > 1d");
|
||||
left = Duration ("1mo"); right = Duration ("1w"); t.ok (left > right, "1mo > 1w");
|
||||
left = Duration ("1q"); right = Duration ("1mo"); t.ok (left > right, "1q > 1mo");
|
||||
left = Duration ("1y"); right = Duration ("1q"); t.ok (left > right, "1y > 1q");
|
||||
}
|
||||
|
||||
catch (const std::string& e) { t.diag (e); }
|
||||
catch (...) { t.diag ("Unknown error"); }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
78
src/tests/hook.api.task_debug.t
Executable file
78
src/tests/hook.api.task_debug.t
Executable file
@@ -0,0 +1,78 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2010, Paul Beckingham.
|
||||
## All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free Software
|
||||
## Foundation; either version 2 of the License, or (at your option) any later
|
||||
## version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
## details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along with
|
||||
## this program; if not, write to the
|
||||
##
|
||||
## Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor,
|
||||
## Boston, MA
|
||||
## 02110-1301
|
||||
## USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 7;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'hook.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"hooks=on\n",
|
||||
"debug=on\n",
|
||||
"hook.pre-display=" . $ENV{'PWD'} . "/hook:test\n";
|
||||
close $fh;
|
||||
ok (-r 'hook.rc', 'Created hook.rc');
|
||||
}
|
||||
|
||||
if (open my $fh, '>', 'hook')
|
||||
{
|
||||
print $fh "function test () task_debug_message ('DEBUG MESSAGE') return 0, nil end\n";
|
||||
close $fh;
|
||||
ok (-r 'hook', 'Created hook');
|
||||
}
|
||||
|
||||
my $output = qx{../task rc:hook.rc version};
|
||||
if ($output =~ /PUC-Rio/)
|
||||
{
|
||||
# Test the hook.
|
||||
qx{../task rc:hook.rc add foo};
|
||||
$output = qx{../task rc:hook.rc info 1};
|
||||
like ($output, qr/DEBUG MESSAGE/ms, 'Hook called task_debug_message');
|
||||
}
|
||||
else
|
||||
{
|
||||
pass ('Hook called task_debug_message - skip: no Lua support');
|
||||
}
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'undo.data';
|
||||
ok (!-r 'undo.data', 'Removed undo.data');
|
||||
|
||||
unlink 'hook';
|
||||
ok (!-r 'hook', 'Removed hook');
|
||||
|
||||
unlink 'hook.rc';
|
||||
ok (!-r 'hook.rc', 'Removed hook.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
77
src/tests/hook.api.task_footnote.t
Executable file
77
src/tests/hook.api.task_footnote.t
Executable file
@@ -0,0 +1,77 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2010, Paul Beckingham.
|
||||
## All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free Software
|
||||
## Foundation; either version 2 of the License, or (at your option) any later
|
||||
## version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
## details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along with
|
||||
## this program; if not, write to the
|
||||
##
|
||||
## Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor,
|
||||
## Boston, MA
|
||||
## 02110-1301
|
||||
## USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 7;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'hook.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"hooks=on\n",
|
||||
"hook.pre-display=" . $ENV{'PWD'} . "/hook:test\n";
|
||||
close $fh;
|
||||
ok (-r 'hook.rc', 'Created hook.rc');
|
||||
}
|
||||
|
||||
if (open my $fh, '>', 'hook')
|
||||
{
|
||||
print $fh "function test () task_footnote_message ('FOOTNOTE MESSAGE') return 0, nil end\n";
|
||||
close $fh;
|
||||
ok (-r 'hook', 'Created hook');
|
||||
}
|
||||
|
||||
my $output = qx{../task rc:hook.rc version};
|
||||
if ($output =~ /PUC-Rio/)
|
||||
{
|
||||
# Test the hook.
|
||||
qx{../task rc:hook.rc add foo};
|
||||
$output = qx{../task rc:hook.rc info 1};
|
||||
like ($output, qr/FOOTNOTE MESSAGE/ms, 'Hook called task_footnote_message');
|
||||
}
|
||||
else
|
||||
{
|
||||
pass ('Hook called task_footnote_message - skip: no Lua support');
|
||||
}
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'undo.data';
|
||||
ok (!-r 'undo.data', 'Removed undo.data');
|
||||
|
||||
unlink 'hook';
|
||||
ok (!-r 'hook', 'Removed hook');
|
||||
|
||||
unlink 'hook.rc';
|
||||
ok (!-r 'hook.rc', 'Removed hook.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
77
src/tests/hook.api.task_header.t
Executable file
77
src/tests/hook.api.task_header.t
Executable file
@@ -0,0 +1,77 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2010, Paul Beckingham.
|
||||
## All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free Software
|
||||
## Foundation; either version 2 of the License, or (at your option) any later
|
||||
## version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
## details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along with
|
||||
## this program; if not, write to the
|
||||
##
|
||||
## Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor,
|
||||
## Boston, MA
|
||||
## 02110-1301
|
||||
## USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 7;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'hook.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"hooks=on\n",
|
||||
"hook.pre-display=" . $ENV{'PWD'} . "/hook:test\n";
|
||||
close $fh;
|
||||
ok (-r 'hook.rc', 'Created hook.rc');
|
||||
}
|
||||
|
||||
if (open my $fh, '>', 'hook')
|
||||
{
|
||||
print $fh "function test () task_header_message ('HEADER MESSAGE') return 0, nil end\n";
|
||||
close $fh;
|
||||
ok (-r 'hook', 'Created hook');
|
||||
}
|
||||
|
||||
my $output = qx{../task rc:hook.rc version};
|
||||
if ($output =~ /PUC-Rio/)
|
||||
{
|
||||
# Test the hook.
|
||||
qx{../task rc:hook.rc add foo};
|
||||
$output = qx{../task rc:hook.rc info 1};
|
||||
like ($output, qr/HEADER MESSAGE/ms, 'Hook called task_header_message');
|
||||
}
|
||||
else
|
||||
{
|
||||
pass ('Hook called task_header_message - skip: no Lua support');
|
||||
}
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'undo.data';
|
||||
ok (!-r 'undo.data', 'Removed undo.data');
|
||||
|
||||
unlink 'hook';
|
||||
ok (!-r 'hook', 'Removed hook');
|
||||
|
||||
unlink 'hook.rc';
|
||||
ok (!-r 'hook.rc', 'Removed hook.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
68
src/tests/info.t
Executable file
68
src/tests/info.t
Executable file
@@ -0,0 +1,68 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2010, Paul Beckingham.
|
||||
## All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free Software
|
||||
## Foundation; either version 2 of the License, or (at your option) any later
|
||||
## version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
## details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along with
|
||||
## this program; if not, write to the
|
||||
##
|
||||
## Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor,
|
||||
## Boston, MA
|
||||
## 02110-1301
|
||||
## USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 10;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'info.rc')
|
||||
{
|
||||
print $fh "data.location=.\n",
|
||||
"confirmation=off\n";
|
||||
close $fh;
|
||||
ok (-r 'info.rc', 'Created info.rc');
|
||||
}
|
||||
|
||||
# Test the add command.
|
||||
qx{../task rc:info.rc add test one};
|
||||
qx{../task rc:info.rc add test two};
|
||||
qx{../task rc:info.rc add test three};
|
||||
|
||||
my $output = qx{../task rc:info.rc 1};
|
||||
like ($output, qr/Description\s+test one\n/, 'single auto-info one');
|
||||
unlike ($output, qr/Description\s+test two\n/, 'single auto-info !two');
|
||||
unlike ($output, qr/Description\s+test three\n/, 'single auto-info !three');
|
||||
|
||||
$output = qx{../task rc:info.rc 1-2};
|
||||
like ($output, qr/Description\s+test one\n/, 'single auto-info one');
|
||||
like ($output, qr/Description\s+test two\n/, 'single auto-info two');
|
||||
unlike ($output, qr/Description\s+test three\n/, 'single auto-info !three');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'undo.data';
|
||||
ok (!-r 'undo.data', 'Removed undo.data');
|
||||
|
||||
unlink 'info.rc';
|
||||
ok (!-r 'info.rc', 'Removed info.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
96
src/tests/limit.t
Executable file
96
src/tests/limit.t
Executable file
@@ -0,0 +1,96 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2010, Paul Beckingham.
|
||||
## All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free Software
|
||||
## Foundation; either version 2 of the License, or (at your option) any later
|
||||
## version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
## details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along with
|
||||
## this program; if not, write to the
|
||||
##
|
||||
## Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor,
|
||||
## Boston, MA
|
||||
## 02110-1301
|
||||
## USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 8;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'limit.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'limit.rc', 'Created limit.rc');
|
||||
}
|
||||
|
||||
# Add a large number of tasks (> 25).
|
||||
qx{../task rc:limit.rc add one};
|
||||
qx{../task rc:limit.rc add two};
|
||||
qx{../task rc:limit.rc add three};
|
||||
qx{../task rc:limit.rc add four};
|
||||
qx{../task rc:limit.rc add five};
|
||||
qx{../task rc:limit.rc add six};
|
||||
qx{../task rc:limit.rc add seven};
|
||||
qx{../task rc:limit.rc add eight};
|
||||
qx{../task rc:limit.rc add nine};
|
||||
qx{../task rc:limit.rc add ten};
|
||||
qx{../task rc:limit.rc add eleven};
|
||||
qx{../task rc:limit.rc add twelve};
|
||||
qx{../task rc:limit.rc add thirteen};
|
||||
qx{../task rc:limit.rc add fourteen};
|
||||
qx{../task rc:limit.rc add fifteen};
|
||||
qx{../task rc:limit.rc add sixteen};
|
||||
qx{../task rc:limit.rc add seventeen};
|
||||
qx{../task rc:limit.rc add eighteen};
|
||||
qx{../task rc:limit.rc add nineteen};
|
||||
qx{../task rc:limit.rc add twenty};
|
||||
qx{../task rc:limit.rc add twenty one};
|
||||
qx{../task rc:limit.rc add twenty two};
|
||||
qx{../task rc:limit.rc add twenty three};
|
||||
qx{../task rc:limit.rc add twenty four};
|
||||
qx{../task rc:limit.rc add twenty five};
|
||||
qx{../task rc:limit.rc add twenty six};
|
||||
qx{../task rc:limit.rc add twenty seven};
|
||||
qx{../task rc:limit.rc add twenty eight};
|
||||
qx{../task rc:limit.rc add twenty nine};
|
||||
qx{../task rc:limit.rc add thirty};
|
||||
|
||||
my $output = qx{../task rc:limit.rc ls};
|
||||
like ($output, qr/^30 tasks$/ms, 'unlimited');
|
||||
|
||||
$output = qx{../task rc:limit.rc ls limit:0};
|
||||
like ($output, qr/^30 tasks$/ms, 'limited to 0 - unlimited');
|
||||
|
||||
$output = qx{../task rc:limit.rc ls limit:3};
|
||||
like ($output, qr/^30 tasks, 3 shown$/ms, 'limited to 3');
|
||||
|
||||
$output = qx{../task rc:limit.rc ls limit:page};
|
||||
like ($output, qr/^30 tasks, truncated to 20 lines$/ms, 'limited to page');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'undo.data';
|
||||
ok (!-r 'undo.data', 'Removed undo.data');
|
||||
|
||||
unlink 'limit.rc';
|
||||
ok (!-r 'limit.rc', 'Removed limit.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
69
src/tests/list.all.projects.t
Executable file
69
src/tests/list.all.projects.t
Executable file
@@ -0,0 +1,69 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2010, Paul Beckingham.
|
||||
## All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free Software
|
||||
## Foundation; either version 2 of the License, or (at your option) any later
|
||||
## version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
## details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along with
|
||||
## this program; if not, write to the
|
||||
##
|
||||
## Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor,
|
||||
## Boston, MA
|
||||
## 02110-1301
|
||||
## USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 10;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'projects.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'projects.rc', 'Created projects.rc');
|
||||
}
|
||||
|
||||
# Create a data set of two tasks, with unique project names, one
|
||||
# pending, one completed.
|
||||
qx{../task rc:projects.rc add project:p1 one};
|
||||
qx{../task rc:projects.rc add project:p2 two};
|
||||
qx{../task rc:projects.rc done 1};
|
||||
my $output = qx{../task rc:projects.rc ls};
|
||||
unlike ($output, qr/p1/, 'p1 done');
|
||||
like ($output, qr/p2/, 'p2 pending');
|
||||
|
||||
$output = qx{../task rc:projects.rc projects};
|
||||
unlike ($output, qr/p1/, 'p1 done');
|
||||
like ($output, qr/p2/, 'p2 pending');
|
||||
|
||||
$output = qx{../task rc:projects.rc rc.list.all.projects:yes projects};
|
||||
like ($output, qr/p1/, 'p1 listed');
|
||||
like ($output, qr/p2/, 'p2 listed');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'undo.data';
|
||||
ok (!-r 'undo.data', 'Removed undo.data');
|
||||
|
||||
unlink 'projects.rc';
|
||||
ok (!-r 'projects.rc', 'Removed projects.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
69
src/tests/list.all.tags.t
Executable file
69
src/tests/list.all.tags.t
Executable file
@@ -0,0 +1,69 @@
|
||||
#! /usr/bin/perl
|
||||
################################################################################
|
||||
## task - a command line task list manager.
|
||||
##
|
||||
## Copyright 2006 - 2010, Paul Beckingham.
|
||||
## All rights reserved.
|
||||
##
|
||||
## This program is free software; you can redistribute it and/or modify it under
|
||||
## the terms of the GNU General Public License as published by the Free Software
|
||||
## Foundation; either version 2 of the License, or (at your option) any later
|
||||
## version.
|
||||
##
|
||||
## This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
## details.
|
||||
##
|
||||
## You should have received a copy of the GNU General Public License along with
|
||||
## this program; if not, write to the
|
||||
##
|
||||
## Free Software Foundation, Inc.,
|
||||
## 51 Franklin Street, Fifth Floor,
|
||||
## Boston, MA
|
||||
## 02110-1301
|
||||
## USA
|
||||
##
|
||||
################################################################################
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More tests => 10;
|
||||
|
||||
# Create the rc file.
|
||||
if (open my $fh, '>', 'tags.rc')
|
||||
{
|
||||
print $fh "data.location=.\n";
|
||||
close $fh;
|
||||
ok (-r 'tags.rc', 'Created tags.rc');
|
||||
}
|
||||
|
||||
# Create a data set of two tasks, with unique project names, one
|
||||
# pending, one completed.
|
||||
qx{../task rc:tags.rc add +t1 one};
|
||||
qx{../task rc:tags.rc add +t2 two};
|
||||
qx{../task rc:tags.rc done 1};
|
||||
my $output = qx{../task rc:tags.rc long};
|
||||
unlike ($output, qr/t1/, 't1 done');
|
||||
like ($output, qr/t2/, 't2 pending');
|
||||
|
||||
$output = qx{../task rc:tags.rc tags};
|
||||
unlike ($output, qr/t1/, 't1 done');
|
||||
like ($output, qr/t2/, 't2 pending');
|
||||
|
||||
$output = qx{../task rc:tags.rc rc.list.all.tags:yes tags};
|
||||
like ($output, qr/t1/, 't1 listed');
|
||||
like ($output, qr/t2/, 't2 listed');
|
||||
|
||||
# Cleanup.
|
||||
unlink 'pending.data';
|
||||
ok (!-r 'pending.data', 'Removed pending.data');
|
||||
|
||||
unlink 'undo.data';
|
||||
ok (!-r 'undo.data', 'Removed undo.data');
|
||||
|
||||
unlink 'tags.rc';
|
||||
ok (!-r 'tags.rc', 'Removed tags.rc');
|
||||
|
||||
exit 0;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user