Compare commits

..

106 Commits

Author SHA1 Message Date
Federico Hernandez
a13989f18e Release date for 1.9.2 2010-07-10 23:14:06 +02:00
Paul Beckingham
97bb07a617 Documentation
- Removed erroneous entry
2010-07-10 12:39:52 -04:00
Paul Beckingham
01d0d036a4 Documentation
- Synched the wiki FAQ with the man page.
2010-07-10 12:30:01 -04:00
Paul Beckingham
7de5b22f1c Unit Tests
- Corrected misspelling of config variable.
2010-07-09 01:32:00 -04:00
Paul Beckingham
cb635c0d6f Unit Tests
- Changed cal.t calendar colors to avoid false assumptions.
2010-07-09 01:01:16 -04:00
Paul Beckingham
111e9f893d Documentation Update
- Updated the OSX package creation instructions document, after feedback
  from Kevin.
2010-07-09 00:42:33 -04:00
Paul Beckingham
f96d2e6609 Documentation update
- Added Kevin Owens to the AUTHORS file for invaluable help with
  creating OSX 10.5 packages, and debugging the instructions
  document.
2010-07-09 00:38:41 -04:00
Paul Beckingham
8a930653a4 Unit Tests
- Correcting more unit tests that made color assumptions that are no
  longer valid.
2010-07-09 00:30:47 -04:00
Paul Beckingham
bc46888bcd Unit Tests
- Added null values for color.tagged and color.alternate, for the
  tests it affects.
2010-07-08 22:26:41 -04:00
Paul Beckingham
67fd7e2faa Themes
- Final tweak.
2010-07-08 22:03:45 -04:00
Paul Beckingham
9f96ab28ce Merge branch '1.9.2' of tasktools.org:task into 1.9.2 2010-07-08 21:13:28 -04:00
Paul Beckingham
a66f59a7e1 Packaging
- PDF of OSX packaging instructions.
2010-07-08 21:13:04 -04:00
Paul Beckingham
24e1522e32 Packaging
- First minor tweaks.
2010-07-08 19:47:10 -04:00
Paul Beckingham
f5bc5dfd0f Packaging
- Finished first version of the OSX packaging document.
2010-07-08 19:13:31 -04:00
Paul Beckingham
82702bffdc Unit Tests
- Modified unit tests for rc.t, in the hopes that task for OSX 10.5
  can pass them.
2010-07-08 01:55:17 -04:00
Paul Beckingham
1a05224816 Portability
- Fixed warning on Solaris.
2010-07-08 01:44:15 -04:00
Paul Beckingham
e4f7bda430 Packaging
- Updated 'update' script.
- Began README that provides instructions on how to create packages for
  OSX.  Unfinished.
2010-07-08 01:43:30 -04:00
Paul Beckingham
38ca8c8fb5 Themes
- Last tweaking.
2010-07-07 09:12:53 -04:00
Paul Beckingham
ad9c89b9fb Performance
- Found some inefficient string initialization in Table.cpp, report.cpp,
  and in switching over to using more std::string capabilities, realized
  a 25% boost in Table::render speed.
- Eliminated Table::suppressWS.
- Eliminated Table::clean.
2010-07-06 01:37:35 -04:00
Paul Beckingham
25db00e97d Unit Tests
- Added specific calendar colors to the rc file used in cal.t, so that
  the colors in the tests (which are in the old theme) match the new
  default theme.
2010-07-05 23:36:08 -04:00
Paul Beckingham
b3f3261190 Themes
- Contrast adjustments.
2010-07-05 18:16:31 -04:00
Paul Beckingham
6efd3299fe Default Theme
- Linux now uses dark-256 equivalent, when a new .taskrc file is created.
2010-07-05 17:56:44 -04:00
Paul Beckingham
844c980bce Enhancement - strippedLength
- Added a text method that calculates a string length but does not
  include color control codes.
