Compare commits

...

156 Commits

Author SHA1 Message Date
Paul Beckingham
06062a96eb Documentation Update - version 2009-04-12 23:41:05 -04:00
Paul Beckingham
7431f0cdd3 Bug Fix - use " not ' for annotation quoting
- Annotations were using ' to quote text, sanitizing ' -> " inside
  the text.  It would be better to quote with " and sanitize " -> '
  because ' is more common in the text (e.g. "Doesn't work") than ".
2009-04-12 22:53:20 -04:00
Paul Beckingham
22f0b1d9fb Documentation Update
- Added the global modifier of the substitution command to the
  command line grammar file.
2009-04-12 22:35:26 -04:00
Paul Beckingham
b8187e24ae Enhancement - file import
- Added support for configuration variables that override field
  mapping.
- Updated documentation.
2009-04-12 20:29:37 -04:00
Paul Beckingham
120593887b Code Cleanup - unit test warning
- Cleaned up Perl warning in unit test.
2009-04-12 02:17:12 -04:00
Paul Beckingham
01e5e773eb Enhancement - stats report
- Rearranged sequence of stats report to make more sense, with
  counts first and statistics (derived data) last.
2009-04-12 02:10:05 -04:00
Paul Beckingham
e0fd39db7b Enhancement - substitutions /from/to/g
- Added support for the "g" modifier to the substitution command,
  that replace every occurrence of "from" with "to", in the task
  description and any annotations.
2009-04-12 02:01:08 -04:00
Paul Beckingham
a39261f82d Unit tests - substitution
- Added unit tests to ensure that substitution works on the task
  description and annotations.
2009-04-12 01:03:52 -04:00
Paul Beckingham
a6b45af0a2 Enhancement - annotation substitution
- Annotations are now modifiable using the /from/to/ modification
  command.
2009-04-12 00:56:58 -04:00
Paul Beckingham
daea320564 Bug Fix - annual recurrence due-date creep
- Fixed bug where annual recurring tasks exhibit due-date creep
  (thanks to T. Charles Yun).
2009-04-12 00:05:21 -04:00
Paul Beckingham
1cbec205f1 Bug Fix - concatenation of colons in description
- When a task description contained a colon, the two words preceding
  the colon were concatenated.  For example, "aa bb:cc dd" gets
  concatenated to "aabb:cc dd".
- Added unit to test to prevent regression.
- Updated documentation.
2009-04-11 23:02:48 -04:00
Paul Beckingham
579232b7ea Documentation Update
- Cygwin doesn't support all color combinations, which include bold,
  underline and bright background colors.  Added a troubleshooting
  item that describes this problem, and suggests running "task colors"
  to determine just which colors are supported.
2009-04-11 22:39:37 -04:00
Paul Beckingham
cee8fda236 Documentation Update
- added Federico Hernandez to the AUTHORS file for his contribution of
  Red Hat RPM packages.
- Added RPM download links.
2009-04-11 22:18:12 -04:00
Paul Beckingham
4dda1f0c27 Documentation Update
- Added Ubuntu Jaunty Jackalope 9.04 (beta) to the list of supported
  platforms.
2009-04-05 12:26:11 -04:00
Paul Beckingham
0571412da0 Documentation Update
- Added Ubuntu 9.04 (Jaunty Jackalope) to the list of supported systems
  (thanks to Federico Hernandez).
2009-03-30 19:51:13 -04:00
Paul Beckingham
b4f031e4a7 New report columns
- Added support for tag_indicator column.
- Added support for recurrence_indicator column.
2009-03-30 00:29:28 -04:00
Paul Beckingham
5b1d64960d Documentation Update
- Added faq question/answer.
- Clarified file format upgrade via backup warning.
2009-03-29 23:50:00 -04:00
Paul Beckingham
a5fef2cc6b Autoconf
- Removed double check for ncurses, causing the library to be listed
  twice on the link line.
2009-03-29 22:17:14 -04:00
Paul Beckingham
8ab3c1cc3c Bug Fix
- Fixed bug whereby if no columns labels were specified, it was
  considered a column count mismatch.
- Fixed unit tests to use m/d/Y not M/D/Y dateformat.
2009-03-29 21:27:48 -04:00
Paul Beckingham
2700713c03 Merge branch 'import' into 1.6.0
Conflicts:
	ChangeLog
	html/task.html
2009-03-29 18:51:27 -04:00
Paul Beckingham
567bdd98a4 Code Cleanup
- Removed temporary file import samples
2009-03-29 17:43:21 -04:00
Paul Beckingham
25425614b1 File Import
- Implemented all remaining import functionality.
2009-03-29 17:42:11 -04:00
Paul Beckingham
3b65051e9e Unit Tests - labels
- Added unit tests to verify that custom report labels are properly used.
2009-03-29 15:41:09 -04:00
Paul Beckingham
5f4563af2f File Import
- Implemented import from task 1.4.3, 1.5.0, 1.6.0, plain text,
  todo.sh and task command line files.
- Implemented unit tests to cover the above.
2009-03-29 15:34:35 -04:00
Paul Beckingham
7e2bd166fa Code Cleanup
- Guaranteed the correct Config::get call via cast.  There is some
  doubt as to the correct call being made otherwise.  This is not a
  very likely fix, but does eliminate one possibility.
2009-03-29 11:08:32 -04:00
Paul Beckingham
41b60f88d3 Custom Report Labels
- Added the ability to override the labels of custom reports (thanks
  to T. Charles Yun).
2009-03-27 23:51:20 -04:00
Paul Beckingham
93ec320555 Updated FAQ 2009-03-27 22:32:40 -04:00
Paul Beckingham
c1291dc587 Updated Documentation
- Added description of import process.
2009-03-27 22:02:13 -04:00
Paul Beckingham
57deb83b25 Documentation Update
- Added a faq.html file, although it is not so much a set of frequently
  asked questions, but of repeatedly asked questions.  Questions from
  the mail bag, if they apply to a general audience might be shown
  here.
2009-03-27 21:25:34 -04:00
Paul Beckingham
e4f5d6579c File Import
- Updated documentation.
- Added another recognized format - task command line.
2009-03-26 00:52:51 -04:00
Paul Beckingham
99dc72f26f File Import
- Added format identifier code for task 1.4.3, task 1.5.0, todo.sh
  2.0 and CSV.
- Implemented import for type text.
- Implemented util.cpp:slurp function.
- Gathered sample input files for import testing, and later, unit
  tests.
2009-03-26 00:41:15 -04:00
Paul Beckingham
406e648d58 Code Cleanup
- The new 'echo.command' configuration variable was incorrectly
  flagged as obsolete by report.cpp:handleVersion.
2009-03-25 17:49:22 -04:00
Paul Beckingham
db7b2dd9fe File Import
- Implemented scaffolding for new import command.
2009-03-25 02:05:50 -04:00
Paul Beckingham
c31ec6b6a6 Unit Tests - all file formats
- Added unit tests to verify correct parsing of file formats 1, 2
  and 3.
2009-03-25 01:29:59 -04:00
Paul Beckingham
1a656f0f60 Recurring Tasks - upgrades and bug fixes
- Improved (fixed) logical consistency checks that prevent the
  addition of a recurrence frequency without a due date.
- Improved (fixed) logical consistency checks that prevent the
  addition of an until date with a recurrence frequency.
- When a recurring task is modified, all sibling instances, as well
  as the parent task now get modified.
- When a recurring task is appended, all sibling instances, as well
  as the parent task now get modified.
- Updated documentation.
- It is now possible to upgrade a regular task to a recurring task,
  which is triggered by the "recur" attribute.
2009-03-25 01:08:13 -04:00
Paul Beckingham
5ec0d569a9 Enhancement - annotations
- Added annotated description to the active, overdue and next reports.
2009-03-24 23:15:55 -04:00
Paul Beckingham
3979c3283e Enhancement - annotations
- Added support for "annotate" command to annotate existing tasks.
- Bumped file format to version 3, due to the annotations.
- Added unit tests to verify that annotations work.
- Changed 'description' column everywhere to include annotations.
- Added 'description_only' column to exclude the annotations.
- Fixed bug in Table.cpp that calculated the width of multi-line
  columns by using the cell length, instead of the length of the
  longest individual line.
- Updated documentation with new feature.
- Updated documentation with new column.
- Enhanced t.t unit tests to cover format 43
2009-03-24 01:57:12 -04:00
Paul Beckingham
ca795ea281 Bug Fix - confirmation was broken
- Fixed inverted condition that broke confirmation.
2009-03-23 21:55:02 -04:00
Paul Beckingham
d10e9be500 Bug fix - assumed "yes" value, instead of Bool
- Fixed bug where only a value of "yes" would enable confirmation,
  instead of any Boolean true value.
2009-03-22 23:50:42 -04:00
Paul Beckingham
f790df24c5 Enhancement - added echo of id, description
- Added an echo of the ID and description of the task for the start,
  stop, do, undo, delete and undelete commands.  Thanks to Bruce
  Dillahunty.
- Updated documentation.
- Added "echo.command=no" to delete.t, undo.t because the default
  value is "yes", which breaks tests.
- Fixed syntax errors in utf8.t
- Corrected expected number of tests in recur.t
2009-03-22 23:34:17 -04:00
Paul Beckingham
ca933d7f39 Unit Tests - duration
- Corrected unit tests that were mistakenly using 'week' instead of
  'weekly'.
2009-03-20 20:02:59 -04:00
Paul Beckingham
827bc6204b Unit Tests - autocomplete
- Implemented unit test to verify the functionality of the
  util.cpp:autoComplete function.
2009-03-20 20:01:44 -04:00
Paul Beckingham
4537d5048e Unit Tests - confirmation
- Implemented unit tests to very that "confirmation=yes" works.
- Implemented unit tests to very that \n causes a re-prompt.
- Updated docs with regard to this fix, thanks to Bruce Dillahunty.
2009-03-20 18:12:11 -04:00
Paul Beckingham
74ea5b4ef6 Bug Fix - confirmation not processing newline
- Fixed bug where util.cpp:confirm was eating newlines, and not
  rewriting the prompt.  Consequently, after confirm asked the
  question, and the user hit <Enter>, nothing was displayed but
  the newline.  Now uses std::getline.
2009-03-20 16:56:25 -04:00
Paul Beckingham
cc2220b406 Unit Tests - text
- Added unit tests to verify correct functioning of the text utility
  code.
2009-03-19 20:48:02 -04:00
Paul Beckingham
7389ce617a i18n - utf8 support
- Added more unit tests to verify that utf8 projects and tags are
  supported.
2009-03-19 19:46:41 -04:00
Paul Beckingham
165001acac i18n - unit tests
- Added more utf8.t unit tests.
- Removed text.cpp:extractParagraphs, which is not used.
2009-03-19 19:14:01 -04:00
Paul Beckingham
3d3d788961 Recurring Tasks - new "weekdays" frequency
- Added support for "weekdays" as a recurrence frequency, which skips
  Saturday and Sunday, but is otherwise a daily recurrence.  Thanks
  to Chris Pride.
2009-03-18 23:29:25 -04:00
Paul Beckingham
3c196230dd Autoconf
- Added the "-Wall and -pedantic" compiler flags for the non-debug
  build.  The should have been there anyway.
2009-03-18 22:54:59 -04:00
Paul Beckingham
9a350a7dcd Documentation Update
- Updated docs that referenced 1.4.1, failed to include new 1.5.0
  and 1.6.0 commands.
2009-03-17 23:54:56 -04:00
Paul Beckingham
92579e5531 Unit Test - oldest/newest
- Added unit tests to verify oldest and newest reports both work when
  less than 10 tasks are added, and have the correct sort order.
2009-03-17 23:36:00 -04:00
Paul Beckingham
40a538a769 Unit Tests - utf8.t
- Implemented unit tests (more of a demo) that add a bunch of UTF-8
  encoded tasks, as a starting point to updating task to be aware of
  encodings, Unicode etc.
2009-03-17 22:45:53 -04:00
Paul Beckingham
b6e4bc966f Merge branch 'master' of git@github.com:pbeckingham/task into 1.6.0 2009-03-16 22:27:40 -04:00
Paul Beckingham
03815967d2 Documentation Update - task.html
- Added reference to github to allow direct download, clone, fork etc.
2009-03-16 22:26:27 -04:00
Andy Lester
7049bf19d9 Ignore backup files, too
Signed-off-by: Paul Beckingham <paul@beckingham.net>
2009-03-17 10:19:07 +08:00
Paul Beckingham
c69c3bb090 New Command - append
- New "append" command concatenates additional text onto an existing
  task description.
- Added unit tests to append command.
2009-03-16 08:29:09 -04:00
Paul Beckingham
7238d1f1c9 Began 1.6.0 Development 2009-03-16 08:27:24 -04:00
Paul Beckingham
9f82c55c5b Merge branch '1.5.0'
Conflicts:
	html/task.html
2009-03-15 22:26:50 -04:00
Paul Beckingham
87be68e2e8 Bug Fix
- Shebang in tests/run_all was backwards.
2009-03-15 22:12:18 -04:00
Paul Beckingham
7b1dec0d77 Bug Fix - abbreviation.t
- abbreviation.t contains unit tests that fail to specify an alternate
  rc file (rc:abbrev.rc), and so instead rely on ~/.taskrc.  For a new
  installation, there is no .taskrc, so task offers to create one.
  When done in the context of a unit test, task hangs waiting for input.
2009-03-15 19:15:35 -04:00
Paul Beckingham
f8af5d999a Unit Tests - run_all
- Added script to run all unit tests and capture output.
2009-03-15 17:38:54 -04:00
Paul Beckingham
8efd8620c8 Portability - Ubuntu 8.10
- When creating a new .taskrc file, no newlines were included at EOL.
  This needs a 1.5.1 regression test.
2009-03-15 17:21:54 -04:00
Paul Beckingham
e8a795befb Unit Tests - due, export
- due.t was incorrectly reporting the number of tests it intended to
  run.
- export.t was not updated when the export command was updated to include
  recurrence information.
2009-03-15 17:01:22 -04:00
Paul Beckingham
b5690f00e2 Portabiliy - Fedora 9, Ubuntu 8
- The custom report limit "report.x.limit" was being used to limit the
  rendered rows in the table.  Instead, there should be something like
  min (limit, actual_rows) used, in Table.cpp.
  The symptom was duplicate tasks in a "task oldest" report, when there
  were less than 10 tasks.
2009-03-15 16:39:41 -04:00
Paul Beckingham
65f74da7a4 Portability - Fedora 9
- Using size_t as a result for std::string::find causes a silent error,
  reported only on Ubuntu 8.  size_t is not large enough.  The proper
  result type is std::string::size_type.  This fixes a problem with
  the command "task old" responding with "Ambiguous commane 'old' -
  could be one of oldest, oldest.description, oldest.limit, oldest.sort".
2009-03-15 16:26:20 -04:00
Paul Beckingham
429d0f3071 Portability - Fedora 9
- Compiler pointed out an expression (a || b && c) that clearly needs
  parentheses around (a || b).  Gcc on other OSes don't mention this.
2009-03-15 16:14:16 -04:00
Paul Beckingham
4baf30cf9c Portability - Ubuntu 8
- Changed unsigned int to size_t for std::string::npos comparison.
- Removed validBuiltinCommand function that is not used.
2009-03-15 16:13:02 -04:00
Paul Beckingham
a3882160fa Documentation Update
- Updated docs to reflect the 1.5.0 release date.
2009-03-15 15:12:16 -04:00
Paul Beckingham
cd85a28e98 Unit Tests - due, overdue
- Unit tests to verify that the "overdue" report is properly
  displaying tasks.
- Unit tests to verify that "due" can be defined.
2009-03-15 15:04:52 -04:00
Paul Beckingham
e33a918c24 Bug Fix - summary report
- Fixed bug in summary report where recently completed (and therefore
  not yet in the completed.data file) tasks were not included in the
  report.
2009-03-15 11:37:05 -04:00
Paul Beckingham
df82fade2c Unit Tests - bug.summry, custom.columns, next
- Added unit tests to verify that the next report returns the correct
  tasks.
- Added unit test to verify that unrecognized columns in a custom
  report are flagged.
- Added unit tests to verify that only pending and completed tasks
  are included in the summary report.
2009-03-15 11:31:27 -04:00
Paul Beckingham
2d2bd47075 Bug Fix - summary report included deleted tasks
- Applied patch from Benjamin Tegarden to exclude deleted tasks from
  the summary report.
2009-03-14 13:47:48 -04:00
Paul Beckingham
bdd1b16ba0 Documentation Update
- Updated docs to reflect recent changes.
2009-03-14 13:38:39 -04:00
Paul Beckingham
5383943fa7 Enhanced export command
- Now sanitizes output by replacing ' with " in descriptions.
- Added 'recur' attribute to exported output.
- Removed recurring, deleted and complete tasks from the export.
2009-03-14 13:36:32 -04:00
Paul Beckingham
8ac3978222 Unit Tests - dateformat, shadow
- Improved dateformat.t tests to cover all acceptable date format
  characters.
- Unit tests for shadow file update notification.
- Unit tests for shadow file updates under certain circumstances.
- Unit tests for shadow file no updates under other circumstances.
2009-03-14 12:54:11 -04:00
Paul Beckingham
c9a6d2a750 Improved GC and Shadow File Handling
- Every command now returns an output string, or at least has an
  opportunity to do so.
- TDB::gc is only performed a) when allowed, and b) when the command
  will display line numbers.
- updateShadowFile is only performed when a) shadow updates are allowed,
  and either b) when a command is guaranteed to have modified a task or
  c) when TDB:gc has already made changes.
2009-03-14 12:05:32 -04:00
Paul Beckingham
64cfc26ff3 Enhanced Stats Report
- now reports number of unique tags (given filtering)
- now reports number of unique projects (given filtering)
2009-03-14 12:04:25 -04:00
Paul Beckingham
7c87bbc19a Unit Tests - dateformat
- Unit tests determine whether the dateformat configuration variable
  determines how dates are parsed, and how dates are rendered.
2009-03-14 12:02:33 -04:00
Paul Beckingham
4a524a220e Bug Fix - default command, default unit test
- Task runs the default command when no arguments are provided, but
  when an "rc:..." argument is provided, it does not run the default
  command.
- Implemented unit tests to verify the functioning of default commands,
  default project and default priority.
2009-03-14 00:21:42 -04:00
Paul Beckingham
2216eee678 Help Consistency
- Added note about frequent releases to the shortUsage output, so it
  is now consistent with that of "version".
2009-03-13 13:12:34 -04:00
Paul Beckingham
28c97f181a Grammar
- Changed wording of the help output.
2009-03-13 10:35:17 -04:00
Paul Beckingham
0cfc9c720e Compile Bug - missing <stdlib.h>
- Added stdlib.h to Grid.cpp, thanks to Benjamin Tegardin.
2009-03-13 09:06:23 -04:00
Paul Beckingham
05b5273136 Unit Tests - oldest
- Implemented unit tests to verify that the "oldest" report does
  indeed show the oldest 10 tasks.
- Implemented unit tests to verify that the "newest" report does
  indeed show the newest 10 tasks.
2009-03-12 22:56:22 -04:00
Paul Beckingham
c35a764019 Custom Reports - oldest, newest
- Added support for the "report.X.limit" configuration variable, to
  restrict the number of rows a report generates.
- Added support for Table::render (limit) to limit the number of rows
  that are rendered.
- Removed "oldest" and "newest" report code.
- Added "oldest" and "newest" custom report details to Config.cpp
- Updated various documentation.
2009-03-12 22:34:45 -04:00
Paul Beckingham
8c95e82a63 Unit Tests - start/stop/acive
- Added unit tests to test the start and stop commands via the active
  report.
2009-03-10 23:06:02 -04:00
Paul Beckingham
79d644c257 Unit Tests - custom
- Added unit tests to verify correct functioning of custom report
  filters.
2009-03-10 22:30:15 -04:00
Paul Beckingham
2d07b08260 Custom Reports - usage
- Added defined custom reports to the usage text.  This includes the
  new "report.X.description" configuration variable.
2009-03-10 22:21:23 -04:00
Paul Beckingham
1f45e47e36 Bug Fix - history/ghistory triggered only by add
- Fixed bug whereby if a new month rolls around, and no task is added,
  no row of data is shown in the history or ghistory reports, even
  though tasks may have been completed or deleted ni the new month.
2009-03-10 16:37:35 -04:00
Paul Beckingham
dac1942cad Bug Fix - calendar
- Task now displays as many calendars will fit across the window,
  unless a lower value is specified in the "monthsperline" configuration
  variable.
- Task now obeys the "color" configuration variable when determining
  whether to add a legend to the calendar output.
2009-03-10 16:12:59 -04:00
Paul Beckingham
6d8cb5181f Bug Fix - unit test tdb.t
- Fixed two failing unit tests in tdb.t.cpp, which were both due to
  incorrect test logic, rather than a TDB bug.
2009-03-10 15:40:48 -04:00
Paul Beckingham
d174bb1143 Bug Workaround - locking
- Added support for the "locking" configuration variable that disables
  file locking.  This can be helpful to folks who use task on Solaris,
  and store their task data files on an NFS mount.
2009-03-10 15:21:29 -04:00
Paul Beckingham
dc946e175e Unit Tests - completed, delete
- Added unit tests to verify that the completed.data file is not
  created until the first report is run after the task is marked
  as done.
- Added unit tests to verify that delete/undelete work as expected.
2009-03-10 14:32:32 -04:00
Paul Beckingham
9f278b1ffc Unit Tests - export
- Added unit tests to export tasks and compare.
2009-03-10 00:22:23 -04:00
Paul Beckingham
6fade84535 Unit Tests - color.*, abbreviation
- Added unit tests for all auto coloration configuration settings.
- Tweaked colorization rule precedence to allow color.due to override
  the built-in coloration of due tasks.
2009-03-10 00:08:40 -04:00
Paul Beckingham
0ff33d1c16 Version command changes
- Added color.recurring to the list of valid config values.
- Added message to "version" command hinting that folks should look
  periodically for updated versions of task.  Task does not "call home"
  and check for updates (and never will), and so it is easy to not
  realize that there may be newer versions of task with bug fixes and
  new features.
2009-03-09 23:02:01 -04:00
Paul Beckingham
1999e38ba5 Colorization - color.recurring
- Added support for "color.recurring" configuration variable to
  colorize recurring tasks.
- Updated docs.
2009-03-09 22:12:49 -04:00
Paul Beckingham
17de9fec9f New Column - recur
- Added new column 'recur' for use in custom reports.
- Implemented Table::ascendingPeriod, Table::descendingPeriod allowing
  sorting on the recur column.
- Added unit tests to both use the new column and test the sorting.
- Code cleanup.
2009-03-09 22:01:08 -04:00
Paul Beckingham
751094cffb Documentation Update
- Added recent bug fix details.
2009-03-09 03:09:43 -04:00
Paul Beckingham
012e47267f Bug Fix - concatenated description on modify
- When a task was modified, the new description was concatenated
  without spaces.
2009-03-09 03:06:41 -04:00
Paul Beckingham
bd5e91c31f Merge branch '1.5.0' of git@github.com:pbeckingham/task into 1.5.0 2009-03-09 02:54:10 -04:00
Paul Beckingham
9e7844796b Updated Documentation
- Added 'beta' download section to main web page.
2009-03-09 02:53:44 -04:00
Paul Beckingham
209f7ffb00 Updated Documentation
- Added new platforms to NEWS file.
2009-03-09 02:52:36 -04:00
Paul Beckingham
28e997691f Unit Tests - repair
- Added auto right trim to all table rows, which is a much more
  efficient way of doing what Table::optimize was doing.
- Table::optimize is now a nop.
2009-03-08 22:56:47 -04:00
Paul Beckingham
3f418c6fdc Performance
- Made Table::optimize a public method.
- Table::optimize called only from handleReportGHistory, where it's
  needed.
- Retaining benchmark.txt, to allow further improvements.
2009-03-08 21:29:55 -04:00
Paul Beckingham
0362b41f3b Performance
- Added Timer class to display high resolution timing information.
- Found terrible bug in Table::optimize that was taking up 99.7%,
  on average, of the Table::rendering time, including sorting.  This
  fix naturally causes a 187-fold speedup of rendering.
- Changed report.cpp in handleCustomReport to only load pending tasks,
  instead of all pending tasks.  Subtle, but important difference.
2009-03-08 20:49:33 -04:00
Paul Beckingham
4fa4c5f532 Unit Tests - t.benchmark.t
- Added benchmark to measure time taken to parse 1,000,000 T records.
2009-03-08 17:59:27 -04:00
Paul Beckingham
3088e1ebe1 Unit Tests - abbreviation, filter, benchmark
- Added tests for attribute abbreviation.
- Added tests for filter permutation testing.
- Added benchmark for ongoing performance measurement.
- Mentioned test suite in docs.  Why not?
2009-03-07 02:06:13 -05:00
Paul Beckingham
6a7c66aa05 Unit Tests - color.disable color.pri config.obsolete
- Added unit tests to cover automatic colorization by priority.
- Added unit tests to cover automatic disabling of color when !isatty.
- Added unit tests to cover display of unsupported configuration
  variable in the 'version' report.
- Added support the '_forcecolor' configuration variable to allow the
  possibility of unit tests that test color support, yet redirect
  output to a file.  This configuration variable will not be
  documented.
2009-03-07 00:14:58 -05:00
Paul Beckingham
3b1d396e0a Acknowledgement
- Michael Greb acknowledged for his help in reporting several bugs in
  sufficient detail, and narrowing down the cause.
2009-03-06 21:59:25 -05:00
Paul Beckingham
463c968cac Unit Tests - undo.t
- Added unit tests for the undo command, which verify that a task may
  only be undone if a TDB::gc has not occurred.
2009-03-06 00:39:28 -05:00
Paul Beckingham
41b8b207d4 Documentation Update
- Added examples to the grammar file.
- Added recent change to ChangeLog, html/task.html.
2009-03-05 10:13:10 -05:00
Paul Beckingham
9535121c1e Performance
- Removed the unnecessary sort in the 'completed' report.  The tasks
  are already sorted.
2009-03-05 10:08:25 -05:00
Paul Beckingham
9988ecec5e Portability
- Modified util.cpp to allow clean compilation on Solaris.
2009-03-04 09:37:00 -05:00
Paul Beckingham
d573599a7e Unit Tests - subproject
- Implemented unit test to verify that the project and subproject
  filtering is working properly.
2009-03-04 00:04:09 -05:00
Paul Beckingham
d831ab335a Report Column Header
- Added "Number" to the ghistory graph title.
2009-03-03 23:13:31 -05:00
Paul Beckingham
d7a9d06360 Unit Tests - add, bug_hang, bug_period, bug_sort, nag, tag
- Implemented unit tests to verify tag manipulation
- Implemented unit tests to verify nag functionality
- Implemented unit tests to verify bug fix for hang on shadow write
- Implemented unit tests to verify bug fix for unsupported recurrence periods
- Implemented unit tests to verify bug fix for hang on sort
- Corrected typo in add.t
2009-03-03 21:19:07 -05:00
Paul Beckingham
d69d658531 Unit Tests - tag
- Added unit tests to test the +tag and -tag task modification
  feature.
2009-03-03 17:15:40 -05:00
Paul Beckingham
5c89c0f1be Documentation Update
- Modified ChangeLog and task.html to reflect new bug fixes.
2009-03-03 00:53:32 -05:00
Paul Beckingham
964d04322c Bug Fix - nag
- Implemented new nag algorithm, and debugged why it then broke.
2009-03-03 00:46:02 -05:00
Paul Beckingham
8157c729d6 Unit Tests - bug_sort
- Added a unit test to cover the bug whereby certain combinations
  of adding tasks causes Table::sort to loop indefinitely.
2009-03-03 00:08:06 -05:00
Paul Beckingham
a1b7516cf8 Sort Algorithm Fix
- The sort algorithm (Combsort11) was broken because it didn't
  consider all the possible variations of present/missing, same/
  different combinations of data, when performing a compare.  This
  led to an unstable sort, which is an infinite loop in Combsort11.
2009-03-02 23:49:13 -05:00
Paul Beckingham
1e70400143 Shadow File Rewrite
- No longer writes shadow files based on TDB onChange trigger.
- Addressed bug whereby adding a recurring task trigger a shadow
  file rewrite, which in turn performs trigger another rewrite...
2009-03-02 23:47:41 -05:00
Paul Beckingham
6e956b45ad Code Cleanup
- Fixed typo in unit test
2009-03-02 00:44:28 -05:00
Paul Beckingham
59a014d866 Unit Tests - nag
- Added unit tests to exercise the nag option.
2009-03-01 23:52:28 -05:00
Paul Beckingham
76c9d3565c Documentation Update
- Added paragraph tags.  Don't know why, but the rendering was odd.
2009-02-24 22:27:51 -05:00
Paul Beckingham
8c484a333d Documentation Update
- Added folks to AUTHORS file.
- Added Fedora Core 10, Ubuntu 8.10 Intrepid Ibex to compatibility
  list.
2009-02-23 22:59:17 -05:00
Paul Beckingham
0605161236 Updated OS Compatibility List
- Fedora Core 10
- Ubuntu 8.10 Intrepid Ibex
2009-02-23 10:38:01 -05:00
Paul Beckingham
f9272773ac Credit
- Added Carlos Yoder to AUTHORS, for his contribution.
- Added Russell Friesenhahn to AUTHORS, for his contribution.
2009-02-21 17:24:07 -05:00
Paul Beckingham
e2fca47a27 Typo
- Added missing "http://" to "www.samurize.com", at the suggestion
  of Carlos Yoder.
2009-02-20 21:08:39 -05:00
Paul Beckingham
92ba36bdec Unit Tests - add, delete, info, ///
- Began set of high-level integration tests, in Perl.
2009-02-16 23:12:04 -05:00
Paul Beckingham
72efddc066 Sample .taskrc - update
- Added default config variables for new reports.
- Removed README.1.5.0.
- Removed messages configure.ac
2009-02-16 21:35:26 -05:00
Paul Beckingham
bcf512e529 Nag Rewrite
- Now uses a better escalating scale of "importance".
2009-02-16 21:09:00 -05:00
Paul Beckingham
6d551357ff Packaging
- Began modification of script.txt in preparation for next movie!
- Added README.1.5.0 warning to configure.ac.  Do you think people
  will see it?  And then read the file?  I may need to provide an
  automated solution.
2009-02-15 23:44:58 -05:00
Paul Beckingham
0219ed4fe3 Packaging
- Added README.1.5.0 detailing the new custom report configuration
  variables that must be added.
- Added README.1.5.0 to the distribution.
- Added new custom.html documentation.
- Added warning to task.html about the README.1.5.0 changes.
2009-02-15 23:26:15 -05:00
Paul Beckingham
cc7c1819ce Sample .taskrc - update
- Added recent .taskrc file changes to the default file that is created
  when task is run the first time.
2009-02-15 22:45:50 -05:00
Paul Beckingham
1a4469d388 Error handling
- Validates specified columns in custom reports against list of good
  column names.
- Validates list of sort columns in custom reports against list of
  specified column names.
- Minor fix to grammar file.
2009-02-15 22:33:18 -05:00
Paul Beckingham
4e63d93005 Documentation Update
- Added commit ids to ChangeLog
- Added tags to respective commit ids
2009-02-15 16:54:59 -05:00
Paul Beckingham
481a0aa1eb Custom Reports - old reports removed 2009-02-15 15:13:24 -05:00
Paul Beckingham
6764a6a7ec Custom Reports - basic implementation
- Custom reports can be defined and run.
- Custom columns included.
- Custom filter applied.
- Custom sorting applied.
2009-02-15 14:54:54 -05:00
Paul Beckingham
dae268a836 Merge branch '1.5.0' of git@github.com:pbeckingham/task into 1.5.0 2009-02-14 23:18:05 -05:00
Paul Beckingham
096a4b9bdb Bug Fix - split
- Fixed bug in split functions, which was causing empty strings to be
  split into a single element list consisting of one empty string.
  The symptom was that all tasks without tags appeared to have one
  zero-length tag and the task was colored according to color.tagged.
2009-02-14 23:17:35 -05:00
Paul Beckingham
e65a45ce17 Bug Fix
- Fixed bug in split functions, which was causing empty strings to be
  split into a single element list consisting of one empty string.
  The symptom was that all tasks without tags appeared to have one
  zero-length tag and the task was colored according to color.tagged.
2009-02-14 23:13:31 -05:00
Paul Beckingham
01b3cb190c Configuration Variable - due
- Added support for the "due" configuration variable that defines
  how many days into the future when a task is considered due.
2009-02-14 20:19:47 -05:00
Paul Beckingham
6faf1e44f5 Bug Fix - lower case priorities
- Changed a call to isupper to islower.  This was preventing the
  internal modification to upper case.
- Updated ChangeLog accordingly.
2009-02-14 20:04:34 -05:00
Paul Beckingham
2307dcab8a Copyright Update
- bumped the year, on the source copyright notices.
2009-02-14 17:50:38 -05:00
Paul Beckingham
eba05513f7 Unit Tests
- Converted unit tests to use a UnitTest object, with more methods and
  and exit summary.
- Removed "fail" tests in tdb.t.cpp, because it artificially reduces
  the number of passing tests - the comments in the code suffice.
2009-02-14 17:05:50 -05:00
Paul Beckingham
2f7060ce56 Unit Tests
- Fixed long-broken unit tests that were expecting wrong values.
2009-01-31 12:08:03 -05:00
Paul Beckingham
c28c698bbf Cleanup
- Converted grammar.bnf to the EBNF used by Parser.
2009-01-28 12:09:24 -05:00
Paul Beckingham
b55eaf8f16 Cleanup
- renamed grammar.txt to grammar.bnf
2009-01-28 11:51:29 -05:00
Paul Beckingham
3d4beaf41f - Enhanced split algorithm to be non-destrutive, and therefore faster
- Added autoconf testing to detect Solaris
- Added Solaris-specific flock implementation
2008-12-14 15:18:33 -05:00
Paul Beckingham
50ccb67185 - Added builtin command detection
- Now allows override of due/overdue coloration
2008-12-14 11:09:15 -05:00
Paul Beckingham
14d3abacf4 - Beginning to fill out processing of the generalized custom report. 2008-11-19 00:33:43 -05:00
Paul Beckingham
857f813a24 - Added the 1.4.3 debian package from Richard Querin. 2008-11-11 08:54:55 -05:00
Paul Beckingham
5498986e15 - Fixed typo. 2008-11-11 00:27:14 -05:00
Paul Beckingham
eb827603c3 - Final tidying up of 1.4.3 loose ends. 2008-11-11 00:10:14 -05:00
Paul Beckingham
b548342acc - Modified docs to include "shadow.notify". 2008-11-02 23:21:41 -05:00
127 changed files with 10226 additions and 1997 deletions

3
.gitignore vendored
View File

@@ -1,4 +1,3 @@
Makefile.in
aclocal.m4 aclocal.m4
autom4te.cache autom4te.cache
auto.h* auto.h*
@@ -11,3 +10,5 @@ stamp-h1
Makefile Makefile
configure configure
config.log config.log
www.xls
*~

13
AUTHORS
View File

@@ -5,11 +5,16 @@ Contributing Authors:
Damian Glenny Damian Glenny
Andy Lester Andy Lester
H. İbrahim Güngör H. İbrahim Güngör
Stefan Dorn
Michael Greb
Benjamin Tegarden
Chris Pride
Richard Querin
Federico Hernandez
With thanks to: With thanks to:
Eugene Kramer Eugene Kramer
Srijith K Srijith K
Richard Querin
Bruce Israel Bruce Israel
Thomas Engel Thomas Engel
Nishiishii Nishiishii
@@ -18,4 +23,10 @@ With thanks to:
Vincent Fleuranceau Vincent Fleuranceau
T. Charles Yun T. Charles Yun
ArchiMark ArchiMark
Carlos Yoder
Russell Friesenhahn
Paolo Marsi
Eric Farris
Bruce Dillahunty
Askme Too

