Compare commits

..

230 Commits

Author SHA1 Message Date
Federico Hernandez
df49aaba12 Version number and release date for 2.4.4 2015-05-10 22:57:16 +02:00
Paul Beckingham
0d45bb75e8 Merge branch '2.4.4' of ssh://git.tasktools.org/tm/task into 2.4.4 2015-05-10 13:19:12 -04:00
Paul Beckingham
5d5e824453 Docs: Filled in balnks in NEWS file. 2015-05-10 13:18:54 -04:00
Wilhelm Schuermann
92b5dfd83d Add-ons: Fix UTF8 problems with export-sql.py 2015-05-10 17:58:20 +02:00
Paul Beckingham
7293de75b0 TW-1608: The recur/recurring report shows tasks without a recur interval
- Lexer needed additional lookbehind criteria for ::isTag (thanks to Brad
  Collette).
2015-05-09 21:27:48 -04:00
Paul Beckingham
f30f4d45c6 TW-1285: I'd like to use relative dates combined with times
- With the new parser and datemath in place, this can now be done (thanks to
  Adam Gibbins).
2015-05-09 11:22:05 -04:00
Paul Beckingham
32ef3fdb3d TW-69: wait dates relative to due date
- Possible now with DOM access:  task add ... due:eom wait:due-1wk
  (thanks to John Florian).
2015-05-09 11:15:35 -04:00
Wilhelm Schuermann
65b6a35ef5 Tests: Make self.t('add proj:"with space" foo') work 2015-05-08 18:19:37 +02:00
Roman Inflianskas
e16bd6ee83 Fish: Use variables for completion options 2015-05-07 20:21:32 -04:00
Wilhelm Schuermann
69698454c3 Tests: Speed up filter.t
- None of the tests in filter.t write data.  Make use of that by
  setting up task data once for all included tests.
2015-05-07 17:23:14 +02:00
Wilhelm Schuermann
3a7af017f8 Tests: Make "run_all --fast" even faster
- Run isolated tests in the background, bringing the time for running
  "run_all" down to the time it takes to run the old tests.
2015-05-07 11:41:05 +02:00
Wilhelm Schuermann
accd51bc35 Tests: Fix problems with "run_all --fast" on OpenBSD 2015-05-06 22:06:11 +02:00
Wilhelm Schuermann
5fee3ef27c Tests: Clean up after "run_all --fast" 2015-05-06 20:56:35 +02:00
Paul Beckingham
0850e26a3e Tests: Removed annoying comment. 2015-05-06 14:44:35 -04:00
Wilhelm Schuermann
4deb17696e Tests: Parallelize Python tests
- "./run_all --fast" parallelizes all Python tests.  Perl and C++ tests
  are not guaranteed to run in an isolated environment, so run them
  serially instead.
- Adjust some tests in order to recognize them as Python.
2015-05-06 19:17:33 +02:00
Wilhelm Schuermann
7d859d6b6d Tests: Beautify gc.t, add one more GC test 2015-05-05 21:00:39 +02:00
Wilhelm Schuermann
f6e04585ae Tests: Add simpler self.t("add foo +bar") syntax 2015-05-05 20:28:10 +02:00
Renato Alves
1e31df3c7a Tests: bug.368.t > feature.recurrence.t as python 2015-05-05 15:13:01 +01:00
Renato Alves
db04f1b583 Tests: bug.327.t > feature.recurrence.t in python 2015-05-05 15:05:42 +01:00
Wilhelm Schuermann
1c9edcc2ec TW-1610: Add tests
- More GC tests needed, this is just a basic "starter pack" to
  reproduce the problem reported in TW-1610.
2015-05-05 10:10:29 +02:00
Wilhelm Schuermann
710372b8db TW-1610: Disabling GC can lead to editing the wrong task
- 9e6c6ecb93 introduced a change that
  can lead to the wrong task being edited when GC is manually turned
  off.  Fix this by taking the user's GC setting into account.
2015-05-04 09:01:01 +02:00
Paul Beckingham
c8756f0201 TW-1474: Documentation is confusing with respect to user/uuid on the server
- Man page clarified, mention of 'password' removed (thanks to Tomas Babej).
2015-05-03 11:21:01 -04:00
Paul Beckingham
b6b49ca7e4 Docs: Added comment to prevent changes 2015-05-03 10:54:52 -04:00
Renato Alves
ec9b8c5aa9 Tests: Force protocol to IPv4 on localhost 2015-05-03 15:52:12 +01:00
Wilhelm Schuermann
023a17e6be (t|T)ask(w|W)arrior ---> Taskwarrior
- Standardize spelling of "Taskwarrior" across most files.
- Fix other minor typos in help text and docs.
2015-05-02 18:12:21 +02:00
Paul Beckingham
c346cf9395 Portability: Use fcntl instead of flock
- POSIX file locking mechanism, eliminating platform-specific code.
2015-05-02 11:47:39 -04:00
Paul Beckingham
71fef9f22f Docs: Updated INSTALL 2015-05-02 09:47:06 -04:00
Paul Beckingham
36e31811b0 TW-1606: scheduled.any filter
- The Lexer::dom type worked embedded, but not isolated (thanks to Peter Rochen).
2015-04-29 18:53:13 -04:00
Paul Beckingham
71753ef666 TW-1605: Japanese translation for Taskwarrior
- Initial Japanese translation (thanks to Oota Toshiya).
2015-04-28 20:11:11 -04:00
Paul Beckingham
7a9e099568 TW-1603: Priority color precedence changed since it is a UDA, should be lowered again
- The 'uda.' element is moved to the end, where 'pri.' used to be (thanks to
  Jens Erat).
2015-04-27 17:21:01 -04:00
Renato Alves
fcfc95df86 Tests: Fix framework log collection error 2015-04-27 11:39:34 +01:00
Paul Beckingham
5f9a543b1b TLS: Diagnostics
- When a certificate fails validation, display the full set of reasons, in
  debug mode.
2015-04-26 20:52:34 -04:00
Paul Beckingham
75775786e6 TLS: Fixed version conditional
- The call to gnutls_certificate_verification_status_print was protected by an
  #ifdef which had the wrong GnuTLS version number.
2015-04-26 20:51:46 -04:00
Paul Beckingham
caa8c8e884 TLS: Fixed cert verification bug
- When a cert was unreadable, instead of exiting verification with a value of
  GNUTLS_E_CERTIFICATE_ERROR, the value was assigned to 'status', which has
  different semantics.
2015-04-26 20:51:08 -04:00
Paul Beckingham
93470bb8d8 Merge branch '2.4.4' of ssh://git.tasktools.org/tm/task into 2.4.4 2015-04-26 13:29:13 -04:00
Paul Beckingham
8e01976abb Sync: Made more explicit exit codes for various errors 2015-04-26 13:28:53 -04:00
Renato Alves
e60ea2e07a Revert "Tests: Use IP address instead of hostname with taskd"
Going back to using "localhost". Using the IP address causes GNUTLS
handshake errors in GnuTLS <= 3.2.18

This reverts commit 233d97fbff.
2015-04-26 18:13:20 +01:00
Renato Alves
931afb0674 Tests: Documentation on TASK/TASKD_USE_PATH 2015-04-26 17:46:44 +01:00
Paul Beckingham
1b63a2dde5 Documentation: Added the 'rc.obfuscate' setting.
- The 'obfuscate' setting, if set to '1' will replace all text with 'xxx'.
2015-04-26 11:14:05 -04:00
Paul Beckingham
c62ba68f10 Merge branch '2.4.4' of ssh://git.tasktools.org/tm/task into 2.4.4 2015-04-26 10:34:40 -04:00
Paul Beckingham
5d60f426a8 Obfuscation: rc.obfuscate=1 hides private details 2015-04-26 10:31:32 -04:00
Renato Alves
7fcb26f363 Tests: Increase timeout to 5 seconds 2015-04-26 15:28:51 +01:00
Paul Beckingham
c34b2b8cfb Color: Removed "pri." from the color rule precedence
- This is an obsolete entry (thanks To Jens Erat).
2015-04-26 09:36:08 -04:00
Paul Beckingham
b9a8d62324 Diagnostics: Removed 'Build caps' line 2015-04-26 09:30:44 -04:00
Paul Beckingham
c8c7123eb9 Merge branch '2.4.4' of ssh://git.tasktools.org/tm/task into 2.4.4 2015-04-26 09:23:08 -04:00
Paul Beckingham
dc8e874f19 Diagnostics: Removed obsolete items
- Removed '+pthreads' caps indicator.
- Removed HAVE_LIB defines for pthreads and readline.
- Removed CMake module for finding readline.
2015-04-26 09:17:31 -04:00
Renato Alves
233d97fbff Tests: Use IP address instead of hostname with taskd 2015-04-26 00:24:59 +01:00
Renato Alves
64be230639 Tests: Include taskd in USE_PATH warning 2015-04-25 23:59:49 +01:00
Renato Alves
a52bba46f1 Output taskd.log to stdout on taskd failures (not test errors) 2015-04-25 23:51:01 +01:00
Paul Beckingham
b91a4b4982 Tests: Code formatting 2015-04-25 11:55:19 -04:00
Paul Beckingham
f9e3f865b1 TW-1596: TW-1596 taskwarrior can't compile FreeBSD 9.3 32bit environment
- On 32-bit systems, 'int' and 'time_t' are ambiguous overrides, and must be
  disambiguated with other signature changes (thanks to ribbon).
2015-04-21 11:24:44 +01:00
Paul Beckingham
67a008e7bf Docs: Updated compiler requirements 2015-04-21 10:55:51 +01:00
Federico Hernandez
5c70619d68 Bumped version number in ref page 2015-04-20 00:22:15 +02:00
Federico Hernandez
6cf3345595 Bumped version number to 2.4.4 2015-04-20 00:07:53 +02:00
Federico Hernandez
9959d8eac8 Added SHA1 of tagged release commit 2015-04-20 00:04:19 +02:00
Federico Hernandez
499044b9b6 Version number and release date for 2.4.3 2015-04-19 23:47:18 +02:00
Wilhelm Schuermann
f66c706370 Portability: FreeBSD 9.3 x86 needs limits.h 2015-04-18 11:38:01 +02:00
Paul Beckingham
e3e72e32f1 Build: More changes to address 32-bit builds 2015-04-18 10:26:37 +01:00
Paul Beckingham
39fb45447b Lexer: Migrated ispunct to Lexer::isPunctuation 2015-04-16 23:52:43 -04:00
Paul Beckingham
3cbb2bb20f Lexer: Migrated isdigit to Lexer::isDigit 2015-04-16 23:33:25 -04:00
Paul Beckingham
c6dbdf87a4 Lexer: Migrated isalpha to Lexer::isAlpha 2015-04-16 23:24:17 -04:00
Paul Beckingham
fe8d235a6b UTF8: Moved mk_wcwidth definition to utf8.h 2015-04-16 23:11:17 -04:00
Paul Beckingham
1371b6595e Build: Disambiguated Variant instantiation that causes 32-bit problems 2015-04-16 22:53:38 -04:00
Paul Beckingham
21407e0ca2 TW-1595: info command doesn't print urgency details, if urgency is negative
- Thanks to Peter Rochen.
2015-04-12 10:13:15 -04:00
Paul Beckingham
c0efa0f4d7 L10N: Removed unused strings, add string missing from fra-FRA.h 2015-04-06 20:19:25 -04:00
Paul Beckingham
236e7898b9 Vim: Modified 'priority' syntax elements. 2015-04-06 20:02:33 -04:00
Paul Beckingham
33738af3e4 Show: Removed obsolete settings. 2015-04-06 19:59:54 -04:00
Fidel Mato
f684917c3c L10N esp-ESP
- Added two missing strings and its translation.
- Order changed to follow eng-USA.h
2015-04-06 19:54:44 -04:00
Fidel Mato
876a7d29b9 L10N esp-ESP
- Newly translated string from eng-USA to esp-ESP, and some corrections.
2015-04-06 19:54:38 -04:00
Paul Beckingham
119c19b519 TW-1591: add and option to see non-pending project with command task summary
- Setting 'summary.all.projects' shows all projects, not just those with pending
  tasks.
2015-04-06 15:47:02 -04:00
Paul Beckingham
935b2993f3 C++11: Took advantage of N1757. 2015-04-06 15:30:39 -04:00
Renato Alves
afec6d451f Tests: Force stopping taskd on 5mins timeout 2015-04-06 13:46:08 +01:00
Renato Alves
fd17a68930 Tests: expose 'args' passed to hook scripts
- Useful to validate that all the expected arguments were passed with
  correct escaping.
- Update test/template.t with one use-case for 'args'
2015-04-06 13:43:41 +01:00
Renato Alves
09d86eb165 Tests: Better diagnostics on taskd start failure. 2015-04-06 13:08:17 +01:00
Wilhelm Schuermann
8d5a77f490 Tests: Adjust wrapper to make hook env test work 2015-04-06 10:01:09 +02:00
Paul Beckingham
e9b54ea74f TW-1556: task hangs when modifying uda field with percent-encoded (url-encoded)
- This bug іs fixed by the new Lexer, which has allows unrecognized lexemes
  to fall through to becomre 'word' or 'dom' types (thanks to Stefan Frühwirth).
2015-04-05 23:45:27 -04:00
Paul Beckingham
3a035a7d1d TW-1590: syntax of rcfile not documented (whitespace, line continuation)
- Updated top of the taskrc(5) man page with a description of the file syntax.
  (thanks to Scott M).
2015-04-05 23:37:43 -04:00
Paul Beckingham
d405a5f3b5 Tests: Changed hook test to use a command that actually produces output 2015-04-05 16:14:20 -04:00
Paul Beckingham
0cba34268c Build: Fixed broken compile 2015-04-05 16:08:33 -04:00
Paul Beckingham
61e1401073 Performance: Only measures the first fixed-width column row 2015-04-05 16:05:43 -04:00
Paul Beckingham
a883c5ca41 Themes: Updated the built-in default theme regarding priority 2015-04-05 15:17:33 -04:00
Paul Beckingham
d98b6e5c0b Tests: Converted priority urgency coefficients to UDAs 2015-04-05 14:58:07 -04:00
Paul Beckingham
6b0d288da7 Themes: Converted color rules for 'priority'. 2015-04-05 14:09:40 -04:00
Paul Beckingham
e8654c49b5 Tests: Modified tests to accomodate new 'prioirity' color rules 2015-04-05 14:05:29 -04:00
Paul Beckingham
c28932ebbe Tests: Removed diag output from test. Still doens't work. 2015-04-05 13:29:00 -04:00
Paul Beckingham
826769bcd9 Tests: Removed unused code 2015-04-05 13:21:20 -04:00
Paul Beckingham
d31227d2e2 Tests: Add testing for hook args. Doesn't work. 2015-04-05 13:04:51 -04:00
Paul Beckingham
0a54d46589 Hooks: With rc.debug.hooks=2, shows hook arguments 2015-04-05 12:19:55 -04:00
Paul Beckingham
3f457dc744 Info: Don't print an urgency detail table is the value is zero 2015-04-05 12:00:08 -04:00
Paul Beckingham
f9c99624b2 Info: Properly breaks out urgency values for UDA coefficients 2015-04-05 11:56:55 -04:00
Paul Beckingham
b19b0f47e5 TW-1541: Priority should be converted to UDA (in default taskrc)
- The 'priority' core attribute is removed, replaced by a UDA configured to
  behave in the same manner.
2015-04-05 10:41:23 -04:00
Paul Beckingham
fbf9a8be8d TW-1539: user-defined urgency coefficients for priority values
- The 'urgency.uda.<uda>.coefficient', and 'urgency.uda.<uda>.<value>.coefficient'
  settings allow the setting of an urgency coefficient for the presence of data,
  or a specific value (takes precedence).
2015-04-05 10:38:13 -04:00
Paul Beckingham
9476069b41 TW-111 User-defined priorities
- The 'priority' attribute is no longer a core attribute, and is instead defined
  by default as a UDA that behaves in the same way. It is therefore
  reconfigurable with defined values, sort order, and urgency coefficients.
2015-04-05 10:35:21 -04:00
Paul Beckingham
35b77f93c4 TW-57: user defined attribute sort order
- When a UDA of type 'string' specifies allowable values, that list is used to
  indicate the sort order, from high to low (thanks to Max Muller).
2015-04-05 10:33:36 -04:00
Paul Beckingham
5da3416b79 TW-70: urgency.user.keyword.<keyword>.coefficient=...
- The 'urgency.user.keyword.<keywrod>.coefficient' setting allows for urgency
  adjustments based on description keywords.
2015-04-05 10:25:42 -04:00
Paul Beckingham
79207a8e42 Info: A '+' symbol was shown instead of a '*', for urgency details 2015-04-05 10:22:56 -04:00
Paul Beckingham
5af4579741 Priority: Converted 'priority' attribute to a UDA
- 'priority.long' and 'priority.short' formats now map to 'priority', and
  generate a warning.
- Man page updated.
- Converted priority urgency coefficients to UDA equivalents.
- Converted priority color rules to UDA color rules.
- Removed 'default.priority' support.
- Removed special sort handling for 'priority' field in Variant, added special
  UDA sort handling.
- Removed ColPriority.{h,cpp} source files.
- Removed asorted newly-unused variables.
- The 'show' command now highlights unused priority settings.
- Removed unused localized priority-relateѕ strings.
- Added legacy mapping for columns and sort columns for 'priority.long' and
  'priority.short' columns in report definitions.
- Removed priority color rules implementation.
- Removed obsolete tests for #860, #990, custom.priority_long.t.
- Updated various tests that set priority default, colors.
2015-04-04 19:30:33 -04:00
Paul Beckingham
7a9d314016 Variant: Temporarily put back the priority string handling
- In order to test that the UDA sorting is good, the priority processing must
  be in place, as many test rely on priority values. Will be removed later.
2015-04-04 16:16:51 -04:00
Paul Beckingham
07a18f4fae Tests: UDA sort tests 2015-04-04 15:48:01 -04:00
Paul Beckingham
29a09707f3 Variant: Implemented custom UDA sorting 2015-04-04 15:47:41 -04:00
Paul Beckingham
743cb92958 Context: Static initialize UDA sort order values 2015-04-04 14:50:38 -04:00
Paul Beckingham
370afa0d26 Sort: Delegate UDA string sorting to Variant::operator< 2015-04-04 12:53:06 -04:00
Paul Beckingham
8c0f46309b Variant: Return const refs rather than string copies 2015-04-04 12:51:56 -04:00
Paul Beckingham
fa7d4352cd Sort: All attributes are now sortable 2015-04-04 11:15:43 -04:00
Paul Beckingham
f1ef53bea0 Column: Return const refs rather than string copies 2015-04-04 10:58:55 -04:00
Paul Beckingham
21dc2ec100 UTF8: Moved variable into lower scope 2015-04-04 09:55:54 -04:00
Wilhelm Schuermann
5b01abc27f Fix problem with special chars in descriptions
Fix 'task add a; task add "\n"; task next' returning "Unknown error."
The problem can be reproduced with any report including "description"
as a column.

For task descriptions that had more special characters than regular
ones, "length" in utf8_width() underflowed, leading to problems
elsewhere in the code.
2015-04-03 22:22:44 +02:00
Wilhelm Schuermann
c830b4b669 TW-1287: default.* values applied to synced tasks
- Tasks that arrive through "task sync" no longer have defaults applied
  to them.
2015-04-02 13:39:20 +02:00
Wilhelm Schuermann
70d5f595c7 TW-1584: attr.{isnt,not} use partial matching
- Change attr.{isnt,not} to be the exact opposite of attr{:is,:},
  i.e. exact matching.
- Fix tests that assumed the old behavior was intended.
2015-04-02 13:38:04 +02:00
Wilhelm Schuermann
c1815b8277 TW-1279: default.* applies to recurring tasks
- Recurring tasks inherit attributes from their parent.  default.*
  is no longer applied to them.
2015-04-02 13:37:59 +02:00
Wilhelm Schuermann
2eea7805c6 Lexer: Fix "task calc now+3days" error
- Fix isDuration() consuming operators, leading to evaluation errors.
  Previously only "task calc now + 3days" worked, now the spaces are
  entirely optional.
2015-04-02 13:29:57 +02:00
Wilhelm Schuermann
5487414003 Hooks: Add "version:" to hooks v2 arguments
- Saves a call to "task --version", potentially saving precious hook
  execution time.  Useful for writing backwards compatible hooks in
  case of buggy Taskwarrior behavior.
2015-04-02 09:18:34 +02:00
Wilhelm Schuermann
229078ffed Scripts: Disable hooks in bash completion script
- Stop on-launch and on-exit hooks with output from interfering with
  bash completion.
2015-04-01 16:23:42 +02:00
Wilhelm Schuermann
04d0c52a43 Hooks: Implement "Hooks v2" API
- All hook scripts now receive key:value pair command line arguments.
- Add only the basics: api, args, command, rc, data.  Possibly more to
  come.
2015-04-01 11:44:37 +02:00
Wilhelm Schuermann
5d4859c44d Tests: Fix bash_completion.t problem
- bash_completion.t rewrites task.sh during setup in order to be able
  to test it.  704eb1eab3 broke that
  rewrite mechanism.
2015-03-31 11:28:12 +02:00
Wilhelm Schuermann
3f394fa164 TW-1588: Fix broken export scripts 2015-03-31 07:26:10 +02:00
Wilhelm Schuermann
df209b9b8b TW-1587: Further improve example on-exit hook
- Initial patch was not quite right.  on-exit _does_ receive added and
  modified tasks on STDIN, but is not allowed to return JSON.
2015-03-31 07:25:23 +02:00
Jochen Sprickerhof
c27f5d23b6 Hooks: Remove read loop from example on-exit hook
There is no input to the on-exit script. Prevents error:
"Hook Error: Expected 0 JSON task(s), found 1"

Signed-off-by: Wilhelm Schuermann <wimschuermann@googlemail.com>
2015-03-30 21:38:25 +02:00
Wilhelm Schuermann
df3f8ead11 TW-1579: Add INSTALL note for OpenBSD 2015-03-30 21:17:36 +02:00
Wilhelm Schuermann
bc335e8075 Add-Ons: Fix export-html.pl for new export format 2015-03-30 09:41:45 +02:00
Paul Beckingham
e0f3e6d328 Tests: Corrected test that assumes lines are longer than they are 2015-03-29 23:52:34 -04:00
Paul Beckingham
eb35386d76 Tests: Recategorized lexemes that are only dates in the presence of Eval 2015-03-29 23:14:59 -04:00
Paul Beckingham
96c448ca1e Lexer: Corrected off-by-one error in ::isTripleCharOperator 2015-03-29 23:07:18 -04:00
Paul Beckingham
71fea510bb Tests: Corrected lexer test "\"" 2015-03-29 23:02:59 -04:00
Paul Beckingham
1e411ed4b8 Tests: Corrected lexer text '\'' 2015-03-29 23:01:33 -04:00
Paul Beckingham
cfbdd4bc05 Tests: Corrected lexer test "\"three\"" 2015-03-29 22:59:27 -04:00
Paul Beckingham
5af3f71ac5 Lexer: Fixed /from/to/g detection at EOS 2015-03-29 22:56:34 -04:00
Paul Beckingham
8b863c9764 Lexer: Fixed /pattern/ detection at EOS 2015-03-29 22:53:38 -04:00
Paul Beckingham
9630b76990 Build: Resolve warnings from flod build 2015-03-29 18:21:33 -04:00
Paul Beckingham
690d9493f0 Build: Resolve some more compiler warnings 2015-03-29 18:03:36 -04:00
Paul Beckingham
73f4f55e0a Merge branch '2.4.3' of ssh://git.tasktools.org/tm/task into 2.4.3 2015-03-29 17:30:06 -04:00
Paul Beckingham
267f054449 Duration: Some units were not marked as standalone 2015-03-29 17:25:08 -04:00
Wilhelm Schuermann
7a64c19641 Resolve most compiler warnings 2015-03-29 22:05:38 +02:00
Wilhelm Schuermann
b8105812fc CMake: Enable compiler warnings 2015-03-29 22:04:48 +02:00
Paul Beckingham
f454a02224 Tests: Added more Lexer::Type::date tests 2015-03-28 16:57:34 -04:00
Paul Beckingham
1bbe709e38 Tests: Removed redundant LExer::Type::tag tests 2015-03-28 16:53:32 -04:00
Paul Beckingham
a4b96a3191 Tests: Added Lexer::Type::op tests, a full set 2015-03-28 16:49:57 -04:00
Paul Beckingham
ddb6014358 Tests: Converted Lexer::Type::duration tests 2015-03-28 16:38:17 -04:00
Paul Beckingham
31a7a3343b Tests: Converted ordinal tests 2015-03-28 16:26:50 -04:00
Paul Beckingham
3a0971f290 Tests: Added Lexer::Type::tag test for +@tag 2015-03-28 16:23:02 -04:00
Paul Beckingham
fee58b0eb6 Tests: Added Lexer::Type::operator tests, removed old ones 2015-03-28 16:21:25 -04:00
Paul Beckingham
9adf3fc0fa Tests: Added Lexer compound token expression tests 2015-03-28 12:05:45 -04:00
Paul Beckingham
39d330631d Tests: Added Lexer::Type::date tests 2015-03-28 12:05:17 -04:00
Paul Beckingham
b41d7c4582 Tests: Added Lexer::Type::duration tests 2015-03-28 11:40:31 -04:00
Paul Beckingham
12eca4b2cc Tests: Added Lexer::Type::op tests 2015-03-28 11:38:03 -04:00
Paul Beckingham
f26f790e74 Tests: Added Lexer::Type::separator test 2015-03-28 11:33:57 -04:00
Paul Beckingham
7ac0a919aa Tests: Added Lexer::Type::uuid tests 2015-03-28 11:32:17 -04:00
Paul Beckingham
e9e91ce55e Tests: Added Lexer::type::pair tests 2015-03-28 11:05:19 -04:00
Paul Beckingham
880fb5bcc6 Tests: Added Lexer::Type::number and Lexer::Type::hex tests 2015-03-28 10:58:27 -04:00
Paul Beckingham
84eb75c705 Tests: Added Lexer::Type::string tests 2015-03-28 10:45:19 -04:00
Paul Beckingham
f697e4df73 Tests: Added Lexer::Type::url tests 2015-03-28 10:26:14 -04:00
Paul Beckingham
0eaa061efe Tests: Added more Lexer::Type::dom tests 2015-03-28 10:19:54 -04:00
Paul Beckingham
b02d518b02 Tests: Lexer::Type::dom and Lexer::Type::path tests 2015-03-28 10:06:56 -04:00
Paul Beckingham
0973e6566b Tests: Added Lexer::Type::tag tests 2015-03-28 09:41:04 -04:00
Paul Beckingham
d0a9e9a253 Tests: Added Lexer::Type::substitution tests 2015-03-28 09:32:36 -04:00
Paul Beckingham
ff445c567e Unit Tests: Lexer now tests embedded and isolated tokens
- The tests are now defined in a static structure, simplifying maintenance of
  these tests.
- Instead of simply lexing large strings and checking the lexemes, the tests
  now take a single token and test it as-is ("token"), and surrounded by spaces
  (" token "), which yields surprising results.
2015-03-28 09:22:33 -04:00
Paul Beckingham
254b1eb49c Merge branch '2.4.3' of ssh://git.tasktools.org/tm/task into 2.4.3 2015-03-28 08:28:56 -04:00
Paul Beckingham
15005afd1e Unit Tests: Added tests for Lexer::Type::pattern 2015-03-28 08:24:49 -04:00
Wilhelm Schuermann
9e6c6ecb93 TW-1583: Invalid ID displayed after done/delete
- Fix completed/deleted tasks getting an ID when GC is going to be run,
  previously resulting in invalid IDs being displayed in reports that
  show non-pending tasks.

A side effect of this fix is that it is sometimes not possible to
filter by ID when running a report right after calling done/delete.
This problem existed before; this change makes it happen on the first
report instead of the second, so it is more consistently broken.
Commands that modify tasks are not affected, making this an annoying
yet harmless defect.
2015-03-28 10:36:58 +01:00
Tomas Babej
20eaa312e6 localization: Fix inconsisitent case in the legend of History commands 2015-03-27 19:23:22 -04:00
Renato Alves
fdb22ad341 Tests: Merge bug.299 with project.t and add more scenarios
* Currently one of the new scenarios fails. Looks like a bug.
2015-03-27 11:15:53 +00:00
Renato Alves
d76d5c3587 Tests: Make sleeptime in wait_conditional an argument 2015-03-27 10:53:18 +00:00
Renato Alves
526665d4ec Tests: Configurable check for taskd readyness
* Also increase the frequency from 1/s to 2/s
2015-03-27 10:51:38 +00:00
Renato Alves
834b4ddab6 Tests: Use faketime instead of time.sleep. 2015-03-27 10:14:44 +00:00
Renato Alves
357850177d Tests: common/reusable variables live in basetest.utils 2015-03-27 10:14:44 +00:00
Wilhelm Schuermann
d2e6c90446 TW-1581: Wrong urgency after done/delete command
- TDB2::dependency_scan() is run before GC, so we need to check both
  tasks in a dependency chain for their status before setting the
  blocking/blocked flag to true.
