Compare commits

...

162 Commits

Author SHA1 Message Date
Paul Beckingham
1b6faf57c9 Unit Tests - correction to T::compose tests
- Uses " instead of ' to quote annotations.
2009-04-24 00:09:59 -04:00
Paul Beckingham
76c66b8ab1 Documentation Update
- Added Ubuntu 9.04 (Jaunty Jackalope) to the docs.
2009-04-23 23:59:59 -04:00
Paul Beckingham
fe84ddcc98 Bug Fix - missing report labels in default .taskrc
- Added report labels to the .taskrc file that is created by default,
  when no .taskrc is found.  Thanks to P. C. Shyamshankar.
2009-04-23 23:54:21 -04:00
Paul Beckingham
a77d4662f8 New Version - 1.6.1 2009-04-22 19:50:06 -04:00
Paul Beckingham
60915cefd4 Documentation Update
- Added 1.6.0 rpm download link.
2009-04-22 19:39:56 -04:00
Paul Beckingham
e23243e195 Bug Fix - missing ///g from usage
- Added text describing the ///g substitution feature.
- Updated ChangeLog.
2009-04-13 20:44:35 -04:00
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 10283 additions and 1999 deletions

3
.gitignore vendored
View File

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

14
AUTHORS
View File

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

337
ChangeLog
View File

