Compare commits

...

128 Commits

Author SHA1 Message Date
Federico Hernandez
b9dc0813d9 Version number and release date for 2.4.2 2015-03-16 00:01:52 +01:00
Paul Beckingham
25c687e1ec Themes
- Updated default theme to match dark-16 or dark-256.
2015-03-15 12:16:40 -04:00
Paul Beckingham
6e98bbbd85 Themes
- Consistency tweaks across all themes.
2015-03-15 12:06:02 -04:00
Paul Beckingham
06c8976be5 Themes
- Changed color.error to white on red.
- Changed color.debug to blue.
- Made color.active more yellow.
- Added color.scheduled.
- Changed due, due.today and overdue to be more yellow.
- Changed color.summary.background to match theme.
- Changed color.undo to match theme.
2015-03-15 11:55:32 -04:00
Paul Beckingham
d13a5a3f47 Themes
- Changed color.error to white on red.
- Changed color.debug to blue.
- Added color.scheduled.
- Changed color.due, color.overdue to match theme.
- Added color.summary.background.
2015-03-15 11:46:00 -04:00
Paul Beckingham
b662afa1ff Themes
- Removed color.completed, color.deleted.
- Darkened color.alternate.
- Changed color.debug to blue.
- Changed color.error to white on red.
- Added fg to color.scheduled.
- Changed color.tag.next to match theme.
- Changed color.undo to match theme.
2015-03-15 11:37:57 -04:00
Paul Beckingham
bde83d3195 Themes
- Darkened color.alternate.
- Changed color.debug to blue.
- Changed color.error to white on red.
- Changed color.warning to match theme.
- Removed color.completed, color.deleted.
- Added fg to color.scheduled.
- Added color.summary.background.
- Darkened color.undo.before.
2015-03-15 11:32:51 -04:00
Paul Beckingham
0edb7e57f6 Themes
- Changed color.debug to blue.
- Change color.error to white on red.
- Added fg to burndown and history.
- Added color.summary.bckground.
- Changed undo colors to match theme.
2015-03-15 11:27:55 -04:00
Paul Beckingham
4569d2da24 Themes
- Changed color.debug to a common blue.
- Changed color.error to white on red.
- Added fg to color.calendar.due.
- Fixed typo for color.synd.added.
2015-03-15 11:21:13 -04:00
Paul Beckingham
6b00f08794 Themes
- Removed color.completed, color.deleted.
- Made color.scheduled more blue than green.
- Made summary light on dark blue.
2015-03-15 11:16:14 -04:00
Paul Beckingham
e83809c6aa Themes
- Lightened color.alternate.
- Changed color.debug to a common blue.
2015-03-15 11:12:26 -04:00
Paul Beckingham
39b736d23e Themes
- Changed color.debug to a readable color.
- Added fg to color.scheduled.
- Removed color.completed, color.deleted.
2015-03-15 11:08:34 -04:00
Paul Beckingham
3e90554f40 Themes
- Removed background color from debug.
- Removed color.completed, color.deleted.
- Darkened color.active, for contrast.
- Removed color.pri.none, which was the same as color.pri.M.
- Inverted color.calendar.holiday.
- Changed burndown and history to use red, yellow, green.

+color.history.delete=color0 on rgb550

 # Report: summary
 color.summary.bar=on rgb141
@@ -82,7 +82,7 @@ color.summary.background=on gray20
 # Command: calendar
 color.calendar.due=on rgb343
 color.calendar.due.today=on rgb353
-color.calendar.holiday=rgb420
+color.calendar.holiday=color0 on rgb530
 color.calendar.overdue=on rgb533
 color.calendar.today=rgb005
 color.calendar.weekend=on gray21
2015-03-15 11:02:27 -04:00
Paul Beckingham
4690b1a6cb Themes
- Removed background color from debug messages.
- Removed color.completed and color.deleted.
- Swapped the overdue magenta for red.
- Changed burndown and history to use red, yellow, green.
- Inverted the calendar holiday colors.
- Removed background from color.calendar.weeknumber.
2015-03-15 10:52:28 -04:00
Paul Beckingham
ce1a7b921c Themes
- Removed all the 16-color names, which do not apply to the solarized palette.
- Modified color.blocking and color.blocked so that both fg and bg are specified.
- Modified color.burndown.* and color.history.* to use red, yellow, green.
2015-03-15 10:40:11 -04:00
Paul Beckingham
7a1645bba3 Themes
- Fixed color.burndown.done and color.burndown.started, which were two different
  shades of red.
- Fixed color.history.done, which was dark gray and should be closer to green.
2015-03-15 10:13:08 -04:00
Paul Beckingham
9f1b3e0d56 Themes
- Added run.default to test the default theme.
2015-03-15 10:08:47 -04:00
Paul Beckingham
0af8b1dbab Themes
- Added 'task color legend' to the scripts to make it easier to spot broken
  themes.
- Removed the 'run' script, which is no longer used.
2015-03-15 09:09:54 -04:00
Tomas Babej
1465bcb918 Context: Do not apply context for the export command 2015-03-14 17:28:20 -04:00
Paul Beckingham
4eb70e68b7 TW-63
- TW-63 indicators for UDAs (thanks to Datvid Patrick).
- Note that this was implemented in 2.4.0 and tracked via the duplicate
  issue TW-161.
2015-03-14 11:57:22 -04:00
Renato Alves
cd216bd4fd simpletap - Add color to test state when running on tty 2015-03-12 20:49:50 +00:00
Renato Alves
ac4a5c6d62 simpletap - Include scenario for expected failures
* Expected failures are treated as "ok" followed by a report of what went wrong
2015-03-12 20:00:02 +00:00
Renato Alves
a67593decf Tests - merge bug.1110.t with filter.t and convert to python 2015-03-12 19:34:58 +00:00
Renato Alves
7be294267b Tests - rename bug.1065.t to custom.config.t and convert to python 2015-03-11 15:32:54 +00:00
Renato Alves
920cdcca10 Tests - convert bug.1063.t to python 2015-03-11 15:32:54 +00:00
Paul Beckingham
7cc410f58e Documentation
- Fixed obsolete wiki reference in the main man page (thanks to David Patrick).
2015-03-11 08:46:05 -04:00
Paul Beckingham
5d42c0f6b6 Themes
- Updated the README for this version, not the previous one.
2015-03-10 19:17:17 -04:00
Renato Alves
cff680d074 Tests - merge bug.1056.t with project.t and convert to python 2015-03-10 19:18:55 +00:00
Renato Alves
dda190703e Tests - merge basic.t with version.t and convert to python
* _version now outputs "2.4.2 (git-ref)" instead of only "git-ref" when building from git.
* Changelog updated accordingly.
2015-03-09 16:02:26 +00:00
Wilhelm Schuermann
281edcc38f Unit Tests
- The Sith must never be allowed to regain their power over us.
2015-03-08 09:04:39 -04:00
Paul Beckingham
87d00698db Unit Tests
- Successful hook tests now query the task to make sure processing continued.
  Could be better.
2015-03-07 16:18:44 -05:00
Paul Beckingham
19674ee339 Unit Tests
- Specifically set certain color rules to '' to override default theme.
2015-03-07 16:11:38 -05:00
Paul Beckingham
9f654a5c95 Unit Tests
- Test was wrong.
2015-03-07 16:06:18 -05:00
Paul Beckingham
87e9578666 Unit Tests
- Combined all the separate color rule tests into one script, and converted
  it to Python.
2015-03-07 13:29:59 -05:00
Paul Beckingham
e3ec52f6ca Unit Tests
- Cleaned up color.t.cpp.
2015-03-07 12:14:39 -05:00
Paul Beckingham
70c3d9845c Unіt Tests
- Merged width.t.cpp into utf8.t.cpp.
2015-03-07 11:59:37 -05:00
Paul Beckingham
9d1c4101c2 Unit Tests
- Renamed feature.exit.t to shell.t so that this test script is known to
  contain shell-interaction tests.
- Converted to Python.
2015-03-07 11:48:42 -05:00
Paul Beckingham
44ed974fa2 Unit Tests
- Fixed all the test descriptions.
2015-03-07 11:44:44 -05:00
Paul Beckingham
3cf7a701c8 Conversion
- Updated script for BSD.
2015-03-07 11:38:52 -05:00
Paul Beckingham
d390f99fc5 Unit Tests
- Simplified the msg.t.cpp tests.
2015-03-07 11:35:48 -05:00
Paul Beckingham
a2cae67644 Unit Tests
- Converted filter-prefix.t to Python.  Still needs a rename and possible merge
  with other tests.
2015-03-07 11:11:18 -05:00
Renato Alves
ebd6977480 Tests - merge bug.1044 into project.t and convert to python 2015-03-06 16:44:28 +00:00
Renato Alves
276050ce0b Tests - rename bug.1043.t to completion.t and convert to python 2015-03-06 15:19:04 +00:00
Renato Alves
197815a3a7 Tests - convert bug.1036.t to python 2015-03-06 15:10:07 +00:00
Paul Beckingham
5e8426f0cc Config
- The 'next' report was not sㄡrted by urgency, which is wrong (thanks
  to Adam Coddington).
2015-03-05 18:26:43 -05:00
Wilhelm Schuermann
138360b7bc Hooks
- Fixed on-modify hook regression which stopped hooks from modifying
  tasks.  On a related note, more hooks tests are definitely needed.
2015-03-05 07:21:30 -05:00
Renato Alves
7fa3c5ac84 Tests - convert bug.1031.t to python 2015-03-04 00:54:40 +00:00
Renato Alves
b5da4acab9 Tests - run_all script now exports TASKD_USE_PATH=1 2015-03-03 01:50:57 +00:00
Renato Alves
180c382de2 Tests - Finer control on which binaries to look for on PATH
* It is now possible to control whether taskw and/or taskd are looked up
on the PATH by setting TASK_USE_PATH/TASKD_USE_PATH to "1"
2015-03-03 01:46:53 +00:00
Renato Alves
23d4e2b3c9 Tests - rename bug.1023.t to feature.default.project.t and convert to python
Also add testcase from TW-1287 and TW-1279 which are part of the same feature
2015-03-03 01:25:45 +00:00
Paul Beckingham
96185cbd61 Merge branch '2.4.2' of ssh://git.tasktools.org/tm/task into 2.4.2 2015-03-02 16:17:09 -05:00
Paul Beckingham
7665d13d42 Duration
- Removed legacy duration value mapping, which causes much performance
  degradation.
2015-03-02 16:16:39 -05:00
Paul Beckingham
a40967a324 Unit Tests
- Fixed project.t errors.
2015-03-02 11:35:19 -05:00
Paul Beckingham
01feec568b Merge branch '2.4.2' of ssh://git.tasktools.org/tm/task into 2.4.2 2015-03-02 09:35:45 -05:00
Paul Beckingham
104aeb3905 TDB2
- Commented and reorganized for threading.
2015-03-02 09:33:57 -05:00
Tomas Babej
f0cc0151b7 TDB2: Explicitly mark updates done as addition to optimize performance
We are able to avoid loading the completed.data in certain scenarios.
2015-02-28 16:54:09 -05:00
Tomas Babej
48be6986c2 Make tasks affect statistics of super-projects 2015-02-28 09:34:10 -05:00
Tomas Babej
ffd6465661 CmdProjects: Enforce garbage collector 2015-02-28 09:33:36 -05:00
Paul Beckingham
58e62711f3 Virtual Tags
- The 'info' command now shows virtual tags.
2015-02-26 21:09:50 -05:00
Tomas Babej
3b9d88a87b completion: Add bash completion for contexts 2015-02-26 20:51:39 -05:00
Paul Beckingham
aa8cd54142 TW-1535
- TW-1535 move default listing-break from list to ls (thanks to David Patrick).
2015-02-24 22:57:56 -05:00
Paul Beckingham
651ac3f174 Tw-1551
- TW-1551 Unable to get a UDA value from DOM (thanks to Tomas Babej).
2015-02-24 22:35:18 -05:00
Paul Beckingham
ea78200ae3 TW-1549
- TW-1549 task annotate hangs with specific text pattern (thanks to Alexandre
          de Verteuil).
2015-02-24 22:04:05 -05:00
Paul Beckingham
ad89a90d12 TW-1550
- TW-1550 _contexts helper-command (thanks to David Patrick).
2015-02-24 20:43:28 -05:00
Tomas Babej
85d0e1789a CmdContext: Validate context's filter upon definition 2015-02-24 16:55:28 -05:00
Tomas Babej
e19c99ce1e CmdContext: Fix incorrect exception handling 2015-02-24 16:53:23 -05:00
Tomas Babej
0868ba757c CmdConfig: Do not leave empty line upon variable removal 2015-02-24 16:52:55 -05:00
Tomas Babej
bf5f246168 man: Fix copy-paste error in task.1 2015-02-24 16:51:28 -05:00
Tomas Babej
9748fa2ab1 tests: Fix asserted strings in context tests 2015-02-24 16:51:20 -05:00
Tomas Babej
1a0f479394 CmdContext: Add helpful hint to output when setting context 2015-02-24 16:51:05 -05:00
Wilhelm Schuermann
e2f35a1a06 Hooks
- onAdd, onExit, onLaunch and onModify hooks now output feedback messages
  as footnotes when hooks exit with status 0, as per hooks documentation.
2015-02-24 16:45:23 -05:00
Paul Beckingham
394acae790 CmdContext
- Trivіal code edits.
2015-02-23 20:07:53 -05:00
Tomas Babej
e8d385119a Update NEWS and ChangeLog files with the info about the context 2015-02-23 19:25:40 -05:00
Tomas Babej
070fdf60fa localization: Update other locale files 2015-02-23 19:22:06 -05:00
Tomas Babej
1278226c16 CmdContext: Localize the hardcoded strings 2015-02-23 19:22:01 -05:00
Tomas Babej
98410cff42 CmdShow: Add context related variables 2015-02-23 19:21:57 -05:00
Tomas Babej
ee23a099f2 CmdContext: Minor style and message changes 2015-02-23 19:21:50 -05:00
Tomas Babej
0ab1dc0c9c man: Update task and taskrc manpages with the information about context 2015-02-23 19:21:46 -05:00
Tomas Babej
c2a9bb65e6 tests: Add tests for the context feature 2015-02-23 19:20:00 -05:00
Tomas Babej
75cf742a55 tests: Add taskrc_content property 2015-02-23 19:19:55 -05:00
Tomas Babej
dc0502dd9f CLI: Apply context filter directly in getFilter method 2015-02-23 19:19:51 -05:00
Tomas Babej
3a77a5f291 CLI: Add addContextFilter method 2015-02-23 19:19:47 -05:00
Tomas Babej
1abda3900b CLI: Abstract adding new raw filter to a new helper method 2015-02-23 19:19:44 -05:00
Tomas Babej
09fe5be086 CmdContext: Add show subcommand 2015-02-23 19:19:41 -05:00
Tomas Babej
1a3550541b CmdContext: Add support for unsetting context 2015-02-23 19:19:38 -05:00
Tomas Babej
371ca27da0 CmdContext: Add support for setting context 2015-02-23 19:19:35 -05:00
Tomas Babej
5f3dd43893 CmdCompletionContext: Implement the context completion list 2015-02-23 19:19:32 -05:00
Tomas Babej
edb54a51b3 CmdContext: Add list subcommand 2015-02-23 19:19:29 -05:00
Tomas Babej
636f6bfd96 CmdContext: Add initial implementation of the delete subcommand 2015-02-23 19:19:24 -05:00
Tomas Babej
e91063426a CmdContext: Add initial implementation of the context define subcommand 2015-02-23 19:19:18 -05:00
Tomas Babej
a4d5ab07e9 CmdConfig: Abstract saving and removal of the configuration values into separate methods 2015-02-23 19:19:15 -05:00
Tomas Babej
49a7e46eaf CmdContext: Add initial plumbing 2015-02-23 19:19:08 -05:00
Wilhelm Schuermann
0891ed4b57 Util
- Closed dangling pipes in execute (), resolving problems when a hook script
  forks (thanks to Jens Erat).
2015-02-22 14:43:16 -05:00
Wilhelm Schuermann
af772f4c49 Util
- Closed dangling pipes in execute (), resolving problems when a hook script
  forks.
2015-02-22 14:03:30 -05:00
Wilhelm Schuermann
3484e44c7d CMake
- Added workaround for Cygwin build errors.
2015-02-22 13:53:53 -05:00
Wilhelm Schuermann
be855af8c4 CMake
- Custom compile flags and flags for c++11 ignored even less on OSX now...
2015-02-19 19:17:14 -08:00
Paul Beckingham
1ae4ea2ea3 I18N
- Removed unnecessary string termination and exceptions.
- Removed associated localized errors.
2015-02-19 08:51:36 -08:00
Renato Alves
d37937d970 Tests - add total number of tests to conversion script 2015-02-19 14:11:19 +00:00
Renato Alves
51e947064f Tests - merge args.[2-5].t with enpassant.t and convert to python 2015-02-19 13:38:27 +00:00
Renato Alves
606a7505d3 Tests - convert args.5.t to python 2015-02-19 13:02:46 +00:00
Renato Alves
846dd14a9f Tests - convert args.4.t to python 2015-02-19 12:56:19 +00:00
Renato Alves
d8f436cca9 Tests - convert args.3.t to python 2015-02-19 12:54:45 +00:00
Renato Alves
ac9c726782 Tests - convert args.2.t to python 2015-02-19 12:50:40 +00:00
Paul Beckingham
88d65b23c1 CMake Feedback Messages
- Reworded the '-std=c++11' feedback messages to user fewer '!' characters,
  and be more emphatic about upgrading the compiler.
2015-02-18 21:15:58 -08:00
Paul Beckingham
f2998aba74 TW-1547
- TW-1547 Recur column is always shown even if no recurring task is displayed
          (thanks to Renato Alves).
2015-02-18 20:53:56 -08:00
Paul Beckingham
d2b2631db7 TW-1546
- TW-1546 column type due.remaining breaks colors on due tasks (thanks to Renato
          Alves).
2015-02-18 20:18:31 -08:00
Renato Alves
4c491d8a0d Tests - convert args.1.t to python 2015-02-18 19:54:45 +00:00
Renato Alves
917a152a1e Tests - convert args.t to python 2015-02-18 19:32:58 +00:00
Renato Alves
289e45499a Tests - convert append.t to python 2015-02-18 16:26:59 +00:00
Renato Alves
2efb9594d9 Tests - convert annotate.t to python 2015-02-18 14:05:53 +00:00
Wilhelm Schuermann
0d096a5a42 CMake
- Fixed the C++11 config to actually check for availability of C++11 before trying to use it.
- Custom CXX flags no longer ignored on some platforms.
2015-02-17 16:16:02 -08:00
Paul Beckingham
cc1c063925 Merge branch '2.4.2' of ssh://git.tasktools.org/tm/task into 2.4.2 2015-02-17 18:46:41 -05:00
Paul Beckingham
dd31a15001 Portability
- Removed pthreads linkage.
2015-02-17 12:49:58 -05:00
Paul Beckingham
c11601e30e Cleanup
- Removed unused Nibbler::getHex.
2015-02-17 10:58:45 -05:00
Paul Beckingham
520067f522 Cleanup
- Eliminated text.cpp upperCase(), as it was not UTF8-safe, and is no longer
  used.
2015-02-17 10:44:31 -05:00
Paul Beckingham
693fe9b8fd ColPriority
- Made the acceptance of lower-case priorities explicitly either lower or upper
  case, but converted to upper case. This eliminates the dependency on text.cpp
  upperCase(), which is not UTF8-safe.
2015-02-17 10:40:51 -05:00
Renato Alves
fa249bfedd Tests - Convert alias.t to python 2015-02-17 13:46:00 +00:00
Paul Beckingham
952d743218 Cleanup
- Removed duplicate legacy value map entry.
- Added version number to legacy mapping.
- Added TODO for later clarification.
2015-02-17 08:39:53 -05:00
Paul Beckingham
91f6980d2f Documents
- Updated INSTALL instructions with dependencies.
2015-02-17 08:39:17 -05:00
Renato Alves
d211969236 Tests - clarify that USE_PATH alone is not enough. 2015-02-17 13:37:39 +00:00
Renato Alves
bd320b6729 Tests - Remove commented code 2015-02-17 12:24:13 +00:00
Renato Alves
3f004f547e Tests - Don't hang if spawning taskw fails 2015-02-17 12:24:13 +00:00
Paul Beckingham
3b192cddcf Merge branch '2.4.2' of ssh://git.tasktools.org/tm/task into 2.4.2 2015-02-16 19:33:14 -05:00
Paul Beckingham
ca6061a987 Documentation
- Updated for 2.4.2.
2015-02-16 19:32:02 -05:00
Federico Hernandez
2787ee960b Cleanup NEWS file 2015-02-17 00:22:07 +01:00
Federico Hernandez
c27ad4dc27 Bumped version number in ref page 2015-02-17 00:18:45 +01:00
Federico Hernandez
a36eb974ee Bumped version number to 2.4.2 2015-02-17 00:04:04 +01:00
Federico Hernandez
a55a7bf1a2 Added SHA1 of tagged release commit 2015-02-17 00:00:20 +01:00
145 changed files with 4317 additions and 3524 deletions

View File

@@ -245,3 +245,4 @@ suggestions:
Scott Carter Scott Carter
Taisuke Hachimura Taisuke Hachimura
Martin Martin
Alexandre de Verteuil

View File