333
ChangeLog
View File

@@ -1,7 +1,51 @@
------ current release --------------------------- ------ current release ---------------------------
1.5.0 (?) 1.6.0 (4/12/2009)
+ Added support for new "append" command that adds more description text to
an existing task.
+ Added support for the "weekdays" recurrence, which means a task can recur
five times a week, and not on weekends (thanks to Chris Pride).
+ UTF8 text is now supported in task project names, tags and descriptions.
+ Fixed bug that caused the y/n confirmation on task deletion to ignore the
Enter key and fail to re-prompt (thanks to Bruce Dillahunty).
+ When the "echo.command" configuration variable is set to "yes", it causes
commands that modify tasks to display which task was affected (thanks to
Bruce Dillahunty).
+ A task can now be annotated with the command "task <id> annotate ...", and
a timestamped annotation will appear in reports.
+ A 'description_only' column is now available for use in custom reports,
and it excludes annotations.
+ A task can now be upgraded to a recurring task by adding a recurrence
frequency, a due date, and an optional until date.
+ When a recurring task is modified, all other instances of the recurring
task are also modified.
+ Custom reports now support user-specified column labels (thanks to T.
Charles Yun).
+ Task can now import tasks from a variety of data formats, including task
export files from versions 1.4.3 and earlier, versions 1.5.0 and later,
todo.sh 2.x, CSV, plain text and task command line. See online docs for
full details.
+ Export was including 'id' in the column header even though it was not
included in the data.
+ The task file format has changed slightly. Please back up your task
data files before upgrading to 1.6.0.
+ Added new column 'recurrence_indicator' that displays an 'R' if the task
is a recurring task. This column can be added to any custom report.
+ Added new column 'tag_indicator' that displays a '+' if the task
has any tags. This column can be added to any custom report.
+ Fixed bug where sometimes a task description was concatenated oddly if
there was a colon somewhere in the description.
+ Fixed bug that caused recurring annual tasks to exhibit a creeping due
date, because of an assumption of 365 days per year, which failed to
consider leap years (thanks to T. Charles Yun).
+ Annotations can now be modified with the substitution commands /from/to/.
+ Substitutions can now be made global with /from/to/g and all occurrences
of "from" will be replaced with "to".
------ old releases ------------------------------
1.5.0 (3/15/2009)
+ Removed deprecated TUTORIAL file. + Removed deprecated TUTORIAL file.
+ Removed "showage" configuration variable. + Removed "showage" configuration variable.
+ "task stop" can now remove the start time from a started task. + "task stop" can now remove the start time from a started task.
@@ -11,146 +55,175 @@
which may be spelling mistakes or deprecated variables. which may be spelling mistakes or deprecated variables.
+ "configure --enable-debug" now supported to suppress compiler optimization + "configure --enable-debug" now supported to suppress compiler optimization
to allow debugging. to allow debugging.
+ Allow lower case priorities, and automatically upper case them.
+ Added support for "due" configuration variable which defines the number
of days in the future when a task is considered due.
+ Added support for custom reports, comprised of a set of column names and
sort order, with optional filtering in the configuration file. This
means user-defined reports can be written, and the reports currently
in the configuration file can be renamed. Several of task's built in
reports have been converted to user-defined reports.
+ New online documentation for custom reports.
+ New algorithm for determining when the "nag" message is displayed.
+ Fixed bug where task hangs with a certain combination of recurring tasks
and shadow files.
+ Fixed bug with the task sort algorithm, which led to an unstable sequence
when there were only a handful of tasks.
+ Performance enhanced by eliminating unnecessary sorting.
+ Task now has a large (and growing) test suite and bug regression tests
to help ensure higher quality releases.
+ Fixed bug that caused performance hit during table rendering.
+ Fixed bug that concatenated a modified description without spaces.
+ Added new column 'recur' that displays the recurrence period of any
recurring tasks. This column can be added to any custom report.
+ Added support for "color.recurring" configuration variable which
specifies the color of recurring tasks.
+ Added support for "locking" configuration variable that controls whether
file locking is used.
+ Task export feature now includes recurrence information, removes nested
quotes, and limits output to pending tasks.
+ Task no longer includes deleted tasks in the summary report (thanks to
Benjamin Tegarden).
+ Fixed bug that prevented the summary report from properly reporting
recently completed tasks.
------ old releases ------------------------------ 1.4.3 (11/1/2008) 8639e9260646c8c9224e0fc47e5d2443b46eecfc
1.4.3 (11/1/2008)
+ Fixed misleading task count at bottom on "info" report. + Fixed misleading task count at bottom on "info" report.
+ Added support for a shadow file that contains a plain text task report, + Added support for a shadow file that contains a plain text task report,
with the "shadow.file" and "shadow.command" configuration variables with the "shadow.file" and "shadow.command" configuration variables.
The shadow file is automatically updated whenever the task database The shadow file is automatically updated whenever the task database
changes. Useful for integrating with "Samurize" changes. Useful for integrating with "Samurize".
+ Task now displays a message whenever a shadow file is updated, if the + Task now displays a message whenever a shadow file is updated, if the
"shadow.notify" configuration variable is set "on" "shadow.notify" configuration variable is set "on".
+ Bug: adding a task with a \n, \r or \f in it now fails properly + Bug: adding a task with a \n, \r or \f in it now fails properly.
+ Removed "usage" command, and support for "command.logging" configuration + Removed "usage" command, and support for "command.logging" configuration
variable. variable.
+ Added documentation for Shadow files. + Added documentation for Shadow files.
+ Added documentation for task filters. + Added documentation for task filters.
1.4.2 (9/18/2008) 1.4.2 (9/18/2008) e7304e86ce9bb80978c7055fd2a9e999619a6fb8
+ "task undo" can now retract a "task done" command, provided no reports + "task undo" can now retract a "task done" command, provided no reports
have been run (and therefore TDB::gc run) have been run (and therefore TDB::gc run).
+ Task now correctly sorts on entire strings, instead of just the first + Task now correctly sorts on entire strings, instead of just the first
character (thanks to Andy Lester) character (thanks to Andy Lester).
+ Task now uses dashes (-----) to column underlines when color is disabled + Task now uses dashes (-----) to column underlines when color is disabled
(thanks to Vincent Fleuranceau) (thanks to Vincent Fleuranceau).
+ Task now allows mixed case attribute names (pri:, PRI:, Pri: ...) and + Task now allows mixed case attribute names (pri:, PRI:, Pri: ...) and
commands (add, ADD, Add ...) (thanks to Vincent Fleuranceau) commands (add, ADD, Add ...) (thanks to Vincent Fleuranceau).
+ Task now supports a default project and priority for new tasks, via + Task now supports a default project and priority for new tasks, via
the new "default.project" and "default.priority" configuration variables the new "default.project" and "default.priority" configuration variables
(thanks to Vincent Fleuranceau) (thanks to Vincent Fleuranceau).
+ Task supports improved word-wrapping to the terminal width + Task supports improved word-wrapping to the terminal width.
+ Task now supports "default.command" configuration variable (for example + Task now supports "default.command" configuration variable (for example
it could contain "list due:tomorrow") that is the command that is run it could contain "list due:tomorrow") that is the command that is run
whenever task is invoked with no arguments. whenever task is invoked with no arguments.
+ Task supports modifying the existing description of a task, with the + Task supports modifying the existing description of a task, with the
following syntax: task <id> "new description ...". following syntax: task <id> "new description ...".
+ Bug: Now properly supports relative dates in filters (task list due:eom, + Bug: Now properly supports relative dates in filters (task list due:eom,
task list due:tomorrow, task list due:23rd ...) task list due:tomorrow, task list due:23rd ...).
+ Bug: Source now properly includes <string.h> in order to build clean + Bug: Source now properly includes <string.h> in order to build clean
using gcc 4.3 (thanks to H. İbrahim Güngör) using gcc 4.3 (thanks to H. İbrahim Güngör).
1.4.1 (7/18/2008) 1.4.1 (7/18/2008) e080c3168c6064628ab85b21bd859d9875a3a9a7
+ Bug: Descriptions can not be altered with "task 123 New description" + Bug: Descriptions can not be altered with "task 123 New description".
+ Tweak: For "task calendar" month names are now centered over the month + Tweak: For "task calendar" month names are now centered over the month.
+ Removed TUTORIAL file contents in favor of online version + Removed TUTORIAL file contents in favor of online version.
+ Provided Mac .pkg binary + Provided Mac .pkg binary.
1.4.0 (7/10/2008) 1.4.0 (7/10/2008) 60b7d15a1d22e064acf0974c5d7eabbb57dd8071
+ New recurring tasks feature + New recurring tasks feature.
+ "task undelete" can now undelete erroneously deleted tasks, provided no + "task undelete" can now undelete erroneously deleted tasks, provided no
reports have been run (and therefore TDB::gc run) reports have been run (and therefore TDB::gc run).
+ Added averages to the "task history" report + Added averages to the "task history" report.
+ Added ability to override ~/.taskrc with rc:<file> + Added ability to override ~/.taskrc with rc:<file>.
+ Added bar chart history report "task ghistory" + Added bar chart history report "task ghistory".
+ Added task filtering on all reports + Added task filtering on all reports.
+ Automatically shuts off color, curses when output is not a tty + Automatically shuts off color, curses when output is not a tty.
+ Supports relative due: dates (tomorrow, wednesday, 23rd, eom ...) + Supports relative due: dates (tomorrow, wednesday, 23rd, eom ...).
+ Supports the ~ character in .taskrc data.location + Supports the ~ character in .taskrc data.location.
+ Allows colons on the description, provided what is to the left of the colon + Allows colons on the description, provided what is to the left of the colon
is not a standard attribute name is not a standard attribute name.
+ Bug: Fixed where Esc[0m sequences were being emitted for no good reason + Bug: Fixed where Esc[0m sequences were being emitted for no good reason.
+ Bug: Fixed underlined table headers when color is turned off + Bug: Fixed underlined table headers when color is turned off.
+ Bug: Adding a blank priority resulted in an assigned garbage value + Bug: Adding a blank priority resulted in an assigned garbage value.
+ Bug: Fixed parsing of date "07/08/2008" when using dateformat "m/d/Y" + Bug: Fixed parsing of date "07/08/2008" when using dateformat "m/d/Y".
1.3.1 (6/21/2008) 1.3.1 (6/21/2008) 3a6de7d9402f2609a773a73b16eff97b14a32869
+ New configuration variable, "defaultwidth" that determines the width + New configuration variable, "defaultwidth" that determines the width
of tables when ncurses support is not available of tables when ncurses support is not available.
+ Bug: "showage" configuration variable should apply to all reports, not + Bug: "showage" configuration variable should apply to all reports, not
just the ones based on "list" just the ones based on "list".
+ Bug: Fixed segmentation faults on Ubuntu when the "dateformat" + Bug: Fixed segmentation faults on Ubuntu when the "dateformat"
configuration variables was missing. This was a code bug, and should configuration variables was missing. This was a code bug, and should
have affected more platforms have affected more platforms.
+ Bug: Task now will recreate a missing ~/.taskrc file, OR a missing + Bug: Task now will recreate a missing ~/.taskrc file, OR a missing
~/.task directory ~/.task directory.
1.3.0 (6/18/2008) 1.3.0 (6/18/2008) 6673e408a223af98c38779c20b08524042c0edfa
+ "task calendar" now displays multiple months per line, adjustable by the + "task calendar" now displays multiple months per line, adjustable by the
"monthsperline" configuration variable. Feature added by Damian Glenny "monthsperline" configuration variable. Feature added by Damian Glenny.
+ "task export" can now filter tasks like the reports + "task export" can now filter tasks like the reports.
+ Factored out code to filter tasks + Factored out code to filter tasks.
+ Displays shorter message when a command is entered incorrectly, and the + Displays shorter message when a command is entered incorrectly, and the
full usage for "task help" full usage for "task help".
+ "task oldest" shows the oldest tasks + "task oldest" shows the oldest tasks.
+ "task newest" shows the newest tasks + "task newest" shows the newest tasks.
+ Bug: Segmentation fault when no "dateformat" configuration variable + Bug: Segmentation fault when no "dateformat" configuration variable
specified specified.
+ Bug: Fixed bug whereby if you have more than one task with a due date, 7 + Bug: Fixed bug whereby if you have more than one task with a due date, 7
days gets added to the entry date of task 2..n days gets added to the entry date of task 2..n.
+ Bug: Fixed bug whereby "1 wks" was being improperly pluralized + Bug: Fixed bug whereby "1 wks" was being improperly pluralized.
1.2.0 (6/13/2008) 1.2.0 (6/13/2008) c393d47cdfe7e197a31e94f4bb764474fa05ad8d
+ Bug: "dateformat" configuration variable used to display dates, but + Bug: "dateformat" configuration variable used to display dates, but
not parse them not parse them.
+ "task list x" now performs a caseless comparison between "x" and the + "task list x" now performs a caseless comparison between "x" and the
description description.
+ Task sub projects supported + Task sub projects supported.
+ "showage" confguration determines whether "Age" column appears on the + "showage" confguration determines whether "Age" column appears on the
"list" and "next" reports "list" and "next" reports.
+ Improved TUTORIAL + Improved TUTORIAL.
1.1.0 (6/7/2008) 1.1.0 (6/7/2008) 73286e86628725b346db2a25fbcd4bd68efb9b3a
+ "blanklines" configuration to stop displaying unnecessary white + "blanklines" configuration to stop displaying unnecessary white
space and thus work better on small-screen devices space and thus work better on small-screen devices.
+ "dateformat" configuration now determines how dates are formatted + "dateformat" configuration now determines how dates are formatted.
+ Better formatting of "task tags" output + Better formatting of "task tags" output.
+ http://www.beckingham.net/task.html home page set up + http://www.beckingham.net/task.html home page set up.
+ Added tags to the "task long" report + Added tags to the "task long" report.
1.0.1 (6/4/2008) 1.0.1 (6/4/2008) d216d401217027d93581808fc8944ab7d6b85fb0
+ Bug: UUID generator not properly terminating string. + Bug: UUID generator not properly terminating string.
+ Bug: srandom/srand not called prior to UUID generation. + Bug: srandom/srand not called prior to UUID generation.
1.0.0 (6/3/2008) 1.0.0 (6/3/2008) f3de5c07118c597091a05c7d7fe8bdeae95474c1
+ New movie made, uploaded + New movie made, uploaded.
+ Bug: assertion fails on mobile for t v + Bug: assertion fails on mobile for t v.
+ Bug: configure.ac does not properly determine ncurses availability + Bug: configure.ac does not properly determine ncurses availability.
+ Bug: Cannot seem to use the percent character in a task description + Bug: Cannot seem to use the percent character in a task description.
+ Bug: New installation "task stats" reports newest task 12/31/1969 + Bug: New installation "task stats" reports newest task 12/31/1969.
+ Bug: New installation task projects displays header but no data - should short-circuit + Bug: New installation task projects displays header but no data - should short-circuit.
+ Bug: incorrect color specification in sample .taskrc file + Bug: incorrect color specification in sample .taskrc file.
+ Bug: when run without arguments, task dumps core on Solaris 10 + Bug: when run without arguments, task dumps core on Solaris 10.
+ "task calendar" now reports all months with due pending tasks + "task calendar" now reports all months with due pending tasks.
+ Added rules for colorization by tag, project and keyword + Added rules for colorization by tag, project and keyword.
+ Added legend to "task calendar" + Added legend to "task calendar".
0.9.9 (5/27/2008) 0.9.9 (5/27/2008) 2ecf50032226c91b406f247417a063dc17c8e324
+ Autoconf/automake behaving properly. + Autoconf/automake behaving properly.
+ Clean build on OS X 10.5. + Clean build on OS X 10.5.
+ Clean build on Ubuntu 8.0. + Clean build on Ubuntu 8.0.
+ Clean build on Fedora Core 8. + Clean build on Fedora Core 8.
+ Clean build on Fedora Core 9. + Clean build on Fedora Core 9.
0.9.8 (5/25/2008) 0.9.8 (5/25/2008) 18fd59a1edb20e5c68d086a97fae5fa9f6bb348a
+ Added "task color" command. + Added "task color" command.
+ Removed unnecessary files. + Removed unnecessary files.
+ Completed documentation. + Completed documentation.
0.9.7 (5/24/2008) 0.9.7 (5/24/2008) 25dc4150947a3e612c8118838d04b3bbe68441f7
+ Migrated old compiler flags into Makefile.am + Migrated old compiler flags into Makefile.am.
+ Added ncurses endwin function check to configure.ac + Added ncurses endwin function check to configure.ac.
+ Set up structure for AUTHORS file. + Set up structure for AUTHORS file.
+ Set up NEWS file, with pleas for feedback. + Set up NEWS file, with pleas for feedback.
+ Added welcome message to README. + Added welcome message to README.
@@ -161,31 +234,31 @@
+ Removed unnecessary SAMPLE_taskrc, and assorted references. + Removed unnecessary SAMPLE_taskrc, and assorted references.
+ Cleaned up ChangeLog. + Cleaned up ChangeLog.
+ Minor mods to standard docs. + Minor mods to standard docs.
+ Bumped version to 0.9.7 + Bumped version to 0.9.7.
+ Changed some autoconf details + Changed some autoconf details.
+ Corrected comment in T.cpp + Corrected comment in T.cpp.
+ Made unit tests compile and run again. + Made unit tests compile and run again.
+ Removed tests from distibution. + Removed tests from distibution.
0.9.6 (5/13/208) 0.9.6 (5/13/208)
+ Corrected wrong include file in Table.cpp + Corrected wrong include file in Table.cpp.
+ Replaced color management code. + Replaced color management code.
+ Improved color rules code. + Improved color rules code.
0.9.5 (5/12/2008) 0.9.5 (5/12/2008)
+ Replaced Table storage with Grid. + Replaced Table storage with Grid.
+ Added Grid.cpp to configure.ac + Added Grid.cpp to configure.ac.
+ Added Makefile to src/.gitignore + Added Makefile to src/.gitignore.
+ Makefile should not be part of the repository. + Makefile should not be part of the repository.
+ Added Grid.cpp + Added Grid.cpp.
+ Added Grid::Cell::operator== + Added Grid::Cell::operator==.
+ ChangeLog file begun. + ChangeLog file begun.
+ Bumped version to 0.9.5 for next release. + Bumped version to 0.9.5 for next release.
0.9.4 (4/26/2008) 0.9.4 (4/26/2008)
+ Integrated new Grid object into build - not yet integrated into Table. + Integrated new Grid object into build - not yet integrated into Table.
+ More .gitignore tweaks. + More .gitignore tweaks.
+ Added .gitignore + Added .gitignore.
+ Added more missing files. + Added more missing files.
+ Added all source code. + Added all source code.
+ Generic OSS files added. + Generic OSS files added.
@@ -206,29 +279,29 @@
+ Consolidated header files, removed unnecessary ones. + Consolidated header files, removed unnecessary ones.
0.9.0 (3/23/2008) 0.9.0 (3/23/2008)
+ flat source directory + flat source directory.
+ autoconf complete + autoconf complete.
+ "task next" + "task next".
+ "task stats" + "task stats".
+ "task export" + "task export".
+ Rules-based colorization + Rules-based colorization.
0.8.1 (1/28/2008) - 0.8.16 (3/13/2008) 0.8.1 (1/28/2008) - 0.8.16 (3/13/2008)
+ autoconf conversion (many builds) + autoconf conversion (many builds).
0.8.0 Polish (1/25/2008) 0.8.0 Polish (1/25/2008)
+ Code cleanup, reorganization + Code cleanup, reorganization.
+ "task overdue" + "task overdue".
+ Add "age" column to list and long + Add "age" column to list and long.
+ Use 'conf' for build, version tracking + Use 'conf' for build, version tracking.
+ Add "/from/to/" description editing + Add "/from/to/" description editing.
0.7.0 Multi-user, File handling, atomicity (1/8/2008) 0.7.0 Multi-user, File handling, atomicity (1/8/2008)
+ Clean, publishable API reimplementation + Clean, publishable API reimplementation.
+ File locking + File locking.
+ retain deleted tasks + retain deleted tasks.
+ "task info ID" report showing all metadata + "task info ID" report showing all metadata.
+ File format v2, including UUID + File format v2, including UUID.
[Development hiatus while planning for T, TDB API, new features and the future [Development hiatus while planning for T, TDB API, new features and the future
of the project. Seeded to two testers for feedback, suggestions. Development of the project. Seeded to two testers for feedback, suggestions. Development
@@ -236,40 +309,40 @@ deliberately stopped to allow extended use of task, allowing command logging and
regular usage to determine which features were needed or unnecessary.] regular usage to determine which features were needed or unnecessary.]
0.6.0 Reports (12/27/2006) 0.6.0 Reports (12/27/2006)
+ "task history" + "task history".
+ "task summary" + "task summary".
+ "task calendar" + "task calendar".
+ due support + due support.
+ Table sorting + Table sorting.
0.5.0 Multi-user support (12/10/2006) 0.5.0 Multi-user support (12/10/2006)
+ Command logging + Command logging.
+ "task usage" report + "task usage" report.
0.4.0 Destructive / modification commands (12/3/2006) 0.4.0 Destructive / modification commands (12/3/2006)
+ "task delete" complete + "task delete" complete.
+ "task id ..." complete + "task id ..." complete.
+ "task list ..." synonym for "task find ..." + "task list ..." synonym for "task find ...".
0.3.0 Work in progress support (12/3/2006) 0.3.0 Work in progress support (12/3/2006)
+ "task start" complete + "task start" complete.
+ "task done" complete + "task done" complete.
+ completed.data support + completed.data support.
0.2.0 Neutral commands (12/2/2006) 0.2.0 Neutral commands (12/2/2006)
+ "task find" complete + "task find" complete.
+ "task projects" complete + "task projects" complete.
+ "task tags" complete + "task tags" complete.
0.1.0 Constructive commands (12/1/2006) 0.1.0 Constructive commands (12/1/2006)
+ "task add" complete + "task add" complete.
+ completed.data support + completed.data support.
+ ~/.taskrc support + ~/.taskrc support.
0.0.1 Basic infrastructure (11/29/2006) 0.0.1 Basic infrastructure (11/29/2006)
+ Command line parsing + Command line parsing.
+ API layer + API layer.
+ Usage + Usage.
------ start ----------------------------------- ------ start -----------------------------------

595
Makefile.in Normal file
View File

@@ -0,0 +1,595 @@
# Makefile.in generated by automake 1.10 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
subdir = .
DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in $(srcdir)/auto.h.in \
$(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \
depcomp install-sh missing
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
configure.lineno config.status.lineno
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = auto.h
CONFIG_CLEAN_FILES =
SOURCES =
DIST_SOURCES =
RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
html-recursive info-recursive install-data-recursive \
install-dvi-recursive install-exec-recursive \
install-html-recursive install-info-recursive \
install-pdf-recursive install-ps-recursive install-recursive \
installcheck-recursive installdirs-recursive pdf-recursive \
ps-recursive uninstall-recursive
RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
distclean-recursive maintainer-clean-recursive
ETAGS = etags
CTAGS = ctags
DIST_SUBDIRS = $(SUBDIRS)
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
am__remove_distdir = \
{ test ! -d $(distdir) \
|| { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
&& rm -fr $(distdir); }; }
DIST_ARCHIVES = $(distdir).tar.gz
GZIP_ENV = --best
distuninstallcheck_listfiles = find . -type f -print
distcleancheck_listfiles = find . -type f -print
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
GREP = @GREP@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LTLIBOBJS = @LTLIBOBJS@
MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build_alias = @build_alias@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host_alias = @host_alias@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
SUBDIRS = src
EXTRA_DIST = DEVELOPERS
all: auto.h
$(MAKE) $(AM_MAKEFLAGS) all-recursive
.SUFFIXES:
am--refresh:
@:
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \
cd $(srcdir) && $(AUTOMAKE) --gnu \
&& exit 0; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
cd $(top_srcdir) && \
$(AUTOMAKE) --gnu Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
echo ' $(SHELL) ./config.status'; \
$(SHELL) ./config.status;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
$(SHELL) ./config.status --recheck
$(top_srcdir)/configure: $(am__configure_deps)
cd $(srcdir) && $(AUTOCONF)
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
auto.h: stamp-h1
@if test ! -f $@; then \
rm -f stamp-h1; \
$(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
else :; fi
stamp-h1: $(srcdir)/auto.h.in $(top_builddir)/config.status
@rm -f stamp-h1
cd $(top_builddir) && $(SHELL) ./config.status auto.h
$(srcdir)/auto.h.in: $(am__configure_deps)
cd $(top_srcdir) && $(AUTOHEADER)
rm -f stamp-h1
touch $@
distclean-hdr:
-rm -f auto.h stamp-h1
# This directory's subdirectories are mostly independent; you can cd
# into them and run `make' without going through this Makefile.
# To change the values of `make' variables: instead of editing Makefiles,
# (1) if the variable is set in `config.status', edit `config.status'
# (which will cause the Makefiles to be regenerated when you run `make');
# (2) otherwise, pass the desired values on the `make' command line.
$(RECURSIVE_TARGETS):
@failcom='exit 1'; \
for f in x $$MAKEFLAGS; do \
case $$f in \
*=* | --[!k]*);; \
*k*) failcom='fail=yes';; \
esac; \
done; \
dot_seen=no; \
target=`echo $@ | sed s/-recursive//`; \
list='$(SUBDIRS)'; for subdir in $$list; do \
echo "Making $$target in $$subdir"; \
if test "$$subdir" = "."; then \
dot_seen=yes; \
local_target="$$target-am"; \
else \
local_target="$$target"; \
fi; \
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|| eval $$failcom; \
done; \
if test "$$dot_seen" = "no"; then \
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
fi; test -z "$$fail"
$(RECURSIVE_CLEAN_TARGETS):
@failcom='exit 1'; \
for f in x $$MAKEFLAGS; do \
case $$f in \
*=* | --[!k]*);; \
*k*) failcom='fail=yes';; \
esac; \
done; \
dot_seen=no; \
case "$@" in \
distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
*) list='$(SUBDIRS)' ;; \
esac; \
rev=''; for subdir in $$list; do \
if test "$$subdir" = "."; then :; else \
rev="$$subdir $$rev"; \
fi; \
done; \
rev="$$rev ."; \
target=`echo $@ | sed s/-recursive//`; \
for subdir in $$rev; do \
echo "Making $$target in $$subdir"; \
if test "$$subdir" = "."; then \
local_target="$$target-am"; \
else \
local_target="$$target"; \
fi; \
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|| eval $$failcom; \
done && test -z "$$fail"
tags-recursive:
list='$(SUBDIRS)'; for subdir in $$list; do \
test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
done
ctags-recursive:
list='$(SUBDIRS)'; for subdir in $$list; do \
test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
done
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: tags-recursive $(HEADERS) $(SOURCES) auto.h.in $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
here=`pwd`; \
if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
include_option=--etags-include; \
empty_fix=.; \
else \
include_option=--include; \
empty_fix=; \
fi; \
list='$(SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
test ! -f $$subdir/TAGS || \
tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
fi; \
done; \
list='$(SOURCES) $(HEADERS) auto.h.in $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$tags $$unique; \
fi
ctags: CTAGS
CTAGS: ctags-recursive $(HEADERS) $(SOURCES) auto.h.in $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) auto.h.in $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$tags $$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& cd $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) $$here
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
$(am__remove_distdir)
test -d $(distdir) || mkdir $(distdir)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
fi; \
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
else \
test -f $(distdir)/$$file \
|| cp -p $$d/$$file $(distdir)/$$file \
|| exit 1; \
fi; \
done
list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
test -d "$(distdir)/$$subdir" \
|| $(MKDIR_P) "$(distdir)/$$subdir" \
|| exit 1; \
distdir=`$(am__cd) $(distdir) && pwd`; \
top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
(cd $$subdir && \
$(MAKE) $(AM_MAKEFLAGS) \
top_distdir="$$top_distdir" \
distdir="$$distdir/$$subdir" \
am__remove_distdir=: \
am__skip_length_check=: \
distdir) \
|| exit 1; \
fi; \
done
-find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|| chmod -R a+r $(distdir)
dist-gzip: distdir
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
$(am__remove_distdir)
dist-bzip2: distdir
tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
$(am__remove_distdir)
dist-tarZ: distdir
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
$(am__remove_distdir)
dist-shar: distdir
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
$(am__remove_distdir)
dist-zip: distdir
-rm -f $(distdir).zip
zip -rq $(distdir).zip $(distdir)
$(am__remove_distdir)
dist dist-all: distdir
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
$(am__remove_distdir)
# This target untars the dist file and tries a VPATH configuration. Then
# it guarantees that the distribution is self-contained by making another
# tarfile.
distcheck: dist
case '$(DIST_ARCHIVES)' in \
*.tar.gz*) \
GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
*.tar.bz2*) \
bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
*.tar.Z*) \
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
*.shar.gz*) \
GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
*.zip*) \
unzip $(distdir).zip ;;\
esac
chmod -R a-w $(distdir); chmod a+w $(distdir)
mkdir $(distdir)/_build
mkdir $(distdir)/_inst
chmod a-w $(distdir)
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
&& cd $(distdir)/_build \
&& ../configure --srcdir=.. --prefix="$$dc_install_base" \
$(DISTCHECK_CONFIGURE_FLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
&& $(MAKE) $(AM_MAKEFLAGS) check \
&& $(MAKE) $(AM_MAKEFLAGS) install \
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
&& $(MAKE) $(AM_MAKEFLAGS) uninstall \
&& $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
distuninstallcheck \
&& chmod -R a-w "$$dc_install_base" \
&& ({ \
(cd ../.. && umask 077 && mkdir "$$dc_destdir") \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
} || { rm -rf "$$dc_destdir"; exit 1; }) \
&& rm -rf "$$dc_destdir" \
&& $(MAKE) $(AM_MAKEFLAGS) dist \
&& rm -rf $(DIST_ARCHIVES) \
&& $(MAKE) $(AM_MAKEFLAGS) distcleancheck
$(am__remove_distdir)
@(echo "$(distdir) archives ready for distribution: "; \
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
distuninstallcheck:
@cd $(distuninstallcheck_dir) \
&& test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
|| { echo "ERROR: files left after uninstall:" ; \
if test -n "$(DESTDIR)"; then \
echo " (check DESTDIR support)"; \
fi ; \
$(distuninstallcheck_listfiles) ; \
exit 1; } >&2
distcleancheck: distclean
@if test '$(srcdir)' = . ; then \
echo "ERROR: distcleancheck can only run from a VPATH build" ; \
exit 1 ; \
fi
@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
|| { echo "ERROR: files left in build directory after distclean:" ; \
$(distcleancheck_listfiles) ; \
exit 1; } >&2
check-am: all-am
check: check-recursive
all-am: Makefile auto.h
installdirs: installdirs-recursive
installdirs-am:
install: install-recursive
install-exec: install-exec-recursive
install-data: install-data-recursive
uninstall: uninstall-recursive
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-recursive
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-recursive
clean-am: clean-generic mostlyclean-am
distclean: distclean-recursive
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -f Makefile
distclean-am: clean-am distclean-generic distclean-hdr distclean-tags
dvi: dvi-recursive
dvi-am:
html: html-recursive
info: info-recursive
info-am:
install-data-am:
install-dvi: install-dvi-recursive
install-exec-am:
install-html: install-html-recursive
install-info: install-info-recursive
install-man:
install-pdf: install-pdf-recursive
install-ps: install-ps-recursive
installcheck-am:
maintainer-clean: maintainer-clean-recursive
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -rf $(top_srcdir)/autom4te.cache
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-recursive
mostlyclean-am: mostlyclean-generic
pdf: pdf-recursive
pdf-am:
ps: ps-recursive
ps-am:
uninstall-am:
.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \
install-strip
.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
all all-am am--refresh check check-am clean clean-generic \
ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \
dist-shar dist-tarZ dist-zip distcheck distclean \
distclean-generic distclean-hdr distclean-tags distcleancheck \
distdir distuninstallcheck dvi dvi-am html html-am info \
info-am install install-am install-data install-data-am \
install-dvi install-dvi-am install-exec install-exec-am \
install-html install-html-am install-info install-info-am \
install-man install-pdf install-pdf-am install-ps \
install-ps-am install-strip installcheck installcheck-am \
installdirs installdirs-am maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
pdf-am ps ps-am tags tags-recursive uninstall uninstall-am
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

7
NEWS
View File

@@ -1,4 +1,4 @@
Welcome to Task 1.5.0. Welcome to Task 1.6.0.
Task has been built and tested on the following configurations: Task has been built and tested on the following configurations:
@@ -6,8 +6,11 @@ Task has been built and tested on the following configurations:
- OS X 10.5 Leopard - OS X 10.5 Leopard
- Fedora Core 8 - Fedora Core 8
- Fedora Core 9 - Fedora Core 9
- Fedora Core 10
- Ubuntu 7 Feisty Fawn
- Ubuntu 8 Hardy Heron - Ubuntu 8 Hardy Heron
- Ubuntu 9 Feisty Fawn - Ubuntu 8.10 Intrepid Ibex
- Ubuntu 9.04 Jaunty Jackalope (beta)
- Solaris 10 - Solaris 10
- Cygwin 1.5.25-14 - Cygwin 1.5.25-14

View File

@@ -2,8 +2,7 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61) AC_PREREQ(2.61)
AC_INIT(task, 1.5.0, bugs@beckingham.net) AC_INIT(task, 1.6.0, bugs@beckingham.net)
CFLAGS="${CFLAGS=}" CFLAGS="${CFLAGS=}"
CXXFLAGS="${CXXFLAGS=}" CXXFLAGS="${CXXFLAGS=}"
@@ -15,16 +14,23 @@ debug_default="yes"
AC_ARG_ENABLE(debug, [ --enable-debug=[no/yes] turn on debugging AC_ARG_ENABLE(debug, [ --enable-debug=[no/yes] turn on debugging
[default=$debug_default]],, enable_debug=$debug_default) [default=$debug_default]],, enable_debug=$debug_default)
# Yes, shell scripts can be used # Yes, shell scripts can be used
if test "x$enable_debug" = "xyes"; then if test "$enable_debug" = "yes"; then
CFLAGS="$CFLAGS -Wall -pedantic -ggdb3 -DDEBUG" CXXFLAGS="$CFLAGS -Wall -pedantic -ggdb3 -DDEBUG"
CXXFLAGS="$CFLAGS -Wall -pedantic -ggdb3 -DDEBUG" AC_MSG_RESULT(yes)
AC_MSG_RESULT(yes)
else else
CFLAGS="$CFLAGS -O3" CXXFLAGS="$CFLAGS -Wall -pedantic -O3"
CXXFLAGS="$CFLAGS -O3" AC_MSG_RESULT(no)
AC_MSG_RESULT(no)
fi fi
# Check for OS.
OS=`uname|sed -e 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'`
if test "$OS" = "sunos"; then
AC_MSG_NOTICE([OS Solaris detected])
AC_DEFINE([SOLARIS], [], [Compiling on Solaris])
else
AC_MSG_NOTICE([OS Non-Solaris detected])
AC_DEFINE([LINUX], [], [Compiling on Non-Solaris])
fi
AM_INIT_AUTOMAKE AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([src/task.cpp]) AC_CONFIG_SRCDIR([src/task.cpp])
@@ -39,7 +45,6 @@ AC_SUBST(CFLAGS)
# Checks for libraries. # Checks for libraries.
AC_CHECK_LIB(ncurses,initscr) AC_CHECK_LIB(ncurses,initscr)
AC_CHECK_LIB(ncurses,endwin)
# Checks for header files. # Checks for header files.
AC_HEADER_STDC AC_HEADER_STDC
@@ -58,10 +63,11 @@ AC_STRUCT_TM
AC_FUNC_MKTIME AC_FUNC_MKTIME
AC_FUNC_SELECT_ARGTYPES AC_FUNC_SELECT_ARGTYPES
AC_CHECK_FUNCS([select]) AC_CHECK_FUNCS([select])
AC_CHECK_FUNC(flock, [AC_DEFINE([HAVE_FLOCK], [1], [Found flock])]) #AC_CHECK_FUNC(flock, [AC_DEFINE([HAVE_FLOCK], [1], [Found flock])])
AC_CHECK_FUNC(uuid_unparse_lower, [AC_DEFINE([HAVE_UUID], [1], [Found uuid_unparse_lower])]) AC_CHECK_FUNC(uuid_unparse_lower, [AC_DEFINE([HAVE_UUID], [1], [Found uuid_unparse_lower])])
AC_CHECK_FUNC(random, [AC_DEFINE([HAVE_RANDOM], [1], [Found random])]) AC_CHECK_FUNC(random, [AC_DEFINE([HAVE_RANDOM], [1], [Found random])])
AC_CHECK_FUNC(srandom, [AC_DEFINE([HAVE_SRANDOM], [1], [Found srandom])]) AC_CHECK_FUNC(srandom, [AC_DEFINE([HAVE_SRANDOM], [1], [Found srandom])])
AC_CONFIG_FILES([Makefile src/Makefile]) AC_CONFIG_FILES([Makefile src/Makefile])
AC_OUTPUT AC_OUTPUT

40
grammar.bnf Normal file
View File

@@ -0,0 +1,40 @@
# This is a full BNF grammar for the task command line. It is intended that a
# future release of task will incorporate a complete lexer/parser implementing
# this grammar, which will allow for more sophisticated command lines, for
# example:
#
# task delete 1 2 4-7
# task add pri:H pro:X -- pro pri 1 ///
#
command ::= simple_command
| filter_command filter?
| id_command
| "export" file
| <id>
| <id> <substitution> ;
simple_command ::= "version" | "help" | "projects" | "tags" | "next" | "stats"
| "color" ;
filter_command ::= "summary" | "history" | "calendar" | "active" | "overdue"
| "oldest" | "newest" | "add" | "list" | "long" | "ls"
| "completed" ;
id_command ::= "delete" | "undelete" | "info" | "start" | "end" | "done"
| "undo" ;
filter ::= filter_part+ ;
filter_part ::= tag_add | tag_remove | attribute | word ;
tag_add ::= "+" word ;
tag_remove ::= "-" word ;
attribute ::= word ":" word ;
word ::=
file ::=
id ::= digit+ ;
digit ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
substitution ::= "/" word+ "/" word* "/" "g"? ;

View File

@@ -1,69 +0,0 @@
This is a full BNF grammar for the task command line. It is intended that a
future release of task will incorporate a complete lexer/parser implementing
this grammar.
command:
VERSION
| HELP
| PROJECTS
| TAGS
| SUMMARY
| HISTORY
| NEXT
| CALENDAR
| ACTIVE
| OVERDUE
| STATS
| USAGE
| OLDEST
| NEWEST
| EXPORT <file>
| COLOR
| DELETE <id>
| UNDELETE <id>
| INFO <id>
| START <id>
| DONE <id>
| ADD [<tags>] [<attrs>] [<desc>]
| LIST [<tags>] [<attrs>] [<desc>]
| LONG [<tags>] [<attrs>] [<desc>]
| LS [<tags>] [<attrs>] [<desc>]
| COMPLETED [<tags>] [<attrs>] [<desc>]
| <id> [<tags>] [<attrs>] [<desc>]
| <id> <substitution>
id:
\d+
| \d{8}-\d{4}-\d{4}-\d{12}
tags:
+<tag>
| -<tag>
tag:
\w+
attrs:
<attr>
| <attr> <attrs>
attr:
<name>:<value>
name:
\w+
value:
.+
substitution:
/ <pattern> / <pattern> /
pattern:
.+
file:
?

View File

@@ -80,7 +80,7 @@ No matches</code></pre>
<br /> <br />
<div class="content"> <div class="content">
<p> <p>
Copyright 2006-2008, P. Beckingham. All rights reserved. Copyright 2006-2009, P. Beckingham. All rights reserved.
</p> </p>
</div> </div>

View File

@@ -97,6 +97,30 @@ Car 2 2 wks 25% XXXXXXXXX</code></pre>
indicating that percentage. indicating that percentage.
</p> </p>
<strong>% task &lt;id&gt; append ...</strong>
<p>
Appends the additional description to an existing task.
</p>
<strong>% task annotate &lt;id&gt; additional note...</strong>
<p>
Allows an annotation to be attached to an existing task. Each
annotation has a time stamp, and when displayed, the annotations
are shown under the task description. For example:
</p>
<pre><code>% task add Go to the supermarket
% task annotate 1 need milk
% task ls
ID Project Pri Due Active Age Description
1 Go to the supermarket
3/23/2009 need milk</code></pre>
<p>
The date of the annotation uses the "dateformat" configuration
variable.
</p>
<strong>% task delete &lt;id&gt;</strong> <strong>% task delete &lt;id&gt;</strong>
<p> <p>
There are two ways of getting rid of tasks - mark them as done, or There are two ways of getting rid of tasks - mark them as done, or
@@ -120,6 +144,13 @@ Car 2 2 wks 25% XXXXXXXXX</code></pre>
This is how a task is marked as done. This is how a task is marked as done.
</p> </p>
<strong>% task undo &lt;id&gt;</strong>
<p>
If a task was recently marked as done, and no report has been run, it
may be possible to cancel the completed status of the task as though
"task done ..." was never run.
</p>
<strong>% task list ...</strong> <strong>% task list ...</strong>
<p> <p>
The list report will show the active status, and age of the task in The list report will show the active status, and age of the task in
@@ -258,7 +289,7 @@ ID Project Pri Description
set via the "newest" configuration variable. set via the "newest" configuration variable.
</p> </p>
<strong>% task /from/to/</strong> <strong>% task &lt;id&gt; /from/to/</strong>
<p> <p>
If a task has been entered with a typo, it can be easily corrected If a task has been entered with a typo, it can be easily corrected
by this command. For example: by this command. For example:
@@ -278,7 +309,20 @@ ID Project Pri Description
...</code></pre> ...</code></pre>
<p> <p>
This command makes single corrections to a task description. This command makes a single correction to the first occurrence of
"from" in a task description.
</p>
<p>
If a task is annotated, the annotation can also be modified using
this command.
</p>
<strong>% task &lt;id&gt; /from/to/g</strong>
<p>
The "g" modifier to the substitution command causes every occurrence
of "from" to be replaced with "to", in both the description and any
annotations.
</p> </p>
<strong>% task tags</strong> <strong>% task tags</strong>
@@ -398,7 +442,7 @@ on_white on_bright_white</code></pre>
<br /> <br />
<div class="content"> <div class="content">
<p> <p>
Copyright 2006-2008, P. Beckingham. All rights reserved. Copyright 2006-2009, P. Beckingham. All rights reserved.
</p> </p>
</div> </div>

View File

@@ -77,7 +77,7 @@ on_white on_bright_white</code></pre>
<br /> <br />
<div class="content"> <div class="content">
<p> <p>
Copyright 2006-2008, P. Beckingham. All rights reserved. Copyright 2006-2009, P. Beckingham. All rights reserved.
</p> </p>
</div> </div>

View File

@@ -58,6 +58,13 @@
confirmation before deleting a task. confirmation before deleting a task.
</dd> </dd>
<dt>echo.command</dt>
<dd>
May be "yes" or "no", and causes task to display the ID and
description of any task when you run the start, stop, do, undo,
delete and undelete commands. The default value is "yes".
</dd>
<dt>nag</dt> <dt>nag</dt>
<dd> <dd>
This may be a string of text, or blank. It is used as a prompt This may be a string of text, or blank. It is used as a prompt
@@ -174,19 +181,9 @@
<dt>monthsperline</dt> <dt>monthsperline</dt>
<dd> <dd>
Determines how many months the "task calendar" command Determines how many months the "task calendar" command
renders across the screen. Defaults to 1. renders across the screen. Defaults to however many will
</dd> fit. If more months that will fit are specified, task will
only show as many that will fit.
<dt>oldest</dt>
<dd>
Determines how many tasks the "task oldest" command displays.
Defaults to 10.
</dd>
<dt>newest</dt>
<dd>
Determines how many tasks the "task newest" command displays.
Defaults to 10.
</dd> </dd>
<dt>defaultwidth</dt> <dt>defaultwidth</dt>
@@ -195,6 +192,14 @@
Defaults to 80. Defaults to 80.
</dd> </dd>
<dt>due</dt>
<dd>
This is the number of days into the future that define when a
task is considered due, and is colored accordingly.
Defaults to 7.
</dd>
<dt>color</dt> <dt>color</dt>
<dd> <dd>
May be "on" or "off". Determines whether task uses color. May be "on" or "off". Determines whether task uses color.
@@ -210,7 +215,8 @@
color.pri.L<br /> color.pri.L<br />
color.pri.none<br /> color.pri.none<br />
color.active<br /> color.active<br />
color.tagged color.tagged<br />
color.recurring
</dt> </dt>
<dd> <dd>
These are the coloration rules. They correspond to a particular These are the coloration rules. They correspond to a particular
@@ -316,6 +322,43 @@ ID Project Pri Description
whenever the shadow file is updated by some task command. whenever the shadow file is updated by some task command.
</dd> </dd>
<dt>locking</dt>
<dd>
<p>
Determines whether task uses file locking when accessing the pending.data
and completed.data files. Default to "on". Solaris users who store
the task data files on an NFS mount may need to set locking to "off".
</p>
<p>
Note that setting this value to "off" is dangerous. It means that
another program may write to the task.pending file when task is
attempting to do the same.
</p>
</dd>
<dt>import.synonym.id</dt>
<dt>import.synonym.uuid</dt>
<dt>import.synonym.status</dt>
<dt>import.synonym.tags</dt>
<dt>import.synonym.entry</dt>
<dt>import.synonym.start</dt>
<dt>import.synonym.due</dt>
<dt>import.synonym.recur</dt>
<dt>import.synonym.end</dt>
<dt>import.synonym.project</dt>
<dt>import.synonym.priority</dt>
<dt>import.synonym.fg</dt>
<dt>import.synonym.bg</dt>
<dt>import.synonym.description</dt>
<dd>
If any of these configuration variables are found, they influence
data import by specifying a single additional field name synonym.
If a data import is failing because certain column names are not
being recognized, then this is how the field mapping can be
controlled.
</dd>
<p> <p>
Note that the command: Note that the command:
</p> </p>
@@ -326,13 +369,15 @@ ID Project Pri Description
will display the configuration variables found in the .taskrc file, will display the configuration variables found in the .taskrc file,
and will warn you of any variables that are not recognized. and will warn you of any variables that are not recognized.
</p> </p>
</div> </div>
<br /> <br />
<br /> <br />
<div class="content"> <div class="content">
<p> <p>
Copyright 2006-2008, P. Beckingham. All rights reserved. Copyright 2006-2009, P. Beckingham. All rights reserved.
</p> </p>
</div> </div>

179
html/custom.html Normal file
View File

@@ -0,0 +1,179 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Custom Reports</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="usage.html">Usage</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title">Custom Reports</h2>
<div class="content">
<p>
Task allows you to customize reports, to a limited degree.
The "list", "long", "ls", "oldest" and "newest" reports are
all now custom reports, whereas in previous releases of task
they were not mutable. This means they can be modified,
renamed, or deleted.
</p>
<p>
More importantly, you can define your own. Here are the
three necessary items in the .taskrc file that define a new
report:
</p>
<code><pre>report.mine.description=Just the essentials
report.mine.columns=id,project,priority,description
report.mine.sort=priority-,project+</pre></code>
<p>
This defines a report, called "mine", that has four columns:
id, project, priority and description. It will be sorted on
two columns: by descending priority then ascending project.
The description that shows up in the task command usage page
is "Just the essentials". Because this report is called
"mine", it can be run with the command:
</p>
<code><pre>% task mine</pre></code>
<p>
An optional filter can also be specified like this:
</p>
<code><pre>report.mine.filter=priority:H +bug</pre></code>
<p>
This adds a filter so that only tasks with priority "H" and
with the "bug" tag are included in the report. This filter
definition is optional.
</p>
<p>
An optional limit can also be specified, which limits the
number of tasks shown in the report. If a limit is not
specified, then the number of tasks is not limited.
</p>
<code><pre>report.mine.limit=10</pre></code>
<p>
Here is a list of all the possible columns that may be included
in a report:
</p>
<p>
It is also possible to override the default columns names, if
the following line is added to your .taskrc file:
</p>
<pre><code>report.mine.labels=ID,Project,Priority,Description of task</code></pre>
<p>
Note that there must be the same number of labels as there are
columns to label, and they must appear in the same sequence.
</p>
<ul>
<li>id
<li>uuid
<li>project
<li>priority
<li>entry
<li>start
<li>due
<li>age
<li>active
<li>tags
<li>recur
<li>description_only
<li>description
<li>tag_indicator
<li>recurrence_indicator
</ul>
<p>
Custom reports will show up in the task command line usage.
</p>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View File

@@ -110,7 +110,7 @@
<br /> <br />
<div class="content"> <div class="content">
<p> <p>
Copyright 2006-2008, P. Beckingham. All rights reserved. Copyright 2006-2009, P. Beckingham. All rights reserved.
</p> </p>
</div> </div>

175
html/faq.html Normal file
View File

@@ -0,0 +1,175 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Frequently Asked Questions</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="usage.html">Usage</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title">Frequently Asked Questions</h2>
<div class="content">
<p>
(Actually, that's a misnomer. These are really Repeatedly Asked
Questions.)
</p>
<p>
<b>
Q: When I redirect the output of task to a file, I lose all
the colors. How do I fix this?
</b>
<br />
A: Task knows (or thinks it knows) when the output is not going
directly to a terminal, and strips out all the color control
characters. Prevent this with the following entry in your
.taskrc file:
<pre><code>_forcecolor=on</code></pre>
</p>
<hr>
<p>
<b>
Q: How do I backup my task data files? Where are they?
</b>
<br />
A: Task writes all pending tasks to the file ~/.task/pending.data
and all completed and deleted tasks to ~/.task/completed.data.
They are text files, so they can just be copied to another
location for safekeeping. Don't forget there is also the
~/.taskrc file that contains your task configuration data.
</p>
<hr>
<p>
<b>
Q: How can I separate my work tasks from my home tasks?
Specifically, can I keep them completely separate?
</b>
<br />
A: You can do this by creating an alternate .taskrc file,
then using shell aliases. Here is are example Bash
commands to achieve this:
<pre><code>% cp ~/.taskrc ~/.taskrc_home
% (now edit .taskrc_home to change the value of data.location)
% alias wtask="task"
% alias htask="task rc:~/.taskrc_home"</code></pre>
This gives you two commands, 'wtask' and 'htask' that
operate using two different sets of task data files.
</p>
<hr>
<p>
<b>
Q: Can I revert to a previous version of task? How?
</b>
<br />
A: Yes, you can revert to a previous version of task,
simply by downloading an
<a href="versions.html">older version</a> and
installing it. If you find a bug in task, then this
may be the only way to work around the bug, until a
new release is made.
</p>
<p>
Note that it is possible that the task file format will
change. For example, the format changed between versions
1.5.0 and 1.6.0. Task will automatically upgrade the file
but if you need to revert to a previous version of task,
there is the file format to consider. This is yet another
good reason to back up your task data files!
</p>
<hr>
<!--
<p>
<b>
Q:
</b>
<br />
A:
</p>
<hr>
-->
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View File

@@ -82,7 +82,7 @@
<br /> <br />
<div class="content"> <div class="content">
<p> <p>
Copyright 2006-2008, P. Beckingham. All rights reserved. Copyright 2006-2009, P. Beckingham. All rights reserved.
</p> </p>
</div> </div>

158
html/import.html Normal file
View File

@@ -0,0 +1,158 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Data Import</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="task.css" type="text/css" />
</head>
<body>
<div id="container">
<table>
<tr>
<td>
<div id="toolbar">
<a href="task.html">Home</a>
<a href="setup.html">Setup</a>
<a href="30second.html">30-second Tutorial</a>
<a href="simple.html">Simple</a>
<a href="advanced.html">Advanced</a>
<a href="shell.html">Shell</a>
<a href="config.html">Configuration</a>
<a href="color.html">Colors</a>
<a href="usage.html">Usage</a>
<a href="recur.html">Recurrence</a>
<a href="date.html">Date Handling</a>
<a href="troubleshooting.html">Troubleshooting</a>
<a href="versions.html">Old Versions</a>
<a href="links.html">Task on the Web</a>
</div>
<div id="content">
<br />
<br />
<br />
<h2 class="title">Data Import</h2>
<div class="content">
<p>
Tasks can be imported from files with this command:
<pre><code>% task import file</code></pre>
A variety of different file types are recognized by task, namely:
<ul>
<li>Tasks exported from task prior to version 1.5.0.
<li>Tasks exported from task version 1.5.0 and later. The file
format changed with 1.5.0.
<li>todo.sh files.
<li>CSV files with a variety of recognized column names.
<li>Plain text files, with one task listed per line.
<li>Task command line format.
</ul>
</p>
<p>
Task makes a good effort to determine which of these formats a
file is. It does this by reading the file, and looking for
familiar patterns. For example, the easiest files to recognize
are those exported from task itself, because they all have a
header line that comes in only three variations. Other formats
are a little harder to identify, but they all have their own
identifying characteristics.
</p>
<p>
The most complex import is when a CSV file is recognized.
Task needs a field header line in order to map columns to task
data items. For example, the if the following file is
imported:
</p>
<pre><code>number,status,task
1,pending,task one
2,pending,task two</code></pre>
<p>
Task will map the "number" field to task's "id" field, etc,
based on name. Task has a list of synonyms that it uses to
map fields, but you can specify your own override with any of
the following configuration variables:
</p>
<ul>
<li>import.synonym.id
<li>import.synonym.uuid
<li>import.synonym.status
<li>import.synonym.tags
<li>import.synonym.entry
<li>import.synonym.start
<li>import.synonym.due
<li>import.synonym.recur
<li>import.synonym.end
<li>import.synonym.project
<li>import.synonym.priority
<li>import.synonym.fg
<li>import.synonym.bg
<li>import.synonym.description
</ul>
<p>
Please note that it is wise to backup your task data files
before an import.
</p>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>
</div>
</td>
<td align="right" valign="top" width="200px">
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9709799404235424";
/* Task Main */
google_ad_slot = "8660617875";
google_ad_width = 120;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-4737637-1");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>

View File

@@ -37,6 +37,32 @@
Task links from around the web... Task links from around the web...
</p> </p>
<dt>
February 2009, <a href="http://lifehacker.com/5155450/todotxt-cli-manages-your-tasks-from-the-command-line">Todo.txt CLI Manages Your Tasks from the Command Line</a>
</dt>
<dd>
Gina Trapani generously mentions task in an article about the newly updated, todo.sh 2.0.
</dd>
<br>
<dt>
February, 2009, <a href="http://forum.worklifecreativity.net/index.php/topic,219.0.html">My command line based task management tools</a>
</dt>
<dd>
Richard Querin talks about his task management tools.
Richard generously provides the Debian packages for task.
</dd>
<br>
<dt>
February, 2009, <a href="http://wiki.archlinux.org/index.php/Common_Apps">Common Apps</a>
</dt>
<dd>
<a href="http://wiki.archlinux.org">Archlinux.org</a> mentions task on a page which is
a point of reference for people looking for software to fill a particular need.
</dd>
<br>
<dt> <dt>
November 2008, <a href="http://github.com/pbeckingham/task/tree/master/">Task repository on GitHub</a> November 2008, <a href="http://github.com/pbeckingham/task/tree/master/">Task repository on GitHub</a>
</dt> </dt>
@@ -137,7 +163,7 @@
<br /> <br />
<div class="content"> <div class="content">
<p> <p>
Copyright 2006-2008, P. Beckingham. All rights reserved. Copyright 2006-2009, P. Beckingham. All rights reserved.
</p> </p>
</div> </div>

View File

@@ -101,6 +101,13 @@ Permanently delete task? (y/n) y
This is a recurring task. Do you want to delete all pending This is a recurring task. Do you want to delete all pending
recurrences of this same task? (y/n) y</code></pre> recurrences of this same task? (y/n) y</code></pre>
<h4>Modification</h4>
<p>
When a recurring task is modified, all the other recurring task instances will
be modified. For example, if you raise the priority of one of the recurring
task instances, all will be modified.
</p>
<h4>Recurrence Periods</h4> <h4>Recurrence Periods</h4>
<p> <p>
In the above examples, the recurrence period was specified as "monthly" and In the above examples, the recurrence period was specified as "monthly" and
@@ -116,6 +123,13 @@ recurrences of this same task? (y/n) y</code></pre>
<td class="table_d">daily, day, 1d, 2d ...</td> <td class="table_d">daily, day, 1d, 2d ...</td>
<td class="table_d">Every day, or a number of days</td> <td class="table_d">Every day, or a number of days</td>
</tr> </tr>
<tr>
<td class="table_d">weekdays</td>
<td class="table_d">
Monday, Tuesday, Wednesday, Thursday and Friday,
skipping weekend days
</td>
</tr>
<tr> <tr>
<td class="table_d">weekly, 1w, 2w ...</td> <td class="table_d">weekly, 1w, 2w ...</td>
<td class="table_d">Every week, or a number of weeks</td> <td class="table_d">Every week, or a number of weeks</td>
@@ -155,7 +169,7 @@ recurrences of this same task? (y/n) y</code></pre>
<br /> <br />
<div class="content"> <div class="content">
<p> <p>
Copyright 2006-2008, P. Beckingham. All rights reserved. Copyright 2006-2009, P. Beckingham. All rights reserved.
</p> </p>
</div> </div>

View File

@@ -40,10 +40,10 @@
</p> </p>
<pre><code>% ls <pre><code>% ls
task-1.4.1.tar.gz task-1.6.0.tar.gz
% gunzip task-1.4.1.tar.gz % gunzip task-1.6.0.tar.gz
% tar xf task-1.4.1.tar % tar xf task-1.6.0.tar
% cd task-1.4.1 % cd task-1.6.0
% ./configure % ./configure
... ...
% make % make
@@ -90,7 +90,7 @@ Done.
<br /> <br />
<div class="content"> <div class="content">
<p> <p>
Copyright 2006-2008, P. Beckingham. All rights reserved. Copyright 2006-2009, P. Beckingham. All rights reserved.
</p> </p>
</div> </div>

View File

@@ -43,7 +43,7 @@
<p> <p>
This means there is always a current version of the task This means there is always a current version of the task
report kept in a text file. Products such as report kept in a text file. Products such as
<a href="www.samurize.com">Samurize</a>, <a href="http://www.samurize.com">Samurize</a>,
<a href="http://www.mulle-kybernetik.com/software/MkConsole/">MkConsole</a>, <a href="http://www.mulle-kybernetik.com/software/MkConsole/">MkConsole</a>,
or or
<a href="http://projects.tynsoe.org/en/geektool/">GeekTool</a> <a href="http://projects.tynsoe.org/en/geektool/">GeekTool</a>
@@ -53,15 +53,18 @@
<p> <p>
To use a shadow file, edit your .taskrc configuration file, To use a shadow file, edit your .taskrc configuration file,
and add two entries as shown: and add three entries as shown:
</p> </p>
<pre><code>shadow.file=/path/to/file <pre><code>shadow.file=/path/to/file
shadow.command=list pri:H</code></pre> shadow.command=list pri:H
shadow.notify=on</code></pre>
<p> <p>
In this example the shadow file contains a report equivalent In this example the shadow file contains a report equivalent
to running "task list pri:H". to running "task list pri:H". Note that the third entry
causes a message to be displayed whenever task updates the
shadow file. It is optional.
</p> </p>
<p> <p>
@@ -75,7 +78,7 @@ shadow.command=list pri:H</code></pre>
<br /> <br />
<div class="content"> <div class="content">
<p> <p>
Copyright 2006-2008, P. Beckingham. All rights reserved. Copyright 2006-2009, P. Beckingham. All rights reserved.
</p> </p>
</div> </div>

View File

@@ -80,7 +80,7 @@
<br /> <br />
<div class="content"> <div class="content">
<p> <p>
Copyright 2006-2008, P. Beckingham. All rights reserved. Copyright 2006-2009, P. Beckingham. All rights reserved.
</p> </p>
</div> </div>

View File

@@ -305,7 +305,7 @@ ID Project Pri Due Active Age Description
<br /> <br />
<div class="content"> <div class="content">
<p> <p>
Copyright 2006-2008, P. Beckingham. All rights reserved. Copyright 2006-2009, P. Beckingham. All rights reserved.
</p> </p>
</div> </div>

View File

@@ -57,6 +57,9 @@
<li><a href="versions.html">Old Versions</a> <li><a href="versions.html">Old Versions</a>
<li><a href="filter.html">Filters</a> <li><a href="filter.html">Filters</a>
<li><a href="shadow.html">Shadow Files</a> <li><a href="shadow.html">Shadow Files</a>
<li><a href="custom.html">Custom Reports</a>
<li><a href="import.html">Data Import</a>
<li><a href="faq.html">Frequently Asked Questions</a>
</ul> </ul>
<p> <p>
@@ -70,61 +73,129 @@
</p> </p>
<br /> <br />
<h2 class="title">Get the Latest Release</h2> <h2 class="title">Get the Latest Stable Release</h2>
<div class="content"> <div class="content">
<table> <table>
<tr> <tr>
<td>Source:</td> <td>Source:</td>
<td><a href="http://www.beckingham.net/task-1.5.0.tar.gz">task-1.5.0.tar.gz</a></td> <td><a href="http://www.beckingham.net/task-1.6.0.tar.gz">task-1.6.0.tar.gz</a></td>
</tr> </tr>
<!--
<tr> <tr>
<td>Mac OS X 10.5 (Leopard) Intel-only:</td> <td>Mac OS X 10.5 (Leopard) Intel-only:</td>
<td><a href="http://www.beckingham.net/task-1.5.0.pkg">task-1.5.0.pkg</a></td> <td><a href="http://www.beckingham.net/task-1.6.0.pkg">task-1.6.0.pkg</a></td>
</tr> </tr>
<tr> <tr>
<td> <td>
Debian package: Debian:
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>): (Thanks to <a href="http://blog.rfquerin.org">Richard&nbsp;Querin</a>):
</td> </td>
<td><a href="http://www.beckingham.net/task_1.5.0-1_i386.deb">task_1.5.0-1_i386.deb</a></td> <td><a href="http://www.beckingham.net/task_1.6.0-1_i386.deb">task_1.6.0-1_i386.deb</a></td>
</tr>
<tr>
<td>
Red Hat:
(Thanks to <a href="http://www.ultrafredde.com">Federico&nbsp;Hernandez</a>):
</td>
<td><a href="http://www.beckingham.net/task-1.6.0-1.i386.rpm">task-1.6.0-1.i386.rpm</a></td>
</tr>
<tr>
<td>Git - get the whole source and history:</td>
<td><a href="http://github.com/pbeckingham/task">http://github.com/pbeckingham/task</a></td>
</tr> </tr>
-->
</table> </table>
<h4>New in version 1.5.0 (?)</h4> <h4>New in version 1.6.0 (?)</h4>
<ul> <ul>
<li>Removed deprecated TUTORIAL file. <li>Added support for new "append" command that adds more description text to
<li>Removed support for the "showage" configuration variable. an existing task.
<li>"task stop" can remove the start time from a started task. <li>Added support for the "weekdays" recurrence, which means a task can recur
<li>"task ghistory" now displays a differently aligned graph, allowing five times a week, and not on weekends (thanks to Chris Pride).
easier comparison by month of tasks added versus completed and deleted. <li>UTF8 text is now supported in task project names, tags and descriptions.
<li>"task version" command now reports unrecognized configuration variables, <li>Fixed bug that caused the y/n confirmation on task deletion to ignore the
which may be spelling mistakes or deprecated variables. Enter key and fail to re-prompt (thanks to Bruce Dillahunty).
<li>"configure --enable-debug" now supported to suppress compiler optimization <li>When the "echo.command" configuration variable is set to "yes", it causes
to allow debugging. commands that modify tasks to display which task was affected (thanks to
Bruce Dillahunty).
<li>A task can now be annotated with the command "task <id> annotate ...", and
a timestamped annotation will appear in reports.
<li>A 'description_only' column is now available for use in custom reports,
and it excludes annotations.
<li>A task can now be upgraded to a recurring task by adding a recurrence
frequency, a due date, and an optional until date.
<li>When a recurring task is modified, all other instances of the recurring
task are also modified.
<li>Custom reports now support user-specified column labels (thanks to T.
Charles Yun).
<li>Task can now import tasks from a variety of data formats, including task
export files from versions 1.4.3 and earlier, versions 1.5.0 and later,
todo.sh 2.x, CSV, plain text and task command line. See online docs for
full details.
<li>Export was including 'id' in the column header even though it was not
included in the data.
<li>The task file format has changed slightly. Please back up your task
data files before upgrading to 1.6.0.
<li>Added new column 'recurrence_indicator' that displays an 'R' if the task
is a recurring task. This column can be added to any custom report.
<li>Added new column 'tag_indicator' that displays a '+' if the task
has any tags. This column can be added to any custom report.
<li>Fixed bug where sometimes a task description was concatenated oddly if
there was a colon somewhere in the description.
<li>Fixed bug that caused recurring annual tasks to exhibit a creeping due
date, because of an assumption of 365 days per year, which failed to
consider leap years (thanks to T. Charles Yun).
<li>Annotations can now be modified with the substitution commands /from/to/.
<li>Substitutions can now be made global with /from/to/g and all occurrences
of "from" will be replaced with "to".
</ul> </ul>
<p> <p>
(Find out <a href="versions.html">what was new in prior versions</a>) (Find out <a href="versions.html">what was new in prior versions</a>)
</p> </p>
<!--
<h2>Task 1.6.0 Beta</h2>
<p>
The next version of task is in beta. This means it is approaching the
end of the current development and testing cycle, and feedback from
a wider audience is needed to find the last bugs. If you would like
to help test the next release of task, download the beta source below
and install in the usual manner.
</p>
<p>
Please note that beta software may contain significant bugs. If you
use this beta release, you should first backup your existing task
data files.
</p>
<p>
Refer to the ChangeLog file for details regarding the various fixes
and enhancements.
</p>
<table>
<tr>
<td>Source:</td>
<td><a href="http://www.beckingham.net/task-1.6.0beta.tar.gz">task-1.6.0beta.tar.gz</a></td>
</tr>
</table>
-->
<h2>Troubleshooting</h2> <h2>Troubleshooting</h2>
<p> <p>
Task has been built from source and tested in the following environments: Task has been built from source and tested in the following environments:
</p> </p>
<ul> <p>
<li>OS X 10.4 Tiger <ul>
<li>OS X 10.5 Leopard <li>OS X 10.4 Tiger
<li>Fedora Core 8 <li>OS X 10.5 Leopard
<li>Fedora Core 9 <li>Fedora Core 8
<li>Ubuntu 7 Feisty Fawn <li>Fedora Core 9
<li>Ubuntu 8 Hardy Heron <li>Fedora Core 10
<li>Solaris 10 <li>Ubuntu 7 Feisty Fawn
<li>Cygwin 1.5.25-14 <li>Ubuntu 8 Hardy Heron
</ul> <li>Ubuntu 8.10 Intrepid Ibex
<li>Solaris 10
<li>Cygwin 1.5.25-14
</ul>
</p>
<p> <p>
If you have difficulties building task, have found a bug, have a If you have difficulties building task, have found a bug, have a
@@ -143,7 +214,7 @@
<br /> <br />
<div class="content"> <div class="content">
<p> <p>
Copyright 2006-2008, P. Beckingham. All rights reserved. Copyright 2006-2009, P. Beckingham. All rights reserved.
</p> </p>
</div> </div>