@@ -1,7 +1,55 @@
------ current release ---------------------------
1.5.0 (?)
1.6.1 (4/22/2009)
+ Fixed bug that caused new, first-time .taskrc files to be written without
including the custom report labels (thanks to P.C. Shyamshankar).
------ old releases ------------------------------
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".
1.5.0 (3/15/2009) 87be68e2e83d7bb628be1e5679b16a49a26d3549
+ Removed deprecated TUTORIAL file.
+ Removed "showage" configuration variable.
+ "task stop" can now remove the start time from a started task.
@@ -11,146 +59,175 @@
which may be spelling mistakes or deprecated variables.
+ "configure --enable-debug" now supported to suppress compiler optimization
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)
1.4.3 (11/1/2008) 8639e9260646c8c9224e0fc47e5d2443b46eecfc
+ Fixed misleading task count at bottom on "info" report.
+ Added support for a shadow file that contains a plain text task report,
with the "shadow.file" and "shadow.command" configuration variables
with the "shadow.file" and "shadow.command" configuration variables.
The shadow file is automatically updated whenever the task database
changes. Useful for integrating with "Samurize"
changes. Useful for integrating with "Samurize".
+ Task now displays a message whenever a shadow file is updated, if the
"shadow.notify" configuration variable is set "on"
+ Bug: adding a task with a \n, \r or \f in it now fails properly
"shadow.notify" configuration variable is set "on".
+ Bug: adding a task with a \n, \r or \f in it now fails properly.
+ Removed "usage" command, and support for "command.logging" configuration
variable.
+ Added documentation for Shadow files.
+ 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
have been run (and therefore TDB::gc run)
have been run (and therefore TDB::gc run).
+ Task now correctly sorts on entire strings, instead of just the first
character (thanks to Andy Lester)
character (thanks to Andy Lester).
+ Task now uses dashes (-----) to column underlines when color is disabled
(thanks to Vincent Fleuranceau)
(thanks to Vincent Fleuranceau).
+ Task now allows mixed case attribute names (pri:, PRI:, Pri: ...) and
commands (add, ADD, Add ...) (thanks to Vincent Fleuranceau)
commands (add, ADD, Add ...) (thanks to Vincent Fleuranceau).
+ Task now supports a default project and priority for new tasks, via
the new "default.project" and "default.priority" configuration variables
(thanks to Vincent Fleuranceau)
+ Task supports improved word-wrapping to the terminal width
(thanks to Vincent Fleuranceau).
+ Task supports improved word-wrapping to the terminal width.
+ Task now supports "default.command" configuration variable (for example
it could contain "list due:tomorrow") that is the command that is run
whenever task is invoked with no arguments.
+ Task supports modifying the existing description of a task, with the
following syntax: task <id> "new description ...".
+ Bug: Now properly supports relative dates in filters (task list due:eom,
task list due:tomorrow, task list due:23rd ...)
task list due:tomorrow, task list due:23rd ...).
+ Bug: Source now properly includes <string.h> in order to build clean
using gcc 4.3 (thanks to H. İbrahim Güngör)
using gcc 4.3 (thanks to H. İbrahim Güngör).
1.4.1 (7/18/2008)
+ Bug: Descriptions can not be altered with "task 123 New description"
+ Tweak: For "task calendar" month names are now centered over the month
+ Removed TUTORIAL file contents in favor of online version
+ Provided Mac .pkg binary
1.4.1 (7/18/2008) e080c3168c6064628ab85b21bd859d9875a3a9a7
+ Bug: Descriptions can not be altered with "task 123 New description".
+ Tweak: For "task calendar" month names are now centered over the month.
+ Removed TUTORIAL file contents in favor of online version.
+ Provided Mac .pkg binary.
1.4.0 (7/10/2008)
+ New recurring tasks feature
1.4.0 (7/10/2008) 60b7d15a1d22e064acf0974c5d7eabbb57dd8071
+ New recurring tasks feature.
+ "task undelete" can now undelete erroneously deleted tasks, provided no
reports have been run (and therefore TDB::gc run)
+ Added averages to the "task history" report
+ Added ability to override ~/.taskrc with rc:<file>
+ Added bar chart history report "task ghistory"
+ Added task filtering on all reports
+ Automatically shuts off color, curses when output is not a tty
+ Supports relative due: dates (tomorrow, wednesday, 23rd, eom ...)
+ Supports the ~ character in .taskrc data.location
reports have been run (and therefore TDB::gc run).
+ Added averages to the "task history" report.
+ Added ability to override ~/.taskrc with rc:<file>.
+ Added bar chart history report "task ghistory".
+ Added task filtering on all reports.
+ Automatically shuts off color, curses when output is not a tty.
+ Supports relative due: dates (tomorrow, wednesday, 23rd, eom ...).
+ Supports the ~ character in .taskrc data.location.
+ Allows colons on the description, provided what is to the left of the colon
is not a standard attribute name
+ Bug: Fixed where Esc[0m sequences were being emitted for no good reason
+ Bug: Fixed underlined table headers when color is turned off
+ Bug: Adding a blank priority resulted in an assigned garbage value
+ Bug: Fixed parsing of date "07/08/2008" when using dateformat "m/d/Y"
is not a standard attribute name.
+ Bug: Fixed where Esc[0m sequences were being emitted for no good reason.
+ Bug: Fixed underlined table headers when color is turned off.
+ Bug: Adding a blank priority resulted in an assigned garbage value.
+ Bug: Fixed parsing of date "07/08/2008" when using dateformat "m/d/Y".
1.3.1 (6/21/2008)
1.3.1 (6/21/2008) 3a6de7d9402f2609a773a73b16eff97b14a32869
+ New configuration variable, "defaultwidth" that determines the width
of tables when ncurses support is not available
of tables when ncurses support is not available.
+ Bug: "showage" configuration variable should apply to all reports, not
just the ones based on "list"
just the ones based on "list".
+ Bug: Fixed segmentation faults on Ubuntu when the "dateformat"
configuration variables was missing. This was a code bug, and should
have affected more platforms
have affected more platforms.
+ Bug: Task now will recreate a missing ~/.taskrc file, OR a missing
~/.task directory
~/.task directory.
1.3.0 (6/18/2008)
1.3.0 (6/18/2008) 6673e408a223af98c38779c20b08524042c0edfa
+ "task calendar" now displays multiple months per line, adjustable by the
"monthsperline" configuration variable. Feature added by Damian Glenny
+ "task export" can now filter tasks like the reports
+ Factored out code to filter tasks
"monthsperline" configuration variable. Feature added by Damian Glenny.
+ "task export" can now filter tasks like the reports.
+ Factored out code to filter tasks.
+ Displays shorter message when a command is entered incorrectly, and the
full usage for "task help"
+ "task oldest" shows the oldest tasks
+ "task newest" shows the newest tasks
full usage for "task help".
+ "task oldest" shows the oldest tasks.
+ "task newest" shows the newest tasks.
+ Bug: Segmentation fault when no "dateformat" configuration variable
specified
specified.
+ Bug: Fixed bug whereby if you have more than one task with a due date, 7
days gets added to the entry date of task 2..n
+ Bug: Fixed bug whereby "1 wks" was being improperly pluralized
days gets added to the entry date of task 2..n.
+ Bug: Fixed bug whereby "1 wks" was being improperly pluralized.
1.2.0 (6/13/2008)
1.2.0 (6/13/2008) c393d47cdfe7e197a31e94f4bb764474fa05ad8d
+ Bug: "dateformat" configuration variable used to display dates, but
not parse them
not parse them.
+ "task list x" now performs a caseless comparison between "x" and the
description
+ Task sub projects supported
description.
+ Task sub projects supported.
+ "showage" confguration determines whether "Age" column appears on the
"list" and "next" reports
+ Improved TUTORIAL
"list" and "next" reports.
+ Improved TUTORIAL.
1.1.0 (6/7/2008)
1.1.0 (6/7/2008) 73286e86628725b346db2a25fbcd4bd68efb9b3a
+ "blanklines" configuration to stop displaying unnecessary white
space and thus work better on small-screen devices
+ "dateformat" configuration now determines how dates are formatted
+ Better formatting of "task tags" output
+ http://www.beckingham.net/task.html home page set up
+ Added tags to the "task long" report
space and thus work better on small-screen devices.
+ "dateformat" configuration now determines how dates are formatted.
+ Better formatting of "task tags" output.
+ http://www.beckingham.net/task.html home page set up.
+ Added tags to the "task long" report.
1.0.1 (6/4/2008)
1.0.1 (6/4/2008) d216d401217027d93581808fc8944ab7d6b85fb0
+ Bug: UUID generator not properly terminating string.
+ Bug: srandom/srand not called prior to UUID generation.
1.0.0 (6/3/2008)
+ New movie made, uploaded
+ Bug: assertion fails on mobile for t v
+ Bug: configure.ac does not properly determine ncurses availability
+ Bug: Cannot seem to use the percent character in a task description
+ Bug: New installation "task stats" reports newest task 12/31/1969
+ Bug: New installation task projects displays header but no data - should short-circuit
+ Bug: incorrect color specification in sample .taskrc file
+ Bug: when run without arguments, task dumps core on Solaris 10
+ "task calendar" now reports all months with due pending tasks
+ Added rules for colorization by tag, project and keyword
+ Added legend to "task calendar"
1.0.0 (6/3/2008) f3de5c07118c597091a05c7d7fe8bdeae95474c1
+ New movie made, uploaded.
+ Bug: assertion fails on mobile for t v.
+ Bug: configure.ac does not properly determine ncurses availability.
+ Bug: Cannot seem to use the percent character in a task description.
+ Bug: New installation "task stats" reports newest task 12/31/1969.
+ Bug: New installation task projects displays header but no data - should short-circuit.
+ Bug: incorrect color specification in sample .taskrc file.
+ Bug: when run without arguments, task dumps core on Solaris 10.
+ "task calendar" now reports all months with due pending tasks.
+ Added rules for colorization by tag, project and keyword.
+ Added legend to "task calendar".
0.9.9 (5/27/2008)
0.9.9 (5/27/2008) 2ecf50032226c91b406f247417a063dc17c8e324
+ Autoconf/automake behaving properly.
+ Clean build on OS X 10.5.
+ Clean build on Ubuntu 8.0.
+ Clean build on Fedora Core 8.
+ Clean build on Fedora Core 9.
0.9.8 (5/25/2008)
0.9.8 (5/25/2008) 18fd59a1edb20e5c68d086a97fae5fa9f6bb348a
+ Added "task color" command.
+ Removed unnecessary files.
+ Completed documentation.
0.9.7 (5/24/2008)
+ Migrated old compiler flags into Makefile.am
+ Added ncurses endwin function check to configure.ac
0.9.7 (5/24/2008) 25dc4150947a3e612c8118838d04b3bbe68441f7
+ Migrated old compiler flags into Makefile.am.
+ Added ncurses endwin function check to configure.ac.
+ Set up structure for AUTHORS file.
+ Set up NEWS file, with pleas for feedback.
+ Added welcome message to README.
@@ -161,31 +238,31 @@
+ Removed unnecessary SAMPLE_taskrc, and assorted references.
+ Cleaned up ChangeLog.
+ Minor mods to standard docs.
+ Bumped version to 0.9.7
+ Changed some autoconf details
+ Corrected comment in T.cpp
+ Bumped version to 0.9.7.
+ Changed some autoconf details.
+ Corrected comment in T.cpp.
+ Made unit tests compile and run again.
+ Removed tests from distibution.
0.9.6 (5/13/208)
+ Corrected wrong include file in Table.cpp
+ Corrected wrong include file in Table.cpp.
+ Replaced color management code.
+ Improved color rules code.
0.9.5 (5/12/2008)
+ Replaced Table storage with Grid.
+ Added Grid.cpp to configure.ac
+ Added Makefile to src/.gitignore
+ Added Grid.cpp to configure.ac.
+ Added Makefile to src/.gitignore.
+ Makefile should not be part of the repository.
+ Added Grid.cpp
+ Added Grid::Cell::operator==
+ Added Grid.cpp.
+ Added Grid::Cell::operator==.
+ ChangeLog file begun.
+ Bumped version to 0.9.5 for next release.
0.9.4 (4/26/2008)
+ Integrated new Grid object into build - not yet integrated into Table.
+ More .gitignore tweaks.
+ Added .gitignore
+ Added .gitignore.
+ Added more missing files.
+ Added all source code.
+ Generic OSS files added.
@@ -206,29 +283,29 @@
+ Consolidated header files, removed unnecessary ones.
0.9.0 (3/23/2008)
+ flat source directory
+ autoconf complete
+ "task next"
+ "task stats"
+ "task export"
+ Rules-based colorization
+ flat source directory.
+ autoconf complete.
+ "task next".
+ "task stats".
+ "task export".
+ Rules-based colorization.
0.8.1 (1/28/2008) - 0.8.16 (3/13/2008)
+ autoconf conversion (many builds)
+ autoconf conversion (many builds).
0.8.0 Polish (1/25/2008)
+ Code cleanup, reorganization
+ "task overdue"
+ Add "age" column to list and long
+ Use 'conf' for build, version tracking
+ Add "/from/to/" description editing
+ Code cleanup, reorganization.
+ "task overdue".
+ Add "age" column to list and long.
+ Use 'conf' for build, version tracking.
+ Add "/from/to/" description editing.
0.7.0 Multi-user, File handling, atomicity (1/8/2008)
+ Clean, publishable API reimplementation
+ File locking
+ retain deleted tasks
+ "task info ID" report showing all metadata
+ File format v2, including UUID
+ Clean, publishable API reimplementation.
+ File locking.
+ retain deleted tasks.
+ "task info ID" report showing all metadata.
+ File format v2, including UUID.
[Development hiatus while planning for T, TDB API, new features and the future
of the project. Seeded to two testers for feedback, suggestions. Development
@@ -236,40 +313,40 @@ deliberately stopped to allow extended use of task, allowing command logging and
regular usage to determine which features were needed or unnecessary.]
0.6.0 Reports (12/27/2006)
+ "task history"
+ "task summary"
+ "task calendar"
+ due support
+ Table sorting
+ "task history".
+ "task summary".
+ "task calendar".
+ due support.
+ Table sorting.
0.5.0 Multi-user support (12/10/2006)
+ Command logging
+ "task usage" report
+ Command logging.
+ "task usage" report.
0.4.0 Destructive / modification commands (12/3/2006)
+ "task delete" complete
+ "task id ..." complete
+ "task list ..." synonym for "task find ..."
+ "task delete" complete.
+ "task id ..." complete.
+ "task list ..." synonym for "task find ...".
0.3.0 Work in progress support (12/3/2006)
+ "task start" complete
+ "task done" complete
+ completed.data support
+ "task start" complete.
+ "task done" complete.
+ completed.data support.
0.2.0 Neutral commands (12/2/2006)
+ "task find" complete
+ "task projects" complete
+ "task tags" complete
+ "task find" complete.
+ "task projects" complete.
+ "task tags" complete.
0.1.0 Constructive commands (12/1/2006)
+ "task add" complete
+ completed.data support
+ ~/.taskrc support
+ "task add" complete.
+ completed.data support.
+ ~/.taskrc support.
0.0.1 Basic infrastructure (11/29/2006)
+ Command line parsing
+ API layer
+ Usage
+ Command line parsing.
+ API layer.
+ Usage.
------ start -----------------------------------

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.1.
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
- Fedora Core 8
- Fedora Core 9
- Fedora Core 10
- Ubuntu 7 Feisty Fawn
- Ubuntu 8 Hardy Heron
- Ubuntu 9 Feisty Fawn
- Ubuntu 8.10 Intrepid Ibex
- Ubuntu 9.04 Jaunty Jackalope
- Solaris 10
- Cygwin 1.5.25-14

View File

@@ -2,8 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61)
AC_INIT(task, 1.5.0, bugs@beckingham.net)
AC_INIT(task, 1.6.1, bugs@beckingham.net)
CFLAGS="${CFLAGS=}"
CXXFLAGS="${CXXFLAGS=}"
@@ -15,16 +14,23 @@ debug_default="yes"
AC_ARG_ENABLE(debug, [ --enable-debug=[no/yes] turn on debugging
[default=$debug_default]],, enable_debug=$debug_default)
# Yes, shell scripts can be used
if test "x$enable_debug" = "xyes"; then
CFLAGS="$CFLAGS -Wall -pedantic -ggdb3 -DDEBUG"
CXXFLAGS="$CFLAGS -Wall -pedantic -ggdb3 -DDEBUG"
AC_MSG_RESULT(yes)
if test "$enable_debug" = "yes"; then
CXXFLAGS="$CFLAGS -Wall -pedantic -ggdb3 -DDEBUG"
AC_MSG_RESULT(yes)
else
CFLAGS="$CFLAGS -O3"
CXXFLAGS="$CFLAGS -O3"
AC_MSG_RESULT(no)
CXXFLAGS="$CFLAGS -Wall -pedantic -O3"
AC_MSG_RESULT(no)
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
AC_CONFIG_SRCDIR([src/task.cpp])
@@ -39,7 +45,6 @@ AC_SUBST(CFLAGS)
# Checks for libraries.
AC_CHECK_LIB(ncurses,initscr)
AC_CHECK_LIB(ncurses,endwin)
# Checks for header files.
AC_HEADER_STDC
@@ -58,10 +63,11 @@ AC_STRUCT_TM
AC_FUNC_MKTIME
AC_FUNC_SELECT_ARGTYPES
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(random, [AC_DEFINE([HAVE_RANDOM], [1], [Found random])])
AC_CHECK_FUNC(srandom, [AC_DEFINE([HAVE_SRANDOM], [1], [Found srandom])])
AC_CONFIG_FILES([Makefile src/Makefile])
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 />
<div class="content">
<p>
Copyright 2006-2008, P. Beckingham. All rights reserved.
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>

View File

@@ -97,6 +97,30 @@ Car 2 2 wks 25% XXXXXXXXX</code></pre>
indicating that percentage.
</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>
<p>
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.
</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>
<p>
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.
</p>
<strong>% task /from/to/</strong>
<strong>% task &lt;id&gt; /from/to/</strong>
<p>
If a task has been entered with a typo, it can be easily corrected
by this command. For example:
@@ -278,7 +309,20 @@ ID Project Pri Description
...</code></pre>
<p>
This command makes single corrections to a task description.
This command makes a single correction to the first occurrence of
"from" in a task description.
</p>
<p>
If a task is annotated, the annotation can also be modified using
this command.
</p>
<strong>% task &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>
<strong>% task tags</strong>
@@ -398,7 +442,7 @@ on_white on_bright_white</code></pre>
<br />
<div class="content">
<p>
Copyright 2006-2008, P. Beckingham. All rights reserved.
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>

View File

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

View File

@@ -58,6 +58,13 @@
confirmation before deleting a task.
</dd>
<dt>echo.command</dt>
<dd>
May be "yes" or "no", and causes task to display the ID and
description of any task when you run the start, stop, do, undo,
delete and undelete commands. The default value is "yes".
</dd>
<dt>nag</dt>
<dd>
This may be a string of text, or blank. It is used as a prompt
@@ -174,19 +181,9 @@
<dt>monthsperline</dt>
<dd>
Determines how many months the "task calendar" command
renders across the screen. Defaults to 1.
</dd>
<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.
renders across the screen. Defaults to however many will
fit. If more months that will fit are specified, task will
only show as many that will fit.
</dd>
<dt>defaultwidth</dt>
@@ -195,6 +192,14 @@
Defaults to 80.
</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>
<dd>
May be "on" or "off". Determines whether task uses color.
@@ -210,7 +215,8 @@
color.pri.L<br />
color.pri.none<br />
color.active<br />
color.tagged
color.tagged<br />
color.recurring
</dt>
<dd>
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.
</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>
Note that the command:
</p>
@@ -326,13 +369,15 @@ ID Project Pri Description
will display the configuration variables found in the .taskrc file,
and will warn you of any variables that are not recognized.
</p>
</div>
<br />
<br />
<div class="content">
<p>
Copyright 2006-2008, P. Beckingham. All rights reserved.
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</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 />
<div class="content">
<p>
Copyright 2006-2008, P. Beckingham. All rights reserved.
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</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 />
<div class="content">
<p>
Copyright 2006-2008, P. Beckingham. All rights reserved.
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</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...
</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>
November 2008, <a href="http://github.com/pbeckingham/task/tree/master/">Task repository on GitHub</a>
</dt>
@@ -137,7 +163,7 @@
<br />
<div class="content">
<p>
Copyright 2006-2008, P. Beckingham. All rights reserved.
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</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
recurrences of this same task? (y/n) y</code></pre>
<h4>Modification</h4>
<p>
When a recurring task is modified, all the other recurring task instances will
be modified. For example, if you raise the priority of one of the recurring
task instances, all will be modified.
</p>
<h4>Recurrence Periods</h4>
<p>
In the above examples, the recurrence period was specified as "monthly" and
@@ -116,6 +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">Every day, or a number of days</td>
</tr>
<tr>
<td class="table_d">weekdays</td>
<td class="table_d">
Monday, Tuesday, Wednesday, Thursday and Friday,
skipping weekend days
</td>
</tr>
<tr>
<td class="table_d">weekly, 1w, 2w ...</td>
<td class="table_d">Every week, or a number of weeks</td>
@@ -155,7 +169,7 @@ recurrences of this same task? (y/n) y</code></pre>
<br />
<div class="content">
<p>
Copyright 2006-2008, P. Beckingham. All rights reserved.
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>

View File

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

View File

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

View File

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

View File

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

View File

@@ -57,6 +57,9 @@
<li><a href="versions.html">Old Versions</a>
<li><a href="filter.html">Filters</a>
<li><a href="shadow.html">Shadow Files</a>
<li><a href="custom.html">Custom Reports</a>
<li><a href="import.html">Data Import</a>
<li><a href="faq.html">Frequently Asked Questions</a>
</ul>
<p>
@@ -70,61 +73,94 @@
</p>
<br />
<h2 class="title">Get the Latest Release</h2>
<h2 class="title">Get the Latest Stable Release</h2>
<div class="content">
<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>Source:</td>
<td><a href="http://www.beckingham.net/task-1.6.0.tar.gz">task-1.6.0.tar.gz</a></td>
</tr>
<tr>
<td>Mac OS X 10.5 (Leopard) Intel-only:</td>
<td><a href="http://www.beckingham.net/task-1.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>
<td>
Debian package:
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>):
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>
<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.FC10.i386.rpm">task-1.6.0-1.FC10.i386.rpm</a></td>
</tr>
-->
<tr>
<td>Git - get the whole source and history:</td>
<td><a href="http://github.com/pbeckingham/task">http://github.com/pbeckingham/task</a></td>
</tr>
</table>
<h4>New in version 1.5.0 (?)</h4>
<h4>New in version 1.6.1 (4/22/2009)</h4>
<ul>
<li>Removed deprecated TUTORIAL file.
<li>Removed support for the "showage" configuration variable.
<li>"task stop" can remove the start time from a started task.
<li>"task ghistory" now displays a differently aligned graph, allowing
easier comparison by month of tasks added versus completed and deleted.
<li>"task version" command now reports unrecognized configuration variables,
which may be spelling mistakes or deprecated variables.
<li>"configure --enable-debug" now supported to suppress compiler optimization
to allow debugging.
<li>Fixed bug that caused new, first-time .taskrc files to be written without
including the custom report labels (thanks to P.C. Shyamshankar).
</ul>
<p>
(Find out <a href="versions.html">what was new in prior versions</a>)
</p>
<!--
<h2>Task 1.6.1 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.1beta.tar.gz">task-1.6.1beta.tar.gz</a></td>
</tr>
</table>
-->
<h2>Troubleshooting</h2>
<p>
Task has been built from source and tested in the following environments:
</p>
<ul>
<li>OS X 10.4 Tiger
<li>OS X 10.5 Leopard
<li>Fedora Core 8
<li>Fedora Core 9
<li>Ubuntu 7 Feisty Fawn
<li>Ubuntu 8 Hardy Heron
<li>Solaris 10
<li>Cygwin 1.5.25-14
</ul>
<p>
<ul>
<li>OS X 10.4 Tiger
<li>OS X 10.5 Leopard
<li>Fedora Core 8
<li>Fedora Core 9
<li>Fedora Core 10
<li>Ubuntu 7 Feisty Fawn
<li>Ubuntu 8 Hardy Heron
<li>Ubuntu 8.10 Intrepid Ibex
<li>Ubuntu 9.04 Jaunty Jackalope
<li>Solaris 10
<li>Cygwin 1.5.25-14
</ul>
</p>
<p>
If you have difficulties building task, have found a bug, have a
@@ -143,7 +179,7 @@
<br />
<div class="content">
<p>
Copyright 2006-2008, P. Beckingham. All rights reserved.
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>