@@ -10,17 +10,40 @@ include (CheckStructHasMember)
set (HAVE_CMAKE true) set (HAVE_CMAKE true)
project (task) project (task)
set (PROJECT_VERSION "2.4.1") set (PROJECT_VERSION "2.4.2")
OPTION(USE_GNUTLS "Build gnutls support." ON) OPTION(USE_GNUTLS "Build gnutls support." ON)
message ("CMAKE_SYSTEM_NAME ${CMAKE_SYSTEM_NAME}") message ("CMAKE_SYSTEM_NAME ${CMAKE_SYSTEM_NAME}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
include (CheckCXXCompilerFlag)
# NOTE: If we are to actually use C++11 features, we should either require
# a compiler that supports the -std=c++11 flag or check for the
# features used.
# Relying on -std=c++0x or even -std=gnu++0x is highly volatile.
CHECK_CXX_COMPILER_FLAG("-std=c++11" _HAS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" _HAS_CXX0X)
CHECK_CXX_COMPILER_FLAG("-std=gnu++0x" _HAS_GNU0X)
if (_HAS_CXX11)
set (_CXX11_FLAGS "-std=c++11")
elseif (_HAS_CXX0X)
message (WARNING "Enabling -std=c++0x draft compile flag. Your compiler does not support the standard '-std=c++11' option. Consider upgrading.")
set (_CXX11_FLAGS "-std=c++0x")
elseif (_HAS_GNU0X)
message (WARNING "Enabling -std=gnu++0x draft compile flag. Your compiler does not support the standard '-std=c++11' option. Consider upgrading.")
set (_CXX11_FLAGS "-std=gnu++0x")
else (_HAS_CXX11)
message (FATAL_ERROR "C++11 support missing. Try upgrading your C++ compiler. If you have a good reason for using an outdated compiler, please let us know at support@taskwarrior.org.")
endif (_HAS_CXX11)
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set (LINUX true) set (LINUX true)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set (DARWIN true) set (DARWIN true)
set (CMAKE_CXX_FLAGS "-std=c++11 -stdlib=libc++") set (_CXX11_FLAGS "${_CXX11_FLAGS} -stdlib=libc++")
elseif (${CMAKE_SYSTEM_NAME} MATCHES "kFreeBSD") elseif (${CMAKE_SYSTEM_NAME} MATCHES "kFreeBSD")
set (KFREEBSD true) set (KFREEBSD true)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
@@ -35,11 +58,16 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "GNU")
set (GNUHURD true) set (GNUHURD true)
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "CYGWIN") elseif (${CMAKE_SYSTEM_NAME} STREQUAL "CYGWIN")
set (CYGWIN true) set (CYGWIN true)
set (CMAKE_CXX_FLAGS "-std=gnu++0x") # NOTE: Not setting -std=gnu++0x leads to compile errors even with
# GCC 4.8.3, and debugging those leads to insanity. Adding this
# workaround instead of fixing Cygwin.
set (_CXX11_FLAGS "-std=gnu++0x")
else (${CMAKE_SYSTEM_NAME} MATCHES "Linux") else (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set (UNKNOWN true) set (UNKNOWN true)
endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set (CMAKE_CXX_FLAGS "${_CXX11_FLAGS} ${CMAKE_CXX_FLAGS}")
if (NETBSD) if (NETBSD)
# Since readline, etc likely to be in /usr/pkg/lib, not standard library # Since readline, etc likely to be in /usr/pkg/lib, not standard library
# Otherwise will remove links during install # Otherwise will remove links during install
@@ -86,16 +114,6 @@ if (USE_GNUTLS)
endif (GNUTLS_FOUND) endif (GNUTLS_FOUND)
endif (USE_GNUTLS) endif (USE_GNUTLS)
#message ("-- Looking for pthread")
#find_path (PTHREAD_INCLUDE_DIR pthread.h)
#find_library (PTHREAD_LIBRARY NAMES pthread)
#if (PTHREAD_INCLUDE_DIR AND PTHREAD_LIBRARY)
# message ("-- Found pthread: ${PTHREAD_LIBRARY}")
# set (HAVE_LIBPTHREAD true)
# set (TASK_INCLUDE_DIRS ${TASK_INCLUDE_DIRS} ${PTHREAD_INCLUDE_DIR})
# set (TASK_LIBRARIES ${TASK_LIBRARIES} ${PTHREAD_LIBRARIES})
#endif (PTHREAD_INCLUDE_DIR AND PTHREAD_LIBRARY)
check_function_exists (timegm HAVE_TIMEGM) check_function_exists (timegm HAVE_TIMEGM)
check_function_exists (get_current_dir_name HAVE_GET_CURRENT_DIR_NAME) check_function_exists (get_current_dir_name HAVE_GET_CURRENT_DIR_NAME)
check_function_exists (wordexp HAVE_WORDEXP) check_function_exists (wordexp HAVE_WORDEXP)

View File

@@ -1,4 +1,35 @@
2.4.1 (2015-02-16) - 2.4.2 (2015-03-15) -
- TW-41 Tasks in subprojects are not counted in project completion (thanks
to Renato Alves).
- TW-1450 Projects command should trigger running garbage collector (thanks to
Tomas Babej).
- TW-1535 move default listing-break from list to ls (thanks to David Patrick).
- TW-1545 cc1plus: error: unrecognized command line option '-std=c++11' (thanks
to Petteri).
- TW-1546 column type due.remaining breaks colors on due tasks (thanks to
Renato Alves).
- TW-1547 Recur column is always shown even if no recurring task is displayed
(thanks to Renato Alves).
- TW-1549 task annotate hangs with specific text pattern (thanks to Alexandre
de Verteuil).
- TW-1550 _contexts helper-command (thanks to David Patrick).
- TW-1551 Unable to get a UDA value from DOM (thanks to Tomas Babej).
- Eliminated some code that is not UTF8-safe.
- Removed pthreads linkage.
- Implemented the context feature.
- Closed dangling pipes in execute (), resolving problems when a hook script
forks (thanks to Jens Erat).
- Re-enabled hook script feedback when exiting with 0 exit status.
- The 'info' command now shows virtual tags.
- Fixed major on-modify hooks regression where hooks could no longer modify
the tasks handed to them.
- '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 - TW-1457 Non-existent attributes are not properly handled (thanks to Tomas
Babej). Babej).
@@ -46,8 +77,6 @@
Sujeevan Vijayakumaran). Sujeevan Vijayakumaran).
- New 'recurrence' configuration setting can disable recurring task generation. - New 'recurrence' configuration setting can disable recurring task generation.
------ current release ---------------------------
2.4.0 (2015-01-01) 670102842c39bdc62ef84ae4b679a8f5a2d89523 2.4.0 (2015-01-01) 670102842c39bdc62ef84ae4b679a8f5a2d89523
- TD-42 Cannot compile taskd - GNUTLS_VERSION undefined in diag.cpp (thanks - TD-42 Cannot compile taskd - GNUTLS_VERSION undefined in diag.cpp (thanks
@@ -95,6 +124,7 @@
- TW-52 "task add ... recur:2 months" interpreted as "2s" (thanks to jwhisnant). - TW-52 "task add ... recur:2 months" interpreted as "2s" (thanks to jwhisnant).
- TW-55 Bulk edit recurring tasks without answering yes/no for each? (thanks to - TW-55 Bulk edit recurring tasks without answering yes/no for each? (thanks to
Max Muller). Max Muller).
- TW-63 indicators for UDAs (thanks to David Patrick).
- TW-71 task ls/list/long/etc. should match contents of projects too (thanks to - TW-71 task ls/list/long/etc. should match contents of projects too (thanks to
Cory Donnelly). Cory Donnelly).
- TW-72 extend info report with urgency column. - TW-72 extend info report with urgency column.

View File

@@ -10,7 +10,7 @@ How to Build Taskwarrior
Obtain and build code: Obtain and build code:
$ git clone https://git.tasktools.org/scm/tm/task.git task.git $ git clone https://git.tasktools.org/scm/tm/task.git task.git
$ cd task.git $ cd task.git
$ git checkout 2.4.1 # Latest dev branch $ git checkout 2.4.2 # Latest dev branch
$ cmake -DCMAKE_BUILD_TYPE=debug . # debug or release. Default: neither. $ cmake -DCMAKE_BUILD_TYPE=debug . # debug or release. Default: neither.
$ make VERBOSE=1 # Shows details $ make VERBOSE=1 # Shows details

11
INSTALL
View File

@@ -8,16 +8,17 @@ 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. from source. More information on cmake can be obtained at http://cmake.org
You will need a C++ compiler that support C++11 N1984, which includes: You will need a C++ compiler that supports C++11 N1984, which includes:
- gcc 4.4 (released 2009-04-21) - gcc 4.4 (released 2009-04-21)
- clang 2.9 (released 2011-04-06) - clang 2.9 (released 2011-04-06)
- uuid lib
- gnutls (optional)
More information on cmake can be obtained at http://cmake.org In addition:
- uuid lib
- gnutls (optional - for syncing)
It is HIGHLY RECOMMENDED that you build with a library that provides uuid_* It is HIGHLY RECOMMENDED that you build with a library that provides uuid_*
functions, such as libuuid. functions, such as libuuid.

46
NEWS
View File

@@ -1,26 +1,24 @@
New Features in taskwarrior 2.4.1 New Features in taskwarrior 2.4.2
- New German translation. - Ability to set context, which serves as a permanent user-defined filter.
- Hook scripts are now under much stricter control. - The 'info' command now shows virtual tags.
New commands in taskwarrior 2.4.1 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
- None - None
New configuration options in taskwarrior 2.4.1 Removed features in 2.4.2
- The 'date.iso' setting allows you to enable (default) or disable support
for ISO-8601 dates. This is because some of you have 'dateformat' settings
that conflict.
- The 'recurrence' setting enables (default) or disables recurring task
instance generation.
Newly deprecated features in taskwarrior 2.4.1
- None
Removed features in 2.4.1
- None - None
@@ -40,13 +38,13 @@ Known Issues
Taskwarrior has been built and tested on the following configurations: Taskwarrior has been built and tested on the following configurations:
* OS X 10.10 Yosemite * OS X
* Fedora 20 Heisenbug * Fedora
* Ubuntu 14.04 Trusty Tahr * Ubuntu
* Debian 7.0 Wheezy (stable) * Debian
* Arch 2014.05 * Arch
* FreeBSD 10 * FreeBSD
* Cygwin 1.7.29, 1.7.32 * Cygwin
--- ---

View File

@@ -1,4 +1,4 @@
.TH task-color 5 2015-02-16 "${PACKAGE_STRING}" "User Manuals" .TH task-color 5 2015-03-15 "${PACKAGE_STRING}" "User Manuals"
.SH NAME .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.

View File

@@ -1,4 +1,4 @@
.TH task-sync 5 2015-02-16 "${PACKAGE_STRING}" "User Manuals" .TH task-sync 5 2015-03-15 "${PACKAGE_STRING}" "User Manuals"
.SH NAME .SH NAME
task-sync \- A discussion and tutorial for the various task(1) data task-sync \- A discussion and tutorial for the various task(1) data

View File

@@ -1,4 +1,4 @@
.TH task 1 2015-02-16 "${PACKAGE_STRING}" "User Manuals" .TH task 1 2015-03-15 "${PACKAGE_STRING}" "User Manuals"
.SH NAME .SH NAME
task \- A command line todo manager. task \- A command line todo manager.
@@ -396,6 +396,46 @@ Finally, this command removes any 'name=...' entry from the .taskrc file:
task config name task config name
.TP
.B task context <name>
Sets the currectly active context. See the CONTEXT section.
Example:
task context work
.TP
.B task context delete <name>
Deletes the context with the name <name>. If the context being deleted is currently
set as active, it will be unset.
Example:
task context delete work
.TP
.B task context define <name> <filter>
Defines a new context with name <name> and definition <filter>. This command
does not affect the currently set context, just adds a new context definition.
Examples:
task context define work project:Work
task context define home project:Home or +home
task context define superurgent due:today and +urgent
.TP
.B task context list
Outputs a list of available contexts along with their definitions.
.TP
.B task context none
Unsets the currently active context, if any was set.
.TP
.B task context show
Shows the currently active context, along with its definition.
.TP .TP
.B task diagnostics .B task diagnostics
Shows diagnostic information, of the kind needed when reporting a problem. Shows diagnostic information, of the kind needed when reporting a problem.
@@ -474,6 +514,10 @@ Generates a list of all commands, for autocompletion purposes.
.B task _config .B task _config
Lists all supported configuration variables, for completion purposes. Lists all supported configuration variables, for completion purposes.
.TP
.B task _context
Lists all available context variables, for completion purposes.
.TP .TP
.B task <filter> _ids .B task <filter> _ids
Shows only the IDs of matching tasks, in the form of a list. Shows only the IDs of matching tasks, in the form of a list.
@@ -962,6 +1006,66 @@ biannual, biyearly, 2yr
Every two years. Every two years.
.RE .RE
.SH CONTEXT
Context is a user-defined filter, which is automatically applied to all commands
that filter the task list. In particular, any report command will have its
result affected by the current active context.
$ task list
ID Age Project Description Urg
1 2d Sport Run 5 miles 1.42
2 1d Home Clean the dishes 1.14
$ task context home
Context 'home' set. Use 'task context none' to remove.
$ task list
ID Age Project Description Urg
2 1d Home Clean the dishes 1.14
Context 'home' set. Use 'task context none' to remove.
As seen in the example above, context is applied by specifying its name to the
"context" command. To change the currently applied context, just pass the
new context's name to the 'context' command.
To unset any context, use the 'none' subcommand.
$ task context none
Context unset.
$ task list
ID Age Project Description Urg
1 2d Sport Run 5 miles 1.42
2 1d Home Clean the dishes 1.14
Context can be defined using the 'define' subcommand, specifying both the name
of the new context, and it's assigned filter.
$ task context define home
Are you sure you want to add 'context.home' with a value of 'project:Home'? (yes/no) yes
Context 'home' successfully defined.
To remove the definition, use the 'delete' subcommand.
$ task context delete home
Are you sure you want to remove 'context.home'? (yes/no) yes
Context 'home' successfully undefined.
To check what is the currently active context, use the 'show' subcommand.
$ task context show
Context 'home' with filter 'project:Home' is currently applied.
Contexts can store arbitrarily complex filters.
$ task context define family project:Family or +paul or +nancy
Are you sure you want to add 'context.home' with a value of 'project:Family or +paul or +nancy'? (yes/no) yes
Context 'family' successfully defined.
Contexts are permanent, and the currently set context name is stored in the
"context" configuration variable. The context definition is stored in the
"context.<name>" configuration variable.
.SH COMMAND ABBREVIATION .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: for example:
@@ -1057,11 +1161,11 @@ the 'data.location' configuration setting of the task data directory.
For examples please see the online documentation starting at For examples please see the online documentation starting at
.RS .RS
<http://taskwarrior.org/projects/taskwarrior/wiki> <http://taskwarrior.org/docs>
.RE .RE
Note that the online documentation is more detailed and more current than this Note that the online documentation can be more detailed and more current than
man page. this man page.
.SH FILES .SH FILES

View File

@@ -1,4 +1,4 @@
.TH taskrc 5 2015-02-16 "${PACKAGE_STRING}" "User Manuals" .TH taskrc 5 2015-03-15 "${PACKAGE_STRING}" "User Manuals"
.SH NAME .SH NAME
taskrc \- Configuration details for the task(1) command taskrc \- Configuration details for the task(1) command
@@ -1351,6 +1351,26 @@ of a task.
.B uda.estimate.values=trivial,small,medium,large,huge .B uda.estimate.values=trivial,small,medium,large,huge
.RE .RE
.SS CONTEXT
Context setting is a mechanism which allows the user to set a permanent filter,
thus avoiding the need to specify one filter repeatedly. More details on usage
can be found in the task(1) manpage.
The current context is stored in the taskrc file, along with definitions for
all user provided contexts.
.TP
.B context=<name>
.RS
Stores the value of the currently active context.
.RE
.TP
.B context.<name>=<filter>
.RS
Stores the definition of the context with the name <name>.
.RE
.SS SYNC .SS SYNC
These configuration settings are used to connect and sync tasks with the task These configuration settings are used to connect and sync tasks with the task

View File

@@ -1,15 +1,24 @@
Themes Themes
To generate samples of themes, first execute the 'run' script to generate the To generate samples of themes, first execute the 'setup' script to generate the
sample data. Note that this data may need to be tweaked to include qualities sample data. Note that this data may need to be tweaked to include qualities
that need to be illustrated in theme sample. that need to be illustrated in theme sample.
Then edit the 'rc' file to include the desired theme file. Using a dark-background terminal (black recommended), run the following:
Then run 'per' to run a few commands for each theme. run.dark
Note that this will require that the terminal window be switched between a black Using a light-background terminal, run the following:
and white background to properly show the light and dark themes.
run.light
Using a solarized dark terminal, run the following:
run.solar.dark
Using a solarized light terminal, run the following:
run.solar.light
Note that for the solarized themes, the terminal color palette needs to be set Note that for the solarized themes, the terminal color palette needs to be set
to specific colors. to specific colors.

View File

@@ -1,23 +0,0 @@
for theme in $PWD/../../rc/*.theme
do
cat <<EOF >>x
data.location=.
confirmation=off
_forcecolor=on
include $theme
EOF
echo "--- $theme -----------------------------------------------------"
echo '$ task list'
task rc:x list
echo '$ task summary'
task rc:x summary
echo '$ task ghistory'
task rc:x ghistory
echo '$ task calendar'
task rc:x calendar
echo '$ task burndown.daily'
task rc:x burndown.daily
done

View File

@@ -21,6 +21,8 @@ include $theme
EOF EOF
echo "--- $theme -----------------------------------------------------" echo "--- $theme -----------------------------------------------------"
echo '$ task color legend'
task rc:x color legend
echo '$ task list' echo '$ task list'
task rc:x list task rc:x list
echo '$ task summary' echo '$ task summary'

24
doc/misc/themes/run.default Executable file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
cat <<EOF >x
data.location=.
confirmation=off
detection=off
_forcecolor=on
default.height=24
verbose=off
EOF
echo "--- DEFAULT -----------------------------------------------------"
echo '$ task color legend'
task rc:x color legend
echo '$ task list'
task rc:x list
echo '$ task summary'
task rc:x summary
echo '$ task ghistory'
task rc:x ghistory
echo '$ task calendar'
task rc:x calendar
echo '$ task burndown.daily'
task rc:x burndown.daily

View File

@@ -14,6 +14,8 @@ include $theme
EOF EOF
echo "--- $theme -----------------------------------------------------" echo "--- $theme -----------------------------------------------------"
echo '$ task color legend'
task rc:x color legend
echo '$ task list' echo '$ task list'
task rc:x list task rc:x list
echo '$ task summary' echo '$ task summary'

View File

@@ -13,6 +13,8 @@ include $theme
EOF EOF
echo "--- $theme -----------------------------------------------------" echo "--- $theme -----------------------------------------------------"
echo '$ task color legend'
task rc:x color legend
echo '$ task list' echo '$ task list'
task rc:x list task rc:x list
echo '$ task summary' echo '$ task summary'

View File

@@ -13,6 +13,8 @@ include $theme
EOF EOF
echo "--- $theme -----------------------------------------------------" echo "--- $theme -----------------------------------------------------"
echo '$ task color legend'
task rc:x color legend
echo '$ task list' echo '$ task list'
task rc:x list task rc:x list
echo '$ task summary' echo '$ task summary'

View File

@@ -33,15 +33,15 @@ color.alternate=
color.header=yellow color.header=yellow
color.footnote=yellow color.footnote=yellow
color.warning=bold red color.warning=bold red
color.error=yellow color.error=white on red
color.debug=yellow color.debug=blue
# Task state # Task state
color.completed=green on white color.completed=
color.deleted=red on white color.deleted=
color.active=black on bright green color.active=black on bright green
color.recurring=magenta color.recurring=magenta
color.scheduled=on green color.scheduled=white on green
color.until= color.until=
color.blocked=black on white color.blocked=black on white
color.blocking=black on bright white color.blocking=black on bright white

View File

@@ -29,16 +29,16 @@ rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overd
# General decoration # General decoration
color.label= color.label=
color.label.sort= color.label.sort=
color.alternate=on gray1 color.alternate=on gray2
color.header=color3 color.header=color3
color.footnote=color3 color.footnote=color3
color.warning=bold red color.warning=bold red
color.error=color3 color.error=white on red
color.debug=color3 color.debug=color4
# Task state # Task state
color.completed=rgb010 on white color.completed=
color.deleted=rgb100 on white color.deleted=
color.active=rgb555 on rgb410 color.active=rgb555 on rgb410
color.recurring=rgb013 color.recurring=rgb013
color.scheduled=on rgb001 color.scheduled=on rgb001

View File

@@ -29,19 +29,19 @@ rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overd
# General decoration # General decoration
color.label= color.label=
color.label.sort= color.label.sort=
color.alternate=on gray1 color.alternate=on gray2
color.header=rgb013 color.header=rgb013
color.footnote=rgb013 color.footnote=rgb013
color.warning=bold red color.warning=bold red
color.error=rgb013 color.error=white on red
color.debug=rgb013 color.debug=rgb013
# Task state # Task state
color.completed=rgb001 on white color.completed=
color.deleted=rgb100 on white color.deleted=
color.active=rgb045 on rgb015 color.active=rgb045 on rgb015
color.recurring=rgb115 color.recurring=rgb115
color.scheduled=on rgb011 color.scheduled=on rgb012
color.until= color.until=
color.blocked=white on rgb001 color.blocked=white on rgb001
color.blocking=white on rgb002 color.blocking=white on rgb002
@@ -76,8 +76,8 @@ color.history.delete=color0 on rgb035
color.history.done=color0 on rgb025 color.history.done=color0 on rgb025
# Report: summary # Report: summary
color.summary.background=white on color0 color.summary.background=on rgb001
color.summary.bar=white on rgb003 color.summary.bar=on rgb114
# Command: calendar # Command: calendar
color.calendar.due.today=color0 on color252 color.calendar.due.today=color0 on color252

View File

@@ -29,16 +29,16 @@ rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overd
# General decoration # General decoration
color.label= color.label=
color.label.sort= color.label.sort=
color.alternate=on gray1 color.alternate=on gray2
color.header=color0 on gray11 color.header=color0 on gray11
color.footnote=on gray5 color.footnote=on gray5
color.warning=bold red color.warning=bold red
color.error=red on white color.error=white on red
color.debug=black on white color.debug=blue
# Task state # Task state
color.completed=black on white color.completed=
color.deleted=black on white color.deleted=
color.active=black on gray18 color.active=black on gray18
color.recurring= color.recurring=
color.scheduled=on gray8 color.scheduled=on gray8
@@ -61,7 +61,7 @@ color.tag.none=
color.tagged= color.tagged=
# Due # Due
color.due=on gray2 color.due=on gray3
color.due.today=on gray4 color.due.today=on gray4
color.overdue=on gray6 color.overdue=on gray6
@@ -76,12 +76,12 @@ color.history.delete=black on gray10
color.history.done=gray5 on gray23 color.history.done=gray5 on gray23
# Report: summary # Report: summary
color.summary.bar=on gray15 color.summary.bar=on gray12
color.summary.background=on black color.summary.background=on gray5
# Command: calendar # Command: calendar
color.calendar.due=on gray8 color.calendar.due=on gray8
color.calendar.due.today=on gray15 color.calendar.due.today=black on gray15
color.calendar.holiday=black on gray20 color.calendar.holiday=black on gray20
color.calendar.overdue=gray2 on gray10 color.calendar.overdue=gray2 on gray10
color.calendar.today=bold white color.calendar.today=bold white
@@ -89,7 +89,7 @@ color.calendar.weekend=on gray2
color.calendar.weeknumber=gray6 color.calendar.weeknumber=gray6
# Command: sync # Command: sync
color.sync.add=gray15 on gray5 color.sync.added=gray15 on gray5
color.sync.changed=black on gray10 color.sync.changed=black on gray10
color.sync.rejected=gray5 on gray23 color.sync.rejected=gray5 on gray23

View File

@@ -29,12 +29,12 @@ rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overd
# General decoration # General decoration
color.label= color.label=
color.label.sort= color.label.sort=
color.alternate=on gray0 color.alternate=on gray2
color.header=gray10 color.header=gray10
color.footnote=gray10 color.footnote=gray10
color.warning= color.warning=
color.error=rgb500 color.error=white on red
color.debug=rgb500 color.debug=blue
# Task state # Task state
color.completed= color.completed=
@@ -66,18 +66,18 @@ color.due.today=color0 on rgb024
color.overdue=color0 on rgb035 color.overdue=color0 on rgb035
# Report: burndown # Report: burndown
color.burndown.pending=on gray9 color.burndown.pending=white on gray9
color.burndown.started=on gray16 color.burndown.started=black on gray16
color.burndown.done=on rgb013 color.burndown.done=white on rgb013
# Report: history # Report: history
color.history.add=on gray9 color.history.add=white on gray6
color.history.delete=black on gray23 color.history.delete=black on gray18
color.history.done=black on rgb013 color.history.done=black on rgb024
# Report: summary # Report: summary
color.summary.bar=on rgb012 color.summary.bar=on rgb012
color.summary.background=on color0 color.summary.background=on gray2
# Command: calendar # Command: calendar
color.calendar.due=color0 on gray10 color.calendar.due=color0 on gray10
@@ -94,6 +94,6 @@ color.sync.changed=gray15
color.sync.rejected=gray23 color.sync.rejected=gray23
# Command: undo # Command: undo
color.undo.before=green color.undo.before=rgb013
color.undo.after=red color.undo.after=rgb035

View File

@@ -29,19 +29,19 @@ rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overd
# General decoration # General decoration
color.label= color.label=
color.label.sort= color.label.sort=
color.alternate=on gray1 color.alternate=on gray2
color.header=rgb031 color.header=rgb031
color.footnote=rgb031 color.footnote=rgb031
color.warning=bold red color.warning=rgb020
color.error=rgb031 color.error=white on red
color.debug=rgb031 color.debug=blue
# Task state # Task state
color.completed=rgb020 on white color.completed=
color.deleted=rgb200 on white color.deleted=
color.active=rgb050 on rgb010 color.active=rgb050 on rgb010
color.recurring=rgb151 color.recurring=rgb151
color.scheduled=on rgb011 color.scheduled=black on rgb031
color.until= color.until=
color.blocked=white on rgb010 color.blocked=white on rgb010
color.blocking=white on rgb020 color.blocking=white on rgb020
@@ -76,7 +76,7 @@ color.history.delete=color0 on rgb050
color.history.done=color0 on rgb030 color.history.done=color0 on rgb030
# Report: summary # Report: summary
color.summary.background=white on color0 color.summary.background=white on gray3
color.summary.bar=white on rgb030 color.summary.bar=white on rgb030
# Command: calendar # Command: calendar
@@ -95,4 +95,4 @@ color.sync.rejected=rgb010
# Command: undo # Command: undo
color.undo.after=rgb053 color.undo.after=rgb053
color.undo.before=rgb031 color.undo.before=rgb021

View File

@@ -29,19 +29,19 @@ rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overd
# General decoration # General decoration
color.label= color.label=
color.label.sort= color.label.sort=
color.alternate=on gray1 color.alternate=on gray2
color.header=rgb100 color.header=rgb100
color.footnote=rgb100 color.footnote=rgb100
color.warning=bold red color.warning=red
color.error=rgb100 color.error=white on red
color.debug=rgb100 color.debug=blue
# Task state # Task state
color.completed=rgb020 on white color.completed=
color.deleted=rgb200 on white color.deleted=
color.active=rgb500 on rgb100 color.active=rgb500 on rgb100
color.recurring=rgb511 color.recurring=rgb511
color.scheduled=on rgb201 color.scheduled=white on rgb311
color.until= color.until=
color.blocked=white on rgb100 color.blocked=white on rgb100
color.blocking=white on rgb200 color.blocking=white on rgb200
@@ -56,7 +56,7 @@ color.pri.M=rgb400
color.pri.none= color.pri.none=
# Tags # Tags
color.tag.next=rgb440 color.tag.next=rgb511
color.tag.none= color.tag.none=
color.tagged=color246 color.tagged=color246
@@ -94,6 +94,6 @@ color.sync.changed=rgb411
color.sync.rejected=rgb200 color.sync.rejected=rgb200
# Command: undo # Command: undo
color.undo.after=rgb503 color.undo.after=rgb511
color.undo.before=rgb301 color.undo.before=rgb200

View File

@@ -33,15 +33,15 @@ color.alternate=on gray2
color.header=rgb013 color.header=rgb013
color.footnote=rgb013 color.footnote=rgb013
color.warning= color.warning=
color.error=rgb013 color.error=white on red
color.debug=rgb013 color.debug=blue
# Task state # Task state
color.completed= color.completed=
color.deleted= color.deleted=
color.active=rgb445 on rgb213 color.active=rgb445 on rgb213
color.recurring=rgb115 color.recurring=rgb115
color.scheduled= color.scheduled=white on rgb113
color.until= color.until=
color.blocked=white on rgb101 color.blocked=white on rgb101
color.blocking=white on rgb202 color.blocking=white on rgb202
@@ -61,9 +61,9 @@ color.tag.none=
color.tagged=rgb334 color.tagged=rgb334
# Due # Due
color.due=rgb055 color.due=rgb015
color.due.today=rgb533 color.due.today=rgb125
color.overdue=color9 color.overdue=color5
# Report: burndown # Report: burndown
color.burndown.pending=on rgb103 color.burndown.pending=on rgb103
@@ -76,14 +76,14 @@ color.history.done=color0 on rgb205
color.history.delete=color0 on rgb305 color.history.delete=color0 on rgb305
# Report: summary # Report: summary
color.summary.bar=white on rgb103 color.summary.bar=white on rgb104
color.summary.background=white on color0 color.summary.background=white on rgb001
# Command: calendar # Command: calendar
color.calendar.due=color0 on rgb325 color.calendar.due=color0 on rgb325
color.calendar.due.today=color0 on rgb404 color.calendar.due.today=color0 on rgb404
color.calendar.holiday=color15 on rgb022 color.calendar.holiday=color15 on rgb102
color.calendar.overdue=color0 on color9 color.calendar.overdue=color0 on color5
color.calendar.today=color15 on rgb103 color.calendar.today=color15 on rgb103
color.calendar.weekend=gray12 on gray3 color.calendar.weekend=gray12 on gray3
color.calendar.weeknumber=rgb104 color.calendar.weeknumber=rgb104

View File

@@ -33,15 +33,15 @@ color.alternate=on gray2
color.header=rgb031 color.header=rgb031
color.footnote=rgb031 color.footnote=rgb031
color.warning= color.warning=
color.error=rgb031 color.error=white on red
color.debug=rgb031 color.debug=blue
# Task state # Task state
color.completed= color.completed=
color.deleted= color.deleted=
color.active=rgb451 on rgb310 color.active=rgb451 on rgb320
color.recurring=rgb343 color.recurring=rgb343
color.scheduled= color.scheduled=black on rgb441
color.until= color.until=
color.blocked=white on rgb110 color.blocked=white on rgb110
color.blocking=white on rgb220 color.blocking=white on rgb220
@@ -61,9 +61,9 @@ color.tag.none=
color.tagged=rgb342 color.tagged=rgb342
# Due # Due
color.due=rgb420 color.due=rgb440
color.due.today=rgb410 color.due.today=rgb430
color.overdue=rgb400 color.overdue=rgb420
# Report: burndown # Report: burndown
color.burndown.pending=on rgb110 color.burndown.pending=on rgb110
@@ -71,19 +71,19 @@ color.burndown.started=on rgb430
color.burndown.done=on gray4 color.burndown.done=on gray4
# Report: history # Report: history
color.history.add=color0 on rgb010 color.history.add=color0 on rgb110
color.history.done=color0 on rgb030 color.history.done=color0 on rgb430
color.history.delete=color0 on rgb050 color.history.delete=white on gray4
# Report: summary # Report: summary
color.summary.bar=white on rgb030 color.summary.bar=white on rgb330
color.summary.background=white on color0 color.summary.background=white on rgb110
# Command: calendar # Command: calendar
color.calendar.due=color0 on rgb430 color.calendar.due=color0 on rgb440
color.calendar.due.today=color0 on rgb410 color.calendar.due.today=color0 on rgb430
color.calendar.holiday=rgb151 on rgb020 color.calendar.holiday=rgb151 on rgb020
color.calendar.overdue=color0 on rgb400 color.calendar.overdue=color0 on rgb420
color.calendar.today=color15 on rgb110 color.calendar.today=color15 on rgb110
color.calendar.weekend=on color235 color.calendar.weekend=on color235
color.calendar.weeknumber=rgb110 color.calendar.weeknumber=rgb110
@@ -94,6 +94,6 @@ color.sync.changed=rgb430
color.sync.rejected=rgb110 color.sync.rejected=rgb110
# Command: undo # Command: undo
color.undo.before=rgb031 color.undo.before=rgb021
color.undo.after=rgb053 color.undo.after=rgb042

View File

@@ -33,12 +33,12 @@ color.alternate=
color.header=bold white on bright black color.header=bold white on bright black
color.footnote=bold cyan on bright black color.footnote=bold cyan on bright black
color.warning=bold red color.warning=bold red
color.error=red on white color.error=white on red
color.debug=white on black color.debug=blue
# Task state # Task state
color.completed=green on black color.completed=
color.deleted=red on black color.deleted=
color.active=bold yellow on bright black color.active=bold yellow on bright black
color.recurring= color.recurring=
color.scheduled=on bright cyan color.scheduled=on bright cyan
@@ -63,17 +63,17 @@ color.tagged=
# Due # Due
color.due=on bright green color.due=on bright green
color.due.today=on bright yellow color.due.today=on bright yellow
color.overdue=on bright magenta color.overdue=on bright red
# Report: burndown # Report: burndown
color.burndown.pending=on bright green color.burndown.pending=on bright red
color.burndown.started=on bright yellow color.burndown.started=on bright yellow
color.burndown.done=on green color.burndown.done=on green
# Report: history # Report: history
color.history.add=blue on bright yellow color.history.add=black on bright red
color.history.done=green on bright green color.history.done=black on bright green
color.history.delete=black on red color.history.delete=black on yellow
# Report: summary # Report: summary
color.summary.bar=on bright green color.summary.bar=on bright green
@@ -82,11 +82,11 @@ color.summary.background=on white
# Command: calendar # Command: calendar
color.calendar.due=on bright green color.calendar.due=on bright green
color.calendar.due.today=blue on bright yellow color.calendar.due.today=blue on bright yellow
color.calendar.holiday=yellow color.calendar.holiday=on yellow
color.calendar.overdue=on bright magenta color.calendar.overdue=on bright red
color.calendar.today=blue color.calendar.today=blue
color.calendar.weekend=on white color.calendar.weekend=on white
color.calendar.weeknumber=white on bright black color.calendar.weeknumber=blue
# Command: sync # Command: sync
color.sync.added=green color.sync.added=green

View File

@@ -33,13 +33,13 @@ color.alternate=on gray22
color.header=color15 on gray8 color.header=color15 on gray8
color.footnote=on gray18 color.footnote=on gray18
color.warning=color9 color.warning=color9
color.error=red on white color.error=white on red
color.debug=color7 on color0 color.debug=rgb025
# Task state # Task state
color.completed=rgb353 on rgb000 color.completed=
color.deleted=rgb533 on rgb000 color.deleted=
color.active=rgb420 color.active=rgb510
color.recurring= color.recurring=
color.scheduled=on rgb345 color.scheduled=on rgb345
color.until= color.until=
@@ -53,7 +53,7 @@ color.project.none=
color.pri.H=gray0 color.pri.H=gray0
color.pri.M=gray5 color.pri.M=gray5
color.pri.L=gray10 color.pri.L=gray10
color.pri.none=gray5 color.pri.none=
# Tags # Tags
color.tag.next=rgb420 color.tag.next=rgb420
@@ -66,14 +66,14 @@ color.due.today=on rgb353
color.overdue=on rgb544 color.overdue=on rgb544
# Report: burndown # Report: burndown
color.burndown.pending=on rgb141 color.burndown.pending=on rgb411
color.burndown.started=on rgb440 color.burndown.started=on rgb550
color.burndown.done=on rgb151 color.burndown.done=on rgb151
# Report: history # Report: history
color.history.add=rgb005 on rgb440 color.history.add=color0 on rgb411
color.history.done=rgb020 on rgb343 color.history.done=color0 on rgb151
color.history.delete=rgb300 on rgb533 color.history.delete=color0 on rgb550
# Report: summary # Report: summary
color.summary.bar=on rgb141 color.summary.bar=on rgb141
@@ -82,7 +82,7 @@ color.summary.background=on gray20
# Command: calendar # Command: calendar
color.calendar.due=on rgb343 color.calendar.due=on rgb343
color.calendar.due.today=on rgb353 color.calendar.due.today=on rgb353
color.calendar.holiday=rgb420 color.calendar.holiday=color0 on rgb530
color.calendar.overdue=on rgb533 color.calendar.overdue=on rgb533
color.calendar.today=rgb005 color.calendar.today=rgb005
color.calendar.weekend=on gray21 color.calendar.weekend=on gray21

View File

@@ -83,14 +83,14 @@ color.due.today=color1
color.overdue=color5 color.overdue=color5
# Report: burndown # Report: burndown
color.burndown.done=color0 on color4 color.burndown.done=color0 on color6
color.burndown.pending=color0 on color1 color.burndown.pending=color0 on color1
color.burndown.started=color0 on color9 color.burndown.started=color0 on color3
# Report: history # Report: history
color.history.add=color0 on color1 color.history.add=color0 on color1
color.history.delete=color0 on color3 color.history.delete=color0 on color3
color.history.done=color0 on color10 color.history.done=color0 on color6
# Report: summary # Report: summary
color.summary.background=on color0 color.summary.background=on color0

View File

@@ -46,7 +46,7 @@ rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overd
# General decoration # General decoration
color.label= color.label=
color.label.sort= color.label.sort=
color.alternate=on white #color7 (allows bold for alternate rows) color.alternate=on color7
color.header=color2 color.header=color2
color.footnote=color2 color.footnote=color2
color.warning= color.warning=
@@ -56,20 +56,20 @@ color.debug=color3
# Task state # Task state
color.completed= color.completed=
color.deleted= color.deleted=
color.active=bold red #color9 color.active=color9
color.recurring=color4 color.recurring=color4
color.scheduled= color.scheduled=
color.until= color.until=
color.blocked=on color14 color.blocked=color0 on color14
color.blocking=on color14 color.blocking=color15 on color0
# Project # Project
color.project.none= color.project.none=
# Priority # Priority
color.pri.H=bold black #color0 color.pri.H=bold color0
color.pri.M=bold yellow #color11 color.pri.M=bold color11
color.pri.L=bold cyan #color14 color.pri.L=bold color14
color.pri.none= color.pri.none=
# Tags # Tags
@@ -83,14 +83,14 @@ color.due.today=color1
color.overdue=color5 color.overdue=color5
# Report: burndown # Report: burndown
color.burndown.done=color0 on color4 color.burndown.done=color0 on color6
color.burndown.pending=color0 on color1 color.burndown.pending=color0 on color1
color.burndown.started=color0 on color9 color.burndown.started=color0 on color3
# Report: history # Report: history
color.history.add=color0 on color1 color.history.add=color0 on color1
color.history.delete=color0 on color3 color.history.delete=color0 on color3
color.history.done=color14 on color0 color.history.done=color0 on color6
# Report: summary # Report: summary
color.summary.background=on color7 color.summary.background=on color7

Binary file not shown.

Binary file not shown.

View File

@@ -68,7 +68,13 @@ _task_offer_projects() {
COMPREPLY=( $(compgen -W "$($taskcommand _projects)" -- ${cur/*:/}) ) COMPREPLY=( $(compgen -W "$($taskcommand _projects)" -- ${cur/*:/}) )
} }
_task() _task_offer_contexts() {
COMPREPLY=( $(compgen -W "$($taskcommand _context) define delete list none show" -- $cur) )
}
_task_context_alias=$($taskcommand show | grep alias.*context | cut -d' ' -f1 | cut -d. -f2)
_task()
{ {
local cur prev opts base local cur prev opts base
@@ -91,6 +97,10 @@ _task()
opts="$commands_aliases $($taskcommand _columns)" opts="$commands_aliases $($taskcommand _columns)"
case "${prev}" in case "${prev}" in
$_task_context_alias|cont|conte|contex|context)
_task_offer_contexts
return 0
;;
:) :)
case "${prev2}" in case "${prev2}" in
pri|prior|priori|priorit|priority) pri|prior|priori|priorit|priority)

View File

@@ -374,6 +374,64 @@ void CLI::add (const std::string& arg)
analyze (); analyze ();
} }
////////////////////////////////////////////////////////////////////////////////
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.");
return;
}
// Detect if UUID or ID is set, and bail out
if (_args.size ())
{
std::vector <A>::const_iterator a;
for (a = _args.begin (); a != _args.end (); ++a)
{
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")));
return;
}
}
}
// Apply context
context.debug("Applying context: " + contextName);
std::string contextFilter = context.config.get ("context." + contextName);
if (contextFilter == "")
context.debug("Context '" + contextName + "' not defined!");
else
{
addRawFilter("( " + contextFilter + " )");
if (context.verbose ("context"))
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;
Lexer::Type type;
Lexer lex (arg);
lex.ambiguity (false);
while (lex.token (lexeme, type))
add (lexeme);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Intended to be called after ::initialize() and ::add(), to perform the final // Intended to be called after ::initialize() and ::add(), to perform the final
// analysis. Analysis is also performed directly after the above, because there // analysis. Analysis is also performed directly after the above, because there
@@ -474,8 +532,14 @@ void CLI::applyOverrides ()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Extract all the FILTER-tagged items. // Extract all the FILTER-tagged items.
const std::string CLI::getFilter () const std::string CLI::getFilter (bool applyContext /* = true */)
{ {
// Handle context setting
// Commands that don't want to respect current context should leverage
// the applyContext argument
if (applyContext)
addContextFilter ();
std::string filter = ""; std::string filter = "";
if (_args.size ()) if (_args.size ())
{ {
@@ -500,6 +564,7 @@ const std::string CLI::getFilter ()
filter = "( " + filter + " )"; filter = "( " + filter + " )";
} }
context.debug("Derived filter: '" + filter + "'");
return filter; return filter;
} }

View File

@@ -77,9 +77,11 @@ public:
void entity (const std::string&, const std::string&); void entity (const std::string&, const std::string&);
void initialize (int, const char**); void initialize (int, const char**);
void add (const std::string&); void add (const std::string&);
void addContextFilter ();
void addRawFilter (const std::string& arg);
void analyze (bool parse = true, bool strict = false); void analyze (bool parse = true, bool strict = false);
void applyOverrides (); void applyOverrides ();
const std::string getFilter (); const std::string getFilter (bool applyContext = true);
const std::vector <std::string> getWords (); const std::vector <std::string> getWords ();
bool canonicalize (std::string&, const std::string&, const std::string&) const; bool canonicalize (std::string&, const std::string&, const std::string&) const;
std::string getBinary () const; std::string getBinary () const;

View File

@@ -165,29 +165,29 @@ std::string Config::_defaults =
"\n" "\n"
"# Color controls.\n" "# Color controls.\n"
"color=on # Enable color\n" "color=on # Enable color\n"
#ifdef LINUX #if defined(LINUX) || defined(DARWIN)
"\n" "\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.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.\n"
"\n" "\n"
"# General decoration\n" "# General decoration\n"
"color.label=\n" "color.label=\n"
"color.label.sort=\n" "color.label.sort=\n"
"color.alternate=on gray1\n" "color.alternate=on gray2\n"
"color.header=color3\n" "color.header=color3\n"
"color.footnote=color3\n" "color.footnote=color3\n"
"color.warning=bold red\n" "color.warning=bold red\n"
"color.error=color3\n" "color.error=white on red\n"
"color.debug=color3\n" "color.debug=color4\n"
"\n" "\n"
"# Task state\n" "# Task state\n"
"color.completed=rgb010 on white\n" "color.completed=\n"
"color.deleted=rgb100 on white\n" "color.deleted=\n"
"color.active=rgb555 on rgb410\n" "color.active=rgb555 on rgb410\n"
"color.recurring=rgb013\n" "color.recurring=rgb013\n"
"color.scheduled=on rgb001\n" "color.scheduled=on rgb001\n"
"color.until=\n" "color.until=\n"
"color.blocked=white on color8\n" "color.blocked=white on color8\n"
"color.blocking=white on color15\n" "color.blocking=black on color15\n"
"\n" "\n"
"# Project\n" "# Project\n"
"color.project.none=\n" "color.project.none=\n"
@@ -251,15 +251,15 @@ std::string Config::_defaults =
"color.header=yellow\n" "color.header=yellow\n"
"color.footnote=yellow\n" "color.footnote=yellow\n"
"color.warning=bold red\n" "color.warning=bold red\n"
"color.error=yellow\n" "color.error=white on red\n"
"color.debug=yellow\n" "color.debug=blue\n"
"\n" "\n"
"# Task state\n" "# Task state\n"
"color.completed=green on white\n" "color.completed=\n"
"color.deleted=red on white\n" "color.deleted=\n"
"color.active=black on bright green\n" "color.active=black on bright green\n"
"color.recurring=magenta\n" "color.recurring=magenta\n"
"color.scheduled=on green\n" "color.scheduled=white on green\n"
"color.until=\n" "color.until=\n"
"color.blocked=black on white\n" "color.blocked=black on white\n"
"color.blocking=black on bright white\n" "color.blocking=black on bright white\n"
@@ -368,7 +368,7 @@ std::string Config::_defaults =
"report.list.labels=ID,Active,Age,D,P,Project,Tags,R,Sch,Due,Until,Description,Urg\n" "report.list.labels=ID,Active,Age,D,P,Project,Tags,R,Sch,Due,Until,Description,Urg\n"
"report.list.columns=id,start.age,entry.age,depends.indicator,priority,project,tags,recur.indicator,scheduled.countdown,due,until.remaining,description.count,urgency\n" "report.list.columns=id,start.age,entry.age,depends.indicator,priority,project,tags,recur.indicator,scheduled.countdown,due,until.remaining,description.count,urgency\n"
"report.list.filter=status:pending\n" "report.list.filter=status:pending\n"
"report.list.sort=start-,due+,project+/,urgency-\n" "report.list.sort=start-,due+,project+,urgency-\n"
"\n" "\n"
"report.ls.description=Few details of tasks\n" "report.ls.description=Few details of tasks\n"
"report.ls.labels=ID,A,D,Project,Tags,R,Wait,S,Due,Until,Description\n" "report.ls.labels=ID,A,D,Project,Tags,R,Wait,S,Due,Until,Description\n"
@@ -433,7 +433,7 @@ std::string Config::_defaults =
"report.next.labels=ID,Active,Age,Deps,P,Project,Tag,Recur,S,Due,Until,Description,Urg\n" "report.next.labels=ID,Active,Age,Deps,P,Project,Tag,Recur,S,Due,Until,Description,Urg\n"
"report.next.columns=id,start.age,entry.age,depends,priority,project,tags,recur,scheduled.countdown,due.remaining,until.remaining,description,urgency\n" "report.next.columns=id,start.age,entry.age,depends,priority,project,tags,recur,scheduled.countdown,due.remaining,until.remaining,description,urgency\n"
"report.next.filter=status:pending limit:page\n" "report.next.filter=status:pending limit:page\n"
"report.next.sort=start-,urgency-\n" "report.next.sort=urgency-\n"
"\n" "\n"
"report.ready.description=Most urgent actionable tasks\n" "report.ready.description=Most urgent actionable tasks\n"
"report.ready.labels=ID,Active,Age,D,P,Project,Tags,R,S,Due,Until,Description,Urg\n" "report.ready.labels=ID,Active,Age,D,P,Project,Tags,R,S,Due,Until,Description,Urg\n"

View File

@@ -275,7 +275,7 @@ int Context::initialize (int argc, const char** argv)
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// //
// [8] Run on.launch hooks. // [8] Initialize hooks.
// //
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////

View File

@@ -313,7 +313,7 @@ bool DOM::get (const std::string& name, const Task& task, Variant& value)
Column* column = context.columns[canonical]; Column* column = context.columns[canonical];
if (column) if (column)
{ {
if (column->is_uda () && ! task.has (canonical)) if (column->is_uda () && ! ref.has (canonical))
{ {
value = Variant ("''"); value = Variant ("''");
return true; return true;

View File

@@ -61,31 +61,48 @@ static struct
{"fortnight", 14 * DAY, true}, {"fortnight", 14 * DAY, true},
{"hours", 1 * HOUR, false}, {"hours", 1 * HOUR, false},
{"hour", 1 * HOUR, true}, {"hour", 1 * HOUR, true},
{"hrs", 1 * HOUR, true},
{"hr", 1 * HOUR, true},
{"h", 1 * HOUR, false}, {"h", 1 * HOUR, false},
{"minutes", 1 * MINUTE, false}, {"minutes", 1 * MINUTE, false},
{"minute", 1 * MINUTE, false}, {"minute", 1 * MINUTE, false},
{"mins", 1 * MINUTE, false},
{"min", 1 * MINUTE, false}, {"min", 1 * MINUTE, false},
{"monthly", 30 * DAY, true}, {"monthly", 30 * DAY, true},
{"months", 30 * DAY, false}, {"months", 30 * DAY, false},
{"month", 30 * DAY, true}, {"month", 30 * DAY, true},
{"mnths", 30 * DAY, false},
{"mths", 30 * DAY, false},
{"mth", 30 * DAY, false},
{"mos", 30 * DAY, false},
{"mo", 30 * DAY, false}, {"mo", 30 * DAY, false},
{"m", 30 * DAY, false},
{"quarterly", 91 * DAY, true}, {"quarterly", 91 * DAY, true},
{"quarters", 91 * DAY, false}, {"quarters", 91 * DAY, false},
{"quarter", 91 * DAY, true}, {"quarter", 91 * DAY, true},
{"qrtrs", 91 * DAY, false},
{"qtrs", 91 * DAY, false},
{"qtr", 91 * DAY, false},
{"q", 91 * DAY, false}, {"q", 91 * DAY, false},
{"semiannual", 183 * DAY, true}, {"semiannual", 183 * DAY, true},
{"sennight", 14 * DAY, false}, {"sennight", 14 * DAY, false},
{"seconds", 1 * SECOND, false}, {"seconds", 1 * SECOND, false},
{"second", 1 * SECOND, true}, {"second", 1 * SECOND, true},
{"secs", 1 * SECOND, true},
{"sec", 1 * SECOND, true},
{"s", 1 * SECOND, false}, {"s", 1 * SECOND, false},
{"weekdays", 1 * DAY, true}, {"weekdays", 1 * DAY, true},
{"weekly", 7 * DAY, true}, {"weekly", 7 * DAY, true},
{"weeks", 7 * DAY, false}, {"weeks", 7 * DAY, false},
{"week", 7 * DAY, true}, {"week", 7 * DAY, true},
{"wks", 7 * DAY, true},
{"wk", 7 * DAY, true},
{"w", 7 * DAY, false}, {"w", 7 * DAY, false},
{"yearly", 365 * DAY, true}, {"yearly", 365 * DAY, true},
{"years", 365 * DAY, false}, {"years", 365 * DAY, false},
{"year", 365 * DAY, true}, {"year", 365 * DAY, true},
{"yrs", 365 * DAY, true},
{"yr", 365 * DAY, true},
{"y", 365 * DAY, false}, {"y", 365 * DAY, false},
}; };

View File

@@ -67,7 +67,7 @@ Filter::~Filter ()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Take an input set of tasks and filter into a subset. // Take an input set of tasks and filter into a subset.
void Filter::subset (const std::vector <Task>& input, std::vector <Task>& output) void Filter::subset (const std::vector <Task>& input, std::vector <Task>& output, bool applyContext /* = true */)
{ {
context.timer_filter.start (); context.timer_filter.start ();
_startCount = (int) input.size (); _startCount = (int) input.size ();
@@ -75,7 +75,7 @@ void Filter::subset (const std::vector <Task>& input, std::vector <Task>& output
if (context.config.getInteger ("debug.parser") >= 1) if (context.config.getInteger ("debug.parser") >= 1)
context.debug (context.cli.dump ("Filter::subset")); context.debug (context.cli.dump ("Filter::subset"));
std::string filterExpr = context.cli.getFilter (); std::string filterExpr = context.cli.getFilter (applyContext);
if (filterExpr.length ()) if (filterExpr.length ())
{ {
Eval eval; Eval eval;
@@ -111,7 +111,7 @@ void Filter::subset (const std::vector <Task>& input, std::vector <Task>& output
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Take the set of all tasks and filter into a subset. // Take the set of all tasks and filter into a subset.
void Filter::subset (std::vector <Task>& output) void Filter::subset (std::vector <Task>& output, bool applyContext /* = true */)
{ {
context.timer_filter.start (); context.timer_filter.start ();
@@ -119,7 +119,7 @@ void Filter::subset (std::vector <Task>& output)
context.debug (context.cli.dump ("Filter::subset")); context.debug (context.cli.dump ("Filter::subset"));
bool shortcut = false; bool shortcut = false;
std::string filterExpr = context.cli.getFilter (); std::string filterExpr = context.cli.getFilter (applyContext);
if (filterExpr.length ()) if (filterExpr.length ())
{ {
context.timer_filter.stop (); context.timer_filter.stop ();

View File

@@ -40,8 +40,8 @@ public:
Filter (); Filter ();
~Filter (); ~Filter ();
void subset (const std::vector <Task>&, std::vector <Task>&); void subset (const std::vector <Task>&, std::vector <Task>&, bool applyContext = true);
void subset (std::vector <Task>&); void subset (std::vector <Task>&, bool applyContext = true);
bool pendingOnly (); bool pendingOnly ();
void safety (); void safety ();

View File

@@ -141,7 +141,7 @@ void Hooks::onLaunch ()
{ {
std::vector <std::string>::iterator message; std::vector <std::string>::iterator message;
for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message) for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message)
context.debug (*message); context.footnote (*message);
} }
else else
{ {
@@ -208,7 +208,7 @@ void Hooks::onExit ()
{ {
std::vector <std::string>::iterator message; std::vector <std::string>::iterator message;
for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message) for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message)
context.debug (*message); context.footnote (*message);
} }
else else
{ {
@@ -274,7 +274,7 @@ void Hooks::onAdd (Task& task)
std::vector <std::string>::iterator message; std::vector <std::string>::iterator message;
for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message) for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message)
context.debug (*message); context.footnote (*message);
} }
else else
{ {
@@ -345,7 +345,7 @@ void Hooks::onModify (const Task& before, Task& after)
std::vector <std::string>::iterator message; std::vector <std::string>::iterator message;
for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message) for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message)
context.debug (*message); context.footnote (*message);
} }
else else
{ {
@@ -358,6 +358,8 @@ void Hooks::onModify (const Task& before, Task& after)
throw 0; // This is how hooks silently terminate processing. throw 0; // This is how hooks silently terminate processing.
} }
} }
after = Task (input[1]);
} }
context.timer_hooks.stop (); context.timer_hooks.stop ();

View File

@@ -387,6 +387,12 @@ bool Lexer::token (std::string& result, Type& type)
result += utf8_character (_n0); result += utf8_character (_n0);
shift (); shift ();
} }
else
{
result += utf8_character (hex_to_int (_n0, _n1, _n2, _n3));
shift ();
type = quote ? typeString : typeIdentifier;
}
break; break;
case typeExponent: case typeExponent:

View File

@@ -403,33 +403,6 @@ bool Nibbler::getInt (int& result)
return false; return false;
} }
////////////////////////////////////////////////////////////////////////////////
bool Nibbler::getHex (int& result)
{
std::string::size_type i = _cursor;
if (i < _length)
{
if (_input[i] == '-')
++i;
else if (_input[i] == '+')
++i;
}
// TODO Potential for use of find_first_not_of
while (i < _length && isxdigit (_input[i]))
++i;
if (i > _cursor)
{
result = strtoimax (_input.substr (_cursor, i - _cursor).c_str (), NULL, 16);
_cursor = i;
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool Nibbler::getUnsignedInt (int& result) bool Nibbler::getUnsignedInt (int& result)
{ {

View File

@@ -68,7 +68,6 @@ public:
bool getDigit3 (int&); bool getDigit3 (int&);
bool getDigit2 (int&); bool getDigit2 (int&);
bool getInt (int&); bool getInt (int&);
bool getHex (int&);
bool getUnsignedInt (int&); bool getUnsignedInt (int&);
bool getNumber (std::string&); bool getNumber (std::string&);
bool getNumber (double&); bool getNumber (double&);

View File

@@ -572,7 +572,7 @@ void TDB2::add (Task& task, bool add_to_backlog /* = true */)
if (add_to_backlog) if (add_to_backlog)
context.hooks.onAdd (task); context.hooks.onAdd (task);
update (uuid, task, add_to_backlog); update (uuid, task, add_to_backlog, true);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -580,7 +580,6 @@ 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, and provide defaults if necessary.
task.validate (false); task.validate (false);
task.upgradeLegacyValues ();
std::string uuid = task.get ("uuid"); std::string uuid = task.get ("uuid");
// Get the unmodified task as reference, so the hook can compare. // Get the unmodified task as reference, so the hook can compare.
@@ -598,14 +597,15 @@ void TDB2::modify (Task& task, bool add_to_backlog /* = true */)
void TDB2::update ( void TDB2::update (
const std::string& uuid, const std::string& uuid,
Task& task, Task& task,
const bool add_to_backlog) const bool add_to_backlog,
const bool addition)
{ {
// Validate to add metadata. // Validate to add metadata.
task.validate (false); task.validate (false);
// If the task already exists, it is a modification, else addition. // If the task already exists, it is a modification, else addition.
Task original; Task original;
if (get (task.get ("uuid"), original)) if (not addition && get (task.get ("uuid"), original))
{ {
// Update the task, wherever it is. // Update the task, wherever it is.
if (!pending.modify_task (task)) if (!pending.modify_task (task))
@@ -1179,18 +1179,21 @@ int TDB2::gc ()
// Allowed as an override, but not recommended. // Allowed as an override, but not recommended.
if (context.config.getBoolean ("gc")) if (context.config.getBoolean ("gc"))
{ {
std::vector <Task> pending_tasks = pending.get_tasks (); std::vector <Task> pending_tasks = pending.get_tasks ();
// TODO Thread.
std::vector <Task> completed_tasks = completed.get_tasks (); std::vector <Task> completed_tasks = completed.get_tasks ();
// TODO Assume pending < completed, therefore there is room here to process
// data before joining with the completed.data thread.
bool pending_changes = false; bool pending_changes = false;
bool completed_changes = false; bool completed_changes = false;
std::vector <Task> pending_tasks_after; std::vector <Task> pending_tasks_after;
std::vector <Task> completed_tasks_after; std::vector <Task> completed_tasks_after;
// Reduce unnecessary allocation/copies. // Reduce unnecessary allocation/copies.
pending_tasks_after.reserve (pending_tasks.size ()); pending_tasks_after.reserve (pending_tasks.size ());
completed_tasks_after.reserve (completed_tasks.size ());
// Scan all pending tasks, looking for any that need to be relocated to // Scan all pending tasks, looking for any that need to be relocated to
// completed, or need to be 'woken'. // completed, or need to be 'woken'.
@@ -1227,6 +1230,11 @@ int TDB2::gc ()
} }
} }
// TODO Join completed.data thread.
// Reduce unnecessary allocation/copies.
completed_tasks_after.reserve (completed_tasks.size ());
// Scan all completed tasks, looking for any that need to be relocated to // Scan all completed tasks, looking for any that need to be relocated to
// pending. // pending.
for (task = completed_tasks.begin (); for (task = completed_tasks.begin ();

View File

@@ -128,7 +128,7 @@ public:
private: private:
void gather_changes (); void gather_changes ();
void update (const std::string&, Task&, const bool); void update (const std::string&, Task&, const bool, const bool addition = false);
bool verifyUniqueUUID (const std::string&); bool verifyUniqueUUID (const std::string&);
void show_diff (const std::string&, const std::string&, const std::string&); void show_diff (const std::string&, const std::string&, const std::string&);
void revert_undo (std::vector <std::string>&, std::string&, std::string&, std::string&, std::string&); void revert_undo (std::vector <std::string>&, std::string&, std::string&, std::string&, std::string&);

View File

@@ -565,7 +565,6 @@ void Task::parse (const std::string& input)
nl.getQuoted ('"', value)) nl.getQuoted ('"', value))
{ {
legacyAttributeMap (name); legacyAttributeMap (name);
legacyValueMap (name, value);
if (name.substr (0, 11) == "annotation_") if (name.substr (0, 11) == "annotation_")
++annotation_count; ++annotation_count;
@@ -586,8 +585,6 @@ void Task::parse (const std::string& input)
parseJSON (copy); parseJSON (copy);
else else
throw std::string (STRING_RECORD_NOT_FF4); throw std::string (STRING_RECORD_NOT_FF4);
upgradeLegacyValues ();
} }
catch (const std::string&) catch (const std::string&)
@@ -719,8 +716,6 @@ void Task::parseJSON (const std::string& line)
} }
} }
} }
upgradeLegacyValues ();
} }
} }
@@ -1105,6 +1100,7 @@ int Task::getTagCount () const
bool Task::hasTag (const std::string& tag) const bool Task::hasTag (const std::string& tag) const
{ {
// Synthetic tags - dynamically generated, but do not occupy storage space. // Synthetic tags - dynamically generated, but do not occupy storage space.
// Note: This list must match that in CmdInfo::execute.
if (tag == "BLOCKED") return is_blocked; if (tag == "BLOCKED") return is_blocked;
if (tag == "UNBLOCKED") return !is_blocked; if (tag == "UNBLOCKED") return !is_blocked;
if (tag == "BLOCKING") return is_blocking; if (tag == "BLOCKING") return is_blocking;
@@ -2218,78 +2214,3 @@ void Task::modify (modType type, bool text_required /* = false */)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Task::upgradeLegacyValues ()
{
// 2.4.0 Update recurrence values.
if (has ("recur"))
{
std::string value = get ("recur");
if (value != "")
{
std::string new_value = value;
upgradeLegacyValue (new_value);
if (new_value != value)
{
set ("recur", new_value);
context.debug (format ("Legacy upgrade: recur {1} --> {2}", value, new_value));
}
}
}
// 2.4.0 Update UDA duration values.
Config::const_iterator name;
for (name = context.config.begin (); name != context.config.end (); ++name)
{
if (name->first.substr (0, 4) == "uda." &&
name->first.find (".type") != std::string::npos)
{
if (name->second == "duration")
{
std::string::size_type period = name->first.find ('.', 4);
if (period != std::string::npos)
{
std::string uda = name->first.substr (4, period - 4);
std::string value = get (uda);
std::string new_value = value;
upgradeLegacyValue (new_value);
if (new_value != value)
{
set ("recur", new_value);
context.debug (format ("Legacy upgrade: UDA {1}, {2} --> {3}", uda, value, new_value));
}
}
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
void Task::upgradeLegacyValue (std::string& value)
{
std::string::size_type len = value.length ();
std::string::size_type p;
if (value == "-") value = "0s";
else if ((p = value.find ("hr")) != std::string::npos && p == len - 2) value = value.substr (0, p) + "h";
else if ((p = value.find ("hrs")) != std::string::npos && p == len - 3) value = value.substr (0, p) + "h";
else if ((p = value.find ("mins")) != std::string::npos && p == len - 4) value = value.substr (0, p) + "min";
else if ((p = value.find ("mnths")) != std::string::npos && p == len - 5) value = value.substr (0, p) + "mo";
else if ((p = value.find ("mos")) != std::string::npos && p == len - 3) value = value.substr (0, p) + "mo";
else if ((p = value.find ("mth")) != std::string::npos && p == len - 3) value = value.substr (0, p) + "mo";
else if ((p = value.find ("mths")) != std::string::npos && p == len - 4) value = value.substr (0, p) + "mo";
else if ((p = value.find ("qrtrs")) != std::string::npos && p == len - 5) value = value.substr (0, p) + "q";
else if ((p = value.find ("qtr")) != std::string::npos && p == len - 3) value = value.substr (0, p) + "q";
else if ((p = value.find ("qtrs")) != std::string::npos && p == len - 4) value = value.substr (0, p) + "q";
else if ((p = value.find ("sec")) != std::string::npos && p == len - 3) value = value.substr (0, p) + "s";
else if ((p = value.find ("secs")) != std::string::npos && p == len - 4) value = value.substr (0, p) + "s";
else if ((p = value.find ("wk")) != std::string::npos && p == len - 2) value = value.substr (0, p) + "w";
else if ((p = value.find ("wks")) != std::string::npos && p == len - 3) value = value.substr (0, p) + "w";
else if ((p = value.find ("yr")) != std::string::npos && p == len - 2) value = value.substr (0, p) + "y";
else if ((p = value.find ("yrs")) != std::string::npos && p == len - 3) value = value.substr (0, p) + "y";
// It is not an error to have a non-legacy value.
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -154,7 +154,6 @@ public:
enum modType {modReplace, modPrepend, modAppend, modAnnotate}; enum modType {modReplace, modPrepend, modAppend, modAnnotate};
void modify (modType, bool text_required = false); void modify (modType, bool text_required = false);
void upgradeLegacyValues ();
private: private:
int determineVersion (const std::string&); int determineVersion (const std::string&);
@@ -163,7 +162,6 @@ private:
void validate_before (const std::string&, const std::string&); void validate_before (const std::string&, const std::string&);
const std::string encode (const std::string&) const; const std::string encode (const std::string&) const;
const std::string decode (const std::string&) const; const std::string decode (const std::string&) const;
void upgradeLegacyValue (std::string&);
public: public:
float urgency_priority () const; float urgency_priority () const;

View File

@@ -207,8 +207,6 @@ void ColumnDate::render (
color.colorize ( color.colorize (
rightJustify ( rightJustify (
Duration (date - now).format (), width))); Duration (date - now).format (), width)));
else
lines.push_back (rightJustify ("", width));
} }
} }
} }