View File

@@ -83,11 +83,29 @@
</p> </p>
</div> </div>
<br />
<h2 class="title">Do colors work under Cygwin?</h2>
<div class="content">
<p>
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.
</p>
<p>
If you run the command:
<code><pre>% task colors</pre></code>
Task will display all the colors it can use, and you will
see which ones you can use.
</p>
</div>
<br /> <br />
<br /> <br />
<div class="content"> <div class="content">
<p> <p>
Copyright 2006-2008, P. Beckingham. All rights reserved. Copyright 2006-2009, P. Beckingham. All rights reserved.
</p> </p>
</div> </div>

View File

@@ -34,12 +34,12 @@
<br /> <br />
<h2 class="title"><a name="usage">Command Usage<a></h2> <h2 class="title"><a name="usage">Command Usage<a></h2>
<div class="content"> <div class="content">
<pre><code>task add [tags] [attrs] desc... <pre><code>Usage: task
task list [tags] [attrs] desc... task add [tags] [attrs] desc...
task long [tags] [attrs] desc... task append [tags] [attrs] desc...
task ls [tags] [attrs] desc... task annotate ID desc...
task completed [tags] [attrs] desc... task completed [tags] [attrs] desc...
task ID [tags] [attrs] ["desc..."] task ID [tags] [attrs] [desc...]
task ID /from/to/ task ID /from/to/
task delete ID task delete ID
task undelete ID task undelete ID
@@ -57,12 +57,18 @@
task calendar task calendar
task active task active
task overdue task overdue
task oldest
task newest
task stats task stats
task export task export
task color task color
task version task version
task help
task list [tags] [attrs] desc...
task long [tags] [attrs] desc...
task ls [tags] [attrs] desc...
task newest [tags] [attrs] desc...
task oldest [tags] [attrs] desc...
See http://www.beckingham.net/task.html for the latest releases and a full tutorial.
ID is the numeric identifier displayed by the 'task list' command ID is the numeric identifier displayed by the 'task list' command
@@ -74,8 +80,11 @@ Attributes are:
project: Project name project: Project name
priority: Priority priority: Priority
due: Due date due: Due date
recur: Recurrence frequency
until: Recurrence end date
fg: Foreground color fg: Foreground color
bg: Background color bg: Background color
rc: Alternate .taskrc file
Any command or attribute name may be abbreviated if still unique: Any command or attribute name may be abbreviated if still unique:
task list project:Home task list project:Home
@@ -86,14 +95,14 @@ Some task descriptions need to be escaped because of the shell:
task add escaped \' quote task add escaped \' quote
Many characters have special meaning to the shell, including: Many characters have special meaning to the shell, including:
$ ! ' " ( ) ; \ ` * ? { } [ ] < > | &amp; % # ~</code></pre> $ ! ' " ( ) ; \ ` * ? { } [ ] < > | & % # ~</code></pre>
<div> <div>
<br /> <br />
<br /> <br />
<div class="content"> <div class="content">
<p> <p>
Copyright 2006-2008, P. Beckingham. All rights reserved. Copyright 2006-2009, P. Beckingham. All rights reserved.
</p> </p>
</div> </div>

View File