View File

@@ -83,11 +83,29 @@
</p>
</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 />
<div class="content">
<p>
Copyright 2006-2008, P. Beckingham. All rights reserved.
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</div>

View File

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

View File

@@ -36,6 +36,153 @@
<br />
<div class="content">
<h4>New in version 1.6.0 (4/13/2009)</h4>
<p>
<table>
<tr>
<td>Source:</td>
<td><a href="http://www.beckingham.net/task-1.6.0.tar.gz">task-1.6.0.tar.gz</a></td>
</tr>
<!--
<tr>
<td>Mac OS X 10.5 (Leopard) Intel-only:</td>
<td><a href="http://www.beckingham.net/task-1.6.0.pkg">task-1.6.0.pkg</a></td>
</tr>
<tr>
<td>
Debian:
(Thanks to <a href="http://blog.rfquerin.org">Richard&nbsp;Querin</a>):
</td>
<td><a href="http://www.beckingham.net/task_1.6.0-1_i386.deb">task_1.6.0-1_i386.deb</a></td>
</tr>
-->
<tr>
<td>
Red Hat:
(Thanks to <a href="http://www.ultrafredde.com">Federico&nbsp;Hernandez</a>):
</td>
<td><a href="http://www.beckingham.net/task-1.6.0-1.FC10.i386.rpm">task-1.6.0-1.FC10.i386.rpm</a></td>
</tr>
<tr>
<td>Git - get the whole source and history:</td>
<td><a href="http://github.com/pbeckingham/task">http://github.com/pbeckingham/task</a></td>
</tr>
</table>
<ul>
<li>Added support for new "append" command that adds more description text to
an existing task.
<li>Added support for the "weekdays" recurrence, which means a task can recur
five times a week, and not on weekends (thanks to Chris Pride).
<li>UTF8 text is now supported in task project names, tags and descriptions.
<li>Fixed bug that caused the y/n confirmation on task deletion to ignore the
Enter key and fail to re-prompt (thanks to Bruce Dillahunty).
<li>When the "echo.command" configuration variable is set to "yes", it causes
commands that modify tasks to display which task was affected (thanks to
Bruce Dillahunty).
<li>A task can now be annotated with the command "task <id> annotate ...", and
a timestamped annotation will appear in reports.
<li>A 'description_only' column is now available for use in custom reports,
and it excludes annotations.
<li>A task can now be upgraded to a recurring task by adding a recurrence
frequency, a due date, and an optional until date.
<li>When a recurring task is modified, all other instances of the recurring
task are also modified.
<li>Custom reports now support user-specified column labels (thanks to T.
Charles Yun).
<li>Task can now import tasks from a variety of data formats, including task
export files from versions 1.4.3 and earlier, versions 1.5.0 and later,
todo.sh 2.x, CSV, plain text and task command line. See online docs for
full details.
<li>Export was including 'id' in the column header even though it was not
included in the data.
<li>The task file format has changed slightly. Please back up your task
data files before upgrading to 1.6.0.
<li>Added new column 'recurrence_indicator' that displays an 'R' if the task
is a recurring task. This column can be added to any custom report.
<li>Added new column 'tag_indicator' that displays a '+' if the task
has any tags. This column can be added to any custom report.
<li>Fixed bug where sometimes a task description was concatenated oddly if
there was a colon somewhere in the description.
<li>Fixed bug that caused recurring annual tasks to exhibit a creeping due
date, because of an assumption of 365 days per year, which failed to
consider leap years (thanks to T. Charles Yun).
<li>Annotations can now be modified with the substitution commands /from/to/.
<li>Substitutions can now be made global with /from/to/g and all occurrences
of "from" will be replaced with "to".
</ul>
</p>
<p>
<h4>New in version 1.5.0 (3/15/2009)</h4>
<table>
<tr>
<td>Source:</td>
<td><a href="http://www.beckingham.net/task-1.5.0.tar.gz">task-1.5.0.tar.gz</a></td>
</tr>
<tr>
<td>Mac OS X 10.5 (Leopard) Intel-only:</td>
<td><a href="http://www.beckingham.net/task-1.5.0.pkg">task-1.5.0.pkg</a></td>
</tr>
<tr>
<td>
Debian:
(Thanks to <a href="http://blog.rfquerin.org">Richard&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>
<h4>New in version 1.4.3 (11/1/2008)</h4>
<a href="http://www.beckingham.net/task-1.4.3.tar.gz">task-1.4.3.tar.gz</a>
@@ -47,6 +194,7 @@
(Thanks to <a href="http://blog.rfquerin.org">Richard Querin</a>)
</p>
<p>
<ul>
<li>Fixed misleading task count at bottom of "info" report.
<li>Added support for a shadow file that contains a plain text task report,
@@ -250,7 +398,7 @@
<br />
<div class="content">
<p>
Copyright 2006-2008, P. Beckingham. All rights reserved.
Copyright 2006-2009, P. Beckingham. All rights reserved.
</p>
</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
I need to do laundry
task add do laundry Let's add some tasks
I need to do laundry
task add project:garage order dumpster Oh yeah, 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
useful for searching, categorizing)
task add +phone tell mom i loveher Must call Mom (that "phone" there is a tag - they can
be useful for searching and categorizing)
task add +phone pro:garage schedule
goodwill pickup
task ad +email pro:garage ask Tom if Notice I can abbreviating commands
task ad +email pro:garage ask Tom if Notice I can abbreviate commands
he wants that old bkie
task ls Let's see what we've got
I spelled bike wrong
task ls Let's see what we've got
Oh, I spelled bike wrong
task 5 /bkie/bike/
task ls That's better
task ls That's better
task 1 pro:home Let's assign projects
task 1 pro:home Let's assign projects
task 3 pro:home tell mom I love her
task ls pro:garage
task long pro:garage Let's see all the columns
task long pro:garage Let's see all the columns
task list pro:garage There are different ways to list
task list pro:garage There are different ways to list
task lis +phone By tag
task li pro:garage +phone By project and tag
task l mom By word
task lis +phone By tag
task li pro:garage +phone By project and tag
task l mom By word
task 1 priority:H Priorities can be High, Medium or Low
task 1 priority:H Priorities can be High, Medium or Low
task pri:H 3
task 1 pri:M
task li The list is sorted by priority.
task li The list is sorted by priority.
task 2 pri:L
task li
task done 3 Suppose task 3 is done
task li ...and it's gone
task done 3 Suppose task 3 is done
task li ...and it's gone
task 2 +phone +mistake Lets add tags
task 2 +phone +mistake Lets add tags
# Oops!
task 2 -mistake or remove tags
task 2 -mistake or remove tags
task tags or look at all the tags
task tags or look at all the tags
task info 2 or all the details
task info 2 or all the details
task projects or all the projects
task projects or all the projects
task 3 fg:bold Let's make it colorful
task 3 fg:bold Let's make it colorful
task 4 fg:bold_green
task li
task 3 fg:bold_underline_white
task li
task 4 bg:on_bright_red fg:bold_yellow
task li Oh that's just nasty - let's get rid of that.
task li Oh that's just nasty - let's get rid of that.
task 4 bg:
task li
task 4 fg:
task 3 fg:
task colors There are many combinations to choose from
task colors There are many combinations to choose from
(Slashes!!!)
task 1 due:6/8/2008 Let's add a due date
task 1 due:6/8/2008 Let's add a due date
date
task li
task calendar Notice the due task is in yellow, today is marked cyan
task calendar Notice the due task is in yellow, today is marked cyan
task 1 due:5/20/2008 This is now an overdue task
task li and it shows up red
task 1 due:5/20/2008 This is now an overdue task
task li and it shows up red
task overdue
task cal
task export file.csv You can export the tasks to a spreadsheet
task export file.csv You can export the tasks to a spreadsheet
cat file.csv
task start 1 Started tasks can be used as reminders
of what you are supposed to be doing
task start 1 Started tasks can be used as reminders
of what you are supposed to be doing
task active They show up as active
task done 1 Let's clear out a couple
task active They show up as active
task done 1 Let's clear out a couple
task li
task done 3
task active
task summary Summary shows progress on all projects
task summary Summary shows progress on all projects
task history History shows general activity - how many added,
completed etc, by month
task history History shows general activity - how many added,
completed etc, by month
And that's it. There are more commands than this
covered in the online documentation, but this should give
the basic idea.
task ghistory This report shows a histogram of tasks that were
added (in red), completed (in green) and deleted
(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.
//
// Copyright 2006 - 2008, Paul Beckingham.
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
@@ -36,8 +36,40 @@
#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 ()
{
(*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
// is simply lines with name=value pairs. Whitespace between name, = and value
// is not tolerated, but blank lines and comments starting with # are allowed.
// Read the Configuration file and populate the *this map. The file format is
// simply lines with name=value pairs. Whitespace between name, = and value is
// not tolerated, but blank lines and comments starting with # are allowed.
bool Config::load (const std::string& file)
{
std::ifstream in;
@@ -113,26 +145,69 @@ void Config::createDefault (const std::string& home)
{
fprintf (out, "data.location=%s\n", dataDir.c_str ());
fprintf (out, "confirmation=yes\n");
fprintf (out, "echo.command=yes\n");
fprintf (out, "next=2\n");
fprintf (out, "dateformat=m/d/Y\n");
fprintf (out, "monthsperline=1\n");
fprintf (out, "#monthsperline=2\n");
fprintf (out, "curses=on\n");
fprintf (out, "color=on\n");
fprintf (out, "due=7\n");
fprintf (out, "nag=You have higher priority tasks.\n");
fprintf (out, "locking=on\n");
fprintf (out, "color.overdue=bold_red\n");
fprintf (out, "#color.due=on_bright_yellow\n");
fprintf (out, "#color.pri.H=on_red\n");
fprintf (out, "color.due=bold_yellow\n");
fprintf (out, "color.pri.H=bold\n");
fprintf (out, "#color.pri.M=on_yellow\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.tagged=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.recurring=on_red\n");
fprintf (out, "#shadow.file=%s/shadow.txt\n", dataDir.c_str ());
fprintf (out, "#shadow.command=list\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.labels=ID,Project,Pri,Added,Started,Due,Recur,Age,Tags,Description\n");
fprintf (out, "report.long.columns=id,project,priority,entry,start,due,recur,age,tags,description\n");
fprintf (out, "report.long.sort=due+,priority-,project+\n");
fprintf (out, "report.list.description=Lists all tasks matching the specified criteria\n");
fprintf (out, "report.list.labels=ID,Project,Pri,Due,Active,Age,Description\n");
fprintf (out, "report.list.columns=id,project,priority,due,active,age,description\n");
fprintf (out, "report.list.sort=due+,priority-,project+\n");
fprintf (out, "report.ls.description=Minimal listing of all tasks matching the specified criteria\n");
fprintf (out, "report.ls.labels=ID,Project,Pri,Description\n");
fprintf (out, "report.ls.columns=id,project,priority,description\n");
fprintf (out, "report.ls.sort=priority-,project+\n");
fprintf (out, "report.newest.description=Shows the newest tasks\n");
fprintf (out, "report.newest.labels=ID,Project,Pri,Due,Active,Age,Description\n");
fprintf (out, "report.newest.columns=id,project,priority,due,active,age,description\n");
fprintf (out, "report.newest.sort=id-\n");
fprintf (out, "report.newest.limit=10\n");
fprintf (out, "report.oldest.description=Shows the oldest tasks\n");
fprintf (out, "report.oldest.labels=ID,Project,Pri,Due,Active,Age,Description\n");
fprintf (out, "report.oldest.columns=id,project,priority,due,active,age,description\n");
fprintf (out, "report.oldest.sort=id+\n");
fprintf (out, "report.oldest.limit=10\n");
fclose (out);
@@ -191,11 +266,13 @@ bool Config::get (const std::string& key, bool default_value)
{
std::string value = lowerCase ((*this)[key]);
if (value == "t" ||
value == "true" ||
value == "1" ||
value == "yes" ||
value == "on")
if (value == "t" ||
value == "true" ||
value == "1" ||
value == "yes" ||
value == "on" ||
value == "enable" ||
value == "enabled")
return true;
return false;

View File

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

View File

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

View File

@@ -1,2 +1,2 @@
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)
PROGRAMS = $(bin_PROGRAMS)
am_task_OBJECTS = Config.$(OBJEXT) Date.$(OBJEXT) T.$(OBJEXT) \
TDB.$(OBJEXT) Table.$(OBJEXT) Grid.$(OBJEXT) color.$(OBJEXT) \
parse.$(OBJEXT) task.$(OBJEXT) command.$(OBJEXT) \
report.$(OBJEXT) util.$(OBJEXT) text.$(OBJEXT) rules.$(OBJEXT)
TDB.$(OBJEXT) Table.$(OBJEXT) Grid.$(OBJEXT) Timer.$(OBJEXT) \
color.$(OBJEXT) parse.$(OBJEXT) task.$(OBJEXT) \
command.$(OBJEXT) report.$(OBJEXT) util.$(OBJEXT) \
text.$(OBJEXT) rules.$(OBJEXT) import.$(OBJEXT)
task_OBJECTS = $(am_task_OBJECTS)
task_LDADD = $(LDADD)
DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@
@@ -154,7 +155,7 @@ sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_builddir = @top_builddir@
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
.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)/TDB.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)/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)/report.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.
//
// Copyright 2006 - 2008, Paul Beckingham.
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
@@ -25,6 +25,7 @@
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <sstream>
#include <algorithm>
#include "task.h"
#include "T.h"
@@ -39,6 +40,10 @@ T::T ()
mTags.clear ();
mAttributes.clear ();
mDescription = "";
mFrom = "";
mTo = "";
mGlobal = false;
mAnnotations.clear ();
}
////////////////////////////////////////////////////////////////////////////////
@@ -58,6 +63,7 @@ T::T (const T& other)
mTags = other.mTags;
mRemoveTags = other.mRemoveTags;
mAttributes = other.mAttributes;
mAnnotations = other.mAnnotations;
}
////////////////////////////////////////////////////////////////////////////////
@@ -72,6 +78,7 @@ T& T::operator= (const T& other)
mTags = other.mTags;
mRemoveTags = other.mRemoveTags;
mAttributes = other.mAttributes;
mAnnotations = other.mAnnotations;
}
return *this;
@@ -109,6 +116,12 @@ void T::addRemoveTag (const std::string& tag)
mRemoveTags.push_back (tag);
}
////////////////////////////////////////////////////////////////////////////////
int T::getTagCount () const
{
return mTags.size ();
}
////////////////////////////////////////////////////////////////////////////////
void T::getTags (std::vector<std::string>& all) const
{
@@ -230,21 +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;
to = mTo;
from = mFrom;
to = mTo;
global = mGlobal;
}
////////////////////////////////////////////////////////////////////////////////
void T::setSubstitution (const std::string& from, const std::string& to)
void T::setSubstitution (
const std::string& from,
const std::string& to,
bool global)
{
mFrom = from;
mTo = to;
mFrom = from;
mTo = to;
mGlobal = global;
}
////////////////////////////////////////////////////////////////////////////////
// uuid status [tags] [attributes] description
void T::getAnnotations (std::map <time_t, std::string>& all) const
{
all = mAnnotations;
}
////////////////////////////////////////////////////////////////////////////////
void T::setAnnotations (const std::map <time_t, std::string>& all)
{
mAnnotations = all;
}
////////////////////////////////////////////////////////////////////////////////
void T::addAnnotation (const std::string& description)
{
std::string sanitized = description;
std::replace (sanitized.begin (), sanitized.end (), '"', '\'');
std::replace (sanitized.begin (), sanitized.end (), '[', '(');
std::replace (sanitized.begin (), sanitized.end (), ']', ')');
mAnnotations[time (NULL)] = sanitized;
}
////////////////////////////////////////////////////////////////////////////////
// uuid status [tags] [attributes] [annotations] description
//
// uuid \x{8}-\x{4}-\x{4}-\x{4}-\x{12}
// status - + X r
@@ -282,10 +325,26 @@ const std::string T::compose () const
++count;
}
line += "] ";
line += "] [";
// Annotations
std::stringstream annotation;
bool first = true;
foreach (note, mAnnotations)
{
if (first)
first = false;
else
annotation << " ";
annotation << note->first << ":\"" << note->second << "\"";
}
line += annotation.str () + "] ";
// Description
line += mDescription;
// EOL
line += "\n";
if (line.length () > T_LINE_MAX)
@@ -328,6 +387,11 @@ const std::string T::composeCSV ()
line += value;
line += ",";
value = mAttributes["recur"];
if (value != "")
line += value;
line += ",";
value = mAttributes["end"];
if (value != "")
line += value;
@@ -353,7 +417,11 @@ const std::string T::composeCSV ()
line += "'" + value + "'";
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;
}
@@ -412,10 +480,12 @@ void T::parse (const std::string& line)
}
else
throw std::string ("Line too short");
mAnnotations.clear ();
}
break;
// File format version 2, from 2008.1.1
// File format version 2, from 2008.1.1 - 2009.3.23
case 2:
{
if (line.length () > 46) // ^.{36} . \[\] \[\] \n
@@ -437,24 +507,122 @@ void T::parse (const std::string& line)
if (openAttrBracket != std::string::npos &&
closeAttrBracket != std::string::npos)
{
std::string tags = line.substr (
openTagBracket + 1, closeTagBracket - openTagBracket - 1);
std::vector <std::string> rawTags;
split (mTags, tags, ' ');
std::string tags = line.substr (
openTagBracket + 1, closeTagBracket - openTagBracket - 1);
std::vector <std::string> rawTags;
split (mTags, tags, ' ');
std::string attributes = line.substr (
openAttrBracket + 1, closeAttrBracket - openAttrBracket - 1);
std::vector <std::string> pairs;
split (pairs, attributes, ' ');
for (size_t i = 0; i < pairs.size (); ++i)
{
std::vector <std::string> pair;
split (pair, pairs[i], ':');
if (pair.size () == 2)
mAttributes[pair[0]] = pair[1];
}
std::string attributes = line.substr (
openAttrBracket + 1, closeAttrBracket - openAttrBracket - 1);
std::vector <std::string> pairs;
split (pairs, attributes, ' ');
for (size_t i = 0; i < pairs.size (); ++i)
{
std::vector <std::string> pair;
split (pair, pairs[i], ':');
if (pair.size () == 2)
mAttributes[pair[0]] = pair[1];
}
mDescription = line.substr (closeAttrBracket + 2, std::string::npos);
mDescription = line.substr (closeAttrBracket + 2, std::string::npos);
}
else
throw std::string ("Missing attribute brackets");
}
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
throw std::string ("Missing attribute brackets");
@@ -468,7 +636,7 @@ void T::parse (const std::string& line)
break;
default:
throw std::string ();
throw std::string ("Unrecognized task file format.");
break;
}
}
@@ -503,16 +671,31 @@ int T::determineVersion (const std::string& line)
line[23] == '-' &&
line[36] == ' ' &&
(line[37] == '-' || line[37] == '+' || line[37] == 'X' || line[37] == 'r'))
return 2;
{
// Version 3 looks like:
//
// uuid status [tags] [attributes] [annotations] description\n
//
// Scan for the number of [] pairs.
std::string::size_type tagAtts = line.find ("] [", 0);
std::string::size_type attsAnno = line.find ("] [", tagAtts + 1);
std::string::size_type annoDesc = line.find ("] ", attsAnno + 1);
if (tagAtts != std::string::npos &&
attsAnno != std::string::npos &&
annoDesc != std::string::npos)
return 3;
else
return 2;
}
// Version 3?
// Version 4?
//
// Fortunately, with the hindsight that will come with version 3, the
// identifying characteristics of 1 and 2 may be modified such that if 3 has
// a UUID followed by a status, then there is still a way to differentiate
// between 2 and 3.
// Fortunately, with the hindsight that will come with version 4, the
// identifying characteristics of 1, 2 and 3 may be modified such that if 4
// has a UUID followed by a status, then there is still a way to differentiate
// between 2, 3 and 4.
//
// The danger is that a version 2 binary reads and misinterprets a version 3
// The danger is that a version 3 binary reads and misinterprets a version 4
// file. This is why it is a good idea to rely on an explicit version
// declaration rather than chance positioning.
@@ -525,6 +708,7 @@ int T::determineVersion (const std::string& line)
bool T::validate () const
{
// TODO Verify until > due
// TODO Verify entry < until, due, start, end
return true;
}