2015-03-26 18:43:58 +01:00
Paul Beckingham
96922231b8 Merge branch '2.4.3' into lexer2 2015-03-25 07:52:36 -04:00
Wilhelm Schuermann
55db1239bd Info: Hide "modified" attribute changes
- The info report shows modifications already.  "modified" attribute
  updates are implied by other attributes being changed, so there
  is no need to clutter the report with them.
2015-03-23 16:28:53 +01:00
Wilhelm Schuermann
4f75652ccb TW-1580: "modified" attribute not updated
- Make all local modifications update the "modified" attribute.
- As per design, the user cannot overwrite this attribute; neither
  can hooks.
2015-03-23 15:55:47 +01:00
Paul Beckingham
052a5c607a Documentation: 'rc.bulk=0' notes.
- Added ChangeLog and NEWS entries for the rc.bulk=0 change, where zero is
  considered infinity.
2015-03-22 11:43:00 -04:00
Tomas Babej
c306d458e0 Doc: Document bulk=0 in taskrc manpage 2015-03-22 11:41:28 -04:00
Tomas Babej
7babc9c5b1 Command: Let zero bulk denote infinite value 2015-03-22 10:10:08 -04:00
Paul Beckingham
24a1cbefe9 Merge branch '2.4.3' into lexer2 2015-03-20 17:16:48 -04:00
Paul Beckingham
289780c8cc Lexer: Added comments 2015-03-20 17:16:00 -04:00
Tomas Babej
f5af3368a9 Changelog: Record TW-1578 in the changelog 2015-03-19 21:51:09 -04:00
Tomas Babej
a2ed996102 Man: Add task calc command to the task manpage 2015-03-18 14:15:15 -04:00
Tomas Babej
704eb1eab3 scripts: Enforce disabled confirmation in bash completion
https://bug.tasktools.org/browse/TW-1578
2015-03-18 14:14:59 -04:00
Tomas Babej
484979b4e0 Man: Fix typo in allow.empty.filter description 2015-03-18 14:14:32 -04:00
Paul Beckingham
928e94a6e1 Documentation
- Updated for 2.4.3.
2015-03-15 20:19:29 -04:00
Federico Hernandez
e2c9752bc4 Bumped version number in documentation 2015-03-16 00:38:56 +01:00
Federico Hernandez
8386b702dd Bumped version number to 2.4.3 2015-03-16 00:25:55 +01:00
Federico Hernandez
48e9c0518e Added SHA1 of tagged release commit 2015-03-16 00:19:25 +01:00
Paul Beckingham
11dab68fce Unit Tests
- Longer test script names need wider padding.
- Added counts for skipped tests.
2015-03-07 17:55:42 -05:00
Paul Beckingham
29dff399bd Merge branch '2.4.2' into lexer2 2015-03-07 17:36:10 -05:00
Paul Beckingham
a75c293286 Merge branch '2.4.2' into lexer2 2015-03-07 17:33:23 -05:00
Paul Beckingham
dbf31bfce8 Unit Tests
- Added new cli.t to contain asorted command line tests.
2015-03-07 17:31:15 -05:00
Paul Beckingham
7826c7b988 CLI
- Added Lexer::Type arg to ::addArg, for future capture of type.
- Cleaned up code formatting from patch.
2015-03-07 17:29:08 -05:00
Paul Beckingham
d202691638 Lexer
- Improved comment.
2015-03-07 10:09:58 -05:00
Paul Beckingham
c9d61ff71b Duration
- Made list of units static.
2015-03-06 21:15:50 -05:00
Paul Beckingham
4118fe70ae Unit Test
- Added quotes, which is a reasonable workaround for a misinterpreted argument.
2015-03-05 21:29:38 -05:00
Paul Beckingham
e11b333a0b Lexer
- ::isPath was not observing the null character string terminator.
2015-03-05 21:22:40 -05:00
Paul Beckingham
d1f7e44811 Unit Tests
- Removed unit test for a bug that is a deliberate attempt to generate an
  ambiguous command line, to break the parser. The '--' terminator is meant
  to resolve these issues, and we don't need more tests proving that the
  grammar is ambiguous.
2015-03-02 16:44:28 -05:00
Paul Beckingham
53e9bd0cbd Lexer
- Words cannot contain single-char operators.
2015-03-02 00:03:01 -05:00
Paul Beckingham
234e4d7308 Unit Tests
- Modified Lexer types to reflect DOM recognition.
2015-03-01 23:55:10 -05:00
Paul Beckingham
237d932ff9 Lexer
- Improved ::isIdentifier, ::isUUID and ::isDOM.
2015-03-01 23:54:45 -05:00
Paul Beckingham
2af470bb90 Lexer
- Lexer::Type::identifier now includes DOM references.
2015-03-01 22:08:19 -05:00
Paul Beckingham
cefc129e9a Task
- Delegated the modifiability check to Column::modifiable.
2015-03-01 21:36:56 -05:00
Paul Beckingham
7aa55a8a71 Unit Tests
- Corrected test so it doesn't include '--' separator token.
2015-03-01 21:19:16 -05:00
Paul Beckingham
565987a177 Unit Tests
- Corrected token types for '3rd', which is Lexer::Type::word, not
  LExer::Type::identifier.
2015-03-01 21:14:28 -05:00
Paul Beckingham
309b607672 Lexer
- Number digits followed by non-whitespace, non-operators are not numbers, ie
  "2nd" is not "2","nd".
2015-03-01 16:03:10 -05:00
Paul Beckingham
abe8819f2f Unit Tests
- Restored 'name=value' tests that expect three tokens.
2015-03-01 15:53:24 -05:00
Paul Beckingham
3f2d377fef Lexer
- Allow '=' in rc.<name>[:=]<value>, but not in non-rc Lexer::Type::pair
  combinations. That means 'name=value' is not a Lexer::Type::pair.
2015-02-28 12:05:24 -05:00
Paul Beckingham
c849cc9bfe Unit Tests
- Added tests with spaces around the operators, for better coverage.
2015-02-28 12:00:36 -05:00
Paul Beckingham
7e890c084f Report
- Removed bad filter term.
2015-02-27 00:18:19 -05:00
Paul Beckingham
0f1a46e6d3 Lex
- Changed output to reflect current usage.
2015-02-27 00:17:56 -05:00
Paul Beckingham
2811b9a571 Unit Tests
- Fixed tests regarding quoted strings coming out of the Lexer.
2015-02-27 00:16:14 -05:00
Paul Beckingham
9dad0c7eb6 Merge branch '2.4.2' into lexer2 2015-02-24 23:14:58 -05:00
Paul Beckingham
e67c6c45cf Lexer
- Strings now retain their quotes, for compatibility with 2.4.1.
2015-02-24 23:01:12 -05:00
Paul Beckingham
8c6892fed6 Merge branch '2.4.2' into lexer2 2015-02-24 17:03:11 -05:00
Paul Beckingham
0548fca88f Merge branch '2.4.2' into lexer2 2015-02-23 20:22:34 -05:00
Paul Beckingham
26aff348d2 Lexer
- Replaced old digitsOnly() function with Lexer::isAllDigits.
2015-02-22 20:23:00 -05:00
Paul Beckingham
9f82926c65 Text
- Removed obsolete noSpaces() function.
2015-02-22 18:27:19 -05:00
Paul Beckingham
8791c0a921 Lexer
- Migrated old noSpaces() function into Lexer::isOneWord.
2015-02-22 18:23:26 -05:00
Paul Beckingham
745aad0d27 Lexer
- Renamed Lexer2 to Lexer, it looks good enough to assume control.
2015-02-22 18:23:03 -05:00
Paul Beckingham
e1c0d5b130 Merge branch '2.4.2' into lexer2 2015-02-22 15:26:22 -05:00
Paul Beckingham
9898aa15b5 Merge branch '2.4.2' into lexer2 2015-02-22 14:06:01 -05:00
Paul Beckingham
0cf18f3b16 Lexer2
- Integrated Lexer2 in place of Lexer. Tests fail.
2015-02-22 13:52:14 -05:00
Paul Beckingham
2155bd3969 Lexer2
- Implemented ::isAllDigits to distinguish between integers and real numbers.
2015-02-21 10:58:07 -08:00
Paul Beckingham
ae6024ef8b Lex
- Added a 'lex' binary to test Lexer2.
2015-02-21 10:03:17 -08:00
Paul Beckingham
21553d9044 Lexer2
- Implemented ::isDate and ::isDuration.
2015-02-21 10:01:59 -08:00
Paul Beckingham
d6e3430e0d Lexer2
- Implemented ::split for typeless tokenization.
2015-02-21 09:28:56 -08:00
Paul Beckingham
0d23511cee Lexer2
- Stubbed ::isDate and ::isDuration methods.
2015-02-21 09:19:24 -08:00
Paul Beckingham
1128ad8259 Lexer2
- Improved ::isUUID lexing.
2015-02-20 12:13:11 -08:00
Paul Beckingham
66d5a8ba3d Lexer2
- Migrated new ::isURL and ::isPath methods.
- Migrated new ::tokens method to access all tokens at once.
2015-02-20 12:05:03 -08:00
Paul Beckingham
aab93b2cda Lexer2
- Migrated ::dequote method from Lexer.
2015-02-19 21:43:22 -08:00
Paul Beckingham
be80bc4ea3 Converted to Lexer2. 2015-02-19 21:36:04 -08:00
Paul Beckingham
15bec27e03 Converted to Lexer2. 2015-02-19 21:32:51 -08:00
Paul Beckingham
6683cc7e83 Converted to Lexer2. 2015-02-19 21:31:47 -08:00
Paul Beckingham
044ca40bb7 Merge branch '2.4.2' into lexer2 2015-02-19 21:00:27 -08:00
Paul Beckingham
d10ad5c7af Lexer2
- Copied in the Lexer2 object.
2015-02-19 08:54:20 -08:00
164 changed files with 4545 additions and 3245 deletions

View File

@@ -1,4 +1,4 @@
The development of taskwarrior was made possible by the significant
The development of Taskwarrior was made possible by the significant
contributions of the following people:
Paul Beckingham (Principal Author)
@@ -115,6 +115,8 @@ The following submitted code, packages or analysis, and deserve special thanks:
Łukasz Panek
V.Krishn
Jens Erat
Peter Rochen
Oota Toshiya
Thanks to the following, who submitted detailed bug reports and excellent
suggestions:
@@ -246,3 +248,6 @@ suggestions:
Taisuke Hachimura
Martin
Alexandre de Verteuil
Scott M
Stefan Frühwirth
Pierre Campet

View File

@@ -10,7 +10,7 @@ include (CheckStructHasMember)
set (HAVE_CMAKE true)
project (task)
set (PROJECT_VERSION "2.4.2")
set (PROJECT_VERSION "2.4.4")
OPTION(USE_GNUTLS "Build gnutls support." ON)
@@ -68,6 +68,8 @@ endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set (CMAKE_CXX_FLAGS "${_CXX11_FLAGS} ${CMAKE_CXX_FLAGS}")
set (CMAKE_CXX_FLAGS "-Wall -Wsign-compare -Wreturn-type ${CMAKE_CXX_FLAGS}")
if (NETBSD)
# Since readline, etc likely to be in /usr/pkg/lib, not standard library
# Otherwise will remove links during install
@@ -161,6 +163,7 @@ set (LANGUAGE_ITA_ITA 5)
set (LANGUAGE_POR_PRT 6)
set (LANGUAGE_EPO_RUS 7)
set (LANGUAGE_POL_POL 8)
set (LANGUAGE_JPN_JPN 9)
message ("-- Configuring cmake.h")
configure_file (

View File

@@ -1,4 +1,4 @@
taskwarrior - a command line task list manager.
Taskwarrior - a command line task list manager.
Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.

View File

@@ -1,4 +1,65 @@
2.4.2 (2015-03-15) -
2.4.4 (2015-05-10) -
- TW-69 wait dates relative to due date (thanks to John Florian).
- TW-1285 I'd like to use relative dates combined with times (thanks to Adam
Gibbins).
- TW-1474 Documentation is confusing with respect to user/uuid on the server
(thanks to Tomas Babej).
- TW-1596 taskwarrior can't compile FreeBSD 9.3 32bit environment (thanks to
ribbon)
- TW-1603 Priority color precedence changed since it is a UDA, should be lowered
again (thanks to Jens Erat).
- TW-1605 Japanese translation for Taskwarrior (thanks to Oota Toshiya).
- TW-1606 scheduled.any filter (thanks to Peter Rochen).
- TW-1608 The recur/recurring report shows tasks without a recur interval
(thanks to Brad Collette).
- TW-1610 Disabling GC can lead to editing the wrong task (thanks to Scott M).
- The 'obfuscate' setting, if set to '1' will replace all text with 'xxx'.
- POSIX file locking mechanism, eliminating platform-specific code.
------ current release ---------------------------
2.4.3 (2015-04-19) 499044b9b6bdbc95338ea585204e949d80b24a09
- TW-57 user defined attribute sort order (thanks to Max Muller).
- TW-70 urgency.user.keyword.<keyword>.coefficient=...
- TW-111 User-defined priorities.
- TW-1279 Make default.* not apply to recurring tasks.
- TW-1287 Make default.* not apply to synced tasks.
- TW-1539 user-defined urgency coefficients for priority values.
- TW-1541 Priority should be converted to UDA (in default taskrc) (thanks to
Tomas Babej).
- TW-1556 task hangs when modifying uda field with percent-encoded (url-encoded)
value (thanks to Stefan Frühwirth).
- TW-1578 Bash tab completion problems on first run
(thanks to Renato Alves and Ptolemarch).
- TW-1580 "modified" attribute no longer updated (thanks to David Patrick).
- TW-1581 Tasks with dependencies show wrong urgency values for the first
report run after a task in the dependency chain is completed/deleted (thanks
to Ulf Eliasson).
- TW-1583 Invalid ID displayed for first report after done/delete (thanks to
Ulf Eliasson).
- TW-1584 attr.{isnt,not} use partial matching.
- TW-1587 Fix and improve example on-exit hook, adjust to new hooks API
(thanks to Jochen Sprickerhof).
- TW-1588 Most Export scripts cannot deal with new export format (thanks to
Scott Carter).
- TW-1590 syntax of rcfile not documented (whitespace, line continuation)
(thanks to Scott M).
- TW-1591 add an option to see non-pending project with command task summary
(thanks to Pierre Campet).
- TW-1595 info command doesn't print urgency details, if urgency is negative
(thanks to Peter Rochen).
- Setting 'bulk' to zero is interpreted as infinity, which means there is no
amount of changes that is considered dangerous (thanks to Tomas Babej).
- Disable hooks in bash completion script. Hooks were previously able to
abort processing or output interfering data, breaking completion.
- Fix "task add due:tomorrow+3days" failing to work without spaces.
- Performance improvements:
+ Stops after measuring a fixed-width column format.
+ Reduced number of std::string copies.
2.4.2 (2015-03-15) b9dc0813d9a8922b4cef9595033f133f9fbabf44
- TW-41 Tasks in subprojects are not counted in project completion (thanks
to Renato Alves).
@@ -27,8 +88,6 @@
- 'task _version' now outputs "2.4.2 (git-ref)" when built from git. "2.4.2"
when built from release tarballs (thanks to Renato Alves).
------ current release ---------------------------
2.4.1 (2015-02-16) 82e019a4a8b20de63d53b51d59b8d1c89d3c05b2
- TW-1457 Non-existent attributes are not properly handled (thanks to Tomas

View File

@@ -1,16 +1,15 @@
How to Build Taskwarrior
Satisfy the Requirements:
- gcc 4.4 or later, clang 2.9 or later or equivalent. This is because 2.4.1
marks the first step towards using modern C++11. Initially this involves
only feature N1984.
- gcc 4.7 or later, clang 3.3 or later or equivalent. This is because 2.4.4
will be utilizing C++11.
- libuuid
- gnutls (optional)
Obtain and build code:
$ git clone https://git.tasktools.org/scm/tm/task.git task.git
$ cd task.git
$ git checkout 2.4.2 # Latest dev branch
$ git checkout 2.4.4 # Latest dev branch
$ cmake -DCMAKE_BUILD_TYPE=debug . # debug or release. Default: neither.
$ make VERBOSE=1 # Shows details
@@ -189,11 +188,11 @@ Work in Progress
Current Codebase Condition
'master' branch:
- 2.4.1 Current release, locked.
- 2.4.3 Current release, locked.
'2.4.2' branch:
'2.4.4' branch:
- Current development branch no plans yet.
---
2015-02-14 Updated for 2.4.1
2015-04-21 Updated for 2.4.4

60
INSTALL
View File

@@ -1,23 +1,25 @@
Installation Instructions
-------------------------
Please follow the instructions below to build task with cmake.
Please follow the instructions below to build and install Taskwarrior from
source.
Pre-requisites
--------------
You will need the CMake build system installed in order to build taskwarrior
You will need the CMake build system installed in order to build Taskwarrior
from source. More information on cmake can be obtained at http://cmake.org
You will need a C++ compiler that supports C++11 N1984, which includes:
You will also need:
- make
- gcc 4.4 (released 2009-04-21)
- clang 2.9 (released 2011-04-06)
You will need a C++ compiler that supports full C++11, which includes:
- gcc 4.7 (released 2012-03-23)
- clang 3.3 (released 2013-01-07)
In addition:
- uuid lib
You will need the following libraries:
- libuuid
- gnutls (optional - for syncing)
It is HIGHLY RECOMMENDED that you build with a library that provides uuid_*
@@ -27,14 +29,14 @@ functions, such as libuuid.
Basic Installation
------------------
Briefly, these shell commands will unpack, build and install taskwarrior:
Briefly, these shell commands will unpack, build and install Taskwarrior:
$ tar xzf task-X.Y.Z.tar.gz [1]
$ cd task-X.Y.Z [2]
$ cmake . [3]
$ make [4]
$ sudo make install [5]
$ cd .. ; rm -r task-X.Y.Z [6]
$ tar xzf task-X.Y.Z.tar.gz [1]
$ cd task-X.Y.Z [2]
$ cmake . [3]
$ make [4]
$ sudo make install [5]
$ cd .. ; rm -r task-X.Y.Z [6]
These commands are explained below:
@@ -46,7 +48,7 @@ These commands are explained below:
3. Invokes CMake to scan for dependencies and machine-specific details, then
generate the makefiles. This may take a minute.
4. Builds taskwarrior. This may take a minute.
4. Builds Taskwarrior. This may take a minute.
5. Installs the program, documentation and other data files.
@@ -107,24 +109,24 @@ Currently the defined languages are:
epo_RUS 7
pol_POL 8
Uninstallation
--------------
To uninstall taskwarrior, you need the Makefiles, so if you deleted them in
step 7 above, they must first be regenerated by following steps [1], [2] and
[3]. Then simply run:
There is no uninstall option in CMake makefiles. This is a manual process.
$ sudo make uninstall TODO TODO TODO -- cmake doesn't include uninstall
To uninstall Taskwarrior, remove the files listed in the install_manifest.txt
file that was generated when you built Taskwarrior.
Taskwarrior Build Notes
-----------------------
Taskwarrior has dependencies that are detected by cmake in almost all cases, but
Taskwarrior has dependencies that are detected by CMake in almost all cases, but
there are situations and operating systems that mean you will need to offer a
little help.
If taskwarrior will not build on your system, first take a look at the Operating
If Taskwarrior will not build on your system, first take a look at the Operating
System notes below. If this doesn't help, then go to the Troubleshooting
section, which includes instructions on how to contact us for help.
@@ -152,6 +154,18 @@ Darwin, 32bit
http://stackoverflow.com/questions/6077414/cmake-how-to-set-the-ldflags-in-cmakelists-txt
OpenBSD
In order to build Taskwarrior 2.4.2+, you might need to install a newer GCC
version from ports or packages.
Afterwards, run
cmake -DCMAKE_CXX_COMPILER=eg++ .
and build normally.
See: https://bug.tasktools.org/browse/TW-1579
Troubleshooting
---------------
@@ -168,7 +182,7 @@ If a build does not succeed, please send the contents of the 'CMakeCache.txt'
and 'CMakeFiles/CMakeOutput.log' files to support@taskwarrior.org, or post a
message in the support forums at taskwarrior.org along with the information.
If CMake runs but taskwarrior does not build, please send the contents of the
If CMake runs but Taskwarrior does not build, please send the contents of the
above files as well as a transcript from the build, which is not written to a
file and must be captured from the terminal.

View File

@@ -1,4 +1,4 @@
taskwarrior - a command line task list manager.
Taskwarrior - a command line task list manager.
Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.

40
NEWS
View File

@@ -1,39 +1,29 @@
New Features in taskwarrior 2.4.2
New Features in Taskwarrior 2.4.4
- Ability to set context, which serves as a permanent user-defined filter.
- The 'info' command now shows virtual tags.
- Taskwarrior now requires GCC 4.7+ / Clang 3.3+, for full C++11 support.
- Taskwarrior now builds properly on 32-bit platforms.
- The beginnings of a Japaneѕe translation.
New commands in taskwarrior 2.4.2
- The 'context' command has been added, along with it subcommands 'define',
'delete', 'show', 'list' and 'none'.
New configuration options in taskwarrior 2.4.2
- 'context' to store the current context applied.
- 'context.<name>' to store the definition of context 'name'
Newly deprecated features in taskwarrior 2.4.2
New commands in Taskwarrior 2.4.4
- None
Removed features in 2.4.2
New configuration options in Taskwarrior 2.4.4
- The 'obfuscate' setting, if set to '1' will replace all text with 'xxx'.
This is useful when sharing data for bug reporting purposes.
Newly deprecated features in Taskwarrior 2.4.4
- None
Removed features in 2.4.4
- None
Known Issues
- If you upgraded from Taskwarrior 2.3.0, you will need one of the following
settings to allow continued syncing to a Taskserver:
$ task config taskd.trust strict
$ task config taskd.trust 'ignore hostname'
$ task config taskd.trust 'allow all'
These are presented in order of preference from most to least secure, and
depend on how your certs were generated.
- https://bug.tasktools.org/
Taskwarrior has been built and tested on the following configurations:

View File

@@ -39,7 +39,7 @@ Please send your code patches to:
support@taskwarrior.org
Consider joining bug.tasktools.org, answers.tasktools.org and participating in
the future of taskwarrior.
the future of Taskwarrior.
---

View File

@@ -27,6 +27,7 @@
#define LANGUAGE_POR_PRT ${LANGUAGE_POR_PRT}
#define LANGUAGE_EPO_RUS ${LANGUAGE_EPO_RUS}
#define LANGUAGE_POL_POL ${LANGUAGE_POL_POL}
#define LANGUAGE_JPN_JPN ${LANGUAGE_JPN_JPN}
/* git information */
#cmakedefine HAVE_COMMIT
@@ -51,12 +52,6 @@
/* Found the GnuTLS library */
#cmakedefine HAVE_LIBGNUTLS
/* Found the Readline library */
#cmakedefine HAVE_READLINE
/* Found the pthread library */
#cmakedefine HAVE_LIBPTHREAD
/* Found tm_gmtoff */
#cmakedefine HAVE_TM_GMTOFF

View File

@@ -1,81 +0,0 @@
# - Find the readline library
# This module defines
# READLINE_INCLUDE_DIR, path to readline/readline.h, etc.
# READLINE_LIBRARIES, the libraries required to use READLINE.
# READLINE_FOUND, If false, do not try to use READLINE.
# also defined, but not for general use are
# READLINE_readline_LIBRARY, where to find the READLINE library.
# READLINE_ncurses_LIBRARY, where to find the ncurses library [might not be defined]
# Apple readline does not support readline hooks
# So we look for another one by default
IF (APPLE OR FREEBSD)
FIND_PATH (READLINE_INCLUDE_DIR NAMES readline/readline.h PATHS
/usr/include/
/sw/include
/opt/local/include
/opt/include
/usr/local/include
NO_DEFAULT_PATH
)
ENDIF (APPLE OR FREEBSD)
FIND_PATH (READLINE_INCLUDE_DIR NAMES readline/readline.h)
# Apple readline does not support readline hooks
# So we look for another one by default
IF (APPLE OR FREEBSD)
FIND_LIBRARY (READLINE_readline_LIBRARY NAMES readline PATHS
/usr/lib
/sw/lib
/opt/local/lib
/opt/lib
/usr/local/lib
NO_DEFAULT_PATH
)
ENDIF (APPLE OR FREEBSD)
FIND_LIBRARY (READLINE_readline_LIBRARY NAMES readline)
# Sometimes readline really needs ncurses
IF (APPLE OR FREEBSD)
FIND_LIBRARY (READLINE_ncurses_LIBRARY NAMES ncurses PATHS
/usr/lib
/sw/lib
/opt/local/lib
/opt/lib
/usr/local/lib
/usr/lib
NO_DEFAULT_PATH
)
ENDIF (APPLE OR FREEBSD)
FIND_LIBRARY (READLINE_ncurses_LIBRARY NAMES ncurses)
MARK_AS_ADVANCED (
READLINE_INCLUDE_DIR
READLINE_readline_LIBRARY
READLINE_ncurses_LIBRARY
)
SET (READLINE_FOUND "NO" )
IF (READLINE_INCLUDE_DIR)
IF (READLINE_readline_LIBRARY)
SET (READLINE_FOUND "YES" )
SET (READLINE_LIBRARIES
${READLINE_readline_LIBRARY}
)
# some readline libraries depend on ncurses
IF (READLINE_ncurses_LIBRARY)
SET (READLINE_LIBRARIES ${READLINE_LIBRARIES} ${READLINE_ncurses_LIBRARY})
ENDIF (READLINE_ncurses_LIBRARY)
ENDIF (READLINE_readline_LIBRARY)
ENDIF (READLINE_INCLUDE_DIR)
IF (READLINE_FOUND)
MESSAGE (STATUS "Found readline library")
ELSE (READLINE_FOUND)
IF (READLINE_FIND_REQUIRED)
MESSAGE (FATAL_ERROR "Could not find readline -- please give some paths to CMake")
ENDIF (READLINE_FIND_REQUIRED)
ENDIF (READLINE_FOUND)

View File

@@ -1,7 +1,7 @@
.TH task-color 5 2015-03-15 "${PACKAGE_STRING}" "User Manuals"
.TH task-color 5 2015-05-10 "${PACKAGE_STRING}" "User Manuals"
.SH NAME
task-color \- A color tutorial for the taskwarrior command line todo manager.
task-color \- A color tutorial for the Taskwarrior command line todo manager.
.SH SETUP
The first thing you need is a terminal program that supports color. All
@@ -18,8 +18,8 @@ which shell you use). If this is a new setting, you will need to either run
that profile script, or close and reopen the terminal window (which does the
same thing).
Now tell taskwarrior that you want to use color. This is the default for
taskwarrior, so the following step may be unnecessary.
Now tell Taskwarrior that you want to use color. This is the default for
Taskwarrior, so the following step may be unnecessary.
$ task config color on
@@ -28,11 +28,11 @@ like:
color=on
Now taskwarrior is ready.
Now Taskwarrior is ready.
.SH AUTOMATIC MONOCHROME
It should be mentioned that taskwarrior is aware of whether its output is going
to a terminal, or to a file or through a pipe. When taskwarrior output goes to
It should be mentioned that Taskwarrior is aware of whether its output is going
to a terminal, or to a file or through a pipe. When Taskwarrior output goes to
a terminal, color is desirable, but consider the following command:
$ task list > file.txt
@@ -268,7 +268,7 @@ from the example):
include ${CMAKE_INSTALL_PREFIX}/${TASK_RCDIR}/dark-256.theme
.RE
You can use any of the standard taskwarrior themes:
You can use any of the standard Taskwarrior themes:
.RS
dark-16.theme
@@ -323,7 +323,7 @@ http://www.opensource.org/licenses/mit-license.php for more information.
.BR taskrc(5),
.BR task-sync(5)
For more information regarding taskwarrior, the following may be referenced:
For more information regarding Taskwarrior, the following may be referenced:
.TP
The official site at
@@ -339,5 +339,5 @@ You can contact the project by writing an email to
.SH REPORTING BUGS
.TP
Bugs in taskwarrior may be reported to the issue-tracker at
Bugs in Taskwarrior may be reported to the issue-tracker at
<http://taskwarrior.org>