@@ -36,6 +36,77 @@
<br /> <br />
<div class="content"> <div class="content">
<p>
<h4>New in version 1.5.0 (3/15/2009)</h4>
<table>
<tr>
<td>Source:</td>
<td><a href="http://www.beckingham.net/task-1.5.0.tar.gz">task-1.5.0.tar.gz</a></td>
</tr>
<tr>
<td>Mac OS X 10.5 (Leopard) Intel-only:</td>
<td><a href="http://www.beckingham.net/task-1.5.0.pkg">task-1.5.0.pkg</a></td>
</tr>
<tr>
<td>
Debian:
(Thanks to <a href="http://blog.rfquerin.org">Richard&nbsp;Querin</a>):
</td>
<td><a href="http://www.beckingham.net/task_1.5.0-1_i386.deb">task_1.5.0-1_i386.deb</a></td>
</tr>
<tr>
<td>
Red Hat:
(Thanks to <a href="http://www.ultrafredde.com">Federico&nbsp;Hernandez</a>):
</td>
<td><a href="http://www.beckingham.net/task-1.5.0-1.i386.rpm">task-1.5.0-1.i386.rpm</a></td>
</tr>
</table>
<ul>
<li>Removed deprecated TUTORIAL file.
<li>Removed support for the "showage" configuration variable.
<li>"task stop" can remove the start time from a started task.
<li>"task ghistory" now displays a differently aligned graph, allowing
easier comparison by month of tasks added versus completed and deleted.
<li>"task version" command now reports unrecognized configuration variables,
which may be spelling mistakes or deprecated variables.
<li>"configure --enable-debug" now supported to suppress compiler optimization
to allow debugging.
<li>Allow lower case priorities, and automatically upper case them.
<li>Added support for "due" configuration variable which defines the number
of days in the future when a task is considered due.
<li>Added support for custom reports, comprised of a set of column names and
sort order, with optional filtering in the configuration file. This
means user-defined reports can be written, and the reports currently
in the configuration file can be renamed. Several of task's built in
reports have been converted to user-defined reports.
<li>New online documentation for custom reports.
<li>New algorithm for determining when the "nag" message is displayed.
<li>Fixed bug where task hangs with a certain combination of recurring tasks
and shadow files.
<li>Fixed bug with the task sort algorithm, which led to an unstable sequence
when there were only a handful of tasks.
<li>Performance enhanced by eliminating unnecessary sorting.
<li>Task now has a large (and growing) test suite and bug regression tests
to help ensure higher quality releases.
<li>Fixed bug that caused large performance hit during table rendering.
<li>Fixed bug that concatenated a modified description without spaces.
<li>Added new column 'recur' that displays the recurrence period of any
recurring tasks. This column can be added to any custom report.
<li>Added support for "color.recurring" configuration variable which
specifies the color of recurring tasks.
<li>Added support for "locking" configuration variable that controls whether
file locking is used.
<li>Task export feature now includes recurrence information, removes nested
quotes, and limits output to pending tasks.
<li>Task no longer includes deleted tasks in the summary report (thanks to
Benjamin Tegarden).
<li>Fixed bug that prevented the summary report from properly reporting
recently completed tasks.
</ul>
</p>
<p> <p>
<h4>New in version 1.4.3 (11/1/2008)</h4> <h4>New in version 1.4.3 (11/1/2008)</h4>
<a href="http://www.beckingham.net/task-1.4.3.tar.gz">task-1.4.3.tar.gz</a> <a href="http://www.beckingham.net/task-1.4.3.tar.gz">task-1.4.3.tar.gz</a>
@@ -47,6 +118,7 @@
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>) (Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>)
</p> </p>
<p>
<ul> <ul>
<li>Fixed misleading task count at bottom of "info" report. <li>Fixed misleading task count at bottom of "info" report.
<li>Added support for a shadow file that contains a plain text task report, <li>Added support for a shadow file that contains a plain text task report,
@@ -250,7 +322,7 @@
<br /> <br />
<div class="content"> <div class="content">
<p> <p>
Copyright 2006-2008, P. Beckingham. All rights reserved. Copyright 2006-2009, P. Beckingham. All rights reserved.
</p> </p>
</div> </div>
</div> </div>

View File

@@ -1,105 +1,109 @@
Hello, and welcome to this quick demo of the task program. Hello, and welcome to this quick demo of the task program.
task add do laundry Let's add some tasks task add do laundry Let's add some tasks
I need to do laundry I need to do laundry
task add project:garage order dumpster Oh yeah, the dumpster task add project:garage order dumpster Oh yeah, I need to order the dumpster
task add +phone tell mom i loveher Must call Mom (that "phone" there is a tag - they are task add +phone tell mom i loveher Must call Mom (that "phone" there is a tag - they can
useful for searching, categorizing) be useful for searching and categorizing)
task add +phone pro:garage schedule task add +phone pro:garage schedule
goodwill pickup goodwill pickup
task ad +email pro:garage ask Tom if Notice I can abbreviating commands task ad +email pro:garage ask Tom if Notice I can abbreviate commands
he wants that old bkie he wants that old bkie
task ls Let's see what we've got task ls Let's see what we've got
I spelled bike wrong Oh, I spelled bike wrong
task 5 /bkie/bike/ task 5 /bkie/bike/
task ls That's better task ls That's better
task 1 pro:home Let's assign projects task 1 pro:home Let's assign projects
task 3 pro:home tell mom I love her task 3 pro:home tell mom I love her
task ls pro:garage task ls pro:garage
task long pro:garage Let's see all the columns task long pro:garage Let's see all the columns
task list pro:garage There are different ways to list task list pro:garage There are different ways to list
task lis +phone By tag task lis +phone By tag
task li pro:garage +phone By project and tag task li pro:garage +phone By project and tag
task l mom By word task l mom By word
task 1 priority:H Priorities can be High, Medium or Low task 1 priority:H Priorities can be High, Medium or Low
task pri:H 3 task pri:H 3
task 1 pri:M task 1 pri:M
task li The list is sorted by priority. task li The list is sorted by priority.
task 2 pri:L task 2 pri:L
task li task li
task done 3 Suppose task 3 is done task done 3 Suppose task 3 is done
task li ...and it's gone task li ...and it's gone
task 2 +phone +mistake Lets add tags task 2 +phone +mistake Lets add tags
# Oops! # Oops!
task 2 -mistake or remove tags task 2 -mistake or remove tags
task tags or look at all the tags task tags or look at all the tags
task info 2 or all the details task info 2 or all the details
task projects or all the projects task projects or all the projects
task 3 fg:bold Let's make it colorful task 3 fg:bold Let's make it colorful
task 4 fg:bold_green task 4 fg:bold_green
task li task li
task 3 fg:bold_underline_white task 3 fg:bold_underline_white
task li task li
task 4 bg:on_bright_red fg:bold_yellow task 4 bg:on_bright_red fg:bold_yellow
task li Oh that's just nasty - let's get rid of that. task li Oh that's just nasty - let's get rid of that.
task 4 bg: task 4 bg:
task li task li
task 4 fg: task 4 fg:
task 3 fg: task 3 fg:
task colors There are many combinations to choose from task colors There are many combinations to choose from
(Slashes!!!) (Slashes!!!)
task 1 due:6/8/2008 Let's add a due date task 1 due:6/8/2008 Let's add a due date
date date
task li task li
task calendar Notice the due task is in yellow, today is marked cyan task calendar Notice the due task is in yellow, today is marked cyan
task 1 due:5/20/2008 This is now an overdue task task 1 due:5/20/2008 This is now an overdue task
task li and it shows up red task li and it shows up red
task overdue task overdue
task cal task cal
task export file.csv You can export the tasks to a spreadsheet task export file.csv You can export the tasks to a spreadsheet
cat file.csv cat file.csv
task start 1 Started tasks can be used as reminders task start 1 Started tasks can be used as reminders
of what you are supposed to be doing of what you are supposed to be doing
task active They show up as active task active They show up as active
task done 1 Let's clear out a couple task done 1 Let's clear out a couple
task li task li
task done 3 task done 3
task active task active
task summary Summary shows progress on all projects task summary Summary shows progress on all projects
task history History shows general activity - how many added, task history History shows general activity - how many added,
completed etc, by month completed etc, by month
And that's it. There are more commands than this task ghistory This report shows a histogram of tasks that were
covered in the online documentation, but this should give added (in red), completed (in green) and deleted
the basic idea. (in yellow), all by month.
Thank you for watching. And that's it. There are more commands than this
covered in the online documentation, but this should give
the basic idea.
Thank you for watching.

View File

@@ -1,7 +1,7 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under
@@ -36,8 +36,40 @@
#include "Config.h" #include "Config.h"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// These are default (but overridable) reports. These entries are necessary
// because these three reports were converted from hard-coded reports to custom
// reports, and therefore need these config file entries. However, users are
// already used to seeing these five reports, but do not have these entries.
// The choice was a) make users edit their .taskrc files, b) write a .taskrc
// upgrade program to make the change, or c) this.
Config::Config () Config::Config ()
{ {
(*this)["report.long.description"] = "Lists all task, all data, matching the specified criteria";
(*this)["report.long.columns"] = "id,project,priority,entry,start,due,recur,age,tags,description";
(*this)["report.long.labels"] = "ID,Project,Pri,Added,Started,Due,Recur,Age,Tags,Description";
(*this)["report.long.sort"] = "due+,priority-,project+";
(*this)["report.list.description"] = "Lists all tasks matching the specified criteria";
(*this)["report.list.columns"] = "id,project,priority,due,active,age,description";
(*this)["report.list.labels"] = "ID,Project,Pri,Due,Active,Age,Description";
(*this)["report.list.sort"] = "due+,priority-,project+";
(*this)["report.ls.description"] = "Minimal listing of all tasks matching the specified criteria";
(*this)["report.ls.columns"] = "id,project,priority,description";
(*this)["report.ls.labels"] = "ID,Project,Pri,Description";
(*this)["report.ls.sort"] = "priority-,project+";
(*this)["report.newest.description"] = "Shows the newest tasks";
(*this)["report.newest.columns"] = "id,project,priority,due,active,age,description";
(*this)["report.newest.labels"] = "ID,Project,Pri,Due,Active,Age,Description";
(*this)["report.newest.sort"] = "id-";
(*this)["report.newest.limit"] = "10";
(*this)["report.oldest.description"] = "Shows the oldest tasks";
(*this)["report.oldest.columns"] = "id,project,priority,due,active,age,description";
(*this)["report.oldest.labels"] = "ID,Project,Pri,Due,Active,Age,Description";
(*this)["report.oldest.sort"] = "id+";
(*this)["report.oldest.limit"] = "10";
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -47,9 +79,9 @@ Config::Config (const std::string& file)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Read the Configuration filee and populate the *this map. The file format // Read the Configuration file and populate the *this map. The file format is
// is simply lines with name=value pairs. Whitespace between name, = and value // simply lines with name=value pairs. Whitespace between name, = and value is
// is not tolerated, but blank lines and comments starting with # are allowed. // not tolerated, but blank lines and comments starting with # are allowed.
bool Config::load (const std::string& file) bool Config::load (const std::string& file)
{ {
std::ifstream in; std::ifstream in;
@@ -113,26 +145,64 @@ void Config::createDefault (const std::string& home)
{ {
fprintf (out, "data.location=%s\n", dataDir.c_str ()); fprintf (out, "data.location=%s\n", dataDir.c_str ());
fprintf (out, "confirmation=yes\n"); fprintf (out, "confirmation=yes\n");
fprintf (out, "echo.command=yes\n");
fprintf (out, "next=2\n"); fprintf (out, "next=2\n");
fprintf (out, "dateformat=m/d/Y\n"); fprintf (out, "dateformat=m/d/Y\n");
fprintf (out, "monthsperline=1\n"); fprintf (out, "#monthsperline=2\n");
fprintf (out, "curses=on\n"); fprintf (out, "curses=on\n");
fprintf (out, "color=on\n"); fprintf (out, "color=on\n");
fprintf (out, "due=7\n");
fprintf (out, "nag=You have higher priority tasks.\n");
fprintf (out, "locking=on\n");
fprintf (out, "color.overdue=bold_red\n"); fprintf (out, "color.overdue=bold_red\n");
fprintf (out, "#color.due=on_bright_yellow\n"); fprintf (out, "color.due=bold_yellow\n");
fprintf (out, "#color.pri.H=on_red\n"); fprintf (out, "color.pri.H=bold\n");
fprintf (out, "#color.pri.M=on_yellow\n"); fprintf (out, "#color.pri.M=on_yellow\n");
fprintf (out, "#color.pri.L=on_green\n"); fprintf (out, "#color.pri.L=on_green\n");
fprintf (out, "#color.pri.none=white on_blue\n");
fprintf (out, "color.active=bold_cyan\n"); fprintf (out, "color.active=bold_cyan\n");
fprintf (out, "color.tagged=yellow\n"); fprintf (out, "color.tagged=yellow\n");
fprintf (out, "#color.tag.bug=yellow\n"); fprintf (out, "#color.tag.bug=yellow\n");
fprintf (out, "#color.project.home=on_green\n"); fprintf (out, "#color.project.garden=on_green\n");
fprintf (out, "#color.keyword.car=on_blue\n"); fprintf (out, "#color.keyword.car=on_blue\n");
fprintf (out, "#color.recurring=on_red\n");
fprintf (out, "#shadow.file=%s/shadow.txt\n", dataDir.c_str ()); fprintf (out, "#shadow.file=%s/shadow.txt\n", dataDir.c_str ());
fprintf (out, "#shadow.command=list\n"); fprintf (out, "#shadow.command=list\n");
fprintf (out, "#shadow.notify=on\n"); fprintf (out, "#shadow.notify=on\n");
fprintf (out, "#default.command=list\n"); fprintf (out, "#default.project=foo\n");
fprintf (out, "#default.priority=M\n");
fprintf (out, "default.command=list\n");
// Custom reports.
fprintf (out, "# Fields: id,uuid,project,priority,entry,start,due,recur,age,active,tags,description\n");
fprintf (out, "# description_only\n");
fprintf (out, "# Description: This report is ...\n");
fprintf (out, "# Sort: due+,priority-,project+\n");
fprintf (out, "# Filter: pro:x pri:H +bug\n");
fprintf (out, "# Limit: 10\n");
fprintf (out, "report.long.description=Lists all task, all data, matching the specified criteria\n");
fprintf (out, "report.long.columns=id,project,priority,entry,start,due,recur,age,tags,description\n");
fprintf (out, "report.long.sort=due+,priority-,project+\n");
fprintf (out, "report.list.description=Lists all tasks matching the specified criteria\n");
fprintf (out, "report.list.columns=id,project,priority,due,active,age,description\n");
fprintf (out, "report.list.sort=due+,priority-,project+\n");
fprintf (out, "report.ls.description=Minimal listing of all tasks matching the specified criteria\n");
fprintf (out, "report.ls.columns=id,project,priority,description\n");
fprintf (out, "report.ls.sort=priority-,project+\n");
fprintf (out, "report.newest.description=Shows the newest tasks\n");
fprintf (out, "report.newest.columns=id,project,priority,due,active,age,description\n");
fprintf (out, "report.newest.sort=id-\n");
fprintf (out, "report.newest.limit=10\n");
fprintf (out, "report.oldest.description=Shows the oldest tasks\n");
fprintf (out, "report.oldest.columns=id,project,priority,due,active,age,description\n");
fprintf (out, "report.oldest.sort=id+\n");
fprintf (out, "report.oldest.limit=10\n");
fclose (out); fclose (out);
@@ -191,11 +261,13 @@ bool Config::get (const std::string& key, bool default_value)
{ {
std::string value = lowerCase ((*this)[key]); std::string value = lowerCase ((*this)[key]);
if (value == "t" || if (value == "t" ||
value == "true" || value == "true" ||
value == "1" || value == "1" ||
value == "yes" || value == "yes" ||
value == "on") value == "on" ||
value == "enable" ||
value == "enabled")
return true; return true;
return false; return false;

View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under

View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under

View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under

View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under
@@ -60,6 +60,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <iostream> #include <iostream>
#include <stdlib.h>
#include <Grid.h> #include <Grid.h>
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -325,7 +326,7 @@ Grid::Cell::operator int () const
case CELL_INT: return mInt; case CELL_INT: return mInt;
case CELL_FLOAT: return (int) mFloat; case CELL_FLOAT: return (int) mFloat;
case CELL_DOUBLE: return (int) mDouble; case CELL_DOUBLE: return (int) mDouble;
case CELL_STRING: return mString.length (); case CELL_STRING: return ::atoi (mString.c_str ());
} }
return 0; return 0;
@@ -340,7 +341,7 @@ Grid::Cell::operator float () const
case CELL_INT: return (float) mInt; case CELL_INT: return (float) mInt;
case CELL_FLOAT: return mFloat; case CELL_FLOAT: return mFloat;
case CELL_DOUBLE: return (float) mDouble; case CELL_DOUBLE: return (float) mDouble;
case CELL_STRING: return (float) mString.length (); case CELL_STRING: return (float) ::atof (mString.c_str ());
} }
return 0.0; return 0.0;
@@ -355,7 +356,7 @@ Grid::Cell::operator double () const
case CELL_INT: return (double) mInt; case CELL_INT: return (double) mInt;
case CELL_FLOAT: return (double) mFloat; case CELL_FLOAT: return (double) mFloat;
case CELL_DOUBLE: return mDouble; case CELL_DOUBLE: return mDouble;
case CELL_STRING: return (double) mString.length (); case CELL_STRING: return (double) ::atof (mString.c_str ());
} }
return 0.0; return 0.0;

View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under

View File

@@ -1,2 +1,2 @@
bin_PROGRAMS = task bin_PROGRAMS = task
task_SOURCES = Config.cpp Date.cpp T.cpp TDB.cpp Table.cpp Grid.cpp color.cpp parse.cpp task.cpp command.cpp report.cpp util.cpp text.cpp rules.cpp Config.h Date.h T.h TDB.h Table.h Grid.h color.h task.h task_SOURCES = Config.cpp Date.cpp T.cpp TDB.cpp Table.cpp Grid.cpp Timer.cpp color.cpp parse.cpp task.cpp command.cpp report.cpp util.cpp text.cpp rules.cpp import.cpp Config.h Date.h T.h TDB.h Table.h Grid.h Timer.h color.h task.h

View File

@@ -44,9 +44,10 @@ am__installdirs = "$(DESTDIR)$(bindir)"
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(bin_PROGRAMS) PROGRAMS = $(bin_PROGRAMS)
am_task_OBJECTS = Config.$(OBJEXT) Date.$(OBJEXT) T.$(OBJEXT) \ am_task_OBJECTS = Config.$(OBJEXT) Date.$(OBJEXT) T.$(OBJEXT) \
TDB.$(OBJEXT) Table.$(OBJEXT) Grid.$(OBJEXT) color.$(OBJEXT) \ TDB.$(OBJEXT) Table.$(OBJEXT) Grid.$(OBJEXT) Timer.$(OBJEXT) \
parse.$(OBJEXT) task.$(OBJEXT) command.$(OBJEXT) \ color.$(OBJEXT) parse.$(OBJEXT) task.$(OBJEXT) \
report.$(OBJEXT) util.$(OBJEXT) text.$(OBJEXT) rules.$(OBJEXT) command.$(OBJEXT) report.$(OBJEXT) util.$(OBJEXT) \
text.$(OBJEXT) rules.$(OBJEXT) import.$(OBJEXT)
task_OBJECTS = $(am_task_OBJECTS) task_OBJECTS = $(am_task_OBJECTS)
task_LDADD = $(LDADD) task_LDADD = $(LDADD)
DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@ DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@
@@ -154,7 +155,7 @@ sysconfdir = @sysconfdir@
target_alias = @target_alias@ target_alias = @target_alias@
top_builddir = @top_builddir@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@ top_srcdir = @top_srcdir@
task_SOURCES = Config.cpp Date.cpp T.cpp TDB.cpp Table.cpp Grid.cpp color.cpp parse.cpp task.cpp command.cpp report.cpp util.cpp text.cpp rules.cpp Config.h Date.h T.h TDB.h Table.h Grid.h color.h task.h task_SOURCES = Config.cpp Date.cpp T.cpp TDB.cpp Table.cpp Grid.cpp Timer.cpp color.cpp parse.cpp task.cpp command.cpp report.cpp util.cpp text.cpp rules.cpp import.cpp Config.h Date.h T.h TDB.h Table.h Grid.h Timer.h color.h task.h
all: all-am all: all-am
.SUFFIXES: .SUFFIXES:
@@ -227,8 +228,10 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/T.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/T.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TDB.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TDB.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Table.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Table.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Timer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/color.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/color.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/import.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/report.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/report.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rules.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rules.Po@am__quote@

254
src/T.cpp
View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under
@@ -25,6 +25,7 @@
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <iostream> #include <iostream>
#include <sstream>
#include <algorithm> #include <algorithm>
#include "task.h" #include "task.h"
#include "T.h" #include "T.h"
@@ -39,6 +40,10 @@ T::T ()
mTags.clear (); mTags.clear ();
mAttributes.clear (); mAttributes.clear ();
mDescription = ""; mDescription = "";
mFrom = "";
mTo = "";
mGlobal = false;
mAnnotations.clear ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -58,6 +63,7 @@ T::T (const T& other)
mTags = other.mTags; mTags = other.mTags;
mRemoveTags = other.mRemoveTags; mRemoveTags = other.mRemoveTags;
mAttributes = other.mAttributes; mAttributes = other.mAttributes;
mAnnotations = other.mAnnotations;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -72,6 +78,7 @@ T& T::operator= (const T& other)
mTags = other.mTags; mTags = other.mTags;
mRemoveTags = other.mRemoveTags; mRemoveTags = other.mRemoveTags;
mAttributes = other.mAttributes; mAttributes = other.mAttributes;
mAnnotations = other.mAnnotations;
} }
return *this; return *this;
@@ -109,6 +116,12 @@ void T::addRemoveTag (const std::string& tag)
mRemoveTags.push_back (tag); mRemoveTags.push_back (tag);
} }
////////////////////////////////////////////////////////////////////////////////
int T::getTagCount () const
{
return mTags.size ();
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void T::getTags (std::vector<std::string>& all) const void T::getTags (std::vector<std::string>& all) const
{ {
@@ -230,21 +243,51 @@ void T::removeAttribute (const std::string& name)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void T::getSubstitution (std::string& from, std::string& to) const void T::getSubstitution (
std::string& from,
std::string& to,
bool& global) const
{ {
from = mFrom; from = mFrom;
to = mTo; to = mTo;
global = mGlobal;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void T::setSubstitution (const std::string& from, const std::string& to) void T::setSubstitution (
const std::string& from,
const std::string& to,
bool global)
{ {
mFrom = from; mFrom = from;
mTo = to; mTo = to;
mGlobal = global;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// uuid status [tags] [attributes] description void T::getAnnotations (std::map <time_t, std::string>& all) const
{
all = mAnnotations;
}
////////////////////////////////////////////////////////////////////////////////
void T::setAnnotations (const std::map <time_t, std::string>& all)
{
mAnnotations = all;
}
////////////////////////////////////////////////////////////////////////////////
void T::addAnnotation (const std::string& description)
{
std::string sanitized = description;
std::replace (sanitized.begin (), sanitized.end (), '"', '\'');
std::replace (sanitized.begin (), sanitized.end (), '[', '(');
std::replace (sanitized.begin (), sanitized.end (), ']', ')');
mAnnotations[time (NULL)] = sanitized;
}
////////////////////////////////////////////////////////////////////////////////
// uuid status [tags] [attributes] [annotations] description
// //
// uuid \x{8}-\x{4}-\x{4}-\x{4}-\x{12} // uuid \x{8}-\x{4}-\x{4}-\x{4}-\x{12}
// status - + X r // status - + X r
@@ -282,10 +325,26 @@ const std::string T::compose () const
++count; ++count;
} }
line += "] "; line += "] [";
// Annotations
std::stringstream annotation;
bool first = true;
foreach (note, mAnnotations)
{
if (first)
first = false;
else
annotation << " ";
annotation << note->first << ":\"" << note->second << "\"";
}
line += annotation.str () + "] ";
// Description // Description
line += mDescription; line += mDescription;
// EOL
line += "\n"; line += "\n";
if (line.length () > T_LINE_MAX) if (line.length () > T_LINE_MAX)
@@ -328,6 +387,11 @@ const std::string T::composeCSV ()
line += value; line += value;
line += ","; line += ",";
value = mAttributes["recur"];
if (value != "")
line += value;
line += ",";
value = mAttributes["end"]; value = mAttributes["end"];
if (value != "") if (value != "")
line += value; line += value;
@@ -353,7 +417,11 @@ const std::string T::composeCSV ()
line += "'" + value + "'"; line += "'" + value + "'";
line += ","; line += ",";
line += "'" + mDescription + "'\n"; // Convert single quotes to double quotes, because single quotes are used to
// delimit the values that need it.
std::string clean = mDescription;
std::replace (clean.begin (), clean.end (), '\'', '"');
line += "'" + clean + "'\n";
return line; return line;
} }
@@ -412,10 +480,12 @@ void T::parse (const std::string& line)
} }
else else
throw std::string ("Line too short"); throw std::string ("Line too short");
mAnnotations.clear ();
} }
break; break;
// File format version 2, from 2008.1.1 // File format version 2, from 2008.1.1 - 2009.3.23
case 2: case 2:
{ {
if (line.length () > 46) // ^.{36} . \[\] \[\] \n if (line.length () > 46) // ^.{36} . \[\] \[\] \n
@@ -437,24 +507,122 @@ void T::parse (const std::string& line)
if (openAttrBracket != std::string::npos && if (openAttrBracket != std::string::npos &&
closeAttrBracket != std::string::npos) closeAttrBracket != std::string::npos)
{ {
std::string tags = line.substr ( std::string tags = line.substr (
openTagBracket + 1, closeTagBracket - openTagBracket - 1); openTagBracket + 1, closeTagBracket - openTagBracket - 1);
std::vector <std::string> rawTags; std::vector <std::string> rawTags;
split (mTags, tags, ' '); split (mTags, tags, ' ');
std::string attributes = line.substr ( std::string attributes = line.substr (
openAttrBracket + 1, closeAttrBracket - openAttrBracket - 1); openAttrBracket + 1, closeAttrBracket - openAttrBracket - 1);
std::vector <std::string> pairs; std::vector <std::string> pairs;
split (pairs, attributes, ' '); split (pairs, attributes, ' ');
for (size_t i = 0; i < pairs.size (); ++i) for (size_t i = 0; i < pairs.size (); ++i)
{ {
std::vector <std::string> pair; std::vector <std::string> pair;
split (pair, pairs[i], ':'); split (pair, pairs[i], ':');
if (pair.size () == 2) if (pair.size () == 2)
mAttributes[pair[0]] = pair[1]; mAttributes[pair[0]] = pair[1];
} }
mDescription = line.substr (closeAttrBracket + 2, std::string::npos); mDescription = line.substr (closeAttrBracket + 2, std::string::npos);
}
else
throw std::string ("Missing attribute brackets");
}
else
throw std::string ("Missing tag brackets");
}
else
throw std::string ("Line too short");
mAnnotations.clear ();
}
break;
// File format version 3, from 2009.3.23
case 3:
{
if (line.length () > 49) // ^.{36} . \[\] \[\] \[\] \n
{
mUUID = line.substr (0, 36);
mStatus = line[37] == '+' ? completed
: line[37] == 'X' ? deleted
: line[37] == 'r' ? recurring
: pending;
size_t openTagBracket = line.find ("[");
size_t closeTagBracket = line.find ("]", openTagBracket);
if (openTagBracket != std::string::npos &&
closeTagBracket != std::string::npos)
{
size_t openAttrBracket = line.find ("[", closeTagBracket);
size_t closeAttrBracket = line.find ("]", openAttrBracket);
if (openAttrBracket != std::string::npos &&
closeAttrBracket != std::string::npos)
{
size_t openAnnoBracket = line.find ("[", closeAttrBracket);
size_t closeAnnoBracket = line.find ("]", openAnnoBracket);
if (openAnnoBracket != std::string::npos &&
closeAnnoBracket != std::string::npos)
{
std::string tags = line.substr (
openTagBracket + 1, closeTagBracket - openTagBracket - 1);
std::vector <std::string> rawTags;
split (mTags, tags, ' ');
std::string attributes = line.substr (
openAttrBracket + 1, closeAttrBracket - openAttrBracket - 1);
std::vector <std::string> pairs;
split (pairs, attributes, ' ');
for (size_t i = 0; i < pairs.size (); ++i)
{
std::vector <std::string> pair;
split (pair, pairs[i], ':');
if (pair.size () == 2)
mAttributes[pair[0]] = pair[1];
}
// Extract and split the annotations, which are of the form:
// 1234:"..." 5678:"..."
std::string annotations = line.substr (
openAnnoBracket + 1, closeAnnoBracket - openAnnoBracket - 1);
pairs.clear ();
std::string::size_type start = 0;
std::string::size_type end = 0;
do
{
end = annotations.find ('"', start);
if (end != std::string::npos)
{
end = annotations.find ('"', end + 1);
if (start != std::string::npos &&
end != std::string::npos)
{
pairs.push_back (annotations.substr (start, end - start + 1));
start = end + 2;
}
}
}
while (start != std::string::npos &&
end != std::string::npos);
for (size_t i = 0; i < pairs.size (); ++i)
{
std::string pair = pairs[i];
std::string::size_type colon = pair.find (":");
if (colon != std::string::npos)
{
std::string name = pair.substr (0, colon);
std::string value = pair.substr (colon + 2, pair.length () - colon - 3);
mAnnotations[::atoi (name.c_str ())] = value;
}
}
mDescription = line.substr (closeAnnoBracket + 2, std::string::npos);
}
} }
else else
throw std::string ("Missing attribute brackets"); throw std::string ("Missing attribute brackets");
@@ -468,7 +636,7 @@ void T::parse (const std::string& line)
break; break;
default: default:
throw std::string (); throw std::string ("Unrecognized task file format.");
break; break;
} }
} }
@@ -503,16 +671,31 @@ int T::determineVersion (const std::string& line)
line[23] == '-' && line[23] == '-' &&
line[36] == ' ' && line[36] == ' ' &&
(line[37] == '-' || line[37] == '+' || line[37] == 'X' || line[37] == 'r')) (line[37] == '-' || line[37] == '+' || line[37] == 'X' || line[37] == 'r'))
return 2; {
// Version 3 looks like:
//
// uuid status [tags] [attributes] [annotations] description\n
//
// Scan for the number of [] pairs.
std::string::size_type tagAtts = line.find ("] [", 0);
std::string::size_type attsAnno = line.find ("] [", tagAtts + 1);
std::string::size_type annoDesc = line.find ("] ", attsAnno + 1);
if (tagAtts != std::string::npos &&
attsAnno != std::string::npos &&
annoDesc != std::string::npos)
return 3;
else
return 2;
}
// Version 3? // Version 4?
// //
// Fortunately, with the hindsight that will come with version 3, the // Fortunately, with the hindsight that will come with version 4, the
// identifying characteristics of 1 and 2 may be modified such that if 3 has // identifying characteristics of 1, 2 and 3 may be modified such that if 4
// a UUID followed by a status, then there is still a way to differentiate // has a UUID followed by a status, then there is still a way to differentiate
// between 2 and 3. // between 2, 3 and 4.
// //
// The danger is that a version 2 binary reads and misinterprets a version 3 // The danger is that a version 3 binary reads and misinterprets a version 4
// file. This is why it is a good idea to rely on an explicit version // file. This is why it is a good idea to rely on an explicit version
// declaration rather than chance positioning. // declaration rather than chance positioning.
@@ -525,6 +708,7 @@ int T::determineVersion (const std::string& line)
bool T::validate () const bool T::validate () const
{ {
// TODO Verify until > due // TODO Verify until > due
// TODO Verify entry < until, due, start, end
return true; return true;
} }

15
src/T.h
View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under
@@ -56,15 +56,17 @@ public:
const std::string getDescription () const { return mDescription; } const std::string getDescription () const { return mDescription; }
void setDescription (const std::string& description) { mDescription = description; } void setDescription (const std::string& description) { mDescription = description; }
int getAnnotationCount () const { return mAnnotations.size (); }
void getSubstitution (std::string&, std::string&) const; void getSubstitution (std::string&, std::string&, bool&) const;
void setSubstitution (const std::string&, const std::string&); void setSubstitution (const std::string&, const std::string&, bool);
bool hasTag (const std::string&) const; bool hasTag (const std::string&) const;
void getRemoveTags (std::vector<std::string>&); // SPECIAL void getRemoveTags (std::vector<std::string>&); // SPECIAL
void addRemoveTag (const std::string&); // SPECIAL void addRemoveTag (const std::string&); // SPECIAL
int getTagCount () const;
void getTags (std::vector<std::string>&) const; void getTags (std::vector<std::string>&) const;
void addTag (const std::string&); void addTag (const std::string&);
void addTags (const std::vector <std::string>&); void addTags (const std::vector <std::string>&);
@@ -77,6 +79,10 @@ public:
void removeAttribute (const std::string&); void removeAttribute (const std::string&);
void removeAttributes (); void removeAttributes ();
void getAnnotations (std::map <time_t, std::string>&) const;
void setAnnotations (const std::map <time_t, std::string>&);
void addAnnotation (const std::string&);
const std::string compose () const; const std::string compose () const;
const std::string composeCSV (); const std::string composeCSV ();
void parse (const std::string&); void parse (const std::string&);
@@ -93,9 +99,10 @@ private:
std::vector<std::string> mTags; std::vector<std::string> mTags;
std::vector<std::string> mRemoveTags; std::vector<std::string> mRemoveTags;
std::map<std::string, std::string> mAttributes; std::map<std::string, std::string> mAttributes;
std::string mFrom; std::string mFrom;
std::string mTo; std::string mTo;
bool mGlobal;
std::map <time_t, std::string> mAnnotations;
}; };
#endif #endif