15
src/T.h
View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2008, Paul Beckingham.
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// 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)
{
int length = 0;
unsigned int length = 0;
if (mSuppressWS)
{
@@ -238,7 +238,19 @@ void Table::addCell (const int row, const int col, const std::string& data)
data2 = data;
clean (data2);
length = data2.length ();
// For multi-line cells, find the longest line.
if (data2.find ("\n") != std::string::npos)
{
length = 0;
std::vector <std::string> lines;
split (lines, data2, "\n");
for (unsigned int i = 0; i < lines.size (); ++i)
if (lines[i].length () > length)
length = lines[i].length ();
}
else
length = data2.length ();
mData.add (row, col, data2);
}
else
@@ -248,11 +260,22 @@ void Table::addCell (const int row, const int col, const std::string& data)
else
mData.add (row, col, data);
length = data.length ();
// For multi-line cells, find the longest line.
if (data.find ("\n") != std::string::npos)
{
length = 0;
std::vector <std::string> lines;
split (lines, data, "\n");
for (unsigned int i = 0; i < lines.size (); ++i)
if (lines[i].length () > length)
length = lines[i].length ();
}
else
length = data.length ();
}
// Automatically maintain max width.
mMaxDataWidth[col] = max (mMaxDataWidth[col], length);
mMaxDataWidth[col] = max (mMaxDataWidth[col], (int)length);
}
////////////////////////////////////////////////////////////////////////////////
@@ -508,9 +531,7 @@ void Table::calculateColumnWidths ()
}
else
{
// std::cout << "# insufficient room, considering only flexible columns." << std::endl;
// The fallback position is to assume no width was specificed, and just
// The fallback position is to assume no width was specified, and just
// calculate widths accordingly.
mTableWidth = 0;
calculateColumnWidths ();
@@ -736,34 +757,84 @@ int Table::columnCount ()
////////////////////////////////////////////////////////////////////////////////
// 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:
// ^[[31mName^[[0m ^[[31mValue^[[0m -> ^[[31mName Value^[[0m
//
// This method is a work in progress.
void Table::optimize (std::string& output)
void Table::optimize (std::string& output) const
{
/*
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);
}
// int start = output.length ();
/*
std::cout << int ((100 * (start - output.length ()) / start))
<< "%" << std::endl;
Well, how about that!
The benchmark.t unit test adds a 1000 tasks, fiddles with some of them, then
runs a series of reports. The results are timed, and look like this:
1000 tasks added in 3 seconds
600 tasks altered in 32 seconds
'task ls' in 26 seconds
'task list' in 17 seconds
'task list pri:H' in 19 seconds
'task list +tag' in 0 seconds
'task list project_A' in 0 seconds
'task long' in 29 seconds
'task completed' in 2 seconds
'task history' in 0 seconds
'task ghistory' in 0 seconds
This performance is terrible. To identify the worst offender, Various Timer
objects were added in Table::render, assuming that table sorting is the major
bottleneck. But no, it is Table::optimize that is the problem. After
commenting out this method, the results are now:
1000 tasks added in 3 seconds
600 tasks altered in 29 seconds
'task ls' in 0 seconds
'task list' in 0 seconds
'task list pri:H' in 1 seconds
'task list +tag' in 0 seconds
'task list project_A' in 0 seconds
'task long' in 0 seconds
'task completed' in 0 seconds
'task history' in 0 seconds
'task ghistory' in 0 seconds
Much better.
*/
// std::cout << int ((100 * (start - output.length ()) / start))
// << "%" << std::endl;
}
////////////////////////////////////////////////////////////////////////////////
// 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 \
{ \
int temp = order[r]; \
@@ -776,7 +847,7 @@ void Table::sort (std::vector <int>& order)
int gap = order.size ();
int swaps = 1;
while (gap > 1 || swaps != 0)
while (gap > 1 || swaps > 0)
{
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* 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]])
{
@@ -861,24 +950,38 @@ void Table::sort (std::vector <int>& order)
break;
case ascendingPriority:
if (((std::string)*left == "" && (std::string)*right != "") ||
((std::string)*left == "M" && (std::string)*right == "L") ||
((std::string)*left == "H" && ((std::string)*right == "L" || (std::string)*right == "M")))
if (((std::string)*left == "" && (std::string)*right != "") ||
((std::string)*left == "M" && (std::string)*right == "L") ||
((std::string)*left == "H" && ((std::string)*right == "L" || (std::string)*right == "M")))
SWAP
break;
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 == "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
break;
}
break;
}
else
keepScanning = true;
}
++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 ();
@@ -946,8 +1049,14 @@ const std::string Table::render ()
if (mSortColumns.size ())
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.
for (int row = 0; row < mRows; ++row)
for (int row = 0; row < limit; ++row)
{
std::vector <std::vector <std::string> > columns;
std::vector <std::string> blanks;
@@ -981,15 +1090,19 @@ const std::string Table::render ()
else
output += blanks[col];
// Trim right.
output.erase (output.find_last_not_of (" ") + 1);
output += "\n";
}
}
else
{
// Trim right.
output.erase (output.find_last_not_of (" ") + 1);
output += "\n";
}
}
// Eliminate redundant color codes.
optimize (output);
return output;
}