View File

@@ -62,11 +62,16 @@ bool ColumnIMask::validate (std::string& value)
// Set the minimum and maximum widths for the value. // Set the minimum and maximum widths for the value.
void ColumnIMask::measure (Task& task, unsigned int& minimum, unsigned int& maximum) void ColumnIMask::measure (Task& task, unsigned int& minimum, unsigned int& maximum)
{ {
minimum = maximum = task.get ("imask").length (); minimum = maximum = 0;
if (_style != "default" && if (task.has (_name))
_style != "number") {
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style); minimum = maximum = task.get ("imask").length ();
if (_style != "default" &&
_style != "number")
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -76,7 +81,8 @@ void ColumnIMask::render (
int width, int width,
Color& color) Color& color)
{ {
lines.push_back (color.colorize (rightJustify (task.get ("imask"), width))); if (task.has (_name))
lines.push_back (color.colorize (rightJustify (task.get ("imask"), width)));
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@@ -62,10 +62,14 @@ bool ColumnMask::validate (std::string& value)
// Set the minimum and maximum widths for the value. // Set the minimum and maximum widths for the value.
void ColumnMask::measure (Task& task, unsigned int& minimum, unsigned int& maximum) void ColumnMask::measure (Task& task, unsigned int& minimum, unsigned int& maximum)
{ {
minimum = maximum = task.get ("mask").length (); minimum = maximum = 0;
if (task.has (_name))
{
minimum = maximum = task.get ("mask").length ();
if (_style != "default") if (_style != "default")
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style); throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -75,7 +79,8 @@ void ColumnMask::render (
int width, int width,
Color& color) Color& color)
{ {
lines.push_back (color.colorize (task.get ("mask"))); if (task.has (_name))
lines.push_back (color.colorize (task.get ("mask")));
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@@ -62,12 +62,17 @@ bool ColumnParent::validate (std::string& value)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Set the minimum and maximum widths for the value. // Set the minimum and maximum widths for the value.
void ColumnParent::measure (Task&, unsigned int& minimum, unsigned int& maximum) void ColumnParent::measure (Task& task, unsigned int& minimum, unsigned int& maximum)
{ {
if (_style == "default" || _style == "long") minimum = maximum = 36; minimum = maximum = 0;
else if (_style == "short") minimum = maximum = 8;
else if (task.has (_name))
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style); {
if (_style == "default" || _style == "long") minimum = maximum = 36;
else if (_style == "short") minimum = maximum = 8;
else
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -77,20 +82,23 @@ void ColumnParent::render (
int width, int width,
Color& color) Color& color)
{ {
// f30cb9c3-3fc0-483f-bfb2-3bf134f00694 default if (task.has (_name))
// 34f00694 short
if (_style == "default" ||
_style == "long")
{ {
lines.push_back (color.colorize (leftJustify (task.get (_name), width))); // f30cb9c3-3fc0-483f-bfb2-3bf134f00694 default
} // 34f00694 short
if (_style == "default" ||
_style == "long")
{
lines.push_back (color.colorize (leftJustify (task.get (_name), width)));
}
else if (_style == "short") else if (_style == "short")
{ {
if (task.has (_name)) if (task.has (_name))
lines.push_back (color.colorize (leftJustify (task.get (_name).substr (28), width))); lines.push_back (color.colorize (leftJustify (task.get (_name).substr (28), width)));
else else
lines.push_back (color.colorize (leftJustify ("", width))); lines.push_back (color.colorize (leftJustify ("", width)));
}
} }
} }

View File

@@ -53,17 +53,14 @@ ColumnPriority::~ColumnPriority ()
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Allow lower case, but implicitly convert.
bool ColumnPriority::validate (std::string& value) bool ColumnPriority::validate (std::string& value)
{ {
value = upperCase (value); if (value == "h") { value = "H"; return true; }
else if (value == "m") { value = "M"; return true; }
else if (value == "l") { value = "L"; return true; }
if (value == "H" || return value == "H" || value == "M" || value == "L" || value == "";
value == "M" ||
value == "L" ||
value == "")
return true;
return false;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -81,22 +78,26 @@ void ColumnPriority::setStyle (const std::string& value)
// Set the minimum and maximum widths for the value. // Set the minimum and maximum widths for the value.
void ColumnPriority::measure (Task& task, unsigned int& minimum, unsigned int& maximum) void ColumnPriority::measure (Task& task, unsigned int& minimum, unsigned int& maximum)
{ {
std::string priority = task.get (_name); minimum = maximum = 0;
if (task.has (_name))
if (priority == "")
minimum = maximum = 0;
else
minimum = maximum = 1;
if (_style == "long")
{ {
if (priority == "H") minimum = maximum = 4; std::string priority = task.get (_name);
else if (priority == "M") minimum = maximum = 6;
else if (priority == "L") minimum = maximum = 3; 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);
} }
else if (_style != "default" &&
_style != "short")
throw format (STRING_COLUMN_BAD_FORMAT, "priority", _style);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -106,21 +107,28 @@ void ColumnPriority::render (
int width, int width,
Color& color) Color& color)
{ {
std::string priority = task.get (_name); if (task.has (_name))
if (_style == "long")
{ {
if (priority == "H") priority = "High"; std::string priority = task.get (_name);
else if (priority == "M") priority = "Medium"; if (_style == "long")
else if (priority == "L") priority = "Low"; {
} 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))); lines.push_back (color.colorize (leftJustify (priority, width)));
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::string ColumnPriority::modify (std::string& value) std::string ColumnPriority::modify (std::string& value)
{ {
return upperCase (value); if (value == "h") value = "H";
else if (value == "m") value = "M";
else if (value == "l") value = "L";
return value;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@@ -68,25 +68,30 @@ bool ColumnProject::validate (std::string& value)
// Set the minimum and maximum widths for the value. // Set the minimum and maximum widths for the value.
void ColumnProject::measure (Task& task, unsigned int& minimum, unsigned int& maximum) void ColumnProject::measure (Task& task, unsigned int& minimum, unsigned int& maximum)
{ {
std::string project = task.get (_name); minimum = maximum = 0;
if (_style == "parent") if (task.has (_name))
{ {
std::string::size_type period = project.find ('.'); std::string project = task.get (_name);
if (period != std::string::npos)
project = project.substr (0, period);
}
else if (_style == "indented")
{
project = indentProject (project, " ", '.');
}
else if (_style != "default" &&
_style != "full" &&
_style != "indented")
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
minimum = longestWord (project); if (_style == "parent")
maximum = utf8_width (project); {
std::string::size_type period = project.find ('.');
if (period != std::string::npos)
project = project.substr (0, period);
}
else if (_style == "indented")
{
project = indentProject (project, " ", '.');
}
else if (_style != "default" &&
_style != "full" &&
_style != "indented")
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
minimum = longestWord (project);
maximum = utf8_width (project);
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -96,24 +101,27 @@ void ColumnProject::render (
int width, int width,
Color& color) Color& color)
{ {
std::string project = task.get (_name); if (task.has (_name))
if (_style == "parent")
{ {
std::string::size_type period = project.find ('.'); std::string project = task.get (_name);
if (period != std::string::npos) if (_style == "parent")
project = project.substr (0, period); {
} std::string::size_type period = project.find ('.');
else if (_style == "indented") if (period != std::string::npos)
{ project = project.substr (0, period);
project = indentProject (project, " ", '.'); }
} else if (_style == "indented")
{
project = indentProject (project, " ", '.');
}
std::vector <std::string> raw; std::vector <std::string> raw;
wrapText (raw, project, width, _hyphenate); wrapText (raw, project, width, _hyphenate);
std::vector <std::string>::iterator i; std::vector <std::string>::iterator i;
for (i = raw.begin (); i != raw.end (); ++i) for (i = raw.begin (); i != raw.end (); ++i)
lines.push_back (color.colorize (leftJustify (*i, width))); lines.push_back (color.colorize (leftJustify (*i, width)));
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@@ -79,18 +79,23 @@ void ColumnRecur::setStyle (const std::string& value)
// Set the minimum and maximum widths for the value. // Set the minimum and maximum widths for the value.
void ColumnRecur::measure (Task& task, unsigned int& minimum, unsigned int& maximum) void ColumnRecur::measure (Task& task, unsigned int& minimum, unsigned int& maximum)
{ {
if (_style == "default" || minimum = maximum = 0;
_style == "duration")
if (task.has (_name))
{ {
minimum = maximum = Duration (task.get ("recur")).formatISO ().length (); if (_style == "default" ||
_style == "duration")
{
minimum = maximum = Duration (task.get ("recur")).formatISO ().length ();
}
else if (_style == "indicator")
{
if (task.has (_name))
minimum = maximum = utf8_width (context.config.get ("recurrence.indicator"));
}
else
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
} }
else if (_style == "indicator")
{
if (task.has (_name))
minimum = maximum = utf8_width (context.config.get ("recurrence.indicator"));
}
else
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -108,8 +113,7 @@ void ColumnRecur::render (
lines.push_back ( lines.push_back (
color.colorize ( color.colorize (
rightJustify ( rightJustify (
Duration (task.get ("recur")).formatISO (), Duration (task.get ("recur")).formatISO (), width)));
width)));
} }
else if (_style == "indicator") else if (_style == "indicator")
{ {

View File

@@ -71,6 +71,8 @@ void ColumnString::setReport (const std::string& value)
// //
void ColumnString::measure (const std::string& value, unsigned int& minimum, unsigned int& maximum) void ColumnString::measure (const std::string& value, unsigned int& minimum, unsigned int& maximum)
{ {
minimum = maximum = 0;
if (_style == "left" || if (_style == "left" ||
_style == "right" || _style == "right" ||
_style == "default") _style == "default")

View File

@@ -84,30 +84,34 @@ void ColumnTags::setStyle (const std::string& value)
// Set the minimum and maximum widths for the value. // Set the minimum and maximum widths for the value.
void ColumnTags::measure (Task& task, unsigned int& minimum, unsigned int& maximum) void ColumnTags::measure (Task& task, unsigned int& minimum, unsigned int& maximum)
{ {
if (_style == "indicator") minimum = maximum = utf8_width (context.config.get ("tag.indicator")); minimum = maximum = 0;
else if (_style == "count") minimum = maximum = 3;
else if (_style == "default" ||
_style == "list")
{
std::string tags = task.get (_name);
minimum = 0;
maximum = utf8_width (tags);
if (maximum) if (task.has (_name))
{
if (_style == "indicator") minimum = maximum = utf8_width (context.config.get ("tag.indicator"));
else if (_style == "count") minimum = maximum = 3;
else if (_style == "default" ||
_style == "list")
{ {
std::vector <std::string> all; std::string tags = task.get (_name);
split (all, tags, ','); maximum = utf8_width (tags);
std::vector <std::string>::iterator i;
for (i = all.begin (); i != all.end (); ++i) if (maximum)
{ {
unsigned int length = utf8_width (*i); std::vector <std::string> all;
if (length > minimum) split (all, tags, ',');
minimum = length; std::vector <std::string>::iterator i;
for (i = all.begin (); i != all.end (); ++i)
{
unsigned int length = utf8_width (*i);
if (length > minimum)
minimum = length;
}
} }
} }
else
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
} }
else
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -117,9 +121,9 @@ void ColumnTags::render (
int width, int width,
Color& color) Color& color)
{ {
std::string tags = task.get (_name); if (task.has (_name))
if (tags != "")
{ {
std::string tags = task.get (_name);
if (_style == "default" || if (_style == "default" ||
_style == "list") _style == "list")
{ {

View File

@@ -80,49 +80,52 @@ void ColumnUDA::measure (Task& task, unsigned int& minimum, unsigned int& maximu
{ {
minimum = maximum = 0; minimum = maximum = 0;
if (_style == "default") if (task.has (_name))
{ {
std::string value = task.get (_name); if (_style == "default")
if (value != "")
{ {
if (_type == "date") std::string value = task.get (_name);
if (value != "")
{ {
// Determine the output date format, which uses a hierarchy of definitions. if (_type == "date")
// rc.report.<report>.dateformat {
// rc.dateformat.report // Determine the output date format, which uses a hierarchy of definitions.
// rc.dateformat // rc.report.<report>.dateformat
Date date ((time_t) strtol (value.c_str (), NULL, 10)); // rc.dateformat.report
std::string format = context.config.get ("report." + _report + ".dateformat"); // rc.dateformat
if (format == "") Date date ((time_t) strtol (value.c_str (), NULL, 10));
format = context.config.get ("dateformat.report"); std::string format = context.config.get ("report." + _report + ".dateformat");
if (format == "") if (format == "")
format = context.config.get ("dateformat"); format = context.config.get ("dateformat.report");
if (format == "")
format = context.config.get ("dateformat");
minimum = maximum = Date::length (format); minimum = maximum = Date::length (format);
} }
else if (_type == "duration") else if (_type == "duration")
{ {
minimum = maximum = utf8_width (Duration (value).formatISO ()); minimum = maximum = utf8_width (Duration (value).formatISO ());
} }
else if (_type == "string") else if (_type == "string")
{ {
std::string stripped = Color::strip (value); std::string stripped = Color::strip (value);
maximum = longestLine (stripped); maximum = longestLine (stripped);
minimum = longestWord (stripped); minimum = longestWord (stripped);
} }
else if (_type == "numeric") else if (_type == "numeric")
{ {
minimum = maximum = utf8_width (value); minimum = maximum = utf8_width (value);
}
} }
} }
else if (_style == "indicator")
{
if (task.has (_name))
minimum = maximum = utf8_width (context.config.get ("uda." + _name + ".indicator"));
}
else
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
} }
else if (_style == "indicator")
{
if (task.has (_name))
minimum = maximum = utf8_width (context.config.get ("uda." + _name + ".indicator"));
}
else
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -132,11 +135,11 @@ void ColumnUDA::render (
int width, int width,
Color& color) Color& color)
{ {
if (_style == "default") if (task.has (_name))
{ {
std::string value = task.get (_name); if (_style == "default")
if (value != "")
{ {
std::string value = task.get (_name);
if (_type == "date") if (_type == "date")
{ {
// Determine the output date format, which uses a hierarchy of definitions. // Determine the output date format, which uses a hierarchy of definitions.
@@ -177,13 +180,13 @@ void ColumnUDA::render (
lines.push_back (color.colorize (rightJustify (value, width))); lines.push_back (color.colorize (rightJustify (value, width)));
} }
} }
} else if (_style == "indicator")
else if (_style == "indicator") {
{ if (task.has (_name))
if (task.has (_name)) lines.push_back (
lines.push_back ( color.colorize (
color.colorize ( rightJustify (context.config.get ("uda." + _name + ".indicator"), width)));
rightJustify (context.config.get ("uda." + _name + ".indicator"), width))); }
} }
} }

View File

@@ -18,6 +18,7 @@ set (commands_SRCS Command.cpp Command.h
CmdColor.cpp CmdColor.h CmdColor.cpp CmdColor.h
CmdColumns.cpp CmdColumns.h CmdColumns.cpp CmdColumns.h
CmdConfig.cpp CmdConfig.h CmdConfig.cpp CmdConfig.h
CmdContext.cpp CmdContext.h
CmdCount.cpp CmdCount.h CmdCount.cpp CmdCount.h
CmdCustom.cpp CmdCustom.h CmdCustom.cpp CmdCustom.h
CmdDelete.cpp CmdDelete.h CmdDelete.cpp CmdDelete.h

View File

@@ -46,6 +46,107 @@ CmdConfig::CmdConfig ()
_displays_id = false; _displays_id = false;
} }
////////////////////////////////////////////////////////////////////////////////
bool CmdConfig::setConfigVariable (std::string name, std::string value, bool confirmation /* = false */)
{
// Read .taskrc (or equivalent)
std::vector <std::string> contents;
File::read (context.config._original_file, contents);
bool found = false;
bool change = false;
std::vector <std::string>::iterator line;
for (line = contents.begin (); line != contents.end (); ++line)
{
// If there is a comment on the line, it must follow the pattern.
std::string::size_type comment = line->find ("#");
std::string::size_type pos = line->find (name + "=");
if (pos != std::string::npos &&
(comment == std::string::npos ||
comment > pos))
{
found = true;
if (!confirmation ||
confirm (format (STRING_CMD_CONFIG_CONFIRM, name, context.config.get (name), value)))
{
if (comment != std::string::npos)
*line = name + "=" + json::encode (value) + " " + line->substr (comment);
else
*line = name + "=" + json::encode (value);
change = true;
}
}
}
// Not found, so append instead.
if (!found &&
(!confirmation ||
confirm (format (STRING_CMD_CONFIG_CONFIRM2, name, value))))
{
contents.push_back (name + "=" + json::encode (value));
change = true;
}
if (change)
File::write (context.config._original_file, contents);
return change;
}
////////////////////////////////////////////////////////////////////////////////
int CmdConfig::unsetConfigVariable (std::string name, bool confirmation /* = false */)
{
// Read .taskrc (or equivalent)
std::vector <std::string> contents;
File::read (context.config._original_file, contents);
bool found = false;
bool change = false;
std::vector <std::string>::iterator line;
for (line = contents.begin (); line != contents.end (); )
{
bool lineDeleted = false;
// If there is a comment on the line, it must follow the pattern.
std::string::size_type comment = line->find ("#");
std::string::size_type pos = line->find (name + "=");
if (pos != std::string::npos &&
(comment == std::string::npos ||
comment > pos))
{
found = true;
// Remove name
if (!confirmation ||
confirm (format (STRING_CMD_CONFIG_CONFIRM3, name)))
{
// vector::erase method returns a valid iterator to the next object
line = contents.erase (line);
lineDeleted = true;
change = true;
}
}
if (! lineDeleted)
line++;
}
if (change)
File::write (context.config._original_file, contents);
if ( change && found )
return 0;
else if ( found )
return 1;
else
return 2;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int CmdConfig::execute (std::string& output) int CmdConfig::execute (std::string& output)
{ {
@@ -62,10 +163,13 @@ int CmdConfig::execute (std::string& output)
if (words.size ()) if (words.size ())
{ {
bool confirmation = context.config.getBoolean ("confirmation"); bool confirmation = context.config.getBoolean ("confirmation");
bool change = false;
bool found = false;
std::string name = words[0]; std::string name = words[0];
std::string value = ""; std::string value = "";
// Join the remaining words into config variable's value
if (words.size () > 1) if (words.size () > 1)
{ {
for (unsigned int i = 1; i < words.size (); ++i) for (unsigned int i = 1; i < words.size (); ++i)
@@ -81,85 +185,30 @@ int CmdConfig::execute (std::string& output)
{ {
bool change = false; bool change = false;
// Read .taskrc (or equivalent)
std::vector <std::string> contents;
File::read (context.config._original_file, contents);
// task config name value // task config name value
// task config name "" // task config name ""
if (words.size () > 1) if (words.size () > 1)
{ change = setConfigVariable(name, value, confirmation);
bool found = false;
std::vector <std::string>::iterator line;
for (line = contents.begin (); line != contents.end (); ++line)
{
// If there is a comment on the line, it must follow the pattern.
std::string::size_type comment = line->find ("#");
std::string::size_type pos = line->find (name + "=");
if (pos != std::string::npos &&
(comment == std::string::npos ||
comment > pos))
{
found = true;
if (!confirmation ||
confirm (format (STRING_CMD_CONFIG_CONFIRM, name, context.config.get (name), value)))
{
if (comment != std::string::npos)
*line = name + "=" + json::encode (value) + " " + line->substr (comment);
else
*line = name + "=" + json::encode (value);
change = true;
}
}
}
// Not found, so append instead.
if (!found &&
(!confirmation ||
confirm (format (STRING_CMD_CONFIG_CONFIRM2, name, value))))
{
contents.push_back (name + "=" + json::encode (value));
change = true;
}
}
// task config name // task config name
else else
{ {
bool found = false; rc = unsetConfigVariable(name, confirmation);
std::vector <std::string>::iterator line; if (rc == 0)
for (line = contents.begin (); line != contents.end (); ++line)
{ {
// If there is a comment on the line, it must follow the pattern. change = true;
std::string::size_type comment = line->find ("#"); found = true;
std::string::size_type pos = line->find (name + "=");
if (pos != std::string::npos &&
(comment == std::string::npos ||
comment > pos))
{
found = true;
// Remove name
if (!confirmation ||
confirm (format (STRING_CMD_CONFIG_CONFIRM3, name)))
{
*line = "";
change = true;
}
}
} }
else if (rc == 1)
found = true;
if (!found) if (!found)
throw format (STRING_CMD_CONFIG_NO_ENTRY, name); throw format (STRING_CMD_CONFIG_NO_ENTRY, name);
} }
// Write .taskrc (or equivalent) // Show feedback depending on whether .taskrc has been rewritten
if (change) if (change)
{ {
File::write (context.config._original_file, contents);
out << format (STRING_CMD_CONFIG_FILE_MOD, out << format (STRING_CMD_CONFIG_FILE_MOD,
context.config._original_file._data) context.config._original_file._data)
<< "\n"; << "\n";

View File

@@ -34,6 +34,8 @@ class CmdConfig : public Command
{ {
public: public:
CmdConfig (); CmdConfig ();
static bool setConfigVariable (std::string name, std::string value, bool confirmation = false);
static int unsetConfigVariable (std::string name, bool confirmation = false);
int execute (std::string&); int execute (std::string&);
}; };

379
src/commands/CmdContext.cpp Normal file
View File

@@ -0,0 +1,379 @@
////////////////////////////////////////////////////////////////////////////////
//
// 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 <Filter.h>
#include <sstream>
#include <algorithm>
#include <i18n.h>
#include <util.h>
#include <text.h>
#include <CmdContext.h>
#include <CmdConfig.h>
extern Context context;
////////////////////////////////////////////////////////////////////////////////
CmdContext::CmdContext ()
{
_keyword = "context";
_usage = "task context [<name> | subcommand]";
_description = STRING_CMD_CONTEXT_USAGE;
_read_only = true;
_displays_id = false;
}
////////////////////////////////////////////////////////////////////////////////
int CmdContext::execute (std::string& output)
{
int rc = 0;
std::stringstream out;
// Get the non-attribute, non-fancy command line arguments.
std::vector <std::string> words = context.cli.getWords ();
if (words.size () > 0)
{
std::string subcommand = words[0];
if (subcommand == "define")
rc = defineContext (words, out);
else if (subcommand == "delete")
rc = deleteContext (words, out);
else if (subcommand == "list")
rc = listContexts (words, out);
else if (subcommand == "none")
rc = unsetContext (words, out);
else if (subcommand == "show")
rc = showContext (words, out);
else
rc = setContext (words, out);
}
output = out.str ();
return rc;
}
////////////////////////////////////////////////////////////////////////////////
// Joins all the words in the specified interval <from, to) to one string,
// which is then returned.
//
// If to is specified as 0 (default value), all the remaining words will be joined.
//
std::string CmdContext::joinWords (std::vector <std::string>& words, unsigned int from, unsigned int to /* = 0 */)
{
std::string value = "";
if (to == 0)
to = words.size();
for (unsigned int i = from; i < to; ++i)
{
if (i > from)
value += " ";
value += words[i];
}
return value;
}
////////////////////////////////////////////////////////////////////////////////
// Returns all user defined contexts.
//
std::vector <std::string> CmdContext::getContexts ()
{
std::vector <std::string> contexts;
Config::const_iterator name;
for (name = context.config.begin (); name != context.config.end (); ++name)
if (name->first.substr (0, 8) == "context.")
contexts.push_back (name->first.substr (8));
return contexts;
}
////////////////////////////////////////////////////////////////////////////////
// Defines a new user-provided context.
// - The context definition is written into .taskrc as a context.<name> variable.
// - Deletion of the context requires confirmation if rc.confirmation=yes.
//
// Returns: 0 if the addition of the config variable was successful, 1 otherwise
//
// Invoked with: task context define <name> <filter>
// Example: task context define home project:Home
//
int CmdContext::defineContext (std::vector <std::string>& words, std::stringstream& out)
{
int rc = 0;
bool confirmation = context.config.getBoolean ("confirmation");
if (words.size () > 2)
{
std::string name = "context." + words[1];
std::string value = joinWords (words, 2);
// Check if the value is a proper filter by filtering current pending.data
Filter filter;
std::vector <Task> filtered;
const std::vector <Task>& pending = context.tdb2.pending.get_tasks ();
try
{
context.cli.addRawFilter ("( " + value + " )");
filter.subset (pending, filtered);
}
catch (std::string exception)
{
throw format (STRING_CMD_CONTEXT_DEF_ABRT2, exception);
}
// Make user explicitly confirm filters that are matching no pending tasks
if (filtered.size () == 0)
if (confirmation &&
! confirm (format (STRING_CMD_CONTEXT_DEF_CONF, value)))
throw std::string (STRING_CMD_CONTEXT_DEF_ABRT);
// Set context definition config variable
bool success = CmdConfig::setConfigVariable (name, value, confirmation);
if (success)
out << format (STRING_CMD_CONTEXT_DEF_SUCC, words[1]) << "\n";
else
{
out << format (STRING_CMD_CONTEXT_DEF_FAIL, words[1]) << "\n";
rc = 1;
}
}
else
{
out << STRING_CMD_CONTEXT_DEF_USAG << "\n";
rc = 1;
}
return rc;
}
////////////////////////////////////////////////////////////////////////////////
// Deletes the specified context.
// - If the deleted context is currently active, unset it.
// - Deletion of the context requires confirmation if rc.confirmation=yes.
//
// Returns: 0 if the removal of the config variable was successful, 1 otherwise
//
// Invoked with: task context delete <name>
// Example: task context delete home
//
int CmdContext::deleteContext (std::vector <std::string>& words, std::stringstream& out)
{
int rc = 0;
if (words.size () > 1)
{
// Delete the specified context
std::string name = "context." + words[1];
bool confirmation = context.config.getBoolean ("confirmation");
rc = CmdConfig::unsetConfigVariable(name, confirmation);
// If the currently set context was deleted, unset it
std::string currentContext = context.config.get ("context");
if (currentContext == words[1])
CmdConfig::unsetConfigVariable("context", false);
// Output feedback
if (rc == 0)
out << format (STRING_CMD_CONTEXT_DEL_SUCC, words[1]) << "\n";
else
out << format (STRING_CMD_CONTEXT_DEL_FAIL, words[1]) << "\n";
}
else
{
out << STRING_CMD_CONTEXT_DEL_USAG << "\n";
rc = 1;
}
return rc;
}
////////////////////////////////////////////////////////////////////////////////
// Render a list of context names and their definitions.
//
// Returns: 0 the resulting list is non-empty, 1 otherwise
//
// Invoked with: task context list
// Example: task context list
//
int CmdContext::listContexts (std::vector <std::string>& words, std::stringstream& out)
{
int rc = 0;
std::vector <std::string> contexts = getContexts();
if (contexts.size ())
{
std::sort (contexts.begin (), contexts.end ());
ViewText view;
view.width (context.getWidth ());
view.add (Column::factory ("string", "Name"));
view.add (Column::factory ("string", "Definition"));
Color label (context.config.get ("color.label"));
view.colorHeader (label);
std::vector <std::string>::iterator userContext;
for (userContext = contexts.begin (); userContext != contexts.end (); ++userContext)
{
std::string definition = context.config.get ("context." + *userContext);
int row = view.addRow ();
view.set (row, 0, *userContext);
view.set (row, 1, definition);
}
out << optionalBlankLine ()
<< view.render ()
<< optionalBlankLine ();
}
else
{
out << STRING_CMD_CONTEXT_LIST_EMPT << "\n";
rc = 1;
}
return rc;
}
////////////////////////////////////////////////////////////////////////////////
// Sets the specified context as currently active.
// - If some other context was active, the value of currently active context
// is replaced, not added.
// - Setting of the context does not require confirmation.
//
// Returns: 0 if the setting of the context was successful, 1 otherwise
//
// Invoked with: task context <name>
// Example: task context home
//
int CmdContext::setContext (std::vector <std::string>& words, std::stringstream& out)
{
int rc = 0;
std::string value = words[0];
std::vector <std::string> contexts = getContexts ();
// Check that the specified context is defined
if (std::find (contexts.begin (), contexts.end (), value) == contexts.end ())
throw format (STRING_CMD_CONTEXT_SET_NFOU, value);
// Set the active context.
// Should always succeed, as we do not require confirmation.
bool success = CmdConfig::setConfigVariable ("context", value, false);
if (success)
out << format (STRING_CMD_CONTEXT_SET_SUCC, value) << "\n";
else
{
out << format (STRING_CMD_CONTEXT_SET_FAIL, value) << "\n";
rc = 1;
}
return rc;
}
////////////////////////////////////////////////////////////////////////////////
// Shows the currently active context.
//
// Returns: Always returns 0.
//
// Invoked with: task context show
// Example: task context show
//
int CmdContext::showContext (std::vector <std::string>& words, std::stringstream& out)
{
std::string currentContext = context.config.get ("context");
if (currentContext == "")
out << STRING_CMD_CONTEXT_SHOW_EMPT << "\n";
else
{
std::string currentFilter = context.config.get ("context." + currentContext);
out << format (STRING_CMD_CONTEXT_SHOW, currentContext, currentFilter) << "\n";
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// Unsets the currently active context.
// - Unsetting of the context does not require confirmation.
//
// Returns: 0 if the unsetting of the context was successful, 1 otherwise (also
// returned if no context is currently active)
//
// Invoked with: task context none
// Example: task context none
//
int CmdContext::unsetContext (std::vector <std::string>& words, std::stringstream& out)
{
int rc = 0;
int status = CmdConfig::unsetConfigVariable ("context", false);
if (status == 0)
out << STRING_CMD_CONTEXT_NON_SUCC << "\n";
else
{
out << STRING_CMD_CONTEXT_NON_FAIL << "\n";
rc = 1;
}
return rc;
}
////////////////////////////////////////////////////////////////////////////////
CmdCompletionContext::CmdCompletionContext ()
{
_keyword = "_context";
_usage = "task _context";
_description = STRING_CMD_HCONTEXT_USAGE;
_read_only = true;
_displays_id = false;
}
////////////////////////////////////////////////////////////////////////////////
int CmdCompletionContext::execute (std::string& output)
{
std::vector <std::string> userContexts = CmdContext::getContexts ();
std::vector <std::string>::iterator userContext;
for (userContext = userContexts.begin (); userContext != userContexts.end (); ++userContext)
output += *userContext + "\n";
return 0;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -24,40 +24,33 @@
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <cmake.h> #ifndef INCLUDED_CMDCONTEXT
#include <iostream> #define INCLUDED_CMDCONTEXT
#include <stdlib.h>
#include <text.h>
#include <test.h>
//////////////////////////////////////////////////////////////////////////////// #include <string>
int main (int argc, char** argv) #include <Command.h>
class CmdContext : public Command
{ {
UnitTest t (16); public:
CmdContext ();
int execute (std::string&);
std::string joinWords (std::vector <std::string>& words, unsigned int from, unsigned int to = 0);
static std::vector <std::string> getContexts ();
int defineContext (std::vector <std::string>& words, std::stringstream& out);
int deleteContext (std::vector <std::string>& words, std::stringstream& out);
int listContexts (std::vector <std::string>& words, std::stringstream& out);
int setContext (std::vector <std::string>& words, std::stringstream& out);
int showContext (std::vector <std::string>& words, std::stringstream& out);
int unsetContext (std::vector <std::string>& words, std::stringstream& out);
};
// Ensure environment has no influence. class CmdCompletionContext : public Command
unsetenv ("TASKDATA"); {
unsetenv ("TASKRC"); public:
CmdCompletionContext ();
t.is (mk_wcwidth ('a'), 1, "U+0061 --> 1"); int execute (std::string&);
};
t.is (mk_wcwidth (0x5149), 2, "U+5149 --> 2");
t.is (mk_wcwidth (0x9a8c), 2, "U+9a8c --> 2");
t.is (mk_wcwidth (0x4e70), 2, "U+4e70 --> 2");
t.is (mk_wcwidth (0x94b1), 2, "U+94b1 --> 2");
t.is (mk_wcwidth (0x5305), 2, "U+5305 --> 2");
t.is (mk_wcwidth (0x91cd), 2, "U+91cd --> 2");
t.is (mk_wcwidth (0x65b0), 2, "U+65b0 --> 2");
t.is (mk_wcwidth (0x8bbe), 2, "U+8bbe --> 2");
t.is (mk_wcwidth (0x8ba1), 2, "U+8ba1 --> 2");
t.is (mk_wcwidth (0x5411), 2, "U+5411 --> 2");
t.is (mk_wcwidth (0x4e0a), 2, "U+4e0a --> 2");
t.is (mk_wcwidth (0x4e0b), 2, "U+4e0b --> 2");
t.is (mk_wcwidth (0x7bad), 2, "U+7bad --> 2");
t.is (mk_wcwidth (0x5934), 2, "U+5934 --> 2");
t.is (mk_wcwidth (0xff0c), 2, "U+ff0c --> 2"); // comma
return 0;
}
#endif
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@@ -82,15 +82,7 @@ int CmdCustom::execute (std::string& output)
validateSortColumns (sortOrder); validateSortColumns (sortOrder);
// Prepend the argument list with those from the report filter. // Prepend the argument list with those from the report filter.
std::string lexeme; context.cli.addRawFilter(reportFilter);
Lexer::Type type;
Lexer lex (reportFilter);
lex.ambiguity (false);
while (lex.token (lexeme, type))
context.cli.add (lexeme);
// Reparse after tree change.
context.cli.analyze ();
// Apply filter. // Apply filter.
handleRecurrence (); handleRecurrence ();

View File

@@ -54,7 +54,7 @@ int CmdExport::execute (std::string& output)
// Apply filter. // Apply filter.
Filter filter; Filter filter;
std::vector <Task> filtered; std::vector <Task> filtered;
filter.subset (filtered); filter.subset (filtered, false);
// Obey 'limit:N'. // Obey 'limit:N'.
int rows = 0; int rows = 0;

View File

@@ -314,6 +314,40 @@ int CmdInfo::execute (std::string& output)
view.set (row, 1, allTags); view.set (row, 1, allTags);
} }
// Virtual tags.
{
// Note: This list must match that in Task::hasTag.
std::string virtualTags = "";
if (task->hasTag ("ACTIVE")) virtualTags += "ACTIVE ";
if (task->hasTag ("ANNOTATED")) virtualTags += "ANNOTATED ";
if (task->hasTag ("BLOCKED")) virtualTags += "BLOCKED ";
if (task->hasTag ("BLOCKING")) virtualTags += "BLOCKING ";
if (task->hasTag ("CHILD")) virtualTags += "CHILD ";
if (task->hasTag ("COMPLETED")) virtualTags += "COMPLETED ";
if (task->hasTag ("DELETED")) virtualTags += "DELETED ";
if (task->hasTag ("DUE")) virtualTags += "DUE ";
if (task->hasTag ("DUETODAY")) virtualTags += "DUETODAY ";
if (task->hasTag ("MONTH")) virtualTags += "MONTH ";
if (task->hasTag ("OVERDUE")) virtualTags += "OVERDUE ";
if (task->hasTag ("PARENT")) virtualTags += "PARENT ";
if (task->hasTag ("PENDING")) virtualTags += "PENDING ";
if (task->hasTag ("READY")) virtualTags += "READY ";
if (task->hasTag ("SCHEDULED")) virtualTags += "SCHEDULED ";
if (task->hasTag ("TAGGED")) virtualTags += "TAGGED ";
if (task->hasTag ("TODAY")) virtualTags += "TODAY ";
if (task->hasTag ("TOMORROW")) virtualTags += "TOMORROW ";
if (task->hasTag ("UNBLOCKED")) virtualTags += "UNBLOCKED ";
if (task->hasTag ("UNTIL")) virtualTags += "UNTIL ";
if (task->hasTag ("WAITING")) virtualTags += "WAITING ";
if (task->hasTag ("WEEK")) virtualTags += "WEEK ";
if (task->hasTag ("YEAR")) virtualTags += "YEAR ";
if (task->hasTag ("YESTERDAY")) virtualTags += "YESTERDAY ";
row = view.addRow ();
view.set (row, 0, STRING_CMD_INFO_VIRTUAL_TAGS);
view.set (row, 1, virtualTags);
}
// uuid // uuid
row = view.addRow (); row = view.addRow ();
view.set (row, 0, STRING_COLUMN_LABEL_UUID); view.set (row, 0, STRING_COLUMN_LABEL_UUID);

View File

@@ -53,6 +53,9 @@ int CmdProjects::execute (std::string& output)
{ {
int rc = 0; int rc = 0;
// Enforce the garbage collector to show correct task counts
context.tdb2.gc ();
// Get all the tasks. // Get all the tasks.
handleRecurrence (); handleRecurrence ();
std::vector <Task> tasks = context.tdb2.pending.get_tasks (); std::vector <Task> tasks = context.tdb2.pending.get_tasks ();
@@ -89,8 +92,16 @@ int CmdProjects::execute (std::string& output)
continue; continue;
} }
// Increase the count for the project the task belongs to and all
// its super-projects
project = task->get ("project"); project = task->get ("project");
unique[project] += 1;
std::vector <std::string> projects = extractParents (project);
projects.push_back (project);
std::vector <std::string>::const_iterator parent;
for (parent = projects.begin (); parent != projects.end (); ++parent)
unique[*parent] += 1;
if (project == "") if (project == "")
no_project = true; no_project = true;

View File

@@ -127,6 +127,7 @@ int CmdShow::execute (std::string& output)
" column.padding" " column.padding"
" complete.all.tags" " complete.all.tags"
" confirmation" " confirmation"
" context"
" data.location" " data.location"
" dateformat" " dateformat"
" dateformat.annotation" " dateformat.annotation"
@@ -230,6 +231,7 @@ int CmdShow::execute (std::string& output)
i->first.substr (0, 14) != "color.project." && i->first.substr (0, 14) != "color.project." &&
i->first.substr (0, 10) != "color.tag." && i->first.substr (0, 10) != "color.tag." &&
i->first.substr (0, 10) != "color.uda." && i->first.substr (0, 10) != "color.uda." &&
i->first.substr (0, 8) != "context." &&
i->first.substr (0, 8) != "holiday." && i->first.substr (0, 8) != "holiday." &&
i->first.substr (0, 7) != "report." && i->first.substr (0, 7) != "report." &&
i->first.substr (0, 6) != "alias." && i->first.substr (0, 6) != "alias." &&

View File

@@ -92,27 +92,34 @@ int CmdSummary::execute (std::string& output)
for (task = filtered.begin (); task != filtered.end (); ++task) for (task = filtered.begin (); task != filtered.end (); ++task)
{ {
std::string project = task->get ("project"); std::string project = task->get ("project");
++counter[project]; std::vector <std::string> projects = extractParents (project);
projects.push_back (project);
std::vector <std::string>::const_iterator parent;
for (parent = projects.begin (); parent != projects.end (); ++parent)
++counter[*parent];
if (task->getStatus () == Task::pending || if (task->getStatus () == Task::pending ||
task->getStatus () == Task::waiting) task->getStatus () == Task::waiting)
{ for (parent = projects.begin (); parent != projects.end (); ++parent)
++countPending[project]; {
++countPending[*parent];
time_t entry = strtol (task->get ("entry").c_str (), NULL, 10); time_t entry = strtol (task->get ("entry").c_str (), NULL, 10);
if (entry) if (entry)
sumEntry[project] = sumEntry[project] + (double) (now - entry); sumEntry[*parent] = sumEntry[*parent] + (double) (now - entry);
} }
else if (task->getStatus () == Task::completed) else if (task->getStatus () == Task::completed)
{ for (parent = projects.begin (); parent != projects.end (); ++parent)
++countCompleted[project]; {
++countCompleted[*parent];
time_t entry = strtol (task->get ("entry").c_str (), NULL, 10); time_t entry = strtol (task->get ("entry").c_str (), NULL, 10);
time_t end = strtol (task->get ("end").c_str (), NULL, 10); time_t end = strtol (task->get ("end").c_str (), NULL, 10);
if (entry && end) if (entry && end)
sumEntry[project] = sumEntry[project] + (double) (end - entry); sumEntry[*parent] = sumEntry[*parent] + (double) (end - entry);
} }
} }

View File

@@ -135,7 +135,10 @@ CmdCompletionVersion::CmdCompletionVersion ()
int CmdCompletionVersion::execute (std::string& output) int CmdCompletionVersion::execute (std::string& output)
{ {
#ifdef HAVE_COMMIT #ifdef HAVE_COMMIT
output = COMMIT; output = std::string (VERSION)
+ std::string (" (")
+ std::string (COMMIT)
+ std::string (")");
#else #else
output = VERSION; output = VERSION;
#endif #endif

View File

@@ -46,6 +46,7 @@
#include <CmdColumns.h> #include <CmdColumns.h>
#include <CmdCommands.h> #include <CmdCommands.h>
#include <CmdConfig.h> #include <CmdConfig.h>
#include <CmdContext.h>
#include <CmdCount.h> #include <CmdCount.h>
#include <CmdCustom.h> #include <CmdCustom.h>
#include <CmdDelete.h> #include <CmdDelete.h>
@@ -109,6 +110,7 @@ void Command::factory (std::map <std::string, Command*>& all)
c = new CmdCompletionColumns (); all[c->keyword ()] = c; c = new CmdCompletionColumns (); all[c->keyword ()] = c;
c = new CmdCompletionCommands (); all[c->keyword ()] = c; c = new CmdCompletionCommands (); all[c->keyword ()] = c;
c = new CmdCompletionConfig (); all[c->keyword ()] = c; c = new CmdCompletionConfig (); all[c->keyword ()] = c;
c = new CmdCompletionContext (); all[c->keyword ()] = c;
c = new CmdCompletionIds (); all[c->keyword ()] = c; c = new CmdCompletionIds (); all[c->keyword ()] = c;
c = new CmdCompletionUDAs (); all[c->keyword ()] = c; c = new CmdCompletionUDAs (); all[c->keyword ()] = c;
c = new CmdCompletionUuids (); all[c->keyword ()] = c; c = new CmdCompletionUuids (); all[c->keyword ()] = c;
@@ -116,6 +118,7 @@ void Command::factory (std::map <std::string, Command*>& all)
c = new CmdCompletionTags (); all[c->keyword ()] = c; c = new CmdCompletionTags (); all[c->keyword ()] = c;
c = new CmdCompletionVersion (); all[c->keyword ()] = c; c = new CmdCompletionVersion (); all[c->keyword ()] = c;
c = new CmdConfig (); all[c->keyword ()] = c; c = new CmdConfig (); all[c->keyword ()] = c;
c = new CmdContext (); all[c->keyword ()] = c;
c = new CmdCount (); all[c->keyword ()] = c; c = new CmdCount (); all[c->keyword ()] = c;
c = new CmdDelete (); all[c->keyword ()] = c; c = new CmdDelete (); all[c->keyword ()] = c;
c = new CmdDenotate (); all[c->keyword ()] = c; c = new CmdDenotate (); all[c->keyword ()] = c;

View File

@@ -296,6 +296,7 @@
#define STRING_CMD_INFO_UNTIL "Bis" #define STRING_CMD_INFO_UNTIL "Bis"
#define STRING_CMD_INFO_MODIFICATION "Änderung" #define STRING_CMD_INFO_MODIFICATION "Änderung"
#define STRING_CMD_INFO_MODIFIED "Letzte Änderung" #define STRING_CMD_INFO_MODIFIED "Letzte Änderung"
#define STRING_CMD_INFO_VIRTUAL_TAGS "Virtual tags"
#define STRING_CMD_UNDO_USAGE "Macht die letzte Änderung an einer Aufgabe Rückgängig" #define STRING_CMD_UNDO_USAGE "Macht die letzte Änderung an einer Aufgabe Rückgängig"
#define STRING_CMD_UNDO_MODS "Der undo-Befehl erlaubt keine weitere Aufgaben-Änderung." #define STRING_CMD_UNDO_MODS "Der undo-Befehl erlaubt keine weitere Aufgaben-Änderung."
#define STRING_CMD_STATS_USAGE "Zeigt Statistiken zur Aufgaben-Datenbank" #define STRING_CMD_STATS_USAGE "Zeigt Statistiken zur Aufgaben-Datenbank"
@@ -561,6 +562,25 @@
#define STRING_CMD_CONFIG_NO_CHANGE "Keine Änderungen durchgeführt." #define STRING_CMD_CONFIG_NO_CHANGE "Keine Änderungen durchgeführt."
#define STRING_CMD_CONFIG_NO_NAME "Geben Sie den Wert der zu ändernden Option an." #define STRING_CMD_CONFIG_NO_NAME "Geben Sie den Wert der zu ändernden Option an."
#define STRING_CMD_HCONFIG_USAGE "Zeigt alle unterstützten Konfigurations-Optionen zur AUtovervollständigung" #define STRING_CMD_HCONFIG_USAGE "Zeigt alle unterstützten Konfigurations-Optionen zur AUtovervollständigung"
#define STRING_CMD_CONTEXT_USAGE "Set and define contexts (default filters)"
#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_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."
#define STRING_CMD_CONTEXT_DEL_FAIL "Context '{1}' not deleted."
#define STRING_CMD_CONTEXT_DEL_USAG "Context name needs to be specified."
#define STRING_CMD_CONTEXT_LIST_EMPT "No contexts defined."
#define STRING_CMD_CONTEXT_SET_NFOU "Context '{1}' not found."
#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' set. Use 'task context none' to remove."
#define STRING_CMD_CONTEXT_SET_FAIL "Context '{1}' not applied."
#define STRING_CMD_CONTEXT_SHOW_EMPT "No context is currently applied."
#define STRING_CMD_CONTEXT_SHOW "Context '{1}' with filter '{2}' is currently applied."
#define STRING_CMD_CONTEXT_NON_SUCC "Context unset."
#define STRING_CMD_CONTEXT_NON_FAIL "Context not unset."
#define STRING_CMD_HCONTEXT_USAGE "Lists all supported contexts, for completion purposes"
#define STRING_CMD_CUSTOM_MISMATCH "Die Anzahl von Spalten und Beschriftungen für Report '{1}' unterscheidet sich." #define STRING_CMD_CUSTOM_MISMATCH "Die Anzahl von Spalten und Beschriftungen für Report '{1}' unterscheidet sich."
#define STRING_CMD_CUSTOM_SHOWN "{1} gezeigt" #define STRING_CMD_CUSTOM_SHOWN "{1} gezeigt"
#define STRING_CMD_CUSTOM_COUNT "1 Aufgabe" #define STRING_CMD_CUSTOM_COUNT "1 Aufgabe"
@@ -881,10 +901,6 @@
#define STRING_TDB2_UNDO_SYNCED "Kann Änderung nicht rückgängig machen, weil die Aufgabe bereits abgeglichen wurde. Aufgabe stattdessen löschen." #define STRING_TDB2_UNDO_SYNCED "Kann Änderung nicht rückgängig machen, weil die Aufgabe bereits abgeglichen wurde. Aufgabe stattdessen löschen."
#define STRING_TDB2_DIRTY_EXIT "Beende mit ungeschriebenen Änderungen auf {1}" #define STRING_TDB2_DIRTY_EXIT "Beende mit ungeschriebenen Änderungen auf {1}"
// utf8
#define STRING_UTF8_INVALID_CP_REP "Ungültige Codepoint-Darstellung."
#define STRING_UTF8_INVALID_CP "Ungültiger Unicode-Codepoint."
// View // View
#define STRING_VIEW_TOO_SMALL "Dieser Report hat eine Mindestbreite von {1} und passt nicht in die Bildschirmbreite von {2}." #define STRING_VIEW_TOO_SMALL "Dieser Report hat eine Mindestbreite von {1} und passt nicht in die Bildschirmbreite von {2}."

View File

@@ -296,6 +296,7 @@
#define STRING_CMD_INFO_UNTIL "Until" #define STRING_CMD_INFO_UNTIL "Until"
#define STRING_CMD_INFO_MODIFICATION "Modification" #define STRING_CMD_INFO_MODIFICATION "Modification"
#define STRING_CMD_INFO_MODIFIED "Last modified" #define STRING_CMD_INFO_MODIFIED "Last modified"
#define STRING_CMD_INFO_VIRTUAL_TAGS "Virtual tags"
#define STRING_CMD_UNDO_USAGE "Reverts the most recent change to a task" #define STRING_CMD_UNDO_USAGE "Reverts the most recent change to a task"
#define STRING_CMD_UNDO_MODS "The undo command does not allow further task modification." #define STRING_CMD_UNDO_MODS "The undo command does not allow further task modification."
#define STRING_CMD_STATS_USAGE "Shows task database statistics" #define STRING_CMD_STATS_USAGE "Shows task database statistics"
@@ -561,6 +562,25 @@
#define STRING_CMD_CONFIG_NO_CHANGE "No changes made." #define STRING_CMD_CONFIG_NO_CHANGE "No changes made."
#define STRING_CMD_CONFIG_NO_NAME "Specify the name of a config variable to modify." #define STRING_CMD_CONFIG_NO_NAME "Specify the name of a config variable to modify."
#define STRING_CMD_HCONFIG_USAGE "Lists all supported configuration variables, for completion purposes" #define STRING_CMD_HCONFIG_USAGE "Lists all supported configuration variables, for completion purposes"
#define STRING_CMD_CONTEXT_USAGE "Set and define contexts (default filters)"
#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_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."
#define STRING_CMD_CONTEXT_DEL_FAIL "Context '{1}' not deleted."
#define STRING_CMD_CONTEXT_DEL_USAG "Context name needs to be specified."
#define STRING_CMD_CONTEXT_LIST_EMPT "No contexts defined."
#define STRING_CMD_CONTEXT_SET_NFOU "Context '{1}' not found."
#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' set. Use 'task context none' to remove."
#define STRING_CMD_CONTEXT_SET_FAIL "Context '{1}' not applied."
#define STRING_CMD_CONTEXT_SHOW_EMPT "No context is currently applied."
#define STRING_CMD_CONTEXT_SHOW "Context '{1}' with filter '{2}' is currently applied."
#define STRING_CMD_CONTEXT_NON_SUCC "Context unset."
#define STRING_CMD_CONTEXT_NON_FAIL "Context not unset."
#define STRING_CMD_HCONTEXT_USAGE "Lists all supported contexts, for completion purposes"
#define STRING_CMD_CUSTOM_MISMATCH "There are different numbers of columns and labels for report '{1}'." #define STRING_CMD_CUSTOM_MISMATCH "There are different numbers of columns and labels for report '{1}'."
#define STRING_CMD_CUSTOM_SHOWN "{1} shown" #define STRING_CMD_CUSTOM_SHOWN "{1} shown"
#define STRING_CMD_CUSTOM_COUNT "1 task" #define STRING_CMD_CUSTOM_COUNT "1 task"
@@ -881,10 +901,6 @@
#define STRING_TDB2_UNDO_SYNCED "Cannot undo change because the task was already synced. Modify the task instead." #define STRING_TDB2_UNDO_SYNCED "Cannot undo change because the task was already synced. Modify the task instead."
#define STRING_TDB2_DIRTY_EXIT "Exiting with unwritten changes to {1}" #define STRING_TDB2_DIRTY_EXIT "Exiting with unwritten changes to {1}"
// utf8
#define STRING_UTF8_INVALID_CP_REP "Invalid codepoint representation."
#define STRING_UTF8_INVALID_CP "Invalid Unicode codepoint."
// View // View
#define STRING_VIEW_TOO_SMALL "The report has a minimum width of {1} and does not fit in the available width of {2}." #define STRING_VIEW_TOO_SMALL "The report has a minimum width of {1} and does not fit in the available width of {2}."

View File

@@ -296,6 +296,7 @@
#define STRING_CMD_INFO_UNTIL "Ĝis" #define STRING_CMD_INFO_UNTIL "Ĝis"
#define STRING_CMD_INFO_MODIFICATION "Modifado" #define STRING_CMD_INFO_MODIFICATION "Modifado"
#define STRING_CMD_INFO_MODIFIED "Modifado lasta" #define STRING_CMD_INFO_MODIFIED "Modifado lasta"
#define STRING_CMD_INFO_VIRTUAL_TAGS "Virtual tags"
#define STRING_CMD_UNDO_USAGE "Malfaras la plej malfrua modifado al tasko" #define STRING_CMD_UNDO_USAGE "Malfaras la plej malfrua modifado al tasko"
#define STRING_CMD_UNDO_MODS "La komando 'undo' ne permesos, ke oni pli modifus la taskojn." #define STRING_CMD_UNDO_MODS "La komando 'undo' ne permesos, ke oni pli modifus la taskojn."
#define STRING_CMD_STATS_USAGE "Montras statistikon de la taska datumbazo" #define STRING_CMD_STATS_USAGE "Montras statistikon de la taska datumbazo"
@@ -561,6 +562,25 @@
#define STRING_CMD_CONFIG_NO_CHANGE "Ne ŝanĝis nenion." #define STRING_CMD_CONFIG_NO_CHANGE "Ne ŝanĝis nenion."
#define STRING_CMD_CONFIG_NO_NAME "Specifu la nomon de agordvariablo, kiun vi volas modifi." #define STRING_CMD_CONFIG_NO_NAME "Specifu la nomon de agordvariablo, kiun vi volas modifi."
#define STRING_CMD_HCONFIG_USAGE "Listigas çiun subtenatan agordan variablon, por motivo memkompletada" #define STRING_CMD_HCONFIG_USAGE "Listigas çiun subtenatan agordan variablon, por motivo memkompletada"
#define STRING_CMD_CONTEXT_USAGE "Set and define contexts (default filters)"
#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_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."
#define STRING_CMD_CONTEXT_DEL_FAIL "Context '{1}' not deleted."
#define STRING_CMD_CONTEXT_DEL_USAG "Context name needs to be specified."
#define STRING_CMD_CONTEXT_LIST_EMPT "No contexts defined."
#define STRING_CMD_CONTEXT_SET_NFOU "Context '{1}' not found."
#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' set. Use 'task context none' to remove."
#define STRING_CMD_CONTEXT_SET_FAIL "Context '{1}' not applied."
#define STRING_CMD_CONTEXT_SHOW_EMPT "No context is currently applied."
#define STRING_CMD_CONTEXT_SHOW "Context '{1}' with filter '{2}' is currently applied."
#define STRING_CMD_CONTEXT_NON_SUCC "Context unset."
#define STRING_CMD_CONTEXT_NON_FAIL "Context not unset."
#define STRING_CMD_HCONTEXT_USAGE "Lists all supported contexts, for completion purposes"
#define STRING_CMD_CUSTOM_MISMATCH "La nombroj de kolumnoj kaj de siaj titoloj ne kongruas por raporto '{1}'." #define STRING_CMD_CUSTOM_MISMATCH "La nombroj de kolumnoj kaj de siaj titoloj ne kongruas por raporto '{1}'."
#define STRING_CMD_CUSTOM_SHOWN "{1} montritaj" #define STRING_CMD_CUSTOM_SHOWN "{1} montritaj"
#define STRING_CMD_CUSTOM_COUNT "1 tasko" #define STRING_CMD_CUSTOM_COUNT "1 tasko"
@@ -881,10 +901,6 @@
#define STRING_TDB2_UNDO_SYNCED "Ne povos malfari ŝanĝon ĉar la tasko estis jam sinkronigita. Modifu anstataŭe la taskon." #define STRING_TDB2_UNDO_SYNCED "Ne povos malfari ŝanĝon ĉar la tasko estis jam sinkronigita. Modifu anstataŭe la taskon."
#define STRING_TDB2_DIRTY_EXIT "Eliranta kun neskribitajn ŝanĝojn al {1}" #define STRING_TDB2_DIRTY_EXIT "Eliranta kun neskribitajn ŝanĝojn al {1}"
// utf8
#define STRING_UTF8_INVALID_CP_REP "Nevalida kodpunkta nombro."
#define STRING_UTF8_INVALID_CP "Nevalida unikoda kodpunkto."
// View // View
#define STRING_VIEW_TOO_SMALL "La raporto havas larĝecminimumon {1}, al kio ne konformas la disponebla larĝeco {2}." #define STRING_VIEW_TOO_SMALL "La raporto havas larĝecminimumon {1}, al kio ne konformas la disponebla larĝeco {2}."

View File

@@ -298,6 +298,7 @@
#define STRING_CMD_INFO_UNTIL "Hasta" #define STRING_CMD_INFO_UNTIL "Hasta"
#define STRING_CMD_INFO_MODIFICATION "Modificación" #define STRING_CMD_INFO_MODIFICATION "Modificación"
#define STRING_CMD_INFO_MODIFIED "Modificada por última vez" #define STRING_CMD_INFO_MODIFIED "Modificada por última vez"
#define STRING_CMD_INFO_VIRTUAL_TAGS "Virtual tags"
#define STRING_CMD_UNDO_USAGE "Revierte el cambio más reciente a una tarea" #define STRING_CMD_UNDO_USAGE "Revierte el cambio más reciente a una tarea"
#define STRING_CMD_UNDO_MODS "El comando undo no permite más modificación a la tarea." #define STRING_CMD_UNDO_MODS "El comando undo no permite más modificación a la tarea."
#define STRING_CMD_STATS_USAGE "Muestra estadísticas de la base de datos de tareas" #define STRING_CMD_STATS_USAGE "Muestra estadísticas de la base de datos de tareas"
@@ -570,6 +571,25 @@
#define STRING_CMD_CONFIG_NO_CHANGE "No se hicieron cambios." #define STRING_CMD_CONFIG_NO_CHANGE "No se hicieron cambios."
#define STRING_CMD_CONFIG_NO_NAME "Especifique el nombre de una variable de configuración a modificar." #define STRING_CMD_CONFIG_NO_NAME "Especifique el nombre de una variable de configuración a modificar."
#define STRING_CMD_HCONFIG_USAGE "Lista todas las variables de configuración soportadas, a fines de completado" #define STRING_CMD_HCONFIG_USAGE "Lista todas las variables de configuración soportadas, a fines de completado"
#define STRING_CMD_CONTEXT_USAGE "Set and define contexts (default filters)"
#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_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."
#define STRING_CMD_CONTEXT_DEL_FAIL "Context '{1}' not deleted."
#define STRING_CMD_CONTEXT_DEL_USAG "Context name needs to be specified."
#define STRING_CMD_CONTEXT_LIST_EMPT "No contexts defined."
#define STRING_CMD_CONTEXT_SET_NFOU "Context '{1}' not found."
#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' set. Use 'task context none' to remove."
#define STRING_CMD_CONTEXT_SET_FAIL "Context '{1}' not applied."
#define STRING_CMD_CONTEXT_SHOW_EMPT "No context is currently applied."
#define STRING_CMD_CONTEXT_SHOW "Context '{1}' with filter '{2}' is currently applied."
#define STRING_CMD_CONTEXT_NON_SUCC "Context unset."
#define STRING_CMD_CONTEXT_NON_FAIL "Context not unset."
#define STRING_CMD_HCONTEXT_USAGE "Lists all supported contexts, for completion purposes"
#define STRING_CMD_CUSTOM_MISMATCH "Hay diferente número de columnas y etiquetas para el informe '{1}'." #define STRING_CMD_CUSTOM_MISMATCH "Hay diferente número de columnas y etiquetas para el informe '{1}'."
#define STRING_CMD_CUSTOM_SHOWN "{1} mostrada(s)" #define STRING_CMD_CUSTOM_SHOWN "{1} mostrada(s)"
#define STRING_CMD_CUSTOM_COUNT "1 tarea" #define STRING_CMD_CUSTOM_COUNT "1 tarea"
@@ -891,10 +911,6 @@
#define STRING_TDB2_UNDO_SYNCED "No se puede deshacer el cambio porque la tarea ya ha sido sincronizada. Como alternativa, modifique la tarea." #define STRING_TDB2_UNDO_SYNCED "No se puede deshacer el cambio porque la tarea ya ha sido sincronizada. Como alternativa, modifique la tarea."
#define STRING_TDB2_DIRTY_EXIT "Exiting with unwritten changes to {1}" #define STRING_TDB2_DIRTY_EXIT "Exiting with unwritten changes to {1}"
// utf8
#define STRING_UTF8_INVALID_CP_REP "Representación de codepoint no válida."
#define STRING_UTF8_INVALID_CP "Codepoint Unicode no válido."
// View // View
#define STRING_VIEW_TOO_SMALL "El informe tiene una anchura mínima de {1} y no cabe en la disponible, que es {2}." #define STRING_VIEW_TOO_SMALL "El informe tiene una anchura mínima de {1} y no cabe en la disponible, que es {2}."

View File

@@ -296,6 +296,7 @@
#define STRING_CMD_INFO_UNTIL "Jusqu'au" #define STRING_CMD_INFO_UNTIL "Jusqu'au"
#define STRING_CMD_INFO_MODIFICATION "Modification" #define STRING_CMD_INFO_MODIFICATION "Modification"
#define STRING_CMD_INFO_MODIFIED "Dernier modifié" #define STRING_CMD_INFO_MODIFIED "Dernier modifié"
#define STRING_CMD_INFO_VIRTUAL_TAGS "Virtual tags"
#define STRING_CMD_UNDO_USAGE "Annule les changements les plus récents sur une tâche" #define STRING_CMD_UNDO_USAGE "Annule les changements les plus récents sur une tâche"
#define STRING_CMD_UNDO_MODS "The undo command does not allow further task modification." #define STRING_CMD_UNDO_MODS "The undo command does not allow further task modification."
#define STRING_CMD_STATS_USAGE "Affiche les statistiques de la base de donnée" #define STRING_CMD_STATS_USAGE "Affiche les statistiques de la base de donnée"
@@ -561,6 +562,24 @@
#define STRING_CMD_CONFIG_NO_CHANGE "No changes made." #define STRING_CMD_CONFIG_NO_CHANGE "No changes made."
#define STRING_CMD_CONFIG_NO_NAME "Specify the name of a config variable to modify." #define STRING_CMD_CONFIG_NO_NAME "Specify the name of a config variable to modify."
#define STRING_CMD_HCONFIG_USAGE "Lists all supported configuration variables, for completion purposes" #define STRING_CMD_HCONFIG_USAGE "Lists all supported configuration variables, for completion purposes"
#define STRING_CMD_CONTEXT_USAGE "Set and define contexts (default filters)"
#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_CONF "The filter '{1}' matches 0 pending tasks. Do you wish to continue?"
#define STRING_CMD_CONTEXT_DEL_SUCC "Context '{1}' deleted."
#define STRING_CMD_CONTEXT_DEL_FAIL "Context '{1}' not deleted."
#define STRING_CMD_CONTEXT_DEL_USAG "Context name needs to be specified."
#define STRING_CMD_CONTEXT_LIST_EMPT "No contexts defined."
#define STRING_CMD_CONTEXT_SET_NFOU "Context '{1}' not found."
#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' set. Use 'task context none' to remove."
#define STRING_CMD_CONTEXT_SET_FAIL "Context '{1}' not applied."
#define STRING_CMD_CONTEXT_SHOW_EMPT "No context is currently applied."
#define STRING_CMD_CONTEXT_SHOW "Context '{1}' with filter '{2}' is currently applied."
#define STRING_CMD_CONTEXT_NON_SUCC "Context unset."
#define STRING_CMD_CONTEXT_NON_FAIL "Context not unset."
#define STRING_CMD_HCONTEXT_USAGE "Lists all supported contexts, for completion purposes"
#define STRING_CMD_CUSTOM_MISMATCH "There are different numbers of columns and labels for report '{1}'." #define STRING_CMD_CUSTOM_MISMATCH "There are different numbers of columns and labels for report '{1}'."
#define STRING_CMD_CUSTOM_SHOWN "{1} affichées" #define STRING_CMD_CUSTOM_SHOWN "{1} affichées"
#define STRING_CMD_CUSTOM_COUNT "1 tâche" #define STRING_CMD_CUSTOM_COUNT "1 tâche"
@@ -881,10 +900,6 @@
#define STRING_TDB2_UNDO_SYNCED "Impossible d'annuler les changements car la tâche a déjà été synchronysée. Modifiez plutôt la tâche." #define STRING_TDB2_UNDO_SYNCED "Impossible d'annuler les changements car la tâche a déjà été synchronysée. Modifiez plutôt la tâche."
#define STRING_TDB2_DIRTY_EXIT "Exiting with unwritten changes to {1}" #define STRING_TDB2_DIRTY_EXIT "Exiting with unwritten changes to {1}"
// utf8
#define STRING_UTF8_INVALID_CP_REP "Invalid codepoint representation."
#define STRING_UTF8_INVALID_CP "Invalid Unicode codepoint."
// View // View
#define STRING_VIEW_TOO_SMALL "The report has a minimum width of {1} and does not fit in the available width of {2}." #define STRING_VIEW_TOO_SMALL "The report has a minimum width of {1} and does not fit in the available width of {2}."

View File

@@ -295,6 +295,7 @@
#define STRING_CMD_INFO_UNTIL "Fino a" #define STRING_CMD_INFO_UNTIL "Fino a"
#define STRING_CMD_INFO_MODIFICATION "Modifica" #define STRING_CMD_INFO_MODIFICATION "Modifica"
#define STRING_CMD_INFO_MODIFIED "Ultima modifica" #define STRING_CMD_INFO_MODIFIED "Ultima modifica"
#define STRING_CMD_INFO_VIRTUAL_TAGS "Virtual tags"
#define STRING_CMD_UNDO_USAGE "Ritorna alla più recente modifica di un task" #define STRING_CMD_UNDO_USAGE "Ritorna alla più recente modifica di un task"
#define STRING_CMD_UNDO_MODS "Il comando undo non ammette ulteriori modifiche al task." #define STRING_CMD_UNDO_MODS "Il comando undo non ammette ulteriori modifiche al task."
#define STRING_CMD_STATS_USAGE "Mostra le statistiche sul task" #define STRING_CMD_STATS_USAGE "Mostra le statistiche sul task"
@@ -560,6 +561,25 @@
#define STRING_CMD_CONFIG_NO_CHANGE "Nessuna modifica apportata." #define STRING_CMD_CONFIG_NO_CHANGE "Nessuna modifica apportata."
#define STRING_CMD_CONFIG_NO_NAME "Specificare il nome di una variabile di configurazione da modificare." #define STRING_CMD_CONFIG_NO_NAME "Specificare il nome di una variabile di configurazione da modificare."
#define STRING_CMD_HCONFIG_USAGE "Elenca le variabili di configurazione supportate, per autocompletamento" #define STRING_CMD_HCONFIG_USAGE "Elenca le variabili di configurazione supportate, per autocompletamento"
#define STRING_CMD_CONTEXT_USAGE "Set and define contexts (default filters)"
#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_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."
#define STRING_CMD_CONTEXT_DEL_FAIL "Context '{1}' not deleted."
#define STRING_CMD_CONTEXT_DEL_USAG "Context name needs to be specified."
#define STRING_CMD_CONTEXT_LIST_EMPT "No contexts defined."
#define STRING_CMD_CONTEXT_SET_NFOU "Context '{1}' not found."
#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' set. Use 'task context none' to remove."
#define STRING_CMD_CONTEXT_SET_FAIL "Context '{1}' not applied."
#define STRING_CMD_CONTEXT_SHOW_EMPT "No context is currently applied."
#define STRING_CMD_CONTEXT_SHOW "Context '{1}' with filter '{2}' is currently applied."
#define STRING_CMD_CONTEXT_NON_SUCC "Context unset."
#define STRING_CMD_CONTEXT_NON_FAIL "Context not unset."
#define STRING_CMD_HCONTEXT_USAGE "Lists all supported contexts, for completion purposes"
#define STRING_CMD_CUSTOM_MISMATCH "Differente numero di colonne ed etichette per il report '{1}'." #define STRING_CMD_CUSTOM_MISMATCH "Differente numero di colonne ed etichette per il report '{1}'."
#define STRING_CMD_CUSTOM_SHOWN "{1} mostrato" #define STRING_CMD_CUSTOM_SHOWN "{1} mostrato"
#define STRING_CMD_CUSTOM_COUNT "1 task" #define STRING_CMD_CUSTOM_COUNT "1 task"
@@ -880,10 +900,6 @@
#define STRING_TDB2_UNDO_SYNCED "Cannot undo change because the task was already synced. Modify the task instead." #define STRING_TDB2_UNDO_SYNCED "Cannot undo change because the task was already synced. Modify the task instead."
#define STRING_TDB2_DIRTY_EXIT "Exiting with unwritten changes to {1}" #define STRING_TDB2_DIRTY_EXIT "Exiting with unwritten changes to {1}"
// utf8
#define STRING_UTF8_INVALID_CP_REP "Rappresentazione non valida del codepoint."
#define STRING_UTF8_INVALID_CP "Codepoint Unicode non valido."
// View // View
#define STRING_VIEW_TOO_SMALL "Il report ha larghezza minima di {1} e non entra nella larghezza disponibile di {2}." #define STRING_VIEW_TOO_SMALL "Il report ha larghezza minima di {1} e non entra nella larghezza disponibile di {2}."

View File

@@ -296,6 +296,7 @@
#define STRING_CMD_INFO_UNTIL "Do" #define STRING_CMD_INFO_UNTIL "Do"
#define STRING_CMD_INFO_MODIFICATION "Modyfikacja" #define STRING_CMD_INFO_MODIFICATION "Modyfikacja"
#define STRING_CMD_INFO_MODIFIED "Ostatnio zmodyfikowane" #define STRING_CMD_INFO_MODIFIED "Ostatnio zmodyfikowane"
#define STRING_CMD_INFO_VIRTUAL_TAGS "Virtual tags"
#define STRING_CMD_UNDO_USAGE "Odwraca ostatnią zmianę w zadaniu" #define STRING_CMD_UNDO_USAGE "Odwraca ostatnią zmianę w zadaniu"
#define STRING_CMD_UNDO_MODS "Polecenie cofnij nie pozwala na późniejsze modyfikacje zadania." #define STRING_CMD_UNDO_MODS "Polecenie cofnij nie pozwala na późniejsze modyfikacje zadania."
#define STRING_CMD_STATS_USAGE "Pokazuje statystyki bazy danych zadań" #define STRING_CMD_STATS_USAGE "Pokazuje statystyki bazy danych zadań"
@@ -561,6 +562,25 @@
#define STRING_CMD_CONFIG_NO_CHANGE "Brak zmian." #define STRING_CMD_CONFIG_NO_CHANGE "Brak zmian."
#define STRING_CMD_CONFIG_NO_NAME "Podaj nazwę zmiennej w konfiguracji do zmiany." #define STRING_CMD_CONFIG_NO_NAME "Podaj nazwę zmiennej w konfiguracji do zmiany."
#define STRING_CMD_HCONFIG_USAGE "Wylistuj wszystkie zmienne konfiguracji." #define STRING_CMD_HCONFIG_USAGE "Wylistuj wszystkie zmienne konfiguracji."
#define STRING_CMD_CONTEXT_USAGE "Set and define contexts (default filters)"
#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_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."
#define STRING_CMD_CONTEXT_DEL_FAIL "Context '{1}' not deleted."
#define STRING_CMD_CONTEXT_DEL_USAG "Context name needs to be specified."
#define STRING_CMD_CONTEXT_LIST_EMPT "No contexts defined."
#define STRING_CMD_CONTEXT_SET_NFOU "Context '{1}' not found."
#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' set. Use 'task context none' to remove."
#define STRING_CMD_CONTEXT_SET_FAIL "Context '{1}' not applied."
#define STRING_CMD_CONTEXT_SHOW_EMPT "No context is currently applied."
#define STRING_CMD_CONTEXT_SHOW "Context '{1}' with filter '{2}' is currently applied."
#define STRING_CMD_CONTEXT_NON_SUCC "Context unset."
#define STRING_CMD_CONTEXT_NON_FAIL "Context not unset."
#define STRING_CMD_HCONTEXT_USAGE "Lists all supported contexts, for completion purposes"
#define STRING_CMD_CUSTOM_MISMATCH "Liczba kolumn i nagłówków nie zgadza się dla raportu '{1}'." #define STRING_CMD_CUSTOM_MISMATCH "Liczba kolumn i nagłówków nie zgadza się dla raportu '{1}'."
#define STRING_CMD_CUSTOM_SHOWN "{1} pokazanych" #define STRING_CMD_CUSTOM_SHOWN "{1} pokazanych"
#define STRING_CMD_CUSTOM_COUNT "1 zadanie" #define STRING_CMD_CUSTOM_COUNT "1 zadanie"
@@ -881,10 +901,6 @@
#define STRING_TDB2_UNDO_SYNCED "Nie można cofnąć zmian ponieważ zadanie zostało zsynchronizowane. Zmodyfikuj zadanie." #define STRING_TDB2_UNDO_SYNCED "Nie można cofnąć zmian ponieważ zadanie zostało zsynchronizowane. Zmodyfikuj zadanie."
#define STRING_TDB2_DIRTY_EXIT "Zamykanie z niezapisanymi zmianami w {1}" #define STRING_TDB2_DIRTY_EXIT "Zamykanie z niezapisanymi zmianami w {1}"
// utf8
#define STRING_UTF8_INVALID_CP_REP "Niepoprawna reprezentacja znaku."
#define STRING_UTF8_INVALID_CP "Niepoprawny znak Unicode."
// View // View
#define STRING_VIEW_TOO_SMALL "Raport ma minimalną szerokość {1} i nie mieści się w dostępnej przestrzeni {2}." #define STRING_VIEW_TOO_SMALL "Raport ma minimalną szerokość {1} i nie mieści się w dostępnej przestrzeni {2}."

View File

@@ -296,6 +296,7 @@
#define STRING_CMD_INFO_UNTIL "Até" #define STRING_CMD_INFO_UNTIL "Até"
#define STRING_CMD_INFO_MODIFICATION "Modificação" #define STRING_CMD_INFO_MODIFICATION "Modificação"
#define STRING_CMD_INFO_MODIFIED "Última modificação" #define STRING_CMD_INFO_MODIFIED "Última modificação"
#define STRING_CMD_INFO_VIRTUAL_TAGS "Virtual tags"
#define STRING_CMD_UNDO_USAGE "Reverte a mais recente modificação a uma tarefa" #define STRING_CMD_UNDO_USAGE "Reverte a mais recente modificação a uma tarefa"
#define STRING_CMD_UNDO_MODS "O comando undo não permite outras modificações simultâneas." #define STRING_CMD_UNDO_MODS "O comando undo não permite outras modificações simultâneas."
#define STRING_CMD_STATS_USAGE "Exibe estatísticas da base de dados de tarefas" #define STRING_CMD_STATS_USAGE "Exibe estatísticas da base de dados de tarefas"
@@ -561,6 +562,25 @@
#define STRING_CMD_CONFIG_NO_CHANGE "Nenhuma alteração efectuada." #define STRING_CMD_CONFIG_NO_CHANGE "Nenhuma alteração efectuada."
#define STRING_CMD_CONFIG_NO_NAME "Especifique o nome da configuração a modificar." #define STRING_CMD_CONFIG_NO_NAME "Especifique o nome da configuração a modificar."
#define STRING_CMD_HCONFIG_USAGE "Lista todas as configurações suportadas, para fins de terminação automática" #define STRING_CMD_HCONFIG_USAGE "Lista todas as configurações suportadas, para fins de terminação automática"
#define STRING_CMD_CONTEXT_USAGE "Set and define contexts (default filters)"
#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_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."
#define STRING_CMD_CONTEXT_DEL_FAIL "Context '{1}' not deleted."
#define STRING_CMD_CONTEXT_DEL_USAG "Context name needs to be specified."
#define STRING_CMD_CONTEXT_LIST_EMPT "No contexts defined."
#define STRING_CMD_CONTEXT_SET_NFOU "Context '{1}' not found."
#define STRING_CMD_CONTEXT_SET_SUCC "Context '{1}' set. Use 'task context none' to remove."
#define STRING_CMD_CONTEXT_SET_FAIL "Context '{1}' not applied."
#define STRING_CMD_CONTEXT_SHOW_EMPT "No context is currently applied."
#define STRING_CMD_CONTEXT_SHOW "Context '{1}' with filter '{2}' is currently applied."
#define STRING_CMD_CONTEXT_NON_SUCC "Context unset."
#define STRING_CMD_CONTEXT_NON_FAIL "Context not unset."
#define STRING_CMD_HCONTEXT_USAGE "Lists all supported contexts, for completion purposes"
#define STRING_CMD_CUSTOM_MISMATCH "O número de colunas e de rótulos não é o mesmo no relatório '{1}'." #define STRING_CMD_CUSTOM_MISMATCH "O número de colunas e de rótulos não é o mesmo no relatório '{1}'."
#define STRING_CMD_CUSTOM_SHOWN "{1} visiveis" #define STRING_CMD_CUSTOM_SHOWN "{1} visiveis"
#define STRING_CMD_CUSTOM_COUNT "1 tarefa" #define STRING_CMD_CUSTOM_COUNT "1 tarefa"
@@ -881,10 +901,6 @@
#define STRING_TDB2_UNDO_SYNCED "Não é possível reverter a alteração porque a tarefa já foi syncronizada. Em vez disso modifique a tarefa." #define STRING_TDB2_UNDO_SYNCED "Não é possível reverter a alteração porque a tarefa já foi syncronizada. Em vez disso modifique a tarefa."
#define STRING_TDB2_DIRTY_EXIT "Saindo com modificações por gravar de {1}" #define STRING_TDB2_DIRTY_EXIT "Saindo com modificações por gravar de {1}"
// utf8
#define STRING_UTF8_INVALID_CP_REP "Representação de 'codepoint' inválida."
#define STRING_UTF8_INVALID_CP "'Codepoint' Unicode inválido."
// View // View
#define STRING_VIEW_TOO_SMALL "O relatório tem uma largura mínima de {1} e não cabe na largura disponível {2}." #define STRING_VIEW_TOO_SMALL "O relatório tem uma largura mínima de {1} e não cabe na largura disponível {2}."

View File

@@ -160,54 +160,9 @@ std::string legacyCheckForDeprecatedColumns ()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void legacyAttributeMap (std::string& name) void legacyAttributeMap (std::string& name)
{ {
// TW-1274 // TW-1274, 2.4.0
if (name == "modification") if (name == "modification")
name = "modified"; name = "modified";
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void legacyValueMap (const std::string& name, std::string& value)
{
// 2014-07-03: One-time initialization value mapping.
static std::map <std::string, std::string> mapping;
if (mapping.size () == 0)
{
mapping["hrs"] = "hours";
mapping["hrs"] = "hours";
mapping["hr"] = "hours";
mapping["mins"] = "minutes";
mapping["mnths"] = "months";
mapping["mths"] = "months";
mapping["mth"] = "months";
mapping["mos"] = "months";
mapping["m"] = "months";
mapping["qrtrs"] = "quarters";
mapping["qtrs"] = "quarters";
mapping["qtr"] = "quarters";
mapping["secs"] = "seconds";
mapping["sec"] = "seconds";
mapping["s"] = "seconds";
mapping["wks"] = "weeks";
mapping["wk"] = "weeks";
mapping["yrs"] = "years";
mapping["yr"] = "years";
}
if (name == "recur")
{
std::size_t letter = value.find_first_not_of ("0123456789.");
if (letter == std::string::npos)
letter = 0;
std::map <std::string, std::string>::iterator i = mapping.find (value.substr (letter));
if (i != mapping.end ())
{
if (letter)
value = value.substr (0, letter) + i->second;
else
value = i->second;
}
}
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -86,7 +86,6 @@ std::string legacyCheckForDeprecatedColor ();
std::string legacyCheckForDeprecatedVariables (); std::string legacyCheckForDeprecatedVariables ();
std::string legacyCheckForDeprecatedColumns (); std::string legacyCheckForDeprecatedColumns ();
void legacyAttributeMap (std::string&); void legacyAttributeMap (std::string&);
void legacyValueMap (const std::string&, std::string&);
// list template // list template
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@@ -424,14 +424,6 @@ std::string lowerCase (const std::string& input)
return output; return output;
} }
////////////////////////////////////////////////////////////////////////////////
std::string upperCase (const std::string& input)
{
std::string output = input;
std::transform (output.begin (), output.end (), output.begin (), toupper);
return output;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::string ucFirst (const std::string& input) std::string ucFirst (const std::string& input)
{ {

View File

@@ -45,7 +45,6 @@ void join (std::string&, const std::string&, const std::vector<std::string>&);
void join (std::string&, const std::string&, const std::vector<int>&); void join (std::string&, const std::string&, const std::vector<int>&);
std::string commify (const std::string&); std::string commify (const std::string&);
std::string lowerCase (const std::string&); std::string lowerCase (const std::string&);
std::string upperCase (const std::string&);
std::string ucFirst (const std::string&); std::string ucFirst (const std::string&);
const std::string str_replace (std::string&, const std::string&, const std::string&); const std::string str_replace (std::string&, const std::string&, const std::string&);
const std::string str_replace (const std::string&, const std::string&, const std::string&); const std::string str_replace (const std::string&, const std::string&, const std::string&);

View File

@@ -26,9 +26,7 @@
#include <cmake.h> #include <cmake.h>
#include <string> #include <string>
#include <text.h>
#include <utf8.h> #include <utf8.h>
#include <i18n.h>
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Converts '0' -> 0 // Converts '0' -> 0
@@ -66,8 +64,6 @@ unsigned int utf8_codepoint (const std::string& input)
XDIGIT (input[2]) << 4 | XDIGIT (input[2]) << 4 |
XDIGIT (input[3]); XDIGIT (input[3]);
} }
else
throw std::string (STRING_UTF8_INVALID_CP_REP);
return codepoint; return codepoint;
} }
@@ -117,13 +113,12 @@ unsigned int utf8_next_char (const std::string& input, std::string::size_type& i
// http://en.wikipedia.org/wiki/UTF-8 // http://en.wikipedia.org/wiki/UTF-8
std::string utf8_character (unsigned int codepoint) std::string utf8_character (unsigned int codepoint)
{ {
char sequence[5]; char sequence[5] = {0};
// 0xxxxxxx -> 0xxxxxxx // 0xxxxxxx -> 0xxxxxxx
if (codepoint < 0x80) if (codepoint < 0x80)
{ {
sequence[0] = codepoint; sequence[0] = codepoint;
sequence[1] = 0;
} }
// 00000yyy yyxxxxxx -> 110yyyyy 10xxxxxx // 00000yyy yyxxxxxx -> 110yyyyy 10xxxxxx
@@ -131,7 +126,6 @@ std::string utf8_character (unsigned int codepoint)
{ {
sequence[0] = 0xC0 | (codepoint & 0x7C0) >> 6; sequence[0] = 0xC0 | (codepoint & 0x7C0) >> 6;
sequence[1] = 0x80 | (codepoint & 0x3F); sequence[1] = 0x80 | (codepoint & 0x3F);
sequence[2] = 0;
} }
// zzzzyyyy yyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx // zzzzyyyy yyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx
@@ -140,7 +134,6 @@ std::string utf8_character (unsigned int codepoint)
sequence[0] = 0xE0 | (codepoint & 0xF000) >> 12; sequence[0] = 0xE0 | (codepoint & 0xF000) >> 12;
sequence[1] = 0x80 | (codepoint & 0xFC0) >> 6; sequence[1] = 0x80 | (codepoint & 0xFC0) >> 6;
sequence[2] = 0x80 | (codepoint & 0x3F); sequence[2] = 0x80 | (codepoint & 0x3F);
sequence[3] = 0;
} }
// 000wwwzz zzzzyyyy yyxxxxxx -> 11110www 10zzzzzz 10yyyyyy 10xxxxxx // 000wwwzz zzzzyyyy yyxxxxxx -> 11110www 10zzzzzz 10yyyyyy 10xxxxxx
@@ -150,12 +143,8 @@ std::string utf8_character (unsigned int codepoint)
sequence[1] = 0x80 | (codepoint & 0x03F000) >> 12; sequence[1] = 0x80 | (codepoint & 0x03F000) >> 12;
sequence[2] = 0x80 | (codepoint & 0x0FC0) >> 6; sequence[2] = 0x80 | (codepoint & 0x0FC0) >> 6;
sequence[3] = 0x80 | (codepoint & 0x3F); sequence[3] = 0x80 | (codepoint & 0x3F);
sequence[4] = 0;
} }
else
throw std::string (STRING_UTF8_INVALID_CP);
sequence[4] = '\0';
return std::string (sequence); return std::string (sequence);
} }

View File

@@ -299,9 +299,11 @@ int execute (
if (dup2 (pin[0], STDIN_FILENO) == -1) if (dup2 (pin[0], STDIN_FILENO) == -1)
throw std::string (std::strerror (errno)); throw std::string (std::strerror (errno));
close (pin[0]);
if (dup2 (pout[1], STDOUT_FILENO) == -1) if (dup2 (pout[1], STDOUT_FILENO) == -1)
throw std::string (std::strerror (errno)); throw std::string (std::strerror (errno));
close (pout[1]);
char** argv = new char* [args.size () + 2]; char** argv = new char* [args.size () + 2];
argv[0] = (char*) executable.c_str (); argv[0] = (char*) executable.c_str ();

1
test/.gitignore vendored
View File

@@ -53,7 +53,6 @@ variant_partial.t
variant_subtract.t variant_subtract.t
variant_xor.t variant_xor.t
view.t view.t
width.t
json_test json_test

View File

@@ -8,8 +8,8 @@ include_directories (${CMAKE_SOURCE_DIR}
set (test_SRCS autocomplete.t color.t config.t date.t directory.t dom.t set (test_SRCS autocomplete.t color.t config.t date.t directory.t dom.t
file.t i18n.t json.t list.t msg.t nibbler.t path.t rx.t t.t t2.t file.t i18n.t json.t list.t msg.t nibbler.t path.t rx.t t.t t2.t
t3.t tdb2.t text.t utf8.t util.t view.t width.t json_test t3.t tdb2.t text.t utf8.t util.t view.t json_test lexer.t
iso8601d.t iso8601p.t duration.t lexer.t variant_add.t iso8601d.t iso8601p.t duration.t variant_add.t
variant_and.t variant_cast.t variant_divide.t variant_equal.t variant_and.t variant_cast.t variant_divide.t variant_equal.t
variant_exp.t variant_gt.t variant_gte.t variant_inequal.t variant_exp.t variant_gt.t variant_gte.t variant_inequal.t
variant_lt.t variant_lte.t variant_match.t variant_math.t variant_lt.t variant_lte.t variant_match.t variant_math.t

View File

@@ -1,68 +1,80 @@
#! /usr/bin/env perl #!/usr/bin/env python2.7
################################################################################ # -*- coding: utf-8 -*-
## ###############################################################################
## Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez. #
## # 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 # Permission is hereby granted, free of charge, to any person obtaining a copy
## in the Software without restriction, including without limitation the rights # of this software and associated documentation files (the "Software"), to deal
## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # in the Software without restriction, including without limitation the rights
## copies of the Software, and to permit persons to whom the Software is # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
## furnished to do so, subject to the following conditions: # 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 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, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
## SOFTWARE. # 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 #
## # http://www.opensource.org/licenses/mit-license.php
################################################################################ #
###############################################################################
use strict; import sys
use warnings; import os
use Test::More tests => 5; import unittest
# Ensure python finds the local simpletap module
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
# Ensure environment has no influence. from basetest import Task, TestCase
delete $ENV{'TASKDATA'};
delete $ENV{'TASKRC'};
# Create the rc file.
if (open my $fh, '>', 'alias.rc')
{
print $fh "data.location=.\n",
"alias.foo=_projects\n",
"alias.bar=foo\n",
"alias.baz=bar\n",
"alias.qux=baz\n";
close $fh;
}
# Add a task with a certain project, then access that task via aliases. class TestAlias(TestCase):
qx{../src/task rc:alias.rc add project:ALIAS foo 2>&1}; def setUp(self):
"""Executed before each test in the class"""
# Used to initialize objects that should be re-initialized or
# re-created for each individual test
self.t = Task()
my $output = qx{../src/task rc:alias.rc _projects 2>&1}; self.t.config("alias.foo", "_projects")
like ($output, qr/ALIAS/, 'task _projects -> ALIAS'); self.t.config("alias.bar", "foo")
self.t.config("alias.baz", "bar")
self.t.config("alias.qux", "baz")
$output = qx{../src/task rc:alias.rc qux 2>&1}; def test_alias_to_project(self):
like ($output, qr/ALIAS/, 'task foo -> _projects -> ALIAS'); """Access a project via aliases"""
$output = qx{../src/task rc:alias.rc bar 2>&1}; expected = "ALIAS"
like ($output, qr/ALIAS/, 'task bar -> foo -> _projects -> ALIAS'); self.t(("add", "project:{0}".format(expected), "foo"))
$output = qx{../src/task rc:alias.rc baz 2>&1}; code, out, err = self.t(("_projects",))
like ($output, qr/ALIAS/, 'task baz -> bar -> foo -> _projects -> ALIAS'); self.assertIn(expected, out,
msg="task _projects -> ALIAS")
$output = qx{../src/task rc:alias.rc qux 2>&1}; code, out, err = self.t(("foo",))
like ($output, qr/ALIAS/, 'task qux -> baz -> bar -> foo -> _projects -> ALIAS'); self.assertIn(expected, out,
msg="task foo -> _projects > ALIAS")
# Cleanup. code, out, err = self.t(("bar",))
unlink qw(pending.data completed.data undo.data backlog.data alias.rc); self.assertIn(expected, out,
exit 0; msg="task bar -> foo > _projects > ALIAS")
code, out, err = self.t(("baz",))
self.assertIn(expected, out,
msg="task baz -> bar > foo > _projects > ALIAS")
code, out, err = self.t(("qux",))
self.assertIn(expected, out,
msg="task qux -> baz > bar > foo > _projects > ALIAS")
if __name__ == "__main__":
from simpletap import TAPTestRunner
unittest.main(testRunner=TAPTestRunner())
# vim: ai sts=4 et sw=4

View File

@@ -1,121 +1,135 @@
#! /usr/bin/env perl #!/usr/bin/env python2.7
################################################################################ # -*- coding: utf-8 -*-
## ###############################################################################
## 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
##
################################################################################
use strict;
use warnings;
use Test::More tests => 22;
# Ensure environment has no influence.
delete $ENV{'TASKDATA'};
delete $ENV{'TASKRC'};
# Create the rc file.
if (open my $fh, '>', 'annotate.rc')
{
# Note: Use 'rrr' to guarantee a unique report name. Using 'r' conflicts
# with 'recurring'.
print $fh "data.location=.\n",
"confirmation=off\n",
"report.rrr.description=rrr\n",
"report.rrr.columns=id,description\n",
"report.rrr.sort=id+\n",
"color=off\n",
"dateformat=m/d/Y\n";
close $fh;
}
# Add four tasks, annotate one three times, one twice, one just once and one none.
qx{../src/task rc:annotate.rc add one 2>&1};
qx{../src/task rc:annotate.rc add two 2>&1};
qx{../src/task rc:annotate.rc add three 2>&1};
qx{../src/task rc:annotate.rc add four 2>&1};
qx{../src/task rc:annotate.rc 1 annotate foo1 2>&1};
qx{../src/task rc:annotate.rc 1 annotate foo2 2>&1};
qx{../src/task rc:annotate.rc 1 annotate foo3 2>&1};
qx{../src/task rc:annotate.rc 2 annotate bar1 2>&1};
qx{../src/task rc:annotate.rc 2 annotate bar2 2>&1};
qx{../src/task rc:annotate.rc 3 annotate baz1 2>&1};
my $output = qx{../src/task rc:annotate.rc rrr 2>&1};
# ID Description
# -- -------------------------------
# 1 one
# 3/24/2009 foo1
# 3/24/2009 foo2
# 3/24/2009 foo3
# 2 two
# 3/24/2009 bar1
# 3/24/2009 bar2
# 3 three
# 3/24/2009 baz1
# 4 four
# #
# 4 tasks # 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
#
###############################################################################
like ($output, qr/1 one/, 'task 1'); # 2 import sys
like ($output, qr/2 two/, 'task 2'); import os
like ($output, qr/3 three/, 'task 3'); import unittest
like ($output, qr/4 four/, 'task 4'); # Ensure python finds the local simpletap module
like ($output, qr/one.+\d{1,2}\/\d{1,2}\/\d{4}\s+foo1/ms, 'full - first annotation task 1'); sys.path.append(os.path.dirname(os.path.abspath(__file__)))
like ($output, qr/foo1.+\d{1,2}\/\d{1,2}\/\d{4}\s+foo2/ms, 'full - second annotation task 1');
like ($output, qr/foo2.+\d{1,2}\/\d{1,2}\/\d{4}\s+foo3/ms, 'full - third annotation task 1');
like ($output, qr/two.+\d{1,2}\/\d{1,2}\/\d{4}\s+bar1/ms, 'full - first annotation task 2');
like ($output, qr/bar1.+\d{1,2}\/\d{1,2}\/\d{4}\s+bar2/ms, 'full - second annotation task 2');
like ($output, qr/three.+\d{1,2}\/\d{1,2}\/\d{4}\s+baz1/ms,'full - first annotation task 3');
like ($output, qr/4 tasks/, 'count');
if (open my $fh, '>', 'annotate2.rc') from basetest import Task, TestCase
{
# Note: Use 'rrr' to guarantee a unique report name. Using 'r' conflicts
# with 'recurring'.
print $fh "data.location=.\n",
"confirmation=off\n",
"report.rrr.description=rrr\n",
"report.rrr.columns=id,description\n",
"report.rrr.sort=id+\n",
"dateformat.annotation=yMD HNS\n";
close $fh;
}
$output = qx{../src/task rc:annotate2.rc rrr 2>&1};
like ($output, qr/1 one/, 'task 1'); # 14
like ($output, qr/2 two/, 'task 2');
like ($output, qr/3 three/, 'task 3');
like ($output, qr/4 four/, 'task 4');
like ($output, qr/one.+\d{1,6}\s+\d{1,6}\s+foo1/ms, 'dateformat - first annotation task 1'); #18
like ($output, qr/foo1.+\d{1,6}\s+\d{1,6}\s+foo2/ms, 'dateformat - second annotation task 1');
like ($output, qr/foo2.+\d{1,6}\s+\d{1,6}\s+foo3/ms, 'dateformat - third annotation task 1');
like ($output, qr/two.+\d{1,6}\s+\d{1,6}\s+bar1/ms, 'dateformat - first annotation task 2');
like ($output, qr/bar1.+\d{1,6}\s+\d{1,6}\s+bar2/ms, 'dateformat - second annotation task 2');
like ($output, qr/three.+\d{1,6}\s+\d{1,6}\s+baz1/ms,'dateformat - first annotation task 3');
like ($output, qr/4 tasks/, 'count');
# Cleanup. class TestAnnotate(TestCase):
unlink qw(pending.data completed.data undo.data backlog.data annotate.rc annotate2.rc); def setUp(self):
exit 0; self.t = Task()
# ID Description
# -- -------------------------------
# 1 one
# 3/24/2009 foo1
# 3/24/2009 foo2
# 3/24/2009 foo3
# 2 two
# 3/24/2009 bar1
# 3/24/2009 bar2
# 3 three
# 3/24/2009 baz1
# 4 four
#
# 4 tasks
self.t(("add", "one"))
self.t(("add", "two"))
self.t(("add", "three"))
self.t(("add", "four"))
self.t(("1", "annotate", "foo1"))
self.t(("1", "annotate", "foo2"))
self.t(("1", "annotate", "foo3"))
self.t(("2", "annotate", "bar1"))
self.t(("2", "annotate", "bar2"))
self.t(("3", "annotate", "baz1"))
def assertTasksExist(self, out):
self.assertIn("1 one", out)
self.assertIn("2 two", out)
self.assertIn("3 three", out)
self.assertIn("4 four", out)
self.assertIn("4 tasks", out)
def test_annotate(self):
"""Testing annotations in reports"""
# NOTE: Use 'rrr' to guarantee a unique report name. Using 'r'
# conflicts with 'recurring'.
self.t.config("report.rrr.description", "rrr")
self.t.config("report.rrr.columns", "id,description")
self.t.config("report.rrr.sort", "id+")
self.t.config("dateformat", "m/d/Y")
self.t.config("color", "off")
code, out, err = self.t(("rrr",))
self.assertTasksExist(out)
self.assertRegexpMatches(out, "one\n.+\d{1,2}/\d{1,2}/\d{4}\s+foo1",
msg='full - first annotation task 1')
self.assertRegexpMatches(out, "foo1\n.+\d{1,2}/\d{1,2}/\d{4}\s+foo2",
msg='full - first annotation task 1')
self.assertRegexpMatches(out, "foo2\n.+\d{1,2}/\d{1,2}/\d{4}\s+foo3",
msg='full - first annotation task 1')
self.assertRegexpMatches(out, "two\n.+\d{1,2}/\d{1,2}/\d{4}\s+bar1",
msg='full - first annotation task 1')
self.assertRegexpMatches(out, "bar1\n.+\d{1,2}/\d{1,2}/\d{4}\s+bar2",
msg='full - first annotation task 1')
self.assertRegexpMatches(out, "three\n.+\d{1,2}/\d{1,2}/\d{4}\s+baz1",
msg='full - first annotation task 1')
def test_annotate_dateformat(self):
"""Testing annotations in reports using dateformat.annotation"""
# NOTE: Use 'rrr' to guarantee a unique report name. Using 'r'
# conflicts with 'recurring'.
self.t.config("report.rrr.description", "rrr")
self.t.config("report.rrr.columns", "id,description")
self.t.config("report.rrr.sort", "id+")
self.t.config("dateformat.annotation", "yMD HNS")
code, out, err = self.t(("rrr",))
self.assertTasksExist(out)
self.assertRegexpMatches(out, "one\n.+\d{1,6}\s+\d{1,6}\s+foo1",
msg="dateformat - first annotation task 1")
self.assertRegexpMatches(out, "foo1\n.+\d{1,6}\s+\d{1,6}\s+foo2",
msg="dateformat - second annotation task 1")
self.assertRegexpMatches(out, "foo2\n.+\d{1,6}\s+\d{1,6}\s+foo3",
msg="dateformat - third annotation task 1")
self.assertRegexpMatches(out, "two\n.+\d{1,6}\s+\d{1,6}\s+bar1",
msg="dateformat - first annotation task 2")
self.assertRegexpMatches(out, "bar1\n.+\d{1,6}\s+\d{1,6}\s+bar2",
msg="dateformat - second annotation task 2")
self.assertRegexpMatches(out, "three\n.+\d{1,6}\s+\d{1,6}\s+baz1",
msg="dateformat - first annotation task 3")
if __name__ == "__main__":
from simpletap import TAPTestRunner
unittest.main(testRunner=TAPTestRunner())
# vim: ai sts=4 et sw=4

View File

@@ -1,59 +1,71 @@
#! /usr/bin/env perl #!/usr/bin/env python2.7
################################################################################ # -*- coding: utf-8 -*-
## ###############################################################################
## Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez. #
## # 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 # Permission is hereby granted, free of charge, to any person obtaining a copy
## in the Software without restriction, including without limitation the rights # of this software and associated documentation files (the "Software"), to deal
## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # in the Software without restriction, including without limitation the rights
## copies of the Software, and to permit persons to whom the Software is # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
## furnished to do so, subject to the following conditions: # 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 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, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
## SOFTWARE. # 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 #
## # http://www.opensource.org/licenses/mit-license.php
################################################################################ #
###############################################################################
use strict; import sys
use warnings; import os
use Test::More tests => 4; import unittest
# Ensure python finds the local simpletap module
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
# Ensure environment has no influence. from basetest import Task, TestCase
delete $ENV{'TASKDATA'};
delete $ENV{'TASKRC'};
# Create the rc file.
if (open my $fh, '>', 'append.rc')
{
print $fh "data.location=.\n",
"confirmation=off\n";
close $fh;
}
# Add a task, then append more description. class TestAppend(TestCase):
qx{../src/task rc:append.rc add foo 2>&1}; def setUp(self):
my $output = qx{../src/task rc:append.rc 1 append bar 2>&1}; """Executed before each test in the class"""
like ($output, qr/^Appended 1 task.$/m, 'append worked'); self.t = Task()
$output = qx{../src/task rc:append.rc info 1 2>&1}; self.t(("add", "foo"))
like ($output, qr/Description\s+foo\sbar\n/, 'append worked');
# Should cause an error when nothing is appended. def test_append(self):
$output = qx{../src/task rc:append.rc 1 append 2>&1}; """Add a task and then append more description"""
like ($output, qr/^Additional text must be provided.$/m, 'blank append failed'); code, out, err = self.t(("1", "append", "bar"))
unlike ($output, qr/^Appended 1 task.$/, 'blank append failed');
# Cleanup. expected = "Appended 1 task."
unlink qw(pending.data completed.data undo.data backlog.data append.rc); self.assertIn(expected, out)
exit 0;
code, out, err = self.t(("info", "1"))
expected = "Description\s+foo\sbar\n"
self.assertRegexpMatches(out, expected)
def test_append_error_on_empty(self):
"""Should cause an error when nothing is appended"""
code, out, err = self.t.runError(("1", "append"))
expected = "Additional text must be provided."
self.assertIn(expected, err)
notexpected = "Appended 1 task."
self.assertNotIn(notexpected, out)
if __name__ == "__main__":
from simpletap import TAPTestRunner
unittest.main(testRunner=TAPTestRunner())
# vim: ai sts=4 et sw=4

View File

@@ -1,72 +1,73 @@
#! /usr/bin/env perl #!/usr/bin/env python2.7
################################################################################ # -*- coding: utf-8 -*-
## ###############################################################################
## Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez. #
## # 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 # Permission is hereby granted, free of charge, to any person obtaining a copy
## in the Software without restriction, including without limitation the rights # of this software and associated documentation files (the "Software"), to deal
## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # in the Software without restriction, including without limitation the rights
## copies of the Software, and to permit persons to whom the Software is # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
## furnished to do so, subject to the following conditions: # 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 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, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
## SOFTWARE. # 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 #
## # http://www.opensource.org/licenses/mit-license.php
################################################################################ #
###############################################################################
use strict; import sys
use warnings; import os
use Test::More tests => 8; import unittest
# Ensure python finds the local simpletap module
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
# Ensure environment has no influence. from basetest import Task, TestCase
delete $ENV{'TASKDATA'};
delete $ENV{'TASKRC'};
use File::Basename;
my $ut = basename ($0);
my $rc = $ut . '.rc';
# Create the rc file. class TestIDPosition(TestCase):
if (open my $fh, '>', $rc) def setUp(self):
{ """Executed before each test in the class"""
print $fh "data.location=.\n", self.t = Task()
"confirmation=off\n";
close $fh;
}
# Test id before command, and id after command. self.t(("add", "one"))
qx{../src/task rc:$rc add one 2>&1}; self.t(("add", "two"))
qx{../src/task rc:$rc add two 2>&1}; self.t(("add", "three"))
qx{../src/task rc:$rc add three 2>&1};
my $output = qx{../src/task rc:$rc list 2>&1};
like ($output, qr/one/, "$ut: task 1 added");
like ($output, qr/two/, "$ut: task 2 added");
like ($output, qr/three/, "$ut: task 3 added");
$output = qx{../src/task rc:$rc 1 done 2>&1}; def test_id(self):
like ($output, qr/^Completed 1 task\.$/ms, "$ut: COMMAND after ID"); """Test id before and after command"""
code, out, err = self.t(("list",))
$output = qx{../src/task rc:$rc rc.allow.empty.filter:yes done 2 2>&1}; self.assertIn("one", out)
like ($output, qr/^Command prevented from running.$/ms, "$ut: ID after COMMAND, allowing empty filter"); self.assertIn("two", out)
unlike ($output, qr/^Completed 1 task\.$/ms, "$ut: ID after COMMAND, allowing empty filter"); self.assertIn("three", out)
$output = qx{../src/task rc:$rc rc.allow.empty.filter:no done 2 2>&1}; code, out, err = self.t(("1", "done"))
like ($output, qr/^You did not specify a filter, and with the 'allow\.empty\.filter' value, no action is taken\.$/ms, self.assertIn("Completed 1 task.", out)
"$ut: ID after COMMAND, disallowing empty filter");
unlike ($output, qr/^Completed 1 task\.$/ms, "$ut: ID after COMMAND, disallowing empty filter");
# Cleanup. filter = "rc.allow.empty.filter:yes"
unlink qw(pending.data completed.data undo.data backlog.data), $rc; code, out, err = self.t.runError((filter, "done", "2"))
exit 0; self.assertIn("Command prevented from running.", err)
self.assertNotIn("Completed 1 task.", out)
filter = "rc.allow.empty.filter:no"
code, out, err = self.t.runError((filter, "done", "2"))
self.assertIn("You did not specify a filter, and with the "
"'allow.empty.filter' value, no action is taken.", err)
self.assertNotIn("Completed 1 task.", out)
if __name__ == "__main__":
from simpletap import TAPTestRunner
unittest.main(testRunner=TAPTestRunner())
# vim: ai sts=4 et sw=4

View File

@@ -1,78 +0,0 @@
#! /usr/bin/env perl
################################################################################
##
## 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
##
################################################################################
use strict;
use warnings;
use Test::More tests => 5;
# Ensure environment has no influence.
delete $ENV{'TASKDATA'};
delete $ENV{'TASKRC'};
use File::Basename;
my $ut = basename ($0);
my $rc = $ut . '.rc';
# Create the rc file.
if (open my $fh, '>', $rc)
{
print $fh "data.location=.\n",
"confirmation=off\n";
close $fh;
}
# Test 'done' with en-passant changes.
qx{../src/task rc:$rc add one 2>&1};
qx{../src/task rc:$rc add two 2>&1};
qx{../src/task rc:$rc add three 2>&1};
qx{../src/task rc:$rc add four 2>&1};
qx{../src/task rc:$rc add five 2>&1};
qx{../src/task rc:$rc 1 done oneanno 2>&1};
my $output = qx{../src/task rc:$rc 1 info 2>&1};
like ($output, qr/oneanno/, "$ut: done enpassant anno");
qx{../src/task rc:$rc 2 done /two/TWO/ 2>&1};
$output = qx{../src/task rc:$rc 2 info 2>&1};
like ($output, qr/Description\s+TWO/, "$ut: done enpassant subst");
qx{../src/task rc:$rc 3 done +threetag 2>&1};
$output = qx{../src/task rc:$rc 3 info 2>&1};
like ($output, qr/Tags\s+threetag/, "$ut: done enpassant tag");
qx{../src/task rc:$rc 4 done pri:H 2>&1};
$output = qx{../src/task rc:$rc 4 info 2>&1};
like ($output, qr/Priority\s+H/, "$ut: done enpassant priority");
qx{../src/task rc:$rc 5 done pro:A 2>&1};
$output = qx{../src/task rc:$rc 5 info 2>&1};
like ($output, qr/Project\s+A/, "$ut: done enpassant project");
# Cleanup.
unlink qw(pending.data completed.data undo.data backlog.data), $rc;
exit 0;

View File

@@ -1,74 +0,0 @@
#! /usr/bin/env perl
################################################################################
##
## 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
##
################################################################################
use strict;
use warnings;
use Test::More tests => 5;
# Ensure environment has no influence.
delete $ENV{'TASKDATA'};
delete $ENV{'TASKRC'};
# Create the rc file.
if (open my $fh, '>', 'args.rc')
{
print $fh "data.location=.\n",
"confirmation=off\n";
close $fh;
}
# Test 'delete' with en-passant changes.
qx{../src/task rc:args.rc add one 2>&1};
qx{../src/task rc:args.rc add two 2>&1};
qx{../src/task rc:args.rc add three 2>&1};
qx{../src/task rc:args.rc add four 2>&1};
qx{../src/task rc:args.rc add five 2>&1};
qx{../src/task rc:args.rc 1 delete oneanno 2>&1};
my $output = qx{../src/task rc:args.rc 1 info 2>&1};
like ($output, qr/oneanno/, 'delete enpassant anno');
qx{../src/task rc:args.rc 2 delete /two/TWO/ 2>&1};
$output = qx{../src/task rc:args.rc 2 info 2>&1};
like ($output, qr/Description\s+TWO/, 'delete enpassant subst');
qx{../src/task rc:args.rc 3 delete +threetag 2>&1};
$output = qx{../src/task rc:args.rc 3 info 2>&1};
like ($output, qr/Tags\s+threetag/, 'delete enpassant tag');
qx{../src/task rc:args.rc 4 delete pri:H 2>&1};
$output = qx{../src/task rc:args.rc 4 info 2>&1};
like ($output, qr/Priority\s+H/, 'delete enpassant priority');
qx{../src/task rc:args.rc 5 delete pro:A 2>&1};
$output = qx{../src/task rc:args.rc 5 info 2>&1};
like ($output, qr/Project\s+A/, 'delete enpassant project');
# Cleanup.
unlink qw(pending.data completed.data undo.data backlog.data args.rc);
exit 0;

View File

@@ -1,74 +0,0 @@
#! /usr/bin/env perl
################################################################################
##
## 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
##
################################################################################
use strict;
use warnings;
use Test::More tests => 5;
# Ensure environment has no influence.
delete $ENV{'TASKDATA'};
delete $ENV{'TASKRC'};
# Create the rc file.
if (open my $fh, '>', 'args.rc')
{
print $fh "data.location=.\n",
"confirmation=off\n";
close $fh;
}
# Test 'start' with en-passant changes.
qx{../src/task rc:args.rc add one 2>&1};
qx{../src/task rc:args.rc add two 2>&1};
qx{../src/task rc:args.rc add three 2>&1};
qx{../src/task rc:args.rc add four 2>&1};
qx{../src/task rc:args.rc add five 2>&1};
qx{../src/task rc:args.rc 1 start oneanno 2>&1};
my $output = qx{../src/task rc:args.rc 1 info 2>&1};
like ($output, qr/oneanno/, 'start enpassant anno');
qx{../src/task rc:args.rc 2 start /two/TWO/ 2>&1};
$output = qx{../src/task rc:args.rc 2 info 2>&1};
like ($output, qr/Description\s+TWO/, 'start enpassant subst');
qx{../src/task rc:args.rc 3 start +threetag 2>&1};
$output = qx{../src/task rc:args.rc 3 info 2>&1};
like ($output, qr/Tags\s+threetag/, 'start enpassant tag');
qx{../src/task rc:args.rc 4 start pri:H 2>&1};
$output = qx{../src/task rc:args.rc 4 info 2>&1};
like ($output, qr/Priority\s+H/, 'start enpassant priority');
qx{../src/task rc:args.rc 5 start pro:A 2>&1};
$output = qx{../src/task rc:args.rc 5 info 2>&1};
like ($output, qr/Project\s+A/, 'start enpassant project');
# Cleanup.
unlink qw(pending.data completed.data undo.data backlog.data args.rc);
exit 0;

View File

@@ -1,80 +0,0 @@
#! /usr/bin/env perl
################################################################################
##
## 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
##
################################################################################
use strict;
use warnings;
use Test::More tests => 5;
# Ensure environment has no influence.
delete $ENV{'TASKDATA'};
delete $ENV{'TASKRC'};
# Create the rc file.
if (open my $fh, '>', 'args.rc')
{
print $fh "data.location=.\n",
"confirmation=off\n";
close $fh;
}
# Test 'stop' with en-passant changes.
qx{../src/task rc:args.rc add one 2>&1};
qx{../src/task rc:args.rc add two 2>&1};
qx{../src/task rc:args.rc add three 2>&1};
qx{../src/task rc:args.rc add four 2>&1};
qx{../src/task rc:args.rc add five 2>&1};
qx{../src/task rc:args.rc 1 start 2>&1};
qx{../src/task rc:args.rc 2 start 2>&1};
qx{../src/task rc:args.rc 3 start 2>&1};
qx{../src/task rc:args.rc 4 start 2>&1};
qx{../src/task rc:args.rc 5 start 2>&1};
qx{../src/task rc:args.rc 1 stop oneanno 2>&1};
my $output = qx{../src/task rc:args.rc 1 info 2>&1};
like ($output, qr/oneanno/, 'stop enpassant anno');
qx{../src/task rc:args.rc 2 stop /two/TWO/ 2>&1};
$output = qx{../src/task rc:args.rc 2 info 2>&1};
like ($output, qr/Description\s+TWO/, 'stop enpassant subst');
qx{../src/task rc:args.rc 3 stop +threetag 2>&1};
$output = qx{../src/task rc:args.rc 3 info 2>&1};
like ($output, qr/Tags\s+threetag/, 'stop enpassant tag');
qx{../src/task rc:args.rc 4 stop pri:H 2>&1};
$output = qx{../src/task rc:args.rc 4 info 2>&1};
like ($output, qr/Priority\s+H/, 'stop enpassant priority');
qx{../src/task rc:args.rc 5 stop pro:A 2>&1};
$output = qx{../src/task rc:args.rc 5 info 2>&1};
like ($output, qr/Project\s+A/, 'stop enpassant project');
# Cleanup.
unlink qw(pending.data completed.data undo.data backlog.data args.rc);
exit 0;

View File

@@ -1,68 +1,104 @@
#! /usr/bin/env perl #!/usr/bin/env python2.7
################################################################################ # -*- coding: utf-8 -*-
## ###############################################################################
## Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez. #
## # 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 # Permission is hereby granted, free of charge, to any person obtaining a copy
## in the Software without restriction, including without limitation the rights # of this software and associated documentation files (the "Software"), to deal
## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # in the Software without restriction, including without limitation the rights
## copies of the Software, and to permit persons to whom the Software is # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
## furnished to do so, subject to the following conditions: # 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 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, # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
## SOFTWARE. # 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 #
## # http://www.opensource.org/licenses/mit-license.php
################################################################################ #
###############################################################################
use strict; import sys
use warnings; import os
use Test::More tests => 5; import unittest
# Ensure python finds the local simpletap module
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
# Ensure environment has no influence. from basetest import Task, TestCase
delete $ENV{'TASKDATA'};
delete $ENV{'TASKRC'};
# Create the rc file.
if (open my $fh, '>', 'args.rc')
{
print $fh "data.location=.\n",
"confirmation=no\n";
close $fh;
}
# Test the -- argument. class TestArgs(TestCase):
qx{../src/task rc:args.rc add project:p pri:H +tag foo 2>&1}; def setUp(self):
my $output = qx{../src/task rc:args.rc info 1 2>&1}; """Executed before each test in the class"""
like ($output, qr/Description\s+foo\n/ms, 'task add project:p pri:H +tag foo'); self.t = Task()
qx{../src/task rc:args.rc 1 modify project:p pri:H +tag -- foo 2>&1}; def test_dash_dash_argument(self):
$output = qx{../src/task rc:args.rc info 1 2>&1}; """Test the -- argument"""
like ($output, qr/Description\s+foo\n/ms, 'task 1 modify project:p pri:H +tag -- foo'); self.t(("add", "project:p", "pri:H", "+tag", "foo"))
qx{../src/task rc:args.rc 1 modify project:p pri:H -- +tag foo 2>&1}; code, out, err = self.t(("info", "1"))
$output = qx{../src/task rc:args.rc info 1 2>&1}; self.assertRegexpMatches(
like ($output, qr/Description\s+\+tag\sfoo\n/ms, 'task 1 modify project:p pri:H -- +tag foo'); out,
"Description\s+foo\n",
msg='add project:p pri:H +tag foo',
)
qx{../src/task rc:args.rc 1 modify project:p -- pri:H +tag foo 2>&1}; self.t(("1", "modify", "project:p", "pri:H", "+tag", "--", "foo"))
$output = qx{../src/task rc:args.rc info 1 2>&1};
like ($output, qr/Description\s+pri:H\s\+tag\sfoo\n/ms, 'task 1 modify project:p -- pri:H +tag foo');
qx{../src/task rc:args.rc 1 modify -- project:p pri:H +tag foo 2>&1}; code, out, err = self.t(("info", "1"))
$output = qx{../src/task rc:args.rc info 1 2>&1}; self.assertRegexpMatches(
like ($output, qr/Description\s+project:p\spri:H\s\+tag\sfoo\n/ms, 'task 1 modify -- project:p pri:H +tag foo'); out,
"Description\s+foo\n",
msg='1 modify project:p pri:H +tag -- foo',
)
# Cleanup. self.t(("1", "modify", "project:p", "pri:H", "--", "+tag", "foo"))
unlink qw(pending.data completed.data undo.data backlog.data args.rc);
exit 0;
code, out, err = self.t(("info", "1"))
self.assertRegexpMatches(
out,
"Description\s+\+tag\sfoo\n",
msg='1 modify project:p pri:H -- +tag foo',
)
self.t(("1", "modify", "project:p", "--", "pri:H", "+tag", "foo"))
code, out, err = self.t(("info", "1"))
self.assertRegexpMatches(
out,
"Description\s+pri:H\s\+tag\sfoo\n",
msg='1 modify project:p -- pri:H +tag foo',
)
self.t(("1", "modify", "--", "project:p", "pri:H", "+tag", "foo"))
code, out, err = self.t(("info", "1"))
self.assertRegexpMatches(
out,
"Description\s+project:p\spri:H\s\+tag\sfoo\n",
msg='1 modify project:p -- pri:H +tag foo',
)
self.t(("1", "modify", "--", "project:p", "pri:H", "+tag", "--"))
code, out, err = self.t(("info", "1"))
self.assertRegexpMatches(
out,
"Description\s+project:p\spri:H\s\+tag\s--\n",
msg='1 modify project:p -- pri:H +tag foo --',
)
if __name__ == "__main__":
from simpletap import TAPTestRunner
unittest.main(testRunner=TAPTestRunner())
# vim: ai sts=4 et sw=4

View File

@@ -5,8 +5,8 @@ import tempfile
import shutil import shutil
import atexit import atexit
import unittest import unittest
from .utils import (run_cmd_wait, run_cmd_wait_nofail, which, binary_location, from .utils import (run_cmd_wait, run_cmd_wait_nofail, which,
) task_binary_location)
from .exceptions import CommandError from .exceptions import CommandError
from .hooks import Hooks from .hooks import Hooks
@@ -22,7 +22,7 @@ class Task(object):
A taskw client should not be used after being destroyed. A taskw client should not be used after being destroyed.
""" """
DEFAULT_TASK = binary_location("task") DEFAULT_TASK = task_binary_location()
def __init__(self, taskd=None, taskw=DEFAULT_TASK): def __init__(self, taskd=None, taskw=DEFAULT_TASK):
"""Initialize a Task warrior (client) that can interact with a taskd """Initialize a Task warrior (client) that can interact with a taskd
@@ -137,6 +137,15 @@ class Task(object):
cmd = (self.taskw, "config", "--", var, value) cmd = (self.taskw, "config", "--", var, value)
return run_cmd_wait(cmd, env=self.env) return run_cmd_wait(cmd, env=self.env)
@property
def taskrc_content(self):
"""
Returns the contents of the taskrc file.
"""
with open(self.taskrc, "r") as f:
return f.readlines()
def runSuccess(self, args=(), input=None, merge_streams=False, def runSuccess(self, args=(), input=None, merge_streams=False,
timeout=1): timeout=1):
"""Invoke task with given arguments and fail if exit code != 0 """Invoke task with given arguments and fail if exit code != 0

View File

@@ -8,7 +8,8 @@ import atexit
from time import sleep from time import sleep
from subprocess import Popen from subprocess import Popen
from .utils import (find_unused_port, release_port, port_used, run_cmd_wait, from .utils import (find_unused_port, release_port, port_used, run_cmd_wait,
which, parse_datafile, DEFAULT_CERT_PATH, binary_location) which, parse_datafile, DEFAULT_CERT_PATH,
taskd_binary_location)
from .exceptions import CommandError from .exceptions import CommandError
try: try:
@@ -30,7 +31,7 @@ class Taskd(object):
A server can be stopped and started multiple times, but should not be A server can be stopped and started multiple times, but should not be
started or stopped after being destroyed. started or stopped after being destroyed.
""" """
DEFAULT_TASKD = binary_location("taskd") DEFAULT_TASKD = taskd_binary_location()
def __init__(self, taskd=DEFAULT_TASKD, certpath=None, def __init__(self, taskd=DEFAULT_TASKD, certpath=None,
address="localhost"): address="localhost"):

View File

@@ -41,13 +41,28 @@ DEFAULT_HOOK_PATH = os.path.abspath(
TASKW_SKIP = os.environ.get("TASKW_SKIP", False) TASKW_SKIP = os.environ.get("TASKW_SKIP", False)
TASKD_SKIP = os.environ.get("TASKD_SKIP", False) TASKD_SKIP = os.environ.get("TASKD_SKIP", False)
# Environment flags to control use of PATH or in-tree binaries # Environment flags to control use of PATH or in-tree binaries
USE_PATH = os.environ.get("USE_PATH", False) TASK_USE_PATH = os.environ.get("TASK_USE_PATH", False)
TASKD_USE_PATH = os.environ.get("TASKD_USE_PATH", False)
UUID_regex = ("[0-9A-Fa-f]{8}-" + ("[0-9A-Fa-f]{4}-" * 3) + "[0-9A-Fa-f]{12}") UUID_regex = ("[0-9A-Fa-f]{8}-" + ("[0-9A-Fa-f]{4}-" * 3) + "[0-9A-Fa-f]{12}")
def binary_location(cmd): def task_binary_location(cmd="task"):
"""If USE_PATH is set rely on PATH to look for task/taskd binaries. """If TASK_USE_PATH is set rely on PATH to look for task binaries.
Otherwise ../src/ is used by default.
"""
return binary_location(cmd, TASK_USE_PATH)
def taskd_binary_location(cmd="taskd"):
"""If TASKD_USE_PATH is set rely on PATH to look for taskd binaries.
Otherwise ../src/ is used by default.
"""
return binary_location(cmd, TASKD_USE_PATH)
def binary_location(cmd, USE_PATH=False):
"""If USE_PATH is True rely on PATH to look for taskd binaries.
Otherwise ../src/ is used by default. Otherwise ../src/ is used by default.
""" """
if USE_PATH: if USE_PATH:
@@ -108,14 +123,24 @@ def _queue_output(arguments, pidq, outputq):
kwargs = arguments["process"] kwargs = arguments["process"]
input = arguments["input"] input = arguments["input"]
proc = Popen(**kwargs) try:
proc = Popen(**kwargs)
except OSError as e:
# pid None is read by the main thread as a crash of the process
pidq.put(None)
# NOTE If for whatever reason pid is None at the time of access, use the outputq.put((
# following line instead "",
# pid = wait_condition(lambda: proc.pid) ("Unexpected exception caught during execution of taskw: '{0}' . "
pid = proc.pid "If you are running out-of-tree tests set USE_PATH=1 in shell "
# Put the PID in the queue for main process to know "env before execution and add the location of the task binary to "
pidq.put(pid) "the PATH".format(e)),
255)) # false exitcode
return
# Put the PID in the queue for main process to know.
pidq.put(proc.pid)
# Send input and wait for finish # Send input and wait for finish
out, err = proc.communicate(input) out, err = proc.communicate(input)
@@ -161,6 +186,10 @@ def _get_output(arguments, timeout=None):
try: try:
pid = pidq.get(timeout=timeout) pid = pidq.get(timeout=timeout)
except Empty: except Empty:
pid = None
# Process crashed or timed out for some reason
if pid is None:
return _retrieve_output(t, output_timeout, outputq, return _retrieve_output(t, output_timeout, outputq,
"TaskWarrior to start") "TaskWarrior to start")

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