2010-07-05 15:55:50 -04:00
Paul Beckingham
ce99cbf2d4 Themes - default
- Task now defaults to *the equivalent of* the dark-16.theme.
2010-07-05 15:01:15 -04:00
Paul Beckingham
5fb349ca9b Code Cleanup
- Minor formatting change.
2010-07-05 13:33:42 -04:00
Paul Beckingham
00041dce41 Themes
- Included first set of 7 theme files, for light and dark backgrounds,
  with 16- and 256-color support.
- Modified man pages accordingly.
2010-07-05 13:32:11 -04:00
Paul Beckingham
d6631767b5 Themes
- Assorted low-effort theme files, as examples.  More coming.
2010-07-05 12:16:51 -04:00
Paul Beckingham
0c4f83377a RC
- Put a 'calendar.holidays=sparse' entry inside the holidays files,
  which serves to enable the holiday feature if a holiday file is
  included.
2010-07-04 18:04:18 -04:00
Paul Beckingham
a45d6b459f Unit Tests - bug.summary.t
- Fixed tests that expected a newly-added task to have an age of '-',
  but on Cygwin, with the lower performance, the age is actually '3 secs'.
2010-07-04 13:26:19 -04:00
Paul Beckingham
d77a790f21 Portability
- Added stdlib.h to rx.cpp, which is needed by Cygwin at least.
2010-07-04 10:50:34 -04:00
Johannes Schlatow
5ecbd85020 Bug - merge command resulted in an error if
completed/deleted tasks were overwritten with pending tasks
2010-07-04 01:19:44 +02:00
Johannes Schlatow
6428b026ba Missing include 2010-07-04 01:08:21 +02:00
Paul Beckingham
716ed39695 Missing include
- The usual problem, this time <algorithm>.
2010-07-03 18:44:29 -04:00
Paul Beckingham
c650edd4f9 Support #383 - odd feedback when changing an existing, recurring project
- Fixed wording (support issue #383) when modifying a recurring task (thanks
  to T. Charles Yun).
2010-07-03 17:57:31 -04:00
Paul Beckingham
484c31f0e4 Documentation
- Modified the wording of the output of the undo command.
2010-07-03 17:54:02 -04:00
Paul Beckingham
d00b57ec65 Feature - #156
+ Task now supports both a 'side' and 'diff' style of undo.
+ Undo now observes the 'color.undo.before' and 'color.undo.after'
  configuration variables.
2010-07-03 15:50:46 -04:00
Paul Beckingham
724e9b8113 Color
- The ghistory graph bars can now be colored with 'color.history.add',
  'color.history.done' and 'color.history.delete' configuration variables.
2010-07-03 12:51:36 -04:00
Paul Beckingham
356519e58f Bug #420 - Missing ID from help output
- Applied patch from Ed Neville to correct help output for the
  append and prepend commands.
2010-07-03 09:27:11 -04:00
Paul Beckingham
213a7a519b Feature - merge command
- Merged patch that implements the first milestone of the merge
  feature.  Thanks to Johannes Schlatow.
2010-07-01 20:22:33 -04:00
Paul Beckingham
d7c446f010 Bug
- Fixed bug that miscalculated terminal width for the ghistory.annual
  report.
2010-07-01 01:06:43 -04:00
Paul Beckingham
14508742f1 Code Cleanup
- Removed obsolete code from Table object.
2010-06-28 17:46:27 -04:00
Paul Beckingham
6ea6c79375 Bug
- Fixed bug that prevented 'task list priority.above:L' from working.
- Added unit tests.
2010-06-28 17:45:42 -04:00
Paul Beckingham
426eac97aa Feature - sorting by age, age_compact
- Now supports correct sorting of the age and age_compact fields.
2010-06-27 19:31:08 -04:00
Paul Beckingham
7f99d39d19 Unit Tests - timesheet report
- Added unit tests to make sure the timesheet report lists the correct
  tasks in the correct section and week.
2010-06-27 18:43:40 -04:00
Paul Beckingham
623f8d869e Portability
- Added missing includes.
2010-06-27 17:06:51 -04:00
Paul Beckingham
b2eb9c3265 Bug #405 - after upgrade, "due:" filter not working for tasks created in version 1.9.0
- 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).
2010-06-27 16:55:29 -04:00
Paul Beckingham
688233b3a4 Documentation Update
- Fixed formatting problem in taskrc.5, where the indentation was
  not consistent.