View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under
@@ -38,6 +38,7 @@ TDB::TDB ()
: mPendingFile ("") : mPendingFile ("")
, mCompletedFile ("") , mCompletedFile ("")
, mId (1) , mId (1)
, mNoLock (false)
{ {
} }
@@ -289,11 +290,10 @@ bool TDB::modifyT (const T& t)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool TDB::lock (FILE* file) const bool TDB::lock (FILE* file) const
{ {
#ifdef HAVE_FLOCK if (mNoLock)
return true;
return flock (fileno (file), LOCK_EX) ? false : true; return flock (fileno (file), LOCK_EX) ? false : true;
#else
return true;
#endif
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -303,18 +303,16 @@ bool TDB::overwritePending (std::vector <T>& all)
FILE* out; FILE* out;
if ((out = fopen (mPendingFile.c_str (), "w"))) if ((out = fopen (mPendingFile.c_str (), "w")))
{ {
#ifdef HAVE_FLOCK
int retry = 0; int retry = 0;
while (flock (fileno (out), LOCK_EX) && ++retry <= 3) if (!mNoLock)
delay (0.25); while (flock (fileno (out), LOCK_EX) && ++retry <= 3)
#endif delay (0.1);
std::vector <T>::iterator it; std::vector <T>::iterator it;
for (it = all.begin (); it != all.end (); ++it) for (it = all.begin (); it != all.end (); ++it)
fputs (it->compose ().c_str (), out); fputs (it->compose ().c_str (), out);
fclose (out); fclose (out);
dbChanged ();
return true; return true;
} }
@@ -328,16 +326,14 @@ bool TDB::writePending (const T& t)
FILE* out; FILE* out;
if ((out = fopen (mPendingFile.c_str (), "a"))) if ((out = fopen (mPendingFile.c_str (), "a")))
{ {
#ifdef HAVE_FLOCK
int retry = 0; int retry = 0;
while (flock (fileno (out), LOCK_EX) && ++retry <= 3) if (!mNoLock)
delay (0.25); while (flock (fileno (out), LOCK_EX) && ++retry <= 3)
#endif delay (0.1);
fputs (t.compose ().c_str (), out); fputs (t.compose ().c_str (), out);
fclose (out); fclose (out);
dbChanged ();
return true; return true;
} }
@@ -351,17 +347,14 @@ bool TDB::writeCompleted (const T& t)
FILE* out; FILE* out;
if ((out = fopen (mCompletedFile.c_str (), "a"))) if ((out = fopen (mCompletedFile.c_str (), "a")))
{ {
#ifdef HAVE_FLOCK
int retry = 0; int retry = 0;
while (flock (fileno (out), LOCK_EX) && ++retry <= 3) if (!mNoLock)
delay (0.25); while (flock (fileno (out), LOCK_EX) && ++retry <= 3)
#endif delay (0.1);
fputs (t.compose ().c_str (), out); fputs (t.compose ().c_str (), out);
fclose (out); fclose (out);
// Note: No call to dbChanged here because this call never occurs by itself.
// It is always accompanied by an overwritePending call.
return true; return true;
} }
@@ -380,11 +373,10 @@ bool TDB::readLockedFile (
FILE* in; FILE* in;
if ((in = fopen (file.c_str (), "r"))) if ((in = fopen (file.c_str (), "r")))
{ {
#ifdef HAVE_FLOCK
int retry = 0; int retry = 0;
while (flock (fileno (in), LOCK_EX) && ++retry <= 3) if (!mNoLock)
delay (0.25); while (flock (fileno (in), LOCK_EX) && ++retry <= 3)
#endif delay (0.1);
char line[T_LINE_MAX]; char line[T_LINE_MAX];
while (fgets (line, T_LINE_MAX, in)) while (fgets (line, T_LINE_MAX, in))
@@ -406,6 +398,8 @@ bool TDB::readLockedFile (
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Scans the pending tasks for any that are completed or deleted, and if so,
// moves them to the completed.data file. Returns a count of tasks moved.
int TDB::gc () int TDB::gc ()
{ {
int count = 0; int count = 0;
@@ -423,7 +417,9 @@ int TDB::gc ()
// Some tasks stay in the pending file. // Some tasks stay in the pending file.
if (it->getStatus () == T::pending || if (it->getStatus () == T::pending ||
it->getStatus () == T::recurring) it->getStatus () == T::recurring)
{
pending.push_back (*it); pending.push_back (*it);
}
// Others are transferred to the completed file. // Others are transferred to the completed file.
else else
@@ -448,19 +444,9 @@ int TDB::nextId ()
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void TDB::onChange (void (*callback)()) void TDB::noLock ()
{ {
if (callback) mNoLock = true;
mOnChange.push_back (callback);
}
////////////////////////////////////////////////////////////////////////////////
// Iterate over callbacks.
void TDB::dbChanged ()
{
foreach (i, mOnChange)
if (*i)
(**i) ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under
@@ -51,7 +51,7 @@ public:
int gc (); int gc ();
int nextId (); int nextId ();
void onChange (void (*)()); void noLock ();
private: private:
bool lock (FILE*) const; bool lock (FILE*) const;
@@ -59,13 +59,12 @@ private:
bool writePending (const T&); bool writePending (const T&);
bool writeCompleted (const T&); bool writeCompleted (const T&);
bool readLockedFile (const std::string&, std::vector <std::string>&) const; bool readLockedFile (const std::string&, std::vector <std::string>&) const;
void dbChanged ();
private: private:
std::string mPendingFile; std::string mPendingFile;
std::string mCompletedFile; std::string mCompletedFile;
int mId; int mId;
std::vector <void (*)()> mOnChange; bool mNoLock;
}; };
#endif #endif

View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under
@@ -227,7 +227,7 @@ void Table::setRowBg (const int row, const Text::color c)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Table::addCell (const int row, const int col, const std::string& data) void Table::addCell (const int row, const int col, const std::string& data)
{ {
int length = 0; unsigned int length = 0;
if (mSuppressWS) if (mSuppressWS)
{ {
@@ -238,7 +238,19 @@ void Table::addCell (const int row, const int col, const std::string& data)
data2 = data; data2 = data;
clean (data2); clean (data2);
length = data2.length (); // For multi-line cells, find the longest line.
if (data2.find ("\n") != std::string::npos)
{
length = 0;
std::vector <std::string> lines;
split (lines, data2, "\n");
for (unsigned int i = 0; i < lines.size (); ++i)
if (lines[i].length () > length)
length = lines[i].length ();
}
else
length = data2.length ();
mData.add (row, col, data2); mData.add (row, col, data2);
} }
else else
@@ -248,11 +260,22 @@ void Table::addCell (const int row, const int col, const std::string& data)
else else
mData.add (row, col, data); mData.add (row, col, data);
length = data.length (); // For multi-line cells, find the longest line.
if (data.find ("\n") != std::string::npos)
{
length = 0;
std::vector <std::string> lines;
split (lines, data, "\n");
for (unsigned int i = 0; i < lines.size (); ++i)
if (lines[i].length () > length)
length = lines[i].length ();
}
else
length = data.length ();
} }
// Automatically maintain max width. // Automatically maintain max width.
mMaxDataWidth[col] = max (mMaxDataWidth[col], length); mMaxDataWidth[col] = max (mMaxDataWidth[col], (int)length);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -508,9 +531,7 @@ void Table::calculateColumnWidths ()
} }
else else
{ {
// std::cout << "# insufficient room, considering only flexible columns." << std::endl; // The fallback position is to assume no width was specified, and just
// The fallback position is to assume no width was specificed, and just
// calculate widths accordingly. // calculate widths accordingly.
mTableWidth = 0; mTableWidth = 0;
calculateColumnWidths (); calculateColumnWidths ();
@@ -736,34 +757,84 @@ int Table::columnCount ()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Removes extraneous output characters, such as: // Removes extraneous output characters, such as:
// - spaces followed by a newline is collapsed to just a newline, if there is
// no Bg color.
// - removal of redundant color codes: // - removal of redundant color codes:
// ^[[31mName^[[0m ^[[31mValue^[[0m -> ^[[31mName Value^[[0m // ^[[31mName^[[0m ^[[31mValue^[[0m -> ^[[31mName Value^[[0m
// //
// This method is a work in progress. // This method is a work in progress.
void Table::optimize (std::string& output) void Table::optimize (std::string& output) const
{ {
/* // int start = output.length ();
int start = output.length ();
*/
// \s\n -> \n
size_t i = 0;
while ((i = output.find (" \n")) != std::string::npos)
{
output = output.substr (0, i) +
output.substr (i + 1, std::string::npos);
}
/* /*
std::cout << int ((100 * (start - output.length ()) / start)) Well, how about that!
<< "%" << std::endl;
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.
*/ */
// std::cout << int ((100 * (start - output.length ()) / start))
// << "%" << std::endl;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Combsort11, with O(n log n) average, O(n log n) worst case performance. // Combsort11, with O(n log n) average, O(n log n) worst case performance.
//
// function combsort11(array input)
// gap := input.size
//
// loop until gap <= 1 and swaps = 0
// if gap > 1
// gap := gap / 1.3
// if gap = 10 or gap = 9
// gap := 11
// end if
// end if
//
// i := 0
// swaps := 0
//
// loop until i + gap >= input.size
// if input[i] > input[i+gap]
// swap(input[i], input[i+gap])
// swaps := 1
// end if
// i := i + 1
// end loop
//
// end loop
// end function
#define SWAP \ #define SWAP \
{ \ { \
int temp = order[r]; \ int temp = order[r]; \
@@ -776,7 +847,7 @@ void Table::sort (std::vector <int>& order)
int gap = order.size (); int gap = order.size ();
int swaps = 1; int swaps = 1;
while (gap > 1 || swaps != 0) while (gap > 1 || swaps > 0)
{ {
if (gap > 1) if (gap > 1)
{ {
@@ -797,10 +868,28 @@ void Table::sort (std::vector <int>& order)
Grid::Cell* left = mData.byRow (order[r], mSortColumns[c]); Grid::Cell* left = mData.byRow (order[r], mSortColumns[c]);
Grid::Cell* right = mData.byRow (order[r + gap], mSortColumns[c]); Grid::Cell* right = mData.byRow (order[r + gap], mSortColumns[c]);
if (left == NULL && right != NULL)
SWAP
if (left && right && *left != *right) // Data takes precedence over missing data.
if (left == NULL && right != NULL)
{
SWAP
break;
}
// No data - try comparing the next column.
else if (left == NULL && right == NULL)
{
keepScanning = true;
}
// Identical data - try comparing the next column.
else if (left && right && *left == *right)
{
keepScanning = true;
}
// Differing data - do a proper comparison.
else if (left && right && *left != *right)
{ {
switch (mSortOrder[mSortColumns[c]]) switch (mSortOrder[mSortColumns[c]])
{ {
@@ -861,24 +950,38 @@ void Table::sort (std::vector <int>& order)
break; break;
case ascendingPriority: case ascendingPriority:
if (((std::string)*left == "" && (std::string)*right != "") || if (((std::string)*left == "" && (std::string)*right != "") ||
((std::string)*left == "M" && (std::string)*right == "L") || ((std::string)*left == "M" && (std::string)*right == "L") ||
((std::string)*left == "H" && ((std::string)*right == "L" || (std::string)*right == "M"))) ((std::string)*left == "H" && ((std::string)*right == "L" || (std::string)*right == "M")))
SWAP SWAP
break; break;
case descendingPriority: case descendingPriority:
if (((std::string)*left == "" && (std::string)*right != "") || if (((std::string)*left == "" && (std::string)*right != "") ||
((std::string)*left == "L" && ((std::string)*right == "M" || (std::string)*right == "H")) || ((std::string)*left == "L" && ((std::string)*right == "M" || (std::string)*right == "H")) ||
((std::string)*left == "M" && (std::string)*right == "H")) ((std::string)*left == "M" && (std::string)*right == "H"))
SWAP
break;
case ascendingPeriod:
if ((std::string)*left == "" && (std::string)*right != "")
break;
else if ((std::string)*left != "" && (std::string)*right == "")
SWAP
else if (convertDuration ((std::string)*left) > convertDuration ((std::string)*right))
SWAP
break;
case descendingPeriod:
if ((std::string)*left != "" && (std::string)*right == "")
break;
else if ((std::string)*left == "" && (std::string)*right != "")
SWAP
else if (convertDuration ((std::string)*left) < convertDuration ((std::string)*right))
SWAP SWAP
break; break;
} }
break;
} }
else
keepScanning = true;
} }
++r; ++r;
@@ -912,7 +1015,7 @@ void Table::clean (std::string& value)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
const std::string Table::render () const std::string Table::render (int maximum /* = 0 */)
{ {
calculateColumnWidths (); calculateColumnWidths ();
@@ -946,8 +1049,14 @@ const std::string Table::render ()
if (mSortColumns.size ()) if (mSortColumns.size ())
sort (order); sort (order);
// If a non-zero maximum 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);
// Print all rows. // Print all rows.
for (int row = 0; row < mRows; ++row) for (int row = 0; row < limit; ++row)
{ {
std::vector <std::vector <std::string> > columns; std::vector <std::vector <std::string> > columns;
std::vector <std::string> blanks; std::vector <std::string> blanks;
@@ -981,15 +1090,19 @@ const std::string Table::render ()
else else
output += blanks[col]; output += blanks[col];
// Trim right.
output.erase (output.find_last_not_of (" ") + 1);
output += "\n"; output += "\n";
} }
} }
else else
{
// Trim right.
output.erase (output.find_last_not_of (" ") + 1);
output += "\n"; output += "\n";
}
} }
// Eliminate redundant color codes.
optimize (output);
return output; return output;
} }

View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under
@@ -37,9 +37,16 @@ class Table
{ {
public: public:
enum just {left, center, right}; enum just {left, center, right};
enum order {ascendingNumeric, ascendingCharacter, ascendingPriority, enum order {ascendingNumeric,
ascendingDate, descendingNumeric, descendingCharacter, ascendingCharacter,
descendingPriority, descendingDate}; ascendingPriority,
ascendingDate,
ascendingPeriod,
descendingNumeric,
descendingCharacter,
descendingPriority,
descendingDate,
descendingPeriod};
enum sizing {minimum = -1, flexible = 0}; enum sizing {minimum = -1, flexible = 0};
Table (); Table ();
@@ -84,7 +91,7 @@ public:
int rowCount (); int rowCount ();
int columnCount (); int columnCount ();
const std::string render (); const std::string render (int maximum = 0);
private: private:
std::string getCell (const int, const int); std::string getCell (const int, const int);
@@ -101,9 +108,9 @@ private:
const std::string formatHeader (const int, const int, const int); const std::string formatHeader (const int, const int, const int);
const std::string formatHeaderDashedUnderline (const int, const int, const int); const std::string formatHeaderDashedUnderline (const int, const int, const int);
void formatCell (const int, const int, const int, const int, std::vector <std::string>&, std::string&); void formatCell (const int, const int, const int, const int, std::vector <std::string>&, std::string&);
void optimize (std::string&);
void sort (std::vector <int>&); void sort (std::vector <int>&);
void clean (std::string&); void clean (std::string&);
void optimize (std::string&) const;
private: private:
std::vector <std::string> mColumns; std::vector <std::string> mColumns;

56
src/Timer.cpp Normal file
View File

@@ -0,0 +1,56 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <iomanip>
#include <Timer.h>
////////////////////////////////////////////////////////////////////////////////
// Timer starts when the object is constructed.
Timer::Timer (const std::string& description)
: mDescription (description)
{
::gettimeofday (&mStart, NULL);
}
////////////////////////////////////////////////////////////////////////////////
// Timer stops when the object is desctructed.
Timer::~Timer ()
{
struct timeval end;
::gettimeofday (&end, NULL);
std::cout << "Timer "
<< mDescription
<< " "
<< std::setprecision (6)
<< ((end.tv_sec - mStart.tv_sec) +
((end.tv_usec - mStart.tv_usec ) / 1000000.0))
<< std::endl;
}
////////////////////////////////////////////////////////////////////////////////

46
src/Timer.h Normal file
View File

@@ -0,0 +1,46 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_TIMER
#define INCLUDED_TIMER
#include <string>
#include <sys/time.h>
class Timer
{
public:
Timer (const std::string&);
~Timer ();
private:
std::string mDescription;
struct timeval mStart;
};
#endif
////////////////////////////////////////////////////////////////////////////////

View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under

View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under

View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under
@@ -48,8 +48,10 @@
#endif #endif
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleAdd (TDB& tdb, T& task, Config& conf) std::string handleAdd (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
char entryTime[16]; char entryTime[16];
sprintf (entryTime, "%u", (unsigned int) time (NULL)); sprintf (entryTime, "%u", (unsigned int) time (NULL));
task.setAttribute ("entry", entryTime); task.setAttribute ("entry", entryTime);
@@ -86,6 +88,8 @@ void handleAdd (TDB& tdb, T& task, Config& conf)
if (!tdb.addT (task)) if (!tdb.addT (task))
throw std::string ("Could not create new task."); throw std::string ("Could not create new task.");
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -113,7 +117,7 @@ std::string handleProjects (TDB& tdb, T& task, Config& conf)
table.addColumn ("Project"); table.addColumn ("Project");
table.addColumn ("Tasks"); table.addColumn ("Tasks");
if (conf.get ("color", true)) if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{ {
table.setColumnUnderline (0); table.setColumnUnderline (0);
table.setColumnUnderline (1); table.setColumnUnderline (1);
@@ -279,7 +283,7 @@ std::string handleVersion (Config& conf)
std::stringstream out; std::stringstream out;
// Determine window size, and set table accordingly. // Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80); int width = conf.get ("defaultwidth", (int) 80);
#ifdef HAVE_LIBNCURSES #ifdef HAVE_LIBNCURSES
if (conf.get ("curses", true)) if (conf.get ("curses", true))
{ {
@@ -307,7 +311,9 @@ std::string handleVersion (Config& conf)
link.setColumnWidth (0, Table::flexible); link.setColumnWidth (0, Table::flexible);
link.setColumnJustification (0, Table::left); link.setColumnJustification (0, Table::left);
link.addCell (link.addRow (), 0, link.addCell (link.addRow (), 0,
"See http://www.beckingham.net/task.html for the latest releases and a full tutorial."); "See http://www.beckingham.net/task.html for the latest releases and a "
"full tutorial. New releases containing fixes and enhancements are "
"made frequently.");
// Create a table for output. // Create a table for output.
Table table; Table table;
@@ -316,7 +322,7 @@ std::string handleVersion (Config& conf)
table.addColumn ("Config variable"); table.addColumn ("Config variable");
table.addColumn ("Value"); table.addColumn ("Value");
if (conf.get ("color", true)) if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{ {
table.setColumnUnderline (0); table.setColumnUnderline (0);
table.setColumnUnderline (1); table.setColumnUnderline (1);
@@ -343,11 +349,15 @@ std::string handleVersion (Config& conf)
} }
} }
out << "Copyright (C) 2006 - 2008, P. Beckingham." out << "Copyright (C) 2006 - 2009, P. Beckingham."
<< std::endl << std::endl
<< (conf.get ("color", true) ? Text::colorize (Text::bold, Text::nocolor, PACKAGE) : PACKAGE) << ((conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
? Text::colorize (Text::bold, Text::nocolor, PACKAGE)
: PACKAGE)
<< " " << " "
<< (conf.get ("color", true) ? Text::colorize (Text::bold, Text::nocolor, VERSION) : VERSION) << ((conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
? Text::colorize (Text::bold, Text::nocolor, VERSION)
: VERSION)
<< std::endl << std::endl
<< disclaimer.render () << disclaimer.render ()
<< std::endl << std::endl
@@ -359,10 +369,20 @@ std::string handleVersion (Config& conf)
// These are the regular configuration variables. // These are the regular configuration variables.
std::string recognized = std::string recognized =
"blanklines color color.active color.due color.overdue color.pri.H " "blanklines color color.active color.due color.overdue color.pri.H "
"color.pri.L color.pri.M color.pri.none color.tagged confirmation curses " "color.pri.L color.pri.M color.pri.none color.recurring color.tagged "
"data.location dateformat default.command default.priority defaultwidth due " "confirmation curses data.location dateformat default.command "
"monthsperline nag newest next oldest project shadow.command shadow.file " "default.priority defaultwidth due echo.command locking monthsperline nag "
"shadow.notify"; "next project shadow.command shadow.file shadow.notify "
"import.synonym.id import.synonym.uuid import.synonym.status "
"import.synonym.tags import.synonym.entry import.synonym.start "
"import.synonym.due import.synonym.recur import.synonym.end "
"import.synonym.project import.synonym.priority import.synonym.fg "
"import.synonym.bg import.synonym.description";
// This configuration variable is supported, but not documented. It exists
// so that unit tests can force color to be on even when the output from task
// is redirected to a file, or stdout is not a tty.
recognized += " _forcecolor";
std::vector <std::string> unrecognized; std::vector <std::string> unrecognized;
foreach (i, all) foreach (i, all)
@@ -417,7 +437,9 @@ std::string handleVersion (Config& conf)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::string handleDelete (TDB& tdb, T& task, Config& conf) std::string handleDelete (TDB& tdb, T& task, Config& conf)
{ {
if (conf.get ("confirmation") != "yes" || confirm ("Permanently delete task?")) std::stringstream out;
if (!conf.get (std::string ("confirmation"), false) || confirm ("Permanently delete task?"))
{ {
std::vector <T> all; std::vector <T> all;
tdb.allPendingT (all); tdb.allPendingT (all);
@@ -435,11 +457,19 @@ std::string handleDelete (TDB& tdb, T& task, Config& conf)
// Scan all pending tasks for siblings of this task, and the parent // Scan all pending tasks for siblings of this task, and the parent
// itself, and delete them. // itself, and delete them.
foreach (sibling, all) foreach (sibling, all)
{
if (sibling->getAttribute ("parent") == parent || if (sibling->getAttribute ("parent") == parent ||
sibling->getUUID () == parent) sibling->getUUID () == parent)
{
tdb.deleteT (*sibling); tdb.deleteT (*sibling);
if (conf.get ("echo.command", true))
return std::string (""); out << "Deleting recurring task "
<< sibling->getId ()
<< " "
<< sibling->getDescription ()
<< std::endl;
}
}
} }
else else
{ {
@@ -447,20 +477,32 @@ std::string handleDelete (TDB& tdb, T& task, Config& conf)
t->setStatus (T::deleted); t->setStatus (T::deleted);
updateRecurrenceMask (tdb, all, *t); updateRecurrenceMask (tdb, all, *t);
tdb.deleteT (*t); tdb.deleteT (*t);
return std::string (""); out << "Deleting recurring task "
<< t->getId ()
<< " "
<< t->getDescription ()
<< std::endl;
} }
} }
else else
{
tdb.deleteT (*t); tdb.deleteT (*t);
if (conf.get ("echo.command", true))
out << "Deleting task "
<< t->getId ()
<< " "
<< t->getDescription ()
<< std::endl;
}
break; // No point continuing the loop. break; // No point continuing the loop.
} }
} }
} }
else else
return std::string ("Task not deleted.\n"); out << "Task not deleted." << std::endl;
return std::string (""); return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -475,6 +517,7 @@ std::string handleStart (TDB& tdb, T& task, Config& conf)
if (it->getId () == task.getId ()) if (it->getId () == task.getId ())
{ {
T original (*it); T original (*it);
std::stringstream out;
if (original.getAttribute ("start") == "") if (original.getAttribute ("start") == "")
{ {
@@ -485,15 +528,20 @@ std::string handleStart (TDB& tdb, T& task, Config& conf)
original.setId (task.getId ()); original.setId (task.getId ());
tdb.modifyT (original); tdb.modifyT (original);
if (conf.get ("echo.command", true))
out << "Started "
<< original.getId ()
<< " "
<< original.getDescription ()
<< std::endl;
nag (tdb, task, conf); nag (tdb, task, conf);
return std::string ("");
} }
else else
{ {
std::stringstream out;
out << "Task " << task.getId () << " already started." << std::endl; out << "Task " << task.getId () << " already started." << std::endl;
return out.str ();
} }
return out.str ();
} }
} }
@@ -513,6 +561,7 @@ std::string handleStop (TDB& tdb, T& task, Config& conf)
if (it->getId () == task.getId ()) if (it->getId () == task.getId ())
{ {
T original (*it); T original (*it);
std::stringstream out;
if (original.getAttribute ("start") != "") if (original.getAttribute ("start") != "")
{ {
@@ -520,15 +569,15 @@ std::string handleStop (TDB& tdb, T& task, Config& conf)
original.setId (task.getId ()); original.setId (task.getId ());
tdb.modifyT (original); tdb.modifyT (original);
nag (tdb, task, conf); if (conf.get ("echo.command", true))
return std::string (""); out << "Stopped " << original.getId () << " " << original.getDescription () << std::endl;
} }
else else
{ {
std::stringstream out;
out << "Task " << task.getId () << " not started." << std::endl; out << "Task " << task.getId () << " not started." << std::endl;
return out.str ();
} }
return out.str ();
} }
} }
@@ -537,8 +586,10 @@ std::string handleStop (TDB& tdb, T& task, Config& conf)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleDone (TDB& tdb, T& task, Config& conf) std::string handleDone (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
if (!tdb.completeT (task)) if (!tdb.completeT (task))
throw std::string ("Could not mark task as completed."); throw std::string ("Could not mark task as completed.");
@@ -549,6 +600,13 @@ void handleDone (TDB& tdb, T& task, Config& conf)
{ {
if (t->getId () == task.getId ()) if (t->getId () == task.getId ())
{ {
if (conf.get ("echo.command", true))
out << "Completed "
<< t->getId ()
<< " "
<< t->getDescription ()
<< std::endl;
t->setStatus (T::completed); t->setStatus (T::completed);
updateRecurrenceMask (tdb, all, *t); updateRecurrenceMask (tdb, all, *t);
break; break;
@@ -556,11 +614,14 @@ void handleDone (TDB& tdb, T& task, Config& conf)
} }
nag (tdb, task, conf); nag (tdb, task, conf);
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleExport (TDB& tdb, T& task, Config& conf) std::string handleExport (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream output;
// Use the description as a file name, then clobber the description so the // Use the description as a file name, then clobber the description so the
// file name isn't used for filtering. // file name isn't used for filtering.
std::string file = trim (task.getDescription ()); std::string file = trim (task.getDescription ());
@@ -578,6 +639,7 @@ void handleExport (TDB& tdb, T& task, Config& conf)
<< "'entry'," << "'entry',"
<< "'start'," << "'start',"
<< "'due'," << "'due',"
<< "'recur',"
<< "'end'," << "'end',"
<< "'project'," << "'project',"
<< "'priority'," << "'priority',"
@@ -586,32 +648,61 @@ void handleExport (TDB& tdb, T& task, Config& conf)
<< "'description'" << "'description'"
<< "\n"; << "\n";
int count = 0;
std::vector <T> all; std::vector <T> all;
tdb.allT (all); tdb.allPendingT (all);
filter (all, task); filter (all, task);
foreach (t, all) foreach (t, all)
{ {
out << t->composeCSV ().c_str (); if (t->getStatus () != T::recurring &&
t->getStatus () != T::deleted)
{
out << t->composeCSV ().c_str ();
++count;
}
} }
out.close (); out.close ();
output << count << " tasks exported to '" << file << "'" << std::endl;
} }
else else
throw std::string ("Could not write to export file."); throw std::string ("Could not write to export file.");
} }
else else
throw std::string ("You must specify a file to write to."); throw std::string ("You must specify a file to write to.");
return output.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleModify (TDB& tdb, T& task, Config& conf) std::string handleModify (TDB& tdb, T& task, Config& conf)
{ {
std::stringstream out;
std::vector <T> all; std::vector <T> all;
tdb.pendingT (all); tdb.allPendingT (all);
// Lookup the complete task.
T complete = findT (task.getId (), all);
// Perform some logical consistency checks.
if (task.getAttribute ("recur") != "" &&
task.getAttribute ("due") == "" &&
complete.getAttribute ("due") == "")
throw std::string ("You cannot specify a recurring task without a due date.");
if (task.getAttribute ("until") != "" &&
task.getAttribute ("recur") == "" &&
complete.getAttribute ("recur") == "")
throw std::string ("You cannot specify an until date for a non-recurring task.");
int count = 0;
std::vector <T>::iterator it; std::vector <T>::iterator it;
for (it = all.begin (); it != all.end (); ++it) for (it = all.begin (); it != all.end (); ++it)
{ {
if (it->getId () == task.getId ()) if (it->getId () == complete.getId () || // Self
(complete.getAttribute ("parent") != "" &&
it->getAttribute ("parent") == complete.getAttribute ("parent")) || // Sibling
it->getUUID () == complete.getAttribute ("parent")) // Parent
{ {
T original (*it); T original (*it);
@@ -657,39 +748,192 @@ void handleModify (TDB& tdb, T& task, Config& conf)
if (i->second == "") if (i->second == "")
original.removeAttribute (i->first); original.removeAttribute (i->first);
else else
{
original.setAttribute (i->first, i->second); original.setAttribute (i->first, i->second);
// If a "recur" attribute is added, upgrade to a recurring task.
if (i->first == "recur")
original.setStatus (T::recurring);
}
++changes; ++changes;
} }
std::string from; std::string from;
std::string to; std::string to;
task.getSubstitution (from, to); bool global;
task.getSubstitution (from, to, global);
if (from != "") if (from != "")
{ {
std::string description = original.getDescription (); std::string description = original.getDescription ();
size_t pattern = description.find (from); size_t pattern;
if (pattern != std::string::npos)
if (global)
{ {
description = description.substr (0, pattern) + // Perform all subs on description.
to + while ((pattern = description.find (from)) != std::string::npos)
description.substr (pattern + from.length (), std::string::npos); {
description.replace (pattern, from.length (), to);
++changes;
}
original.setDescription (description); original.setDescription (description);
++changes;
// Perform all subs on annotations.
std::map <time_t, std::string> annotations;
original.getAnnotations (annotations);
std::map <time_t, std::string>::iterator it;
for (it = annotations.begin (); it != annotations.end (); ++it)
{
while ((pattern = it->second.find (from)) != std::string::npos)
{
it->second.replace (pattern, from.length (), to);
++changes;
}
}
original.setAnnotations (annotations);
}
else
{
// Perform first description substitution.
if ((pattern = description.find (from)) != std::string::npos)
{
description.replace (pattern, from.length (), to);
original.setDescription (description);
++changes;
}
// Failing that, perform the first annotation substitution.
else
{
std::map <time_t, std::string> annotations;
original.getAnnotations (annotations);
std::map <time_t, std::string>::iterator it;
for (it = annotations.begin (); it != annotations.end (); ++it)
{
if ((pattern = it->second.find (from)) != std::string::npos)
{
it->second.replace (pattern, from.length (), to);
++changes;
break;
}
}
original.setAnnotations (annotations);
}
} }
} }
if (changes) if (changes)
{
original.setId (task.getId ());
tdb.modifyT (original); tdb.modifyT (original);
}
return; ++count;
} }
} }
throw std::string ("Task not found."); if (count == 0)
throw std::string ("Task not found.");
if (conf.get ("echo.command", true))
out << "Modified " << count << " task" << (count == 1 ? "" : "s") << std::endl;
return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
std::string handleAppend (TDB& tdb, T& task, Config& conf)
{
std::stringstream out;
std::vector <T> all;
tdb.allPendingT (all);
// Lookup the complete task.
T complete = findT (task.getId (), all);
int count = 0;
std::vector <T>::iterator it;
for (it = all.begin (); it != all.end (); ++it)
{
if (it->getId () == complete.getId () || // Self
(complete.getAttribute ("parent") != "" &&
it->getAttribute ("parent") == complete.getAttribute ("parent")) || // Sibling
it->getUUID () == complete.getAttribute ("parent")) // Parent
{
T original (*it);
// A non-zero value forces a file write.
int changes = 0;
// Apply a new description, if any.
if (task.getDescription () != "")
{
original.setDescription (original.getDescription () +
" " +
task.getDescription ());
++changes;
}
// Apply or remove tags, if any.
std::vector <std::string> tags;
task.getTags (tags);
for (unsigned int i = 0; i < tags.size (); ++i)
{
if (tags[i][0] == '+')
original.addTag (tags[i].substr (1, std::string::npos));
else
original.addTag (tags[i]);
++changes;
}
task.getRemoveTags (tags);
for (unsigned int i = 0; i < tags.size (); ++i)
{
if (tags[i][0] == '-')
original.removeTag (tags[i].substr (1, std::string::npos));
else
original.removeTag (tags[i]);
++changes;
}
// Apply or remove attributes, if any.
std::map <std::string, std::string> attributes;
task.getAttributes (attributes);
foreach (i, attributes)
{
if (i->second == "")
original.removeAttribute (i->first);
else
original.setAttribute (i->first, i->second);
++changes;
}
if (changes)
{
tdb.modifyT (original);
if (conf.get ("echo.command", true))
out << "Appended '"
<< task.getDescription ()
<< "' to task "
<< original.getId ()
<< std::endl;
}
++count;
}
}
if (count == 0)
throw std::string ("Task not found.");
if (conf.get ("echo.command", true))
out << "Modified " << count << " task" << (count == 1 ? "" : "s") << std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -697,7 +941,7 @@ std::string handleColor (Config& conf)
{ {
std::stringstream out; std::stringstream out;
if (conf.get ("color", true)) if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{ {
out << optionalBlankLine (conf) << "Foreground" << std::endl out << optionalBlankLine (conf) << "Foreground" << std::endl
<< " " << " "
@@ -781,3 +1025,45 @@ std::string handleColor (Config& conf)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::string handleAnnotate (TDB& tdb, T& task, Config& conf)
{
std::stringstream out;
std::vector <T> all;
tdb.pendingT (all);
std::vector <T>::iterator it;
for (it = all.begin (); it != all.end (); ++it)
{
if (it->getId () == task.getId ())
{
it->addAnnotation (task.getDescription ());
tdb.modifyT (*it);
if (conf.get ("echo.command", true))
out << "Annotated "
<< task.getId ()
<< " with '"
<< task.getDescription ()
<< "'"
<< std::endl;
return out.str ();
}
}
throw std::string ("Task not found.");
return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
T findT (int id, const std::vector <T>& all)
{
std::vector <T>::const_iterator it;
for (it = all.begin (); it != all.end (); ++it)
if (id == it->getId ())
return *it;
return T ();
}
////////////////////////////////////////////////////////////////////////////////

1203
src/import.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under
@@ -120,6 +120,8 @@ static const char* commands[] =
{ {
"active", "active",
"add", "add",
"append",
"annotate",
"calendar", "calendar",
"colors", "colors",
"completed", "completed",
@@ -129,13 +131,9 @@ static const char* commands[] =
"help", "help",
"history", "history",
"ghistory", "ghistory",
"import",
"info", "info",
"list",
"long",
"ls",
"newest",
"next", "next",
"oldest",
"overdue", "overdue",
"projects", "projects",
"start", "start",
@@ -164,7 +162,6 @@ void guess (const std::string& type, const char** list, std::string& candidate)
candidate = matches[0]; candidate = matches[0];
else if (0 == matches.size ()) else if (0 == matches.size ())
// throw std::string ("Unrecognized ") + type + " '" + candidate + "'";
candidate = ""; candidate = "";
else else
@@ -194,7 +191,6 @@ void guess (const std::string& type, std::vector<std::string>& options, std::str
candidate = matches[0]; candidate = matches[0];
else if (0 == matches.size ()) else if (0 == matches.size ())
// throw std::string ("Unrecognized ") + type + " '" + candidate + "'";
candidate = ""; candidate = "";
else else
@@ -239,7 +235,7 @@ bool validDate (std::string& date, Config& conf)
{ {
Date test (date, conf.get ("dateformat", "m/d/Y")); Date test (date, conf.get ("dateformat", "m/d/Y"));
char epoch[12]; char epoch[16];
sprintf (epoch, "%d", (int) test.toEpoch ()); sprintf (epoch, "%d", (int) test.toEpoch ());
date = epoch; date = epoch;
@@ -352,7 +348,8 @@ static bool validCommand (std::string& input)
static bool validSubstitution ( static bool validSubstitution (
std::string& input, std::string& input,
std::string& from, std::string& from,
std::string& to) std::string& to,
bool& global)
{ {
size_t first = input.find ('/'); size_t first = input.find ('/');
if (first != std::string::npos) if (first != std::string::npos)
@@ -366,10 +363,17 @@ static bool validSubstitution (
if (first == 0 && if (first == 0 &&
first < second && first < second &&
second < third && second < third &&
third == input.length () - 1) (third == input.length () - 1 ||
third == input.length () - 2))
{ {
from = input.substr (first + 1, second - first - 1); from = input.substr (first + 1, second - first - 1);
to = input.substr (second + 1, third - second - 1); to = input.substr (second + 1, third - second - 1);
global = false;
if (third == input.length () - 2 &&
input.find ('g', third + 1) != std::string::npos)
global = true;
return true; return true;
} }
} }
@@ -415,6 +419,7 @@ void parse (
size_t colon; // Pointer to colon in argument. size_t colon; // Pointer to colon in argument.
std::string from; std::string from;
std::string to; std::string to;
bool global;
// An id is the first argument found that contains all digits. // An id is the first argument found that contains all digits.
if (lowerCase (command) != "add" && // "add" doesn't require an ID if (lowerCase (command) != "add" && // "add" doesn't require an ID
@@ -447,13 +452,17 @@ void parse (
// If it is not a valid attribute, then allow the argument as part of // If it is not a valid attribute, then allow the argument as part of
// the description. // the description.
else else
{
if (descCandidate.length ())
descCandidate += " ";
descCandidate += arg; descCandidate += arg;
}
} }
// Substitution of description text. // Substitution of description text.
else if (validSubstitution (arg, from, to)) else if (validSubstitution (arg, from, to, global))
{ {
task.setSubstitution (from, to); task.setSubstitution (from, to, global);
} }
// Command. // Command.
@@ -463,23 +472,23 @@ void parse (
if (isCommand (l) && validCommand (l)) if (isCommand (l) && validCommand (l))
command = l; command = l;
else else
{
if (descCandidate.length ())
descCandidate += " ";
descCandidate += arg; descCandidate += arg;
}
} }
// Anything else is just considered description. // Anything else is just considered description.
else else
descCandidate += std::string (arg) + " "; {
if (descCandidate.length ())
descCandidate += " ";
descCandidate += arg;
}
} }
} }
if (task.getAttribute ("recur") != "" &&
task.getAttribute ("due") == "")
throw std::string ("You cannot specify a recurring task without a due date.");
if (task.getAttribute ("until") != "" &&
task.getAttribute ("recur") == "")
throw std::string ("You cannot specify an until date for a non-recurring task.");
if (validDescription (descCandidate)) if (validDescription (descCandidate))
task.setDescription (descCandidate); task.setDescription (descCandidate);
} }
@@ -495,7 +504,7 @@ void loadCustomReports (Config& conf)
if (i->substr (0, 7) == "report.") if (i->substr (0, 7) == "report.")
{ {
std::string report = i->substr (7, std::string::npos); std::string report = i->substr (7, std::string::npos);
unsigned int columns = report.find (".columns"); std::string::size_type columns = report.find (".columns");
if (columns != std::string::npos) if (columns != std::string::npos)
{ {
report = report.substr (0, columns); report = report.substr (0, columns);
@@ -515,4 +524,10 @@ bool isCustomReport (const std::string& report)
return false; return false;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void allCustomReports (std::vector <std::string>& all)
{
all = customReports;
}
////////////////////////////////////////////////////////////////////////////////

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under
@@ -80,10 +80,14 @@ void initializeColorRules (Config& conf)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void autoColorize (T& task, Text::color& fg, Text::color& bg) void autoColorize (
T& task,
Text::color& fg,
Text::color& bg,
Config& conf)
{ {
// Note: fg, bg already contain colors specifically assigned via command. // Note: fg, bg already contain colors specifically assigned via command.
// Note: These rules form a hierarchy - the last rule is king. // Note: These rules form a hierarchy - the last rule is King.
// Colorization of the tagged. // Colorization of the tagged.
if (gsFg["color.tagged"] != Text::nocolor || if (gsFg["color.tagged"] != Text::nocolor ||
@@ -153,29 +157,6 @@ void autoColorize (T& task, Text::color& fg, Text::color& bg)
} }
} }
// Colorization of the due and overdue.
std::string due = task.getAttribute ("due");
if (due != "")
{
Date dueDate (::atoi (due.c_str ()));
Date now;
Date then (now + 7 * 86400);
// Overdue
if (dueDate < now)
{
fg = gsFg["color.overdue"];
bg = gsBg["color.overdue"];
}
// Imminent
else if (dueDate < then)
{
fg = gsFg["color.due"];
bg = gsBg["color.due"];
}
}
// Colorization by tag value. // Colorization by tag value.
std::map <std::string, Text::color>::iterator it; std::map <std::string, Text::color>::iterator it;
for (it = gsFg.begin (); it != gsFg.end (); ++it) for (it = gsFg.begin (); it != gsFg.end (); ++it)
@@ -219,6 +200,40 @@ void autoColorize (T& task, Text::color& fg, Text::color& bg)
} }
} }
} }
// Colorization of the due and overdue.
std::string due = task.getAttribute ("due");
if (due != "")
{
Date dueDate (::atoi (due.c_str ()));
Date now;
Date then (now + conf.get ("due", 7) * 86400);
// Overdue
if (dueDate < now)
{
fg = gsFg["color.overdue"];
bg = gsBg["color.overdue"];
}
// Imminent
else if (dueDate < then)
{
fg = gsFg["color.due"];
bg = gsBg["color.due"];
}
}
// Colorization of the recurring.
if (gsFg["color.recurring"] != Text::nocolor ||
gsBg["color.recurring"] != Text::nocolor)
{
if (task.getAttribute ("recur") != "")
{
fg = gsFg["color.recurring"];
bg = gsBg["color.recurring"];
}
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under
@@ -27,6 +27,7 @@
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <fstream> #include <fstream>
#include <sstream>
#include <sys/types.h> #include <sys/types.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@@ -47,15 +48,11 @@
#endif #endif
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Globals for exclusive use by callback function. static std::string shortUsage (Config& conf)
static TDB* gTdb = NULL;
static Config* gConf = NULL;
////////////////////////////////////////////////////////////////////////////////
static void shortUsage (Config& conf)
{ {
std::stringstream out;
Table table; Table table;
int width = conf.get ("defaultwidth", 80); int width = conf.get ("defaultwidth", (int) 80);
#ifdef HAVE_LIBNCURSES #ifdef HAVE_LIBNCURSES
if (conf.get ("curses", true)) if (conf.get ("curses", true))
{ {
@@ -88,16 +85,12 @@ static void shortUsage (Config& conf)
table.addCell (row, 2, "Adds a new task"); table.addCell (row, 2, "Adds a new task");
row = table.addRow (); row = table.addRow ();
table.addCell (row, 1, "task list [tags] [attrs] desc..."); table.addCell (row, 1, "task append [tags] [attrs] desc...");
table.addCell (row, 2, "Lists all tasks matching the specified criteria"); table.addCell (row, 2, "Appends more description to an existing task");
row = table.addRow (); row = table.addRow ();
table.addCell (row, 1, "task long [tags] [attrs] desc..."); table.addCell (row, 1, "task annotate ID desc...");
table.addCell (row, 2, "Lists all task, all data, matching the specified criteria"); table.addCell (row, 2, "Adds an annotation to an existing task");
row = table.addRow ();
table.addCell (row, 1, "task ls [tags] [attrs] desc...");
table.addCell (row, 2, "Minimal listing of all tasks matching the specified criteria");
row = table.addRow (); row = table.addRow ();
table.addCell (row, 1, "task completed [tags] [attrs] desc..."); table.addCell (row, 1, "task completed [tags] [attrs] desc...");
@@ -175,18 +168,14 @@ static void shortUsage (Config& conf)
table.addCell (row, 1, "task overdue"); table.addCell (row, 1, "task overdue");
table.addCell (row, 2, "Shows all incomplete tasks that are beyond their due date"); table.addCell (row, 2, "Shows all incomplete tasks that are beyond their due date");
row = table.addRow ();
table.addCell (row, 1, "task oldest");
table.addCell (row, 2, "Shows the oldest tasks");
row = table.addRow ();
table.addCell (row, 1, "task newest");
table.addCell (row, 2, "Shows the newest tasks");
row = table.addRow (); row = table.addRow ();
table.addCell (row, 1, "task stats"); table.addCell (row, 1, "task stats");
table.addCell (row, 2, "Shows task database statistics"); table.addCell (row, 2, "Shows task database statistics");
row = table.addRow ();
table.addCell (row, 1, "task import");
table.addCell (row, 2, "Imports tasks from a variety of formats");
row = table.addRow (); row = table.addRow ();
table.addCell (row, 1, "task export"); table.addCell (row, 1, "task export");
table.addCell (row, 2, "Exports all tasks as a CSV file"); table.addCell (row, 2, "Exports all tasks as a CSV file");
@@ -203,46 +192,65 @@ static void shortUsage (Config& conf)
table.addCell (row, 1, "task help"); table.addCell (row, 1, "task help");
table.addCell (row, 2, "Shows the long usage text"); table.addCell (row, 2, "Shows the long usage text");
std::cout << table.render () // Add custom reports here...
<< std::endl std::vector <std::string> all;
<< "See http://www.beckingham.net/task.html for the latest releases and a full tutorial." allCustomReports (all);
<< std::endl foreach (report, all)
<< std::endl; {
std::string command = std::string ("task ") + *report + std::string (" [tags] [attrs] desc...");
std::string description = conf.get (
std::string ("report.") + *report + ".description", std::string ("(missing description)"));
row = table.addRow ();
table.addCell (row, 1, command);
table.addCell (row, 2, description);
}
out << table.render ()
<< std::endl
<< "See http://www.beckingham.net/task.html for the latest releases and a "
<< "full tutorial. New releases containing fixes and enhancements are "
<< "made frequently."
<< std::endl
<< std::endl;
return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void longUsage (Config& conf) static std::string longUsage (Config& conf)
{ {
shortUsage (conf); std::stringstream out;
out << shortUsage (conf)
<< "ID is the numeric identifier displayed by the 'task list' command." << "\n"
<< "\n"
<< "Tags are arbitrary words, any quantity:" << "\n"
<< " +tag The + means add the tag" << "\n"
<< " -tag The - means remove the tag" << "\n"
<< "\n"
<< "Attributes are:" << "\n"
<< " project: Project name" << "\n"
<< " priority: Priority" << "\n"
<< " due: Due date" << "\n"
<< " recur: Recurrence frequency" << "\n"
<< " until: Recurrence end date" << "\n"
<< " fg: Foreground color" << "\n"
<< " bg: Background color" << "\n"
<< " rc: Alternate .taskrc file" << "\n"
<< "\n"
<< "Any command or attribute name may be abbreviated if still unique:" << "\n"
<< " task list project:Home" << "\n"
<< " task li pro:Home" << "\n"
<< "\n"
<< "Some task descriptions need to be escaped because of the shell:" << "\n"
<< " task add \"quoted ' quote\"" << "\n"
<< " task add escaped \\' quote" << "\n"
<< "\n"
<< "Many characters have special meaning to the shell, including:" << "\n"
<< " $ ! ' \" ( ) ; \\ ` * ? { } [ ] < > | & % # ~" << "\n"
<< std::endl;
std::cout return out.str ();
<< "ID is the numeric identifier displayed by the 'task list' command" << "\n"
<< "\n"
<< "Tags are arbitrary words, any quantity:" << "\n"
<< " +tag The + means add the tag" << "\n"
<< " -tag The - means remove the tag" << "\n"
<< "\n"
<< "Attributes are:" << "\n"
<< " project: Project name" << "\n"
<< " priority: Priority" << "\n"
<< " due: Due date" << "\n"
<< " recur: Recurrence frequency" << "\n"
<< " until: Recurrence end date" << "\n"
<< " fg: Foreground color" << "\n"
<< " bg: Background color" << "\n"
<< " rc: Alternate .taskrc file" << "\n"
<< "\n"
<< "Any command or attribute name may be abbreviated if still unique:" << "\n"
<< " task list project:Home" << "\n"
<< " task li pro:Home" << "\n"
<< "\n"
<< "Some task descriptions need to be escaped because of the shell:" << "\n"
<< " task add \"quoted ' quote\"" << "\n"
<< " task add escaped \\' quote" << "\n"
<< "\n"
<< "Many characters have special meaning to the shell, including:" << "\n"
<< " $ ! ' \" ( ) ; \\ ` * ? { } [ ] < > | & % # ~" << "\n"
<< std::endl;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -274,9 +282,6 @@ void loadConfFile (int argc, char** argv, Config& conf)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv) int main (int argc, char** argv)
{ {
// TODO Find out what this is, and either promote it to live code, or remove it.
// std::set_terminate (__gnu_cxx::__verbose_terminate_handler);
// Set up randomness. // Set up randomness.
#ifdef HAVE_SRANDOM #ifdef HAVE_SRANDOM
srandom (time (NULL)); srandom (time (NULL));
@@ -289,22 +294,26 @@ int main (int argc, char** argv)
// Load the config file from the home directory. If the file cannot be // Load the config file from the home directory. If the file cannot be
// found, offer to create a sample one. // found, offer to create a sample one.
Config conf; Config conf;
gConf = &conf;
loadConfFile (argc, argv, conf); loadConfFile (argc, argv, conf);
// When redirecting output to a file, do not use color, curses. // When redirecting output to a file, do not use color, curses.
if (!isatty (fileno (stdout))) if (!isatty (fileno (stdout)))
{ {
conf.set ("curses", "off"); conf.set ("curses", "off");
conf.set ("color", "off");
if (! conf.get (std::string ("_forcecolor"), false))
conf.set ("color", "off");
} }
TDB tdb; TDB tdb;
gTdb = &tdb;
std::string dataLocation = expandPath (conf.get ("data.location")); std::string dataLocation = expandPath (conf.get ("data.location"));
tdb.dataDirectory (dataLocation); tdb.dataDirectory (dataLocation);
// Set up TDB callback. // Allow user override of file locking. Solaris/NFS machines may want this.
if (! conf.get ("locking", true))
tdb.noLock ();
// Check for silly shadow file settings.
std::string shadowFile = expandPath (conf.get ("shadow.file")); std::string shadowFile = expandPath (conf.get ("shadow.file"));
if (shadowFile != "") if (shadowFile != "")
{ {
@@ -315,8 +324,6 @@ int main (int argc, char** argv)
if (shadowFile == dataLocation + "/completed.data") if (shadowFile == dataLocation + "/completed.data")
throw std::string ("Configuration variable 'shadow.file' is set to " throw std::string ("Configuration variable 'shadow.file' is set to "
"overwrite your completed tasks. Please change it."); "overwrite your completed tasks. Please change it.");
tdb.onChange (&onChangeCallback);
} }
std::cout << runTaskCommand (argc, argv, tdb, conf); std::cout << runTaskCommand (argc, argv, tdb, conf);
@@ -343,18 +350,56 @@ void nag (TDB& tdb, T& task, Config& conf)
std::string nagMessage = conf.get ("nag", std::string ("")); std::string nagMessage = conf.get ("nag", std::string (""));
if (nagMessage != "") if (nagMessage != "")
{ {
// Load all pending. // Load all pending tasks.
std::vector <T> pending; std::vector <T> pending;
tdb.allPendingT (pending); tdb.allPendingT (pending);
// Restrict to matching subset. // Counters.
std::vector <int> matching; int overdue = 0;
gatherNextTasks (tdb, task, conf, pending, matching); int high = 0;
int medium = 0;
int low = 0;
bool isOverdue = false;
char pri = ' ';
foreach (i, matching) // Scan all pending tasks.
if (pending[*i].getId () == task.getId ()) foreach (t, pending)
return; {
if (t->getId () == task.getId ())
{
if (getDueState (t->getAttribute ("due")) == 2)
isOverdue = true;
std::string priority = t->getAttribute ("priority");
if (priority.length ())
pri = priority[0];
}
else if (t->getStatus () == T::pending)
{
if (getDueState (t->getAttribute ("due")) == 2)
overdue++;
std::string priority = t->getAttribute ("priority");
if (priority.length ())
{
switch (priority[0])
{
case 'H': high++; break;
case 'M': medium++; break;
case 'L': low++; break;
}
}
}
}
// General form is "if there are no more deserving tasks", suppress the nag.
if (isOverdue ) return;
if (pri == 'H' && !overdue ) return;
if (pri == 'M' && !overdue && !high ) return;
if (pri == 'L' && !overdue && !high && !medium ) return;
if (pri == ' ' && !overdue && !high && !medium && !low) return;
// All the excuses are made, all that remains is to nag the user.
std::cout << nagMessage << std::endl; std::cout << nagMessage << std::endl;
} }
} }
@@ -372,15 +417,12 @@ int getDueState (const std::string& due)
// rightNow is the current date + time. // rightNow is the current date + time.
Date rightNow; Date rightNow;
Date midnight (rightNow.month (), rightNow.day (), rightNow.year ());
// By performing this conversion, today is set up as the same date, but if (dt < midnight)
// midnight.
Date today (rightNow.month (), rightNow.day (), rightNow.year ());
if (dt < today)
return 2; return 2;
Date nextweek = today + 7 * 86400; Date nextweek = midnight + 7 * 86400;
if (dt < nextweek) if (dt < nextweek)
return 1; return 1;
} }
@@ -531,6 +573,18 @@ Date getNextRecurrence (Date& current, std::string& period)
return Date (m, d, y); return Date (m, d, y);
} }
if (period == "weekdays")
{
int dow = current.dayOfWeek ();
int days;
if (dow == 5) days = 3;
else if (dow == 6) days = 2;
else days = 1;
return current + (days * 86400);
}
if (isdigit (period[0]) && period[period.length () - 1] == 'm') if (isdigit (period[0]) && period[period.length () - 1] == 'm')
{ {
std::string numeric = period.substr (0, period.length () - 1); std::string numeric = period.substr (0, period.length () - 1);
@@ -620,6 +674,19 @@ Date getNextRecurrence (Date& current, std::string& period)
return Date (m, d, y); return Date (m, d, y);
} }
else if (period == "annual" ||
period == "yearly")
{
y += 1;
// If the due data just happens to be 2/29 in a leap year, then simply
// incrementing y is going to create an invalid date.
if (m == 2 && d == 29)
d = 28;
return Date (m, d, y);
}
// If the period is an 'easy' one, add it to current, and we're done. // If the period is an 'easy' one, add it to current, and we're done.
int days = convertDuration (period); int days = convertDuration (period);
return current + (days * 86400); return current + (days * 86400);
@@ -672,61 +739,53 @@ void updateRecurrenceMask (
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Using gTdb and gConf, generate a report. void updateShadowFile (TDB& tdb, Config& conf)
void onChangeCallback ()
{ {
try try
{ {
if (gConf && gTdb) // Determine if shadow file is enabled.
std::string shadowFile = expandPath (conf.get ("shadow.file"));
if (shadowFile != "")
{ {
// Determine if shadow file is enabled. std::string oldCurses = conf.get ("curses");
std::string shadowFile = expandPath (gConf->get ("shadow.file")); std::string oldColor = conf.get ("color");
if (shadowFile != "") conf.set ("curses", "off");
conf.set ("color", "off");
// Run report. Use shadow.command, using default.command as a fallback
// with "list" as a default.
std::string command = conf.get ("shadow.command",
conf.get ("default.command", "list"));
std::vector <std::string> args;
split (args, command, ' ');
std::string result = runTaskCommand (args, tdb, conf);
std::ofstream out (shadowFile.c_str ());
if (out.good ())
{ {
std::string oldCurses = gConf->get ("curses"); out << result;
std::string oldColor = gConf->get ("color"); out.close ();
gConf->set ("curses", "off");
gConf->set ("color", "off");
// Run report. Use shadow.command, using default.command as a fallback
// with "list" as a default.
std::string command = gConf->get ("shadow.command",
gConf->get ("default.command", "list"));
std::vector <std::string> args;
split (args, command, ' ');
std::string result = runTaskCommand (args, *gTdb, *gConf);
std::ofstream out (shadowFile.c_str ());
if (out.good ())
{
out << result;
out.close ();
}
else
throw std::string ("Could not write file '") + shadowFile + "'";
gConf->set ("curses", oldCurses);
gConf->set ("color", oldColor);
} }
else else
throw std::string ("No specified shadow file '") + shadowFile + "'."; throw std::string ("Could not write file '") + shadowFile + "'";
// Optionally display a notification that the shadow file was updated. conf.set ("curses", oldCurses);
if (gConf->get (std::string ("shadow.notify"), false)) conf.set ("color", oldColor);
std::cout << "[Shadow file '" << shadowFile << "' updated]" << std::endl;
} }
else
throw std::string ("Internal error (TDB/Config)."); // Optionally display a notification that the shadow file was updated.
if (conf.get (std::string ("shadow.notify"), false))
std::cout << "[Shadow file '" << shadowFile << "' updated]" << std::endl;
} }
catch (std::string& error) catch (std::string& error)
{ {
std::cout << error << std::endl; std::cerr << error << std::endl;
} }
catch (...) catch (...)
{ {
std::cout << "Unknown error." << std::endl; std::cerr << "Unknown error." << std::endl;
} }
} }
@@ -736,13 +795,14 @@ std::string runTaskCommand (
char** argv, char** argv,
TDB& tdb, TDB& tdb,
Config& conf, Config& conf,
bool gc /* = true */) bool gc /* = true */,
bool shadow /* = true */)
{ {
std::vector <std::string> args; std::vector <std::string> args;
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i)
args.push_back (argv[i]); args.push_back (argv[i]);
return runTaskCommand (args, tdb, conf, gc); return runTaskCommand (args, tdb, conf, gc, shadow);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -750,12 +810,15 @@ std::string runTaskCommand (
std::vector <std::string>& args, std::vector <std::string>& args,
TDB& tdb, TDB& tdb,
Config& conf, Config& conf,
bool gc /* = false */) bool gc /* = false */,
bool shadow /* = false */)
{ {
// If argc == 1 and the default.command configuration variable is set, // If argc == 1 and the default.command configuration variable is set,
// then use that, otherwise stick with argc/argv. // then use that, otherwise stick with argc/argv.
std::string defaultCommand = conf.get ("default.command"); std::string defaultCommand = conf.get ("default.command");
if (args.size () == 0 && defaultCommand != "") if ((args.size () == 0 ||
(args.size () == 1 && args[0].substr (0, 3) == "rc:")) &&
defaultCommand != "")
{ {
// Stuff the command line. // Stuff the command line.
args.clear (); args.clear ();
@@ -769,39 +832,51 @@ std::string runTaskCommand (
T task; T task;
parse (args, command, task, conf); parse (args, command, task, conf);
std::string out = ""; bool gcMod = false; // Change occurred by way of gc.
bool cmdMod = false; // Change occurred by way of command type.
std::string out;
if (command == "" && task.getId ()) { handleModify (tdb, task, conf ); } // Read-only commands with no side effects.
else if (command == "add") { handleAdd (tdb, task, conf ); } if (command == "export") { out = handleExport (tdb, task, conf); }
else if (command == "done") { handleDone (tdb, task, conf ); } else if (command == "projects") { out = handleProjects (tdb, task, conf); }
else if (command == "export") { handleExport (tdb, task, conf ); } else if (command == "tags") { out = handleTags (tdb, task, conf); }
else if (command == "projects") { out = handleProjects (tdb, task, conf ); } else if (command == "info") { out = handleInfo (tdb, task, conf); }
else if (command == "tags") { out = handleTags (tdb, task, conf ); } else if (command == "stats") { out = handleReportStats (tdb, task, conf); }
else if (command == "info") { out = handleInfo (tdb, task, conf ); } else if (command == "history") { out = handleReportHistory (tdb, task, conf); }
else if (command == "undelete") { out = handleUndelete (tdb, task, conf ); } else if (command == "ghistory") { out = handleReportGHistory (tdb, task, conf); }
else if (command == "delete") { out = handleDelete (tdb, task, conf ); } else if (command == "calendar") { out = handleReportCalendar (tdb, task, conf); }
else if (command == "start") { out = handleStart (tdb, task, conf ); } else if (command == "summary") { out = handleReportSummary (tdb, task, conf); }
else if (command == "stop") { out = handleStop (tdb, task, conf ); } else if (command == "colors") { out = handleColor ( conf); }
else if (command == "undo") { out = handleUndo (tdb, task, conf ); } else if (command == "version") { out = handleVersion ( conf); }
else if (command == "stats") { out = handleReportStats (tdb, task, conf ); } else if (command == "help") { out = longUsage ( conf); }
else if (command == "list") { if (gc) tdb.gc (); out = handleList (tdb, task, conf ); } // TODO replace with Custom
else if (command == "long") { if (gc) tdb.gc (); out = handleLongList (tdb, task, conf ); } // TODO replace with Custom // Commands that cause updates.
else if (command == "ls") { if (gc) tdb.gc (); out = handleSmallList (tdb, task, conf ); } // TODO replace with Custom else if (command == "" && task.getId ()) { cmdMod = true; out = handleModify (tdb, task, conf); }
else if (command == "completed") { if (gc) tdb.gc (); out = handleCompleted (tdb, task, conf ); } // TODO replace with Custom else if (command == "add") { cmdMod = true; out = handleAdd (tdb, task, conf); }
else if (command == "summary") { if (gc) tdb.gc (); out = handleReportSummary (tdb, task, conf ); } else if (command == "append") { cmdMod = true; out = handleAppend (tdb, task, conf); }
else if (command == "next") { if (gc) tdb.gc (); out = handleReportNext (tdb, task, conf ); } // TODO replace with Custom else if (command == "annotate") { cmdMod = true; out = handleAnnotate (tdb, task, conf); }
else if (command == "history") { if (gc) tdb.gc (); out = handleReportHistory (tdb, task, conf ); } else if (command == "done") { cmdMod = true; out = handleDone (tdb, task, conf); }
else if (command == "ghistory") { if (gc) tdb.gc (); out = handleReportGHistory (tdb, task, conf ); } else if (command == "undelete") { cmdMod = true; out = handleUndelete (tdb, task, conf); }
else if (command == "calendar") { if (gc) tdb.gc (); out = handleReportCalendar (tdb, task, conf ); } else if (command == "delete") { cmdMod = true; out = handleDelete (tdb, task, conf); }
else if (command == "active") { if (gc) tdb.gc (); out = handleReportActive (tdb, task, conf ); } // TODO replace with Custom else if (command == "start") { cmdMod = true; out = handleStart (tdb, task, conf); }
else if (command == "overdue") { if (gc) tdb.gc (); out = handleReportOverdue (tdb, task, conf ); } // TODO replace with Custom else if (command == "stop") { cmdMod = true; out = handleStop (tdb, task, conf); }
else if (command == "oldest") { if (gc) tdb.gc (); out = handleReportOldest (tdb, task, conf ); } // TODO replace with Custom else if (command == "undo") { cmdMod = true; out = handleUndo (tdb, task, conf); }
else if (command == "newest") { if (gc) tdb.gc (); out = handleReportNewest (tdb, task, conf ); } // TODO replace with Custom else if (command == "import") { cmdMod = true; out = handleImport (tdb, task, conf); }
else if (command == "colors") { out = handleColor ( conf ); }
else if (command == "version") { out = handleVersion ( conf ); } // Command that display IDs and therefore need TDB::gc first.
else if (command == "help") { longUsage ( conf ); } else if (command == "completed") { if (gc) gcMod = tdb.gc (); out = handleCompleted (tdb, task, conf); }
else if (isCustomReport (command)) { if (gc) tdb.gc (); out = handleCustomReport (tdb, task, conf, command); } // New Custom reports else if (command == "next") { if (gc) gcMod = tdb.gc (); out = handleReportNext (tdb, task, conf); }
else { shortUsage ( conf ); } else if (command == "active") { if (gc) gcMod = tdb.gc (); out = handleReportActive (tdb, task, conf); }
else if (command == "overdue") { if (gc) gcMod = tdb.gc (); out = handleReportOverdue (tdb, task, conf); }
else if (isCustomReport (command)) { if (gc) gcMod = tdb.gc (); out = handleCustomReport (tdb, task, conf, command); }
// If the command is not recognized, display usage.
else { out = shortUsage (conf); }
// Only update the shadow file if such an update was not suppressed (shadow),
// and if an actual change occurred (gcMod || cmdMod).
if (shadow && (gcMod || cmdMod))
updateShadowFile (tdb, conf);
return out; return out;
} }

View File

@@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager. // task - a command line task list manager.
// //
// Copyright 2006 - 2008, Paul Beckingham. // Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved. // All rights reserved.
// //
// This program is free software; you can redistribute it and/or modify it under // This program is free software; you can redistribute it and/or modify it under
@@ -59,6 +59,7 @@ bool validPriority (const std::string&);
bool validDate (std::string&, Config&); bool validDate (std::string&, Config&);
void loadCustomReports (Config&); void loadCustomReports (Config&);
bool isCustomReport (const std::string&); bool isCustomReport (const std::string&);
void allCustomReports (std::vector <std::string>&);
// task.cpp // task.cpp
void gatherNextTasks (const TDB&, T&, Config&, std::vector <T>&, std::vector <int>&); void gatherNextTasks (const TDB&, T&, Config&, std::vector <T>&, std::vector <int>&);
@@ -69,14 +70,15 @@ bool generateDueDates (T&, std::vector <Date>&);
Date getNextRecurrence (Date&, std::string&); Date getNextRecurrence (Date&, std::string&);
void updateRecurrenceMask (TDB&, std::vector <T>&, T&); void updateRecurrenceMask (TDB&, std::vector <T>&, T&);
void onChangeCallback (); void onChangeCallback ();
std::string runTaskCommand (int, char**, TDB&, Config&, bool gc = true); std::string runTaskCommand (int, char**, TDB&, Config&, bool gc = true, bool shadow = true);
std::string runTaskCommand (std::vector <std::string>&, TDB&, Config&, bool gc = false); std::string runTaskCommand (std::vector <std::string>&, TDB&, Config&, bool gc = false, bool shadow = false);
// command.cpp // command.cpp
void handleAdd (TDB&, T&, Config&); std::string handleAdd (TDB&, T&, Config&);
void handleExport (TDB&, T&, Config&); std::string handleAppend (TDB&, T&, Config&);
void handleDone (TDB&, T&, Config&); std::string handleExport (TDB&, T&, Config&);
void handleModify (TDB&, T&, Config&); std::string handleDone (TDB&, T&, Config&);
std::string handleModify (TDB&, T&, Config&);
std::string handleProjects (TDB&, T&, Config&); std::string handleProjects (TDB&, T&, Config&);
std::string handleTags (TDB&, T&, Config&); std::string handleTags (TDB&, T&, Config&);
std::string handleUndelete (TDB&, T&, Config&); std::string handleUndelete (TDB&, T&, Config&);
@@ -86,13 +88,12 @@ std::string handleStart (TDB&, T&, Config&);
std::string handleStop (TDB&, T&, Config&); std::string handleStop (TDB&, T&, Config&);
std::string handleUndo (TDB&, T&, Config&); std::string handleUndo (TDB&, T&, Config&);
std::string handleColor (Config&); std::string handleColor (Config&);
std::string handleAnnotate (TDB&, T&, Config&);
T findT (int, const std::vector <T>&);
// report.cpp // report.cpp
void filter (std::vector<T>&, T&); void filter (std::vector<T>&, T&);
std::string handleList (TDB&, T&, Config&);
std::string handleInfo (TDB&, T&, Config&); std::string handleInfo (TDB&, T&, Config&);
std::string handleLongList (TDB&, T&, Config&);
std::string handleSmallList (TDB&, T&, Config&);
std::string handleCompleted (TDB&, T&, Config&); std::string handleCompleted (TDB&, T&, Config&);
std::string handleReportSummary (TDB&, T&, Config&); std::string handleReportSummary (TDB&, T&, Config&);
std::string handleReportNext (TDB&, T&, Config&); std::string handleReportNext (TDB&, T&, Config&);
@@ -102,18 +103,17 @@ std::string handleReportCalendar (TDB&, T&, Config&);
std::string handleReportActive (TDB&, T&, Config&); std::string handleReportActive (TDB&, T&, Config&);
std::string handleReportOverdue (TDB&, T&, Config&); std::string handleReportOverdue (TDB&, T&, Config&);
std::string handleReportStats (TDB&, T&, Config&); std::string handleReportStats (TDB&, T&, Config&);
std::string handleReportOldest (TDB&, T&, Config&);
std::string handleReportNewest (TDB&, T&, Config&);
std::string handleCustomReport (TDB&, T&, Config&, const std::string&); std::string handleCustomReport (TDB&, T&, Config&, const std::string&);
void validReportColumns (const std::vector <std::string>&);
void validSortColumns (const std::vector <std::string>&, const std::vector <std::string>&);
// util.cpp // text.cpp
bool confirm (const std::string&);
void wrapText (std::vector <std::string>&, const std::string&, const int); void wrapText (std::vector <std::string>&, const std::string&, const int);
std::string trimLeft (const std::string& in, const std::string& t = " "); std::string trimLeft (const std::string& in, const std::string& t = " ");
std::string trimRight (const std::string& in, const std::string& t = " "); std::string trimRight (const std::string& in, const std::string& t = " ");
std::string trim (const std::string& in, const std::string& t = " "); std::string trim (const std::string& in, const std::string& t = " ");
void extractParagraphs (const std::string&, std::vector<std::string>&); std::string unquoteText (const std::string&);
void extractLine (std::string&, std::string&, int); void extractLine (std::string&, std::string&, int);
void split (std::vector<std::string>&, const std::string&, const char); void split (std::vector<std::string>&, const std::string&, const char);
void split (std::vector<std::string>&, const std::string&, const std::string&); void split (std::vector<std::string>&, const std::string&, const std::string&);
@@ -121,17 +121,34 @@ void join (std::string&, const std::string&, const std::vector<std::string>&);
std::string commify (const std::string&); std::string commify (const std::string&);
std::string lowerCase (const std::string&); std::string lowerCase (const std::string&);
std::string upperCase (const std::string&); std::string upperCase (const std::string&);
const char* optionalBlankLine (Config&);
// util.cpp
bool confirm (const std::string&);
void delay (float); void delay (float);
int autoComplete (const std::string&, const std::vector<std::string>&, std::vector<std::string>&);
void formatTimeDeltaDays (std::string&, time_t); void formatTimeDeltaDays (std::string&, time_t);
std::string formatSeconds (time_t); std::string formatSeconds (time_t);
int autoComplete (const std::string&, const std::vector<std::string>&, std::vector<std::string>&);
const std::string uuid (); const std::string uuid ();
const char* optionalBlankLine (Config&); int convertDuration (const std::string&);
int convertDuration (std::string&);
std::string expandPath (const std::string&); std::string expandPath (const std::string&);
#ifdef SOLARIS
#define LOCK_SH 1
#define LOCK_EX 2
#define LOCK_NB 4
#define LOCK_UN 8
int flock (int, int);
#endif
bool slurp (const std::string&, std::vector <std::string>&, bool trimLines = false);
// rules.cpp // rules.cpp
void initializeColorRules (Config&); void initializeColorRules (Config&);
void autoColorize (T&, Text::color&, Text::color&); void autoColorize (T&, Text::color&, Text::color&, Config&);
// import.cpp
std::string handleImport (TDB&, T&, Config&);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@@ -1,7 +1,7 @@
t.t t.t
t.benchmark.t
tdb.t tdb.t
date.t date.t
duration.t duration.t
pending.data text.t
completed.data autocomplete.t

View File

@@ -1,4 +1,4 @@
PROJECT = t.t tdb.t date.t duration.t PROJECT = t.t tdb.t date.t duration.t t.benchmark.t text.t autocomplete.t
CFLAGS = -I. -I.. -Wall -pedantic -ggdb3 -fno-rtti CFLAGS = -I. -I.. -Wall -pedantic -ggdb3 -fno-rtti
LFLAGS = -L/usr/local/lib LFLAGS = -L/usr/local/lib
OBJECTS = ../TDB.o ../T.o ../parse.o ../text.o ../Date.o ../util.o ../Config.o OBJECTS = ../TDB.o ../T.o ../parse.o ../text.o ../Date.o ../util.o ../Config.o
@@ -29,3 +29,12 @@ date.t: date.t.o $(OBJECTS) test.o
duration.t: duration.t.o $(OBJECTS) test.o duration.t: duration.t.o $(OBJECTS) test.o
g++ duration.t.o $(OBJECTS) test.o $(LFLAGS) -o duration.t g++ duration.t.o $(OBJECTS) test.o $(LFLAGS) -o duration.t
t.benchmark.t: t.benchmark.t.o $(OBJECTS) test.o
g++ t.benchmark.t.o $(OBJECTS) test.o $(LFLAGS) -o t.benchmark.t
text.t: text.t.o $(OBJECTS) test.o
g++ text.t.o $(OBJECTS) test.o $(LFLAGS) -o text.t
autocomplete.t: autocomplete.t.o $(OBJECTS) test.o
g++ autocomplete.t.o $(OBJECTS) test.o $(LFLAGS) -o autocomplete.t

99
src/tests/abbreviation.t Executable file
View File

@@ -0,0 +1,99 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 22;
# Create the rc file.
if (open my $fh, '>', 'abbrev.rc')
{
print $fh "data.location=.\n";
close $fh;
ok (-r 'abbrev.rc', 'Created abbrev.rc');
}
# Test the priority attribute abbrevations.
qx{../task rc:abbrev.rc add priority:H with};
qx{../task rc:abbrev.rc add without};
my $output = qx{../task rc:abbrev.rc list priority:H};
like ($output, qr/\bwith\b/, 'priority:H with');
unlike ($output, qr/\bwithout\b/, 'priority:H without');
$output = qx{../task rc:abbrev.rc list priorit:H};
like ($output, qr/\bwith\b/, 'priorit:H with');
unlike ($output, qr/\bwithout\b/, 'priorit:H without');
$output = qx{../task rc:abbrev.rc list priori:H};
like ($output, qr/\bwith\b/, 'priori:H with');
unlike ($output, qr/\bwithout\b/, 'priori:H without');
$output = qx{../task rc:abbrev.rc list prior:H};
like ($output, qr/\bwith\b/, 'prior:H with');
unlike ($output, qr/\bwithout\b/, 'prior:H without');
$output = qx{../task rc:abbrev.rc list prio:H};
like ($output, qr/\bwith\b/, 'prio:H with');
unlike ($output, qr/\bwithout\b/, 'prio:H without');
$output = qx{../task rc:abbrev.rc list pri:H};
like ($output, qr/\bwith\b/, 'pri:H with');
unlike ($output, qr/\bwithout\b/, 'pri:H without');
# Test the version command abbreviations.
$output = qx{../task rc:abbrev.rc version};
like ($output, qr/ABSOLUTELY NO WARRANTY/, 'version');
$output = qx{../task rc:abbrev.rc versio};
like ($output, qr/ABSOLUTELY NO WARRANTY/, 'versio');
$output = qx{../task rc:abbrev.rc versi};
like ($output, qr/ABSOLUTELY NO WARRANTY/, 'versi');
$output = qx{../task rc:abbrev.rc vers};
like ($output, qr/ABSOLUTELY NO WARRANTY/, 'vers');
$output = qx{../task rc:abbrev.rc ver};
like ($output, qr/ABSOLUTELY NO WARRANTY/, 'ver');
$output = qx{../task rc:abbrev.rc ve};
like ($output, qr/ABSOLUTELY NO WARRANTY/, 've');
$output = qx{../task rc:abbrev.rc v};
like ($output, qr/ABSOLUTELY NO WARRANTY/, 'v');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'abbrev.rc';
ok (!-r 'abbrev.rc', 'Removed abbrev.rc');
exit 0;

72
src/tests/add.t Executable file
View File

@@ -0,0 +1,72 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 14;
# Create the rc file.
if (open my $fh, '>', 'add.rc')
{
print $fh "data.location=.\n";
close $fh;
ok (-r 'add.rc', 'Created add.rc');
}
# Test the add command.
my $output = qx{../task rc:add.rc add This is a test; ../task rc:add.rc info 1};
like ($output, qr/ID\s+1\n/, 'add ID');
like ($output, qr/Description\s+This is a test\n/, 'add ID');
like ($output, qr/Status\s+Pending\n/, 'add Pending');
like ($output, qr/UUID\s+[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\n/, 'add UUID');
# Test the /// modifier.
$output = qx{../task rc:add.rc 1 /test/TEST/; ../task rc:add.rc 1 "/is //"; ../task rc:add.rc info 1};
like ($output, qr/ID\s+1\n/, 'add ID');
like ($output, qr/Status\s+Pending\n/, 'add Pending');
like ($output, qr/Description\s+This a TEST\n/, 'add ID');
# Test delete.
$output = qx{../task rc:add.rc delete 1; ../task rc:add.rc info 1};
like ($output, qr/ID\s+1\n/, 'add ID');
like ($output, qr/Status\s+Deleted\n/, 'add Deleted');
# Test undelete.
$output = qx{../task rc:add.rc undelete 1; ../task rc:add.rc info 1};
like ($output, qr/ID\s+1\n/, 'add ID');
like ($output, qr/Status\s+Pending\n/, 'add Pending');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'add.rc';
ok (!-r 'add.rc', 'Removed add.rc');
exit 0;

74
src/tests/annotate.t Executable file
View File

@@ -0,0 +1,74 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 8;
# Create the rc file.
if (open my $fh, '>', 'annotate.rc')
{
print $fh "data.location=.\n",
"report.r.description=r\n",
"report.r.columns=id,description\n",
"report.r.sort=id+\n";
close $fh;
ok (-r 'annotate.rc', 'Created annotate.rc');
}
# Add two tasks, annotate one twice.
qx{../task rc:annotate.rc add one};
qx{../task rc:annotate.rc add two};
qx{../task rc:annotate.rc annotate 1 foo};
sleep 2;
qx{../task rc:annotate.rc annotate 1 bar};
my $output = qx{../task rc:annotate.rc r};
# ID Description
# -- -------------------------------
# 1 one
# 3/24/2009 foo
# 3/24/2009 bar
# 2 two
#
# 2 tasks
like ($output, qr/1 one/, 'task 1');
like ($output, qr/2 two/, 'task 2');
like ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4} foo/ms, 'first annotation');
like ($output, qr/foo.+\d{1,2}\/\d{1,2}\/\d{4} bar/ms, 'second annotation');
like ($output, qr/2 tasks/, 'count');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'annotate.rc';
ok (!-r 'annotate.rc', 'Removed annotate.rc');
exit 0;

55
src/tests/append.t Executable file
View File

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

View File

@@ -0,0 +1,63 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <test.h>
#include <../task.h>
////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv)
{
UnitTest t (8);
std::vector <std::string> options;
options.push_back ("abc");
options.push_back ("abcd");
options.push_back ("abcde");
options.push_back ("bcdef");
options.push_back ("cdefg");
std::vector <std::string> matches;
int result = autoComplete ("", options, matches);
t.is (result, 0, "no match on empty string");
result = autoComplete ("x", options, matches);
t.is (result, 0, "no match on wrong string");
result = autoComplete ("abcd", options, matches);
t.is (result, 1, "exact match on 'abcd'");
t.is (matches[0], "abcd", "exact match on 'abcd'");
result = autoComplete ("ab", options, matches);
t.is (result, 3, "partial match on 'ab'");
t.is (matches[0], "abc", "partial match on 'abc'");
t.is (matches[1], "abcd", "partial match on 'abcd'");
t.is (matches[2], "abcde", "partial match on 'abcde'");
return 0;
}
////////////////////////////////////////////////////////////////////////////////

57
src/tests/basic.t Executable file
View File

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

103
src/tests/benchmark.t Executable file
View File

@@ -0,0 +1,103 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 4;
# Create the rc file.
if (open my $fh, '>', 'bench.rc')
{
print $fh "data.location=.\n",
"_forcecolor=1\n";
close $fh;
ok (-r 'bench.rc', 'Created bench.rc');
}
# Do lots of things. Time it all.
my @tags = qw(t_one t_two t_three t_four t_five t_six t_seven t_eight);
my @projects = qw(p_one p_two p_three p_foud p_five p_six p_seven p_eight);
my @priorities = qw(H M L);
my $description = 'This is a medium-sized description with no special characters';
# Start the clock.
my $start = time ();
my $cursor = $start;
diag ("start=$start");
# Make a mess.
for my $i (1 .. 1000)
{
my $project = $projects[rand % 8];
my $priority = $priorities[rand % 3];
my $tag = $tags[rand % 8];
qx{../task rc:bench.rc add project:$project priority:$priority +$tag $i $description};
}
diag ("1000 tasks added in " . (time () - $cursor) . " seconds");
$cursor = time ();
qx{../task rc:bench.rc /with/WITH/} for 1 .. 200;
qx{../task rc:bench.rc done $_} for 201 .. 400;
qx{../task rc:bench.rc start $_} for 401 .. 600;
diag ("600 tasks altered in " . (time () - $cursor) . " seconds");
$cursor = time ();
# Report it all. Note that all Timer information is displayed.
for (1 .. 100)
{
diag (grep {/^Timer /} qx{../task rc:bench.rc ls});
diag (grep {/^Timer /} qx{../task rc:bench.rc list});
diag (grep {/^Timer /} qx{../task rc:bench.rc list priority:H});
diag (grep {/^Timer /} qx{../task rc:bench.rc list +tag});
diag (grep {/^Timer /} qx{../task rc:bench.rc list project_A});
diag (grep {/^Timer /} qx{../task rc:bench.rc long});
diag (grep {/^Timer /} qx{../task rc:bench.rc completed});
diag (grep {/^Timer /} qx{../task rc:bench.rc history});
diag (grep {/^Timer /} qx{../task rc:bench.rc ghistory});
}
# Stop the clock.
my $stop = time ();
diag ("stop=$stop");
diag ("total=" . ($stop - $start));
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'completed.data';
ok (!-r 'completed.data', 'Removed completed.data');
unlink 'bench.rc';
ok (!-r 'bench.rc', 'Removed bench.rc');
exit 0;

40
src/tests/benchmark.txt Normal file
View File

@@ -0,0 +1,40 @@
3/8/2009
Before:
Table::render
26.1792
16.67
18.9697
28.6328
1.86553
0.00044
0.000319
---------
92.317989
After Table::optimize removed:
Table::render
0.146177
0.145928
0.184444
0.014784
0.000512
0.000267
---------
0.492112
Speedup:
92.317989 / 0.492112 = 187.6
3/8/2009
New benchmark:
1..4
ok 1 - Created bench.rc
# start=1236565862
# 1000 tasks added in 3 seconds
# 600 tasks altered in 28 seconds
# stop=1236566048
# total=186
ok 2 - Removed pending.data
ok 3 - Removed completed.data
ok 4 - Removed bench.rc

79
src/tests/bug.annual.t Executable file
View File

@@ -0,0 +1,79 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 14;
# Create the rc file.
if (open my $fh, '>', 'annual.rc')
{
print $fh "data.location=.\n";
close $fh;
ok (-r 'annual.rc', 'Created annual.rc');
}
# If a task is added with a due date ten years ago, with an annual recurrence,
# then the synthetic tasks in between then and now have a due date that creeps.
#
# ID Project Pri Due Active Age Description
# -- ------- --- ---------- ------ --- -----------
# 2 1/1/2000 - foo
# 3 12/31/2000 - foo
# 4 12/31/2001 - foo
# 5 12/31/2002 - foo
# 6 12/31/2003 - foo
# 7 12/30/2004 - foo
# 8 12/30/2005 - foo
# 9 12/30/2006 - foo
# 10 12/30/2007 - foo
# 11 12/29/2008 - foo
# 12 12/29/2009 - foo
qx{../task rc:annual.rc add foo due:1/1/2000 recur:annual until:1/1/2009};
my $output = qx{../task rc:annual.rc list};
like ($output, qr/2\s+1\/1\/2000\s+- foo/, 'synthetic 1 no creep');
like ($output, qr/3\s+1\/1\/2001\s+- foo/, 'synthetic 2 no creep');
like ($output, qr/4\s+1\/1\/2002\s+- foo/, 'synthetic 3 no creep');
like ($output, qr/5\s+1\/1\/2003\s+- foo/, 'synthetic 4 no creep');
like ($output, qr/6\s+1\/1\/2004\s+- foo/, 'synthetic 5 no creep');
like ($output, qr/7\s+1\/1\/2005\s+- foo/, 'synthetic 6 no creep');
like ($output, qr/8\s+1\/1\/2006\s+- foo/, 'synthetic 7 no creep');
like ($output, qr/9\s+1\/1\/2007\s+- foo/, 'synthetic 8 no creep');
like ($output, qr/10\s+1\/1\/2008\s+- foo/, 'synthetic 9 no creep');
like ($output, qr/11\s+1\/1\/2009\s+- foo/, 'synthetic 10 no creep');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'annual.rc';
ok (!-r 'annual.rc', 'Removed annual.rc');
exit 0;

77
src/tests/bug.concat.t Executable file
View File

@@ -0,0 +1,77 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 6;
# Create the rc file.
if (open my $fh, '>', 'bug_concat.rc')
{
print $fh "data.location=.\n";
close $fh;
ok (-r 'bug_concat.rc', 'Created bug_concat.rc');
}
# When a task is modified like this:
#
# % task 1 This is a new description
#
# The arguments are concatenated thus:
#
# Thisisanewdescription
qx{../task rc:bug_concat.rc add This is the original text};
my $output = qx{../task rc:bug_concat.rc info 1};
like ($output, qr/Description\s+This is the original text\n/, 'original correct');
qx{../task rc:bug_concat.rc 1 This is the modified text};
$output = qx{../task rc:bug_concat.rc info 1};
like ($output, qr/Description\s+This is the modified text\n/, 'modified correct');
# When a task is added like this:
#
# % task add aaa bbb:ccc ddd
#
# The description is concatenated thus:
#
# aaabbb:ccc ddd
qx{../task rc:bug_concat.rc add aaa bbb:ccc ddd};
$output = qx{../task rc:bug_concat.rc info 2};
like ($output, qr/Description\s+aaa bbb:ccc ddd\n/, 'properly concatenated');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'bug_concat.rc';
ok (!-r 'bug_concat.rc', 'Removed bug_concat.rc');
exit 0;

83
src/tests/bug.hang.t Executable file
View File

@@ -0,0 +1,83 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 5;
# Create the rc file.
if (open my $fh, '>', 'hang.rc')
{
print $fh "data.location=.\n",
"shadow.file=shadow.txt\n",
"shadow.command=list\n";
close $fh;
ok (-r 'hang.rc', 'Created hang.rc');
}
=pod
I found a bug in the current version of task. Using recur and a shadow file will
lead to an infinite loop. To reproduce it, define a shadow file in the .taskrc,
set a command for it that rebuilds the database, e.g. "list", and then add a
task with a recurrence set, e.g. "task add due:today recur:1d infinite loop".
Task will then loop forever and add the same recurring task until it runs out of
memory. So I checked the source and I believe I found the cause.
handleRecurrence() in task.cpp will modify the mask, but writes it only after it
has added all new tasks. Adding the task will, however, invoke onChangeCallback,
which starts the same process all over again.
=cut
eval
{
$SIG{'ALRM'} = sub {die "alarm\n"};
alarm 10;
my $output = qx{../task rc:hang.rc list;
../task rc:hang.rc add due:today recur:1d infinite loop;
../task rc:hang.rc info 1};
alarm 0;
like ($output, qr/^Description\s+infinite loop\n/m, 'no hang');
};
if ($@ eq "alarm\n")
{
fail ('task hang on add or recurring task, with shadow file, for 10s');
}
# Cleanup.
unlink 'shadow.txt';
ok (!-r 'shadow.txt', 'Removed shadow.txt');
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'hang.rc';
ok (!-r 'hang.rc', 'Removed hang.rc');
exit 0;

164
src/tests/bug.period.t Executable file
View File

@@ -0,0 +1,164 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 41;
# Create the rc file.
if (open my $fh, '>', 'period.rc')
{
print $fh "data.location=.\n";
close $fh;
ok (-r 'period.rc', 'Created period.rc');
}
=pod
http://github.com/pbeckingham/task/blob/857f813a24f7ce15fea9f2c28aadad84cb5c8847/src/task.cpp
619 // If the period is an 'easy' one, add it to current, and we're done.
620 int days = convertDuration (period);
Date getNextRecurrence (Date& current, std::string& period)
starting at line 509 special cases several possibilities for period, '\d\s?m'
'monthly', 'quarterly', 'semiannual', 'bimonthly', 'biannual', 'biyearly'.
Everything else falls through with period being passed to convertDuration.
convertDuration doesn't know about 'daily' though so it seems to be returning 0.
Confirmed:
getNextRecurrence convertDuration
----------------- ---------------
daily
day
weekly
sennight
biweekly
fortnight
monthly monthly
quarterly quarterly
semiannual semiannual
bimonthly bimonthly
biannual biannual
biyearly biyearly
annual
yearly
*m *m
*q *q
*d
*w
*y
=cut
my $output = qx{../task rc:period.rc add daily due:tomorrow recur:daily};
like ($output, qr/^$/, 'recur:daily');
$output = qx{../task rc:period.rc add day due:tomorrow recur:day};
like ($output, qr/^$/, 'recur:day');
$output = qx{../task rc:period.rc add weekly due:tomorrow recur:weekly};
like ($output, qr/^$/, 'recur:weekly');
$output = qx{../task rc:period.rc add sennight due:tomorrow recur:sennight};
like ($output, qr/^$/, 'recur:sennight');
$output = qx{../task rc:period.rc add biweekly due:tomorrow recur:biweekly};
like ($output, qr/^$/, 'recur:biweekly');
$output = qx{../task rc:period.rc add fortnight due:tomorrow recur:fortnight};
like ($output, qr/^$/, 'recur:fortnight');
$output = qx{../task rc:period.rc add monthly due:tomorrow recur:monthly};
like ($output, qr/^$/, 'recur:monthly');
$output = qx{../task rc:period.rc add quarterly due:tomorrow recur:quarterly};
like ($output, qr/^$/, 'recur:quarterly');
$output = qx{../task rc:period.rc add semiannual due:tomorrow recur:semiannual};
like ($output, qr/^$/, 'recur:semiannual');
$output = qx{../task rc:period.rc add bimonthly due:tomorrow recur:bimonthly};
like ($output, qr/^$/, 'recur:bimonthly');
$output = qx{../task rc:period.rc add biannual due:tomorrow recur:biannual};
like ($output, qr/^$/, 'recur:biannual');
$output = qx{../task rc:period.rc add biyearly due:tomorrow recur:biyearly};
like ($output, qr/^$/, 'recur:biyearly');
$output = qx{../task rc:period.rc add annual due:tomorrow recur:annual};
like ($output, qr/^$/, 'recur:annual');
$output = qx{../task rc:period.rc add yearly due:tomorrow recur:yearly};
like ($output, qr/^$/, 'recur:yearly');
$output = qx{../task rc:period.rc add 2d due:tomorrow recur:2d};
like ($output, qr/^$/, 'recur:2m');
$output = qx{../task rc:period.rc add 2w due:tomorrow recur:2w};
like ($output, qr/^$/, 'recur:2q');
$output = qx{../task rc:period.rc add 2m due:tomorrow recur:2m};
like ($output, qr/^$/, 'recur:2d');
$output = qx{../task rc:period.rc add 2q due:tomorrow recur:2q};
like ($output, qr/^$/, 'recur:2w');
$output = qx{../task rc:period.rc add 2y due:tomorrow recur:2y};
like ($output, qr/^$/, 'recur:2y');
# Verify that the recurring task instances get created. One of each.
$output = qx{../task rc:period.rc list};
like ($output, qr/\bdaily\b/, 'verify daily');
like ($output, qr/\bday\b/, 'verify day');
like ($output, qr/\bweekly\b/, 'verify weekly');
like ($output, qr/\bsennight\b/, 'verify sennight');
like ($output, qr/\bbiweekly\b/, 'verify biweekly');
like ($output, qr/\bfortnight\b/, 'verify fortnight');
like ($output, qr/\bmonthly\b/, 'verify monthly');
like ($output, qr/\bquarterly\b/, 'verify quarterly');
like ($output, qr/\bsemiannual\b/, 'verify semiannual');
like ($output, qr/\bbimonthly\b/, 'verify bimonthly');
like ($output, qr/\bbiannual\b/, 'verify biannual');
like ($output, qr/\bbiyearly\b/, 'verify biyearly');
like ($output, qr/\bannual\b/, 'verify annual');
like ($output, qr/\byearly\b/, 'verify yearly');
like ($output, qr/\b2d\b/, 'verify 2d');
like ($output, qr/\b2w\b/, 'verify 2w');
like ($output, qr/\b2m\b/, 'verify 2m');
like ($output, qr/\b2q\b/, 'verify 2q');
like ($output, qr/\b2y\b/, 'verify 2y');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'period.rc';
ok (!-r 'period.rc', 'Removed period.rc');
exit 0;

61
src/tests/bug.sort.t Executable file
View File

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

67
src/tests/bug.summary.t Executable file
View File

@@ -0,0 +1,67 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 6;
# Create the rc file.
if (open my $fh, '>', 'summary.rc')
{
print $fh "data.location=.\n",
"confirmation=no\n";
close $fh;
ok (-r 'summary.rc', 'Created summary.rc');
}
# Add three tasks. Do 1, delete 1, leave 1 pending. Summary should depict a
# 50% completion.
qx{../task rc:summary.rc add project:A one};
qx{../task rc:summary.rc add project:A two};
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');
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');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'completed.data';
ok (!-r 'completed.data', 'Removed completed.data');
unlink 'summary.rc';
ok (!-r 'summary.rc', 'Removed summary.rc');
exit 0;

60
src/tests/color.active.t Executable file
View File

@@ -0,0 +1,60 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 5;
# Create the rc file.
if (open my $fh, '>', 'color.rc')
{
print $fh "data.location=.\n",
"color.active=red\n",
"_forcecolor=1\n";
close $fh;
ok (-r 'color.rc', 'Created color.rc');
}
# Test the add command.
qx{../task rc:color.rc add nothing};
qx{../task rc:color.rc add red};
qx{../task rc:color.rc start 2};
my $output = qx{../task rc:color.rc list};
like ($output, qr/ (?!<\033\[\d\dm) .* nothing .* (?!>\033\[0m) /x, 'none');
like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.active');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'color.rc';
ok (!-r 'color.rc', 'Removed color.rc');
exit 0;

58
src/tests/color.disable.t Executable file
View File

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

59
src/tests/color.due.t Executable file
View File

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

62
src/tests/color.keyword.t Executable file
View File

@@ -0,0 +1,62 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 6;
# Create the rc file.
if (open my $fh, '>', 'color.rc')
{
print $fh "data.location=.\n",
"color.keyword.red=red\n",
"color.keyword.green=green\n",
"_forcecolor=1\n";
close $fh;
ok (-r 'color.rc', 'Created color.rc');
}
# Test the add command.
qx{../task rc:color.rc add nothing};
qx{../task rc:color.rc add red};
qx{../task rc:color.rc add green};
my $output = qx{../task rc:color.rc list};
like ($output, qr/ (?!<\033\[\d\dm) .* nothing .* (?!>\033\[0m) /x, 'none');
like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.keyword.red');
like ($output, qr/ \033\[32m .* green .* \033\[0m /x, 'color.keyword.green');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'color.rc';
ok (!-r 'color.rc', 'Removed color.rc');
exit 0;

59
src/tests/color.overdue.t Executable file
View File

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

66
src/tests/color.pri.t Executable file
View File

@@ -0,0 +1,66 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 7;
# Create the rc file.
if (open my $fh, '>', 'color.rc')
{
print $fh "data.location=.\n",
"color.pri.H=red\n",
"color.pri.M=green\n",
"color.pri.L=blue\n",
"color.pri.none=yellow\n",
"_forcecolor=1\n";
close $fh;
ok (-r 'color.rc', 'Created color.rc');
}
# Test the add command.
qx{../task rc:color.rc add priority:H red};
qx{../task rc:color.rc add priority:M green};
qx{../task rc:color.rc add priority:L blue};
qx{../task rc:color.rc add yellow};
my $output = qx{../task rc:color.rc list};
like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.pri.H');
like ($output, qr/ \033\[32m .* green .* \033\[0m /x, 'color.pri.M');
like ($output, qr/ \033\[34m .* blue .* \033\[0m /x, 'color.pri.L');
like ($output, qr/ \033\[33m .* yellow .* \033\[0m /x, 'color.pri.none');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'color.rc';
ok (!-r 'color.rc', 'Removed color.rc');
exit 0;

59
src/tests/color.project.t Executable file
View File

@@ -0,0 +1,59 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 5;
# Create the rc file.
if (open my $fh, '>', 'color.rc')
{
print $fh "data.location=.\n",
"color.project.x=red\n",
"_forcecolor=1\n";
close $fh;
ok (-r 'color.rc', 'Created color.rc');
}
# Test the add command.
qx{../task rc:color.rc add nothing};
qx{../task rc:color.rc add project:x red};
my $output = qx{../task rc:color.rc list};
like ($output, qr/ (?!<\033\[\d\dm) .* nothing .* (?!>\033\[0m) /x, 'none');
like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.project.red');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'color.rc';
ok (!-r 'color.rc', 'Removed color.rc');
exit 0;

59
src/tests/color.recurring.t Executable file
View File

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

62
src/tests/color.tag.t Executable file
View File

@@ -0,0 +1,62 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 6;
# Create the rc file.
if (open my $fh, '>', 'color.rc')
{
print $fh "data.location=.\n",
"color.tag.red=red\n",
"color.tag.green=green\n",
"_forcecolor=1\n";
close $fh;
ok (-r 'color.rc', 'Created color.rc');
}
# Test the add command.
qx{../task rc:color.rc add nothing};
qx{../task rc:color.rc add +red red};
qx{../task rc:color.rc add +green green};
my $output = qx{../task rc:color.rc list};
like ($output, qr/ (?!<\033\[\d\dm) .* nothing .* (?!>\033\[0m) /x, 'none');
like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.tag.red');
like ($output, qr/ \033\[32m .* green .* \033\[0m /x, 'color.tag.green');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'color.rc';
ok (!-r 'color.rc', 'Removed color.rc');
exit 0;

59
src/tests/color.tagged.t Executable file
View File

@@ -0,0 +1,59 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 5;
# Create the rc file.
if (open my $fh, '>', 'color.rc')
{
print $fh "data.location=.\n",
"color.tagged=red\n",
"_forcecolor=1\n";
close $fh;
ok (-r 'color.rc', 'Created color.rc');
}
# Test the add command.
qx{../task rc:color.rc add nothing};
qx{../task rc:color.rc add +tag red};
my $output = qx{../task rc:color.rc list};
like ($output, qr/ (?!<\033\[\d\dm) .* nothing .* (?!>\033\[0m) /x, 'none');
like ($output, qr/ \033\[31m .* red .* \033\[0m /x, 'color.tagged');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'color.rc';
ok (!-r 'color.rc', 'Removed color.rc');
exit 0;

64
src/tests/completed.t Executable file
View File

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

57
src/tests/config.obsolete.t Executable file
View File

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

109
src/tests/confirmation.t Executable file
View File

@@ -0,0 +1,109 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 26;
# Create the rc file.
if (open my $fh, '>', 'confirm.rc')
{
print $fh "data.location=.\n",
"confirmation=yes\n";
close $fh;
ok (-r 'confirm.rc', 'Created confirm.rc');
}
# Create the response file.
if (open my $fh, '>', 'response.txt')
{
print $fh "\n\nn\n";
close $fh;
ok (-r 'response.txt', 'Created response.txt');
}
qx{../task rc:confirm.rc add foo} for 1 .. 10;
# Test the various forms of "yes".
my $output = qx{echo "yes" | ../task rc:confirm.rc del 1};
like ($output, qr/Permanently delete task\? \(y\/n\)/, 'confirmation - yes works');
unlike ($output, qr/Task not deleted\./, 'confirmation - yes works');
$output = qx{echo "ye" | ../task rc:confirm.rc del 2};
like ($output, qr/Permanently delete task\? \(y\/n\)/, 'confirmation - ye works');
unlike ($output, qr/Task not deleted\./, 'confirmation - ye works');
$output = qx{echo "y" | ../task rc:confirm.rc del 3};
like ($output, qr/Permanently delete task\? \(y\/n\)/, 'confirmation - y works');
unlike ($output, qr/Task not deleted\./, 'confirmation - y works');
$output = qx{echo "YES" | ../task rc:confirm.rc del 4};
like ($output, qr/Permanently delete task\? \(y\/n\)/, 'confirmation - YES works');
unlike ($output, qr/Task not deleted\./, 'confirmation - YES works');
$output = qx{echo "YE" | ../task rc:confirm.rc del 5};
like ($output, qr/Permanently delete task\? \(y\/n\)/, 'confirmation - YE works');
unlike ($output, qr/Task not deleted\./, 'confirmation - YE works');
$output = qx{echo "Y" | ../task rc:confirm.rc del 6};
like ($output, qr/Permanently delete task\? \(y\/n\)/, 'confirmation - Y works');
unlike ($output, qr/Task not deleted\./, 'confirmation - Y works');
# Test the various forms of "no".
$output = qx{echo "no" | ../task rc:confirm.rc del 7};
like ($output, qr/Permanently delete task\? \(y\/n\)/, 'confirmation - no works');
like ($output, qr/Task not deleted\./, 'confirmation - no works');
$output = qx{echo "n" | ../task rc:confirm.rc del 7};
like ($output, qr/Permanently delete task\? \(y\/n\)/, 'confirmation - n works');
like ($output, qr/Task not deleted\./, 'confirmation - n works');
$output = qx{echo "NO" | ../task rc:confirm.rc del 7};
like ($output, qr/Permanently delete task\? \(y\/n\)/, 'confirmation - NO works');
like ($output, qr/Task not deleted\./, 'confirmation - NO works');
$output = qx{echo "N" | ../task rc:confirm.rc del 7};
like ($output, qr/Permanently delete task\? \(y\/n\)/, 'confirmation - N works');
like ($output, qr/Task not deleted\./, 'confirmation - N works');
# Test newlines.
$output = qx{cat response.txt | ../task rc:confirm.rc del 7};
like ($output, qr/(Permanently delete task\? \(y\/n\)) \1 \1/, 'confirmation - \n re-prompt works');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'response.txt';
ok (!-r 'response.txt', 'Removed response.txt');
unlink 'confirm.rc';
ok (!-r 'confirm.rc', 'Removed confirm.rc');
exit 0;

57
src/tests/custom.columns.t Executable file
View File

@@ -0,0 +1,57 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 4;
# Create the rc file.
if (open my $fh, '>', 'custom.rc')
{
print $fh "data.location=.\n",
"report.foo.description=DESC\n",
"report.foo.columns=id,foo,description\n",
"report.foo.sort=id+\n",
"report.foo.filter=project:A\n";
close $fh;
ok (-r 'custom.rc', 'Created custom.rc');
}
# Generate the usage screen, and locate the custom report on it.
my $output = qx{../task rc:custom.rc foo 2>&1};
like ($output, qr/Unrecognized column name: foo\n/, 'custom report spotted invalid column');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'custom.rc';
ok (!-r 'custom.rc', 'Removed custom.rc');
exit 0;

61
src/tests/custom.recur_ind.t Executable file
View File

@@ -0,0 +1,61 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 6;
# Create the rc file.
if (open my $fh, '>', 'custom.rc')
{
print $fh "data.location=.\n",
"report.foo.description=DESC\n",
"report.foo.columns=id,recurrence_indicator\n",
"report.foo.labels=ID,R\n",
"report.foo.sort=id+\n";
close $fh;
ok (-r 'custom.rc', 'Created custom.rc');
}
# Generate the usage screen, and locate the custom report on it.
qx{../task rc:custom.rc add foo due:tomorrow recur:weekly};
qx{../task rc:custom.rc add bar};
my $output = qx{../task rc:custom.rc foo 2>&1};
like ($output, qr/ID R/, 'Recurrence indicator heading');
like ($output, qr/3\s+R/, 'Recurrence indicator t1');
unlike ($output, qr/2\s+R/, 'No recurrence indicator t2');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'custom.rc';
ok (!-r 'custom.rc', 'Removed custom.rc');
exit 0;

63
src/tests/custom.t Executable file
View File

@@ -0,0 +1,63 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 6;
# Create the rc file.
if (open my $fh, '>', 'custom.rc')
{
print $fh "data.location=.\n",
"report.foo.description=DESC\n",
"report.foo.columns=id,description\n",
"report.foo.sort=id+\n",
"report.foo.filter=project:A\n";
close $fh;
ok (-r 'custom.rc', 'Created custom.rc');
}
# Generate the usage screen, and locate the custom report on it.
my $output = qx{../task rc:custom.rc usage};
like ($output, qr/task foo \[tags\] \[attrs\] desc\.\.\.\s+DESC\n/m, 'report.foo');
qx{../task rc:custom.rc add project:A one};
qx{../task rc:custom.rc add two};
$output = qx{../task rc:custom.rc foo};
like ($output, qr/one/, 'custom filter included');
unlike ($output, qr/two/, 'custom filter excluded');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'custom.rc';
ok (!-r 'custom.rc', 'Removed custom.rc');
exit 0;

61
src/tests/custom.tag_ind.t Executable file
View File

@@ -0,0 +1,61 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 6;
# Create the rc file.
if (open my $fh, '>', 'custom.rc')
{
print $fh "data.location=.\n",
"report.foo.description=DESC\n",
"report.foo.columns=id,tag_indicator\n",
"report.foo.labels=ID,T\n",
"report.foo.sort=id+\n";
close $fh;
ok (-r 'custom.rc', 'Created custom.rc');
}
# Generate the usage screen, and locate the custom report on it.
qx{../task rc:custom.rc add foo +tag};
qx{../task rc:custom.rc add bar};
my $output = qx{../task rc:custom.rc foo 2>&1};
like ($output, qr/ID T/, 'Tag indicator heading');
like ($output, qr/1\s+\+/, 'Tag indicator t1');
unlike ($output, qr/2\s+\+/, 'No tag indicator t2');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'custom.rc';
ok (!-r 'custom.rc', 'Removed custom.rc');
exit 0;

View File

@@ -1,5 +1,27 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Copyright 2005 - 2008, Paul Beckingham. All rights reserved. // task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <iostream> #include <iostream>
@@ -9,7 +31,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv) int main (int argc, char** argv)
{ {
plan (100); UnitTest t (100);
try try
{ {
@@ -17,207 +39,207 @@ int main (int argc, char** argv)
Date yesterday; Date yesterday;
yesterday -= 1; yesterday -= 1;
ok (yesterday <= now, "yesterday <= now"); t.ok (yesterday <= now, "yesterday <= now");
ok (yesterday < now, "yesterday < now"); t.ok (yesterday < now, "yesterday < now");
notok (yesterday == now, "!(yesterday == now)"); t.notok (yesterday == now, "!(yesterday == now)");
ok (yesterday != now, "yesterday != now"); t.ok (yesterday != now, "yesterday != now");
ok (now >= yesterday, "now >= yesterday"); t.ok (now >= yesterday, "now >= yesterday");
ok (now > yesterday, "now > yesterday"); t.ok (now > yesterday, "now > yesterday");
// Loose comparisons. // Loose comparisons.
Date left ("7/4/2008"); Date left ("7/4/2008");
Date comp1 ("7/4/2008"); Date comp1 ("7/4/2008");
ok (left.sameDay (comp1), "7/4/2008 is on the same day as 7/4/2008"); t.ok (left.sameDay (comp1), "7/4/2008 is on the same day as 7/4/2008");
ok (left.sameMonth (comp1), "7/4/2008 is in the same month as 7/4/2008"); t.ok (left.sameMonth (comp1), "7/4/2008 is in the same month as 7/4/2008");
ok (left.sameYear (comp1), "7/4/2008 is in the same year as 7/4/2008"); t.ok (left.sameYear (comp1), "7/4/2008 is in the same year as 7/4/2008");
Date comp2 ("7/5/2008"); Date comp2 ("7/5/2008");
notok (left.sameDay (comp2), "7/4/2008 is not on the same day as 7/5/2008"); t.notok (left.sameDay (comp2), "7/4/2008 is not on the same day as 7/5/2008");
ok (left.sameMonth (comp2), "7/4/2008 is in the same month as 7/5/2008"); t.ok (left.sameMonth (comp2), "7/4/2008 is in the same month as 7/5/2008");
ok (left.sameYear (comp2), "7/4/2008 is in the same year as 7/5/2008"); t.ok (left.sameYear (comp2), "7/4/2008 is in the same year as 7/5/2008");
Date comp3 ("8/4/2008"); Date comp3 ("8/4/2008");
notok (left.sameDay (comp3), "7/4/2008 is not on the same day as 8/4/2008"); t.notok (left.sameDay (comp3), "7/4/2008 is not on the same day as 8/4/2008");
notok (left.sameMonth (comp3), "7/4/2008 is not in the same month as 8/4/2008"); t.notok (left.sameMonth (comp3), "7/4/2008 is not in the same month as 8/4/2008");
ok (left.sameYear (comp3), "7/4/2008 is in the same year as 8/4/2008"); t.ok (left.sameYear (comp3), "7/4/2008 is in the same year as 8/4/2008");
Date comp4 ("7/4/2009"); Date comp4 ("7/4/2009");
notok (left.sameDay (comp4), "7/4/2008 is not on the same day as 7/4/2009"); t.notok (left.sameDay (comp4), "7/4/2008 is not on the same day as 7/4/2009");
notok (left.sameMonth (comp4), "7/4/2008 is not in the same month as 7/4/2009"); t.notok (left.sameMonth (comp4), "7/4/2008 is not in the same month as 7/4/2009");
notok (left.sameYear (comp4), "7/4/2008 is not in the same year as 7/4/2009"); t.notok (left.sameYear (comp4), "7/4/2008 is not in the same year as 7/4/2009");
// Validity. // Validity.
ok (Date::valid (2, 29, 2008), "valid: 2/29/2008"); t.ok (Date::valid (2, 29, 2008), "valid: 2/29/2008");
notok (Date::valid (2, 29, 2007), "invalid: 2/29/2007"); t.notok (Date::valid (2, 29, 2007), "invalid: 2/29/2007");
// Leap year. // Leap year.
ok (Date::leapYear (2008), "2008 is a leap year"); t.ok (Date::leapYear (2008), "2008 is a leap year");
notok (Date::leapYear (2007), "2007 is not a leap year"); t.notok (Date::leapYear (2007), "2007 is not a leap year");
ok (Date::leapYear (2000), "2000 is a leap year"); t.ok (Date::leapYear (2000), "2000 is a leap year");
ok (Date::leapYear (1900), "1900 is a leap year"); t.ok (Date::leapYear (1900), "1900 is a leap year");
// Days in month. // Days in month.
is (Date::daysInMonth (2, 2008), 29, "29 days in February 2008"); t.is (Date::daysInMonth (2, 2008), 29, "29 days in February 2008");
is (Date::daysInMonth (2, 2007), 28, "28 days in February 2007"); t.is (Date::daysInMonth (2, 2007), 28, "28 days in February 2007");
// Names. // Names.
is (Date::monthName (1), "January", "1 = January"); t.is (Date::monthName (1), "January", "1 = January");
is (Date::monthName (2), "February", "2 = February"); t.is (Date::monthName (2), "February", "2 = February");
is (Date::monthName (3), "March", "3 = March"); t.is (Date::monthName (3), "March", "3 = March");
is (Date::monthName (4), "April", "4 = April"); t.is (Date::monthName (4), "April", "4 = April");
is (Date::monthName (5), "May", "5 = May"); t.is (Date::monthName (5), "May", "5 = May");
is (Date::monthName (6), "June", "6 = June"); t.is (Date::monthName (6), "June", "6 = June");
is (Date::monthName (7), "July", "7 = July"); t.is (Date::monthName (7), "July", "7 = July");
is (Date::monthName (8), "August", "8 = August"); t.is (Date::monthName (8), "August", "8 = August");
is (Date::monthName (9), "September", "9 = September"); t.is (Date::monthName (9), "September", "9 = September");
is (Date::monthName (10), "October", "10 = October"); t.is (Date::monthName (10), "October", "10 = October");
is (Date::monthName (11), "November", "11 = November"); t.is (Date::monthName (11), "November", "11 = November");
is (Date::monthName (12), "December", "12 = December"); t.is (Date::monthName (12), "December", "12 = December");
is (Date::dayName (0), "Sunday", "0 == Sunday"); t.is (Date::dayName (0), "Sunday", "0 == Sunday");
is (Date::dayName (1), "Monday", "1 == Monday"); t.is (Date::dayName (1), "Monday", "1 == Monday");
is (Date::dayName (2), "Tuesday", "2 == Tuesday"); t.is (Date::dayName (2), "Tuesday", "2 == Tuesday");
is (Date::dayName (3), "Wednesday", "3 == Wednesday"); t.is (Date::dayName (3), "Wednesday", "3 == Wednesday");
is (Date::dayName (4), "Thursday", "4 == Thursday"); t.is (Date::dayName (4), "Thursday", "4 == Thursday");
is (Date::dayName (5), "Friday", "5 == Friday"); t.is (Date::dayName (5), "Friday", "5 == Friday");
is (Date::dayName (6), "Saturday", "6 == Saturday"); t.is (Date::dayName (6), "Saturday", "6 == Saturday");
is (Date::dayOfWeek ("SUNDAY"), 0, "SUNDAY == 0"); t.is (Date::dayOfWeek ("SUNDAY"), 0, "SUNDAY == 0");
is (Date::dayOfWeek ("sunday"), 0, "sunday == 0"); t.is (Date::dayOfWeek ("sunday"), 0, "sunday == 0");
is (Date::dayOfWeek ("Sunday"), 0, "Sunday == 0"); t.is (Date::dayOfWeek ("Sunday"), 0, "Sunday == 0");
is (Date::dayOfWeek ("Monday"), 1, "Monday == 1"); t.is (Date::dayOfWeek ("Monday"), 1, "Monday == 1");
is (Date::dayOfWeek ("Tuesday"), 2, "Tuesday == 2"); t.is (Date::dayOfWeek ("Tuesday"), 2, "Tuesday == 2");
is (Date::dayOfWeek ("Wednesday"), 3, "Wednesday == 3"); t.is (Date::dayOfWeek ("Wednesday"), 3, "Wednesday == 3");
is (Date::dayOfWeek ("Thursday"), 4, "Thursday == 4"); t.is (Date::dayOfWeek ("Thursday"), 4, "Thursday == 4");
is (Date::dayOfWeek ("Friday"), 5, "Friday == 5"); t.is (Date::dayOfWeek ("Friday"), 5, "Friday == 5");
is (Date::dayOfWeek ("Saturday"), 6, "Saturday == 6"); t.is (Date::dayOfWeek ("Saturday"), 6, "Saturday == 6");
Date happyNewYear (1, 1, 2008); Date happyNewYear (1, 1, 2008);
is (happyNewYear.dayOfWeek (), 2, "1/1/2008 == Tuesday"); t.is (happyNewYear.dayOfWeek (), 2, "1/1/2008 == Tuesday");
is (happyNewYear.month (), 1, "1/1/2008 == January"); t.is (happyNewYear.month (), 1, "1/1/2008 == January");
is (happyNewYear.day (), 1, "1/1/2008 == 1"); t.is (happyNewYear.day (), 1, "1/1/2008 == 1");
is (happyNewYear.year (), 2008, "1/1/2008 == 2008"); t.is (happyNewYear.year (), 2008, "1/1/2008 == 2008");
is (now - yesterday, 1, "today - yesterday == 1"); t.is (now - yesterday, 1, "today - yesterday == 1");
is (happyNewYear.toString (), "1/1/2008", "toString 1/1/2008"); t.is (happyNewYear.toString (), "1/1/2008", "toString 1/1/2008");
int m, d, y; int m, d, y;
happyNewYear.toMDY (m, d, y); happyNewYear.toMDY (m, d, y);
is (m, 1, "1/1/2008 == January"); t.is (m, 1, "1/1/2008 == January");
is (d, 1, "1/1/2008 == 1"); t.is (d, 1, "1/1/2008 == 1");
is (y, 2008, "1/1/2008 == 2008"); t.is (y, 2008, "1/1/2008 == 2008");
Date epoch (9, 8, 2001); Date epoch (9, 8, 2001);
ok ((int)epoch.toEpoch () < 1000000000, "9/8/2001 < 1,000,000,000"); t.ok ((int)epoch.toEpoch () < 1000000000, "9/8/2001 < 1,000,000,000");
epoch += 86400; epoch += 86400;
ok ((int)epoch.toEpoch () > 1000000000, "9/9/2001 > 1,000,000,000"); t.ok ((int)epoch.toEpoch () > 1000000000, "9/9/2001 > 1,000,000,000");
Date fromEpoch (epoch.toEpoch ()); Date fromEpoch (epoch.toEpoch ());
is (fromEpoch.toString (), epoch.toString (), "ctor (time_t)"); t.is (fromEpoch.toString (), epoch.toString (), "ctor (time_t)");
// Date parsing. // Date parsing.
Date fromString1 ("1/1/2008"); Date fromString1 ("1/1/2008");
is (fromString1.month (), 1, "ctor (std::string) -> m"); t.is (fromString1.month (), 1, "ctor (std::string) -> m");
is (fromString1.day (), 1, "ctor (std::string) -> d"); t.is (fromString1.day (), 1, "ctor (std::string) -> d");
is (fromString1.year (), 2008, "ctor (std::string) -> y"); t.is (fromString1.year (), 2008, "ctor (std::string) -> y");
Date fromString2 ("1/1/2008", "m/d/Y"); Date fromString2 ("1/1/2008", "m/d/Y");
is (fromString2.month (), 1, "ctor (std::string) -> m"); t.is (fromString2.month (), 1, "ctor (std::string) -> m");
is (fromString2.day (), 1, "ctor (std::string) -> d"); t.is (fromString2.day (), 1, "ctor (std::string) -> d");
is (fromString2.year (), 2008, "ctor (std::string) -> y"); t.is (fromString2.year (), 2008, "ctor (std::string) -> y");
Date fromString3 ("20080101", "YMD"); Date fromString3 ("20080101", "YMD");
is (fromString3.month (), 1, "ctor (std::string) -> m"); t.is (fromString3.month (), 1, "ctor (std::string) -> m");
is (fromString3.day (), 1, "ctor (std::string) -> d"); t.is (fromString3.day (), 1, "ctor (std::string) -> d");
is (fromString3.year (), 2008, "ctor (std::string) -> y"); t.is (fromString3.year (), 2008, "ctor (std::string) -> y");
Date fromString4 ("12/31/2007"); Date fromString4 ("12/31/2007");
is (fromString4.month (), 12, "ctor (std::string) -> m"); t.is (fromString4.month (), 12, "ctor (std::string) -> m");
is (fromString4.day (), 31, "ctor (std::string) -> d"); t.is (fromString4.day (), 31, "ctor (std::string) -> d");
is (fromString4.year (), 2007, "ctor (std::string) -> y"); t.is (fromString4.year (), 2007, "ctor (std::string) -> y");
Date fromString5 ("12/31/2007", "m/d/Y"); Date fromString5 ("12/31/2007", "m/d/Y");
is (fromString5.month (), 12, "ctor (std::string) -> m"); t.is (fromString5.month (), 12, "ctor (std::string) -> m");
is (fromString5.day (), 31, "ctor (std::string) -> d"); t.is (fromString5.day (), 31, "ctor (std::string) -> d");
is (fromString5.year (), 2007, "ctor (std::string) -> y"); t.is (fromString5.year (), 2007, "ctor (std::string) -> y");
Date fromString6 ("20071231", "YMD"); Date fromString6 ("20071231", "YMD");
is (fromString6.month (), 12, "ctor (std::string) -> m"); t.is (fromString6.month (), 12, "ctor (std::string) -> m");
is (fromString6.day (), 31, "ctor (std::string) -> d"); t.is (fromString6.day (), 31, "ctor (std::string) -> d");
is (fromString6.year (), 2007, "ctor (std::string) -> y"); t.is (fromString6.year (), 2007, "ctor (std::string) -> y");
Date fromString7 ("01/01/2008", "m/d/Y"); Date fromString7 ("01/01/2008", "m/d/Y");
is (fromString7.month (), 1, "ctor (std::string) -> m"); t.is (fromString7.month (), 1, "ctor (std::string) -> m");
is (fromString7.day (), 1, "ctor (std::string) -> d"); t.is (fromString7.day (), 1, "ctor (std::string) -> d");
is (fromString7.year (), 2008, "ctor (std::string) -> y"); t.is (fromString7.year (), 2008, "ctor (std::string) -> y");
// Relative dates. // Relative dates.
Date r1 ("today"); Date r1 ("today");
ok (r1.sameDay (now), "today = now"); t.ok (r1.sameDay (now), "today = now");
Date r2 ("tomorrow"); Date r2 ("tomorrow");
ok (r2.sameDay (now + 86400), "tomorrow = now + 1d"); t.ok (r2.sameDay (now + 86400), "tomorrow = now + 1d");
Date r3 ("yesterday"); Date r3 ("yesterday");
ok (r3.sameDay (now - 86400), "yesterday = now - 1d"); t.ok (r3.sameDay (now - 86400), "yesterday = now - 1d");
Date r4 ("sunday"); Date r4 ("sunday");
if (now.dayOfWeek () >= 0) if (now.dayOfWeek () >= 0)
ok (r4.sameDay (now + (0 - now.dayOfWeek () + 7) * 86400), "next sunday"); t.ok (r4.sameDay (now + (0 - now.dayOfWeek () + 7) * 86400), "next sunday");
else else
ok (r4.sameDay (now + (0 - now.dayOfWeek ()) * 86400), "next sunday");; t.ok (r4.sameDay (now + (0 - now.dayOfWeek ()) * 86400), "next sunday");;
Date r5 ("monday"); Date r5 ("monday");
if (now.dayOfWeek () >= 1) if (now.dayOfWeek () >= 1)
ok (r5.sameDay (now + (1 - now.dayOfWeek () + 7) * 86400), "next monday"); t.ok (r5.sameDay (now + (1 - now.dayOfWeek () + 7) * 86400), "next monday");
else else
ok (r5.sameDay (now + (1 - now.dayOfWeek ()) * 86400), "next monday");; t.ok (r5.sameDay (now + (1 - now.dayOfWeek ()) * 86400), "next monday");;
Date r6 ("tuesday"); Date r6 ("tuesday");
if (now.dayOfWeek () >= 2) if (now.dayOfWeek () >= 2)
ok (r6.sameDay (now + (2 - now.dayOfWeek () + 7) * 86400), "next tuesday"); t.ok (r6.sameDay (now + (2 - now.dayOfWeek () + 7) * 86400), "next tuesday");
else else
ok (r6.sameDay (now + (2 - now.dayOfWeek ()) * 86400), "next tuesday");; t.ok (r6.sameDay (now + (2 - now.dayOfWeek ()) * 86400), "next tuesday");;
Date r7 ("wednesday"); Date r7 ("wednesday");
if (now.dayOfWeek () >= 3) if (now.dayOfWeek () >= 3)
ok (r7.sameDay (now + (3 - now.dayOfWeek () + 7) * 86400), "next wednesday"); t.ok (r7.sameDay (now + (3 - now.dayOfWeek () + 7) * 86400), "next wednesday");
else else
ok (r7.sameDay (now + (3 - now.dayOfWeek ()) * 86400), "next wednesday");; t.ok (r7.sameDay (now + (3 - now.dayOfWeek ()) * 86400), "next wednesday");;
Date r8 ("thursday"); Date r8 ("thursday");
if (now.dayOfWeek () >= 4) if (now.dayOfWeek () >= 4)
ok (r8.sameDay (now + (4 - now.dayOfWeek () + 7) * 86400), "next thursday"); t.ok (r8.sameDay (now + (4 - now.dayOfWeek () + 7) * 86400), "next thursday");
else else
ok (r8.sameDay (now + (4 - now.dayOfWeek ()) * 86400), "next thursday");; t.ok (r8.sameDay (now + (4 - now.dayOfWeek ()) * 86400), "next thursday");;
Date r9 ("friday"); Date r9 ("friday");
if (now.dayOfWeek () >= 5) if (now.dayOfWeek () >= 5)
ok (r9.sameDay (now + (5 - now.dayOfWeek () + 7) * 86400), "next friday"); t.ok (r9.sameDay (now + (5 - now.dayOfWeek () + 7) * 86400), "next friday");
else else
ok (r9.sameDay (now + (5 - now.dayOfWeek ()) * 86400), "next friday");; t.ok (r9.sameDay (now + (5 - now.dayOfWeek ()) * 86400), "next friday");;
Date r10 ("saturday"); Date r10 ("saturday");
if (now.dayOfWeek () >= 6) if (now.dayOfWeek () >= 6)
ok (r10.sameDay (now + (6 - now.dayOfWeek () + 7) * 86400), "next saturday"); t.ok (r10.sameDay (now + (6 - now.dayOfWeek () + 7) * 86400), "next saturday");
else else
ok (r10.sameDay (now + (6 - now.dayOfWeek ()) * 86400), "next saturday");; t.ok (r10.sameDay (now + (6 - now.dayOfWeek ()) * 86400), "next saturday");;
Date r11 ("eow"); Date r11 ("eow");
ok (r11 < now + (8 * 86400), "eow < 7 days away"); t.ok (r11 < now + (8 * 86400), "eow < 7 days away");
Date r12 ("eom"); Date r12 ("eom");
ok (r12.sameMonth (now), "eom in same month as now"); t.ok (r12.sameMonth (now), "eom in same month as now");
Date r13 ("eoy"); Date r13 ("eoy");
ok (r13.sameYear (now), "eoy in same year as now"); t.ok (r13.sameYear (now), "eoy in same year as now");
} }
catch (std::string& e) catch (std::string& e)
{ {
fail ("Exception thrown."); t.fail ("Exception thrown.");
diag (e); t.diag (e);
} }
return 0; return 0;

72
src/tests/dateformat.t Executable file
View File

@@ -0,0 +1,72 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 8;
# Create the rc file.
if (open my $fh, '>', 'date1.rc')
{
print $fh "data.location=.\n",
"dateformat=YMD\n";
close $fh;
ok (-r 'date1.rc', 'Created date1.rc');
}
if (open my $fh, '>', 'date2.rc')
{
print $fh "data.location=.\n",
"dateformat=m/d/y\n";
close $fh;
ok (-r 'date2.rc', 'Created date2.rc');
}
qx{../task rc:date1.rc add foo due:20091231};
my $output = qx{../task rc:date1.rc info 1};
like ($output, qr/\b20091231\b/, 'date format YMD parsed');
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
qx{../task rc:date2.rc add foo due:12/1/09};
$output = qx{../task rc:date2.rc info 1};
like ($output, qr/\b12\/1\/09\b/, 'date format m/d/y parsed');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'date1.rc';
ok (!-r 'date1.rc', 'Removed date1.rc');
unlink 'date2.rc';
ok (!-r 'date2.rc', 'Removed date2.rc');
exit 0;

83
src/tests/default.t Executable file
View File

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

78
src/tests/delete.t Executable file
View File

@@ -0,0 +1,78 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 16;
# Create the rc file.
if (open my $fh, '>', 'undelete.rc')
{
print $fh "data.location=.\n",
"echo.command=no\n";
close $fh;
ok (-r 'undelete.rc', 'Created undelete.rc');
}
# Add a task, delete it, undelete it.
my $output = qx{../task rc:undelete.rc add one; ../task rc:undelete.rc info 1};
ok (-r 'pending.data', 'pending.data created');
like ($output, qr/Status\s+Pending\n/, 'Pending');
$output = qx{../task rc:undelete.rc delete 1; ../task rc:undelete.rc info 1};
like ($output, qr/Status\s+Deleted\n/, 'Deleted');
ok (! -r 'completed.data', 'completed.data not created');
$output = qx{../task rc:undelete.rc undelete 1; ../task rc:undelete.rc info 1};
like ($output, qr/Status\s+Pending\n/, 'Pending');
ok (! -r 'completed.data', 'completed.data not created');
$output = qx{../task rc:undelete.rc delete 1; ../task rc:undelete.rc list};
like ($output, qr/^No matches/, 'No matches');
ok (-r 'completed.data', 'completed.data created');
$output = qx{../task rc:undelete.rc undelete 1};
like ($output, qr/reliably undeleted/, 'can only be reliable undeleted...');
$output = qx{../task rc:undelete.rc info 1};
like ($output, qr/No matches./, 'no matches');
# Cleanup.
ok (-r 'pending.data', 'Need to remove pending.data');
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
ok (-r 'completed.data', 'Need to remove completed.data');
unlink 'completed.data';
ok (!-r 'completed.data', 'Removed completed.data');
unlink 'undelete.rc';
ok (!-r 'undelete.rc', 'Removed undelete.rc');
exit 0;

67
src/tests/due.t Executable file
View File

@@ -0,0 +1,67 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 5;
# Create the rc file.
if (open my $fh, '>', 'due.rc')
{
print $fh "data.location=.\n",
"due=4\n",
"color=on\n",
"color.due=red\n",
"_forcecolor=on\n",
"dateformat=m/d/Y\n";
close $fh;
ok (-r 'due.rc', 'Created due.rc');
}
# Add a task that is almost due, and one that is just due.
my ($d, $m, $y) = (localtime (time + 3 * 86_400))[3..5];
my $just = sprintf ("%d/%d/%d", $m + 1, $d, $y + 1900);
($d, $m, $y) = (localtime (time + 5 * 86_400))[3..5];
my $almost = sprintf ("%d/%d/%d", $m + 1, $d, $y + 1900);
qx{../task rc:due.rc add one due:$just};
qx{../task rc:due.rc add two due:$almost};
my $output = qx{../task rc:due.rc list};
like ($output, qr/\[31m.+$just.+\[0m/, 'one marked due');
like ($output, qr/\s+$almost\s+/, 'two not marked due');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'due.rc';
ok (!-r 'due.rc', 'Removed due.rc');
exit 0;

View File

@@ -1,5 +1,27 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Copyright 2005 - 2008, Paul Beckingham. All rights reserved. // task - a command line task list manager.
//
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <iostream> #include <iostream>
@@ -16,27 +38,27 @@
// biannual, biyearly, annual, semiannual, yearly, Ny // biannual, biyearly, annual, semiannual, yearly, Ny
int main (int argc, char** argv) int main (int argc, char** argv)
{ {
plan (17); UnitTest t (17);
std::string d; std::string d;
d = "daily"; is (convertDuration (d), 1, "duration daily = 1"); d = "daily"; t.is (convertDuration (d), 1, "duration daily = 1");
d = "day"; is (convertDuration (d), 1, "duration day = 1"); d = "weekdays"; t.is (convertDuration (d), 1, "duration weekdays = 1");
d = "0d"; is (convertDuration (d), 0, "duration 0d = 0"); d = "day"; t.is (convertDuration (d), 1, "duration day = 1");
d = "1d"; is (convertDuration (d), 1, "duration 1d = 1"); d = "0d"; t.is (convertDuration (d), 0, "duration 0d = 0");
d = "7d"; is (convertDuration (d), 7, "duration 7d = 7"); d = "1d"; t.is (convertDuration (d), 1, "duration 1d = 1");
d = "10d"; is (convertDuration (d), 10, "duration 10d = 10"); d = "7d"; t.is (convertDuration (d), 7, "duration 7d = 7");
d = "100d"; is (convertDuration (d), 100, "duration 100d = 100"); d = "10d"; t.is (convertDuration (d), 10, "duration 10d = 10");
d = "100d"; t.is (convertDuration (d), 100, "duration 100d = 100");
d = "weekly"; is (convertDuration (d), 7, "duration weekly = 7"); d = "weekly"; t.is (convertDuration (d), 7, "duration weekly = 7");
d = "sennight"; is (convertDuration (d), 7, "duration sennight = 7"); d = "sennight"; t.is (convertDuration (d), 7, "duration sennight = 7");
d = "biweekly"; is (convertDuration (d), 14, "duration biweekly = 14"); d = "biweekly"; t.is (convertDuration (d), 14, "duration biweekly = 14");
d = "fortnight"; is (convertDuration (d), 14, "duration fortnight = 14"); d = "fortnight"; t.is (convertDuration (d), 14, "duration fortnight = 14");
d = "week"; is (convertDuration (d), 7, "duration week = 7"); d = "0w"; t.is (convertDuration (d), 0, "duration 0w = 0");
d = "0w"; is (convertDuration (d), 0, "duration 0w = 0"); d = "1w"; t.is (convertDuration (d), 7, "duration 1w = 7");
d = "1w"; is (convertDuration (d), 7, "duration 1w = 7"); d = "7w"; t.is (convertDuration (d), 49, "duration 7w = 49");
d = "7w"; is (convertDuration (d), 49, "duration 7w = 49"); d = "10w"; t.is (convertDuration (d), 70, "duration 10w = 70");
d = "10w"; is (convertDuration (d), 70, "duration 10w = 70"); d = "100w"; t.is (convertDuration (d), 700, "duration 100w = 700");
d = "100w"; is (convertDuration (d), 700, "duration 100w = 700");
return 0; return 0;
} }

72
src/tests/export.t Executable file
View File

@@ -0,0 +1,72 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 7;
# Create the rc file.
if (open my $fh, '>', 'export.rc')
{
print $fh "data.location=.\n";
close $fh;
ok (-r 'export.rc', 'Created export.rc');
}
# Add two tasks, export, examine result.
qx{../task rc:export.rc add priority:H project:A one};
qx{../task rc:export.rc add +tag1 +tag2 two};
qx{../task rc:export.rc export ./export.txt};
my @lines;
if (open my $fh, '<', './export.txt')
{
@lines = <$fh>;
close $fh;
}
my $line1 = qr/'id','uuid','status','tags','entry','start','due','recur','end','project','priority','fg','bg','description'\n/;
my $line2 = qr/'.{8}-.{4}-.{4}-.{4}-.{12}','pending','',\d+,,,,,'A','H',,,'one'\n/;
my $line3 = qr/'.{8}-.{4}-.{4}-.{4}-.{12}','pending','tag1 tag2',\d+,,,,,,,,,'two'\n/;
like ($lines[0], $line1, "export line one");
like ($lines[1], $line2, "export line two");
like ($lines[2], $line3, "export line three");
# Cleanup.
unlink 'export.txt';
ok (!-r 'export.txt', 'Removed export.txt');
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'export.rc';
ok (!-r 'export.rc', 'Removed export.rc');
exit 0;

193
src/tests/filter.t Executable file
View File

@@ -0,0 +1,193 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 108;
# Create the rc file.
if (open my $fh, '>', 'filter.rc')
{
print $fh "data.location=.\n";
close $fh;
ok (-r 'filter.rc', 'Created filter.rc');
}
# Test the filters.
qx{../task rc:filter.rc add project:A priority:H +tag one foo};
qx{../task rc:filter.rc add project:A priority:H two};
qx{../task rc:filter.rc add project:A three};
qx{../task rc:filter.rc add priority:H four};
qx{../task rc:filter.rc add +tag five};
qx{../task rc:filter.rc add six foo};
qx{../task rc:filter.rc add priority:L seven bar foo};
my $output = qx{../task rc:filter.rc list};
like ($output, qr/one/, 'a1');
like ($output, qr/two/, 'a2');
like ($output, qr/three/, 'a3');
like ($output, qr/four/, 'a4');
like ($output, qr/five/, 'a5');
like ($output, qr/six/, 'a6');
like ($output, qr/seven/, 'a7');
$output = qx{../task rc:filter.rc list project:A};
like ($output, qr/one/, 'b1');
like ($output, qr/two/, 'b2');
like ($output, qr/three/, 'b3');
unlike ($output, qr/four/, 'b4');
unlike ($output, qr/five/, 'b5');
unlike ($output, qr/six/, 'b6');
unlike ($output, qr/seven/, 'b7');
$output = qx{../task rc:filter.rc list priority:H};
like ($output, qr/one/, 'c1');
like ($output, qr/two/, 'c2');
unlike ($output, qr/three/, 'c3');
like ($output, qr/four/, 'c4');
unlike ($output, qr/five/, 'c5');
unlike ($output, qr/six/, 'c6');
unlike ($output, qr/seven/, 'c7');
$output = qx{../task rc:filter.rc list priority:};
unlike ($output, qr/one/, 'd1');
unlike ($output, qr/two/, 'd2');
like ($output, qr/three/, 'd3');
unlike ($output, qr/four/, 'd4');
like ($output, qr/five/, 'd5');
like ($output, qr/six/, 'd6');
unlike ($output, qr/seven/, 'd7');
$output = qx{../task rc:filter.rc list foo};
like ($output, qr/one/, 'e1');
unlike ($output, qr/two/, 'e2');
unlike ($output, qr/three/, 'e3');
unlike ($output, qr/four/, 'e4');
unlike ($output, qr/five/, 'e5');
like ($output, qr/six/, 'e6');
like ($output, qr/seven/, 'e7');
$output = qx{../task rc:filter.rc list foo bar};
unlike ($output, qr/one/, 'f1');
unlike ($output, qr/two/, 'f2');
unlike ($output, qr/three/, 'f3');
unlike ($output, qr/four/, 'f4');
unlike ($output, qr/five/, 'f5');
unlike ($output, qr/six/, 'f6');
like ($output, qr/seven/, 'f7');
$output = qx{../task rc:filter.rc list +tag};
like ($output, qr/one/, 'g1');
unlike ($output, qr/two/, 'g2');
unlike ($output, qr/three/, 'g3');
unlike ($output, qr/four/, 'g4');
like ($output, qr/five/, 'g5');
unlike ($output, qr/six/, 'g6');
unlike ($output, qr/seven/, 'g7');
$output = qx{../task rc:filter.rc list project:A priority:H};
like ($output, qr/one/, 'h1');
like ($output, qr/two/, 'h2');
unlike ($output, qr/three/, 'h3');
unlike ($output, qr/four/, 'h4');
unlike ($output, qr/five/, 'h5');
unlike ($output, qr/six/, 'h6');
unlike ($output, qr/seven/, 'h7');
$output = qx{../task rc:filter.rc list project:A priority:};
unlike ($output, qr/one/, 'i1');
unlike ($output, qr/two/, 'i2');
like ($output, qr/three/, 'i3');
unlike ($output, qr/four/, 'i4');
unlike ($output, qr/five/, 'i5');
unlike ($output, qr/six/, 'i6');
unlike ($output, qr/seven/, 'i7');
$output = qx{../task rc:filter.rc list project:A foo};
like ($output, qr/one/, 'j1');
unlike ($output, qr/two/, 'j2');
unlike ($output, qr/three/, 'j3');
unlike ($output, qr/four/, 'j4');
unlike ($output, qr/five/, 'j5');
unlike ($output, qr/six/, 'j6');
unlike ($output, qr/seven/, 'j7');
$output = qx{../task rc:filter.rc list project:A +tag};
like ($output, qr/one/, 'k1');
unlike ($output, qr/two/, 'k2');
unlike ($output, qr/three/, 'k3');
unlike ($output, qr/four/, 'k4');
unlike ($output, qr/five/, 'k5');
unlike ($output, qr/six/, 'k6');
unlike ($output, qr/seven/, 'k7');
$output = qx{../task rc:filter.rc list project:A priority:H foo};
like ($output, qr/one/, 'l1');
unlike ($output, qr/two/, 'l2');
unlike ($output, qr/three/, 'l3');
unlike ($output, qr/four/, 'l4');
unlike ($output, qr/five/, 'l5');
unlike ($output, qr/six/, 'l6');
unlike ($output, qr/seven/, 'l7');
$output = qx{../task rc:filter.rc list project:A priority:H +tag};
like ($output, qr/one/, 'm1');
unlike ($output, qr/two/, 'm2');
unlike ($output, qr/three/, 'm3');
unlike ($output, qr/four/, 'm4');
unlike ($output, qr/five/, 'm5');
unlike ($output, qr/six/, 'm6');
unlike ($output, qr/seven/, 'm7');
$output = qx{../task rc:filter.rc list project:A priority:H foo +tag};
like ($output, qr/one/, 'n1');
unlike ($output, qr/two/, 'n2');
unlike ($output, qr/three/, 'n3');
unlike ($output, qr/four/, 'n4');
unlike ($output, qr/five/, 'n5');
unlike ($output, qr/six/, 'n6');
unlike ($output, qr/seven/, 'n7');
$output = qx{../task rc:filter.rc list project:A priority:H foo +tag baz};
unlike ($output, qr/one/, 'n1');
unlike ($output, qr/two/, 'n2');
unlike ($output, qr/three/, 'n3');
unlike ($output, qr/four/, 'n4');
unlike ($output, qr/five/, 'n5');
unlike ($output, qr/six/, 'n6');
unlike ($output, qr/seven/, 'n7');
# Cleanup.
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'filter.rc';
ok (!-r 'filter.rc', 'Removed filter.rc');
exit 0;

70
src/tests/import.143.t Executable file
View File

@@ -0,0 +1,70 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 8;
# Create the rc file.
if (open my $fh, '>', 'import.rc')
{
print $fh "data.location=.\n";
close $fh;
ok (-r 'import.rc', 'Created import.rc');
}
# Create import file.
if (open my $fh, '>', 'import.txt')
{
print $fh "'id','status','tags','entry','start','due','end','project','priority','fg','bg','description'\n",
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,'A','M',,,'foo bar'\n",
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,'A','M',,,'foo, bar'\n",
"\n";
close $fh;
ok (-r 'import.txt', 'Created sample import data');
}
my $output = qx{../task rc:import.rc import import.txt};
is ($output, "Imported 2 tasks successfully, with 0 errors.\n", 'no errors');
$output = qx{../task rc:import.rc list};
like ($output, qr/1.+A.+M.+foo bar/, 't1');
like ($output, qr/2.+A.+M.+foo, bar/, 't2');
# Cleanup.
unlink 'import.txt';
ok (!-r 'import.txt', 'Removed import.txt');
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'import.rc';
ok (!-r 'import.rc', 'Removed import.rc');
exit 0;

70
src/tests/import.150.t Executable file
View File

@@ -0,0 +1,70 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 8;
# Create the rc file.
if (open my $fh, '>', 'import.rc')
{
print $fh "data.location=.\n";
close $fh;
ok (-r 'import.rc', 'Created import.rc');
}
# Create import file.
if (open my $fh, '>', 'import.txt')
{
print $fh "'id','uuid','status','tags','entry','start','due','recur','end','project','priority','fg','bg','description'\n",
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,,'A','M',,,'foo bar'\n",
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,,'A','M',,,'foo, bar'\n",
"\n";
close $fh;
ok (-r 'import.txt', 'Created sample import data');
}
my $output = qx{../task rc:import.rc import import.txt};
is ($output, "Imported 2 tasks successfully, with 0 errors.\n", 'no errors');
$output = qx{../task rc:import.rc list};
like ($output, qr/1.+A.+M.+foo bar/, 't1');
like ($output, qr/2.+A.+M.+foo, bar/, 't2');
# Cleanup.
unlink 'import.txt';
ok (!-r 'import.txt', 'Removed import.txt');
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'import.rc';
ok (!-r 'import.rc', 'Removed import.rc');
exit 0;

70
src/tests/import.160.t Executable file
View File

@@ -0,0 +1,70 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 8;
# Create the rc file.
if (open my $fh, '>', 'import.rc')
{
print $fh "data.location=.\n";
close $fh;
ok (-r 'import.rc', 'Created import.rc');
}
# Create import file.
if (open my $fh, '>', 'import.txt')
{
print $fh "'uuid','status','tags','entry','start','due','recur','end','project','priority','fg','bg','description'\n",
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,,'A','M',,,'foo bar'\n",
"'7f7a4191-c2f2-487f-8855-7a1eb378c267','pending','',1238037947,,,,,'A','M',,,'foo, bar'\n",
"\n";
close $fh;
ok (-r 'import.txt', 'Created sample import data');
}
my $output = qx{../task rc:import.rc import import.txt};
is ($output, "Imported 2 tasks successfully, with 0 errors.\n", 'no errors');
$output = qx{../task rc:import.rc list};
like ($output, qr/1.+A.+M.+foo bar/, 't1');
like ($output, qr/2.+A.+M.+foo, bar/, 't2');
# Cleanup.
unlink 'import.txt';
ok (!-r 'import.txt', 'Removed import.txt');
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'import.rc';
ok (!-r 'import.rc', 'Removed import.rc');
exit 0;

69
src/tests/import.cmd.t Executable file
View File

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

70
src/tests/import.csv.t Executable file
View File

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

76
src/tests/import.todo.t Executable file
View File

@@ -0,0 +1,76 @@
#! /usr/bin/perl
################################################################################
## task - a command line task list manager.
##
## Copyright 2006 - 2009, Paul Beckingham.
## All rights reserved.
##
## This program is free software; you can redistribute it and/or modify it under
## the terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
## FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
## details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the
##
## Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor,
## Boston, MA
## 02110-1301
## USA
##
################################################################################
use strict;
use warnings;
use Test::More tests => 10;
# Create the rc file.
if (open my $fh, '>', 'import.rc')
{
print $fh "data.location=.\n";
close $fh;
ok (-r 'import.rc', 'Created import.rc');
}
# Create import file.
if (open my $fh, '>', 'import.txt')
{
print $fh "x 2009-03-25 Walk the dog +project \@context\n",
"This is a test +project \@context\n",
"(A) A prioritized task\n",
"\n";
close $fh;
ok (-r 'import.txt', 'Created sample import data');
}
my $output = qx{../task rc:import.rc import import.txt};
is ($output, "Imported 3 tasks successfully, with 0 errors.\n", 'no errors');
$output = qx{../task rc:import.rc list};
like ($output, qr/1.+project.+This is a test/, 't1');
like ($output, qr/2.+H.+A prioritized task/, 't2');
$output = qx{../task rc:import.rc completed};
like ($output, qr/3\/25\/2009.+Walk the dog/, 't3');
# Cleanup.
unlink 'import.txt';
ok (!-r 'import.txt', 'Removed import.txt');
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'completed.data';
ok (!-r 'completed.data', 'Removed completed.data');
unlink 'import.rc';
ok (!-r 'import.rc', 'Removed import.rc');
exit 0;

Some files were not shown because too many files have changed in this diff Show More