View File

@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2008, Paul Beckingham.
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
@@ -37,9 +37,16 @@ class Table
{
public:
enum just {left, center, right};
enum order {ascendingNumeric, ascendingCharacter, ascendingPriority,
ascendingDate, descendingNumeric, descendingCharacter,
descendingPriority, descendingDate};
enum order {ascendingNumeric,
ascendingCharacter,
ascendingPriority,
ascendingDate,
ascendingPeriod,
descendingNumeric,
descendingCharacter,
descendingPriority,
descendingDate,
descendingPeriod};
enum sizing {minimum = -1, flexible = 0};
Table ();
@@ -84,7 +91,7 @@ public:
int rowCount ();
int columnCount ();
const std::string render ();
const std::string render (int maximum = 0);
private:
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 formatHeaderDashedUnderline (const int, const int, const int);
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 clean (std::string&);
void optimize (std::string&) const;
private:
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.
//
// Copyright 2006 - 2008, Paul Beckingham.
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// 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.
//
// Copyright 2006 - 2008, Paul Beckingham.
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// 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.
//
// Copyright 2006 - 2008, Paul Beckingham.
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
@@ -48,8 +48,10 @@
#endif
////////////////////////////////////////////////////////////////////////////////
void handleAdd (TDB& tdb, T& task, Config& conf)
std::string handleAdd (TDB& tdb, T& task, Config& conf)
{
std::stringstream out;
char entryTime[16];
sprintf (entryTime, "%u", (unsigned int) time (NULL));
task.setAttribute ("entry", entryTime);
@@ -86,6 +88,8 @@ void handleAdd (TDB& tdb, T& task, Config& conf)
if (!tdb.addT (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 ("Tasks");
if (conf.get ("color", true))
if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
table.setColumnUnderline (0);
table.setColumnUnderline (1);
@@ -279,7 +283,7 @@ std::string handleVersion (Config& conf)
std::stringstream out;
// Determine window size, and set table accordingly.
int width = conf.get ("defaultwidth", 80);
int width = conf.get ("defaultwidth", (int) 80);
#ifdef HAVE_LIBNCURSES
if (conf.get ("curses", true))
{
@@ -307,7 +311,9 @@ std::string handleVersion (Config& conf)
link.setColumnWidth (0, Table::flexible);
link.setColumnJustification (0, Table::left);
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.
Table table;
@@ -316,7 +322,7 @@ std::string handleVersion (Config& conf)
table.addColumn ("Config variable");
table.addColumn ("Value");
if (conf.get ("color", true))
if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
table.setColumnUnderline (0);
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
<< (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
<< disclaimer.render ()
<< std::endl
@@ -359,10 +369,20 @@ std::string handleVersion (Config& conf)
// These are the regular configuration variables.
std::string recognized =
"blanklines color color.active color.due color.overdue color.pri.H "
"color.pri.L color.pri.M color.pri.none color.tagged confirmation curses "
"data.location dateformat default.command default.priority defaultwidth due "
"monthsperline nag newest next oldest project shadow.command shadow.file "
"shadow.notify";
"color.pri.L color.pri.M color.pri.none color.recurring color.tagged "
"confirmation curses data.location dateformat default.command "
"default.priority defaultwidth due echo.command locking monthsperline nag "
"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;
foreach (i, all)
@@ -417,7 +437,9 @@ std::string handleVersion (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;
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
// itself, and delete them.
foreach (sibling, all)
{
if (sibling->getAttribute ("parent") == parent ||
sibling->getUUID () == parent)
{
tdb.deleteT (*sibling);
return std::string ("");
if (conf.get ("echo.command", true))
out << "Deleting recurring task "
<< sibling->getId ()
<< " "
<< sibling->getDescription ()
<< std::endl;
}
}
}
else
{
@@ -447,20 +477,32 @@ std::string handleDelete (TDB& tdb, T& task, Config& conf)
t->setStatus (T::deleted);
updateRecurrenceMask (tdb, all, *t);
tdb.deleteT (*t);
return std::string ("");
out << "Deleting recurring task "
<< t->getId ()
<< " "
<< t->getDescription ()
<< std::endl;
}
}
else
{
tdb.deleteT (*t);
if (conf.get ("echo.command", true))
out << "Deleting task "
<< t->getId ()
<< " "
<< t->getDescription ()
<< std::endl;
}
break; // No point continuing the loop.
}
}
}
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 ())
{
T original (*it);
std::stringstream out;
if (original.getAttribute ("start") == "")
{
@@ -485,15 +528,20 @@ std::string handleStart (TDB& tdb, T& task, Config& conf)
original.setId (task.getId ());
tdb.modifyT (original);
if (conf.get ("echo.command", true))
out << "Started "
<< original.getId ()
<< " "
<< original.getDescription ()
<< std::endl;
nag (tdb, task, conf);
return std::string ("");
}
else
{
std::stringstream out;
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 ())
{
T original (*it);
std::stringstream out;
if (original.getAttribute ("start") != "")
{
@@ -520,15 +569,15 @@ std::string handleStop (TDB& tdb, T& task, Config& conf)
original.setId (task.getId ());
tdb.modifyT (original);
nag (tdb, task, conf);
return std::string ("");
if (conf.get ("echo.command", true))
out << "Stopped " << original.getId () << " " << original.getDescription () << std::endl;
}
else
{
std::stringstream out;
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))
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 (conf.get ("echo.command", true))
out << "Completed "
<< t->getId ()
<< " "
<< t->getDescription ()
<< std::endl;
t->setStatus (T::completed);
updateRecurrenceMask (tdb, all, *t);
break;
@@ -556,11 +614,14 @@ void handleDone (TDB& tdb, T& task, Config& 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
// file name isn't used for filtering.
std::string file = trim (task.getDescription ());
@@ -578,6 +639,7 @@ void handleExport (TDB& tdb, T& task, Config& conf)
<< "'entry',"
<< "'start',"
<< "'due',"
<< "'recur',"
<< "'end',"
<< "'project',"
<< "'priority',"
@@ -586,32 +648,61 @@ void handleExport (TDB& tdb, T& task, Config& conf)
<< "'description'"
<< "\n";
int count = 0;
std::vector <T> all;
tdb.allT (all);
tdb.allPendingT (all);
filter (all, task);
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 ();
output << count << " tasks exported to '" << file << "'" << std::endl;
}
else
throw std::string ("Could not write to export file.");
}
else
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;
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;
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);
@@ -657,39 +748,192 @@ void handleModify (TDB& tdb, T& task, Config& conf)
if (i->second == "")
original.removeAttribute (i->first);
else
{
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;
}
std::string from;
std::string to;
task.getSubstitution (from, to);
bool global;
task.getSubstitution (from, to, global);
if (from != "")
{
std::string description = original.getDescription ();
size_t pattern = description.find (from);
if (pattern != std::string::npos)
size_t pattern;
if (global)
{
description = description.substr (0, pattern) +
to +
description.substr (pattern + from.length (), std::string::npos);
// Perform all subs on description.
while ((pattern = description.find (from)) != std::string::npos)
{
description.replace (pattern, from.length (), to);
++changes;
}
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)
{
original.setId (task.getId ());
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;
if (conf.get ("color", true))
if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
{
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.
//
// Copyright 2006 - 2008, Paul Beckingham.
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
@@ -120,6 +120,8 @@ static const char* commands[] =
{
"active",
"add",
"append",
"annotate",
"calendar",
"colors",
"completed",
@@ -129,13 +131,9 @@ static const char* commands[] =
"help",
"history",
"ghistory",
"import",
"info",
"list",
"long",
"ls",
"newest",
"next",
"oldest",
"overdue",
"projects",
"start",
@@ -164,7 +162,6 @@ void guess (const std::string& type, const char** list, std::string& candidate)
candidate = matches[0];
else if (0 == matches.size ())
// throw std::string ("Unrecognized ") + type + " '" + candidate + "'";
candidate = "";
else
@@ -194,7 +191,6 @@ void guess (const std::string& type, std::vector<std::string>& options, std::str
candidate = matches[0];
else if (0 == matches.size ())
// throw std::string ("Unrecognized ") + type + " '" + candidate + "'";
candidate = "";
else
@@ -239,7 +235,7 @@ bool validDate (std::string& date, Config& conf)
{
Date test (date, conf.get ("dateformat", "m/d/Y"));
char epoch[12];
char epoch[16];
sprintf (epoch, "%d", (int) test.toEpoch ());
date = epoch;
@@ -352,7 +348,8 @@ static bool validCommand (std::string& input)
static bool validSubstitution (
std::string& input,
std::string& from,
std::string& to)
std::string& to,
bool& global)
{
size_t first = input.find ('/');
if (first != std::string::npos)
@@ -366,10 +363,17 @@ static bool validSubstitution (
if (first == 0 &&
first < second &&
second < third &&
third == input.length () - 1)
(third == input.length () - 1 ||
third == input.length () - 2))
{
from = input.substr (first + 1, second - first - 1);
to = input.substr (second + 1, third - second - 1);
global = false;
if (third == input.length () - 2 &&
input.find ('g', third + 1) != std::string::npos)
global = true;
return true;
}
}
@@ -415,6 +419,7 @@ void parse (
size_t colon; // Pointer to colon in argument.
std::string from;
std::string to;
bool global;
// An id is the first argument found that contains all digits.
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
// the description.
else
{
if (descCandidate.length ())
descCandidate += " ";
descCandidate += arg;
}
}
// Substitution of description text.
else if (validSubstitution (arg, from, to))
else if (validSubstitution (arg, from, to, global))
{
task.setSubstitution (from, to);
task.setSubstitution (from, to, global);
}
// Command.
@@ -463,23 +472,23 @@ void parse (
if (isCommand (l) && validCommand (l))
command = l;
else
{
if (descCandidate.length ())
descCandidate += " ";
descCandidate += arg;
}
}
// Anything else is just considered description.
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))
task.setDescription (descCandidate);
}
@@ -495,7 +504,7 @@ void loadCustomReports (Config& conf)
if (i->substr (0, 7) == "report.")
{
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)
{
report = report.substr (0, columns);
@@ -515,4 +524,10 @@ bool isCustomReport (const std::string& report)
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.
//
// Copyright 2006 - 2008, Paul Beckingham.
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// 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: 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.
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.
std::map <std::string, Text::color>::iterator 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.
//
// Copyright 2006 - 2008, Paul Beckingham.
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
@@ -27,6 +27,7 @@
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
@@ -47,15 +48,11 @@
#endif
////////////////////////////////////////////////////////////////////////////////
// Globals for exclusive use by callback function.
static TDB* gTdb = NULL;
static Config* gConf = NULL;
////////////////////////////////////////////////////////////////////////////////
static void shortUsage (Config& conf)
static std::string shortUsage (Config& conf)
{
std::stringstream out;
Table table;
int width = conf.get ("defaultwidth", 80);
int width = conf.get ("defaultwidth", (int) 80);
#ifdef HAVE_LIBNCURSES
if (conf.get ("curses", true))
{
@@ -88,16 +85,12 @@ static void shortUsage (Config& conf)
table.addCell (row, 2, "Adds a new task");
row = table.addRow ();
table.addCell (row, 1, "task list [tags] [attrs] desc...");
table.addCell (row, 2, "Lists all tasks matching the specified criteria");
table.addCell (row, 1, "task append [tags] [attrs] desc...");
table.addCell (row, 2, "Appends more description to an existing task");
row = table.addRow ();
table.addCell (row, 1, "task long [tags] [attrs] desc...");
table.addCell (row, 2, "Lists all task, all data, matching the specified criteria");
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");
table.addCell (row, 1, "task annotate ID desc...");
table.addCell (row, 2, "Adds an annotation to an existing task");
row = table.addRow ();
table.addCell (row, 1, "task completed [tags] [attrs] desc...");
@@ -109,7 +102,11 @@ static void shortUsage (Config& conf)
row = table.addRow ();
table.addCell (row, 1, "task ID /from/to/");
table.addCell (row, 2, "Perform the substitution on the desc, for fixing mistakes");
table.addCell (row, 2, "Performs one substitution on the task description, for fixing mistakes");
row = table.addRow ();
table.addCell (row, 1, "task ID /from/to/g");
table.addCell (row, 2, "Performs all substitutions on the task description, for fixing mistakes");
row = table.addRow ();
table.addCell (row, 1, "task delete ID");
@@ -175,18 +172,14 @@ static void shortUsage (Config& conf)
table.addCell (row, 1, "task overdue");
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 ();
table.addCell (row, 1, "task stats");
table.addCell (row, 2, "Shows task database statistics");
row = table.addRow ();
table.addCell (row, 1, "task import");
table.addCell (row, 2, "Imports tasks from a variety of formats");
row = table.addRow ();
table.addCell (row, 1, "task export");
table.addCell (row, 2, "Exports all tasks as a CSV file");
@@ -203,46 +196,65 @@ static void shortUsage (Config& conf)
table.addCell (row, 1, "task help");
table.addCell (row, 2, "Shows the long usage text");
std::cout << table.render ()
<< std::endl
<< "See http://www.beckingham.net/task.html for the latest releases and a full tutorial."
<< std::endl
<< std::endl;
// Add custom reports here...
std::vector <std::string> all;
allCustomReports (all);
foreach (report, all)
{
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
<< "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;
return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
@@ -274,9 +286,6 @@ void loadConfFile (int argc, char** argv, Config& conf)
////////////////////////////////////////////////////////////////////////////////
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.
#ifdef HAVE_SRANDOM
srandom (time (NULL));
@@ -289,22 +298,26 @@ int main (int argc, char** argv)
// Load the config file from the home directory. If the file cannot be
// found, offer to create a sample one.
Config conf;
gConf = &conf;
loadConfFile (argc, argv, conf);
// When redirecting output to a file, do not use color, curses.
if (!isatty (fileno (stdout)))
{
conf.set ("curses", "off");
conf.set ("color", "off");
if (! conf.get (std::string ("_forcecolor"), false))
conf.set ("color", "off");
}
TDB tdb;
gTdb = &tdb;
std::string dataLocation = expandPath (conf.get ("data.location"));
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"));
if (shadowFile != "")
{
@@ -315,8 +328,6 @@ int main (int argc, char** argv)
if (shadowFile == dataLocation + "/completed.data")
throw std::string ("Configuration variable 'shadow.file' is set to "
"overwrite your completed tasks. Please change it.");
tdb.onChange (&onChangeCallback);
}
std::cout << runTaskCommand (argc, argv, tdb, conf);
@@ -343,18 +354,56 @@ void nag (TDB& tdb, T& task, Config& conf)
std::string nagMessage = conf.get ("nag", std::string (""));
if (nagMessage != "")
{
// Load all pending.
// Load all pending tasks.
std::vector <T> pending;
tdb.allPendingT (pending);
// Restrict to matching subset.
std::vector <int> matching;
gatherNextTasks (tdb, task, conf, pending, matching);
// Counters.
int overdue = 0;
int high = 0;
int medium = 0;
int low = 0;
bool isOverdue = false;
char pri = ' ';
foreach (i, matching)
if (pending[*i].getId () == task.getId ())
return;
// Scan all pending tasks.
foreach (t, pending)
{
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;
}
}
@@ -372,15 +421,12 @@ int getDueState (const std::string& due)
// rightNow is the current date + time.
Date rightNow;
Date midnight (rightNow.month (), rightNow.day (), rightNow.year ());
// By performing this conversion, today is set up as the same date, but
// midnight.
Date today (rightNow.month (), rightNow.day (), rightNow.year ());
if (dt < today)
if (dt < midnight)
return 2;
Date nextweek = today + 7 * 86400;
Date nextweek = midnight + 7 * 86400;
if (dt < nextweek)
return 1;
}
@@ -531,6 +577,18 @@ Date getNextRecurrence (Date& current, std::string& period)
return Date (m, d, y);
}
if (period == "weekdays")
{
int dow = current.dayOfWeek ();
int days;
if (dow == 5) days = 3;
else if (dow == 6) days = 2;
else days = 1;
return current + (days * 86400);
}
if (isdigit (period[0]) && period[period.length () - 1] == 'm')
{
std::string numeric = period.substr (0, period.length () - 1);
@@ -620,6 +678,19 @@ Date getNextRecurrence (Date& current, std::string& period)
return Date (m, d, y);
}
else if (period == "annual" ||
period == "yearly")
{
y += 1;
// If the due data just happens to be 2/29 in a leap year, then simply
// incrementing y is going to create an invalid date.
if (m == 2 && d == 29)
d = 28;
return Date (m, d, y);
}
// If the period is an 'easy' one, add it to current, and we're done.
int days = convertDuration (period);
return current + (days * 86400);
@@ -672,61 +743,53 @@ void updateRecurrenceMask (
}
////////////////////////////////////////////////////////////////////////////////
// Using gTdb and gConf, generate a report.
void onChangeCallback ()
void updateShadowFile (TDB& tdb, Config& conf)
{
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 shadowFile = expandPath (gConf->get ("shadow.file"));
if (shadowFile != "")
std::string oldCurses = conf.get ("curses");
std::string oldColor = conf.get ("color");
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");
std::string oldColor = gConf->get ("color");
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);
out << result;
out.close ();
}
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.
if (gConf->get (std::string ("shadow.notify"), false))
std::cout << "[Shadow file '" << shadowFile << "' updated]" << std::endl;
conf.set ("curses", oldCurses);
conf.set ("color", oldColor);
}
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)
{
std::cout << error << std::endl;
std::cerr << error << std::endl;
}
catch (...)
{
std::cout << "Unknown error." << std::endl;
std::cerr << "Unknown error." << std::endl;
}
}
@@ -736,13 +799,14 @@ std::string runTaskCommand (
char** argv,
TDB& tdb,
Config& conf,
bool gc /* = true */)
bool gc /* = true */,
bool shadow /* = true */)
{
std::vector <std::string> args;
for (int i = 1; i < argc; ++i)
args.push_back (argv[i]);
return runTaskCommand (args, tdb, conf, gc);
return runTaskCommand (args, tdb, conf, gc, shadow);
}
////////////////////////////////////////////////////////////////////////////////
@@ -750,12 +814,15 @@ std::string runTaskCommand (
std::vector <std::string>& args,
TDB& tdb,
Config& conf,
bool gc /* = false */)
bool gc /* = false */,
bool shadow /* = false */)
{
// If argc == 1 and the default.command configuration variable is set,
// then use that, otherwise stick with argc/argv.
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.
args.clear ();
@@ -769,39 +836,51 @@ std::string runTaskCommand (
T task;
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 ); }
else if (command == "add") { handleAdd (tdb, task, conf ); }
else if (command == "done") { handleDone (tdb, task, conf ); }
else if (command == "export") { handleExport (tdb, task, conf ); }
else if (command == "projects") { out = handleProjects (tdb, task, conf ); }
else if (command == "tags") { out = handleTags (tdb, task, conf ); }
else if (command == "info") { out = handleInfo (tdb, task, conf ); }
else if (command == "undelete") { out = handleUndelete (tdb, task, conf ); }
else if (command == "delete") { out = handleDelete (tdb, task, conf ); }
else if (command == "start") { out = handleStart (tdb, task, conf ); }
else if (command == "stop") { out = handleStop (tdb, task, conf ); }
else if (command == "undo") { out = handleUndo (tdb, task, conf ); }
else if (command == "stats") { out = handleReportStats (tdb, task, 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
else if (command == "ls") { if (gc) tdb.gc (); out = handleSmallList (tdb, task, conf ); } // TODO replace with Custom
else if (command == "completed") { if (gc) tdb.gc (); out = handleCompleted (tdb, task, conf ); } // TODO replace with Custom
else if (command == "summary") { if (gc) tdb.gc (); out = handleReportSummary (tdb, task, conf ); }
else if (command == "next") { if (gc) tdb.gc (); out = handleReportNext (tdb, task, conf ); } // TODO replace with Custom
else if (command == "history") { if (gc) tdb.gc (); out = handleReportHistory (tdb, task, conf ); }
else if (command == "ghistory") { if (gc) tdb.gc (); out = handleReportGHistory (tdb, task, conf ); }
else if (command == "calendar") { if (gc) tdb.gc (); out = handleReportCalendar (tdb, task, conf ); }
else if (command == "active") { if (gc) tdb.gc (); out = handleReportActive (tdb, task, conf ); } // TODO replace with Custom
else if (command == "overdue") { if (gc) tdb.gc (); out = handleReportOverdue (tdb, task, conf ); } // TODO replace with Custom
else if (command == "oldest") { if (gc) tdb.gc (); out = handleReportOldest (tdb, task, conf ); } // TODO replace with Custom
else if (command == "newest") { if (gc) tdb.gc (); out = handleReportNewest (tdb, task, conf ); } // TODO replace with Custom
else if (command == "colors") { out = handleColor ( conf ); }
else if (command == "version") { out = handleVersion ( conf ); }
else if (command == "help") { longUsage ( conf ); }
else if (isCustomReport (command)) { if (gc) tdb.gc (); out = handleCustomReport (tdb, task, conf, command); } // New Custom reports
else { shortUsage ( conf ); }
// Read-only commands with no side effects.
if (command == "export") { out = handleExport (tdb, task, conf); }
else if (command == "projects") { out = handleProjects (tdb, task, conf); }
else if (command == "tags") { out = handleTags (tdb, task, conf); }
else if (command == "info") { out = handleInfo (tdb, task, conf); }
else if (command == "stats") { out = handleReportStats (tdb, task, conf); }
else if (command == "history") { out = handleReportHistory (tdb, task, conf); }
else if (command == "ghistory") { out = handleReportGHistory (tdb, task, conf); }
else if (command == "calendar") { out = handleReportCalendar (tdb, task, conf); }
else if (command == "summary") { out = handleReportSummary (tdb, task, conf); }
else if (command == "colors") { out = handleColor ( conf); }
else if (command == "version") { out = handleVersion ( conf); }
else if (command == "help") { out = longUsage ( conf); }
// Commands that cause updates.
else if (command == "" && task.getId ()) { cmdMod = true; out = handleModify (tdb, task, conf); }
else if (command == "add") { cmdMod = true; out = handleAdd (tdb, task, conf); }
else if (command == "append") { cmdMod = true; out = handleAppend (tdb, task, conf); }
else if (command == "annotate") { cmdMod = true; out = handleAnnotate (tdb, task, conf); }
else if (command == "done") { cmdMod = true; out = handleDone (tdb, task, conf); }
else if (command == "undelete") { cmdMod = true; out = handleUndelete (tdb, task, conf); }
else if (command == "delete") { cmdMod = true; out = handleDelete (tdb, task, conf); }
else if (command == "start") { cmdMod = true; out = handleStart (tdb, task, conf); }
else if (command == "stop") { cmdMod = true; out = handleStop (tdb, task, conf); }
else if (command == "undo") { cmdMod = true; out = handleUndo (tdb, task, conf); }
else if (command == "import") { cmdMod = true; out = handleImport (tdb, task, conf); }
// Command that display IDs and therefore need TDB::gc first.
else if (command == "completed") { if (gc) gcMod = tdb.gc (); out = handleCompleted (tdb, task, conf); }
else if (command == "next") { if (gc) gcMod = tdb.gc (); out = handleReportNext (tdb, task, conf); }
else if (command == "active") { if (gc) gcMod = tdb.gc (); out = handleReportActive (tdb, task, conf); }
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;
}

View File

@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2008, Paul Beckingham.
// Copyright 2006 - 2009, Paul Beckingham.
// All rights reserved.
//
// 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&);
void loadCustomReports (Config&);
bool isCustomReport (const std::string&);
void allCustomReports (std::vector <std::string>&);
// task.cpp
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&);
void updateRecurrenceMask (TDB&, std::vector <T>&, T&);
void onChangeCallback ();
std::string runTaskCommand (int, char**, TDB&, Config&, bool gc = true);
std::string runTaskCommand (std::vector <std::string>&, TDB&, Config&, bool gc = false);
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, bool shadow = false);
// command.cpp
void handleAdd (TDB&, T&, Config&);
void handleExport (TDB&, T&, Config&);
void handleDone (TDB&, T&, Config&);
void handleModify (TDB&, T&, Config&);
std::string handleAdd (TDB&, T&, Config&);
std::string handleAppend (TDB&, T&, Config&);
std::string handleExport (TDB&, T&, Config&);
std::string handleDone (TDB&, T&, Config&);
std::string handleModify (TDB&, T&, Config&);
std::string handleProjects (TDB&, T&, Config&);
std::string handleTags (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 handleUndo (TDB&, T&, Config&);
std::string handleColor (Config&);
std::string handleAnnotate (TDB&, T&, Config&);
T findT (int, const std::vector <T>&);
// report.cpp
void filter (std::vector<T>&, T&);
std::string handleList (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 handleReportSummary (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 handleReportOverdue (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&);
void validReportColumns (const std::vector <std::string>&);
void validSortColumns (const std::vector <std::string>&, const std::vector <std::string>&);
// util.cpp
bool confirm (const std::string&);
// text.cpp
void wrapText (std::vector <std::string>&, const std::string&, const int);
std::string trimLeft (const std::string& in, const std::string& t = " ");
std::string trimRight (const std::string& in, const std::string& t = " ");
std::string trim (const std::string& in, const std::string& t = " ");
void extractParagraphs (const std::string&, std::vector<std::string>&);
std::string unquoteText (const std::string&);
void extractLine (std::string&, std::string&, int);
void split (std::vector<std::string>&, const std::string&, const char);
void split (std::vector<std::string>&, const std::string&, const std::string&);
@@ -121,17 +121,34 @@ void join (std::string&, const std::string&, const std::vector<std::string>&);
std::string commify (const std::string&);
std::string lowerCase (const std::string&);
std::string upperCase (const std::string&);
const char* optionalBlankLine (Config&);
// util.cpp
bool confirm (const std::string&);
void delay (float);
int autoComplete (const std::string&, const std::vector<std::string>&, std::vector<std::string>&);
void formatTimeDeltaDays (std::string&, time_t);
std::string formatSeconds (time_t);
int autoComplete (const std::string&, const std::vector<std::string>&, std::vector<std::string>&);
const std::string uuid ();
const char* optionalBlankLine (Config&);
int convertDuration (std::string&);
int convertDuration (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
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.benchmark.t
tdb.t
date.t
duration.t
pending.data
completed.data
text.t
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
LFLAGS = -L/usr/local/lib
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
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>
@@ -9,7 +31,7 @@
////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv)
{
plan (100);
UnitTest t (100);
try
{
@@ -17,207 +39,207 @@ int main (int argc, char** argv)
Date yesterday;
yesterday -= 1;
ok (yesterday <= now, "yesterday <= now");
ok (yesterday < now, "yesterday < now");
notok (yesterday == now, "!(yesterday == now)");
ok (yesterday != now, "yesterday != now");
ok (now >= yesterday, "now >= yesterday");
ok (now > yesterday, "now > yesterday");
t.ok (yesterday <= now, "yesterday <= now");
t.ok (yesterday < now, "yesterday < now");
t.notok (yesterday == now, "!(yesterday == now)");
t.ok (yesterday != now, "yesterday != now");
t.ok (now >= yesterday, "now >= yesterday");
t.ok (now > yesterday, "now > yesterday");
// Loose comparisons.
Date left ("7/4/2008");
Date comp1 ("7/4/2008");
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");
ok (left.sameYear (comp1), "7/4/2008 is in the same year as 7/4/2008");
t.ok (left.sameDay (comp1), "7/4/2008 is on the same day as 7/4/2008");
t.ok (left.sameMonth (comp1), "7/4/2008 is in the same month 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");
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");
ok (left.sameYear (comp2), "7/4/2008 is in the same year as 7/5/2008");
t.notok (left.sameDay (comp2), "7/4/2008 is not on the same day as 7/5/2008");
t.ok (left.sameMonth (comp2), "7/4/2008 is in the same month 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");
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");
ok (left.sameYear (comp3), "7/4/2008 is in the same year as 8/4/2008");
t.notok (left.sameDay (comp3), "7/4/2008 is not on the same day as 8/4/2008");
t.notok (left.sameMonth (comp3), "7/4/2008 is not in the same month 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");
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");
notok (left.sameYear (comp4), "7/4/2008 is not in the same year as 7/4/2009");
t.notok (left.sameDay (comp4), "7/4/2008 is not on the same day as 7/4/2009");
t.notok (left.sameMonth (comp4), "7/4/2008 is not in the same month as 7/4/2009");
t.notok (left.sameYear (comp4), "7/4/2008 is not in the same year as 7/4/2009");
// Validity.
ok (Date::valid (2, 29, 2008), "valid: 2/29/2008");
notok (Date::valid (2, 29, 2007), "invalid: 2/29/2007");
t.ok (Date::valid (2, 29, 2008), "valid: 2/29/2008");
t.notok (Date::valid (2, 29, 2007), "invalid: 2/29/2007");
// Leap year.
ok (Date::leapYear (2008), "2008 is a leap year");
notok (Date::leapYear (2007), "2007 is not a leap year");
ok (Date::leapYear (2000), "2000 is a leap year");
ok (Date::leapYear (1900), "1900 is a leap year");
t.ok (Date::leapYear (2008), "2008 is a leap year");
t.notok (Date::leapYear (2007), "2007 is not a leap year");
t.ok (Date::leapYear (2000), "2000 is a leap year");
t.ok (Date::leapYear (1900), "1900 is a leap year");
// Days in month.
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, 2008), 29, "29 days in February 2008");
t.is (Date::daysInMonth (2, 2007), 28, "28 days in February 2007");
// Names.
is (Date::monthName (1), "January", "1 = January");
is (Date::monthName (2), "February", "2 = February");
is (Date::monthName (3), "March", "3 = March");
is (Date::monthName (4), "April", "4 = April");
is (Date::monthName (5), "May", "5 = May");
is (Date::monthName (6), "June", "6 = June");
is (Date::monthName (7), "July", "7 = July");
is (Date::monthName (8), "August", "8 = August");
is (Date::monthName (9), "September", "9 = September");
is (Date::monthName (10), "October", "10 = October");
is (Date::monthName (11), "November", "11 = November");
is (Date::monthName (12), "December", "12 = December");
t.is (Date::monthName (1), "January", "1 = January");
t.is (Date::monthName (2), "February", "2 = February");
t.is (Date::monthName (3), "March", "3 = March");
t.is (Date::monthName (4), "April", "4 = April");
t.is (Date::monthName (5), "May", "5 = May");
t.is (Date::monthName (6), "June", "6 = June");
t.is (Date::monthName (7), "July", "7 = July");
t.is (Date::monthName (8), "August", "8 = August");
t.is (Date::monthName (9), "September", "9 = September");
t.is (Date::monthName (10), "October", "10 = October");
t.is (Date::monthName (11), "November", "11 = November");
t.is (Date::monthName (12), "December", "12 = December");
is (Date::dayName (0), "Sunday", "0 == Sunday");
is (Date::dayName (1), "Monday", "1 == Monday");
is (Date::dayName (2), "Tuesday", "2 == Tuesday");
is (Date::dayName (3), "Wednesday", "3 == Wednesday");
is (Date::dayName (4), "Thursday", "4 == Thursday");
is (Date::dayName (5), "Friday", "5 == Friday");
is (Date::dayName (6), "Saturday", "6 == Saturday");
t.is (Date::dayName (0), "Sunday", "0 == Sunday");
t.is (Date::dayName (1), "Monday", "1 == Monday");
t.is (Date::dayName (2), "Tuesday", "2 == Tuesday");
t.is (Date::dayName (3), "Wednesday", "3 == Wednesday");
t.is (Date::dayName (4), "Thursday", "4 == Thursday");
t.is (Date::dayName (5), "Friday", "5 == Friday");
t.is (Date::dayName (6), "Saturday", "6 == Saturday");
is (Date::dayOfWeek ("SUNDAY"), 0, "SUNDAY == 0");
is (Date::dayOfWeek ("sunday"), 0, "sunday == 0");
is (Date::dayOfWeek ("Sunday"), 0, "Sunday == 0");
is (Date::dayOfWeek ("Monday"), 1, "Monday == 1");
is (Date::dayOfWeek ("Tuesday"), 2, "Tuesday == 2");
is (Date::dayOfWeek ("Wednesday"), 3, "Wednesday == 3");
is (Date::dayOfWeek ("Thursday"), 4, "Thursday == 4");
is (Date::dayOfWeek ("Friday"), 5, "Friday == 5");
is (Date::dayOfWeek ("Saturday"), 6, "Saturday == 6");
t.is (Date::dayOfWeek ("SUNDAY"), 0, "SUNDAY == 0");
t.is (Date::dayOfWeek ("sunday"), 0, "sunday == 0");
t.is (Date::dayOfWeek ("Sunday"), 0, "Sunday == 0");
t.is (Date::dayOfWeek ("Monday"), 1, "Monday == 1");
t.is (Date::dayOfWeek ("Tuesday"), 2, "Tuesday == 2");
t.is (Date::dayOfWeek ("Wednesday"), 3, "Wednesday == 3");
t.is (Date::dayOfWeek ("Thursday"), 4, "Thursday == 4");
t.is (Date::dayOfWeek ("Friday"), 5, "Friday == 5");
t.is (Date::dayOfWeek ("Saturday"), 6, "Saturday == 6");
Date happyNewYear (1, 1, 2008);
is (happyNewYear.dayOfWeek (), 2, "1/1/2008 == Tuesday");
is (happyNewYear.month (), 1, "1/1/2008 == January");
is (happyNewYear.day (), 1, "1/1/2008 == 1");
is (happyNewYear.year (), 2008, "1/1/2008 == 2008");
t.is (happyNewYear.dayOfWeek (), 2, "1/1/2008 == Tuesday");
t.is (happyNewYear.month (), 1, "1/1/2008 == January");
t.is (happyNewYear.day (), 1, "1/1/2008 == 1");
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;
happyNewYear.toMDY (m, d, y);
is (m, 1, "1/1/2008 == January");
is (d, 1, "1/1/2008 == 1");
is (y, 2008, "1/1/2008 == 2008");
t.is (m, 1, "1/1/2008 == January");
t.is (d, 1, "1/1/2008 == 1");
t.is (y, 2008, "1/1/2008 == 2008");
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;
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 ());
is (fromEpoch.toString (), epoch.toString (), "ctor (time_t)");
t.is (fromEpoch.toString (), epoch.toString (), "ctor (time_t)");
// Date parsing.
Date fromString1 ("1/1/2008");
is (fromString1.month (), 1, "ctor (std::string) -> m");
is (fromString1.day (), 1, "ctor (std::string) -> d");
is (fromString1.year (), 2008, "ctor (std::string) -> y");
t.is (fromString1.month (), 1, "ctor (std::string) -> m");
t.is (fromString1.day (), 1, "ctor (std::string) -> d");
t.is (fromString1.year (), 2008, "ctor (std::string) -> y");
Date fromString2 ("1/1/2008", "m/d/Y");
is (fromString2.month (), 1, "ctor (std::string) -> m");
is (fromString2.day (), 1, "ctor (std::string) -> d");
is (fromString2.year (), 2008, "ctor (std::string) -> y");
t.is (fromString2.month (), 1, "ctor (std::string) -> m");
t.is (fromString2.day (), 1, "ctor (std::string) -> d");
t.is (fromString2.year (), 2008, "ctor (std::string) -> y");
Date fromString3 ("20080101", "YMD");
is (fromString3.month (), 1, "ctor (std::string) -> m");
is (fromString3.day (), 1, "ctor (std::string) -> d");
is (fromString3.year (), 2008, "ctor (std::string) -> y");
t.is (fromString3.month (), 1, "ctor (std::string) -> m");
t.is (fromString3.day (), 1, "ctor (std::string) -> d");
t.is (fromString3.year (), 2008, "ctor (std::string) -> y");
Date fromString4 ("12/31/2007");
is (fromString4.month (), 12, "ctor (std::string) -> m");
is (fromString4.day (), 31, "ctor (std::string) -> d");
is (fromString4.year (), 2007, "ctor (std::string) -> y");
t.is (fromString4.month (), 12, "ctor (std::string) -> m");
t.is (fromString4.day (), 31, "ctor (std::string) -> d");
t.is (fromString4.year (), 2007, "ctor (std::string) -> y");
Date fromString5 ("12/31/2007", "m/d/Y");
is (fromString5.month (), 12, "ctor (std::string) -> m");
is (fromString5.day (), 31, "ctor (std::string) -> d");
is (fromString5.year (), 2007, "ctor (std::string) -> y");
t.is (fromString5.month (), 12, "ctor (std::string) -> m");
t.is (fromString5.day (), 31, "ctor (std::string) -> d");
t.is (fromString5.year (), 2007, "ctor (std::string) -> y");
Date fromString6 ("20071231", "YMD");
is (fromString6.month (), 12, "ctor (std::string) -> m");
is (fromString6.day (), 31, "ctor (std::string) -> d");
is (fromString6.year (), 2007, "ctor (std::string) -> y");
t.is (fromString6.month (), 12, "ctor (std::string) -> m");
t.is (fromString6.day (), 31, "ctor (std::string) -> d");
t.is (fromString6.year (), 2007, "ctor (std::string) -> y");
Date fromString7 ("01/01/2008", "m/d/Y");
is (fromString7.month (), 1, "ctor (std::string) -> m");
is (fromString7.day (), 1, "ctor (std::string) -> d");
is (fromString7.year (), 2008, "ctor (std::string) -> y");
t.is (fromString7.month (), 1, "ctor (std::string) -> m");
t.is (fromString7.day (), 1, "ctor (std::string) -> d");
t.is (fromString7.year (), 2008, "ctor (std::string) -> y");
// Relative dates.
Date r1 ("today");
ok (r1.sameDay (now), "today = now");
t.ok (r1.sameDay (now), "today = now");
Date r2 ("tomorrow");
ok (r2.sameDay (now + 86400), "tomorrow = now + 1d");
t.ok (r2.sameDay (now + 86400), "tomorrow = now + 1d");
Date r3 ("yesterday");
ok (r3.sameDay (now - 86400), "yesterday = now - 1d");
t.ok (r3.sameDay (now - 86400), "yesterday = now - 1d");
Date r4 ("sunday");
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
ok (r4.sameDay (now + (0 - now.dayOfWeek ()) * 86400), "next sunday");;
t.ok (r4.sameDay (now + (0 - now.dayOfWeek ()) * 86400), "next sunday");;
Date r5 ("monday");
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
ok (r5.sameDay (now + (1 - now.dayOfWeek ()) * 86400), "next monday");;
t.ok (r5.sameDay (now + (1 - now.dayOfWeek ()) * 86400), "next monday");;
Date r6 ("tuesday");
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
ok (r6.sameDay (now + (2 - now.dayOfWeek ()) * 86400), "next tuesday");;
t.ok (r6.sameDay (now + (2 - now.dayOfWeek ()) * 86400), "next tuesday");;
Date r7 ("wednesday");
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
ok (r7.sameDay (now + (3 - now.dayOfWeek ()) * 86400), "next wednesday");;
t.ok (r7.sameDay (now + (3 - now.dayOfWeek ()) * 86400), "next wednesday");;
Date r8 ("thursday");
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
ok (r8.sameDay (now + (4 - now.dayOfWeek ()) * 86400), "next thursday");;
t.ok (r8.sameDay (now + (4 - now.dayOfWeek ()) * 86400), "next thursday");;
Date r9 ("friday");
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
ok (r9.sameDay (now + (5 - now.dayOfWeek ()) * 86400), "next friday");;
t.ok (r9.sameDay (now + (5 - now.dayOfWeek ()) * 86400), "next friday");;
Date r10 ("saturday");
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
ok (r10.sameDay (now + (6 - now.dayOfWeek ()) * 86400), "next saturday");;
t.ok (r10.sameDay (now + (6 - now.dayOfWeek ()) * 86400), "next saturday");;
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");
ok (r12.sameMonth (now), "eom in same month as now");
t.ok (r12.sameMonth (now), "eom in same month as now");
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)
{
fail ("Exception thrown.");
diag (e);
t.fail ("Exception thrown.");
t.diag (e);
}
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>
@@ -16,27 +38,27 @@
// biannual, biyearly, annual, semiannual, yearly, Ny
int main (int argc, char** argv)
{
plan (17);
UnitTest t (17);
std::string d;
d = "daily"; is (convertDuration (d), 1, "duration daily = 1");
d = "day"; is (convertDuration (d), 1, "duration day = 1");
d = "0d"; is (convertDuration (d), 0, "duration 0d = 0");
d = "1d"; is (convertDuration (d), 1, "duration 1d = 1");
d = "7d"; is (convertDuration (d), 7, "duration 7d = 7");
d = "10d"; is (convertDuration (d), 10, "duration 10d = 10");
d = "100d"; is (convertDuration (d), 100, "duration 100d = 100");
d = "daily"; t.is (convertDuration (d), 1, "duration daily = 1");
d = "weekdays"; t.is (convertDuration (d), 1, "duration weekdays = 1");
d = "day"; t.is (convertDuration (d), 1, "duration day = 1");
d = "0d"; t.is (convertDuration (d), 0, "duration 0d = 0");
d = "1d"; t.is (convertDuration (d), 1, "duration 1d = 1");
d = "7d"; t.is (convertDuration (d), 7, "duration 7d = 7");
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 = "sennight"; is (convertDuration (d), 7, "duration sennight = 7");
d = "biweekly"; is (convertDuration (d), 14, "duration biweekly = 14");
d = "fortnight"; is (convertDuration (d), 14, "duration fortnight = 14");
d = "week"; is (convertDuration (d), 7, "duration week = 7");
d = "0w"; is (convertDuration (d), 0, "duration 0w = 0");
d = "1w"; is (convertDuration (d), 7, "duration 1w = 7");
d = "7w"; is (convertDuration (d), 49, "duration 7w = 49");
d = "10w"; is (convertDuration (d), 70, "duration 10w = 70");
d = "100w"; is (convertDuration (d), 700, "duration 100w = 700");
d = "weekly"; t.is (convertDuration (d), 7, "duration weekly = 7");
d = "sennight"; t.is (convertDuration (d), 7, "duration sennight = 7");
d = "biweekly"; t.is (convertDuration (d), 14, "duration biweekly = 14");
d = "fortnight"; t.is (convertDuration (d), 14, "duration fortnight = 14");
d = "0w"; t.is (convertDuration (d), 0, "duration 0w = 0");
d = "1w"; t.is (convertDuration (d), 7, "duration 1w = 7");
d = "7w"; t.is (convertDuration (d), 49, "duration 7w = 49");
d = "10w"; t.is (convertDuration (d), 70, "duration 10w = 70");
d = "100w"; t.is (convertDuration (d), 700, "duration 100w = 700");
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