2010-06-27 15:40:59 -04:00
Paul Beckingham
12cdee9809 Documentation Update
- Changed the line "New features in 1.9" to "New features in 1.9.2",
  otherwise the list looks a little light.
2010-06-27 15:20:41 -04:00
Paul Beckingham
66fcdfe01f Bug #312 - Task sorting
- Fixed bug #132, which failed to set a sort order so that active tasks sort
  higher than inactive tasks, all things being equal.
- All reports that include the 'active' column now sort on that column.
2010-06-27 15:14:27 -04:00
Paul Beckingham
0f7cf1cd52 Bug #418 - due.before:eow not working
- 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).
- Bug was probably fixed when #416 was fixed, but now has it's own unit tests.
2010-06-27 14:25:03 -04:00
Paul Beckingham
007c194c8c Bug #417 - Sorting by countdown_compact not working
- Added support for more varied durations when specifying recurring tasks,
  such as '3 mths' or '24 hrs'.
- Fixed bug #417, which caused sorting on countdown fields to be wrong
  (thanks to Michell Crane).
- Durations are now based on seconds, rather than days, and can accept/parse
  negative durations.
2010-06-27 13:44:04 -04:00
Paul Beckingham
ff18241f6f Unit Tests
- Enhanced 'run_all' so that by default, it does not run the benchmark.t
  script, but does if the 'slow' argument is specified.
2010-06-27 00:59:28 -04:00
Paul Beckingham
9477660e02 Enhancement - Duration
- Relocated util/formatSeconds and util/formatSecondsCompact into
  Duration object.
- Relocated unit tests.
- Upgraded Duration object to use seconds, not days.
- Enhanced Duration so that it can now parse '4 mins' etc.
2010-06-27 00:57:52 -04:00
Paul Beckingham
1f8f4c631d Enhancement - Duration
- Durations can now parse '3 wks', '1 wk', '1w', and similar for yrs,
  qtrs, mths, wks, days.
- Added unit tests.
2010-06-26 21:47:52 -04:00
Paul Beckingham
05fd9278a6 Code Cleaup
- Reimplemented Nibbler::getQuoted.
- Reimplemented Nibbler::skipN.
2010-06-26 20:14:45 -04:00
Paul Beckingham
f1a0b842dc Nibbler upgrade
- Merged Nibbler code from Tegelsten.
- Updated unit tests.
2010-06-26 19:55:17 -04:00
Paul Beckingham
cd59f7f510 Code Cleanup
- Corrected comments.
- Eliminated redundant code, at the expense of Task::parse call.
2010-06-26 17:33:58 -04:00
Paul Beckingham
6a1a1cd70f Added regular expression support
- Added rx.{h,cpp} from Tegelsten.
- Added unit tests.
2010-06-26 16:54:31 -04:00
Paul Beckingham
3c2987f53f Bug #416 - Sorting by due date with dateformat MD wrong
- Fixed bug #416, which caused sorting on a date to fail if the year was not
  included in the dateformat (thanks to Michelle Crane).
- Added unit tests.
2010-06-25 09:09:20 -04:00
Paul Beckingham
2ab1df77df Merge branch '1.9.2' of tasktools.org:task into 1.9.2 2010-06-23 17:22:21 -04:00
Paul Beckingham
abf31a6b35 Performance Enhancements
- Nibbler: Now locally stores input length rather than repeatedly calling
  std::string::length.
- Nibbler: Makes greater use of std::string::find_first_not_of, instead of
  looping.
- TDB: No longer applies empty filters to lists - just copies the lists.
- TDB: Now caches data when reading completed.data.
- TDB: During loadPending and loadCompleted, makes fewer copies of the data.
- TDB: In commit, breaks out of search loops after finding the right data.
- TDB: In gc, only writes out minimal pending or completed data, instead of
       all data, all the time.
- TDB: No longer reads completed.data in gc, and simply appends completed
       and deleted tasks to it.