View File

@@ -1,4 +1,4 @@
.TH task-sync 5 2015-03-15 "${PACKAGE_STRING}" "User Manuals"
.TH task-sync 5 2015-05-10 "${PACKAGE_STRING}" "User Manuals"
.SH NAME
task-sync \- A discussion and tutorial for the various task(1) data
@@ -80,24 +80,25 @@ The Taskserver was designed for this purpose to be secure, fast and conflict
free, allowing data interchange between assorted Taskwarrior clients, and
tolerant of network connectivity problems.
There is a 'sync' command built in to Taskwarrior, and with a server account
and client configuration, syncing is done on demand.
There is a 'sync' command built in to Taskwarrior (provided the GnuTLS library
is installed), and with a server account and client configuration, syncing is
done on demand.
Setup is a matter of creating an account on a Taskserver (see your Taskserver
provider or operate your own - see
http://taskwarrior.org/docs/server_setup.html)
Once you have an account, you'll receive a certificate, key and a password.
Once you have an account, you'll receive a certificate, key, and credentials.
You'll need to put the certificate and key somewhere like this:
$ cp <name>.cert.pem ~/.task
$ cp <name>.key.pem ~/.task
Then you configure Taskwarrior, using the account details:
Then you configure Taskwarrior, using the provided details:
$ task config taskd.certificate ~/.task/<name>.cert.pem
$ task config taskd.key ~/.task/<name>.key.pem
$ task config taskd.credentials <organization>/<name>/<password>
$ task config taskd.credentials <organization>/<name>/<UUID>
$ task config taskd.server <server domain>:<port>
If you are using a private server, you are likely also using a self-signed
@@ -108,7 +109,7 @@ certificate, which means you will need one of the following additional entries:
The CA (Certificate Authority) will be used to verify the server certificate.
Alternatively, you can override the cert verification process using:
$ task config taskd.trust yes
$ task config taskd.trust 'allow all'
This is an insecure option that should be used with caution, because it directs
Taskwarrior to trust any certificate.

View File

@@ -1,4 +1,4 @@
.TH task 1 2015-03-15 "${PACKAGE_STRING}" "User Manuals"
.TH task 1 2015-05-10 "${PACKAGE_STRING}" "User Manuals"
.SH NAME
task \- A command line todo manager.
@@ -14,7 +14,7 @@ that you want to do, allowing you to add/remove, and otherwise manipulate them.
Taskwarrior has a rich set of subcommands that allow you to do various things
with it.
At the core, taskwarrior is a list processing program. You add text and
At the core, Taskwarrior is a list processing program. You add text and
additional related parameters and redisplay the information in a nice way. It
turns into a todo list program when you add due dates and recurrence. It turns
into an organized todo list program when you add priorities, tags (one word
@@ -98,7 +98,7 @@ generated, as with verbose=nothing).
.SH READ SUBCOMMANDS
Reports are read subcommands. There are several reports currently predefined in
taskwarrior. The output and sort behavior of these reports can be configured in
Taskwarrior. The output and sort behavior of these reports can be configured in
the configuration file. See also the man page taskrc(5). There are also other
read subcommands that are not reports.
@@ -379,9 +379,25 @@ time from the specified task.
Miscellaneous subcommands either accept no command line arguments, or accept
non-standard arguments.
.TP
.B task calc <expression>
Evaluates an algebraic expression. Can be used to test how Taskwarrior
parses and evaluates the expression given on the command line.
Examples:
task calc 1 + 1
2
task calc now + 8d
2015-03-26T18:06:57
task calc eom
2015-03-31T23:59:59
.TP
.B task config [name [value | '']]
Add, modify and remove settings directly in the taskwarrior configuration.
Add, modify and remove settings directly in the Taskwarrior configuration.
This command either modifies the 'name' setting with a new value of 'value',
or adds a new entry that is equivalent to 'name=value':
@@ -398,7 +414,7 @@ Finally, this command removes any 'name=...' entry from the .taskrc file:
.TP
.B task context <name>
Sets the currectly active context. See the CONTEXT section.
Sets the currently active context. See the CONTEXT section.
Example:
@@ -494,7 +510,7 @@ Reverts the most recent action. Obeys the confirmation setting.
.TP
.B task version
Shows the taskwarrior version number.
Shows the Taskwarrior version number.
.SH HELPER SUBCOMMANDS
@@ -550,7 +566,7 @@ Displays the urgency measure of a task.
.TP
.B task _version
Shows only the taskwarrior version number.
Shows only the Taskwarrior version number.
.TP
.B task _zshcommands
@@ -854,7 +870,7 @@ The original example therefore must be entered as:
task '( project:Home or project:Garden )' list
This includes quotes to escape the parentheses, so that the shell doesn't
interpret them and hide them from taskwarrior.
interpret them and hide them from Taskwarrior.
There is redundancy between operators, attribute modifiers and other syntactic
sugar. For example, the following are all equivalent:
@@ -1067,7 +1083,7 @@ Contexts are permanent, and the currently set context name is stored in the
"context.<name>" configuration variable.
.SH COMMAND ABBREVIATION
All taskwarrior commands may be abbreviated as long as a unique prefix is used,
All Taskwarrior commands may be abbreviated as long as a unique prefix is used,
for example:
.RS
@@ -1106,7 +1122,7 @@ $ task add "quoted ' quote"
$ task add escaped \\' quote
.RE
The argument \-\- (a double dash) tells taskwarrior to treat all other args
The argument \-\- (a double dash) tells Taskwarrior to treat all other args
as description:
.RS
@@ -1203,7 +1219,7 @@ http://www.opensource.org/licenses/mit-license.php for more information.
.BR task-color(5),
.BR task-sync(5)
For more information regarding taskwarrior, see the following:
For more information regarding Taskwarrior, see the following:
.TP
The official site at
@@ -1219,6 +1235,6 @@ You can contact the project by emailing
.SH REPORTING BUGS
.TP
Bugs in taskwarrior may be reported to the issue-tracker at
Bugs in Taskwarrior may be reported to the issue-tracker at
<http://taskwarrior.org>

View File

@@ -1,4 +1,4 @@
.TH taskrc 5 2015-03-15 "${PACKAGE_STRING}" "User Manuals"
.TH taskrc 5 2015-05-10 "${PACKAGE_STRING}" "User Manuals"
.SH NAME
taskrc \- Configuration details for the task(1) command
@@ -11,7 +11,7 @@ taskrc \- Configuration details for the task(1) command
.B TASKRC=<directory-path>/.taskrc task ...
.SH DESCRIPTION
.B taskwarrior
.B Taskwarrior
obtains its configuration data from a file called
.I .taskrc
\&. This file is normally located in the user's home directory:
@@ -49,43 +49,56 @@ $ task rc.<name>=<value> ...
.RE
If
.B taskwarrior
.B Taskwarrior
is run without an existing configuration file it will ask if it should create a
default, sample
.I .taskrc
file in the user's home directory.
The taskwarrior configuration file consists of a series of assignments in each
line. The assignments have the syntax:
The .taskrc file follows a very simply syntax defining name/value pairs:
.RS
<name-of-configuration-variable>=<value-to-be-set>
<name> = <value>
.RE
where:
.RS
.TP
<name-of-configuration-variable>
is one of the variables described below
There may be whitespace around <name>, '=' and <value>, and it is ignored.
Whitespace within the <value> is left intact.
Whitespace is not permitted in comma-separated lists.
The entry must be on a single line, no continuations.
Values support UTF8 as well as JSON encoding, such as \\uNNNN.
.TP
<value-to-be-set>
is the value the variable is to be set to.
.RE
and set a configuration variable to a certain value. The equal sign ("=") is
used to separate the variable name from the value to be set.
The hash mark, or pound sign ("#") is used as a comment character. It can be
used to annotate the configuration file. All text after the character to the end
of the line is ignored.
The configuration file supports UTF8 as well as JSON encoding, such as \\uNNNN.
Note that taskwarrior is flexible about the values used to represent Boolean
Note that Taskwarrior is flexible about the values used to represent Boolean
items. You can use "on", "yes", "y", "1" and "true".
Anything else means "off".
.RS
include <file>
.RE
There may be whitespace around 'include' and <file>. The file may be an
absolute or relative path, and the special character '~' is expanded to mean
$HOME.
The entry must be on a single line, no continuations.
.RS
# <comment>
.RE
A comment consists of the character '#', and extends from the '#' to the end
of the line. There is no way to comment a multi-line block. There may be
blank lines.
Almost every value has a default setting, and an empty .taskrc file is one
that makes use of every default. The contents of the .taskrc file therefore
represent overrides of the default values. To remove a default value completely
there must be an entry like this:
.RS
<name> =
.RE
This entry overrides the default value with a blank value.
.SH EDITING
You can edit your .taskrc file by hand if you wish, or you can use the 'config'
command. To permanently set a value in your .taskrc file, use this command:
@@ -136,7 +149,7 @@ include ${CMAKE_INSTALL_PREFIX}/${TASK_RCDIR}/holidays.en-US.rc
include ${CMAKE_INSTALL_PREFIX}/${TASK_RCDIR}/dark-16.theme
.RE
This includes two standard files that are distributed with taskwarrior, which
This includes two standard files that are distributed with Taskwarrior, which
define a set of US holidays, and set up a 16-color theme to use, to color the
reports and calendar.
@@ -145,7 +158,7 @@ These environment variables override defaults and command line arguments.
.TP
.B TASKDATA=~/.task
This overrides the default path for the taskwarrior data files.
This overrides the default path for the Taskwarrior data files.
.TP
.B TASKRC=~/.taskrc
@@ -158,7 +171,7 @@ Valid variable names and their default values are:
.TP
.B data.location=$HOME/.task
This is a path to the directory containing all the taskwarrior files. By
This is a path to the directory containing all the Taskwarrior files. By
default, it is set up to be ~/.task, for example: /home/paul/.task
Note that you can use the
@@ -281,14 +294,14 @@ and project. The others are sent to standard output.
.TP
.B confirmation=yes
May be "yes" or "no", and determines whether taskwarrior will ask for
May be "yes" or "no", and determines whether Taskwarrior will ask for
confirmation before deleting a task or performing the undo command. The default
value is "yes". Consider leaving this setting as "yes", for safety.
.TP
.B allow.empty.filter=yes
An empty filter combined with a write command is potentially a way to modify
all tasks by mistkae, and when this is detected, confirmation is required.
all tasks by mistake, and when this is detected, confirmation is required.
Setting this to 'no' means that it is an error to use a write command with no
filter.
@@ -314,23 +327,28 @@ Controls padding between columns of the report output. Default is "1".
Is a number, defaulting to 3. When this number or greater of tasks are modified
in a single command, confirmation will be required, regardless of the value of
.B confirmation
variable.
variable. The special value bulk=0 is treated as an infinity.
This is useful for preventing large-scale unintended changes.
.TP
.B nag=You have more urgent tasks.
This may be a string of text, or blank. It is used as a prompt when a task is
started or completed that is not considered high priority. Default value is:
You have more urgent tasks. It is a gentle reminder that you are contradicting
your own priority settings.
This may be a string of text, or blank. It is used as a prompt when a task is
started of completed, when there are other tasks with a higher urgency.
Default value is: 'You have more urgent tasks'.
It is a gentle reminder that you are contradicting your own urgency settings.
.TP
.B list.all.projects=yes
.B list.all.projects=no
May be yes or no, and determines whether the 'projects' command lists all the project
names you have used, or just the ones used in active tasks. The default value is
"no".
.TP
.B summary.all.projects=no
If set to yes, shows all projects in the summary report, even if there are no
pending tasks. The default value is "no".
.TP
.B complete.all.tags=yes
May be yes or no, and determines whether the tab completion scripts consider all
@@ -370,7 +388,7 @@ Defaults to infix.
.TP
.B dom=on
Enables or disables access to taskwarrior internals and task metadata on the
Enables or disables access to Taskwarrior internals and task metadata on the
command line. Defaults to on.
.TP
@@ -436,7 +454,7 @@ and one for a week from tomorrow.
.TP
.B undo.style=side
When the 'undo' command is run, taskwarrior presents a before and after
When the 'undo' command is run, Taskwarrior presents a before and after
comparison of the data. This can be in either the 'side' style, which compares
values side-by-side in a table, or 'diff' style, which uses a format similar to
the 'diff' command.
@@ -484,6 +502,12 @@ shows parse trees from every phase of the parse.
Controls the GnuTLS diagnostic level. For 'sync' debugging. Level 0 means no
diagnostics. Level 9 is the highest. Level 2 is a good setting for debugging.
.TP
.B obfuscate=1
When set to '1', will replace all report text with 'xxx'.
This is useful for sharing report output in bug reports.
Default value is '0'.
.TP
.B alias.rm=delete
Taskwarrior supports command aliases. This alias provides an alternate name
@@ -507,7 +531,7 @@ the 'history' report, for example, or 'export'.
.B dateformat.annotation=
.TP
.B report.X.dateformat=Y-M-D
This is a string of characters that defines how taskwarrior formats date values.
This is a string of characters that defines how Taskwarrior formats date values.
The precedence order for the configuration variable is report.X.dateformat then
dateformat.report then dateformat for formating the due dates in reports.
If both report.X.dateformat and dateformat.report are not set then dateformat
@@ -737,7 +761,7 @@ holiday.eastersunday.date=easter
.RE
.RE
Note that the taskwarrior distribution contains example holiday files that can
Note that the Taskwarrior distribution contains example holiday files that can
be included like this:
.RS
@@ -751,7 +775,7 @@ include ${CMAKE_INSTALL_PREFIX}/${TASK_RCDIR}/holidays.en-US.rc
.B monthsperline=3
Determines how many months the "task calendar" command renders across the
screen. Defaults to however many will fit. If more months than will fit are
specified, taskwarrior will only show as many that will fit.
specified, Taskwarrior will only show as many that will fit.
.SS DEPENDENCIES
@@ -767,7 +791,7 @@ Determines whether dependency chain repair requires confirmation.
.TP
.B color=on
May be "on" or "off". Determines whether taskwarrior uses color. When "off",
May be "on" or "off". Determines whether Taskwarrior uses color. When "off",
will use dashes (-----) to underline column headings.
.TP
@@ -828,18 +852,6 @@ Task has at least one tag.
.B color.recurring
Task is recurring.
.br
.B color.pri.H
Task has priority H.
.br
.B color.pri.M
Task has priority M.
.br
.B color.pri.L
Task has priority L.
.br
.B color.pri.none
Task has no priority.
.br
.B color.completed
Task is completed.
.br
@@ -1058,10 +1070,6 @@ Urgency inherited from dependency chain
.RS
Urgency coefficient for due dates
.RE
.B urgency.priority.coefficient=6.0
.RS
Urgency coefficient for priorities
.RE
.B urgency.waiting.coefficient=-3.0
.RS
Urgency coefficient for waiting status
@@ -1102,6 +1110,10 @@ Specific tag coefficient.
.RS
Specific project coefficient.
.RE
.B urgency.user.keyword.<keyword>.coefficient=...
.RS
Specific description keyword coefficient.
.RE
.B urgency.uda.<name>.coefficient=...
.RS
Presence/absence of UDA data.
@@ -1124,13 +1136,6 @@ Provides a default project name for the
.I task add
command, if you don't specify one. The default is blank.
.TP
.B
default.priority=M
Provides a default priority for the
.I task add
command, if you don't specify one. The default is blank.
.TP
.B
default.due=...
@@ -1149,7 +1154,7 @@ command, if you don't specify values. The default is blank.
.TP
.B
default.command=next
Provides a default command that is run every time taskwarrior is invoked with no
Provides a default command that is run every time Taskwarrior is invoked with no
arguments. For example, if set to:
.RS
@@ -1159,7 +1164,7 @@ default.command=project:foo list
.RE
.RS
then taskwarrior will run the "project:foo list" command if no command is
then Taskwarrior will run the "project:foo list" command if no command is
specified. This means that by merely typing
.RE
@@ -1336,19 +1341,36 @@ Provides a default report label for the UDA called '<name>'.
For type 'string' UDAs only, this provides a comma-separated list of acceptable
values. In this example, the '<name>' UDA may only contain values 'A', 'B',
or 'C', but may also contain no value.
Note that the order of the value is important, and denotes the sort order from
highest ('A') to lowest ('C').
Note that a blank value is permitted.
.RE
.TP
.B uda.<name>.default=...
.RS
Provides a default value for the UDA called '<name>'.
.RE
.TP
.B Example 'estimate' UDA
This example shows an 'estimate' UDA that stores specific values for the size
of a task.
of a task. Note the blank value after 'trivial'.
.RS
.B uda.estimate.type=string
.br
.B uda.estimate.label=Size Estimate
.br
.B uda.estimate.values=trivial,small,medium,large,huge
.B uda.estimate.values=huge,large,medium,small,trivial,
.RE
.RS
Note that the value are sorted
huge > large > medium > small > trivial > ''
.RE
.SS CONTEXT
@@ -1441,7 +1463,7 @@ http://www.opensource.org/licenses/mit-license.php for more information.
.BR task-color(5),
.BR task-sync(5)
For more information regarding taskwarrior, see the following:
For more information regarding Taskwarrior, see the following:
.TP
The official site at
@@ -1457,6 +1479,6 @@ You can contact the project by emailing
.SH REPORTING BUGS
.TP
Bugs in taskwarrior may be reported to the issue-tracker at
Bugs in Taskwarrior may be reported to the issue-tracker at
<http://taskwarrior.org>

View File

@@ -24,7 +24,7 @@
#
###############################################################################
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
# General decoration
color.label=
@@ -50,10 +50,9 @@ color.blocking=black on bright white
color.project.none=
# Priority
color.pri.H=bold white
color.pri.M=white
color.pri.L=
color.pri.none=
color.uda.priority.H=bold white
color.uda.priority.M=white
color.uda.priority.L=
# Tags
color.tag.next=bold yellow

View File

@@ -24,7 +24,7 @@
#
###############################################################################
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
# General decoration
color.label=
@@ -50,10 +50,9 @@ color.blocking=black on color15
color.project.none=
# Priority
color.pri.H=color255
color.pri.L=color245
color.pri.M=color250
color.pri.none=
color.uda.priority.H=color255
color.uda.priority.L=color245
color.uda.priority.M=color250
# Tags
color.tag.next=rgb440

View File

@@ -24,7 +24,7 @@
#
###############################################################################
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
# General decoration
color.label=
@@ -50,10 +50,9 @@ color.blocking=white on rgb002
color.project.none=
# Priority
color.pri.H=rgb035
color.pri.L=rgb015
color.pri.M=rgb025
color.pri.none=
color.uda.priority.H=rgb035
color.uda.priority.L=rgb015
color.uda.priority.M=rgb025
# Tags
color.tag.next=rgb550

View File

@@ -24,7 +24,7 @@
#
###############################################################################
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
# General decoration
color.label=
@@ -50,10 +50,9 @@ color.blocking=bold white
color.project.none=
# Priority
color.pri.H=gray21
color.pri.M=gray18
color.pri.L=gray12
color.pri.none=gray18
color.uda.priority.H=gray21
color.uda.priority.M=gray18
color.uda.priority.L=gray12
# Tags
color.tag.next=bold white

View File

@@ -24,7 +24,7 @@
#
###############################################################################
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
# General decoration
color.label=
@@ -50,10 +50,9 @@ color.blocking=gray18 on gray6
color.project.none=
# Priority
color.pri.H=
color.pri.L=
color.pri.M=
color.pri.none=
color.uda.priority.H=
color.uda.priority.L=
color.uda.priority.M=
# Tags
color.tag.next=

View File

@@ -24,7 +24,7 @@
#
###############################################################################
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
# General decoration
color.label=
@@ -50,10 +50,9 @@ color.blocking=white on rgb020
color.project.none=
# Priority
color.pri.H=rgb050
color.pri.L=rgb010
color.pri.M=rgb030
color.pri.none=
color.uda.priority.H=rgb050
color.uda.priority.L=rgb010
color.uda.priority.M=rgb030
# Tags
color.tag.next=rgb440

View File

@@ -24,7 +24,7 @@
#
###############################################################################
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
# General decoration
color.label=
@@ -50,10 +50,9 @@ color.blocking=white on rgb200
color.project.none=
# Priority
color.pri.H=rgb500
color.pri.L=rgb300
color.pri.M=rgb400
color.pri.none=
color.uda.priority.H=rgb500
color.uda.priority.L=rgb300
color.uda.priority.M=rgb400
# Tags
color.tag.next=rgb511

View File

@@ -24,7 +24,7 @@
#
###############################################################################
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
# General decoration
color.label=
@@ -50,10 +50,9 @@ color.blocking=white on rgb202
color.project.none=
# Priority
color.pri.H=rgb404
color.pri.M=rgb304
color.pri.L=rgb325
color.pri.none=
color.uda.priority.H=rgb404
color.uda.priority.M=rgb304
color.uda.priority.L=rgb325
# Tags
color.tag.next=

View File

@@ -24,7 +24,7 @@
#
###############################################################################
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
# General decoration
color.label=
@@ -50,10 +50,9 @@ color.blocking=white on rgb220
color.project.none=
# Priority
color.pri.H=rgb450
color.pri.M=rgb030
color.pri.L=rgb010
color.pri.none=
color.uda.priority.H=rgb450
color.uda.priority.M=rgb030
color.uda.priority.L=rgb010
# Tags
color.tag.next=

View File

@@ -24,7 +24,7 @@
#
###############################################################################
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
# General decoration
color.label=
@@ -50,10 +50,9 @@ color.blocked=blue
color.project.none=
# Priority
color.pri.H=
color.pri.M=
color.pri.L=bright black
color.pri.none=
color.uda.priority.H=
color.uda.priority.M=
color.uda.priority.L=bright black
# Tags
color.tag.next=bold yellow on bright black

View File

@@ -24,7 +24,7 @@
#
###############################################################################
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
# General decoration
color.label=
@@ -50,10 +50,9 @@ color.blocked=rgb003
color.project.none=
# Priority
color.pri.H=gray0
color.pri.M=gray5
color.pri.L=gray10
color.pri.none=
color.uda.priority.H=gray0
color.uda.priority.M=gray5
color.uda.priority.L=gray10
# Tags
color.tag.next=rgb420

View File

@@ -24,7 +24,7 @@
#
###############################################################################
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
# This is a theme that disables all default colors
# It can be used as template for other themes
@@ -53,10 +53,9 @@ color.blocking=
color.project.none=
# Priority
color.pri.H=
color.pri.L=
color.pri.M=
color.pri.none=
color.uda.priority.H=
color.uda.priority.L=
color.uda.priority.M=
# Tags
color.tag.next=

View File

@@ -41,7 +41,7 @@
#
# Taskwarrior solarized-dark-256 theme created by Stefan A. Keel.
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
# General decoration
color.label=
@@ -67,10 +67,9 @@ color.blocking=color15 on color10
color.project.none=
# Priority
color.pri.H=bold blue #color14
color.pri.M=bold yellow #color12
color.pri.L=bold green #color11
color.pri.none=
color.uda.priority.H=bold blue #color14
color.uda.priority.M=bold yellow #color12
color.uda.priority.L=bold green #color11
# Tags
color.tag.next=

View File

@@ -41,7 +41,7 @@
#
# Taskwarrior solarized-dark-256 theme created by Stefan A. Keel.
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
# General decoration
color.label=
@@ -67,10 +67,9 @@ color.blocking=color15 on color0
color.project.none=
# Priority
color.pri.H=bold color0
color.pri.M=bold color11
color.pri.L=bold color14
color.pri.none=
color.uda.priority.H=bold color0
color.uda.priority.M=bold color11
color.uda.priority.L=bold color14
# Tags
color.tag.next=

Binary file not shown.

Binary file not shown.

View File

@@ -48,7 +48,7 @@ if ($command =~ /No matches/)
print "'uuid','status','tags','entry','start','due','recur','end','project',",
"'priority','fg','bg','description'\n";
for my $task (split /,$/ms, qx{$command})
for my $task (split "\n", qx{$command})
{
my $data = from_json ($task);

View File

@@ -60,7 +60,7 @@ print "<html>\n",
" <tbody>\n";
my $count = 0;
for my $task (split /,$/ms, qx{$command})
for my $task (split "\n", qx{$command})
{
++$count;
my $data = from_json ($task);

View File

@@ -49,7 +49,7 @@ print "BEGIN:VCALENDAR\n",
"VERSION:2.0\n",
"PRODID:=//GBF/taskwarrior 1.9.4//EN\n";
for my $task (split /,$/ms, qx{$command})
for my $task (split "\n", qx{$command})
{
my $data = from_json ($task);

View File

@@ -29,7 +29,7 @@ export-sql.py -- Export the taskwarrior database as a series of SQL commands.
Example usage::
$ ./export-sql.py | sqlite3 mytasks.db
$ PYTHONIOENCODING=UTF-8 ./export-sql.py | sqlite3 mytasks.db
$ /usr/bin/sqlite3 mytasks.db "select * from annotations;"
This script has only been tested with sqlite3, but in theory, it could be
@@ -120,8 +120,8 @@ def to_sql(task):
values = template.format(**annot)
return "INSERT INTO \"annotations\" VALUES(%s)" % values
template = "{uuid}, {description}, {entry}, {end}, " + \
"{priority}, {project}, {status}"
template = u"{uuid}, {description}, {entry}, {end}, " + \
u"{priority}, {project}, {status}"
nullables = ['end', 'priority', 'project', 'status']
defaults = dict([(key, None) for key in nullables])
@@ -140,10 +140,10 @@ def main():
""" Return a list of SQL statements. """
# Use the taskwarrior 2.0+ export command to filter and return JSON
command = "task rc.verbose=nothing rc.json.array=no export " + " ".join(sys.argv[1:])
command = "task rc.verbose=nothing rc.json.array=yes " + " ".join(sys.argv[1:]) + " export"
# Load each task from json to a python dict
tasks = map(json.loads, commands.getoutput(command).split(",\n"))
tasks = json.loads(commands.getoutput(command))
# Mangle datetime strings into python datetime objects
tasks = map(parse_datetime, tasks)
@@ -162,7 +162,7 @@ if __name__ == '__main__':
sql = table_definitions + ";\n".join(lines) + ';'
# Print them out, decorated with sqlite3 trappings
print """
print u"""
BEGIN TRANSACTION;
{sql}
COMMIT;""".format(sql=sql)

View File

@@ -48,7 +48,7 @@ if ($command =~ /No matches/)
print "uuid\tstatus\ttags\tentry\tstart\tdue\trecur\tend\tproject\t",
"priority\tfg\tbg\tdescription\n";
for my $task (split /,$/ms, qx{$command})
for my $task (split "\n", qx{$command})
{
my $data = from_json ($task);

View File

@@ -46,7 +46,7 @@ if ($command =~ /No matches/)
# Generate output.
print "<tasks>\n";
for my $task (split /,$/ms, qx{$command})
for my $task (split "\n", qx{$command})
{
my $data = from_json ($task);

View File

@@ -48,7 +48,7 @@ if ($command =~ /No matches/)
print "'uuid','status','tags','entry','start','due','recur','end','project',",
"'priority','fg','bg','description'\n";
for my $task (split /,$/ms, qx{$command})
for my $task (split "\n", qx{$command})
{
my $data = from_json ($task);

View File

@@ -50,7 +50,7 @@
#
################################################################################
#the following variable is substituted for by ../../test/bash_completion.t
taskcommand='task rc.verbose:nothing'
taskcommand='task rc.verbose:nothing rc.confirmation:no rc.hooks:off'
_task_get_tags() {
$taskcommand _tags

View File

@@ -15,6 +15,24 @@
# * Tags
# * Attribute names and modifiers
#
#
# You can override some default options in your config.fish:
#
# # Tab-completion of task descriptions.
# # Warning: This often creates a list of suggestions which spans several pages,
# # and it usually pushes some of the commands and attributes to the end of the
# # list.
# set -g task_complete_task yes
#
# # Tab-completion of task IDs outside of the "depends" attribute.
# # Warning: This often creates a list of suggestions which spans several pages,
# # and it pushes all commands and attributes to the end of the list.
# set -g task_complete_id yes
#
# # Attribute modifiers (DEPRECATED since 2.4.0)
# set -g task_complete_attribute_modifiers yes
#
#
# Copyright 2014 - 2015, Roman Inflianskas <infroma@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -150,8 +168,7 @@ function __fish.task.list.attr_value_by_name
__fish.task.combos_simple $attr (__fish.task.list $attr)
# case 'description' 'due' 'entry' 'end' 'start' 'project' 'recur' 'until' 'wait'
case '*'
# BUG: remove in 2.4.0
if echo (commandline -ct) | grep -q '\.'
if [ "$task_complete_attribute_modifiers" = 'yes' ]; and echo (commandline -ct) | grep -q '\.'
__fish.task.combos_with_mods $attr (__fish.task.list $attr)
else
__fish.task.combos_simple $attr (__fish.task.list $attr)
@@ -195,7 +212,7 @@ function __fish.task.list.id
end
end
# BUG: remove in 2.4.0
# Attribure modifiers (DEPRECATED since 2.4.0)
function __fish.task.list.mod
for mod in 'before' 'after' 'over' 'under' 'none' 'is' 'isnt' 'has' 'hasnt' 'startswith' 'endswith' 'word' 'noword'
echo $mod
@@ -266,7 +283,7 @@ function __fish.task.combos_simple
end
end
# BUG: remove in 2.4.0
# Attribure modifiers (DEPRECATED since 2.4.0)
function __fish.task.combos_with_mods
__fish.task.combos_simple $argv
for mod in (__fish.task.list.mod)
@@ -290,16 +307,10 @@ __fish.task.complete attr_value
__fish.task.complete attr_name
__fish.task.complete config
# Uncomment the following line if you want tab-completion of task descriptions.
# Warning: This often creates a list of suggestions which spans several pages,
# and it usually pushes some of the commands and attributes to the end of the
# list.
if [ "$task_complete_task" = 'yes' ]
__fish.task.complete task
end
#__fish.task.complete task
# Uncomment the following line if you want tab-completion of task IDs outside
# of the "depends" attribute. Warning: This often creates a list of
# suggestions which spans several pages, and it pushes all commands and
# attributes to the end of the list.
#__fish.task.complete id with_description
if [ "$task_complete_id" = 'yes' ]
__fish.task.complete id with_description
end

View File

@@ -3,18 +3,18 @@
# The on-exit event is triggered once, after all processing is complete.
# This hooks script has no effect on processing.
# Input:
# - Read-only line of JSON for each task added/modified
while read modified_task
do
echo $modified_task
done
# Output:
# - Optional feedback/error.
echo 'on-exit'
n=0
while read modified_task
do
n=$(($n + 1))
done
echo "on-exit: Counted $n added/modified tasks."
# Status:
# - 0: JSON ignored, non-JSON is feedback.
# - non-0: JSON ignored, non-JSON is error.
# - 0: Non-JSON is feedback.
# - non-0: Non-JSON is error.
exit 0

View File

@@ -72,10 +72,9 @@ syn match taskrcGoodKey '^\s*\Vcolor.history.add='he=e-1
syn match taskrcGoodKey '^\s*\Vcolor.history.delete='he=e-1
syn match taskrcGoodKey '^\s*\Vcolor.history.done='he=e-1
syn match taskrcGoodKey '^\s*\Vcolor.overdue='he=e-1
syn match taskrcGoodKey '^\s*\Vcolor.pri.H='he=e-1
syn match taskrcGoodKey '^\s*\Vcolor.pri.L='he=e-1
syn match taskrcGoodKey '^\s*\Vcolor.pri.M='he=e-1
syn match taskrcGoodKey '^\s*\Vcolor.pri.none='he=e-1
syn match taskrcGoodKey '^\s*\Vcolor.uda.priority.H='he=e-1
syn match taskrcGoodKey '^\s*\Vcolor.uda.priority.L='he=e-1
syn match taskrcGoodKey '^\s*\Vcolor.uda.priority.M='he=e-1
syn match taskrcGoodKey '^\s*\Vcolor.recurring='he=e-1
syn match taskrcGoodKey '^\s*\Vcolor.scheduled='he=e-1
syn match taskrcGoodKey '^\s*\Vcolor.summary.background='he=e-1
@@ -154,7 +153,9 @@ syn match taskrcGoodKey '^\s*\Vurgency.blocking.coefficient='he=e-1
syn match taskrcGoodKey '^\s*\Vurgency.due.coefficient='he=e-1
syn match taskrcGoodKey '^\s*\Vurgency.inherit.coefficient='he=e-1
syn match taskrcGoodKey '^\s*\Vurgency.next.coefficient='he=e-1
syn match taskrcGoodKey '^\s*\Vurgency.priority.coefficient='he=e-1
syn match taskrcGoodKey '^\s*\Vurgency.uda.priority.H.coefficient='he=e-1
syn match taskrcGoodKey '^\s*\Vurgency.uda.priority.M.coefficient='he=e-1
syn match taskrcGoodKey '^\s*\Vurgency.uda.priority.L.coefficient='he=e-1
syn match taskrcGoodKey '^\s*\Vurgency.project.coefficient='he=e-1
syn match taskrcGoodKey '^\s*\Vurgency.scheduled.coefficient='he=e-1
syn match taskrcGoodKey '^\s*\Vurgency.tags.coefficient='he=e-1

1
src/.gitignore vendored
View File

@@ -3,3 +3,4 @@ Makefile.in
tw-*
args
calc
lex

View File

@@ -220,16 +220,14 @@ const std::string A::dump () const
// Static method.
void CLI::getOverride (int argc, const char** argv, std::string& home, File& rc)
{
bool terminated = false;
for (int i = 0; i < argc; ++i)
{
std::string raw = argv[i];
if (raw == "--")
terminated = true;
return;
if (! terminated &&
raw.length () > 3 &&
if (raw.length () > 3 &&
raw.substr (0, 3) == "rc:")
{
rc = raw.substr (3);
@@ -351,7 +349,6 @@ void CLI::initialize (int argc, const char** argv)
_terminated = false;
_original_args.push_back (argv[0]);
bool terminated = false;
for (int i = 1; i < argc; ++i)
{
if (isTerminator (argv[i]))
@@ -379,10 +376,9 @@ void CLI::addContextFilter ()
{
// Detect if any context is set, and bail out if not
std::string contextName = context.config.get ("context");
if (contextName == "")
{
context.debug("No context applied.");
context.debug ("No context applied.");
return;
}
@@ -392,35 +388,35 @@ void CLI::addContextFilter ()
std::vector <A>::const_iterator a;
for (a = _args.begin (); a != _args.end (); ++a)
{
// TODO This looks wrong.
if (a->hasTag ("FILTER") &&
a->hasTag ("ATTRIBUTE") &&
! a->hasTag ("TERMINATED") &&
! a->hasTag ("WORD") &&
(a->attribute ("raw") == "id" || a->attribute ("raw") == "uuid"))
{
context.debug(format("UUID/ID lexeme found '{1}', not applying context.", a->attribute ("raw")));
context.debug (format ("UUID/ID lexeme found '{1}', not applying context.", a->attribute ("raw")));
return;
}
}
}
// Apply context
context.debug("Applying context: " + contextName);
context.debug ("Applying context: " + contextName);
std::string contextFilter = context.config.get ("context." + contextName);
if (contextFilter == "")
context.debug("Context '" + contextName + "' not defined!");
context.debug ("Context '" + contextName + "' not defined.");
else
{
addRawFilter("( " + contextFilter + " )");
addRawFilter ("( " + contextFilter + " )");
if (context.verbose ("context"))
context.footnote (format("Context '{1}' set. Use 'task context none' to remove.", contextName));
context.footnote (format ("Context '{1}' set. Use 'task context none' to remove.", contextName));
}
}
////////////////////////////////////////////////////////////////////////////////
// Process raw string into parsed filter.
//
void CLI::addRawFilter (const std::string& arg)
{
std::string lexeme;
@@ -446,7 +442,7 @@ void CLI::analyze (bool parse /* = true */, bool strict /* = false */)
// For propagation.
_strict = strict;
for (int i = 0; i < _original_args.size (); ++i)
for (unsigned int i = 0; i < _original_args.size (); ++i)
{
std::string raw = _original_args[i];
A a ("arg", raw);
@@ -692,7 +688,7 @@ const std::string CLI::dump (const std::string& title /* = "CLI Parser" */) cons
// be lexed from those that need to be left alone.
//
// Either the arg is appended to _original_args intact, or the lexemes are.
void CLI::addArg (const std::string& arg)
void CLI::addArg (const std::string& arg, Lexer::Type type /* = Lexer::Type::word */)
{
std::string raw = trim (arg);
@@ -718,8 +714,8 @@ void CLI::addArg (const std::string& arg)
_original_args.push_back (raw);
}
// The argument may require lexing. Lex anyway, and analyze before comitting
// that.
// The argument may require lexing. Lex anyway, and analyze before comitting
// to that.
else
{
// Lex each remaining argument. The apply a series of disqualifying tests
@@ -730,7 +726,7 @@ void CLI::addArg (const std::string& arg)
Lexer lex (raw);
lex.ambiguity (false);
std::vector <std::pair <std::string, Lexer::Type> > lexemes;
std::vector <std::pair <std::string, Lexer::Type>> lexemes;
while (lex.token (lexeme, type))
lexemes.push_back (std::pair <std::string, Lexer::Type> (lexeme, type));
@@ -746,7 +742,7 @@ void CLI::addArg (const std::string& arg)
{
// How often have I said to you that when you have eliminated the
// impossible, whatever remains, however improbable, must be the truth?
std::vector <std::pair <std::string, Lexer::Type> >::iterator l;
std::vector <std::pair <std::string, Lexer::Type>>::iterator l;
for (l = lexemes.begin (); l != lexemes.end (); ++l)
_original_args.push_back (l->first);
}
@@ -778,9 +774,7 @@ void CLI::aliasExpansion ()
{
if (_aliases.find (raw) != _aliases.end ())
{
std::vector <std::string> lexed;
Lexer::token_split (lexed, _aliases[raw]);
std::vector <std::string> lexed = Lexer::split (_aliases[raw]);
std::vector <std::string>::iterator l;
for (l = lexed.begin (); l != lexed.end (); ++l)
{
@@ -916,7 +910,7 @@ void CLI::categorize ()
a->tag ("MODIFICATION");
// If the argument contains a space, it was quoted. Record that.
if (! noSpaces (raw))
if (! Lexer::isOneWord (raw))
a->tag ("QUOTED");
changes = true;
@@ -926,7 +920,7 @@ void CLI::categorize ()
a->tag ("FILTER");
// If the argument contains a space, it was quoted. Record that.
if (! noSpaces (raw))
if (! Lexer::isOneWord (raw))
a->tag ("QUOTED");
changes = true;
@@ -1240,7 +1234,7 @@ void CLI::desugarFilterAttributeModifiers ()
}
else if (modifier == "isnt" || modifier == "not")
{
op.attribute ("raw", "!=");
op.attribute ("raw", "!==");
rhs.attribute ("raw", "'" + value + "'");
rhs.tag ("LITERAL");
}
@@ -1389,14 +1383,12 @@ void CLI::findIDs ()
{
if (a->hasTag ("FILTER"))
{
bool found = false;
// IDs have a limited character set.
std::string raw = a->attribute ("raw");
if (raw.find_first_not_of ("0123456789,-") == std::string::npos)
{
// Container for min/max ID ranges.
std::vector <std::pair <int, int> > ranges;
std::vector <std::pair <int, int>> ranges;
// Split the ID list into elements.
std::vector <std::string> elements;
@@ -1412,7 +1404,7 @@ void CLI::findIDs ()
if (terms.size () == 1)
{
if (! digitsOnly (terms[0]))
if (! Lexer::isAllDigits (terms[0]))
{
is_an_id = false;
break;
@@ -1433,8 +1425,8 @@ void CLI::findIDs ()
}
else if (terms.size () == 2)
{
if (! digitsOnly (terms[0]) ||
! digitsOnly (terms[1]))
if (! Lexer::isAllDigits (terms[0]) ||
! Lexer::isAllDigits (terms[1]))
{
is_an_id = false;
break;
@@ -1475,7 +1467,7 @@ void CLI::findIDs ()
a->tag ("ID");
// Save the ranges.
std::vector <std::pair <int, int> >::iterator r;
std::vector <std::pair <int, int>>::iterator r;
for (r = ranges.begin (); r != ranges.end (); ++r)
_id_ranges.push_back (*r);
}
@@ -1584,7 +1576,7 @@ void CLI::insertIDExpr ()
reconstructed.push_back (openParen);
// Add all ID ranges.
std::vector <std::pair <int, int> >::iterator r;
std::vector <std::pair <int, int>>::iterator r;
for (r = _id_ranges.begin (); r != _id_ranges.end (); ++r)
{
if (r != _id_ranges.begin ())
@@ -1879,8 +1871,7 @@ void CLI::injectDefaults ()
if (defaultCommand != "")
{
// Split the defaultCommand into separate args.
std::vector <std::string> tokens;
Lexer::token_split (tokens, defaultCommand);
std::vector <std::string> tokens = Lexer::split (defaultCommand);
// Modify _args to be: <args0> [<def0> ...] <args1> [...]
std::vector <A> reconstructed;
@@ -2274,7 +2265,7 @@ bool CLI::isIDSequence (const std::string& raw) const
////////////////////////////////////////////////////////////////////////////////
bool CLI::isID (const std::string& raw) const
{
return digitsOnly (raw);
return Lexer::isAllDigits (raw);
}
////////////////////////////////////////////////////////////////////////////////
@@ -2368,11 +2359,11 @@ bool CLI::isName (const std::string& raw) const
{
if (raw != "")
{
for (int i = 0; i < raw.length (); ++i)
for (unsigned int i = 0; i < raw.length (); ++i)
{
if (i == 0 && ! Lexer::is_ident_start (raw[i]))
if (i == 0 && ! Lexer::isIdentifierStart (raw[i]))
return false;
else if (! Lexer::is_ident (raw[i]))
else if (! Lexer::isIdentifierNext (raw[i]))
return false;
}
@@ -2384,19 +2375,19 @@ bool CLI::isName (const std::string& raw) const
////////////////////////////////////////////////////////////////////////////////
bool CLI::disqualifyInsufficientTerms (
const std::vector <std::pair <std::string, Lexer::Type> >& lexemes) const
const std::vector <std::pair <std::string, Lexer::Type>>& lexemes) const
{
return lexemes.size () < 3 ? true : false;
}
////////////////////////////////////////////////////////////////////////////////
bool CLI::disqualifyNoOps (
const std::vector <std::pair <std::string, Lexer::Type> >& lexemes) const
const std::vector <std::pair <std::string, Lexer::Type>>& lexemes) const
{
bool foundOP = false;
std::vector <std::pair <std::string, Lexer::Type> >::const_iterator l;
std::vector <std::pair <std::string, Lexer::Type>>::const_iterator l;
for (l = lexemes.begin (); l != lexemes.end (); ++l)
if (l->second == Lexer::typeOperator)
if (l->second == Lexer::Type::op)
foundOP = true;
return ! foundOP;
@@ -2404,16 +2395,16 @@ bool CLI::disqualifyNoOps (
////////////////////////////////////////////////////////////////////////////////
bool CLI::disqualifyOnlyParenOps (
const std::vector <std::pair <std::string, Lexer::Type> >& lexemes) const
const std::vector <std::pair <std::string, Lexer::Type>>& lexemes) const
{
int opCount = 0;
int opSugarCount = 0;
int opParenCount = 0;
std::vector <std::pair <std::string, Lexer::Type> >::const_iterator l;
std::vector <std::pair <std::string, Lexer::Type>>::const_iterator l;
for (l = lexemes.begin (); l != lexemes.end (); ++l)
{
if (l->second == Lexer::typeOperator)
if (l->second == Lexer::Type::op)
{
++opCount;
@@ -2440,7 +2431,7 @@ bool CLI::disqualifyOnlyParenOps (
// as there are no operators in between, which includes syntactic sugar that
// hides operators.
bool CLI::disqualifyFirstLastBinary (
const std::vector <std::pair <std::string, Lexer::Type> >& lexemes) const
const std::vector <std::pair <std::string, Lexer::Type>>& lexemes) const
{
bool firstBinary = false;
bool lastBinary = false;
@@ -2459,7 +2450,7 @@ bool CLI::disqualifyFirstLastBinary (
////////////////////////////////////////////////////////////////////////////////
// Disqualify terms when there operators hidden by syntactic sugar.
bool CLI::disqualifySugarFree (
const std::vector <std::pair <std::string, Lexer::Type> >& lexemes) const
const std::vector <std::pair <std::string, Lexer::Type>>& lexemes) const
{
bool sugared = true;
for (unsigned int i = 1; i < lexemes.size () - 1; ++i)

View File

@@ -90,7 +90,7 @@ public:
const std::string dump (const std::string& title = "CLI Parser") const;
private:
void addArg (const std::string&);
void addArg (const std::string&, Lexer::Type type = Lexer::Type::word);
void aliasExpansion ();
void findOverrides ();
void categorize ();
@@ -128,11 +128,11 @@ private:
bool isOperator (const std::string&) const;
bool isName (const std::string&) const;
bool disqualifyInsufficientTerms (const std::vector <std::pair <std::string, Lexer::Type> >&) const;
bool disqualifyNoOps (const std::vector <std::pair <std::string, Lexer::Type> >&) const;
bool disqualifyOnlyParenOps (const std::vector <std::pair <std::string, Lexer::Type> >&) const;
bool disqualifyFirstLastBinary (const std::vector <std::pair <std::string, Lexer::Type> >&) const;
bool disqualifySugarFree (const std::vector <std::pair <std::string, Lexer::Type> >&) const;
bool disqualifyInsufficientTerms (const std::vector <std::pair <std::string, Lexer::Type>>&) const;
bool disqualifyNoOps (const std::vector <std::pair <std::string, Lexer::Type>>&) const;
bool disqualifyOnlyParenOps (const std::vector <std::pair <std::string, Lexer::Type>>&) const;
bool disqualifyFirstLastBinary (const std::vector <std::pair <std::string, Lexer::Type>>&) const;
bool disqualifySugarFree (const std::vector <std::pair <std::string, Lexer::Type>>&) const;
public:
std::multimap <std::string, std::string> _entities;
@@ -140,7 +140,7 @@ public:
std::vector <std::string> _original_args;
std::vector <A> _args;
std::vector <std::pair <int, int> > _id_ranges;
std::vector <std::pair <int, int>> _id_ranges;
std::vector <std::string> _uuid_list;
bool _strict;
bool _terminated;

View File

@@ -48,16 +48,19 @@ set (task_SRCS CLI.cpp CLI.h
add_library (task STATIC ${task_SRCS})
add_executable (task_executable main.cpp)
add_executable (calc_executable calc.cpp)
add_executable (lex_executable lex.cpp)
# Yes, 'task' is included twice, otherwise linking fails on assorted OSes.
target_link_libraries (task_executable task commands columns task ${TASK_LIBRARIES})
target_link_libraries (calc_executable task commands columns task ${TASK_LIBRARIES})
target_link_libraries (lex_executable task commands columns task ${TASK_LIBRARIES})
set_property (TARGET task_executable PROPERTY OUTPUT_NAME "task")
install (TARGETS task_executable DESTINATION ${TASK_BINDIR})
set_property (TARGET calc_executable PROPERTY OUTPUT_NAME "calc")
set_property (TARGET lex_executable PROPERTY OUTPUT_NAME "lex")
#SET(CMAKE_BUILD_TYPE gcov)
#SET(CMAKE_CXX_FLAGS_GCOV "--coverage")

View File

@@ -147,7 +147,6 @@ std::string Config::_defaults =
"urgency.next.coefficient=15.0 # Urgency coefficient for 'next' special tag\n"
"urgency.due.coefficient=12.0 # Urgency coefficient for due dates\n"
"urgency.blocking.coefficient=8.0 # Urgency coefficient for blocking tasks\n"
"urgency.priority.coefficient=6.0 # Urgency coefficient for priorities\n"
"urgency.active.coefficient=4.0 # Urgency coefficient for active tasks\n"
"urgency.scheduled.coefficient=5.0 # Urgency coefficient for scheduled tasks\n"
"urgency.age.coefficient=2.0 # Urgency coefficient for age\n"
@@ -167,7 +166,7 @@ std::string Config::_defaults =
"color=on # Enable color\n"
#if defined(LINUX) || defined(DARWIN)
"\n"
"rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.\n"
"rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.\n"
"\n"
"# General decoration\n"
"color.label=\n"
@@ -192,11 +191,10 @@ std::string Config::_defaults =
"# Project\n"
"color.project.none=\n"
"\n"
"# Priority\n"
"color.pri.H=color255\n"
"color.pri.L=color245\n"
"color.pri.M=color250\n"
"color.pri.none=\n"
"# Priority UDA\n"
"color.uda.priority.H=color255\n"
"color.uda.priority.L=color245\n"
"color.uda.priority.M=color250\n"
"\n"
"# Tags\n"
"color.tag.next=rgb440\n"
@@ -242,7 +240,7 @@ std::string Config::_defaults =
"\n"
#else
"\n"
"rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.\n"
"rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.\n"
"\n"
"# General decoration\n"
"color.label=\n"
@@ -267,11 +265,10 @@ std::string Config::_defaults =
"# Project\n"
"color.project.none=\n"
"\n"
"# Priority\n"
"color.pri.H=bold white\n"
"color.pri.M=white\n"
"color.pri.L=\n"
"color.pri.none=\n"
"# Priority UDA\n"
"color.uda.priority.H=bold white\n"
"color.uda.priority.M=white\n"
"color.uda.priority.L=\n"
"\n"
"# Tags\n"
"color.tag.next=bold yellow\n"
@@ -319,22 +316,33 @@ std::string Config::_defaults =
"color.undo.before=red\n"
"\n"
#endif
"# UDA priority\n"
"uda.priority.type=string # UDA priority is a string type\n"
"uda.priority.label=Priority # UDA priority has a display label'\n"
"uda.priority.values=H,M,L, # UDA priority values are 'H', 'M', 'L' or ''\n"
" # UDA priority sorting is 'H' > 'M' > 'L' > '' (highest to lowest)\n"
"#uda.priority.default=M # UDA priority default value of 'M'\n"
"urgency.uda.priority.H.coefficient=6.0 # UDA priority coefficient for value 'H'\n"
"urgency.uda.priority.M.coefficient=3.9 # UDA priority coefficient for value 'M'\n"
"urgency.uda.priority.L.coefficient=1.8 # UDA priority coefficient for value 'L'\n"
"\n"
"# Here is the rule precedence order, highest to lowest.\n"
"# Note that these are just the color rule names, without the leading 'color.'\n"
"# and any trailing '.value'.\n"
"rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.\n"
"rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.\n"
"\n"
"#default.project=foo # Default project for 'add' command\n"
"#default.priority=M # Default priority for 'add' command\n"
"#default.due=eom # Default due date for 'add' command\n"
"default.command=next # When no arguments are specified\n"
"\n"
"_forcecolor=no # Forces color to be on, even for non TTY output\n"
"complete.all.tags=no # Include old tag names in '_ags' command\n"
"list.all.projects=no # Include old project names in 'projects' command\n"
"summary.all.projects=no # Include old project names in 'summary' command\n"
"list.all.tags=no # Include old tag names in 'tags' command\n"
"print.empty.columns=no # Print columns which have no data for any task\n"
"debug=no # Display diagnostics\n"
"obfuscate=no # Obfuscate data for error reporting\n"
"fontunderline=yes # Uses underlines rather than -------\n"
"shell.prompt=task> # Prompt used by the shell command\n"
"\n"
@@ -385,7 +393,7 @@ std::string Config::_defaults =
"report.newest.description=Newest tasks\n"
"report.newest.labels=ID,Active,Created,Age,Mod,D,P,Project,Tags,R,Wait,Sch,Due,Until,Description\n"
"report.newest.columns=id,start.age,entry,entry.age,modified.age,depends.indicator,priority,project,tags,recur.indicator,wait.remaining,scheduled.countdown,due,until.age,description\n"
"report.newest.filter=(status:pending or status:waiting) and recur.none:\n"
"report.newest.filter=(status:pending or status:waiting)\n"
"report.newest.sort=entry-\n"
"\n"
"report.oldest.description=Oldest tasks\n"

View File

@@ -65,33 +65,6 @@ static const char* modifierNames[] =
#define NUM_MODIFIER_NAMES (sizeof (modifierNames) / sizeof (modifierNames[0]))
static const char* attributeNames[] =
{
"depends",
"description",
"due",
"end",
"entry",
"id",
"imask",
"mask",
"modified",
"parent",
"priority",
"project",
"recur",
"scheduled",
"start",
"status",
"tags",
"until",
"urgency",
"uuid",
"wait"
};
#define NUM_ATTRIBUTE_NAMES (sizeof (attributeNames) / sizeof (attributeNames[0]))
////////////////////////////////////////////////////////////////////////////////
Context::Context ()
: rc_file ("~/.taskrc")
@@ -101,6 +74,7 @@ Context::Context ()
, dom ()
, determine_color_use (true)
, use_color (true)
, run_gc (true)
, verbosity_legacy (false)
, terminal_width (0)
, terminal_height (0)
@@ -478,7 +452,14 @@ int Context::dispatch (std::string &out)
// GC is invoked prior to running any command that displays task IDs, if
// possible.
if (c->displays_id () && !tdb2.read_only ())
{
run_gc = config.getBoolean ("gc");
tdb2.gc ();
}
else
{
run_gc = false;
}
/*
// Only read-only commands can be run when TDB2 is read-only.
@@ -652,7 +633,6 @@ void Context::staticInitialization ()
CLI::minimumMatchLength = config.getInteger ("abbreviation.minimum");
Task::defaultProject = config.get ("default.project");
Task::defaultPriority = config.get ("default.priority");
Task::defaultDue = config.get ("default.due");
Task::searchCaseSensitive = Variant::searchCaseSensitive = config.getBoolean ("search.case.sensitive");
@@ -660,11 +640,25 @@ void Context::staticInitialization ()
Lexer::dateFormat = Variant::dateFormat = config.get ("dateformat");
Lexer::isoEnabled = Variant::isoEnabled = config.getBoolean ("date.iso");
Config::const_iterator rc;
for (rc = config.begin (); rc != config.end (); ++rc)
{
if (rc->first.substr (0, 4) == "uda." &&
rc->first.substr (rc->first.length () - 7, 7) == ".values")
{
std::string name = rc->first.substr (4, rc->first.length () - 7 - 4);
std::vector <std::string> values;
split (values, rc->second, ',');
for (auto r = values.rbegin(); r != values.rend (); ++r)
Task::customOrder[name].push_back (*r);
}
}
std::map <std::string, Column*>::iterator i;
for (i = columns.begin (); i != columns.end (); ++i)
Task::attributes[i->first] = i->second->type ();
Task::urgencyPriorityCoefficient = config.getReal ("urgency.priority.coefficient");
Task::urgencyProjectCoefficient = config.getReal ("urgency.project.coefficient");
Task::urgencyActiveCoefficient = config.getReal ("urgency.active.coefficient");
Task::urgencyScheduledCoefficient = config.getReal ("urgency.scheduled.coefficient");

View File

@@ -94,6 +94,8 @@ public:
bool determine_color_use;
bool use_color;
bool run_gc;
bool verbosity_legacy;
std::vector <std::string> verbosity;
std::vector <std::string> headers;

View File

@@ -116,16 +116,16 @@ bool DOM::get (const std::string& name, Variant& value)
}
else if (name == "context.width")
{
value = Variant (context.terminal_width
? context.terminal_width
: context.getWidth ());
value = Variant (static_cast<int> (context.terminal_width
? context.terminal_width
: context.getWidth ()));
return true;
}
else if (name == "context.height")
{
value = Variant (context.terminal_height
? context.terminal_height
: context.getHeight ());
value = Variant (static_cast<int> (context.terminal_height
? context.terminal_height
: context.getHeight ()));
return true;
}
else
@@ -218,7 +218,7 @@ bool DOM::get (const std::string& name, const Task& task, Variant& value)
// <attr>
if (task.size () && name == "id")
{
value = Variant (task.id);
value = Variant (static_cast<int> (task.id));
return true;
}
@@ -296,7 +296,7 @@ bool DOM::get (const std::string& name, const Task& task, Variant& value)
{
if (elements[1] == "id")
{
value = Variant (ref.id);
value = Variant (static_cast<int> (ref.id));
return true;
}
else if (elements[1] == "urgency")
@@ -353,15 +353,15 @@ bool DOM::get (const std::string& name, const Task& task, Variant& value)
// <date>.minute
// <date>.second
Date date (ref.get_date (canonical));
if (elements[2] == "year") { value = Variant (date.year ()); return true; }
else if (elements[2] == "month") { value = Variant (date.month ()); return true; }
else if (elements[2] == "day") { value = Variant (date.day ()); return true; }
else if (elements[2] == "week") { value = Variant (date.week ()); return true; }
else if (elements[2] == "weekday") { value = Variant (date.dayOfWeek ()); return true; }
else if (elements[2] == "julian") { value = Variant (date.dayOfYear ()); return true; }
else if (elements[2] == "hour") { value = Variant (date.hour ()); return true; }
else if (elements[2] == "minute") { value = Variant (date.minute ()); return true; }
else if (elements[2] == "second") { value = Variant (date.second ()); return true; }
if (elements[2] == "year") { value = Variant (static_cast<int> (date.year ())); return true; }
else if (elements[2] == "month") { value = Variant (static_cast<int> (date.month ())); return true; }
else if (elements[2] == "day") { value = Variant (static_cast<int> (date.day ())); return true; }
else if (elements[2] == "week") { value = Variant (static_cast<int> (date.week ())); return true; }
else if (elements[2] == "weekday") { value = Variant (static_cast<int> (date.dayOfWeek ())); return true; }
else if (elements[2] == "julian") { value = Variant (static_cast<int> (date.dayOfYear ())); return true; }
else if (elements[2] == "hour") { value = Variant (static_cast<int> (date.hour ())); return true; }
else if (elements[2] == "minute") { value = Variant (static_cast<int> (date.minute ())); return true; }
else if (elements[2] == "second") { value = Variant (static_cast<int> (date.second ())); return true; }
}
}
}
@@ -420,15 +420,15 @@ bool DOM::get (const std::string& name, const Task& task, Variant& value)
// <annotations>.<N>.entry.minute
// <annotations>.<N>.entry.second
Date date (i->first.substr (11));
if (elements[4] == "year") { value = Variant (date.year ()); return true; }
else if (elements[4] == "month") { value = Variant (date.month ()); return true; }
else if (elements[4] == "day") { value = Variant (date.day ()); return true; }
else if (elements[4] == "week") { value = Variant (date.week ()); return true; }
else if (elements[4] == "weekday") { value = Variant (date.dayOfWeek ()); return true; }
else if (elements[4] == "julian") { value = Variant (date.dayOfYear ()); return true; }
else if (elements[4] == "hour") { value = Variant (date.hour ()); return true; }
else if (elements[4] == "minute") { value = Variant (date.minute ()); return true; }
else if (elements[4] == "second") { value = Variant (date.second ()); return true; }
if (elements[4] == "year") { value = Variant (static_cast<int> (date.year ())); return true; }
else if (elements[4] == "month") { value = Variant (static_cast<int> (date.month ())); return true; }
else if (elements[4] == "day") { value = Variant (static_cast<int> (date.day ())); return true; }
else if (elements[4] == "week") { value = Variant (static_cast<int> (date.week ())); return true; }
else if (elements[4] == "weekday") { value = Variant (static_cast<int> (date.dayOfWeek ())); return true; }
else if (elements[4] == "julian") { value = Variant (static_cast<int> (date.dayOfYear ())); return true; }
else if (elements[4] == "hour") { value = Variant (static_cast<int> (date.hour ())); return true; }
else if (elements[4] == "minute") { value = Variant (static_cast<int> (date.minute ())); return true; }
else if (elements[4] == "second") { value = Variant (static_cast<int> (date.second ())); return true; }
}
}
}

View File

@@ -31,13 +31,13 @@
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <Nibbler.h>
#include <Date.h>
#include <Variant.h>
#include <Dates.h>
#include <text.h>
#include <util.h>
#include <utf8.h>
#include <i18n.h>
#include <Context.h>
@@ -823,7 +823,7 @@ void Date::operator++ (int)
////////////////////////////////////////////////////////////////////////////////
bool Date::isEpoch (const std::string& input)
{
if (digitsOnly (input) &&
if (Lexer::isAllDigits (input) &&
input.length () <= 10 )
{
_t = (time_t) atoi (input.c_str ());

View File

@@ -30,6 +30,7 @@
#include <text.h>
#include <Dates.h>
#include <Date.h>
#include <Lexer.h>
#include <i18n.h>
////////////////////////////////////////////////////////////////////////////////
@@ -354,7 +355,7 @@ bool namedDates (const std::string& name, Variant& value)
// 4th
else if ((
name.length () == 3 &&
isdigit (name[0]) &&
Lexer::isDigit (name[0]) &&
((name[1] == 's' && name[2] == 't') ||
(name[1] == 'n' && name[2] == 'd') ||
(name[1] == 'r' && name[2] == 'd') ||
@@ -363,8 +364,8 @@ bool namedDates (const std::string& name, Variant& value)
||
(
name.length () == 4 &&
isdigit (name[0]) &&
isdigit (name[1]) &&
Lexer::isDigit (name[0]) &&
Lexer::isDigit (name[1]) &&
((name[2] == 's' && name[3] == 't') ||
(name[2] == 'n' && name[3] == 'd') ||
(name[2] == 'r' && name[3] == 'd') ||
@@ -375,7 +376,7 @@ bool namedDates (const std::string& name, Variant& value)
int number;
std::string ordinal;
if (isdigit (name[1]))
if (Lexer::isDigit (name[1]))
{
number = strtol (name.substr (0, 2).c_str (), NULL, 10);
ordinal = lowerCase (name.substr (2));

View File

@@ -34,7 +34,7 @@
#include <stdlib.h>
#include <Directory.h>
#if defined SOLARIS || defined NETBSD
#if defined SOLARIS || defined NETBSD || defined FREEBSD
#include <limits.h>
#endif

View File

@@ -61,47 +61,48 @@ static struct
{"fortnight", 14 * DAY, true},
{"hours", 1 * HOUR, false},
{"hour", 1 * HOUR, true},
{"hrs", 1 * HOUR, true},
{"hrs", 1 * HOUR, false},
{"hr", 1 * HOUR, true},
{"h", 1 * HOUR, false},
{"minutes", 1 * MINUTE, false},
{"minute", 1 * MINUTE, false},
{"minute", 1 * MINUTE, true},
{"mins", 1 * MINUTE, false},
{"min", 1 * MINUTE, false},
{"min", 1 * MINUTE, true},
{"monthly", 30 * DAY, true},
{"months", 30 * DAY, false},
{"month", 30 * DAY, true},
{"mnths", 30 * DAY, false},
{"mths", 30 * DAY, false},
{"mth", 30 * DAY, false},
{"mth", 30 * DAY, true},
{"mos", 30 * DAY, false},
{"mo", 30 * DAY, false},
{"mo", 30 * DAY, true},
{"m", 30 * DAY, false},
{"quarterly", 91 * DAY, true},
{"quarters", 91 * DAY, false},
{"quarter", 91 * DAY, true},
{"qrtrs", 91 * DAY, false},
{"qrtr", 91 * DAY, true},
{"qtrs", 91 * DAY, false},
{"qtr", 91 * DAY, false},
{"qtr", 91 * DAY, true},
{"q", 91 * DAY, false},
{"semiannual", 183 * DAY, true},
{"sennight", 14 * DAY, false},
{"seconds", 1 * SECOND, false},
{"second", 1 * SECOND, true},
{"secs", 1 * SECOND, true},
{"secs", 1 * SECOND, false},
{"sec", 1 * SECOND, true},
{"s", 1 * SECOND, false},
{"weekdays", 1 * DAY, true},
{"weekly", 7 * DAY, true},
{"weeks", 7 * DAY, false},
{"week", 7 * DAY, true},
{"wks", 7 * DAY, true},
{"wks", 7 * DAY, false},
{"wk", 7 * DAY, true},
{"w", 7 * DAY, false},
{"yearly", 365 * DAY, true},
{"years", 365 * DAY, false},
{"year", 365 * DAY, true},
{"yrs", 365 * DAY, true},
{"yrs", 365 * DAY, false},
{"yr", 365 * DAY, true},
{"y", 365 * DAY, false},
};
@@ -124,7 +125,7 @@ Duration::Duration (time_t input)
Duration::Duration (const std::string& input)
: _secs (0)
{
if (digitsOnly (input))
if (Lexer::isAllDigits (input))
{
time_t value = (time_t) strtol (input.c_str (), NULL, 10);
if (value == 0 || value > 60)
@@ -301,10 +302,11 @@ bool Duration::parse (const std::string& input, std::string::size_type& start)
std::string::size_type original_start = start;
Nibbler n (input.substr (start));
// TODO This can be made static, and so preserved between calls.
std::vector <std::string> units;
for (int i = 0; i < NUM_DURATIONS; i++)
units.push_back (durations[i].unit);
// Static and so preserved between calls.
static std::vector <std::string> units;
if (units.size () == 0)
for (unsigned int i = 0; i < NUM_DURATIONS; i++)
units.push_back (durations[i].unit);
std::string number;
std::string unit;
@@ -312,13 +314,12 @@ bool Duration::parse (const std::string& input, std::string::size_type& start)
if (n.getOneOf (units, unit))
{
if (n.depleted () ||
Lexer::is_ws (n.next ()))
Lexer::isWhitespace (n.next ()))
{
start = original_start + n.cursor ();
// Linear lookup - should be logarithmic.
double seconds = 1;
for (int i = 0; i < NUM_DURATIONS; i++)
for (unsigned int i = 0; i < NUM_DURATIONS; i++)
{
if (durations[i].unit == unit &&
durations[i].standalone == true)
@@ -336,14 +337,14 @@ bool Duration::parse (const std::string& input, std::string::size_type& start)
if (n.getOneOf (units, unit))
{
if (n.depleted () ||
Lexer::is_ws (n.next ()))
Lexer::isWhitespace (n.next ()))
{
start = original_start + n.cursor ();
double quantity = strtod (number.c_str (), NULL);
// Linear lookup - should be logarithmic.
double seconds = 1;
for (int i = 0; i < NUM_DURATIONS; i++)
for (unsigned int i = 0; i < NUM_DURATIONS; i++)
{
if (durations[i].unit == unit)
{

View File

@@ -127,7 +127,7 @@ void Eval::evaluateInfixExpression (const std::string& e, Variant& v) const
// Reduce e to a vector of tokens.
Lexer l (e);
l.ambiguity (_ambiguity);
std::vector <std::pair <std::string, Lexer::Type> > tokens;
std::vector <std::pair <std::string, Lexer::Type>> tokens;
std::string token;
Lexer::Type type;
while (l.token (token, type))
@@ -155,7 +155,7 @@ void Eval::evaluatePostfixExpression (const std::string& e, Variant& v) const
// Reduce e to a vector of tokens.
Lexer l (e);
l.ambiguity (_ambiguity);
std::vector <std::pair <std::string, Lexer::Type> > tokens;
std::vector <std::pair <std::string, Lexer::Type>> tokens;
std::string token;
Lexer::Type type;
while (l.token (token, type))
@@ -179,7 +179,7 @@ void Eval::compileExpression (const std::string& e)
while (l.token (token, type))
{
if (_debug)
context.debug ("Lexer '" + token + "' " + Lexer::type_name (type));
context.debug ("Lexer '" + token + "' " + Lexer::typeToString (type));
_compiled.push_back (std::pair <std::string, Lexer::Type> (token, type));
}
@@ -236,7 +236,7 @@ void Eval::getBinaryOperators (std::vector <std::string>& all)
////////////////////////////////////////////////////////////////////////////////
void Eval::evaluatePostfixStack (
const std::vector <std::pair <std::string, Lexer::Type> >& tokens,
const std::vector <std::pair <std::string, Lexer::Type>>& tokens,
Variant& result) const
{
if (tokens.size () == 0)
@@ -245,11 +245,11 @@ void Eval::evaluatePostfixStack (
// This is stack used by the postfix evaluator.
std::vector <Variant> values;
std::vector <std::pair <std::string, Lexer::Type> >::const_iterator token;
std::vector <std::pair <std::string, Lexer::Type>>::const_iterator token;
for (token = tokens.begin (); token != tokens.end (); ++token)
{
// Unary operators.
if (token->second == Lexer::typeOperator &&
if (token->second == Lexer::Type::op &&
token->first == "!")
{
if (values.size () < 1)
@@ -262,7 +262,7 @@ void Eval::evaluatePostfixStack (
if (_debug)
context.debug (format ("Eval {1} ↓'{2}' → ↑'{3}'", token->first, (std::string) right, (std::string) result));
}
else if (token->second == Lexer::typeOperator &&
else if (token->second == Lexer::Type::op &&
token->first == "_neg_")
{
if (values.size () < 1)
@@ -278,7 +278,7 @@ void Eval::evaluatePostfixStack (
if (_debug)
context.debug (format ("Eval {1} ↓'{2}' → ↑'{3}'", token->first, (std::string) right, (std::string) result));
}
else if (token->second == Lexer::typeOperator &&
else if (token->second == Lexer::Type::op &&
token->first == "_pos_")
{
// The _pos_ operator is a NOP.
@@ -287,7 +287,7 @@ void Eval::evaluatePostfixStack (
}
// Binary operators.
else if (token->second == Lexer::typeOperator)
else if (token->second == Lexer::Type::op)
{
if (values.size () < 2)
throw std::string (STRING_EVAL_NO_EVAL);
@@ -338,24 +338,28 @@ void Eval::evaluatePostfixStack (
Variant v (token->first);
switch (token->second)
{
case Lexer::typeNumber:
case Lexer::typeHex:
v.cast (Variant::type_integer);
if (_debug)
context.debug (format ("Eval literal number ↑'{1}'", (std::string) v));
case Lexer::Type::number:
if (Lexer::isAllDigits (token->first))
{
v.cast (Variant::type_integer);
if (_debug)
context.debug (format ("Eval literal number ↑'{1}'", (std::string) v));
}
else
{
v.cast (Variant::type_real);
if (_debug)
context.debug (format ("Eval literal decimal ↑'{1}'", (std::string) v));
}
break;
case Lexer::typeDecimal:
v.cast (Variant::type_real);
if (_debug)
context.debug (format ("Eval literal decimal ↑'{1}'", (std::string) v));
break;
case Lexer::typeOperator:
case Lexer::Type::op:
throw std::string (STRING_EVAL_OP_EXPECTED);
break;
case Lexer::typeIdentifier:
case Lexer::Type::dom:
case Lexer::Type::identifier:
{
bool found = false;
std::vector <bool (*)(const std::string&, Variant&)>::const_iterator source;
@@ -380,20 +384,33 @@ void Eval::evaluatePostfixStack (
}
break;
case Lexer::typeDate:
case Lexer::Type::date:
v.cast (Variant::type_date);
if (_debug)
context.debug (format ("Eval literal date ↑'{1}'", (std::string) v));
break;
case Lexer::typeDuration:
case Lexer::Type::duration:
v.cast (Variant::type_duration);
if (_debug)
context.debug (format ("Eval literal duration ↑'{1}'", (std::string) v));
break;
// Nothing to do.
case Lexer::typeString:
/*
case Lexer::Type::uuid:
case Lexer::Type::hex:
case Lexer::Type::list:
case Lexer::Type::url:
case Lexer::Type::pair:
case Lexer::Type::separator:
case Lexer::Type::tag:
case Lexer::Type::path:
case Lexer::Type::substitution:
case Lexer::Type::pattern:
case Lexer::Type::word:
*/
case Lexer::Type::string:
default:
if (_debug)
context.debug (format ("Eval literal string ↑'{1}'", (std::string) v));
@@ -427,26 +444,26 @@ void Eval::evaluatePostfixStack (
// Primitive --> "(" Logical ")" | Variant
//
void Eval::infixParse (
std::vector <std::pair <std::string, Lexer::Type> >& infix) const
std::vector <std::pair <std::string, Lexer::Type>>& infix) const
{
int i = 0;
unsigned int i = 0;
parseLogical (infix, i);
}
////////////////////////////////////////////////////////////////////////////////
// Logical --> Regex {( "and" | "or" | "xor" ) Regex}
bool Eval::parseLogical (
std::vector <std::pair <std::string, Lexer::Type> >& infix,
int &i) const
std::vector <std::pair <std::string, Lexer::Type>>& infix,
unsigned int &i) const
{
if (i < infix.size () &&
parseRegex (infix, i))
{
while (i < infix.size () &&
infix[i].second == Lexer::Type::op &&
(infix[i].first == "and" ||
infix[i].first == "or" ||
infix[i].first == "xor") &&
infix[i].second == Lexer::typeOperator)
infix[i].first == "xor"))
{
++i;
if (! parseRegex (infix, i))
@@ -462,16 +479,16 @@ bool Eval::parseLogical (
////////////////////////////////////////////////////////////////////////////////
// Regex --> Equality {( "~" | "!~" ) Equality}
bool Eval::parseRegex (
std::vector <std::pair <std::string, Lexer::Type> >& infix,
int &i) const
std::vector <std::pair <std::string, Lexer::Type>>& infix,
unsigned int &i) const
{
if (i < infix.size () &&
parseEquality (infix, i))
{
while (i < infix.size () &&
infix[i].second == Lexer::Type::op &&
(infix[i].first == "~" ||
infix[i].first == "!~") &&
infix[i].second == Lexer::typeOperator)
infix[i].first == "!~"))
{
++i;
if (! parseEquality (infix, i))
@@ -487,18 +504,18 @@ bool Eval::parseRegex (
////////////////////////////////////////////////////////////////////////////////
// Equality --> Comparative {( "==" | "=" | "!==" | "!=" ) Comparative}
bool Eval::parseEquality (
std::vector <std::pair <std::string, Lexer::Type> >& infix,
int &i) const
std::vector <std::pair <std::string, Lexer::Type>>& infix,
unsigned int &i) const
{
if (i < infix.size () &&
parseComparative (infix, i))
{
while (i < infix.size () &&
infix[i].second == Lexer::Type::op &&
(infix[i].first == "==" ||
infix[i].first == "=" ||
infix[i].first == "!==" ||
infix[i].first == "!=") &&
infix[i].second == Lexer::typeOperator)
infix[i].first == "!="))
{
++i;
if (! parseComparative (infix, i))
@@ -514,18 +531,18 @@ bool Eval::parseEquality (
////////////////////////////////////////////////////////////////////////////////
// Comparative --> Arithmetic {( "<=" | "<" | ">=" | ">" ) Arithmetic}
bool Eval::parseComparative (
std::vector <std::pair <std::string, Lexer::Type> >& infix,
int &i) const
std::vector <std::pair <std::string, Lexer::Type>>& infix,
unsigned int &i) const
{
if (i < infix.size () &&
parseArithmetic (infix, i))
{
while (i < infix.size () &&
infix[i].second == Lexer::Type::op &&
(infix[i].first == "<=" ||
infix[i].first == "<" ||
infix[i].first == ">=" ||
infix[i].first == ">") &&
infix[i].second == Lexer::typeOperator)
infix[i].first == ">"))
{
++i;
if (! parseArithmetic (infix, i))
@@ -541,16 +558,16 @@ bool Eval::parseComparative (
////////////////////////////////////////////////////////////////////////////////
// Arithmetic --> Geometric {( "+" | "-" ) Geometric}
bool Eval::parseArithmetic (
std::vector <std::pair <std::string, Lexer::Type> >& infix,
int &i) const
std::vector <std::pair <std::string, Lexer::Type>>& infix,
unsigned int &i) const
{
if (i < infix.size () &&
parseGeometric (infix, i))
{
while (i < infix.size () &&
infix[i].second == Lexer::Type::op &&
(infix[i].first == "+" ||
infix[i].first == "-") &&
infix[i].second == Lexer::typeOperator)
infix[i].first == "-"))
{
++i;
if (! parseGeometric (infix, i))
@@ -566,17 +583,17 @@ bool Eval::parseArithmetic (
////////////////////////////////////////////////////////////////////////////////
// Geometric --> Tag {( "*" | "/" | "%" ) Tag}
bool Eval::parseGeometric (
std::vector <std::pair <std::string, Lexer::Type> >& infix,
int &i) const
std::vector <std::pair <std::string, Lexer::Type>>& infix,
unsigned int &i) const
{
if (i < infix.size () &&
parseTag (infix, i))
{
while (i < infix.size () &&
infix[i].second == Lexer::Type::op &&
(infix[i].first == "*" ||
infix[i].first == "/" ||
infix[i].first == "%") &&
infix[i].second == Lexer::typeOperator)
infix[i].first == "%"))
{
++i;
if (! parseTag (infix, i))
@@ -592,16 +609,16 @@ bool Eval::parseGeometric (
////////////////////////////////////////////////////////////////////////////////
// Tag --> Unary {( "_hastag_" | "_notag_" ) Unary}
bool Eval::parseTag (
std::vector <std::pair <std::string, Lexer::Type> >& infix,
int &i) const
std::vector <std::pair <std::string, Lexer::Type>>& infix,
unsigned int &i) const
{
if (i < infix.size () &&
parseUnary (infix, i))
{
while (i < infix.size () &&
infix[i].second == Lexer::Type::op &&
(infix[i].first == "_hastag_" ||
infix[i].first == "_notag_") &&
infix[i].second == Lexer::typeOperator)
infix[i].first == "_notag_"))
{
++i;
if (! parseUnary (infix, i))
@@ -617,8 +634,8 @@ bool Eval::parseTag (
////////////////////////////////////////////////////////////////////////////////
// Unary --> [( "-" | "+" | "!" )] Exponent
bool Eval::parseUnary (
std::vector <std::pair <std::string, Lexer::Type> >& infix,
int &i) const
std::vector <std::pair <std::string, Lexer::Type>>& infix,
unsigned int &i) const
{
if (i < infix.size ())
{
@@ -644,15 +661,15 @@ bool Eval::parseUnary (
////////////////////////////////////////////////////////////////////////////////
// Exponent --> Primitive ["^" Primitive]
bool Eval::parseExponent (
std::vector <std::pair <std::string, Lexer::Type> >& infix,
int &i) const
std::vector <std::pair <std::string, Lexer::Type>>& infix,
unsigned int& i) const
{
if (i < infix.size () &&
parsePrimitive (infix, i))
{
while (i < infix.size () &&
infix[i].first == "^" &&
infix[i].second == Lexer::typeOperator)
infix[i].second == Lexer::Type::op &&
infix[i].first == "^")
{
++i;
if (! parsePrimitive (infix, i))
@@ -668,8 +685,8 @@ bool Eval::parseExponent (
////////////////////////////////////////////////////////////////////////////////
// Primitive --> "(" Logical ")" | Variant
bool Eval::parsePrimitive (
std::vector <std::pair <std::string, Lexer::Type> >& infix,
int &i) const
std::vector <std::pair <std::string, Lexer::Type>>& infix,
unsigned int &i) const
{
if (i < infix.size ())
{
@@ -706,7 +723,7 @@ bool Eval::parsePrimitive (
++i;
return true;
}
else if (infix[i].second != Lexer::typeOperator)
else if (infix[i].second != Lexer::Type::op)
{
++i;
return true;
@@ -750,32 +767,32 @@ bool Eval::parsePrimitive (
// Exit.
//
void Eval::infixToPostfix (
std::vector <std::pair <std::string, Lexer::Type> >& infix) const
std::vector <std::pair <std::string, Lexer::Type>>& infix) const
{
// Short circuit.
if (infix.size () == 1)
return;
// Result.
std::vector <std::pair <std::string, Lexer::Type> > postfix;
std::vector <std::pair <std::string, Lexer::Type>> postfix;
// Shunting yard.
std::vector <std::pair <std::string, Lexer::Type> > op_stack;
std::vector <std::pair <std::string, Lexer::Type>> op_stack;
// Operator characteristics.
char type;
int precedence;
unsigned int precedence;
char associativity;
std::vector <std::pair <std::string, Lexer::Type> >::iterator token;
std::vector <std::pair <std::string, Lexer::Type>>::iterator token;
for (token = infix.begin (); token != infix.end (); ++token)
{
if (token->second == Lexer::typeOperator &&
if (token->second == Lexer::Type::op &&
token->first == "(")
{
op_stack.push_back (*token);
}
else if (token->second == Lexer::typeOperator &&
else if (token->second == Lexer::Type::op &&
token->first == ")")
{
while (op_stack.size () &&
@@ -790,11 +807,11 @@ void Eval::infixToPostfix (
else
throw std::string ("Mismatched parentheses in expression");
}
else if (token->second == Lexer::typeOperator &&
else if (token->second == Lexer::Type::op &&
identifyOperator (token->first, type, precedence, associativity))
{
char type2;
int precedence2;
unsigned int precedence2;
char associativity2;
while (op_stack.size () > 0 &&
identifyOperator (op_stack.back ().first, type2, precedence2, associativity2) &&
@@ -830,7 +847,7 @@ void Eval::infixToPostfix (
bool Eval::identifyOperator (
const std::string& op,
char& type,
int& precedence,
unsigned int& precedence,
char& associativity) const
{
for (unsigned int i = 0; i < NUM_OPERATORS; ++i)
@@ -849,22 +866,21 @@ bool Eval::identifyOperator (
////////////////////////////////////////////////////////////////////////////////
std::string Eval::dump (
std::vector <std::pair <std::string, Lexer::Type> >& tokens) const
std::vector <std::pair <std::string, Lexer::Type>>& tokens) const
{
// Set up a color mapping.
std::map <Lexer::Type, Color> color_map;
color_map[Lexer::typeNone] = Color ("rgb000 on gray6");
color_map[Lexer::typeOperator] = Color ("gray14 on gray6");
color_map[Lexer::typeNumber] = Color ("rgb530 on gray6");
color_map[Lexer::typeHex] = Color ("rgb303 on gray6");
color_map[Lexer::typeDecimal] = Color ("rgb530 on gray6");
color_map[Lexer::typeString] = Color ("rgb550 on gray6");
color_map[Lexer::typeIdentifier] = Color ("rgb035 on gray6");
color_map[Lexer::typeDate] = Color ("rgb150 on gray6");
color_map[Lexer::typeDuration] = Color ("rgb531 on gray6");
color_map[Lexer::Type::op] = Color ("gray14 on gray6");
color_map[Lexer::Type::number] = Color ("rgb530 on gray6");
color_map[Lexer::Type::hex] = Color ("rgb303 on gray6");
color_map[Lexer::Type::string] = Color ("rgb550 on gray6");
color_map[Lexer::Type::dom] = Color ("rgb045 on gray6");
color_map[Lexer::Type::identifier] = Color ("rgb035 on gray6");
color_map[Lexer::Type::date] = Color ("rgb150 on gray6");
color_map[Lexer::Type::duration] = Color ("rgb531 on gray6");
std::string output;
std::vector <std::pair <std::string, Lexer::Type> >::const_iterator i;
std::vector <std::pair <std::string, Lexer::Type>>::const_iterator i;
for (i = tokens.begin (); i != tokens.end (); ++i)
{
if (i != tokens.begin ())
@@ -874,7 +890,7 @@ std::string Eval::dump (
if (color_map[i->second].nontrivial ())
c = color_map[i->second];
else
c = color_map[Lexer::typeNone];
c = Color ("rgb000 on gray6");
output += c.colorize (i->first);
}

View File

@@ -53,28 +53,28 @@ public:
static void getBinaryOperators (std::vector <std::string>&);
private:
void evaluatePostfixStack (const std::vector <std::pair <std::string, Lexer::Type> >&, Variant&) const;
void infixToPostfix (std::vector <std::pair <std::string, Lexer::Type> >&) const;
void infixParse (std::vector <std::pair <std::string, Lexer::Type> >&) const;
bool parseLogical (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
bool parseRegex (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
bool parseEquality (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
bool parseComparative (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
bool parseArithmetic (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
bool parseGeometric (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
bool parseTag (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
bool parseUnary (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
bool parseExponent (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
bool parsePrimitive (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
bool identifyOperator (const std::string&, char&, int&, char&) const;
void evaluatePostfixStack (const std::vector <std::pair <std::string, Lexer::Type>>&, Variant&) const;
void infixToPostfix (std::vector <std::pair <std::string, Lexer::Type>>&) const;
void infixParse (std::vector <std::pair <std::string, Lexer::Type>>&) const;
bool parseLogical (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
bool parseRegex (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
bool parseEquality (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
bool parseComparative (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
bool parseArithmetic (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
bool parseGeometric (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
bool parseTag (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
bool parseUnary (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
bool parseExponent (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
bool parsePrimitive (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
bool identifyOperator (const std::string&, char&, unsigned int&, char&) const;
std::string dump (std::vector <std::pair <std::string, Lexer::Type> >&) const;
std::string dump (std::vector <std::pair <std::string, Lexer::Type>>&) const;
private:
std::vector <bool (*)(const std::string&, Variant&)> _sources;
bool _ambiguity;
bool _debug;
std::vector <std::pair <std::string, Lexer::Type> > _compiled;
std::vector <std::pair <std::string, Lexer::Type>> _compiled;
};

View File

@@ -28,14 +28,10 @@
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef SOLARIS
#include <fcntl.h> // for flock() replacement
#include <string.h> // for memset()
#else
#include <sys/file.h>
#endif
#include <pwd.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <pwd.h>
#include <File.h>
#include <text.h>
#include <util.h>
@@ -151,6 +147,9 @@ void File::close ()
{
if (_fh)
{
if (_locked)
unlock ();
fclose (_fh);
_fh = NULL;
_h = -1;
@@ -161,38 +160,31 @@ void File::close ()
////////////////////////////////////////////////////////////////////////////////
bool File::lock ()
{
_locked = false;
if (_fh && _h != -1)
{
// Try three times before failing.
int retry = 0;
while (flock (_h, LOCK_NB | LOCK_EX) && ++retry <= 3)
;
if (retry <= 3)
{
// l_type l_whence l_start l_len l_pid
struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0 };
fl.l_pid = getpid ();
if (fcntl (_h, F_SETLKW, &fl) == 0)
_locked = true;
return true;
}
}
_locked = false;
return false;
return _locked;
}
////////////////////////////////////////////////////////////////////////////////
bool File::waitForLock ()
void File::unlock ()
{
if (_locked)
return true;
{
// l_type l_whence l_start l_len l_pid
struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0 };
fl.l_pid = getpid ();
if (_fh && _h != -1)
if (flock (_h, LOCK_EX) == 0)
{
_locked = true;
return true;
}
return false;
fcntl (_h, F_SETLK, &fl);
_locked = false;
}
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -52,7 +52,7 @@ public:
void close ();
bool lock ();
bool waitForLock ();
void unlock ();
void read (std::string&);
void read (std::vector <std::string>&);

View File

@@ -466,7 +466,7 @@ void Hooks::assertValidJSON (const std::vector <std::string>& input) const
}
////////////////////////////////////////////////////////////////////////////////
void Hooks::assertNTasks (const std::vector <std::string>& input, int n) const
void Hooks::assertNTasks (const std::vector <std::string>& input, unsigned int n) const
{
if (input.size () != n)
{
@@ -520,6 +520,33 @@ void Hooks::assertFeedback (const std::vector <std::string>& input) const
}
}
////////////////////////////////////////////////////////////////////////////////
std::vector <std::string>& Hooks::buildHookScriptArgs (std::vector <std::string>& args)
{
Variant v;
// Hooks API version.
args.push_back ("api:2");
// Command line Taskwarrior was called with.
context.dom.get ("context.args", v);
args.push_back ("args:" + std::string (v));
// Command to be executed.
args.push_back ("command:" + context.cli.getCommand ());
// rc file used after applying all overrides.
args.push_back ("rc:" + context.rc_file._data);
// Directory containing *.data files.
args.push_back ("data:" + context.data_dir._data);
// Taskwarrior version, same as returned by "task --version"
args.push_back ("version:" + std::string(VERSION));
return args;
}
////////////////////////////////////////////////////////////////////////////////
int Hooks::callHookScript (
const std::string& script,
@@ -542,11 +569,18 @@ int Hooks::callHookScript (
for (i = input.begin (); i != input.end (); ++i)
inputStr += *i + "\n";
std::string outputStr;
std::vector <std::string> args;
int status;
buildHookScriptArgs (args);
if (_debug >= 2)
{
context.debug ("Hooks: args");
for (auto arg: args)
context.debug (" " + arg);
}
// Measure time for each hook if running in debug
int status;
std::string outputStr;
if (_debug >= 2)
{
Timer timer_per_hook("Hooks::execute (" + script + ")");

View File

@@ -54,9 +54,10 @@ private:
void separateOutput (const std::vector <std::string>&, std::vector <std::string>&, std::vector <std::string>&) const;
bool isJSON (const std::string&) const;
void assertValidJSON (const std::vector <std::string>&) const;
void assertNTasks (const std::vector <std::string>&, int) const;
void assertNTasks (const std::vector <std::string>&, unsigned int) const;
void assertSameTask (const std::vector <std::string>&, const Task&) const;
void assertFeedback (const std::vector <std::string>&) const;
std::vector <std::string>& buildHookScriptArgs (std::vector <std::string>&);
int callHookScript (const std::string&, const std::vector <std::string>&, std::vector <std::string>&);
private:

View File

@@ -25,6 +25,7 @@
////////////////////////////////////////////////////////////////////////////////
#include <cmake.h>
#include <Lexer.h>
#include <ISO8601.h>
////////////////////////////////////////////////////////////////////////////////
@@ -196,7 +197,7 @@ bool ISO8601d::parse_date_time_ext (Nibbler& n)
else if (parse_off_ext (n))
;
if (! isdigit (n.next ()))
if (! Lexer::isDigit (n.next ()))
return true;
}
@@ -228,16 +229,16 @@ bool ISO8601d::parse_date_time (Nibbler& n)
if (n.skip ('Z'))
{
_utc = true;
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}
else if (parse_off (n))
{
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}
@@ -277,13 +278,13 @@ bool ISO8601d::parse_date_ext (Nibbler& n)
}
_year = year;
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}
else if (n.getDigit3 (_julian))
{
_year = year;
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}
else if (n.getDigit2 (month) &&
@@ -293,7 +294,7 @@ bool ISO8601d::parse_date_ext (Nibbler& n)
_year = year;
_month = month;
_day = day;
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}
}
@@ -327,7 +328,7 @@ bool ISO8601d::parse_date (Nibbler& n, bool ambiguous)
_weekday = day;
_year = year;
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}
}
@@ -336,7 +337,7 @@ bool ISO8601d::parse_date (Nibbler& n, bool ambiguous)
if (n.getDigit2 (_month))
{
_year = year;
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}
}
@@ -345,13 +346,13 @@ bool ISO8601d::parse_date (Nibbler& n, bool ambiguous)
_year = year;
_month = month / 100;
_day = month % 100;
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}
else if (ambiguous && n.getDigit3 (_julian))
{
_year = year;
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}
}
@@ -382,7 +383,7 @@ bool ISO8601d::parse_off_ext (Nibbler& n)
offset += mm * 60;
_offset = (sign == "-") ? -offset : offset;
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}
}
@@ -412,7 +413,7 @@ bool ISO8601d::parse_off (Nibbler& n)
offset += mm * 60;
_offset = (sign == "-") ? -offset : offset;
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}
}
@@ -453,7 +454,7 @@ bool ISO8601d::parse_time_ext (Nibbler& n)
if (_ambiguity)
{
_seconds = seconds;
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}
}
@@ -487,7 +488,7 @@ bool ISO8601d::parse_time (Nibbler& n, bool ambiguous)
}
_seconds = seconds;
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}
@@ -504,7 +505,7 @@ bool ISO8601d::parse_time_utc_ext (Nibbler& n)
n.skip ('Z'))
{
_utc = true;
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}
@@ -521,7 +522,7 @@ bool ISO8601d::parse_time_utc (Nibbler& n)
n.skip ('Z'))
{
_utc = true;
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}
@@ -537,7 +538,7 @@ bool ISO8601d::parse_time_off_ext (Nibbler& n)
if (parse_time_ext (n) &&
parse_off_ext (n))
{
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}
@@ -553,7 +554,7 @@ bool ISO8601d::parse_time_off (Nibbler& n)
if (parse_time (n, true) &&
parse_off (n))
{
if (!isdigit (n.next ()))
if (!Lexer::isDigit (n.next ()))
return true;
}

File diff suppressed because it is too large Load Diff

View File

@@ -27,92 +27,86 @@
#ifndef INCLUDED_LEXER
#define INCLUDED_LEXER
#include <vector>
#include <string>
#include <vector>
#include <cstddef>
// Lexer: A UTF8 lexical analyzer for every construct used on the Taskwarrior
// command line, with additional recognized types for disambiguation.
class Lexer
{
public:
// These are overridable.
static std::string dateFormat;
static bool isoEnabled;
enum Type
{
typeNone = 0,
typeString,
typeIdentifier,
typeIdentifierEscape, // Intermediate
typeEscape, // Intermediate
typeEscapeHex, // Intermediate
typeEscapeUnicode, // Intermediate
typeNumber,
typeDecimal,
typeExponentIndicator, // Intermediate
typeExponent, // Intermediate
typeHex,
typeOperator,
typeDate,
typeDuration,
typeTag,
/*
Recognizing more types means that Lexer::*_split and Lexer::token approach
the ideal form, whereby the command line becomes just one string that is
lexed into tokens. Those tokens are then simply dissected by type..
typeUUID,
typePattern,
typeSubstitution,
typeNameValue,
*/
};
enum class Type { uuid, number, hex,
string,
list, url, pair, separator,
tag,
path,
substitution, pattern,
op,
dom, identifier, word,
date, duration };
Lexer (const std::string&);
virtual ~Lexer ();
Lexer (const Lexer&); // Not implemented.
Lexer& operator= (const Lexer&); // Not implemented.
bool operator== (const Lexer&); // Not implemented.
bool token (std::string&, Type&);
bool word (std::string&, Type&);
~Lexer ();
void ambiguity (bool);
bool token (std::string&, Lexer::Type&);
static std::vector <std::pair <std::string, Lexer::Type>> tokens (const std::string&);
static std::vector <std::string> split (const std::string&);
static std::string typeToString (Lexer::Type);
static bool isAllDigits (const std::string&);
static bool isOneWord (const std::string&);
static const std::string type_name (const Type&);
static bool is_ws (int);
static bool is_ident_start (int);
static bool is_ident (int);
static bool is_single_op (int);
static bool is_dec_digit (int);
static bool boundary (int, int);
static void word_split (std::vector <std::string>&, const std::string&);
static void token_split (std::vector <std::string>&, const std::string&);
static void token_split (std::vector <std::pair <std::string, Lexer::Type> >&, const std::string&);
// Static helpers.
static const std::string typeName (const Lexer::Type&);
static bool isWhitespace (int);
static bool isAlpha (int);
static bool isDigit (int);
static bool isHexDigit (int);
static bool isIdentifierStart (int);
static bool isIdentifierNext (int);
static bool isSingleCharOperator (int);
static bool isDoubleCharOperator (int, int, int);
static bool isTripleCharOperator (int, int, int, int);
static bool isBoundary (int, int);
static bool isPunctuation (int);
static void dequote (std::string&);
private:
bool is_date (std::string&);
bool is_duration (std::string&);
bool is_punct (int) const;
bool is_num (int) const;
bool is_triple_op (int, int, int) const;
bool is_double_op (int, int, int) const;
bool is_hex_digit (int) const;
int decode_escape (int) const;
int hex_to_int (int) const;
int hex_to_int (int, int) const;
int hex_to_int (int, int, int, int) const;
void shift ();
// Helpers.
bool isEOS () const;
int hexToInt (int) const;
int hexToInt (int, int) const;
int hexToInt (int, int, int, int) const;
// Classifiers.
bool isString (std::string&, Lexer::Type&, int quote);
bool isDate (std::string&, Lexer::Type&);
bool isDuration (std::string&, Lexer::Type&);
bool isUUID (std::string&, Lexer::Type&);
bool isNumber (std::string&, Lexer::Type&);
bool isHexNumber (std::string&, Lexer::Type&);
bool isSeparator (std::string&, Lexer::Type&);
bool isList (std::string&, Lexer::Type&);
bool isURL (std::string&, Lexer::Type&);
bool isPair (std::string&, Lexer::Type&);
bool isTag (std::string&, Lexer::Type&);
bool isPath (std::string&, Lexer::Type&);
bool isSubstitution (std::string&, Lexer::Type&);
bool isPattern (std::string&, Lexer::Type&);
bool isOperator (std::string&, Lexer::Type&);
bool isDOM (std::string&, Lexer::Type&);
bool isIdentifier (std::string&, Lexer::Type&);
bool isWord (std::string&, Lexer::Type&);
private:
const std::string _input;
std::string::size_type _i;
std::string::size_type _shift_counter;
int _n0;
int _n1;
int _n2;
int _n3;
bool _boundary01;
bool _boundary12;
bool _boundary23;
bool _ambiguity;
std::string _text;
std::size_t _cursor;
std::size_t _eos;
bool _ambiguity;
};
#endif

View File

@@ -27,9 +27,9 @@
#include <cmake.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <inttypes.h>
#include <Lexer.h>
#include <Nibbler.h>
#ifdef NIBBLER_FEATURE_DATE
#include <Date.h>
@@ -284,7 +284,7 @@ bool Nibbler::getQuoted (
bool Nibbler::getDigit (int& result)
{
if (_cursor < _length &&
isdigit (_input[_cursor]))
Lexer::isDigit (_input[_cursor]))
{
result = _input[_cursor++] - '0';
return true;
@@ -300,12 +300,12 @@ bool Nibbler::getDigit6 (int& result)
if (i < _length &&
_length - i >= 6)
{
if (isdigit (_input[i + 0]) &&
isdigit (_input[i + 1]) &&
isdigit (_input[i + 2]) &&
isdigit (_input[i + 3]) &&
isdigit (_input[i + 4]) &&
isdigit (_input[i + 5]))
if (Lexer::isDigit (_input[i + 0]) &&
Lexer::isDigit (_input[i + 1]) &&
Lexer::isDigit (_input[i + 2]) &&
Lexer::isDigit (_input[i + 3]) &&
Lexer::isDigit (_input[i + 4]) &&
Lexer::isDigit (_input[i + 5]))
{
result = strtoimax (_input.substr (_cursor, 6).c_str (), NULL, 10);
_cursor += 6;
@@ -323,10 +323,10 @@ bool Nibbler::getDigit4 (int& result)
if (i < _length &&
_length - i >= 4)
{
if (isdigit (_input[i + 0]) &&
isdigit (_input[i + 1]) &&
isdigit (_input[i + 2]) &&
isdigit (_input[i + 3]))
if (Lexer::isDigit (_input[i + 0]) &&
Lexer::isDigit (_input[i + 1]) &&
Lexer::isDigit (_input[i + 2]) &&
Lexer::isDigit (_input[i + 3]))
{
result = strtoimax (_input.substr (_cursor, 4).c_str (), NULL, 10);
_cursor += 4;
@@ -344,9 +344,9 @@ bool Nibbler::getDigit3 (int& result)
if (i < _length &&
_length - i >= 3)
{
if (isdigit (_input[i + 0]) &&
isdigit (_input[i + 1]) &&
isdigit (_input[i + 2]))
if (Lexer::isDigit (_input[i + 0]) &&
Lexer::isDigit (_input[i + 1]) &&
Lexer::isDigit (_input[i + 2]))
{
result = strtoimax (_input.substr (_cursor, 3).c_str (), NULL, 10);
_cursor += 3;
@@ -364,8 +364,8 @@ bool Nibbler::getDigit2 (int& result)
if (i < _length &&
_length - i >= 2)
{
if (isdigit (_input[i + 0]) &&
isdigit (_input[i + 1]))
if (Lexer::isDigit (_input[i + 0]) &&
Lexer::isDigit (_input[i + 1]))
{
result = strtoimax (_input.substr (_cursor, 2).c_str (), NULL, 10);
_cursor += 2;
@@ -390,7 +390,7 @@ bool Nibbler::getInt (int& result)
}
// TODO Potential for use of find_first_not_of
while (i < _length && isdigit (_input[i]))
while (i < _length && Lexer::isDigit (_input[i]))
++i;
if (i > _cursor)
@@ -408,7 +408,7 @@ bool Nibbler::getUnsignedInt (int& result)
{
std::string::size_type i = _cursor;
// TODO Potential for use of find_first_not_of
while (i < _length && isdigit (_input[i]))
while (i < _length && Lexer::isDigit (_input[i]))
++i;
if (i > _cursor)
@@ -446,11 +446,11 @@ bool Nibbler::getNumber (std::string& result)
++i;
// digit+
if (i < _length && isdigit (_input[i]))
if (i < _length && Lexer::isDigit (_input[i]))
{
++i;
while (i < _length && isdigit (_input[i]))
while (i < _length && Lexer::isDigit (_input[i]))
++i;
// ( . digit+ )?
@@ -458,7 +458,7 @@ bool Nibbler::getNumber (std::string& result)
{
++i;
while (i < _length && isdigit (_input[i]))
while (i < _length && Lexer::isDigit (_input[i]))
++i;
}
@@ -470,11 +470,11 @@ bool Nibbler::getNumber (std::string& result)
if (i < _length && (_input[i] == '+' || _input[i] == '-'))
++i;
if (i < _length && isdigit (_input[i]))
if (i < _length && Lexer::isDigit (_input[i]))
{
++i;
while (i < _length && isdigit (_input[i]))
while (i < _length && Lexer::isDigit (_input[i]))
++i;
result = _input.substr (_cursor, i - _cursor);
@@ -528,11 +528,11 @@ bool Nibbler::getUnsignedNumber (double& result)
std::string::size_type i = _cursor;
// digit+
if (i < _length && isdigit (_input[i]))
if (i < _length && Lexer::isDigit (_input[i]))
{
++i;
while (i < _length && isdigit (_input[i]))
while (i < _length && Lexer::isDigit (_input[i]))
++i;
// ( . digit+ )?
@@ -540,7 +540,7 @@ bool Nibbler::getUnsignedNumber (double& result)
{
++i;
while (i < _length && isdigit (_input[i]))
while (i < _length && Lexer::isDigit (_input[i]))
++i;
}
@@ -552,11 +552,11 @@ bool Nibbler::getUnsignedNumber (double& result)
if (i < _length && (_input[i] == '+' || _input[i] == '-'))
++i;
if (i < _length && isdigit (_input[i]))
if (i < _length && Lexer::isDigit (_input[i]))
{
++i;
while (i < _length && isdigit (_input[i]))
while (i < _length && Lexer::isDigit (_input[i]))
++i;
result = strtof (_input.substr (_cursor, i - _cursor).c_str (), NULL);
@@ -710,21 +710,21 @@ bool Nibbler::getDateISO (time_t& t)
if (i < _length &&
_length - i >= 16)
{
if (isdigit (_input[i + 0]) &&
isdigit (_input[i + 1]) &&
isdigit (_input[i + 2]) &&
isdigit (_input[i + 3]) &&
isdigit (_input[i + 4]) &&
isdigit (_input[i + 5]) &&
isdigit (_input[i + 6]) &&
isdigit (_input[i + 7]) &&
if (Lexer::isDigit (_input[i + 0]) &&
Lexer::isDigit (_input[i + 1]) &&
Lexer::isDigit (_input[i + 2]) &&
Lexer::isDigit (_input[i + 3]) &&
Lexer::isDigit (_input[i + 4]) &&
Lexer::isDigit (_input[i + 5]) &&
Lexer::isDigit (_input[i + 6]) &&
Lexer::isDigit (_input[i + 7]) &&
_input[i + 8] == 'T' &&
isdigit (_input[i + 9]) &&
isdigit (_input[i + 10]) &&
isdigit (_input[i + 11]) &&
isdigit (_input[i + 12]) &&
isdigit (_input[i + 13]) &&
isdigit (_input[i + 14]) &&
Lexer::isDigit (_input[i + 9]) &&
Lexer::isDigit (_input[i + 10]) &&
Lexer::isDigit (_input[i + 11]) &&
Lexer::isDigit (_input[i + 12]) &&
Lexer::isDigit (_input[i + 13]) &&
Lexer::isDigit (_input[i + 14]) &&
_input[i + 15] == 'Z')
{
_cursor += 16;
@@ -790,7 +790,7 @@ bool Nibbler::parseDigits(std::string::size_type& i,
// Check that 'f' of them are digits
unsigned int g;
for (g = 0; g < f; g++)
if (! isdigit (_input[i + g]))
if (! Lexer::isDigit (_input[i + g]))
break;
// Parse the integer when it is the case
if (g == f)
@@ -881,9 +881,9 @@ bool Nibbler::getDate (const std::string& format, time_t& t)
case 'a':
case 'A':
if (i + 3 <= _length &&
! isdigit (_input[i + 0]) &&
! isdigit (_input[i + 1]) &&
! isdigit (_input[i + 2]))
! Lexer::isDigit (_input[i + 0]) &&
! Lexer::isDigit (_input[i + 1]) &&
! Lexer::isDigit (_input[i + 2]))
{
wday = Date::dayOfWeek (_input.substr (i, 3).c_str ());
i += (format[f] == 'a') ? 3 : Date::dayName (wday).size ();
@@ -895,9 +895,9 @@ bool Nibbler::getDate (const std::string& format, time_t& t)
case 'b':
case 'B':
if (i + 3 <= _length &&
! isdigit (_input[i + 0]) &&
! isdigit (_input[i + 1]) &&
! isdigit (_input[i + 2]))
! Lexer::isDigit (_input[i + 0]) &&
! Lexer::isDigit (_input[i + 1]) &&
! Lexer::isDigit (_input[i + 2]))
{
if (month != -1)
return false;
@@ -1003,14 +1003,14 @@ bool Nibbler::getName (std::string& result)
if (i < _length)
{
if (! isdigit (_input[i]) &&
if (! Lexer::isDigit (_input[i]) &&
! ispunct (_input[i]) &&
! Lexer::is_ws (_input[i]))
! Lexer::isWhitespace (_input[i]))
{
++i;
while (i < _length &&
(_input[i] == '_' || ! ispunct (_input[i])) &&
! Lexer::is_ws (_input[i]))
! Lexer::isWhitespace (_input[i]))
{
++i;
}
@@ -1035,9 +1035,9 @@ bool Nibbler::getWord (std::string& result)
if (i < _length)
{
while (!isdigit (_input[i]) &&
!isPunctuation (_input[i]) &&
!Lexer::is_ws (_input[i]))
while (!Lexer::isDigit (_input[i]) &&
!Lexer::isPunctuation (_input[i]) &&
!Lexer::isWhitespace (_input[i]))
{
++i;
}
@@ -1227,21 +1227,6 @@ bool Nibbler::depleted ()
return false;
}
////////////////////////////////////////////////////////////////////////////////
// Override of ispunct, that considers #, $, _ and @ not to be punctuation.
//
// ispunct: ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~
// Punctuation: ! " % & ' ( ) * + , - . / : ; < = > ? [ \ ] ^ _ ` { | } ~
// delta: # $ @
//
bool Nibbler::isPunctuation (char c)
{
if (c == '@' || c == '#' || c == '$' || c == '_')
return false;
return ispunct (c);
}
////////////////////////////////////////////////////////////////////////////////
std::string Nibbler::dump ()
{

View File

@@ -110,7 +110,6 @@ public:
bool depleted ();
static bool isPunctuation (char);
std::string dump ();
private:

View File

@@ -102,7 +102,7 @@ bool TF2::get (int id, Task& task)
// pending.data file, the task in question cannot appear earlier than line
// (id - 1) in the file. It can, however, appear significantly later because
// it is not known how recent a GC operation was run.
for (int i = id - 1; i < _tasks.size (); ++i)
for (unsigned int i = id - 1; i < _tasks.size (); ++i)
{
if (_tasks[i].id == id)
{
@@ -226,7 +226,7 @@ void TF2::commit ()
if (_file.open ())
{
if (context.config.getBoolean ("locking"))
_file.waitForLock ();
_file.lock ();
// Write out all the added tasks.
std::vector <Task>::iterator task;
@@ -258,7 +258,7 @@ void TF2::commit ()
if (_file.open ())
{
if (context.config.getBoolean ("locking"))
_file.waitForLock ();
_file.lock ();
// Truncate the file and rewrite.
_file.truncate ();
@@ -316,9 +316,15 @@ void TF2::load_tasks ()
++line_number;
Task task (*i);
// Some tasks gets an ID.
// Some tasks get an ID.
if (_has_ids)
task.id = context.tdb2.next_id ();
{
Task::status status = task.getStatus ();
// Completed / deleted tasks in pending.data get an ID if GC is off.
if (!context.run_gc ||
(status != Task::completed && status != Task::deleted))
task.id = context.tdb2.next_id ();
}
_tasks.push_back (task);
@@ -352,7 +358,7 @@ void TF2::load_lines ()
if (_file.open ())
{
if (context.config.getBoolean ("locking"))
_file.waitForLock ();
_file.lock ();
_file.read (_lines);
_file.close ();
@@ -462,9 +468,13 @@ void TF2::dependency_scan ()
{
if (right->get ("uuid") == *d)
{
Task::status status = right->getStatus ();
if (status != Task::completed &&
status != Task::deleted)
// GC hasn't run yet, check both tasks for their current status
Task::status lstatus = left->getStatus ();
Task::status rstatus = right->getStatus ();
if (lstatus != Task::completed &&
lstatus != Task::deleted &&
rstatus != Task::completed &&
rstatus != Task::deleted)
{
left->is_blocked = true;
right->is_blocking = true;
@@ -559,7 +569,9 @@ void TDB2::set_location (const std::string& location)
void TDB2::add (Task& task, bool add_to_backlog /* = true */)
{
// Ensure the task is consistent, and provide defaults if necessary.
task.validate ();
// bool argument to validate() is "applyDefault". Pass add_to_backlog through
// in order to not apply defaults to synchronized tasks.
task.validate (add_to_backlog);
std::string uuid = task.get ("uuid");
// If the tasks are loaded, then verify that this uuid is not already in
@@ -578,7 +590,7 @@ void TDB2::add (Task& task, bool add_to_backlog /* = true */)
////////////////////////////////////////////////////////////////////////////////
void TDB2::modify (Task& task, bool add_to_backlog /* = true */)
{
// Ensure the task is consistent, and provide defaults if necessary.
// Ensure the task is consistent.
task.validate (false);
std::string uuid = task.get ("uuid");
@@ -598,7 +610,7 @@ void TDB2::update (
const std::string& uuid,
Task& task,
const bool add_to_backlog,
const bool addition)
const bool addition /* = false */)
{
// Validate to add metadata.
task.validate (false);
@@ -607,6 +619,13 @@ void TDB2::update (
Task original;
if (not addition && get (task.get ("uuid"), original))
{
if (add_to_backlog)
{
// All locally modified tasks are timestamped, implicitly overwriting any
// changes the user or hooks tried to apply to the "modified" attribute.
task.setAsNow ("modified");
}
// Update the task, wherever it is.
if (!pending.modify_task (task))
completed.modify_task (task);

View File

@@ -298,7 +298,6 @@ int TLSClient::verify_certificate () const
// This verification function uses the trusted CAs in the credentials
// structure. So you must have installed one or more CA certificates.
unsigned int status = 0;
const char* hostname = _host.c_str();
#if GNUTLS_VERSION_NUMBER >= 0x030104
if (_trust == TLSClient::ignore_hostname)
@@ -350,7 +349,7 @@ int TLSClient::verify_certificate () const
if (_debug)
std::cout << "c: ERROR x509 cert import. " << gnutls_strerror (ret) << "\n";
gnutls_x509_crt_deinit(cert);
status = GNUTLS_E_CERTIFICATE_ERROR;
return GNUTLS_E_CERTIFICATE_ERROR;
}
if (gnutls_x509_crt_check_hostname (cert, hostname) == 0)
@@ -366,7 +365,7 @@ int TLSClient::verify_certificate () const
}
#endif
#if GNUTLS_VERSION_NUMBER >= 0x030105
#if GNUTLS_VERSION_NUMBER >= 0x030104
gnutls_certificate_type_t type = gnutls_certificate_type_get (_session);
gnutls_datum_t out;
ret = gnutls_certificate_verification_status_print (status, type, &out, 0);
@@ -377,6 +376,8 @@ int TLSClient::verify_certificate () const
return GNUTLS_E_CERTIFICATE_ERROR;
}
if (_debug)
std::cout << "c: INFO " << out.data << "\n";
gnutls_free (out.data);
#endif

View File

@@ -65,14 +65,12 @@ static const float epsilon = 0.000001;
#endif
std::string Task::defaultProject = "";
std::string Task::defaultPriority = "";
std::string Task::defaultDue = "";
bool Task::searchCaseSensitive = true;
bool Task::regex = false;
std::map <std::string, std::string> Task::attributes;
std::map <std::string, float> Task::coefficients;
float Task::urgencyPriorityCoefficient = 0.0;
float Task::urgencyProjectCoefficient = 0.0;
float Task::urgencyActiveCoefficient = 0.0;
float Task::urgencyScheduledCoefficient = 0.0;
@@ -87,6 +85,8 @@ float Task::urgencyBlockingCoefficient = 0.0;
float Task::urgencyAgeCoefficient = 0.0;
float Task::urgencyAgeMax = 0.0;
std::map <std::string, std::vector <std::string>> Task::customOrder;
static const std::string dummy ("");
////////////////////////////////////////////////////////////////////////////////
@@ -1384,7 +1384,7 @@ void Task::validate (bool applyDefault /* = true */)
if (!has ("modified") || get ("modified") == "")
setAsNow ("modified");
if (applyDefault)
if (applyDefault && (! has ("parent") || get ("parent") == ""))
{
// Override with default.project, if not specified.
if (Task::defaultProject != "" &&
@@ -1394,14 +1394,6 @@ void Task::validate (bool applyDefault /* = true */)
set ("project", Task::defaultProject);
}
// Override with default.priority, if not specified.
if (Task::defaultPriority != "" &&
! has ("priority"))
{
if (context.columns["priority"]->validate (Task::defaultPriority))
set ("priority", Task::defaultPriority);
}
// Override with default.due, if not specified.
if (Task::defaultDue != "" &&
! has ("due"))
@@ -1487,17 +1479,6 @@ void Task::validate (bool applyDefault /* = true */)
throw std::string (format (STRING_TASK_VALID_RECUR, value));
}
}
// Priorities must be valid.
if (has ("priority"))
{
std::string priority = get ("priority");
if (priority != "H" &&
priority != "M" &&
priority != "L" &&
priority != "")
throw format (STRING_TASK_VALID_PRIORITY, priority);
}
}
////////////////////////////////////////////////////////////////////////////////
@@ -1655,7 +1636,6 @@ float Task::urgency_c () const
{
float value = 0.0;
#ifdef PRODUCT_TASKWARRIOR
value += fabsf (Task::urgencyPriorityCoefficient) > epsilon ? (urgency_priority () * Task::urgencyPriorityCoefficient) : 0.0;
value += fabsf (Task::urgencyProjectCoefficient) > epsilon ? (urgency_project () * Task::urgencyProjectCoefficient) : 0.0;
value += fabsf (Task::urgencyActiveCoefficient) > epsilon ? (urgency_active () * Task::urgencyActiveCoefficient) : 0.0;
value += fabsf (Task::urgencyScheduledCoefficient) > epsilon ? (urgency_scheduled () * Task::urgencyScheduledCoefficient) : 0.0;
@@ -1697,6 +1677,16 @@ float Task::urgency_c () const
if (hasTag (tag))
value += var->second;
}
// urgency.user.keyword.<keyword>.coefficient
if (var->first.substr (13, 8) == "keyword." &&
(end = var->first.find (".coefficient")) != std::string::npos)
{
std::string keyword = var->first.substr (21, end - 21);
if (get ("description").find (keyword) != std::string::npos)
value += var->second;
}
}
else if (var->first.substr (0, 12) == "urgency.uda.")
{
@@ -1742,18 +1732,6 @@ float Task::urgency ()
return urgency_value;
}
////////////////////////////////////////////////////////////////////////////////
float Task::urgency_priority () const
{
const std::string& value = get_ref ("priority");
if (value == "H") return 1.0;
else if (value == "M") return 0.65;
else if (value == "L") return 0.3;
return 0.0;
}
////////////////////////////////////////////////////////////////////////////////
float Task::urgency_inherit () const
{
@@ -1775,7 +1753,6 @@ float Task::urgency_inherit () const
v += it->urgency_annotations ();
v += it->urgency_due ();
v += it->urgency_next ();
v += it->urgency_priority ();
v += it->urgency_scheduled ();
v += it->urgency_waiting ();
@@ -1956,17 +1933,13 @@ void Task::modify (modType type, bool text_required /* = false */)
}
else
{
// Some columns are not modifiable.
if (name == "uuid" ||
name == "id" ||
name == "mask" ||
name == "imask" ||
name == "parent")
throw format (STRING_INVALID_MOD, name, value);
// Get the column info.
Column* column = context.columns[name];
// Some columns are not modifiable.
if (! column->modifiable ())
throw format (STRING_INVALID_MOD, name, value);
// Dependencies are specified as IDs.
if (name == "depends")
{

View File

@@ -37,13 +37,12 @@ class Task : public std::map <std::string, std::string>
{
public:
static std::string defaultProject;
static std::string defaultPriority;
static std::string defaultDue;
static bool searchCaseSensitive;
static bool regex;
static std::map <std::string, std::string> attributes; // name -> type
static std::map <std::string, float> coefficients;
static float urgencyPriorityCoefficient;
static std::map <std::string, std::vector <std::string>> customOrder;
static float urgencyProjectCoefficient;
static float urgencyActiveCoefficient;
static float urgencyScheduledCoefficient;
@@ -164,7 +163,6 @@ private:
const std::string decode (const std::string&) const;
public:
float urgency_priority () const;
float urgency_project () const;
float urgency_active () const;
float urgency_scheduled () const;

View File

@@ -26,6 +26,7 @@
#include <cmake.h>
#include <sstream>
#include <algorithm>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
@@ -135,7 +136,7 @@ Variant::Variant (const char* value)
}
////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const time_t value, const enum type new_type /*=type_date*/)
Variant::Variant (const time_t value, const enum type new_type)
: _type (new_type)
, _bool (false)
, _integer (0)
@@ -166,7 +167,7 @@ void Variant::source (const std::string& input)
}
////////////////////////////////////////////////////////////////////////////////
std::string Variant::source () const
const std::string& Variant::source () const
{
return _source;
}
@@ -314,19 +315,25 @@ bool Variant::operator< (const Variant& other) const
return left._string < right._string;
case type_string:
if (left.source () == "priority" || right.source () == "priority")
{
if (left._string != "H" && right._string == "H") return true;
else if (left._string == "L" && right._string == "M") return true;
else if (left._string == "" && right._string != "") return true;
else return false;
}
else
{
if (left.trivial () || right.trivial ())
if (left._string == right._string)
return false;
return left._string < right._string;
auto order = Task::customOrder.find (left.source ());
if (order != Task::customOrder.end ())
{
// Guaranteed to be found, because of ColUDA::validate ().
auto posLeft = std::find (order->second.begin (), order->second.end (), left._string);
auto posRight = std::find (order->second.begin (), order->second.end (), right._string);
return posLeft < posRight;
}
else
{
if (left.trivial () || right.trivial ())
return false;
return left._string < right._string;
}
}
case type_date:
@@ -459,20 +466,25 @@ bool Variant::operator<= (const Variant& other) const
return left._string <= right._string;
case type_string:
if (left.source () == "priority" || right.source () == "priority")
{
if (left._string == right._string ) return true;
else if ( right._string == "H") return true;
else if (left._string == "L" && right._string == "M") return true;
else if (left._string == "" ) return true;
else return false;
}
else
{
if (left.trivial () || right.trivial ())
return false;
if (left._string == right._string)
return true;
return left._string <= right._string;
auto order = Task::customOrder.find (left.source ());
if (order != Task::customOrder.end ())
{
// Guaranteed to be found, because of ColUDA::validate ().
auto posLeft = std::find (order->second.begin (), order->second.end (), left._string);
auto posRight = std::find (order->second.begin (), order->second.end (), right._string);
return posLeft <= posRight;
}
else
{
if (left.trivial () || right.trivial ())
return false;
return left._string <= right._string;
}
}
case type_date:
@@ -605,20 +617,27 @@ bool Variant::operator> (const Variant& other) const
return left._string > right._string;
case type_string:
if (left.source () == "priority" || right.source () == "priority")
{
if (left._string == "H" && right._string != "H") return true;
else if (left._string == "M" && right._string == "L") return true;
else if (left._string != "" && right._string == "") return true;
else return false;
}
else
{
if (left.trivial () || right.trivial ())
if (left._string == right._string)
return false;
return left._string> right._string;
auto order = Task::customOrder.find (left.source ());
if (order != Task::customOrder.end ())
{
// Guaranteed to be found, because of ColUDA::validate ().
auto posLeft = std::find (order->second.begin (), order->second.end (), left._string);
auto posRight = std::find (order->second.begin (), order->second.end (), right._string);
return posLeft > posRight;
}
else
{
if (left.trivial () || right.trivial ())
return false;
return left._string > right._string;
}
}
case type_date:
if (left.trivial () || right.trivial ())
return false;
@@ -749,20 +768,25 @@ bool Variant::operator>= (const Variant& other) const
return left._string >= right._string;
case type_string:
if (left.source () == "priority" || right.source () == "priority")
{
if (left._string == right._string ) return true;
else if (left._string == "H" ) return true;
else if (left._string == "M" && right._string == "L") return true;
else if ( right._string == "" ) return true;
else return false;
}
else
{
if (left.trivial () || right.trivial ())
return false;
if (left._string == right._string)
return true;
return left._string >= right._string;
auto order = Task::customOrder.find (left.source ());
if (order != Task::customOrder.end ())
{
// Guaranteed to be found, because of ColUDA::validate ().
auto posLeft = std::find (order->second.begin (), order->second.end (), left._string);
auto posRight = std::find (order->second.begin (), order->second.end (), right._string);
return posLeft >= posRight;
}
else
{
if (left.trivial () || right.trivial ())
return false;
return left._string >= right._string;
}
}
case type_date:
@@ -1964,6 +1988,8 @@ Variant::operator std::string () const
case type_unknown:
throw std::string (STRING_VARIANT_RENDER_UNK);
}
return "";
}
////////////////////////////////////////////////////////////////////////////////
@@ -2172,7 +2198,7 @@ double Variant::get_real () const
}
////////////////////////////////////////////////////////////////////////////////
std::string Variant::get_string () const
const std::string& Variant::get_string () const
{
return _string;
}

View File

@@ -27,6 +27,7 @@
#ifndef INCLUDED_VARIANT
#define INCLUDED_VARIANT
#include <map>
#include <string>
#include <time.h>
#include <Task.h>
@@ -49,11 +50,11 @@ public:
Variant (const double);
Variant (const std::string&);
Variant (const char*);
Variant (const time_t, const enum type new_type = type_date);
Variant (const time_t, const enum type);
~Variant ();
void source (const std::string&);
std::string source () const;
const std::string& source () const;
Variant& operator= (const Variant&);
@@ -99,12 +100,12 @@ public:
int type ();
bool trivial () const;
bool get_bool () const;
int get_integer () const;
double get_real () const;
std::string get_string () const;
time_t get_date () const;
time_t get_duration () const;
bool get_bool () const;
int get_integer () const;
double get_real () const;
const std::string& get_string () const;
time_t get_date () const;
time_t get_duration () const;
private:
enum type _type;

View File

@@ -114,6 +114,7 @@ std::string ViewTask::render (std::vector <Task>& data, std::vector <int>& seque
{
context.timer_render.start ();
bool const obfuscate = context.config.getBoolean ("obfuscate");
bool const print_empty_columns = context.config.getBoolean ("print.empty.columns");
std::vector <Column*> nonempty_columns;
std::vector <bool> nonempty_sort;
@@ -143,6 +144,11 @@ std::string ViewTask::render (std::vector <Task>& data, std::vector <int>& seque
if (min > global_min) global_min = min;
if (ideal > global_ideal) global_ideal = ideal;
// If a fixed-width column was just measured, there is no point repeating
// the measurement for all tasks.
if (_columns[i]->is_fixed_width ())
break;
}
if (print_empty_columns || global_min != 0)
@@ -237,7 +243,7 @@ std::string ViewTask::render (std::vector <Task>& data, std::vector <int>& seque
// Compose column headers.
unsigned int max_lines = 0;
std::vector <std::vector <std::string> > headers;
std::vector <std::vector <std::string>> headers;
for (unsigned int c = 0; c < _columns.size (); ++c)
{
headers.push_back (std::vector <std::string> ());
@@ -290,7 +296,7 @@ std::string ViewTask::render (std::vector <Task>& data, std::vector <int>& seque
// Compose, render columns, in sequence.
_rows = 0;
std::vector <std::vector <std::string> > cells;
std::vector <std::vector <std::string>> cells;
std::vector <int>::iterator s;
for (unsigned int s = 0; s < sequence.size (); ++s)
{
@@ -316,6 +322,11 @@ std::string ViewTask::render (std::vector <Task>& data, std::vector <int>& seque
if (cells[c].size () > max_lines)
max_lines = cells[c].size ();
if (obfuscate)
if (_columns[c]->type () == "string")
for (unsigned int line = 0; line < cells[c].size (); ++line)
cells[c][line] = obfuscateText (cells[c][line]);
}
// Listing breaks are simply blank lines inserted when a column value

View File

@@ -114,6 +114,8 @@ void ViewText::set (int row, int col, Color color)
////////////////////////////////////////////////////////////////////////////////
std::string ViewText::render ()
{
bool const obfuscate = context.config.getBoolean ("obfuscate");
// Determine minimal, ideal column widths.
std::vector <int> minimal;
std::vector <int> ideal;
@@ -132,6 +134,11 @@ std::string ViewText::render ()
if (min > global_min) global_min = min;
if (ideal > global_ideal) global_ideal = ideal;
// If a fixed-width column was just measured, there is no point repeating
// the measurement for all tasks.
if (_columns[col]->is_fixed_width ())
break;
}
minimal.push_back (global_min);
@@ -181,7 +188,7 @@ std::string ViewText::render ()
// Compose column headers.
unsigned int max_lines = 0;
std::vector <std::vector <std::string> > headers;
std::vector <std::vector <std::string>> headers;
for (unsigned int c = 0; c < _columns.size (); ++c)
{
headers.push_back (std::vector <std::string> ());
@@ -233,7 +240,7 @@ std::string ViewText::render ()
// Compose, render columns, in sequence.
_rows = 0;
std::vector <std::vector <std::string> > cells;
std::vector <std::vector <std::string>> cells;
for (unsigned int row = 0; row < _data.size (); ++row)
{
max_lines = 0;
@@ -260,6 +267,11 @@ std::string ViewText::render ()
if (cells[col].size () > max_lines)
max_lines = cells[col].size ();
if (obfuscate)
if (_columns[col]->type () == "string")
for (unsigned int line = 0; line < cells[col].size (); ++line)
cells[col][line] = obfuscateText (cells[col][line]);
}
for (unsigned int i = 0; i < max_lines; ++i)

View File

@@ -68,24 +68,24 @@ public:
std::string render ();
private:
std::vector <std::vector <std::string> > _data;
std::vector <std::vector <Color> > _color;
std::vector <Column*> _columns;
int _width;
int _left_margin;
Color _header;
Color _odd;
Color _even;
int _intra_padding;
Color _intra_odd;
Color _intra_even;
int _extra_padding;
Color _extra_odd;
Color _extra_even;
int _truncate_lines;
int _truncate_rows;
int _lines;
int _rows;
std::vector <std::vector <std::string>> _data;
std::vector <std::vector <Color>> _color;
std::vector <Column*> _columns;
int _width;
int _left_margin;
Color _header;
Color _odd;
Color _even;
int _intra_padding;
Color _intra_odd;
Color _intra_even;
int _extra_padding;
Color _extra_odd;
Color _extra_even;
int _truncate_lines;
int _truncate_rows;
int _lines;
int _rows;
};
#endif

View File

@@ -135,7 +135,6 @@ int main (int argc, const char** argv)
cli.entity ("attribute", "mask");
cli.entity ("attribute", "modified");
cli.entity ("attribute", "parent");
cli.entity ("attribute", "priority");
cli.entity ("attribute", "project");
cli.entity ("attribute", "recur");
cli.entity ("attribute", "scheduled");

View File

@@ -17,7 +17,6 @@ set (columns_SRCS Column.cpp Column.h
ColMask.cpp ColMask.h
ColModified.cpp ColModified.h
ColParent.cpp ColParent.h
ColPriority.cpp ColPriority.h
ColProject.cpp ColProject.h
ColRecur.cpp ColRecur.h
ColScheduled.cpp ColScheduled.h

View File

@@ -83,8 +83,15 @@ void ColumnDepends::measure (Task& task, unsigned int& minimum, unsigned int& ma
std::vector <Task> blocking;
dependencyGetBlocking (task, blocking);
if (_style == "indicator") minimum = maximum = utf8_width (context.config.get ("dependency.indicator"));
else if (_style == "count") minimum = maximum = 2 + format ((int) blocking.size ()).length ();
if (_style == "indicator")
{
minimum = maximum = utf8_width (context.config.get ("dependency.indicator"));
_fixed_width = true;
}
else if (_style == "count")
{
minimum = maximum = 2 + format ((int) blocking.size ()).length ();
}
else if (_style == "default" ||
_style == "list")
{

View File

@@ -1,141 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////
#include <cmake.h>
#include <Context.h>
#include <ColPriority.h>
#include <text.h>
#include <i18n.h>
extern Context context;
////////////////////////////////////////////////////////////////////////////////
ColumnPriority::ColumnPriority ()
{
_name = "priority";
_type = "string";
_style = "short";
_label = STRING_COLUMN_LABEL_PRI;
_styles.push_back ("short");
_styles.push_back ("long");
_examples.push_back ("H");
_examples.push_back ("High");
}
////////////////////////////////////////////////////////////////////////////////
ColumnPriority::~ColumnPriority ()
{
}
////////////////////////////////////////////////////////////////////////////////
// Allow lower case, but implicitly convert.
bool ColumnPriority::validate (std::string& value)
{
if (value == "h") { value = "H"; return true; }
else if (value == "m") { value = "M"; return true; }
else if (value == "l") { value = "L"; return true; }
return value == "H" || value == "M" || value == "L" || value == "";
}
////////////////////////////////////////////////////////////////////////////////
// Overriden so that style <----> label are linked.
// Note that you can not determine which gets called first.
void ColumnPriority::setStyle (const std::string& value)
{
_style = value;
if (_style == "long" && _label == STRING_COLUMN_LABEL_PRI)
_label = STRING_COLUMN_LABEL_PRIORITY;
}
////////////////////////////////////////////////////////////////////////////////
// Set the minimum and maximum widths for the value.
void ColumnPriority::measure (Task& task, unsigned int& minimum, unsigned int& maximum)
{
minimum = maximum = 0;
if (task.has (_name))
{
std::string priority = task.get (_name);
if (priority == "")
minimum = maximum = 0;
else
minimum = maximum = 1;
if (_style == "long")
{
if (priority == "H") minimum = maximum = 4;
else if (priority == "M") minimum = maximum = 6;
else if (priority == "L") minimum = maximum = 3;
}
else if (_style != "default" &&
_style != "short")
throw format (STRING_COLUMN_BAD_FORMAT, "priority", _style);
}
}
////////////////////////////////////////////////////////////////////////////////
void ColumnPriority::render (
std::vector <std::string>& lines,
Task& task,
int width,
Color& color)
{
if (task.has (_name))
{
std::string priority = task.get (_name);
if (_style == "long")
{
if (priority == "H") priority = "High";
else if (priority == "M") priority = "Medium";
else if (priority == "L") priority = "Low";
}
lines.push_back (color.colorize (leftJustify (priority, width)));
}
}
////////////////////////////////////////////////////////////////////////////////
std::string ColumnPriority::modify (std::string& value)
{
if (value == "h") value = "H";
else if (value == "m") value = "M";
else if (value == "l") value = "L";
return value;
}
////////////////////////////////////////////////////////////////////////////////
bool ColumnPriority::can_modify ()
{
return true;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -1,53 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_COLPRIORITY
#define INCLUDED_COLPRIORITY
#include <vector>
#include <string>
#include <Column.h>
#include <Color.h>
#include <Task.h>
class ColumnPriority : public Column
{
public:
ColumnPriority ();
~ColumnPriority ();
bool validate (std::string&);
void setStyle (const std::string&);
void measure (Task&, unsigned int&, unsigned int&);
void render (std::vector <std::string>&, Task&, int, Color&);
std::string modify (std::string&);
bool can_modify ();
private:
};
#endif
////////////////////////////////////////////////////////////////////////////////

View File

@@ -90,8 +90,8 @@ void ColumnRecur::measure (Task& task, unsigned int& minimum, unsigned int& maxi
}
else if (_style == "indicator")
{
if (task.has (_name))
minimum = maximum = utf8_width (context.config.get ("recurrence.indicator"));
minimum = maximum = utf8_width (context.config.get ("recurrence.indicator"));
_fixed_width = true;
}
else
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);

View File

@@ -76,8 +76,8 @@ void ColumnStart::measure (Task& task, unsigned int& minimum, unsigned int& maxi
{
if (_style == "active")
{
if (! task.has ("end"))
minimum = maximum = utf8_width (context.config.get ("active.indicator"));
minimum = maximum = utf8_width (context.config.get ("active.indicator"));
_fixed_width = true;
}
else
ColumnDate::measure (task, minimum, maximum);

View File

@@ -88,8 +88,15 @@ void ColumnTags::measure (Task& task, unsigned int& minimum, unsigned int& maxim
if (task.has (_name))
{
if (_style == "indicator") minimum = maximum = utf8_width (context.config.get ("tag.indicator"));
else if (_style == "count") minimum = maximum = 3;
if (_style == "indicator")
{
minimum = maximum = utf8_width (context.config.get ("tag.indicator"));
_fixed_width = true;
}
else if (_style == "count")
{
minimum = maximum = 3;
}
else if (_style == "default" ||
_style == "list")
{

View File

@@ -120,8 +120,8 @@ void ColumnUDA::measure (Task& task, unsigned int& minimum, unsigned int& maximu
}
else if (_style == "indicator")
{
if (task.has (_name))
minimum = maximum = utf8_width (context.config.get ("uda." + _name + ".indicator"));
minimum = maximum = utf8_width (context.config.get ("uda." + _name + ".indicator"));
_fixed_width = true;
}
else
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);

View File

@@ -37,7 +37,6 @@
#include <ColMask.h>
#include <ColModified.h>
#include <ColParent.h>
#include <ColPriority.h>
#include <ColProject.h>
#include <ColRecur.h>
#include <ColScheduled.h>
@@ -88,7 +87,6 @@ Column* Column::factory (const std::string& name, const std::string& report)
else if (column_name == "mask") c = new ColumnMask ();
else if (column_name == "modified") c = new ColumnModified ();
else if (column_name == "parent") c = new ColumnParent ();
else if (column_name == "priority") c = new ColumnPriority ();
else if (column_name == "project") c = new ColumnProject ();
else if (column_name == "recur") c = new ColumnRecur ();
else if (column_name == "scheduled") c = new ColumnScheduled ();
@@ -131,7 +129,6 @@ void Column::factory (std::map <std::string, Column*>& all)
c = new ColumnMask (); all[c->_name] = c;
c = new ColumnModified (); all[c->_name] = c;
c = new ColumnParent (); all[c->_name] = c;
c = new ColumnPriority (); all[c->_name] = c;
c = new ColumnProject (); all[c->_name] = c;
c = new ColumnRecur (); all[c->_name] = c;
c = new ColumnScheduled (); all[c->_name] = c;
@@ -211,19 +208,21 @@ Column::Column ()
, _report ("")
, _modifiable (true)
, _uda (false)
, _fixed_width (false)
{
}
////////////////////////////////////////////////////////////////////////////////
Column::Column (const Column& other)
{
_name = other._name;
_type = other._type;
_style = other._style;
_label = other._label;
_label = other._report;
_modifiable = other._modifiable;
_uda = other._uda;
_name = other._name;
_type = other._type;
_style = other._style;
_label = other._label;
_label = other._report;
_modifiable = other._modifiable;
_uda = other._uda;
_fixed_width = other._fixed_width;
}
////////////////////////////////////////////////////////////////////////////////
@@ -238,6 +237,7 @@ Column& Column::operator= (const Column& other)
_report = other._report;
_modifiable = other._modifiable;
_uda = other._uda;
_fixed_width = other._fixed_width;
}
return *this;

View File

@@ -46,12 +46,13 @@ public:
bool operator== (const Column&) const; // TODO Is this necessary?
virtual ~Column ();
std::string name () const { return _name; }
std::string style () const { return _style; }
std::string label () const { return _label; }
std::string type () const { return _type; }
const std::string& name () const { return _name; }
const std::string& style () const { return _style; }
const std::string& label () const { return _label; }
const std::string& type () const { return _type; }
bool modifiable () const { return _modifiable; }
bool is_uda () const { return _uda; }
bool is_fixed_width () const { return _fixed_width;}
std::vector <std::string> styles () const { return _styles; }
std::vector <std::string> examples () const { return _examples; }
@@ -76,6 +77,7 @@ protected:
std::string _report;
bool _modifiable;
bool _uda;
bool _fixed_width;
std::vector <std::string> _styles;
std::vector <std::string> _examples;
};

View File

@@ -120,11 +120,11 @@ int CmdCalendar::execute (std::string& output)
argWholeYear = true;
// YYYY.
else if (digitsOnly (*arg) && arg->length () == 4)
else if (Lexer::isAllDigits (*arg) && arg->length () == 4)
argYear = strtol (arg->c_str (), NULL, 10);
// MM.
else if (digitsOnly (*arg) && arg->length () <= 2)
else if (Lexer::isAllDigits (*arg) && arg->length () <= 2)
{
argMonth = strtol (arg->c_str (), NULL, 10);
if (argMonth < 1 || argMonth > 12)
@@ -366,7 +366,7 @@ int CmdCalendar::execute (std::string& output)
holTable.colorHeader (color_label);
Config::const_iterator it;
std::map <time_t, std::vector<std::string> > hm; // we need to store multiple holidays per day
std::map <time_t, std::vector<std::string>> hm; // we need to store multiple holidays per day
for (it = context.config.begin (); it != context.config.end (); ++it)
if (it->first.substr (0, 8) == "holiday.")
if (it->first.substr (it->first.size () - 4) == "name")
@@ -389,7 +389,7 @@ int CmdCalendar::execute (std::string& output)
if (format == "")
format = context.config.get ("dateformat");
std::map <time_t, std::vector<std::string> >::iterator hm_it;
std::map <time_t, std::vector<std::string>>::iterator hm_it;
for (hm_it = hm.begin(); hm_it != hm.end(); ++hm_it)
{
std::vector <std::string> v = hm_it->second;

View File

@@ -163,7 +163,6 @@ int CmdConfig::execute (std::string& output)
if (words.size ())
{
bool confirmation = context.config.getBoolean ("confirmation");
bool change = false;
bool found = false;
std::string name = words[0];

View File

@@ -82,7 +82,7 @@ int CmdCustom::execute (std::string& output)
validateSortColumns (sortOrder);
// Prepend the argument list with those from the report filter.
context.cli.addRawFilter(reportFilter);
context.cli.addRawFilter (reportFilter);
// Apply filter.
handleRecurrence ();

View File

@@ -160,20 +160,7 @@ int CmdDiagnostics::execute (std::string& output)
#ifdef HAVE_COMMIT
<< " " << STRING_CMD_DIAG_COMMIT << ": " << COMMIT << "\n"
#endif
<< " CMake: " << CMAKE_VERSION << "\n"
<< " " << STRING_CMD_DIAG_CAPS << ":"
#ifdef HAVE_LIBPTHREAD
<< " +pthreads"
#else
<< " -pthreads"
#endif
#ifdef HAVE_LIBGNUTLS
<< " +tls"
#else
<< " -tls"
#endif
<< "\n";
<< " CMake: " << CMAKE_VERSION << "\n";
out << " libuuid: "
#ifdef HAVE_UUID_UNPARSE_LOWER

View File

@@ -206,8 +206,7 @@ std::string CmdEdit::formatTask (Task task, const std::string& dateformat)
<< "# Status: " << ucFirst (Task::statusToText (task.getStatus ())) << "\n" // L10N safe ucFirst.
<< "# Mask: " << task.get ("mask") << "\n"
<< "# iMask: " << task.get ("imask") << "\n"
<< " Project: " << task.get ("project") << "\n"
<< " Priority: " << task.get ("priority") << "\n";
<< " Project: " << task.get ("project") << "\n";
std::vector <std::string> tags;
task.getTags (tags);
@@ -343,25 +342,6 @@ void CmdEdit::parseTask (Task& task, const std::string& after, const std::string
}
}
// priority
value = findValue (after, "\n Priority:");
if (task.get ("priority") != value)
{
if (value != "")
{
if (context.columns["priority"]->validate (value))
{
context.footnote (STRING_EDIT_PRIORITY_MOD);
task.set ("priority", value);
}
}
else
{
context.footnote (STRING_EDIT_PRIORITY_DEL);
task.remove ("priority");
}
}
// tags
value = findValue (after, "\n Tags:");
std::vector <std::string> tags;

View File

@@ -39,8 +39,6 @@
extern Context context;
static const float epsilon = 0.000001;
////////////////////////////////////////////////////////////////////////////////
CmdInfo::CmdInfo ()
{
@@ -152,14 +150,6 @@ int CmdInfo::execute (std::string& output)
view.set (row, 1, task->get ("project"));
}
// priority
if (task->has ("priority"))
{
row = view.addRow ();
view.set (row, 0, STRING_COLUMN_LABEL_PRIORITY);
view.set (row, 1, task->get ("priority"));
}
// dependencies: blocked
{
std::vector <Task> blocked;
@@ -401,83 +391,107 @@ int CmdInfo::execute (std::string& output)
}
}
// Create a second table, containing urgency details.
// Create a second table, containing urgency details, if necessary.
ViewText urgencyDetails;
if (context.color ())
if (task->urgency () != 0.0)
{
Color alternate (context.config.get ("color.alternate"));
urgencyDetails.colorOdd (alternate);
urgencyDetails.intraColorOdd (alternate);
Color label (context.config.get ("color.label"));
urgencyDetails.colorHeader (label);
}
urgencyDetails.width (context.getWidth ());
urgencyDetails.add (Column::factory ("string", "")); // Attribute
urgencyDetails.add (Column::factory ("string", "")); // Value
urgencyDetails.add (Column::factory ("string", "")); // *
urgencyDetails.add (Column::factory ("string", "")); // Coefficient
urgencyDetails.add (Column::factory ("string", "")); // =
urgencyDetails.add (Column::factory ("string", "")); // Result
urgencyTerm (urgencyDetails, "project", task->urgency_project (), Task::urgencyProjectCoefficient);
urgencyTerm (urgencyDetails, "priority", task->urgency_priority (), Task::urgencyPriorityCoefficient);
urgencyTerm (urgencyDetails, "active", task->urgency_active (), Task::urgencyActiveCoefficient);
urgencyTerm (urgencyDetails, "scheduled", task->urgency_scheduled (), Task::urgencyScheduledCoefficient);
urgencyTerm (urgencyDetails, "waiting", task->urgency_waiting (), Task::urgencyWaitingCoefficient);
urgencyTerm (urgencyDetails, "blocked", task->urgency_blocked (), Task::urgencyBlockedCoefficient);
urgencyTerm (urgencyDetails, "blocking", task->urgency_blocking (), Task::urgencyBlockingCoefficient);
urgencyTerm (urgencyDetails, "annotations", task->urgency_annotations (), Task::urgencyAnnotationsCoefficient);
urgencyTerm (urgencyDetails, "tags", task->urgency_tags (), Task::urgencyTagsCoefficient);
urgencyTerm (urgencyDetails, "next", task->urgency_next (), Task::urgencyNextCoefficient);
urgencyTerm (urgencyDetails, "due", task->urgency_due (), Task::urgencyDueCoefficient);
urgencyTerm (urgencyDetails, "age", task->urgency_age (), Task::urgencyAgeCoefficient);
// Tag, Project- and UDA-specific coefficients.
std::map <std::string, float>::iterator var;
for (var = Task::coefficients.begin (); var != Task::coefficients.end (); ++var)
{
if (var->first.substr (0, 13) == "urgency.user.")
if (context.color ())
{
// urgency.user.project.<project>.coefficient
std::string::size_type end = std::string::npos;
if (var->first.substr (13, 8) == "project." &&
(end = var->first.find (".coefficient")) != std::string::npos)
Color alternate (context.config.get ("color.alternate"));
urgencyDetails.colorOdd (alternate);
urgencyDetails.intraColorOdd (alternate);
Color label (context.config.get ("color.label"));
urgencyDetails.colorHeader (label);
}
urgencyDetails.width (context.getWidth ());
urgencyDetails.add (Column::factory ("string", "")); // Attribute
urgencyDetails.add (Column::factory ("string", "")); // Value
urgencyDetails.add (Column::factory ("string", "")); // *
urgencyDetails.add (Column::factory ("string", "")); // Coefficient
urgencyDetails.add (Column::factory ("string", "")); // =
urgencyDetails.add (Column::factory ("string", "")); // Result
urgencyTerm (urgencyDetails, "project", task->urgency_project (), Task::urgencyProjectCoefficient);
urgencyTerm (urgencyDetails, "active", task->urgency_active (), Task::urgencyActiveCoefficient);
urgencyTerm (urgencyDetails, "scheduled", task->urgency_scheduled (), Task::urgencyScheduledCoefficient);
urgencyTerm (urgencyDetails, "waiting", task->urgency_waiting (), Task::urgencyWaitingCoefficient);
urgencyTerm (urgencyDetails, "blocked", task->urgency_blocked (), Task::urgencyBlockedCoefficient);
urgencyTerm (urgencyDetails, "blocking", task->urgency_blocking (), Task::urgencyBlockingCoefficient);
urgencyTerm (urgencyDetails, "annotations", task->urgency_annotations (), Task::urgencyAnnotationsCoefficient);
urgencyTerm (urgencyDetails, "tags", task->urgency_tags (), Task::urgencyTagsCoefficient);
urgencyTerm (urgencyDetails, "next", task->urgency_next (), Task::urgencyNextCoefficient);
urgencyTerm (urgencyDetails, "due", task->urgency_due (), Task::urgencyDueCoefficient);
urgencyTerm (urgencyDetails, "age", task->urgency_age (), Task::urgencyAgeCoefficient);
// Tag, Project- and UDA-specific coefficients.
std::map <std::string, float>::iterator var;
for (var = Task::coefficients.begin (); var != Task::coefficients.end (); ++var)
{
if (var->first.substr (0, 13) == "urgency.user.")
{
std::string project = var->first.substr (21, end - 21);
if (task->get ("project").find (project) == 0)
urgencyTerm (urgencyDetails, "PROJECT " + project, 1.0, var->second);
// urgency.user.project.<project>.coefficient
std::string::size_type end = std::string::npos;
if (var->first.substr (13, 8) == "project." &&
(end = var->first.find (".coefficient")) != std::string::npos)
{
std::string project = var->first.substr (21, end - 21);
if (task->get ("project").find (project) == 0)
urgencyTerm (urgencyDetails, "PROJECT " + project, 1.0, var->second);
}
// urgency.user.tag.<tag>.coefficient
if (var->first.substr (13, 4) == "tag." &&
(end = var->first.find (".coefficient")) != std::string::npos)
{
std::string name = var->first.substr (17, end - 17);
if (task->hasTag (name))
urgencyTerm (urgencyDetails, "TAG " + name, 1.0, var->second);
}
// urgency.user.keyword.<keyword>.coefficient
if (var->first.substr (13, 8) == "keyword." &&
(end = var->first.find (".coefficient")) != std::string::npos)
{
std::string keyword = var->first.substr (21, end - 21);
if (task->get ("description").find (keyword) != std::string::npos)
urgencyTerm (urgencyDetails, "KEYWORD " + keyword, 1.0, var->second);
}
}
// urgency.user.tag.<tag>.coefficient
if (var->first.substr (13, 4) == "tag." &&
(end = var->first.find (".coefficient")) != std::string::npos)
// urgency.uda.<name>.coefficient
else if (var->first.substr (0, 12) == "urgency.uda.")
{
std::string name = var->first.substr (17, end - 17);
if (task->hasTag (name))
urgencyTerm (urgencyDetails, "TAG " + name, 1.0, var->second);
// urgency.uda.<name>.coefficient
// urgency.uda.<name>.<value>.coefficient
std::string::size_type end = var->first.find (".coefficient");
if (end != std::string::npos)
{
const std::string uda = var->first.substr (12, end - 12);
std::string::size_type dot = uda.find (".");
if (dot == std::string::npos)
{
// urgency.uda.<name>.coefficient
if (task->has (uda))
urgencyTerm (urgencyDetails, std::string ("UDA ") + uda, 1.0, var->second);
}
else
{
// urgency.uda.<name>.<value>.coefficient
if (task->get (uda.substr(0, dot)) == uda.substr(dot+1))
urgencyTerm (urgencyDetails, std::string ("UDA ") + uda, 1.0, var->second);
}
}
}
}
// urgency.uda.<name>.coefficient
else if (var->first.substr (0, 12) == "urgency.uda.")
{
std::string::size_type end = var->first.find (".coefficient");
if (end != std::string::npos)
{
std::string name = var->first.substr (12, end - 12);
if (task->has (name))
urgencyTerm (urgencyDetails, "UDA " + name, 1.0, var->second);
}
}
row = urgencyDetails.addRow ();
urgencyDetails.set (row, 5, rightJustify ("------", 6));
row = urgencyDetails.addRow ();
urgencyDetails.set (row, 5, rightJustify (format (task->urgency (), 4, 4), 6));
}
row = urgencyDetails.addRow ();
urgencyDetails.set (row, 5, rightJustify ("------", 6));
row = urgencyDetails.addRow ();
urgencyDetails.set (row, 5, rightJustify (format (task->urgency (), 4, 4), 6));
// Create a third table, containing undo log change details.
ViewText journal;
@@ -562,7 +576,7 @@ void CmdInfo::urgencyTerm (
int row = view.addRow ();
view.set (row, 0, " " + label);
view.set (row, 1, rightJustify (format (measure, 5, 3), 6));
view.set (row, 2, "+");
view.set (row, 2, "*");
view.set (row, 3, rightJustify (format (coefficient, 4, 2), 4));
view.set (row, 4, "=");
view.set (row, 5, rightJustify (format (value, 5, 3), 6));

View File

@@ -82,7 +82,6 @@ int CmdProjects::execute (std::string& output)
std::map <std::string, int> unique;
bool no_project = false;
std::string project;
std::string priority;
std::vector <Task>::iterator task;
for (task = filtered.begin (); task != filtered.end (); ++task)
{

View File

@@ -109,10 +109,6 @@ int CmdShow::execute (std::string& output)
" color.label"
" color.label.sort"
" color.overdue"
" color.pri.H"
" color.pri.L"
" color.pri.M"
" color.pri.none"
" color.recurring"
" color.scheduled"
" color.summary.background"
@@ -142,7 +138,6 @@ int CmdShow::execute (std::string& output)
" debug.tls"
" default.command"
" default.due"
" default.priority"
" default.project"
" defaultheight"
" defaultwidth"
@@ -172,6 +167,7 @@ int CmdShow::execute (std::string& output)
" locking"
" monthsperline"
" nag"
" obfuscate"
" print.empty.columns"
" recurrence"
" recurrence.confirmation"
@@ -183,6 +179,7 @@ int CmdShow::execute (std::string& output)
" rule.precedence.color"
" search.case.sensitive"
" shell.prompt"
" summary.all.projects"
" tag.indicator"
" taskd.server"
" taskd.ca"
@@ -200,7 +197,6 @@ int CmdShow::execute (std::string& output)
" urgency.inherit.coefficient"
" urgency.due.coefficient"
" urgency.next.coefficient"
" urgency.priority.coefficient"
" urgency.project.coefficient"
" urgency.tags.coefficient"
" urgency.waiting.coefficient"
@@ -240,6 +236,7 @@ int CmdShow::execute (std::string& output)
i->first.substr (0, 8) != "default." &&
i->first.substr (0, 21) != "urgency.user.project." &&
i->first.substr (0, 17) != "urgency.user.tag." &&
i->first.substr (0, 21) != "urgency.user.keyword." &&
i->first.substr (0, 12) != "urgency.uda.")
{
unrecognized.push_back (i->first);
@@ -367,15 +364,6 @@ int CmdShow::execute (std::string& output)
out << format (STRING_CMD_SHOW_CONFIG_ERROR, "calendar.holidays", calendarholidays)
<< "\n";
// Check for bad values in rc.default.priority.
std::string defaultPriority = context.config.get ("default.priority");
if (defaultPriority != "H" &&
defaultPriority != "M" &&
defaultPriority != "L" &&
defaultPriority != "")
out << format (STRING_CMD_SHOW_CONFIG_ERROR, "default.priority", defaultPriority)
<< "\n";
// Verify installation. This is mentioned in the documentation as the way
// to ensure everything is properly installed.

View File

@@ -57,6 +57,7 @@ CmdSummary::CmdSummary ()
int CmdSummary::execute (std::string& output)
{
int rc = 0;
bool showAllProjects = context.config.getBoolean ("summary.all.projects");
// Apply filter.
handleRecurrence ();
@@ -68,7 +69,7 @@ int CmdSummary::execute (std::string& output)
std::map <std::string, bool> allProjects;
std::vector <Task>::iterator task;
for (task = filtered.begin (); task != filtered.end (); ++task)
if (task->getStatus () == Task::pending)
if (showAllProjects || task->getStatus () == Task::pending)
allProjects[task->get ("project")] = false;
// Initialize counts, sum.
@@ -122,7 +123,6 @@ int CmdSummary::execute (std::string& output)
}
}
// Create a table for output.
ViewText view;
view.width (context.getWidth ());
@@ -143,7 +143,7 @@ int CmdSummary::execute (std::string& output)
std::map <std::string, bool>::iterator i;
for (i = allProjects.begin (); i != allProjects.end (); ++i)
{
if (countPending[i->first] > 0)
if (showAllProjects || countPending[i->first] > 0)
{
const std::vector <std::string> parents = extractParents (i->first);
std::vector <std::string>::const_iterator parent;
@@ -169,7 +169,9 @@ int CmdSummary::execute (std::string& output)
int c = countCompleted[i->first];
int p = countPending[i->first];
int completedBar = (c * barWidth) / (c + p);
int completedBar = 0;
if (c + p)
completedBar = (c * barWidth) / (c + p);
std::string bar;
std::string subbar;
@@ -185,8 +187,9 @@ int CmdSummary::execute (std::string& output)
}
view.set (row, 4, bar);
char percent[12];
sprintf (percent, "%d%%", 100 * c / (c + p));
char percent[12] = "0%";
if (c + p)
sprintf (percent, "%d%%", 100 * c / (c + p));
view.set (row, 3, percent);
processed.push_back (i->first);
}

View File

@@ -255,10 +255,13 @@ int CmdSync::execute (std::string& output)
else if (upload_count > 0 && download_count > 0)
context.footnote (format (STRING_CMD_SYNC_SUCCESS3, upload_count, download_count));
}
status = 0;
}
else if (code == "201")
{
context.footnote (STRING_CMD_SYNC_SUCCESS_NOP);
status = 0;
}
else if (code == "301")
{
@@ -266,6 +269,7 @@ int CmdSync::execute (std::string& output)
context.config.set ("taskd.server", new_server);
context.error (STRING_CMD_SYNC_RELOCATE0);
context.error (" " + format (STRING_CMD_SYNC_RELOCATE1, new_server));
status = 2;
}
else if (code == "430")
{
@@ -335,6 +339,8 @@ bool CmdSync::send (
const Msg& request,
Msg& response)
{
// It is important that the ':' be the *last* colon, in order to support
// IPv6 addresses.
std::string::size_type colon = to.rfind (':');
if (colon == std::string::npos)
throw format (STRING_CMD_SYNC_BAD_SERVER, to);

View File

@@ -86,7 +86,6 @@
#include <Context.h>
#include <ColProject.h>
#include <ColPriority.h>
#include <ColDue.h>
extern Context context;
@@ -323,8 +322,8 @@ bool Command::permission (
}
// 1 < Quantity < bulk modifications have optional confirmation, in the (y/n/a/q)
// style.
if (quantity < bulk && (!_needs_confirm || !confirmation))
// style. Bulk = 0 denotes infinite bulk.
if ((bulk == 0 || quantity < bulk) && (!_needs_confirm || !confirmation))
return true;
if (context.verbose ("blank") && !_first_iteration)

View File

@@ -252,6 +252,7 @@ std::string taskInfoDifferences (
for (name = beforeAtts.begin (); name != beforeAtts.end (); ++name)
if (*name != "uuid" &&
*name != "modified" &&
before.get (*name) != after.get (*name) &&
before.get (*name) != "" && after.get (*name) != "")
{

View File

@@ -58,6 +58,8 @@
#include <l10n/epo-RUS.h>
#elif PACKAGE_LANGUAGE == LANGUAGE_POL_POL
#include <l10n/pol-POL.h>
#elif PACKAGE_LANGUAGE == LANGUAGE_JPN_JPN
#include <l10n/jpn-JPN.h>
#endif
#endif

View File

@@ -172,13 +172,6 @@
#define STRING_VARIANT_SQRT_NEG "Quadratwurzel einer negativen Zahl kann nicht berechnet werden."
#define STRING_VARIANT_COERCE_UNK "Kann nicht in oder von einem unbekannten Typ konvertieren"
// Lexer
//
// These are errors generated at the lowest level of input analysis,
// at the character level.
#define STRING_LEX_IMMEDIATE_UNK "Lexer konnte nicht gestartet werden, sofort unbekannte Zeichen gefunden."
#define STRING_LEX_TYPE_UNK "Lexer kann unbekanntes Symbol nicht verarbeiten."
// Dates
//
// These are errors generated when parsing date values.
@@ -204,8 +197,6 @@
#define STRING_COLUMN_LABEL_ADDED "Hinzugefügt"
#define STRING_COLUMN_LABEL_AGE "Alter"
#define STRING_COLUMN_LABEL_ID "ID"
#define STRING_COLUMN_LABEL_PRI "Pri"
#define STRING_COLUMN_LABEL_PRIORITY "Priorität"
#define STRING_COLUMN_LABEL_PROJECT "Projekt"
#define STRING_COLUMN_LABEL_UNTIL "Bis"
#define STRING_COLUMN_LABEL_WAIT "Aufgeschoben"
@@ -708,8 +699,6 @@
#define STRING_EDIT_PROJECT_MOD "Projekt geändert."
#define STRING_EDIT_PROJECT_DEL "Projekt gelöscht."
#define STRING_EDIT_PRIORITY_MOD "Wichtigkeit geändert."
#define STRING_EDIT_PRIORITY_DEL "Wichtigkeit gelöscht."
#define STRING_EDIT_DESC_MOD "Beschreibung geändert."
#define STRING_EDIT_DESC_REMOVE_ERR "Beschreibung kann nicht entfernt werden."
#define STRING_EDIT_ENTRY_REMOVE_ERR "Erstelldatum kann nicht entfernt werden."
@@ -874,7 +863,6 @@
#define STRING_TASK_VALID_BEFORE "Warnung: Das '{1}'-Datum ist nach dem '{2}'-Datum."
#define STRING_TASK_VALID_REC_DUE "Wiederholende Aufgaben müssen eine Fälligkeit besitzen."
#define STRING_TASK_VALID_RECUR "Wiederhol-Periode '{1}' ist ungültig."
#define STRING_TASK_VALID_PRIORITY "Die Wichtigkeit kann die Werte 'H', 'M' oder 'L' annehmen, nicht jedoch '{1}'."
#define STRING_TASK_SAFETY_VALVE "Dieser Befehl hat keinen Filter und wird alle Aufgaben verändern. Sind Sie sicher?"
#define STRING_TASK_SAFETY_FAIL "Befehl an Ausführung gehindert."
#define STRING_TASK_SAFETY_ALLOW "Kein Filter angegeben, und durch den konfigurierten 'allow.empty.filter'-Wert wurde keine Aktion durchgeführt."
@@ -1029,4 +1017,7 @@
#define STRING_UTIL_KIBIBYTES "KiB"
#define STRING_UTIL_BYTES "B"
// Legacy
#define STRING_LEGACY_PRIORITY "Legacy attribute found. Please change '{1}' to '{2}'."
#endif

View File

@@ -172,13 +172,6 @@
#define STRING_VARIANT_SQRT_NEG "Cannot take the square root of a negative number."
#define STRING_VARIANT_COERCE_UNK "Cannot coerce data either to or from an unknown type"
// Lexer
//
// These are errors generated at the lowest level of input analysis,
// at the character level.
#define STRING_LEX_IMMEDIATE_UNK "Lexer start failure, unknown characters found immediately."
#define STRING_LEX_TYPE_UNK "Lexer cannot process an unknown token type."
// Dates
//
// These are errors generated when parsing date values.
@@ -204,8 +197,6 @@
#define STRING_COLUMN_LABEL_ADDED "Added"
#define STRING_COLUMN_LABEL_AGE "Age"
#define STRING_COLUMN_LABEL_ID "ID"
#define STRING_COLUMN_LABEL_PRI "Pri"
#define STRING_COLUMN_LABEL_PRIORITY "Priority"
#define STRING_COLUMN_LABEL_PROJECT "Project"
#define STRING_COLUMN_LABEL_UNTIL "Until"
#define STRING_COLUMN_LABEL_WAIT "Wait"
@@ -263,10 +254,10 @@
// commands/Cmd*
// USAGE strings are visible in 'task help'
#define STRING_CMD_CONFLICT "Custom report '{1}' conflicts with built-in task command."
#define STRING_CMD_VERSION_USAGE "Shows the taskwarrior version number"
#define STRING_CMD_VERSION_USAGE2 "Shows only the taskwarrior version number"
#define STRING_CMD_VERSION_MIT "Taskwarrior may be copied only under the terms of the MIT license, which may be found in the taskwarrior source kit."
#define STRING_CMD_VERSION_DOCS "Documentation for taskwarrior can be found using 'man task', 'man taskrc', 'man task-color', 'man task-sync' or at http://taskwarrior.org"
#define STRING_CMD_VERSION_USAGE "Shows the Taskwarrior version number"
#define STRING_CMD_VERSION_USAGE2 "Shows only the Taskwarrior version number"
#define STRING_CMD_VERSION_MIT "Taskwarrior may be copied only under the terms of the MIT license, which may be found in the Taskwarrior source kit."
#define STRING_CMD_VERSION_DOCS "Documentation for Taskwarrior can be found using 'man task', 'man taskrc', 'man task-color', 'man task-sync' or at http://taskwarrior.org"
#define STRING_CMD_VERSION_BUILT "{1} {2} built for "
#define STRING_CMD_VERSION_UNKNOWN "unknown"
#define STRING_CMD_VERSION_COPY "Copyright (C) 2006 - 2015 P. Beckingham, F. Hernandez."
@@ -341,7 +332,7 @@
#define STRING_CMD_HISTORY_USAGE_A "Shows a report of task history, by year"
#define STRING_CMD_HISTORY_AVERAGE "Average"
#define STRING_CMD_HISTORY_LEGEND "Legend: {1}, {2}, {3}"
#define STRING_CMD_HISTORY_LEGEND_A "Legend: + added, X completed, - deleted"
#define STRING_CMD_HISTORY_LEGEND_A "Legend: + Added, X Completed, - Deleted"
#define STRING_CMD_GHISTORY_USAGE_M "Shows a graphical report of task history, by month"
#define STRING_CMD_GHISTORY_USAGE_A "Shows a graphical report of task history, by year"
#define STRING_CMD_GHISTORY_YEAR "Year"
@@ -566,7 +557,7 @@
#define STRING_CMD_CONTEXT_DEF_SUCC "Context '{1}' defined."
#define STRING_CMD_CONTEXT_DEF_FAIL "Context '{1}' not defined."
#define STRING_CMD_CONTEXT_DEF_USAG "Both context name and its definition must be provided."
#define STRING_CMD_CONTEXT_DEF_ABRT "Context definiton aborted."
#define STRING_CMD_CONTEXT_DEF_ABRT "Context definition aborted."
#define STRING_CMD_CONTEXT_DEF_ABRT2 "Filter validation failed: {1}"
#define STRING_CMD_CONTEXT_DEF_CONF "The filter '{1}' matches 0 pending tasks. Do you wish to continue?"
#define STRING_CMD_CONTEXT_DEL_SUCC "Context '{1}' deleted."
@@ -624,7 +615,7 @@
#define STRING_CONFIG_DEPRECATED_VAR "Your .taskrc file contains variables that are deprecated:"
// Context
#define STRING_CONTEXT_CREATE_RC "A configuration file could not be found in {1}\n\nWould you like a sample {2} created, so taskwarrior can proceed?"
#define STRING_CONTEXT_CREATE_RC "A configuration file could not be found in {1}\n\nWould you like a sample {2} created, so Taskwarrior can proceed?"
#define STRING_CONTEXT_NEED_RC "Cannot proceed without rc file."
#define STRING_CONTEXT_RC_OVERRIDE "TASKRC override: {1}"
#define STRING_CONTEXT_DATA_OVERRIDE "TASKDATA override: {1}"
@@ -708,8 +699,6 @@
#define STRING_EDIT_PROJECT_MOD "Project modified."
#define STRING_EDIT_PROJECT_DEL "Project deleted."
#define STRING_EDIT_PRIORITY_MOD "Priority modified."
#define STRING_EDIT_PRIORITY_DEL "Priority deleted."
#define STRING_EDIT_DESC_MOD "Description modified."
#define STRING_EDIT_DESC_REMOVE_ERR "Cannot remove description."
#define STRING_EDIT_ENTRY_REMOVE_ERR "Cannot remove creation date."
@@ -741,12 +730,12 @@
#define STRING_EDIT_HEADER_1 "The 'task <id> edit' command allows you to modify all aspects of a task"
#define STRING_EDIT_HEADER_2 "using a text editor. Below is a representation of all the task details."
#define STRING_EDIT_HEADER_3 "Modify what you wish, and when you save and quit your editor,"
#define STRING_EDIT_HEADER_4 "taskwarrior will read this file, determine what changed, and apply"
#define STRING_EDIT_HEADER_4 "Taskwarrior will read this file, determine what changed, and apply"
#define STRING_EDIT_HEADER_5 "those changes. If you exit your editor without saving or making"
#define STRING_EDIT_HEADER_6 "modifications, taskwarrior will do nothing."
#define STRING_EDIT_HEADER_6 "modifications, Taskwarrior will do nothing."
#define STRING_EDIT_HEADER_7 "Lines that begin with # represent data you cannot change, like ID."
#define STRING_EDIT_HEADER_8 "If you get too creative with your editing, taskwarrior will send you"
#define STRING_EDIT_HEADER_8 "If you get too creative with your editing, Taskwarrior will send you"
#define STRING_EDIT_HEADER_9 "back to the editor to try again."
#define STRING_EDIT_HEADER_10 "Should you find yourself in an endless loop, re-editing the same file,"
@@ -863,7 +852,7 @@
#define STRING_TASK_NO_FF1 "Taskwarrior no longer supports file format 1, originally used between 27 November 2006 and 31 December 2007."
#define STRING_TASK_NO_FF2 "Taskwarrior no longer supports file format 2, originally used between 1 January 2008 and 12 April 2009."
#define STRING_TASK_NO_FF3 "Taskwarrior no longer supports file format 3, originally used between 23 March 2009 and 16 May 2009."
#define STRING_TASK_PARSE_UNREC_FF "Unrecognized taskwarrior file format."
#define STRING_TASK_PARSE_UNREC_FF "Unrecognized Taskwarrior file format."
#define STRING_TASK_DEPEND_ITSELF "A task cannot be dependent on itself."
#define STRING_TASK_DEPEND_MISS_CREA "Could not create a dependency on task {1} - not found."
#define STRING_TASK_DEPEND_MISS_DEL "Could not delete a dependency on task {1} - not found."
@@ -874,7 +863,6 @@
#define STRING_TASK_VALID_BEFORE "Warning: You have specified that the '{1}' date is after the '{2}' date."
#define STRING_TASK_VALID_REC_DUE "A recurring task must also have a 'due' date."
#define STRING_TASK_VALID_RECUR "The recurrence value '{1}' is not valid."
#define STRING_TASK_VALID_PRIORITY "Priority values may be 'H', 'M' or 'L', not '{1}'."
#define STRING_TASK_SAFETY_VALVE "This command has no filter, and will modify all tasks. Are you sure?"
#define STRING_TASK_SAFETY_FAIL "Command prevented from running."
#define STRING_TASK_SAFETY_ALLOW "You did not specify a filter, and with the 'allow.empty.filter' value, no action is taken."
@@ -997,7 +985,7 @@
" task add \"quoted ' quote\"\n" \
" task add escaped \\' quote\n" \
"\n" \
"The argument -- tells taskwarrior to treat all other args as description, even " \
"The argument -- tells Taskwarrior to treat all other args as description, even " \
"if they would otherwise be attributes or tags:\n" \
" task add -- project:Home needs scheduling\n" \
"\n" \
@@ -1006,7 +994,7 @@
"\n"
/*
To be included later, before the 'precendence' line.
To be included later, before the 'precedence' line.
" + - Addition, subtraction\n" \
" ! Inversion\n" \
@@ -1026,4 +1014,7 @@
#define STRING_UTIL_KIBIBYTES "KiB"
#define STRING_UTIL_BYTES "B"
// Legacy
#define STRING_LEGACY_PRIORITY "Legacy attribute found. Please change '{1}' to '{2}'."
#endif

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