2010-06-23 17:21:56 -04:00
Federico Hernandez
b6d320d311 Adjusted denotate
- partly matched strings are now also detected in the middle of the
  annotation and not only from the beginning.
2010-06-21 22:56:05 +02:00
Paul Beckingham
cd648270ab New alias
- Added export.vcalendar as an alias to export.ical.  They are the same.
2010-06-20 23:17:56 -04:00
Paul Beckingham
2161ffac2c Documentation update
- Added RFC references to ChangeLog, NEWS.
- Replaced the answer in the FAQ regarding annotation deletion.
2010-06-20 23:15:04 -04:00
Paul Beckingham
4f4a32b405 Enhancement
- Swapped std::string::find for find (from text.cpp) to allow
  configurable case sensitivity.
2010-06-20 20:22:39 -04:00
Paul Beckingham
99bce308e6 Bug #414 - Tags filtering not working with unicode characters
- 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 #414, that caused filtering on the presence or absence of tags
+   containing Unicode characters to fail (thanks to Michal Josífko).

 ------ old releases ------------------------------
2010-06-20 20:10:20 -04:00
Paul Beckingham
916b8641b3 Feature #415
- 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).
- Modified the 'next' report to only display a page, by default.
2010-06-20 17:32:11 -04:00
Paul Beckingham
2f85941d37 Typo
- Removed residual conflict marker.
2010-06-20 16:03:00 -04:00
Federico Hernandez
f3f4ae15eb Merge branch 'denotate' into 1.9.2 2010-06-20 21:03:36 +02:00
Federico Hernandez
5e53226eb8 Feature #408 - Allow deletion of annotations.
- Added new denotate command
- Added unit tests in denotate.t
- Change task.1 man page
2010-06-20 20:58:46 +02:00
Paul Beckingham
2c7552222a Feature #412
- 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 unit tests.
- Updated man pages.
2010-06-20 13:06:24 -04:00
Paul Beckingham
8572080677 Documentation
- With Charles permission, lifted an excellent description of task from
  a forum message to include in the main man page.  Thanks to T. Charles
  Yun.
2010-06-20 12:22:37 -04:00
Paul Beckingham
ba87499eca FF4
- Removed encodings for ',' -> '&comma;', ''' -> '&squot;', and
  ':' -> '&colon'.
- Retained decodings to provide backward compatibility.
2010-06-20 00:35:09 -04:00
Paul Beckingham
fbe24b3fda Unit Tests
- Added a vramsteg progress bar, which is only used if it is found
  in /usr/local/bin.
2010-06-20 00:31:55 -04:00
Paul Beckingham
5e55166617 Merge branch '1.9.2' of tasktools.org:task into 1.9.2 2010-06-15 08:31:08 -04:00
Paul Beckingham
bcd5524563 Bug #411 - projects command only lists those in use by pending tasks
- Fixed bug in man page that doesn't properly state the above (thanks
  to Dirk Deimeke).
2010-06-15 08:30:15 -04:00
Paul Beckingham
bb19361956 Feature #298 - Configurable recurring task count
- Added new recurrence.limit value (default 1) to control the number of
  future pending tasks generated from a recurring parent task.
- Added unit tests.
- Updated taskrc man page.
2010-06-13 12:45:41 -04:00
Paul Beckingham
78d092c588 Merge branch '1.9.2' of tasktools.org:task into 1.9.2 2010-06-11 20:21:58 -04:00
Paul Beckingham
3da3d3f99d Documentation
- Added FAQ about deleting an annotation.
2010-06-11 20:21:03 -04:00
Paul Beckingham
e2b240fd06 Minor doc edit
- Just to prove push is working.
2010-06-11 18:26:07 -04:00
Federico Hernandez
ee6ab69023 Removed X-2 versions from OS list in NEWS 2010-06-12 00:07:22 +02:00
Federico Hernandez
74e13670d0 Added msg to 'task show' when no config variables are matched 2010-06-08 23:13:38 +02:00
Federico Hernandez
d37c798dbc Enhancement - #407 show command
- finalized the implementation
- a searchstring can now be supplied to limit the display
  of configuration settings
2010-06-08 22:38:35 +02:00
Paul Beckingham
c93db168f3 Typo in comment in config file. 2010-06-08 08:29:57 -04:00
Federico Hernandez
52c029d4d9 Marked place in code with TODO for completion of enhancement #407.
(which was called #307 wrongly in commit 51e5a183)
2010-06-08 10:05:27 +02:00
Federico Hernandez
c9360ad9c4 Minor syntax error in task.1 2010-06-07 23:41:57 +02:00
Federico Hernandez
51e5a18384 Enhancement - #307 show command
- introduced new show command to display configuration settings
- config command is used to just set config values
- modified documentation
- modified some unit tests calling 'task config' to 'task show'
2010-06-07 23:35:58 +02:00
Federico Hernandez
f1368d6ac6 Added missing config variables to the big recognized string 2010-06-04 01:03:21 +02:00
Federico Hernandez
70e6f4f9f6 Enhancement - #390 timestamps in annotations
- added new dateformat for annotations
- documented prev. added format modifiers H, N and S
2010-06-04 00:57:42 +02:00
Federico Hernandez
2bfd220714 Missing include for Ubuntu. 2010-06-03 14:30:13 +02:00
Federico Hernandez
3214c1f02a Added information on bug fix #211 to ChangLog file. 2010-06-03 07:16:07 +02:00
Federico Hernandez
297f48a07c Bug Fix #211 - it was unclear which commands modify a task description
- rearranged commands on man page.
- new subsection for the "modifying" commands.
2010-06-03 06:57:33 +02:00
Paul Beckingham
ea067acb52 Enhancement - Hooks
- Implement task api calls for debug, header and footnote messages.
- Added unit tests.
2010-05-31 20:08:25 -04:00
Paul Beckingham
8a70b78d71 Unit Tests - cmd.t
- Fixed test of whether "export" is a read-only command.  There are now
  two export commands.
2010-05-31 16:45:21 -04:00
Paul Beckingham
e368043fb8 Enhancement - #363 export.ical
- Added feature #363 supporting iCalendar export via the 'export.ical'
  command.
- Updated documentation.
- Removed unnecessary localization of canonical command names.
2010-05-31 16:05:51 -04:00
Paul Beckingham
3ef6aa9f8e Enhancement - Date::toISO
- Added ISO date format support (19980119T070000Z) to Date class, for use
  in export.ical.
- Added unit test.
2010-05-31 13:18:41 -04:00
Paul Beckingham
8cd8c4753b Bug fix - #406
- Fixed bug #406 so that task now includes command aliases in the _commands
  helper command used by shell completion scripts.
2010-05-31 11:40:42 -04:00
Paul Beckingham
24085e0960 Enhancement - consistency checks
- Reintroduced disabled (no idea why) checks that ensure that shadow
  files weren't set up to clobber authoritative task files.
2010-05-30 17:03:42 -04:00
Paul Beckingham
d92e80e289 Enhancement - #36, #37
- Added features #36 and #37, providing annual versions of the 'history'
  and 'ghistory' command as 'history.annual' and 'ghistory.annual'.
- Uses new canonical names history.monthly, history.annual, ghistory.monthly
  and ghistory.annual, with aliases providing original history and ghistory
  commands.
- Updated man pages.
2010-05-30 17:01:38 -04:00
Paul Beckingham
fcbc8a2ee2 Enhancement - #326
- 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 log command to task.1 man page.
- Added log command to task-tutorial.5 man page.
- Added log command to help text.
- Added log command unit tests.
2010-05-30 15:20:12 -04:00
Paul Beckingham
336a4dea01 Bug Fix - Problem with #320
- The new auto-info command interfered with task modification.  Should
  have run all the unit tests before committing that change.
- Added auto-info command to the help text.
2010-05-30 15:03:58 -04:00
Paul Beckingham
67ffd07312 Enhancement - #320
- Added feature #320, so the command "task 123" is interpreted as an
  implicit "task info 123" command (thanks to John Florian).
- Modified task man page.
- Added unit tests.
- Updated supported platform lists with F13 and Ubuntu 10.04.
2010-05-30 13:20:39 -04:00
Federico Hernandez
b2ad305f23 Bumped version number to 1.9.2 2010-05-23 21:38:27 +02:00
Federico Hernandez
fa34f47f8a Packaging for ubuntu and fedora
- Updated packaging details for 1.9.1
2010-05-23 21:29:44 +02:00
Federico Hernandez
9a47e2b748 Added SHA1 of tagged release commit 2010-05-23 21:24:31 +02:00
Paul Beckingham
60d6cd62c8 Packaging for OSX
- Updated packaging details for 1.9.1
2010-05-23 11:03:56 -04:00
118 changed files with 7124 additions and 2033 deletions

View File

@@ -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

View File

@@ -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.

View File

@@ -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
View File

@@ -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

View File

@@ -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.

View File

@@ -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>.

View File

@@ -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

View File

@@ -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>

View File

@@ -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.

View File

@@ -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

View 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=

View File

@@ -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

View 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

View 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
View 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

View File

@@ -1,3 +1,5 @@
calendar.holidays=sparse
holiday.nyårsdagen.name=Nyårsdagen
holiday.nyårsdagen.date=20100101
holiday.trettondedagjul.name=Trettondedag jul

View File

@@ -1,3 +1,5 @@
calendar.holidays=sparse
holiday.newyearsday.name=New Years Day
holiday.newyearsday.date=20100101
holiday.martinlutherkingday.name=Martin Luther King Day

View File

@@ -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=

View File

@@ -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

View File

@@ -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

View File

@@ -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.

Binary file not shown.

278
package-config/osx/README Normal file
View 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.
---

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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 © 19942008 Lua.org, PUC-Rio
License:

View File

@@ -1,2 +0,0 @@
scripts
i18n

View File

@@ -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

View File

@@ -0,0 +1 @@
1.0

View File

@@ -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
View File

@@ -1,2 +1,3 @@
*.o
Makefile.in
*_test

View File

@@ -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");

View File

@@ -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;
// , -> &comma;
// [ -> &open;
// ] -> &close;
// : -> &colon;
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, "&comma;"); // 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, "&colon;"); // 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 ("&quot;")) != std::string::npos) // no i18n
while ((i = value.find ("&quot;")) != std::string::npos)
value.replace (i, 6, "\"");
while ((i = value.find ("&comma;")) != 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 ("&colon;")) != 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 ("&comma;")) != std::string::npos)
value.replace (i, 7, ",");
while ((i = value.find ("&colon;")) != std::string::npos)
value.replace (i, 7, ":");
}

View File

@@ -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;

View File

@@ -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") ||

View File

@@ -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";

View File

@@ -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");
}
}

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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
}

View File

@@ -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

View File

@@ -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" ||

View File

@@ -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)

View File

@@ -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)
+ "";
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
};

View File

@@ -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
View 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
View 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

View File

@@ -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)
{

View File

@@ -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;
}
}
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -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
View 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;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -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)

View File

@@ -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;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -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
View 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
View 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

View File

@@ -21,4 +21,5 @@ path.t
file.t
directory.t
grid.t
rx.t
*.log

View File

@@ -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

View File

@@ -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;

View File

@@ -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;&comma;&open;&close;&colon;\"", "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;&quot;&comma;&open;&close;&colon;\"");
a7.parse (n);
t.is (a7.composeF4 (), "name:\"&tab;&dquot;&comma;&open;&close;&colon;\"",
"Att::parse (name:\"&tab;&quot;&comma;&open;&close;&colon;\")");
t.is (a7.composeF4 (), "name:\"&tab;&dquot;,&open;&close;:\"",
"Att::parse (name:\"&tab;&quot;,&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;
}

View File

@@ -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
View 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
View 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
View 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;

View File

@@ -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};

View File

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

View File

@@ -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",

View File

@@ -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");

View File

@@ -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.

View File

@@ -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";

View File

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

View File

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

View File

@@ -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";

View File

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

View File

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

View File

@@ -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
View 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
View 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;

View File

@@ -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;

View File

@@ -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
View 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;

View 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;

View 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
View 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
View 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
View 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
View 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