Compare commits
509 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df49aaba12 | ||
|
|
0d45bb75e8 | ||
|
|
5d5e824453 | ||
|
|
92b5dfd83d | ||
|
|
7293de75b0 | ||
|
|
f30f4d45c6 | ||
|
|
32ef3fdb3d | ||
|
|
65b6a35ef5 | ||
|
|
e16bd6ee83 | ||
|
|
69698454c3 | ||
|
|
3a7af017f8 | ||
|
|
accd51bc35 | ||
|
|
5fee3ef27c | ||
|
|
0850e26a3e | ||
|
|
4deb17696e | ||
|
|
7d859d6b6d | ||
|
|
f6e04585ae | ||
|
|
1e31df3c7a | ||
|
|
db04f1b583 | ||
|
|
1c9edcc2ec | ||
|
|
710372b8db | ||
|
|
c8756f0201 | ||
|
|
b6b49ca7e4 | ||
|
|
ec9b8c5aa9 | ||
|
|
023a17e6be | ||
|
|
c346cf9395 | ||
|
|
71fef9f22f | ||
|
|
36e31811b0 | ||
|
|
71753ef666 | ||
|
|
7a9e099568 | ||
|
|
fcfc95df86 | ||
|
|
5f9a543b1b | ||
|
|
75775786e6 | ||
|
|
caa8c8e884 | ||
|
|
93470bb8d8 | ||
|
|
8e01976abb | ||
|
|
e60ea2e07a | ||
|
|
931afb0674 | ||
|
|
1b63a2dde5 | ||
|
|
c62ba68f10 | ||
|
|
5d60f426a8 | ||
|
|
7fcb26f363 | ||
|
|
c34b2b8cfb | ||
|
|
b9a8d62324 | ||
|
|
c8c7123eb9 | ||
|
|
dc8e874f19 | ||
|
|
233d97fbff | ||
|
|
64be230639 | ||
|
|
a52bba46f1 | ||
|
|
b91a4b4982 | ||
|
|
f9e3f865b1 | ||
|
|
67a008e7bf | ||
|
|
5c70619d68 | ||
|
|
6cf3345595 | ||
|
|
9959d8eac8 | ||
|
|
499044b9b6 | ||
|
|
f66c706370 | ||
|
|
e3e72e32f1 | ||
|
|
39fb45447b | ||
|
|
3cbb2bb20f | ||
|
|
c6dbdf87a4 | ||
|
|
fe8d235a6b | ||
|
|
1371b6595e | ||
|
|
21407e0ca2 | ||
|
|
c0efa0f4d7 | ||
|
|
236e7898b9 | ||
|
|
33738af3e4 | ||
|
|
f684917c3c | ||
|
|
876a7d29b9 | ||
|
|
119c19b519 | ||
|
|
935b2993f3 | ||
|
|
afec6d451f | ||
|
|
fd17a68930 | ||
|
|
09d86eb165 | ||
|
|
8d5a77f490 | ||
|
|
e9b54ea74f | ||
|
|
3a035a7d1d | ||
|
|
d405a5f3b5 | ||
|
|
0cba34268c | ||
|
|
61e1401073 | ||
|
|
a883c5ca41 | ||
|
|
d98b6e5c0b | ||
|
|
6b0d288da7 | ||
|
|
e8654c49b5 | ||
|
|
c28932ebbe | ||
|
|
826769bcd9 | ||
|
|
d31227d2e2 | ||
|
|
0a54d46589 | ||
|
|
3f457dc744 | ||
|
|
f9c99624b2 | ||
|
|
b19b0f47e5 | ||
|
|
fbf9a8be8d | ||
|
|
9476069b41 | ||
|
|
35b77f93c4 | ||
|
|
5da3416b79 | ||
|
|
79207a8e42 | ||
|
|
5af4579741 | ||
|
|
7a9d314016 | ||
|
|
07a18f4fae | ||
|
|
29a09707f3 | ||
|
|
743cb92958 | ||
|
|
370afa0d26 | ||
|
|
8c0f46309b | ||
|
|
fa7d4352cd | ||
|
|
f1ef53bea0 | ||
|
|
21dc2ec100 | ||
|
|
5b01abc27f | ||
|
|
c830b4b669 | ||
|
|
70d5f595c7 | ||
|
|
c1815b8277 | ||
|
|
2eea7805c6 | ||
|
|
5487414003 | ||
|
|
229078ffed | ||
|
|
04d0c52a43 | ||
|
|
5d4859c44d | ||
|
|
3f394fa164 | ||
|
|
df209b9b8b | ||
|
|
c27f5d23b6 | ||
|
|
df3f8ead11 | ||
|
|
bc335e8075 | ||
|
|
e0f3e6d328 | ||
|
|
eb35386d76 | ||
|
|
96c448ca1e | ||
|
|
71fea510bb | ||
|
|
1e411ed4b8 | ||
|
|
cfbdd4bc05 | ||
|
|
5af3f71ac5 | ||
|
|
8b863c9764 | ||
|
|
9630b76990 | ||
|
|
690d9493f0 | ||
|
|
73f4f55e0a | ||
|
|
267f054449 | ||
|
|
7a64c19641 | ||
|
|
b8105812fc | ||
|
|
f454a02224 | ||
|
|
1bbe709e38 | ||
|
|
a4b96a3191 | ||
|
|
ddb6014358 | ||
|
|
31a7a3343b | ||
|
|
3a0971f290 | ||
|
|
fee58b0eb6 | ||
|
|
9adf3fc0fa | ||
|
|
39d330631d | ||
|
|
b41d7c4582 | ||
|
|
12eca4b2cc | ||
|
|
f26f790e74 | ||
|
|
7ac0a919aa | ||
|
|
e9e91ce55e | ||
|
|
880fb5bcc6 | ||
|
|
84eb75c705 | ||
|
|
f697e4df73 | ||
|
|
0eaa061efe | ||
|
|
b02d518b02 | ||
|
|
0973e6566b | ||
|
|
d0a9e9a253 | ||
|
|
ff445c567e | ||
|
|
254b1eb49c | ||
|
|
15005afd1e | ||
|
|
9e6c6ecb93 | ||
|
|
20eaa312e6 | ||
|
|
fdb22ad341 | ||
|
|
d76d5c3587 | ||
|
|
526665d4ec | ||
|
|
834b4ddab6 | ||
|
|
357850177d | ||
|
|
d2e6c90446 | ||
|
|
96922231b8 | ||
|
|
55db1239bd | ||
|
|
4f75652ccb | ||
|
|
052a5c607a | ||
|
|
c306d458e0 | ||
|
|
7babc9c5b1 | ||
|
|
24a1cbefe9 | ||
|
|
289780c8cc | ||
|
|
f5af3368a9 | ||
|
|
a2ed996102 | ||
|
|
704eb1eab3 | ||
|
|
484979b4e0 | ||
|
|
928e94a6e1 | ||
|
|
e2c9752bc4 | ||
|
|
8386b702dd | ||
|
|
48e9c0518e | ||
|
|
b9dc0813d9 | ||
|
|
25c687e1ec | ||
|
|
6e98bbbd85 | ||
|
|
06c8976be5 | ||
|
|
d13a5a3f47 | ||
|
|
b662afa1ff | ||
|
|
bde83d3195 | ||
|
|
0edb7e57f6 | ||
|
|
4569d2da24 | ||
|
|
6b00f08794 | ||
|
|
e83809c6aa | ||
|
|
39b736d23e | ||
|
|
3e90554f40 | ||
|
|
4690b1a6cb | ||
|
|
ce1a7b921c | ||
|
|
7a1645bba3 | ||
|
|
9f1b3e0d56 | ||
|
|
0af8b1dbab | ||
|
|
1465bcb918 | ||
|
|
4eb70e68b7 | ||
|
|
cd216bd4fd | ||
|
|
ac4a5c6d62 | ||
|
|
a67593decf | ||
|
|
7be294267b | ||
|
|
920cdcca10 | ||
|
|
7cc410f58e | ||
|
|
5d42c0f6b6 | ||
|
|
cff680d074 | ||
|
|
dda190703e | ||
|
|
281edcc38f | ||
|
|
11dab68fce | ||
|
|
29dff399bd | ||
|
|
a75c293286 | ||
|
|
dbf31bfce8 | ||
|
|
7826c7b988 | ||
|
|
87d00698db | ||
|
|
19674ee339 | ||
|
|
9f654a5c95 | ||
|
|
87e9578666 | ||
|
|
e3ec52f6ca | ||
|
|
70c3d9845c | ||
|
|
9d1c4101c2 | ||
|
|
44ed974fa2 | ||
|
|
3cf7a701c8 | ||
|
|
d390f99fc5 | ||
|
|
a2cae67644 | ||
|
|
d202691638 | ||
|
|
c9d61ff71b | ||
|
|
ebd6977480 | ||
|
|
276050ce0b | ||
|
|
197815a3a7 | ||
|
|
4118fe70ae | ||
|
|
e11b333a0b | ||
|
|
5e8426f0cc | ||
|
|
138360b7bc | ||
|
|
7fa3c5ac84 | ||
|
|
b5da4acab9 | ||
|
|
180c382de2 | ||
|
|
23d4e2b3c9 | ||
|
|
d1f7e44811 | ||
|
|
96185cbd61 | ||
|
|
7665d13d42 | ||
|
|
a40967a324 | ||
|
|
01feec568b | ||
|
|
104aeb3905 | ||
|
|
53e9bd0cbd | ||
|
|
234e4d7308 | ||
|
|
237d932ff9 | ||
|
|
2af470bb90 | ||
|
|
cefc129e9a | ||
|
|
7aa55a8a71 | ||
|
|
565987a177 | ||
|
|
309b607672 | ||
|
|
abe8819f2f | ||
|
|
f0cc0151b7 | ||
|
|
3f2d377fef | ||
|
|
c849cc9bfe | ||
|
|
48be6986c2 | ||
|
|
ffd6465661 | ||
|
|
7e890c084f | ||
|
|
0f1a46e6d3 | ||
|
|
2811b9a571 | ||
|
|
58e62711f3 | ||
|
|
3b9d88a87b | ||
|
|
9dad0c7eb6 | ||
|
|
e67c6c45cf | ||
|
|
aa8cd54142 | ||
|
|
651ac3f174 | ||
|
|
ea78200ae3 | ||
|
|
ad89a90d12 | ||
|
|
8c6892fed6 | ||
|
|
85d0e1789a | ||
|
|
e19c99ce1e | ||
|
|
0868ba757c | ||
|
|
bf5f246168 | ||
|
|
9748fa2ab1 | ||
|
|
1a0f479394 | ||
|
|
e2f35a1a06 | ||
|
|
0548fca88f | ||
|
|
394acae790 | ||
|
|
e8d385119a | ||
|
|
070fdf60fa | ||
|
|
1278226c16 | ||
|
|
98410cff42 | ||
|
|
ee23a099f2 | ||
|
|
0ab1dc0c9c | ||
|
|
c2a9bb65e6 | ||
|
|
75cf742a55 | ||
|
|
dc0502dd9f | ||
|
|
3a77a5f291 | ||
|
|
1abda3900b | ||
|
|
09fe5be086 | ||
|
|
1a3550541b | ||
|
|
371ca27da0 | ||
|
|
5f3dd43893 | ||
|
|
edb54a51b3 | ||
|
|
636f6bfd96 | ||
|
|
e91063426a | ||
|
|
a4d5ab07e9 | ||
|
|
49a7e46eaf | ||
|
|
26aff348d2 | ||
|
|
9f82926c65 | ||
|
|
8791c0a921 | ||
|
|
745aad0d27 | ||
|
|
e1c0d5b130 | ||
|
|
0891ed4b57 | ||
|
|
9898aa15b5 | ||
|
|
af772f4c49 | ||
|
|
3484e44c7d | ||
|
|
0cf18f3b16 | ||
|
|
2155bd3969 | ||
|
|
ae6024ef8b | ||
|
|
21553d9044 | ||
|
|
d6e3430e0d | ||
|
|
0d23511cee | ||
|
|
1128ad8259 | ||
|
|
66d5a8ba3d | ||
|
|
aab93b2cda | ||
|
|
be80bc4ea3 | ||
|
|
15bec27e03 | ||
|
|
6683cc7e83 | ||
|
|
044ca40bb7 | ||
|
|
be855af8c4 | ||
|
|
d10ad5c7af | ||
|
|
1ae4ea2ea3 | ||
|
|
d37937d970 | ||
|
|
51e947064f | ||
|
|
606a7505d3 | ||
|
|
846dd14a9f | ||
|
|
d8f436cca9 | ||
|
|
ac9c726782 | ||
|
|
88d65b23c1 | ||
|
|
f2998aba74 | ||
|
|
d2b2631db7 | ||
|
|
4c491d8a0d | ||
|
|
917a152a1e | ||
|
|
289e45499a | ||
|
|
2efb9594d9 | ||
|
|
0d096a5a42 | ||
|
|
cc1c063925 | ||
|
|
dd31a15001 | ||
|
|
c11601e30e | ||
|
|
520067f522 | ||
|
|
693fe9b8fd | ||
|
|
fa249bfedd | ||
|
|
952d743218 | ||
|
|
91f6980d2f | ||
|
|
d211969236 | ||
|
|
bd320b6729 | ||
|
|
3f004f547e | ||
|
|
3b192cddcf | ||
|
|
ca6061a987 | ||
|
|
2787ee960b | ||
|
|
c27ad4dc27 | ||
|
|
a36eb974ee | ||
|
|
a55a7bf1a2 | ||
|
|
82e019a4a8 | ||
|
|
9180aa6e33 | ||
|
|
32d837fb25 | ||
|
|
395b08385b | ||
|
|
9cc9e19757 | ||
|
|
c07d74574d | ||
|
|
73401664b6 | ||
|
|
d052b8752d | ||
|
|
68d9e3bb5e | ||
|
|
86837022d3 | ||
|
|
e831f85823 | ||
|
|
4b839f2c83 | ||
|
|
1e1bd32c42 | ||
|
|
880ab5d665 | ||
|
|
ef583dedea | ||
|
|
1bd26fe9ab | ||
|
|
80c01f3ffb | ||
|
|
7cd42b5d2f | ||
|
|
1b218d68f5 | ||
|
|
e6031183dd | ||
|
|
f9bcb8cfc8 | ||
|
|
2ef0214248 | ||
|
|
0a62061ca8 | ||
|
|
5d96547c07 | ||
|
|
eb3afa1fdc | ||
|
|
885ff46066 | ||
|
|
5a060802e7 | ||
|
|
acce2d5a68 | ||
|
|
adac566665 | ||
|
|
f454eecafb | ||
|
|
f83702076b | ||
|
|
83519a44c6 | ||
|
|
a2e980c6b8 | ||
|
|
e00704a375 | ||
|
|
8fb3161a02 | ||
|
|
fa528beb58 | ||
|
|
c5a2b7f759 | ||
|
|
4213afd408 | ||
|
|
8ad0c1172e | ||
|
|
f887173bf7 | ||
|
|
328b7ec260 | ||
|
|
ab41e005c9 | ||
|
|
bd785ffad5 | ||
|
|
3cce6c23f5 | ||
|
|
ec919a8677 | ||
|
|
5911286218 | ||
|
|
9e49325d6e | ||
|
|
c483c8dda9 | ||
|
|
2d2579d801 | ||
|
|
4f6c51e7ae | ||
|
|
cd6808ab15 | ||
|
|
8b648bc690 | ||
|
|
9a0a6188b1 | ||
|
|
b79453afa7 | ||
|
|
60dddffda3 | ||
|
|
e8dc5a16a1 | ||
|
|
528e72062b | ||
|
|
876820ee1a | ||
|
|
8e730f2da3 | ||
|
|
8b28c36485 | ||
|
|
04be198281 | ||
|
|
1b69ac6ad2 | ||
|
|
b1081bd510 | ||
|
|
a72322b9db | ||
|
|
82e6574d30 | ||
|
|
1f14454be7 | ||
|
|
384ca82292 | ||
|
|
066143d939 | ||
|
|
e845a25ea6 | ||
|
|
75a2b11638 | ||
|
|
6a3edc88a1 | ||
|
|
bb3555f217 | ||
|
|
5de80eedeb | ||
|
|
10c1b5f902 | ||
|
|
049ed04471 | ||
|
|
3ff42af9c7 | ||
|
|
1cfdfbae52 | ||
|
|
61291e4d1e | ||
|
|
77ec56dcd0 | ||
|
|
d0f74c4a80 | ||
|
|
4bdee56fa7 | ||
|
|
8323407242 | ||
|
|
6626207ad1 | ||
|
|
4865269630 | ||
|
|
8683574b18 | ||
|
|
5e90510530 | ||
|
|
a8bab90c34 | ||
|
|
87c2a9b5a5 | ||
|
|
cba5948a1d | ||
|
|
f4a6ec6f97 | ||
|
|
a3490966c0 | ||
|
|
855537b975 | ||
|
|
473019c1f0 | ||
|
|
d1698eab2d | ||
|
|
73b7b21b81 | ||
|
|
44f2c0c98c | ||
|
|
654159b2fd | ||
|
|
67cb30fdce | ||
|
|
7d75547f44 | ||
|
|
d68fa7ea8a | ||
|
|
db78851b40 | ||
|
|
6fdf0738a7 | ||
|
|
41003fc78b | ||
|
|
d2928dc4e4 | ||
|
|
61deb7ce7e | ||
|
|
0311ea6689 | ||
|
|
0b0ddbfbc4 | ||
|
|
cd31335742 | ||
|
|
5a3037f257 | ||
|
|
a22d173b9b | ||
|
|
134d201cb0 | ||
|
|
547d9edb55 | ||
|
|
cdde747733 | ||
|
|
588009d679 | ||
|
|
adf9f25289 | ||
|
|
ea0397f542 | ||
|
|
411fab3a27 | ||
|
|
da6a57b203 | ||
|
|
235e4ef047 | ||
|
|
1dbb0a57a8 | ||
|
|
5a7117630e | ||
|
|
e9f9f6a86e | ||
|
|
8ea1563944 | ||
|
|
e522c1980a | ||
|
|
845fe047cc | ||
|
|
5932d9f90b | ||
|
|
a8ff7655ef | ||
|
|
79cc9d8ed9 | ||
|
|
b83dc8a29e | ||
|
|
99ebf82c3a | ||
|
|
231e8ca913 | ||
|
|
9bd9a3b285 | ||
|
|
b882cd151e | ||
|
|
a3b0d5c6a6 | ||
|
|
d1664b3f55 | ||
|
|
1cac14f3f8 | ||
|
|
507e2d5807 | ||
|
|
c664d62c2f | ||
|
|
f32c4d1f73 | ||
|
|
9bf7dfda4f | ||
|
|
2a782b8f01 | ||
|
|
3c07510a43 | ||
|
|
07eff0f3c1 | ||
|
|
dad0ac0c27 | ||
|
|
2c986d6e6b | ||
|
|
1e8f83cab9 | ||
|
|
15f00452c2 | ||
|
|
6a3b13dbfc | ||
|
|
8180b94b1b | ||
|
|
6aafa9f04e | ||
|
|
fe07f62214 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,6 +2,7 @@ cmake.h
|
||||
commit.h
|
||||
Makefile
|
||||
src/task
|
||||
src/taskd
|
||||
src/libtask.a
|
||||
src/commands/libcommands.a
|
||||
src/columns/libcolumns.a
|
||||
|
||||
17
AUTHORS
17
AUTHORS
@@ -1,4 +1,4 @@
|
||||
The development of taskwarrior was made possible by the significant
|
||||
The development of Taskwarrior was made possible by the significant
|
||||
contributions of the following people:
|
||||
|
||||
Paul Beckingham (Principal Author)
|
||||
@@ -13,6 +13,7 @@ contributions of the following people:
|
||||
Louis-Claude Canon (Contributing Author)
|
||||
Scott Kostyshak (Contributing Author)
|
||||
Renato Alves (Contributing Author)
|
||||
Tomas Babej (Contributing Author)
|
||||
|
||||
The following submitted code, packages or analysis, and deserve special thanks:
|
||||
|
||||
@@ -112,6 +113,10 @@ The following submitted code, packages or analysis, and deserve special thanks:
|
||||
Jeremy John Reeder
|
||||
Roman Inflianskas
|
||||
Łukasz Panek
|
||||
V.Krishn
|
||||
Jens Erat
|
||||
Peter Rochen
|
||||
Oota Toshiya
|
||||
|
||||
Thanks to the following, who submitted detailed bug reports and excellent
|
||||
suggestions:
|
||||
@@ -233,10 +238,16 @@ suggestions:
|
||||
dev-zero
|
||||
Petteri
|
||||
Black Ops Testing
|
||||
Jens Erat
|
||||
Leon Feng
|
||||
Tomas Babej
|
||||
Nick Person
|
||||
Arnoud K
|
||||
Ozgur Akgun
|
||||
David Costa
|
||||
Sujeevan Vijayakumaran
|
||||
Scott Carter
|
||||
Taisuke Hachimura
|
||||
Martin
|
||||
Alexandre de Verteuil
|
||||
Scott M
|
||||
Stefan Frühwirth
|
||||
Pierre Campet
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
cmake_minimum_required (VERSION 2.8)
|
||||
set(CMAKE_LEGACY_CYGWIN_WIN32 0) # Remove when CMake >= 2.8.4 is required
|
||||
if(POLICY CMP0037)
|
||||
cmake_policy(SET CMP0037 OLD)
|
||||
endif()
|
||||
|
||||
include (CheckFunctionExists)
|
||||
include (CheckStructHasMember)
|
||||
@@ -7,12 +10,40 @@ include (CheckStructHasMember)
|
||||
set (HAVE_CMAKE true)
|
||||
|
||||
project (task)
|
||||
set (PROJECT_VERSION "2.4.0")
|
||||
set (PROJECT_VERSION "2.4.4")
|
||||
|
||||
OPTION(USE_GNUTLS "Build gnutls support." ON)
|
||||
|
||||
message ("CMAKE_SYSTEM_NAME ${CMAKE_SYSTEM_NAME}")
|
||||
|
||||
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")
|
||||
set (LINUX true)
|
||||
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set (DARWIN true)
|
||||
set (_CXX11_FLAGS "${_CXX11_FLAGS} -stdlib=libc++")
|
||||
elseif (${CMAKE_SYSTEM_NAME} MATCHES "kFreeBSD")
|
||||
set (KFREEBSD true)
|
||||
elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
@@ -25,10 +56,20 @@ elseif (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
|
||||
set (SOLARIS true)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "GNU")
|
||||
set (GNUHURD true)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "CYGWIN")
|
||||
set (CYGWIN true)
|
||||
# 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")
|
||||
set (UNKNOWN true)
|
||||
endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
|
||||
set (CMAKE_CXX_FLAGS "${_CXX11_FLAGS} ${CMAKE_CXX_FLAGS}")
|
||||
|
||||
set (CMAKE_CXX_FLAGS "-Wall -Wsign-compare -Wreturn-type ${CMAKE_CXX_FLAGS}")
|
||||
|
||||
if (NETBSD)
|
||||
# Since readline, etc likely to be in /usr/pkg/lib, not standard library
|
||||
# Otherwise will remove links during install
|
||||
@@ -65,23 +106,15 @@ set (PACKAGE_TARNAME "${PACKAGE}")
|
||||
set (PACKAGE_VERSION "${VERSION}")
|
||||
set (PACKAGE_STRING "${PACKAGE} ${VERSION}")
|
||||
|
||||
message ("-- Looking for GnuTLS")
|
||||
find_package (GnuTLS)
|
||||
if (GNUTLS_FOUND)
|
||||
set (HAVE_LIBGNUTLS true)
|
||||
set (TASK_INCLUDE_DIRS ${TASK_INCLUDE_DIRS} ${GNUTLS_INCLUDE_DIR})
|
||||
set (TASK_LIBRARIES ${TASK_LIBRARIES} ${GNUTLS_LIBRARIES})
|
||||
endif (GNUTLS_FOUND)
|
||||
|
||||
#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)
|
||||
if (USE_GNUTLS)
|
||||
message ("-- Looking for GnuTLS")
|
||||
find_package (GnuTLS)
|
||||
if (GNUTLS_FOUND)
|
||||
set (HAVE_LIBGNUTLS true)
|
||||
set (TASK_INCLUDE_DIRS ${TASK_INCLUDE_DIRS} ${GNUTLS_INCLUDE_DIR})
|
||||
set (TASK_LIBRARIES ${TASK_LIBRARIES} ${GNUTLS_LIBRARIES})
|
||||
endif (GNUTLS_FOUND)
|
||||
endif (USE_GNUTLS)
|
||||
|
||||
check_function_exists (timegm HAVE_TIMEGM)
|
||||
check_function_exists (get_current_dir_name HAVE_GET_CURRENT_DIR_NAME)
|
||||
@@ -130,6 +163,7 @@ set (LANGUAGE_ITA_ITA 5)
|
||||
set (LANGUAGE_POR_PRT 6)
|
||||
set (LANGUAGE_EPO_RUS 7)
|
||||
set (LANGUAGE_POL_POL 8)
|
||||
set (LANGUAGE_JPN_JPN 9)
|
||||
|
||||
message ("-- Configuring cmake.h")
|
||||
configure_file (
|
||||
|
||||
2
COPYING
2
COPYING
@@ -1,4 +1,4 @@
|
||||
taskwarrior - a command line task list manager.
|
||||
Taskwarrior - a command line task list manager.
|
||||
|
||||
Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
|
||||
|
||||
|
||||
147
ChangeLog
147
ChangeLog
@@ -1,10 +1,148 @@
|
||||
2.4.0 (2015-01-01) -
|
||||
2.4.4 (2015-05-10) -
|
||||
|
||||
- TW-69 wait dates relative to due date (thanks to John Florian).
|
||||
- TW-1285 I'd like to use relative dates combined with times (thanks to Adam
|
||||
Gibbins).
|
||||
- TW-1474 Documentation is confusing with respect to user/uuid on the server
|
||||
(thanks to Tomas Babej).
|
||||
- TW-1596 taskwarrior can't compile FreeBSD 9.3 32bit environment (thanks to
|
||||
ribbon)
|
||||
- TW-1603 Priority color precedence changed since it is a UDA, should be lowered
|
||||
again (thanks to Jens Erat).
|
||||
- TW-1605 Japanese translation for Taskwarrior (thanks to Oota Toshiya).
|
||||
- TW-1606 scheduled.any filter (thanks to Peter Rochen).
|
||||
- TW-1608 The recur/recurring report shows tasks without a recur interval
|
||||
(thanks to Brad Collette).
|
||||
- TW-1610 Disabling GC can lead to editing the wrong task (thanks to Scott M).
|
||||
- The 'obfuscate' setting, if set to '1' will replace all text with 'xxx'.
|
||||
- POSIX file locking mechanism, eliminating platform-specific code.
|
||||
|
||||
------ current release ---------------------------
|
||||
|
||||
2.4.3 (2015-04-19) 499044b9b6bdbc95338ea585204e949d80b24a09
|
||||
|
||||
- TW-57 user defined attribute sort order (thanks to Max Muller).
|
||||
- TW-70 urgency.user.keyword.<keyword>.coefficient=...
|
||||
- TW-111 User-defined priorities.
|
||||
- TW-1279 Make default.* not apply to recurring tasks.
|
||||
- TW-1287 Make default.* not apply to synced tasks.
|
||||
- TW-1539 user-defined urgency coefficients for priority values.
|
||||
- TW-1541 Priority should be converted to UDA (in default taskrc) (thanks to
|
||||
Tomas Babej).
|
||||
- TW-1556 task hangs when modifying uda field with percent-encoded (url-encoded)
|
||||
value (thanks to Stefan Frühwirth).
|
||||
- TW-1578 Bash tab completion problems on first run
|
||||
(thanks to Renato Alves and Ptolemarch).
|
||||
- TW-1580 "modified" attribute no longer updated (thanks to David Patrick).
|
||||
- TW-1581 Tasks with dependencies show wrong urgency values for the first
|
||||
report run after a task in the dependency chain is completed/deleted (thanks
|
||||
to Ulf Eliasson).
|
||||
- TW-1583 Invalid ID displayed for first report after done/delete (thanks to
|
||||
Ulf Eliasson).
|
||||
- TW-1584 attr.{isnt,not} use partial matching.
|
||||
- TW-1587 Fix and improve example on-exit hook, adjust to new hooks API
|
||||
(thanks to Jochen Sprickerhof).
|
||||
- TW-1588 Most Export scripts cannot deal with new export format (thanks to
|
||||
Scott Carter).
|
||||
- TW-1590 syntax of rcfile not documented (whitespace, line continuation)
|
||||
(thanks to Scott M).
|
||||
- TW-1591 add an option to see non-pending project with command task summary
|
||||
(thanks to Pierre Campet).
|
||||
- TW-1595 info command doesn't print urgency details, if urgency is negative
|
||||
(thanks to Peter Rochen).
|
||||
- Setting 'bulk' to zero is interpreted as infinity, which means there is no
|
||||
amount of changes that is considered dangerous (thanks to Tomas Babej).
|
||||
- Disable hooks in bash completion script. Hooks were previously able to
|
||||
abort processing or output interfering data, breaking completion.
|
||||
- Fix "task add due:tomorrow+3days" failing to work without spaces.
|
||||
- Performance improvements:
|
||||
+ Stops after measuring a fixed-width column format.
|
||||
+ Reduced number of std::string copies.
|
||||
|
||||
2.4.2 (2015-03-15) b9dc0813d9a8922b4cef9595033f133f9fbabf44
|
||||
|
||||
- TW-41 Tasks in subprojects are not counted in project completion (thanks
|
||||
to Renato Alves).
|
||||
- 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).
|
||||
|
||||
2.4.1 (2015-02-16) 82e019a4a8b20de63d53b51d59b8d1c89d3c05b2
|
||||
|
||||
- TW-1457 Non-existent attributes are not properly handled (thanks to Tomas
|
||||
Babej).
|
||||
- TW-1484 The 'history' and 'ghistory' reports do not obey rc.color.label.
|
||||
- TW-1486 task wait shows completed tasks which has a wait attribute (thanks to
|
||||
Sujeevan Vijayakumaran).
|
||||
- TW-1487 Task export exports some numeric attributes as strings (thanks to
|
||||
Tomas Babej).
|
||||
- TW-1491 Regression in deleting due dates (thanks to Jens Erat).
|
||||
- TW-1492 compiling v2.4.0 using musl(libc) (thanks to V.Krishn).
|
||||
- TW-1495 German translation for taskwarrior (thanks to Jens Erat).
|
||||
- TW-1498 Filtering for presence of UDA matches all tasks (thanks to Ralph
|
||||
Bean).
|
||||
- TW-1501 Calc can't handle multi-digit numbers in some expressions (thanks to
|
||||
Jeremy John Reeder).
|
||||
- TW-1502 Successful on-add hook with no output confuses TW (thanks to Tomas
|
||||
Babej).
|
||||
- TW-1504 On-modify hook does not accept correct JSON format (thanks to Tomas
|
||||
Babej).
|
||||
- TW-1505 completely ignore mis-named hook scripts (thanks to Tomas Babej,
|
||||
David Patrick).
|
||||
- TW-1509 Hooks modifications performed on sync not sycning back (thanks to
|
||||
Tomas Babej).
|
||||
- TW-1510 Task can save empty value in the data backlog (thanks to Tomas Babej).
|
||||
- TW-1517 Hook performance should be measured individually for each hook (thanks
|
||||
to Tomas Babej).
|
||||
- TW-1518 Misbehaving hooks silently break task processing (thanks to Wim
|
||||
Schuermann).
|
||||
- TW-1519 Testing suite forces taskd.trust="ignore hostname" (thanks to Renato
|
||||
Alves).
|
||||
- TW-1522 Date format doesn't like hyphens (thanks to Scott Carter).
|
||||
- TW-1524 Build Broken (thanks to Jack).
|
||||
- TW-1530 Multiple on-add hooks generating new tasks are ignored (thanks to
|
||||
Tomas Babej).
|
||||
- TW-1531 'task export' should handle recurrence (thanks to Tomas Babej).
|
||||
- TW-1532 Hooks does not execute any script on Cygwin (thanks to Taisuke
|
||||
Hachimura).
|
||||
- TW-1534 Urgency coefficient for user project disables 'info' output (thanks to
|
||||
Martin).
|
||||
- TW-1542 Large numeric UDA values get rendered in scientific notation on export
|
||||
(thanks to Ralph Bean).
|
||||
- Fixed assorted color theme problems.
|
||||
- Changed assorted reports so they do not use '.age' format for dates that are
|
||||
in the future, because those are never shown with this format (thanks to
|
||||
Sujeevan Vijayakumaran).
|
||||
- New 'recurrence' configuration setting can disable recurring task generation.
|
||||
|
||||
2.4.0 (2015-01-01) 670102842c39bdc62ef84ae4b679a8f5a2d89523
|
||||
|
||||
- TD-42 Cannot compile taskd - GNUTLS_VERSION undefined in diag.cpp (thanks
|
||||
to Michele Vetturi).
|
||||
- TD-45 Fix preprocessor define (thanks to Jochen Sprickerhof).
|
||||
- TD-55 TLSServer/Client need to include <errno.h> on Solaris (thanks to Tatjana
|
||||
Heuser). Also applied to NetBSD.
|
||||
- TD-55 TLSServer/Client need to include <errno.h> on Solaris (thanks to
|
||||
Tatjana Heuser). Also applied to NetBSD.
|
||||
- TD-56 File.cpp needs to include <string.h> on Solaris (thanks to Tatjana
|
||||
Heuѕer).
|
||||
- TD-57 taskdctl script assumes /bin/sh is /bin/bash (thanks to Tatjana Heuser).
|
||||
@@ -45,6 +183,7 @@
|
||||
- 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
|
||||
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
|
||||
Cory Donnelly).
|
||||
- TW-72 extend info report with urgency column.
|
||||
@@ -286,8 +425,6 @@
|
||||
- Supports 'debug.parser' configuration setting.
|
||||
- Supports 'color.label.sort' for column labels of sort columns.
|
||||
|
||||
------ current release ---------------------------
|
||||
|
||||
2.3.0 (2014-01-15) c4eb46507031b7dee839dcb932bb2a22b2f0d3a2
|
||||
|
||||
Features
|
||||
|
||||
22
DEVELOPER
22
DEVELOPER
@@ -1,9 +1,15 @@
|
||||
How to Build Taskwarrior
|
||||
|
||||
Satisfy the Requirements:
|
||||
- gcc 4.7 or later, clang 3.3 or later or equivalent. This is because 2.4.4
|
||||
will be utilizing C++11.
|
||||
- libuuid
|
||||
- gnutls (optional)
|
||||
|
||||
Obtain and build code:
|
||||
$ git clone https://git.tasktools.org/scm/tm/task.git task.git
|
||||
$ cd task.git
|
||||
$ git checkout 2.4.0 # Latest dev branch
|
||||
$ git checkout 2.4.4 # Latest dev branch
|
||||
$ cmake -DCMAKE_BUILD_TYPE=debug . # debug or release. Default: neither.
|
||||
$ make VERBOSE=1 # Shows details
|
||||
|
||||
@@ -18,8 +24,9 @@ How to Build Taskwarrior
|
||||
current development branch. The source tarballs do not reflect HEAD, and do
|
||||
not contain the test suite.
|
||||
|
||||
If you send us a patch, make sure that patch is made against git HEAD. We
|
||||
cannot apply patches made against the tarball source.
|
||||
If you send a patch (support@taskwarrior.org), make sure that patch is made
|
||||
against git HEAD on the development branch. We cannot apply patches made
|
||||
against the tarball source, or master.
|
||||
|
||||
General Statement
|
||||
This file is intended to convey the current efforts, priorities and needs of
|
||||
@@ -181,12 +188,11 @@ Work in Progress
|
||||
Current Codebase Condition
|
||||
|
||||
'master' branch:
|
||||
- 2.3.0 Current release, locked.
|
||||
- 2.4.3 Current release, locked.
|
||||
|
||||
'2.4.0' branch:
|
||||
- Current development branch with new command line parser, expressions,
|
||||
and heading for beta soon.
|
||||
'2.4.4' branch:
|
||||
- Current development branch no plans yet.
|
||||
|
||||
---
|
||||
|
||||
2014-10-12 Updated for 2.4.0
|
||||
2015-04-21 Updated for 2.4.4
|
||||
|
||||
@@ -24,7 +24,7 @@ Command Line Parsing
|
||||
determines whether subsequent arguments are interpreted as part of a filter or
|
||||
set of modifications.
|
||||
|
||||
The Parser object is fed command line arguments, then through a succession of
|
||||
The CLI object is fed command line arguments, then through a succession of
|
||||
calls builds and annotates a parse tree. To help with this, the Lexer is
|
||||
used to break up strings into tokens.
|
||||
|
||||
|
||||
66
INSTALL
66
INSTALL
@@ -1,16 +1,26 @@
|
||||
Installation Instructions
|
||||
-------------------------
|
||||
|
||||
Please follow the instructions below to build task with cmake.
|
||||
Please follow the instructions below to build and install Taskwarrior from
|
||||
source.
|
||||
|
||||
|
||||
Pre-requisites
|
||||
--------------
|
||||
|
||||
You will need the CMake build system installed in order to build taskwarrior
|
||||
from source.
|
||||
You will need the CMake build system installed in order to build Taskwarrior
|
||||
from source. More information on cmake can be obtained at http://cmake.org
|
||||
|
||||
More information on cmake can be obtained at http://cmake.org
|
||||
You will also need:
|
||||
- make
|
||||
|
||||
You will need a C++ compiler that supports full C++11, which includes:
|
||||
- gcc 4.7 (released 2012-03-23)
|
||||
- clang 3.3 (released 2013-01-07)
|
||||
|
||||
You will need the following libraries:
|
||||
- libuuid
|
||||
- gnutls (optional - for syncing)
|
||||
|
||||
It is HIGHLY RECOMMENDED that you build with a library that provides uuid_*
|
||||
functions, such as libuuid.
|
||||
@@ -19,14 +29,14 @@ functions, such as libuuid.
|
||||
Basic Installation
|
||||
------------------
|
||||
|
||||
Briefly, these shell commands will unpack, build and install taskwarrior:
|
||||
Briefly, these shell commands will unpack, build and install Taskwarrior:
|
||||
|
||||
$ tar xzf task-X.Y.Z.tar.gz [1]
|
||||
$ cd task-X.Y.Z [2]
|
||||
$ cmake . [3]
|
||||
$ make [4]
|
||||
$ sudo make install [5]
|
||||
$ cd .. ; rm -r task-X.Y.Z [6]
|
||||
$ tar xzf task-X.Y.Z.tar.gz [1]
|
||||
$ cd task-X.Y.Z [2]
|
||||
$ cmake . [3]
|
||||
$ make [4]
|
||||
$ sudo make install [5]
|
||||
$ cd .. ; rm -r task-X.Y.Z [6]
|
||||
|
||||
These commands are explained below:
|
||||
|
||||
@@ -38,7 +48,7 @@ These commands are explained below:
|
||||
3. Invokes CMake to scan for dependencies and machine-specific details, then
|
||||
generate the makefiles. This may take a minute.
|
||||
|
||||
4. Builds taskwarrior. This may take a minute.
|
||||
4. Builds Taskwarrior. This may take a minute.
|
||||
|
||||
5. Installs the program, documentation and other data files.
|
||||
|
||||
@@ -92,29 +102,31 @@ Currently the defined languages are:
|
||||
|
||||
eng_USA 1
|
||||
esp_ESP 2
|
||||
deu_DEU 3
|
||||
fra_FRA 4
|
||||
ita_ITA 5
|
||||
por_PRT 6
|
||||
epo_RUS 7
|
||||
pol_POL 8
|
||||
|
||||
|
||||
Uninstallation
|
||||
--------------
|
||||
|
||||
To uninstall taskwarrior, you need the Makefiles, so if you deleted them in
|
||||
step 7 above, they must first be regenerated by following steps [1], [2] and
|
||||
[3]. Then simply run:
|
||||
There is no uninstall option in CMake makefiles. This is a manual process.
|
||||
|
||||
$ sudo make uninstall TODO TODO TODO -- cmake doesn't include uninstall
|
||||
To uninstall Taskwarrior, remove the files listed in the install_manifest.txt
|
||||
file that was generated when you built Taskwarrior.
|
||||
|
||||
|
||||
Taskwarrior Build Notes
|
||||
-----------------------
|
||||
|
||||
Taskwarrior has dependencies that are detected by cmake in almost all cases, but
|
||||
Taskwarrior has dependencies that are detected by CMake in almost all cases, but
|
||||
there are situations and operating systems that mean you will need to offer a
|
||||
little help.
|
||||
|
||||
If taskwarrior will not build on your system, first take a look at the Operating
|
||||
If Taskwarrior will not build on your system, first take a look at the Operating
|
||||
System notes below. If this doesn't help, then go to the Troubleshooting
|
||||
section, which includes instructions on how to contact us for help.
|
||||
|
||||
@@ -131,9 +143,7 @@ Cygwin
|
||||
|
||||
|
||||
Darwin, 32bit
|
||||
The taskwarrior packages will not work on a 32-bit OSX installation on Core
|
||||
Duo hardware. You will need to build Taskwarrior from source, and use this
|
||||
configure command:
|
||||
Taskwarrior needs to be built from source, and use this configure command:
|
||||
|
||||
cmake -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 -DCMAKE_EXE_LINKER_FLAGS=-m32 .
|
||||
|
||||
@@ -144,6 +154,18 @@ Darwin, 32bit
|
||||
http://stackoverflow.com/questions/6077414/cmake-how-to-set-the-ldflags-in-cmakelists-txt
|
||||
|
||||
|
||||
OpenBSD
|
||||
In order to build Taskwarrior 2.4.2+, you might need to install a newer GCC
|
||||
version from ports or packages.
|
||||
|
||||
Afterwards, run
|
||||
cmake -DCMAKE_CXX_COMPILER=eg++ .
|
||||
|
||||
and build normally.
|
||||
|
||||
See: https://bug.tasktools.org/browse/TW-1579
|
||||
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
@@ -160,7 +182,7 @@ If a build does not succeed, please send the contents of the 'CMakeCache.txt'
|
||||
and 'CMakeFiles/CMakeOutput.log' files to support@taskwarrior.org, or post a
|
||||
message in the support forums at taskwarrior.org along with the information.
|
||||
|
||||
If CMake runs but taskwarrior does not build, please send the contents of the
|
||||
If CMake runs but Taskwarrior does not build, please send the contents of the
|
||||
above files as well as a transcript from the build, which is not written to a
|
||||
file and must be captured from the terminal.
|
||||
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
taskwarrior - a command line task list manager.
|
||||
Taskwarrior - a command line task list manager.
|
||||
|
||||
Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
|
||||
|
||||
|
||||
100
NEWS
100
NEWS
@@ -1,98 +1,40 @@
|
||||
|
||||
New Features in taskwarrior 2.4.0
|
||||
New Features in Taskwarrior 2.4.4
|
||||
|
||||
- The 'show' command displays default configuration values, when appropriate.
|
||||
- Removed deprecated commands 'push', 'pull' and 'merge'.
|
||||
- Portuguese (por-PRT), French (fra-FRA), Esperanto (epo-RUS) and Polish
|
||||
(pol-POL) localizations.
|
||||
- Better handling for deletion of recurring tasks.
|
||||
- New virtual tags: YESTERDAY, TOMORROW, READY, PENDING, COMPLETED, DELETED,
|
||||
TAGGED.
|
||||
- The '_get' command properly uses exit codes.
|
||||
- Regular expressions are now enabled by default.
|
||||
- The 'filter' verbosity token shows the complete filter used for the last
|
||||
command.
|
||||
- The 'new-uuid' verbosity token shows the UUID of newly created tasks.
|
||||
- The 'info' report now breaks down urgency values.
|
||||
- New 'color.until' color rule.
|
||||
- Using a non-zero 'urgency.inherit.coefficient' value means a task inherits
|
||||
the urgency values of the dependency chain.
|
||||
- Listing breaks now supported. See 'man taskrc'.
|
||||
- New fish shell completion script.
|
||||
- The filter form 'name:value' now maps to the partial match operator '=',
|
||||
rather than the exact match operator, '=='. This means that dates now
|
||||
match on the day by default, not the time also.
|
||||
- UDA indicator format.
|
||||
- Hooks.
|
||||
- New and updated holidays.rc files.
|
||||
- Taskwarrior now requires GCC 4.7+ / Clang 3.3+, for full C++11 support.
|
||||
- Taskwarrior now builds properly on 32-bit platforms.
|
||||
- The beginnings of a Japaneѕe translation.
|
||||
|
||||
New commands in taskwarrior 2.4.0
|
||||
New commands in Taskwarrior 2.4.4
|
||||
|
||||
- New 'calc' command (and standalone utility) for quick command line
|
||||
calculations.
|
||||
- None
|
||||
|
||||
New configuration options in taskwarrior 2.4.0
|
||||
New configuration options in Taskwarrior 2.4.4
|
||||
|
||||
- The 'taskd.trust' setting is now a tri-state, supporting values 'strict',
|
||||
'ignore hostname' and 'allow all', for server certificate validation.
|
||||
- New theme: dark-gray-blue-256.theme
|
||||
- The 'allow.empty.filter' setting can be set to 'no' to disallow the
|
||||
potentially dangerous combination of write commands and empty filters.
|
||||
- New truncated_count column style for the description field which as the
|
||||
name says is a combination of the existing truncated and count styles.
|
||||
- New 'hooks' setting is a master control switch for hook processing.
|
||||
- New 'debug.hooks' for debugging hook scripts.
|
||||
- New 'debug.parser' for debugging parser issues scripts.
|
||||
- New 'color.label.sort' is used to color the column label of sort columns.
|
||||
- New 'urgency.uda.<name>.<value>' allows specific UDA values to affect
|
||||
urgency.
|
||||
- New 'recurrence.confirmation' which allows bypassing confirmation for
|
||||
changes to recurring tasks, by accepting, rejecting or prompting.
|
||||
- New 'uda.<name>.indicator' to override the UDA indicator.
|
||||
- The 'obfuscate' setting, if set to '1' will replace all text with 'xxx'.
|
||||
This is useful when sharing data for bug reporting purposes.
|
||||
|
||||
Newly deprecated features in taskwarrior 2.4.0
|
||||
Newly deprecated features in Taskwarrior 2.4.4
|
||||
|
||||
- The alias '_query' is deprecated.
|
||||
- Bare word search terms are deprecated, so 'task pattern list' will not
|
||||
be supported in future releases, instead requiring 'task /pattern/ list'.
|
||||
- The 'limit' pseudo attribute will change to 'rc.limit' in a future release.
|
||||
- None
|
||||
|
||||
Removed features in 2.4.0
|
||||
Removed features in 2.4.4
|
||||
|
||||
- Version 1.x column names no longer supported.
|
||||
- Version 1.x sort columns no longer supported.
|
||||
- Old-style color names including underscores are no longer supported.
|
||||
- Removed priority counts from the 'projects' commands.
|
||||
- Removed the unused 'locale' configuration variable.
|
||||
- Removed the unused 'patterns' confguration variable.
|
||||
- Removed the obsolete 'task-faq.5' man page.
|
||||
- Removed the obsolete 'task-tutorial.5' man page.
|
||||
- Removed the obsolete 'tasksh.1' man page.
|
||||
- Removed the 'tasksh' program from the Taskwarrior distribution. It is now
|
||||
a separate project.
|
||||
- Removed the 'complete.all.projects' setting that was not used.
|
||||
- Removed support for 'report.X.limit', which can now be set in the report
|
||||
filter 'limit:N'.
|
||||
- The 'total active time' information is removed from the 'info' report.
|
||||
This was being misinterpreted as support for time tracking.
|
||||
- The 'shadow file' feature is removed, but replaced with an example hook
|
||||
script that performs the same function..
|
||||
- None
|
||||
|
||||
Known Issues
|
||||
|
||||
- On Cygwin, case-insensitive regex searches are broken. The default is
|
||||
now case-sensitive for Cygwin only.
|
||||
- https://bug.tasktools.org
|
||||
- https://bug.tasktools.org/
|
||||
|
||||
Taskwarrior has been built and tested on the following configurations:
|
||||
|
||||
* OS X 10.10 Yosemite, 10.9 Mavericks
|
||||
* Fedora 20 Heisenbug
|
||||
* Ubuntu 14.04 Trusty Tahr
|
||||
* Debian 7.0 Wheezy (stable)
|
||||
* Arch 2014.05
|
||||
* FreeBSD 10
|
||||
* Cygwin 1.7.29, 1.7.32
|
||||
* OS X
|
||||
* Fedora
|
||||
* Ubuntu
|
||||
* Debian
|
||||
* Arch
|
||||
* FreeBSD
|
||||
* Cygwin
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ Please send your code patches to:
|
||||
support@taskwarrior.org
|
||||
|
||||
Consider joining bug.tasktools.org, answers.tasktools.org and participating in
|
||||
the future of taskwarrior.
|
||||
the future of Taskwarrior.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#define LANGUAGE_POR_PRT ${LANGUAGE_POR_PRT}
|
||||
#define LANGUAGE_EPO_RUS ${LANGUAGE_EPO_RUS}
|
||||
#define LANGUAGE_POL_POL ${LANGUAGE_POL_POL}
|
||||
#define LANGUAGE_JPN_JPN ${LANGUAGE_JPN_JPN}
|
||||
|
||||
/* git information */
|
||||
#cmakedefine HAVE_COMMIT
|
||||
@@ -51,12 +52,6 @@
|
||||
/* Found the GnuTLS library */
|
||||
#cmakedefine HAVE_LIBGNUTLS
|
||||
|
||||
/* Found the Readline library */
|
||||
#cmakedefine HAVE_READLINE
|
||||
|
||||
/* Found the pthread library */
|
||||
#cmakedefine HAVE_LIBPTHREAD
|
||||
|
||||
/* Found tm_gmtoff */
|
||||
#cmakedefine HAVE_TM_GMTOFF
|
||||
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
# - Find the readline library
|
||||
# This module defines
|
||||
# READLINE_INCLUDE_DIR, path to readline/readline.h, etc.
|
||||
# READLINE_LIBRARIES, the libraries required to use READLINE.
|
||||
# READLINE_FOUND, If false, do not try to use READLINE.
|
||||
# also defined, but not for general use are
|
||||
# READLINE_readline_LIBRARY, where to find the READLINE library.
|
||||
# READLINE_ncurses_LIBRARY, where to find the ncurses library [might not be defined]
|
||||
|
||||
# Apple readline does not support readline hooks
|
||||
# So we look for another one by default
|
||||
IF (APPLE OR FREEBSD)
|
||||
FIND_PATH (READLINE_INCLUDE_DIR NAMES readline/readline.h PATHS
|
||||
/usr/include/
|
||||
/sw/include
|
||||
/opt/local/include
|
||||
/opt/include
|
||||
/usr/local/include
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
ENDIF (APPLE OR FREEBSD)
|
||||
FIND_PATH (READLINE_INCLUDE_DIR NAMES readline/readline.h)
|
||||
|
||||
|
||||
# Apple readline does not support readline hooks
|
||||
# So we look for another one by default
|
||||
IF (APPLE OR FREEBSD)
|
||||
FIND_LIBRARY (READLINE_readline_LIBRARY NAMES readline PATHS
|
||||
/usr/lib
|
||||
/sw/lib
|
||||
/opt/local/lib
|
||||
/opt/lib
|
||||
/usr/local/lib
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
ENDIF (APPLE OR FREEBSD)
|
||||
FIND_LIBRARY (READLINE_readline_LIBRARY NAMES readline)
|
||||
|
||||
# Sometimes readline really needs ncurses
|
||||
IF (APPLE OR FREEBSD)
|
||||
FIND_LIBRARY (READLINE_ncurses_LIBRARY NAMES ncurses PATHS
|
||||
/usr/lib
|
||||
/sw/lib
|
||||
/opt/local/lib
|
||||
/opt/lib
|
||||
/usr/local/lib
|
||||
/usr/lib
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
ENDIF (APPLE OR FREEBSD)
|
||||
FIND_LIBRARY (READLINE_ncurses_LIBRARY NAMES ncurses)
|
||||
|
||||
MARK_AS_ADVANCED (
|
||||
READLINE_INCLUDE_DIR
|
||||
READLINE_readline_LIBRARY
|
||||
READLINE_ncurses_LIBRARY
|
||||
)
|
||||
|
||||
SET (READLINE_FOUND "NO" )
|
||||
IF (READLINE_INCLUDE_DIR)
|
||||
IF (READLINE_readline_LIBRARY)
|
||||
SET (READLINE_FOUND "YES" )
|
||||
SET (READLINE_LIBRARIES
|
||||
${READLINE_readline_LIBRARY}
|
||||
)
|
||||
|
||||
# some readline libraries depend on ncurses
|
||||
IF (READLINE_ncurses_LIBRARY)
|
||||
SET (READLINE_LIBRARIES ${READLINE_LIBRARIES} ${READLINE_ncurses_LIBRARY})
|
||||
ENDIF (READLINE_ncurses_LIBRARY)
|
||||
|
||||
ENDIF (READLINE_readline_LIBRARY)
|
||||
ENDIF (READLINE_INCLUDE_DIR)
|
||||
|
||||
IF (READLINE_FOUND)
|
||||
MESSAGE (STATUS "Found readline library")
|
||||
ELSE (READLINE_FOUND)
|
||||
IF (READLINE_FIND_REQUIRED)
|
||||
MESSAGE (FATAL_ERROR "Could not find readline -- please give some paths to CMake")
|
||||
ENDIF (READLINE_FIND_REQUIRED)
|
||||
ENDIF (READLINE_FOUND)
|
||||
@@ -1,7 +1,7 @@
|
||||
.TH task-color 5 2015-01-01 "${PACKAGE_STRING}" "User Manuals"
|
||||
.TH task-color 5 2015-05-10 "${PACKAGE_STRING}" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
task-color \- A color tutorial for the taskwarrior command line todo manager.
|
||||
task-color \- A color tutorial for the Taskwarrior command line todo manager.
|
||||
|
||||
.SH SETUP
|
||||
The first thing you need is a terminal program that supports color. All
|
||||
@@ -18,8 +18,8 @@ which shell you use). If this is a new setting, you will need to either run
|
||||
that profile script, or close and reopen the terminal window (which does the
|
||||
same thing).
|
||||
|
||||
Now tell taskwarrior that you want to use color. This is the default for
|
||||
taskwarrior, so the following step may be unnecessary.
|
||||
Now tell Taskwarrior that you want to use color. This is the default for
|
||||
Taskwarrior, so the following step may be unnecessary.
|
||||
|
||||
$ task config color on
|
||||
|
||||
@@ -28,11 +28,11 @@ like:
|
||||
|
||||
color=on
|
||||
|
||||
Now taskwarrior is ready.
|
||||
Now Taskwarrior is ready.
|
||||
|
||||
.SH AUTOMATIC MONOCHROME
|
||||
It should be mentioned that taskwarrior is aware of whether its output is going
|
||||
to a terminal, or to a file or through a pipe. When taskwarrior output goes to
|
||||
It should be mentioned that Taskwarrior is aware of whether its output is going
|
||||
to a terminal, or to a file or through a pipe. When Taskwarrior output goes to
|
||||
a terminal, color is desirable, but consider the following command:
|
||||
|
||||
$ task list > file.txt
|
||||
@@ -268,7 +268,7 @@ from the example):
|
||||
include ${CMAKE_INSTALL_PREFIX}/${TASK_RCDIR}/dark-256.theme
|
||||
.RE
|
||||
|
||||
You can use any of the standard taskwarrior themes:
|
||||
You can use any of the standard Taskwarrior themes:
|
||||
|
||||
.RS
|
||||
dark-16.theme
|
||||
@@ -323,7 +323,7 @@ http://www.opensource.org/licenses/mit-license.php for more information.
|
||||
.BR taskrc(5),
|
||||
.BR task-sync(5)
|
||||
|
||||
For more information regarding taskwarrior, the following may be referenced:
|
||||
For more information regarding Taskwarrior, the following may be referenced:
|
||||
|
||||
.TP
|
||||
The official site at
|
||||
@@ -339,5 +339,5 @@ You can contact the project by writing an email to
|
||||
|
||||
.SH REPORTING BUGS
|
||||
.TP
|
||||
Bugs in taskwarrior may be reported to the issue-tracker at
|
||||
Bugs in Taskwarrior may be reported to the issue-tracker at
|
||||
<http://taskwarrior.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.TH task-sync 5 2015-01-01 "${PACKAGE_STRING}" "User Manuals"
|
||||
.TH task-sync 5 2015-05-10 "${PACKAGE_STRING}" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
task-sync \- A discussion and tutorial for the various task(1) data
|
||||
@@ -80,24 +80,25 @@ The Taskserver was designed for this purpose to be secure, fast and conflict
|
||||
free, allowing data interchange between assorted Taskwarrior clients, and
|
||||
tolerant of network connectivity problems.
|
||||
|
||||
There is a 'sync' command built in to Taskwarrior, and with a server account
|
||||
and client configuration, syncing is done on demand.
|
||||
There is a 'sync' command built in to Taskwarrior (provided the GnuTLS library
|
||||
is installed), and with a server account and client configuration, syncing is
|
||||
done on demand.
|
||||
|
||||
Setup is a matter of creating an account on a Taskserver (see your Taskserver
|
||||
provider or operate your own - see
|
||||
http://taskwarrior.org/docs/server_setup.html)
|
||||
|
||||
Once you have an account, you'll receive a certificate, key and a password.
|
||||
Once you have an account, you'll receive a certificate, key, and credentials.
|
||||
You'll need to put the certificate and key somewhere like this:
|
||||
|
||||
$ cp <name>.cert.pem ~/.task
|
||||
$ cp <name>.key.pem ~/.task
|
||||
|
||||
Then you configure Taskwarrior, using the account details:
|
||||
Then you configure Taskwarrior, using the provided details:
|
||||
|
||||
$ task config taskd.certificate ~/.task/<name>.cert.pem
|
||||
$ task config taskd.key ~/.task/<name>.key.pem
|
||||
$ task config taskd.credentials <organization>/<name>/<password>
|
||||
$ task config taskd.credentials <organization>/<name>/<UUID>
|
||||
$ task config taskd.server <server domain>:<port>
|
||||
|
||||
If you are using a private server, you are likely also using a self-signed
|
||||
@@ -108,7 +109,7 @@ certificate, which means you will need one of the following additional entries:
|
||||
The CA (Certificate Authority) will be used to verify the server certificate.
|
||||
Alternatively, you can override the cert verification process using:
|
||||
|
||||
$ task config taskd.trust yes
|
||||
$ task config taskd.trust 'allow all'
|
||||
|
||||
This is an insecure option that should be used with caution, because it directs
|
||||
Taskwarrior to trust any certificate.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.TH task 1 2015-01-01 "${PACKAGE_STRING}" "User Manuals"
|
||||
.TH task 1 2015-05-10 "${PACKAGE_STRING}" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
task \- A command line todo manager.
|
||||
@@ -14,7 +14,7 @@ that you want to do, allowing you to add/remove, and otherwise manipulate them.
|
||||
Taskwarrior has a rich set of subcommands that allow you to do various things
|
||||
with it.
|
||||
|
||||
At the core, taskwarrior is a list processing program. You add text and
|
||||
At the core, Taskwarrior is a list processing program. You add text and
|
||||
additional related parameters and redisplay the information in a nice way. It
|
||||
turns into a todo list program when you add due dates and recurrence. It turns
|
||||
into an organized todo list program when you add priorities, tags (one word
|
||||
@@ -98,7 +98,7 @@ generated, as with verbose=nothing).
|
||||
.SH READ SUBCOMMANDS
|
||||
|
||||
Reports are read subcommands. There are several reports currently predefined in
|
||||
taskwarrior. The output and sort behavior of these reports can be configured in
|
||||
Taskwarrior. The output and sort behavior of these reports can be configured in
|
||||
the configuration file. See also the man page taskrc(5). There are also other
|
||||
read subcommands that are not reports.
|
||||
|
||||
@@ -379,9 +379,25 @@ time from the specified task.
|
||||
Miscellaneous subcommands either accept no command line arguments, or accept
|
||||
non-standard arguments.
|
||||
|
||||
.TP
|
||||
.B task calc <expression>
|
||||
Evaluates an algebraic expression. Can be used to test how Taskwarrior
|
||||
parses and evaluates the expression given on the command line.
|
||||
|
||||
Examples:
|
||||
|
||||
task calc 1 + 1
|
||||
2
|
||||
|
||||
task calc now + 8d
|
||||
2015-03-26T18:06:57
|
||||
|
||||
task calc eom
|
||||
2015-03-31T23:59:59
|
||||
|
||||
.TP
|
||||
.B task config [name [value | '']]
|
||||
Add, modify and remove settings directly in the taskwarrior configuration.
|
||||
Add, modify and remove settings directly in the Taskwarrior configuration.
|
||||
This command either modifies the 'name' setting with a new value of 'value',
|
||||
or adds a new entry that is equivalent to 'name=value':
|
||||
|
||||
@@ -396,6 +412,46 @@ Finally, this command removes any 'name=...' entry from the .taskrc file:
|
||||
|
||||
task config name
|
||||
|
||||
.TP
|
||||
.B task context <name>
|
||||
Sets the currently 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
|
||||
.B task diagnostics
|
||||
Shows diagnostic information, of the kind needed when reporting a problem.
|
||||
@@ -454,7 +510,7 @@ Reverts the most recent action. Obeys the confirmation setting.
|
||||
|
||||
.TP
|
||||
.B task version
|
||||
Shows the taskwarrior version number.
|
||||
Shows the Taskwarrior version number.
|
||||
|
||||
.SH HELPER SUBCOMMANDS
|
||||
|
||||
@@ -474,6 +530,10 @@ Generates a list of all commands, for autocompletion purposes.
|
||||
.B task _config
|
||||
Lists all supported configuration variables, for completion purposes.
|
||||
|
||||
.TP
|
||||
.B task _context
|
||||
Lists all available context variables, for completion purposes.
|
||||
|
||||
.TP
|
||||
.B task <filter> _ids
|
||||
Shows only the IDs of matching tasks, in the form of a list.
|
||||
@@ -506,7 +566,7 @@ Displays the urgency measure of a task.
|
||||
|
||||
.TP
|
||||
.B task _version
|
||||
Shows only the taskwarrior version number.
|
||||
Shows only the Taskwarrior version number.
|
||||
|
||||
.TP
|
||||
.B task _zshcommands
|
||||
@@ -810,7 +870,7 @@ The original example therefore must be entered as:
|
||||
task '( project:Home or project:Garden )' list
|
||||
|
||||
This includes quotes to escape the parentheses, so that the shell doesn't
|
||||
interpret them and hide them from taskwarrior.
|
||||
interpret them and hide them from Taskwarrior.
|
||||
|
||||
There is redundancy between operators, attribute modifiers and other syntactic
|
||||
sugar. For example, the following are all equivalent:
|
||||
@@ -962,8 +1022,68 @@ biannual, biyearly, 2yr
|
||||
Every two years.
|
||||
.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
|
||||
All taskwarrior commands may be abbreviated as long as a unique prefix is used,
|
||||
All Taskwarrior commands may be abbreviated as long as a unique prefix is used,
|
||||
for example:
|
||||
|
||||
.RS
|
||||
@@ -1002,7 +1122,7 @@ $ task add "quoted ' quote"
|
||||
$ task add escaped \\' quote
|
||||
.RE
|
||||
|
||||
The argument \-\- (a double dash) tells taskwarrior to treat all other args
|
||||
The argument \-\- (a double dash) tells Taskwarrior to treat all other args
|
||||
as description:
|
||||
|
||||
.RS
|
||||
@@ -1057,11 +1177,11 @@ the 'data.location' configuration setting of the task data directory.
|
||||
For examples please see the online documentation starting at
|
||||
|
||||
.RS
|
||||
<http://taskwarrior.org/projects/taskwarrior/wiki>
|
||||
<http://taskwarrior.org/docs>
|
||||
.RE
|
||||
|
||||
Note that the online documentation is more detailed and more current than this
|
||||
man page.
|
||||
Note that the online documentation can be more detailed and more current than
|
||||
this man page.
|
||||
|
||||
.SH FILES
|
||||
|
||||
@@ -1099,7 +1219,7 @@ http://www.opensource.org/licenses/mit-license.php for more information.
|
||||
.BR task-color(5),
|
||||
.BR task-sync(5)
|
||||
|
||||
For more information regarding taskwarrior, see the following:
|
||||
For more information regarding Taskwarrior, see the following:
|
||||
|
||||
.TP
|
||||
The official site at
|
||||
@@ -1115,6 +1235,6 @@ You can contact the project by emailing
|
||||
|
||||
.SH REPORTING BUGS
|
||||
.TP
|
||||
Bugs in taskwarrior may be reported to the issue-tracker at
|
||||
Bugs in Taskwarrior may be reported to the issue-tracker at
|
||||
<http://taskwarrior.org>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.TH taskrc 5 2015-01-01 "${PACKAGE_STRING}" "User Manuals"
|
||||
.TH taskrc 5 2015-05-10 "${PACKAGE_STRING}" "User Manuals"
|
||||
|
||||
.SH NAME
|
||||
taskrc \- Configuration details for the task(1) command
|
||||
@@ -11,7 +11,7 @@ taskrc \- Configuration details for the task(1) command
|
||||
.B TASKRC=<directory-path>/.taskrc task ...
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B taskwarrior
|
||||
.B Taskwarrior
|
||||
obtains its configuration data from a file called
|
||||
.I .taskrc
|
||||
\&. This file is normally located in the user's home directory:
|
||||
@@ -49,43 +49,56 @@ $ task rc.<name>=<value> ...
|
||||
.RE
|
||||
|
||||
If
|
||||
.B taskwarrior
|
||||
.B Taskwarrior
|
||||
is run without an existing configuration file it will ask if it should create a
|
||||
default, sample
|
||||
.I .taskrc
|
||||
file in the user's home directory.
|
||||
|
||||
The taskwarrior configuration file consists of a series of assignments in each
|
||||
line. The assignments have the syntax:
|
||||
The .taskrc file follows a very simply syntax defining name/value pairs:
|
||||
|
||||
.RS
|
||||
<name-of-configuration-variable>=<value-to-be-set>
|
||||
<name> = <value>
|
||||
.RE
|
||||
|
||||
where:
|
||||
.RS
|
||||
.TP
|
||||
<name-of-configuration-variable>
|
||||
is one of the variables described below
|
||||
There may be whitespace around <name>, '=' and <value>, and it is ignored.
|
||||
Whitespace within the <value> is left intact.
|
||||
Whitespace is not permitted in comma-separated lists.
|
||||
The entry must be on a single line, no continuations.
|
||||
Values support UTF8 as well as JSON encoding, such as \\uNNNN.
|
||||
|
||||
.TP
|
||||
<value-to-be-set>
|
||||
is the value the variable is to be set to.
|
||||
.RE
|
||||
|
||||
and set a configuration variable to a certain value. The equal sign ("=") is
|
||||
used to separate the variable name from the value to be set.
|
||||
|
||||
The hash mark, or pound sign ("#") is used as a comment character. It can be
|
||||
used to annotate the configuration file. All text after the character to the end
|
||||
of the line is ignored.
|
||||
|
||||
The configuration file supports UTF8 as well as JSON encoding, such as \\uNNNN.
|
||||
|
||||
Note that taskwarrior is flexible about the values used to represent Boolean
|
||||
Note that Taskwarrior is flexible about the values used to represent Boolean
|
||||
items. You can use "on", "yes", "y", "1" and "true".
|
||||
Anything else means "off".
|
||||
|
||||
.RS
|
||||
include <file>
|
||||
.RE
|
||||
|
||||
There may be whitespace around 'include' and <file>. The file may be an
|
||||
absolute or relative path, and the special character '~' is expanded to mean
|
||||
$HOME.
|
||||
The entry must be on a single line, no continuations.
|
||||
|
||||
.RS
|
||||
# <comment>
|
||||
.RE
|
||||
|
||||
A comment consists of the character '#', and extends from the '#' to the end
|
||||
of the line. There is no way to comment a multi-line block. There may be
|
||||
blank lines.
|
||||
|
||||
Almost every value has a default setting, and an empty .taskrc file is one
|
||||
that makes use of every default. The contents of the .taskrc file therefore
|
||||
represent overrides of the default values. To remove a default value completely
|
||||
there must be an entry like this:
|
||||
|
||||
.RS
|
||||
<name> =
|
||||
.RE
|
||||
|
||||
This entry overrides the default value with a blank value.
|
||||
|
||||
.SH EDITING
|
||||
You can edit your .taskrc file by hand if you wish, or you can use the 'config'
|
||||
command. To permanently set a value in your .taskrc file, use this command:
|
||||
@@ -136,7 +149,7 @@ include ${CMAKE_INSTALL_PREFIX}/${TASK_RCDIR}/holidays.en-US.rc
|
||||
include ${CMAKE_INSTALL_PREFIX}/${TASK_RCDIR}/dark-16.theme
|
||||
.RE
|
||||
|
||||
This includes two standard files that are distributed with taskwarrior, which
|
||||
This includes two standard files that are distributed with Taskwarrior, which
|
||||
define a set of US holidays, and set up a 16-color theme to use, to color the
|
||||
reports and calendar.
|
||||
|
||||
@@ -145,7 +158,7 @@ These environment variables override defaults and command line arguments.
|
||||
|
||||
.TP
|
||||
.B TASKDATA=~/.task
|
||||
This overrides the default path for the taskwarrior data files.
|
||||
This overrides the default path for the Taskwarrior data files.
|
||||
|
||||
.TP
|
||||
.B TASKRC=~/.taskrc
|
||||
@@ -158,7 +171,7 @@ Valid variable names and their default values are:
|
||||
|
||||
.TP
|
||||
.B data.location=$HOME/.task
|
||||
This is a path to the directory containing all the taskwarrior files. By
|
||||
This is a path to the directory containing all the Taskwarrior files. By
|
||||
default, it is set up to be ~/.task, for example: /home/paul/.task
|
||||
|
||||
Note that you can use the
|
||||
@@ -281,15 +294,14 @@ and project. The others are sent to standard output.
|
||||
|
||||
.TP
|
||||
.B confirmation=yes
|
||||
May be "yes" or "no", and determines whether taskwarrior will ask for
|
||||
confirmation before deleting a task, performing bulk changes, or the undo
|
||||
command. The default value is "yes". Consider leaving this setting as "yes",
|
||||
for safety.
|
||||
May be "yes" or "no", and determines whether Taskwarrior will ask for
|
||||
confirmation before deleting a task or performing the undo command. The default
|
||||
value is "yes". Consider leaving this setting as "yes", for safety.
|
||||
|
||||
.TP
|
||||
.B allow.empty.filter=yes
|
||||
An empty filter combined with a write command is potentially a way to modify
|
||||
all tasks by mistkae, and when this is detected, confirmation is required.
|
||||
all tasks by mistake, and when this is detected, confirmation is required.
|
||||
Setting this to 'no' means that it is an error to use a write command with no
|
||||
filter.
|
||||
|
||||
@@ -313,25 +325,30 @@ Controls padding between columns of the report output. Default is "1".
|
||||
.TP
|
||||
.B bulk=3
|
||||
Is a number, defaulting to 3. When this number or greater of tasks are modified
|
||||
in a single command, confirmation will be required, unless the
|
||||
in a single command, confirmation will be required, regardless of the value of
|
||||
.B confirmation
|
||||
variable is "no".
|
||||
variable. The special value bulk=0 is treated as an infinity.
|
||||
|
||||
This is useful for preventing large-scale unintended changes.
|
||||
|
||||
.TP
|
||||
.B nag=You have more urgent tasks.
|
||||
This may be a string of text, or blank. It is used as a prompt when a task is
|
||||
started or completed that is not considered high priority. Default value is:
|
||||
You have more urgent tasks. It is a gentle reminder that you are contradicting
|
||||
your own priority settings.
|
||||
This may be a string of text, or blank. It is used as a prompt when a task is
|
||||
started of completed, when there are other tasks with a higher urgency.
|
||||
Default value is: 'You have more urgent tasks'.
|
||||
It is a gentle reminder that you are contradicting your own urgency settings.
|
||||
|
||||
.TP
|
||||
.B list.all.projects=yes
|
||||
.B list.all.projects=no
|
||||
May be yes or no, and determines whether the 'projects' command lists all the project
|
||||
names you have used, or just the ones used in active tasks. The default value is
|
||||
"no".
|
||||
|
||||
.TP
|
||||
.B summary.all.projects=no
|
||||
If set to yes, shows all projects in the summary report, even if there are no
|
||||
pending tasks. The default value is "no".
|
||||
|
||||
.TP
|
||||
.B complete.all.tags=yes
|
||||
May be yes or no, and determines whether the tab completion scripts consider all
|
||||
@@ -371,7 +388,7 @@ Defaults to infix.
|
||||
|
||||
.TP
|
||||
.B dom=on
|
||||
Enables or disables access to taskwarrior internals and task metadata on the
|
||||
Enables or disables access to Taskwarrior internals and task metadata on the
|
||||
command line. Defaults to on.
|
||||
|
||||
.TP
|
||||
@@ -412,6 +429,11 @@ The character or string to show in the depends.indicator column. Defaults to +.
|
||||
.B uda.<name>.indicator=U
|
||||
The character or string to show in the <uda>.indicator column. Defaults to U.
|
||||
|
||||
.TP
|
||||
.B recurrence=yes
|
||||
Controls whether recurrence is enable, and whether recurring tasks continue to
|
||||
generate new task instances. Defaults to 'yes'.
|
||||
|
||||
.TP
|
||||
.B recurrence.confirmation=prompt
|
||||
Controls whether changes to recurring tasks propagates to other child tasks with
|
||||
@@ -432,7 +454,7 @@ and one for a week from tomorrow.
|
||||
|
||||
.TP
|
||||
.B undo.style=side
|
||||
When the 'undo' command is run, taskwarrior presents a before and after
|
||||
When the 'undo' command is run, Taskwarrior presents a before and after
|
||||
comparison of the data. This can be in either the 'side' style, which compares
|
||||
values side-by-side in a table, or 'diff' style, which uses a format similar to
|
||||
the 'diff' command.
|
||||
@@ -480,6 +502,12 @@ shows parse trees from every phase of the parse.
|
||||
Controls the GnuTLS diagnostic level. For 'sync' debugging. Level 0 means no
|
||||
diagnostics. Level 9 is the highest. Level 2 is a good setting for debugging.
|
||||
|
||||
.TP
|
||||
.B obfuscate=1
|
||||
When set to '1', will replace all report text with 'xxx'.
|
||||
This is useful for sharing report output in bug reports.
|
||||
Default value is '0'.
|
||||
|
||||
.TP
|
||||
.B alias.rm=delete
|
||||
Taskwarrior supports command aliases. This alias provides an alternate name
|
||||
@@ -503,7 +531,7 @@ the 'history' report, for example, or 'export'.
|
||||
.B dateformat.annotation=
|
||||
.TP
|
||||
.B report.X.dateformat=Y-M-D
|
||||
This is a string of characters that defines how taskwarrior formats date values.
|
||||
This is a string of characters that defines how Taskwarrior formats date values.
|
||||
The precedence order for the configuration variable is report.X.dateformat then
|
||||
dateformat.report then dateformat for formating the due dates in reports.
|
||||
If both report.X.dateformat and dateformat.report are not set then dateformat
|
||||
@@ -616,6 +644,10 @@ field that is set. Otherwise, they are set to the corresponding values of
|
||||
.RE
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B date.iso=yes
|
||||
Enables ISO-8601 date support. The default value is "yes".
|
||||
|
||||
.TP
|
||||
.B weekstart=Sunday
|
||||
Determines the day a week starts. Valid values are Sunday or Monday only. The
|
||||
@@ -729,7 +761,7 @@ holiday.eastersunday.date=easter
|
||||
.RE
|
||||
.RE
|
||||
|
||||
Note that the taskwarrior distribution contains example holiday files that can
|
||||
Note that the Taskwarrior distribution contains example holiday files that can
|
||||
be included like this:
|
||||
|
||||
.RS
|
||||
@@ -743,7 +775,7 @@ include ${CMAKE_INSTALL_PREFIX}/${TASK_RCDIR}/holidays.en-US.rc
|
||||
.B monthsperline=3
|
||||
Determines how many months the "task calendar" command renders across the
|
||||
screen. Defaults to however many will fit. If more months than will fit are
|
||||
specified, taskwarrior will only show as many that will fit.
|
||||
specified, Taskwarrior will only show as many that will fit.
|
||||
|
||||
.SS DEPENDENCIES
|
||||
|
||||
@@ -759,7 +791,7 @@ Determines whether dependency chain repair requires confirmation.
|
||||
|
||||
.TP
|
||||
.B color=on
|
||||
May be "on" or "off". Determines whether taskwarrior uses color. When "off",
|
||||
May be "on" or "off". Determines whether Taskwarrior uses color. When "off",
|
||||
will use dashes (-----) to underline column headings.
|
||||
|
||||
.TP
|
||||
@@ -820,18 +852,6 @@ Task has at least one tag.
|
||||
.B color.recurring
|
||||
Task is recurring.
|
||||
.br
|
||||
.B color.pri.H
|
||||
Task has priority H.
|
||||
.br
|
||||
.B color.pri.M
|
||||
Task has priority M.
|
||||
.br
|
||||
.B color.pri.L
|
||||
Task has priority L.
|
||||
.br
|
||||
.B color.pri.none
|
||||
Task has no priority.
|
||||
.br
|
||||
.B color.completed
|
||||
Task is completed.
|
||||
.br
|
||||
@@ -1050,10 +1070,6 @@ Urgency inherited from dependency chain
|
||||
.RS
|
||||
Urgency coefficient for due dates
|
||||
.RE
|
||||
.B urgency.priority.coefficient=6.0
|
||||
.RS
|
||||
Urgency coefficient for priorities
|
||||
.RE
|
||||
.B urgency.waiting.coefficient=-3.0
|
||||
.RS
|
||||
Urgency coefficient for waiting status
|
||||
@@ -1094,6 +1110,10 @@ Specific tag coefficient.
|
||||
.RS
|
||||
Specific project coefficient.
|
||||
.RE
|
||||
.B urgency.user.keyword.<keyword>.coefficient=...
|
||||
.RS
|
||||
Specific description keyword coefficient.
|
||||
.RE
|
||||
.B urgency.uda.<name>.coefficient=...
|
||||
.RS
|
||||
Presence/absence of UDA data.
|
||||
@@ -1116,13 +1136,6 @@ Provides a default project name for the
|
||||
.I task add
|
||||
command, if you don't specify one. The default is blank.
|
||||
|
||||
.TP
|
||||
.B
|
||||
default.priority=M
|
||||
Provides a default priority for the
|
||||
.I task add
|
||||
command, if you don't specify one. The default is blank.
|
||||
|
||||
.TP
|
||||
.B
|
||||
default.due=...
|
||||
@@ -1141,7 +1154,7 @@ command, if you don't specify values. The default is blank.
|
||||
.TP
|
||||
.B
|
||||
default.command=next
|
||||
Provides a default command that is run every time taskwarrior is invoked with no
|
||||
Provides a default command that is run every time Taskwarrior is invoked with no
|
||||
arguments. For example, if set to:
|
||||
|
||||
.RS
|
||||
@@ -1151,7 +1164,7 @@ default.command=project:foo list
|
||||
.RE
|
||||
|
||||
.RS
|
||||
then taskwarrior will run the "project:foo list" command if no command is
|
||||
then Taskwarrior will run the "project:foo list" command if no command is
|
||||
specified. This means that by merely typing
|
||||
.RE
|
||||
|
||||
@@ -1328,19 +1341,56 @@ Provides a default report label for the UDA called '<name>'.
|
||||
For type 'string' UDAs only, this provides a comma-separated list of acceptable
|
||||
values. In this example, the '<name>' UDA may only contain values 'A', 'B',
|
||||
or 'C', but may also contain no value.
|
||||
|
||||
Note that the order of the value is important, and denotes the sort order from
|
||||
highest ('A') to lowest ('C').
|
||||
|
||||
Note that a blank value is permitted.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B uda.<name>.default=...
|
||||
.RS
|
||||
Provides a default value for the UDA called '<name>'.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B Example 'estimate' UDA
|
||||
This example shows an 'estimate' UDA that stores specific values for the size
|
||||
of a task.
|
||||
of a task. Note the blank value after 'trivial'.
|
||||
|
||||
.RS
|
||||
.B uda.estimate.type=string
|
||||
.br
|
||||
.B uda.estimate.label=Size Estimate
|
||||
.br
|
||||
.B uda.estimate.values=trivial,small,medium,large,huge
|
||||
.B uda.estimate.values=huge,large,medium,small,trivial,
|
||||
.RE
|
||||
|
||||
.RS
|
||||
Note that the value are sorted
|
||||
|
||||
huge > large > medium > small > trivial > ''
|
||||
.RE
|
||||
|
||||
.SS CONTEXT
|
||||
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
|
||||
@@ -1413,7 +1463,7 @@ http://www.opensource.org/licenses/mit-license.php for more information.
|
||||
.BR task-color(5),
|
||||
.BR task-sync(5)
|
||||
|
||||
For more information regarding taskwarrior, see the following:
|
||||
For more information regarding Taskwarrior, see the following:
|
||||
|
||||
.TP
|
||||
The official site at
|
||||
@@ -1429,6 +1479,6 @@ You can contact the project by emailing
|
||||
|
||||
.SH REPORTING BUGS
|
||||
.TP
|
||||
Bugs in taskwarrior may be reported to the issue-tracker at
|
||||
Bugs in Taskwarrior may be reported to the issue-tracker at
|
||||
<http://taskwarrior.org>
|
||||
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
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
|
||||
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
|
||||
and white background to properly show the light and dark themes.
|
||||
Using a light-background terminal, run the following:
|
||||
|
||||
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
|
||||
to specific colors.
|
||||
|
||||
@@ -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
|
||||
@@ -21,6 +21,8 @@ include $theme
|
||||
EOF
|
||||
|
||||
echo "--- $theme -----------------------------------------------------"
|
||||
echo '$ task color legend'
|
||||
task rc:x color legend
|
||||
echo '$ task list'
|
||||
task rc:x list
|
||||
echo '$ task summary'
|
||||
|
||||
24
doc/misc/themes/run.default
Executable file
24
doc/misc/themes/run.default
Executable 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
|
||||
@@ -14,6 +14,8 @@ include $theme
|
||||
EOF
|
||||
|
||||
echo "--- $theme -----------------------------------------------------"
|
||||
echo '$ task color legend'
|
||||
task rc:x color legend
|
||||
echo '$ task list'
|
||||
task rc:x list
|
||||
echo '$ task summary'
|
||||
|
||||
@@ -13,6 +13,8 @@ include $theme
|
||||
EOF
|
||||
|
||||
echo "--- $theme -----------------------------------------------------"
|
||||
echo '$ task color legend'
|
||||
task rc:x color legend
|
||||
echo '$ task list'
|
||||
task rc:x list
|
||||
echo '$ task summary'
|
||||
|
||||
@@ -13,6 +13,8 @@ include $theme
|
||||
EOF
|
||||
|
||||
echo "--- $theme -----------------------------------------------------"
|
||||
echo '$ task color legend'
|
||||
task rc:x color legend
|
||||
echo '$ task list'
|
||||
task rc:x list
|
||||
echo '$ task summary'
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
|
||||
|
||||
# General decoration
|
||||
color.label=
|
||||
@@ -33,15 +33,15 @@ color.alternate=
|
||||
color.header=yellow
|
||||
color.footnote=yellow
|
||||
color.warning=bold red
|
||||
color.error=yellow
|
||||
color.debug=yellow
|
||||
color.error=white on red
|
||||
color.debug=blue
|
||||
|
||||
# Task state
|
||||
color.completed=green on white
|
||||
color.deleted=red on white
|
||||
color.completed=
|
||||
color.deleted=
|
||||
color.active=black on bright green
|
||||
color.recurring=magenta
|
||||
color.scheduled=on green
|
||||
color.scheduled=white on green
|
||||
color.until=
|
||||
color.blocked=black on white
|
||||
color.blocking=black on bright white
|
||||
@@ -50,10 +50,9 @@ color.blocking=black on bright white
|
||||
color.project.none=
|
||||
|
||||
# Priority
|
||||
color.pri.H=bold white
|
||||
color.pri.M=white
|
||||
color.pri.L=
|
||||
color.pri.none=
|
||||
color.uda.priority.H=bold white
|
||||
color.uda.priority.M=white
|
||||
color.uda.priority.L=
|
||||
|
||||
# Tags
|
||||
color.tag.next=bold yellow
|
||||
|
||||
@@ -24,36 +24,35 @@
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
|
||||
|
||||
# General decoration
|
||||
color.label=
|
||||
color.label.sort=
|
||||
color.alternate=on gray1
|
||||
color.alternate=on gray2
|
||||
color.header=color3
|
||||
color.footnote=color3
|
||||
color.warning=bold red
|
||||
color.error=color3
|
||||
color.debug=color3
|
||||
color.error=white on red
|
||||
color.debug=color4
|
||||
|
||||
# Task state
|
||||
color.completed=rgb010 on white
|
||||
color.deleted=rgb100 on white
|
||||
color.completed=
|
||||
color.deleted=
|
||||
color.active=rgb555 on rgb410
|
||||
color.recurring=rgb013
|
||||
color.scheduled=on rgb001
|
||||
color.until=
|
||||
color.blocked=white on color8
|
||||
color.blocking=white on color15
|
||||
color.blocking=black on color15
|
||||
|
||||
# Project
|
||||
color.project.none=
|
||||
|
||||
# Priority
|
||||
color.pri.H=color255
|
||||
color.pri.L=color245
|
||||
color.pri.M=color250
|
||||
color.pri.none=
|
||||
color.uda.priority.H=color255
|
||||
color.uda.priority.L=color245
|
||||
color.uda.priority.M=color250
|
||||
|
||||
# Tags
|
||||
color.tag.next=rgb440
|
||||
|
||||
@@ -24,24 +24,24 @@
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
|
||||
|
||||
# General decoration
|
||||
color.label=
|
||||
color.label.sort=
|
||||
color.alternate=on gray1
|
||||
color.alternate=on gray2
|
||||
color.header=rgb013
|
||||
color.footnote=rgb013
|
||||
color.warning=bold red
|
||||
color.error=rgb013
|
||||
color.error=white on red
|
||||
color.debug=rgb013
|
||||
|
||||
# Task state
|
||||
color.completed=rgb001 on white
|
||||
color.deleted=rgb100 on white
|
||||
color.completed=
|
||||
color.deleted=
|
||||
color.active=rgb045 on rgb015
|
||||
color.recurring=rgb115
|
||||
color.scheduled=on rgb011
|
||||
color.scheduled=on rgb012
|
||||
color.until=
|
||||
color.blocked=white on rgb001
|
||||
color.blocking=white on rgb002
|
||||
@@ -50,10 +50,9 @@ color.blocking=white on rgb002
|
||||
color.project.none=
|
||||
|
||||
# Priority
|
||||
color.pri.H=rgb035
|
||||
color.pri.L=rgb015
|
||||
color.pri.M=rgb025
|
||||
color.pri.none=
|
||||
color.uda.priority.H=rgb035
|
||||
color.uda.priority.L=rgb015
|
||||
color.uda.priority.M=rgb025
|
||||
|
||||
# Tags
|
||||
color.tag.next=rgb550
|
||||
@@ -76,8 +75,8 @@ color.history.delete=color0 on rgb035
|
||||
color.history.done=color0 on rgb025
|
||||
|
||||
# Report: summary
|
||||
color.summary.background=white on color0
|
||||
color.summary.bar=white on rgb003
|
||||
color.summary.background=on rgb001
|
||||
color.summary.bar=on rgb114
|
||||
|
||||
# Command: calendar
|
||||
color.calendar.due.today=color0 on color252
|
||||
|
||||
@@ -24,21 +24,21 @@
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
|
||||
|
||||
# General decoration
|
||||
color.label=
|
||||
color.label.sort=
|
||||
color.alternate=on gray1
|
||||
color.alternate=on gray2
|
||||
color.header=color0 on gray11
|
||||
color.footnote=on gray5
|
||||
color.warning=bold red
|
||||
color.error=red on white
|
||||
color.debug=black on white
|
||||
color.error=white on red
|
||||
color.debug=blue
|
||||
|
||||
# Task state
|
||||
color.completed=black on white
|
||||
color.deleted=black on white
|
||||
color.completed=
|
||||
color.deleted=
|
||||
color.active=black on gray18
|
||||
color.recurring=
|
||||
color.scheduled=on gray8
|
||||
@@ -50,10 +50,9 @@ color.blocking=bold white
|
||||
color.project.none=
|
||||
|
||||
# Priority
|
||||
color.pri.H=gray21
|
||||
color.pri.M=gray18
|
||||
color.pri.L=gray12
|
||||
color.pri.none=gray18
|
||||
color.uda.priority.H=gray21
|
||||
color.uda.priority.M=gray18
|
||||
color.uda.priority.L=gray12
|
||||
|
||||
# Tags
|
||||
color.tag.next=bold white
|
||||
@@ -61,7 +60,7 @@ color.tag.none=
|
||||
color.tagged=
|
||||
|
||||
# Due
|
||||
color.due=on gray2
|
||||
color.due=on gray3
|
||||
color.due.today=on gray4
|
||||
color.overdue=on gray6
|
||||
|
||||
@@ -76,12 +75,12 @@ color.history.delete=black on gray10
|
||||
color.history.done=gray5 on gray23
|
||||
|
||||
# Report: summary
|
||||
color.summary.bar=on gray15
|
||||
color.summary.background=on black
|
||||
color.summary.bar=on gray12
|
||||
color.summary.background=on gray5
|
||||
|
||||
# Command: calendar
|
||||
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.overdue=gray2 on gray10
|
||||
color.calendar.today=bold white
|
||||
@@ -89,7 +88,7 @@ color.calendar.weekend=on gray2
|
||||
color.calendar.weeknumber=gray6
|
||||
|
||||
# Command: sync
|
||||
color.sync.add=gray15 on gray5
|
||||
color.sync.added=gray15 on gray5
|
||||
color.sync.changed=black on gray10
|
||||
color.sync.rejected=gray5 on gray23
|
||||
|
||||
|
||||
@@ -24,17 +24,17 @@
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
|
||||
|
||||
# General decoration
|
||||
color.label=
|
||||
color.label.sort=
|
||||
color.alternate=on gray0
|
||||
color.alternate=on gray2
|
||||
color.header=gray10
|
||||
color.footnote=gray10
|
||||
color.warning=
|
||||
color.error=rgb500
|
||||
color.debug=rgb500
|
||||
color.error=white on red
|
||||
color.debug=blue
|
||||
|
||||
# Task state
|
||||
color.completed=
|
||||
@@ -44,16 +44,15 @@ color.recurring=
|
||||
color.scheduled=
|
||||
color.until=
|
||||
color.blocked=bold gray10 on gray4
|
||||
color.blocking=bold gray18 on gray6
|
||||
color.blocking=gray18 on gray6
|
||||
|
||||
# Project
|
||||
color.project.none=
|
||||
|
||||
# Priority
|
||||
color.pri.H=
|
||||
color.pri.L=
|
||||
color.pri.M=
|
||||
color.pri.none=
|
||||
color.uda.priority.H=
|
||||
color.uda.priority.L=
|
||||
color.uda.priority.M=
|
||||
|
||||
# Tags
|
||||
color.tag.next=
|
||||
@@ -66,18 +65,18 @@ color.due.today=color0 on rgb024
|
||||
color.overdue=color0 on rgb035
|
||||
|
||||
# Report: burndown
|
||||
color.burndown.pending=on gray9
|
||||
color.burndown.started=on gray16
|
||||
color.burndown.done=on rgb013
|
||||
color.burndown.pending=white on gray9
|
||||
color.burndown.started=black on gray16
|
||||
color.burndown.done=white on rgb013
|
||||
|
||||
# Report: history
|
||||
color.history.add=on gray9
|
||||
color.history.delete=black on gray23
|
||||
color.history.done=black on rgb013
|
||||
color.history.add=white on gray6
|
||||
color.history.delete=black on gray18
|
||||
color.history.done=black on rgb024
|
||||
|
||||
# Report: summary
|
||||
color.summary.bar=on rgb012
|
||||
color.summary.background=on color0
|
||||
color.summary.background=on gray2
|
||||
|
||||
# Command: calendar
|
||||
color.calendar.due=color0 on gray10
|
||||
@@ -94,6 +93,6 @@ color.sync.changed=gray15
|
||||
color.sync.rejected=gray23
|
||||
|
||||
# Command: undo
|
||||
color.undo.before=green
|
||||
color.undo.after=red
|
||||
color.undo.before=rgb013
|
||||
color.undo.after=rgb035
|
||||
|
||||
|
||||
@@ -24,24 +24,24 @@
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
|
||||
|
||||
# General decoration
|
||||
color.label=
|
||||
color.label.sort=
|
||||
color.alternate=on gray1
|
||||
color.alternate=on gray2
|
||||
color.header=rgb031
|
||||
color.footnote=rgb031
|
||||
color.warning=bold red
|
||||
color.error=rgb031
|
||||
color.debug=rgb031
|
||||
color.warning=rgb020
|
||||
color.error=white on red
|
||||
color.debug=blue
|
||||
|
||||
# Task state
|
||||
color.completed=rgb020 on white
|
||||
color.deleted=rgb200 on white
|
||||
color.completed=
|
||||
color.deleted=
|
||||
color.active=rgb050 on rgb010
|
||||
color.recurring=rgb151
|
||||
color.scheduled=on rgb011
|
||||
color.scheduled=black on rgb031
|
||||
color.until=
|
||||
color.blocked=white on rgb010
|
||||
color.blocking=white on rgb020
|
||||
@@ -50,10 +50,9 @@ color.blocking=white on rgb020
|
||||
color.project.none=
|
||||
|
||||
# Priority
|
||||
color.pri.H=rgb050
|
||||
color.pri.L=rgb010
|
||||
color.pri.M=rgb030
|
||||
color.pri.none=
|
||||
color.uda.priority.H=rgb050
|
||||
color.uda.priority.L=rgb010
|
||||
color.uda.priority.M=rgb030
|
||||
|
||||
# Tags
|
||||
color.tag.next=rgb440
|
||||
@@ -76,7 +75,7 @@ color.history.delete=color0 on rgb050
|
||||
color.history.done=color0 on rgb030
|
||||
|
||||
# Report: summary
|
||||
color.summary.background=white on color0
|
||||
color.summary.background=white on gray3
|
||||
color.summary.bar=white on rgb030
|
||||
|
||||
# Command: calendar
|
||||
@@ -95,4 +94,4 @@ color.sync.rejected=rgb010
|
||||
|
||||
# Command: undo
|
||||
color.undo.after=rgb053
|
||||
color.undo.before=rgb031
|
||||
color.undo.before=rgb021
|
||||
|
||||
@@ -24,24 +24,24 @@
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
|
||||
|
||||
# General decoration
|
||||
color.label=
|
||||
color.label.sort=
|
||||
color.alternate=on gray1
|
||||
color.alternate=on gray2
|
||||
color.header=rgb100
|
||||
color.footnote=rgb100
|
||||
color.warning=bold red
|
||||
color.error=rgb100
|
||||
color.debug=rgb100
|
||||
color.warning=red
|
||||
color.error=white on red
|
||||
color.debug=blue
|
||||
|
||||
# Task state
|
||||
color.completed=rgb020 on white
|
||||
color.deleted=rgb200 on white
|
||||
color.completed=
|
||||
color.deleted=
|
||||
color.active=rgb500 on rgb100
|
||||
color.recurring=rgb511
|
||||
color.scheduled=on rgb201
|
||||
color.scheduled=white on rgb311
|
||||
color.until=
|
||||
color.blocked=white on rgb100
|
||||
color.blocking=white on rgb200
|
||||
@@ -50,13 +50,12 @@ color.blocking=white on rgb200
|
||||
color.project.none=
|
||||
|
||||
# Priority
|
||||
color.pri.H=rgb500
|
||||
color.pri.L=rgb300
|
||||
color.pri.M=rgb400
|
||||
color.pri.none=
|
||||
color.uda.priority.H=rgb500
|
||||
color.uda.priority.L=rgb300
|
||||
color.uda.priority.M=rgb400
|
||||
|
||||
# Tags
|
||||
color.tag.next=rgb440
|
||||
color.tag.next=rgb511
|
||||
color.tag.none=
|
||||
color.tagged=color246
|
||||
|
||||
@@ -94,6 +93,6 @@ color.sync.changed=rgb411
|
||||
color.sync.rejected=rgb200
|
||||
|
||||
# Command: undo
|
||||
color.undo.after=rgb503
|
||||
color.undo.before=rgb301
|
||||
color.undo.after=rgb511
|
||||
color.undo.before=rgb200
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
|
||||
|
||||
# General decoration
|
||||
color.label=
|
||||
@@ -33,15 +33,15 @@ color.alternate=on gray2
|
||||
color.header=rgb013
|
||||
color.footnote=rgb013
|
||||
color.warning=
|
||||
color.error=rgb013
|
||||
color.debug=rgb013
|
||||
color.error=white on red
|
||||
color.debug=blue
|
||||
|
||||
# Task state
|
||||
color.completed=
|
||||
color.deleted=
|
||||
color.active=rgb445 on rgb213
|
||||
color.recurring=rgb115
|
||||
color.scheduled=
|
||||
color.scheduled=white on rgb113
|
||||
color.until=
|
||||
color.blocked=white on rgb101
|
||||
color.blocking=white on rgb202
|
||||
@@ -50,10 +50,9 @@ color.blocking=white on rgb202
|
||||
color.project.none=
|
||||
|
||||
# Priority
|
||||
color.pri.H=rgb404
|
||||
color.pri.M=rgb304
|
||||
color.pri.L=rgb325
|
||||
color.pri.none=
|
||||
color.uda.priority.H=rgb404
|
||||
color.uda.priority.M=rgb304
|
||||
color.uda.priority.L=rgb325
|
||||
|
||||
# Tags
|
||||
color.tag.next=
|
||||
@@ -61,9 +60,9 @@ color.tag.none=
|
||||
color.tagged=rgb334
|
||||
|
||||
# Due
|
||||
color.due=rgb055
|
||||
color.due.today=rgb533
|
||||
color.overdue=color9
|
||||
color.due=rgb015
|
||||
color.due.today=rgb125
|
||||
color.overdue=color5
|
||||
|
||||
# Report: burndown
|
||||
color.burndown.pending=on rgb103
|
||||
@@ -76,14 +75,14 @@ color.history.done=color0 on rgb205
|
||||
color.history.delete=color0 on rgb305
|
||||
|
||||
# Report: summary
|
||||
color.summary.bar=white on rgb103
|
||||
color.summary.background=white on color0
|
||||
color.summary.bar=white on rgb104
|
||||
color.summary.background=white on rgb001
|
||||
|
||||
# Command: calendar
|
||||
color.calendar.due=color0 on rgb325
|
||||
color.calendar.due.today=color0 on rgb404
|
||||
color.calendar.holiday=color15 on rgb022
|
||||
color.calendar.overdue=color0 on color9
|
||||
color.calendar.holiday=color15 on rgb102
|
||||
color.calendar.overdue=color0 on color5
|
||||
color.calendar.today=color15 on rgb103
|
||||
color.calendar.weekend=gray12 on gray3
|
||||
color.calendar.weeknumber=rgb104
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
|
||||
|
||||
# General decoration
|
||||
color.label=
|
||||
@@ -33,15 +33,15 @@ color.alternate=on gray2
|
||||
color.header=rgb031
|
||||
color.footnote=rgb031
|
||||
color.warning=
|
||||
color.error=rgb031
|
||||
color.debug=rgb031
|
||||
color.error=white on red
|
||||
color.debug=blue
|
||||
|
||||
# Task state
|
||||
color.completed=
|
||||
color.deleted=
|
||||
color.active=rgb451 on rgb310
|
||||
color.active=rgb451 on rgb320
|
||||
color.recurring=rgb343
|
||||
color.scheduled=
|
||||
color.scheduled=black on rgb441
|
||||
color.until=
|
||||
color.blocked=white on rgb110
|
||||
color.blocking=white on rgb220
|
||||
@@ -50,10 +50,9 @@ color.blocking=white on rgb220
|
||||
color.project.none=
|
||||
|
||||
# Priority
|
||||
color.pri.H=rgb450
|
||||
color.pri.M=rgb030
|
||||
color.pri.L=rgb010
|
||||
color.pri.none=
|
||||
color.uda.priority.H=rgb450
|
||||
color.uda.priority.M=rgb030
|
||||
color.uda.priority.L=rgb010
|
||||
|
||||
# Tags
|
||||
color.tag.next=
|
||||
@@ -61,9 +60,9 @@ color.tag.none=
|
||||
color.tagged=rgb342
|
||||
|
||||
# Due
|
||||
color.due=rgb420
|
||||
color.due.today=rgb410
|
||||
color.overdue=rgb400
|
||||
color.due=rgb440
|
||||
color.due.today=rgb430
|
||||
color.overdue=rgb420
|
||||
|
||||
# Report: burndown
|
||||
color.burndown.pending=on rgb110
|
||||
@@ -71,19 +70,19 @@ color.burndown.started=on rgb430
|
||||
color.burndown.done=on gray4
|
||||
|
||||
# Report: history
|
||||
color.history.add=color0 on rgb010
|
||||
color.history.done=color0 on rgb030
|
||||
color.history.delete=color0 on rgb050
|
||||
color.history.add=color0 on rgb110
|
||||
color.history.done=color0 on rgb430
|
||||
color.history.delete=white on gray4
|
||||
|
||||
# Report: summary
|
||||
color.summary.bar=white on rgb030
|
||||
color.summary.background=white on color0
|
||||
color.summary.bar=white on rgb330
|
||||
color.summary.background=white on rgb110
|
||||
|
||||
# Command: calendar
|
||||
color.calendar.due=color0 on rgb430
|
||||
color.calendar.due.today=color0 on rgb410
|
||||
color.calendar.due=color0 on rgb440
|
||||
color.calendar.due.today=color0 on rgb430
|
||||
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.weekend=on color235
|
||||
color.calendar.weeknumber=rgb110
|
||||
@@ -94,6 +93,6 @@ color.sync.changed=rgb430
|
||||
color.sync.rejected=rgb110
|
||||
|
||||
# Command: undo
|
||||
color.undo.before=rgb031
|
||||
color.undo.after=rgb053
|
||||
color.undo.before=rgb021
|
||||
color.undo.after=rgb042
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
|
||||
|
||||
# General decoration
|
||||
color.label=
|
||||
@@ -33,12 +33,12 @@ color.alternate=
|
||||
color.header=bold white on bright black
|
||||
color.footnote=bold cyan on bright black
|
||||
color.warning=bold red
|
||||
color.error=red on white
|
||||
color.debug=white on black
|
||||
color.error=white on red
|
||||
color.debug=blue
|
||||
|
||||
# Task state
|
||||
color.completed=green on black
|
||||
color.deleted=red on black
|
||||
color.completed=
|
||||
color.deleted=
|
||||
color.active=bold yellow on bright black
|
||||
color.recurring=
|
||||
color.scheduled=on bright cyan
|
||||
@@ -50,10 +50,9 @@ color.blocked=blue
|
||||
color.project.none=
|
||||
|
||||
# Priority
|
||||
color.pri.H=
|
||||
color.pri.M=
|
||||
color.pri.L=bright black
|
||||
color.pri.none=
|
||||
color.uda.priority.H=
|
||||
color.uda.priority.M=
|
||||
color.uda.priority.L=bright black
|
||||
|
||||
# Tags
|
||||
color.tag.next=bold yellow on bright black
|
||||
@@ -63,17 +62,17 @@ color.tagged=
|
||||
# Due
|
||||
color.due=on bright green
|
||||
color.due.today=on bright yellow
|
||||
color.overdue=on bright magenta
|
||||
color.overdue=on bright red
|
||||
|
||||
# Report: burndown
|
||||
color.burndown.pending=on bright green
|
||||
color.burndown.pending=on bright red
|
||||
color.burndown.started=on bright yellow
|
||||
color.burndown.done=on green
|
||||
|
||||
# Report: history
|
||||
color.history.add=blue on bright yellow
|
||||
color.history.done=green on bright green
|
||||
color.history.delete=black on red
|
||||
color.history.add=black on bright red
|
||||
color.history.done=black on bright green
|
||||
color.history.delete=black on yellow
|
||||
|
||||
# Report: summary
|
||||
color.summary.bar=on bright green
|
||||
@@ -82,11 +81,11 @@ color.summary.background=on white
|
||||
# Command: calendar
|
||||
color.calendar.due=on bright green
|
||||
color.calendar.due.today=blue on bright yellow
|
||||
color.calendar.holiday=yellow
|
||||
color.calendar.overdue=on bright magenta
|
||||
color.calendar.holiday=on yellow
|
||||
color.calendar.overdue=on bright red
|
||||
color.calendar.today=blue
|
||||
color.calendar.weekend=on white
|
||||
color.calendar.weeknumber=white on bright black
|
||||
color.calendar.weeknumber=blue
|
||||
|
||||
# Command: sync
|
||||
color.sync.added=green
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
|
||||
|
||||
# General decoration
|
||||
color.label=
|
||||
@@ -33,13 +33,13 @@ color.alternate=on gray22
|
||||
color.header=color15 on gray8
|
||||
color.footnote=on gray18
|
||||
color.warning=color9
|
||||
color.error=red on white
|
||||
color.debug=color7 on color0
|
||||
color.error=white on red
|
||||
color.debug=rgb025
|
||||
|
||||
# Task state
|
||||
color.completed=rgb353 on rgb000
|
||||
color.deleted=rgb533 on rgb000
|
||||
color.active=rgb420
|
||||
color.completed=
|
||||
color.deleted=
|
||||
color.active=rgb510
|
||||
color.recurring=
|
||||
color.scheduled=on rgb345
|
||||
color.until=
|
||||
@@ -50,10 +50,9 @@ color.blocked=rgb003
|
||||
color.project.none=
|
||||
|
||||
# Priority
|
||||
color.pri.H=gray0
|
||||
color.pri.M=gray5
|
||||
color.pri.L=gray10
|
||||
color.pri.none=gray5
|
||||
color.uda.priority.H=gray0
|
||||
color.uda.priority.M=gray5
|
||||
color.uda.priority.L=gray10
|
||||
|
||||
# Tags
|
||||
color.tag.next=rgb420
|
||||
@@ -66,14 +65,14 @@ color.due.today=on rgb353
|
||||
color.overdue=on rgb544
|
||||
|
||||
# Report: burndown
|
||||
color.burndown.pending=on rgb141
|
||||
color.burndown.started=on rgb440
|
||||
color.burndown.pending=on rgb411
|
||||
color.burndown.started=on rgb550
|
||||
color.burndown.done=on rgb151
|
||||
|
||||
# Report: history
|
||||
color.history.add=rgb005 on rgb440
|
||||
color.history.done=rgb020 on rgb343
|
||||
color.history.delete=rgb300 on rgb533
|
||||
color.history.add=color0 on rgb411
|
||||
color.history.done=color0 on rgb151
|
||||
color.history.delete=color0 on rgb550
|
||||
|
||||
# Report: summary
|
||||
color.summary.bar=on rgb141
|
||||
@@ -82,7 +81,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
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
|
||||
|
||||
# This is a theme that disables all default colors
|
||||
# It can be used as template for other themes
|
||||
@@ -53,10 +53,9 @@ color.blocking=
|
||||
color.project.none=
|
||||
|
||||
# Priority
|
||||
color.pri.H=
|
||||
color.pri.L=
|
||||
color.pri.M=
|
||||
color.pri.none=
|
||||
color.uda.priority.H=
|
||||
color.uda.priority.L=
|
||||
color.uda.priority.M=
|
||||
|
||||
# Tags
|
||||
color.tag.next=
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#
|
||||
# Taskwarrior solarized-dark-256 theme created by Stefan A. Keel.
|
||||
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
|
||||
|
||||
# General decoration
|
||||
color.label=
|
||||
@@ -67,10 +67,9 @@ color.blocking=color15 on color10
|
||||
color.project.none=
|
||||
|
||||
# Priority
|
||||
color.pri.H=bold blue #color14
|
||||
color.pri.M=bold yellow #color12
|
||||
color.pri.L=bold green #color11
|
||||
color.pri.none=
|
||||
color.uda.priority.H=bold blue #color14
|
||||
color.uda.priority.M=bold yellow #color12
|
||||
color.uda.priority.L=bold green #color11
|
||||
|
||||
# Tags
|
||||
color.tag.next=
|
||||
@@ -83,14 +82,14 @@ color.due.today=color1
|
||||
color.overdue=color5
|
||||
|
||||
# Report: burndown
|
||||
color.burndown.done=color0 on color4
|
||||
color.burndown.done=color0 on color6
|
||||
color.burndown.pending=color0 on color1
|
||||
color.burndown.started=color0 on color9
|
||||
color.burndown.started=color0 on color3
|
||||
|
||||
# Report: history
|
||||
color.history.add=color0 on color1
|
||||
color.history.delete=color0 on color3
|
||||
color.history.done=color0 on color10
|
||||
color.history.done=color0 on color6
|
||||
|
||||
# Report: summary
|
||||
color.summary.background=on color0
|
||||
|
||||
@@ -41,12 +41,12 @@
|
||||
#
|
||||
# Taskwarrior solarized-dark-256 theme created by Stefan A. Keel.
|
||||
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.
|
||||
rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.
|
||||
|
||||
# General decoration
|
||||
color.label=
|
||||
color.label.sort=
|
||||
color.alternate=on white #color7 (allows bold for alternate rows)
|
||||
color.alternate=on color7
|
||||
color.header=color2
|
||||
color.footnote=color2
|
||||
color.warning=
|
||||
@@ -56,21 +56,20 @@ color.debug=color3
|
||||
# Task state
|
||||
color.completed=
|
||||
color.deleted=
|
||||
color.active=bold red #color9
|
||||
color.active=color9
|
||||
color.recurring=color4
|
||||
color.scheduled=
|
||||
color.until=
|
||||
color.blocked=on color14
|
||||
color.blocking=on color14
|
||||
color.blocked=color0 on color14
|
||||
color.blocking=color15 on color0
|
||||
|
||||
# Project
|
||||
color.project.none=
|
||||
|
||||
# Priority
|
||||
color.pri.H=bold black #color0
|
||||
color.pri.M=bold yellow #color11
|
||||
color.pri.L=bold cyan #color14
|
||||
color.pri.none=
|
||||
color.uda.priority.H=bold color0
|
||||
color.uda.priority.M=bold color11
|
||||
color.uda.priority.L=bold color14
|
||||
|
||||
# Tags
|
||||
color.tag.next=
|
||||
@@ -83,14 +82,14 @@ color.due.today=color1
|
||||
color.overdue=color5
|
||||
|
||||
# Report: burndown
|
||||
color.burndown.done=color0 on color4
|
||||
color.burndown.done=color0 on color6
|
||||
color.burndown.pending=color0 on color1
|
||||
color.burndown.started=color0 on color9
|
||||
color.burndown.started=color0 on color3
|
||||
|
||||
# Report: history
|
||||
color.history.add=color0 on color1
|
||||
color.history.delete=color0 on color3
|
||||
color.history.done=color14 on color0
|
||||
color.history.done=color0 on color6
|
||||
|
||||
# Report: summary
|
||||
color.summary.background=on color7
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -48,7 +48,7 @@ if ($command =~ /No matches/)
|
||||
print "'uuid','status','tags','entry','start','due','recur','end','project',",
|
||||
"'priority','fg','bg','description'\n";
|
||||
|
||||
for my $task (split /,$/ms, qx{$command})
|
||||
for my $task (split "\n", qx{$command})
|
||||
{
|
||||
my $data = from_json ($task);
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ print "<html>\n",
|
||||
" <tbody>\n";
|
||||
|
||||
my $count = 0;
|
||||
for my $task (split /,$/ms, qx{$command})
|
||||
for my $task (split "\n", qx{$command})
|
||||
{
|
||||
++$count;
|
||||
my $data = from_json ($task);
|
||||
|
||||
@@ -49,7 +49,7 @@ print "BEGIN:VCALENDAR\n",
|
||||
"VERSION:2.0\n",
|
||||
"PRODID:=//GBF/taskwarrior 1.9.4//EN\n";
|
||||
|
||||
for my $task (split /,$/ms, qx{$command})
|
||||
for my $task (split "\n", qx{$command})
|
||||
{
|
||||
my $data = from_json ($task);
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export-sql.py -- Export the taskwarrior database as a series of SQL commands.
|
||||
|
||||
Example usage::
|
||||
|
||||
$ ./export-sql.py | sqlite3 mytasks.db
|
||||
$ PYTHONIOENCODING=UTF-8 ./export-sql.py | sqlite3 mytasks.db
|
||||
$ /usr/bin/sqlite3 mytasks.db "select * from annotations;"
|
||||
|
||||
This script has only been tested with sqlite3, but in theory, it could be
|
||||
@@ -120,8 +120,8 @@ def to_sql(task):
|
||||
values = template.format(**annot)
|
||||
return "INSERT INTO \"annotations\" VALUES(%s)" % values
|
||||
|
||||
template = "{uuid}, {description}, {entry}, {end}, " + \
|
||||
"{priority}, {project}, {status}"
|
||||
template = u"{uuid}, {description}, {entry}, {end}, " + \
|
||||
u"{priority}, {project}, {status}"
|
||||
|
||||
nullables = ['end', 'priority', 'project', 'status']
|
||||
defaults = dict([(key, None) for key in nullables])
|
||||
@@ -140,10 +140,10 @@ def main():
|
||||
""" Return a list of SQL statements. """
|
||||
|
||||
# Use the taskwarrior 2.0+ export command to filter and return JSON
|
||||
command = "task rc.verbose=nothing rc.json.array=no export " + " ".join(sys.argv[1:])
|
||||
command = "task rc.verbose=nothing rc.json.array=yes " + " ".join(sys.argv[1:]) + " export"
|
||||
|
||||
# Load each task from json to a python dict
|
||||
tasks = map(json.loads, commands.getoutput(command).split(",\n"))
|
||||
tasks = json.loads(commands.getoutput(command))
|
||||
|
||||
# Mangle datetime strings into python datetime objects
|
||||
tasks = map(parse_datetime, tasks)
|
||||
@@ -162,7 +162,7 @@ if __name__ == '__main__':
|
||||
sql = table_definitions + ";\n".join(lines) + ';'
|
||||
|
||||
# Print them out, decorated with sqlite3 trappings
|
||||
print """
|
||||
print u"""
|
||||
BEGIN TRANSACTION;
|
||||
{sql}
|
||||
COMMIT;""".format(sql=sql)
|
||||
|
||||
@@ -48,7 +48,7 @@ if ($command =~ /No matches/)
|
||||
print "uuid\tstatus\ttags\tentry\tstart\tdue\trecur\tend\tproject\t",
|
||||
"priority\tfg\tbg\tdescription\n";
|
||||
|
||||
for my $task (split /,$/ms, qx{$command})
|
||||
for my $task (split "\n", qx{$command})
|
||||
{
|
||||
my $data = from_json ($task);
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ if ($command =~ /No matches/)
|
||||
|
||||
# Generate output.
|
||||
print "<tasks>\n";
|
||||
for my $task (split /,$/ms, qx{$command})
|
||||
for my $task (split "\n", qx{$command})
|
||||
{
|
||||
my $data = from_json ($task);
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ if ($command =~ /No matches/)
|
||||
print "'uuid','status','tags','entry','start','due','recur','end','project',",
|
||||
"'priority','fg','bg','description'\n";
|
||||
|
||||
for my $task (split /,$/ms, qx{$command})
|
||||
for my $task (split "\n", qx{$command})
|
||||
{
|
||||
my $data = from_json ($task);
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
#
|
||||
################################################################################
|
||||
#the following variable is substituted for by ../../test/bash_completion.t
|
||||
taskcommand='task rc.verbose:nothing'
|
||||
taskcommand='task rc.verbose:nothing rc.confirmation:no rc.hooks:off'
|
||||
|
||||
_task_get_tags() {
|
||||
$taskcommand _tags
|
||||
@@ -68,7 +68,13 @@ _task_offer_projects() {
|
||||
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
|
||||
|
||||
@@ -91,6 +97,10 @@ _task()
|
||||
opts="$commands_aliases $($taskcommand _columns)"
|
||||
|
||||
case "${prev}" in
|
||||
$_task_context_alias|cont|conte|contex|context)
|
||||
_task_offer_contexts
|
||||
return 0
|
||||
;;
|
||||
:)
|
||||
case "${prev2}" in
|
||||
pri|prior|priori|priorit|priority)
|
||||
|
||||
@@ -15,6 +15,24 @@
|
||||
# * Tags
|
||||
# * Attribute names and modifiers
|
||||
#
|
||||
#
|
||||
# You can override some default options in your config.fish:
|
||||
#
|
||||
# # Tab-completion of task descriptions.
|
||||
# # Warning: This often creates a list of suggestions which spans several pages,
|
||||
# # and it usually pushes some of the commands and attributes to the end of the
|
||||
# # list.
|
||||
# set -g task_complete_task yes
|
||||
#
|
||||
# # Tab-completion of task IDs outside of the "depends" attribute.
|
||||
# # Warning: This often creates a list of suggestions which spans several pages,
|
||||
# # and it pushes all commands and attributes to the end of the list.
|
||||
# set -g task_complete_id yes
|
||||
#
|
||||
# # Attribute modifiers (DEPRECATED since 2.4.0)
|
||||
# set -g task_complete_attribute_modifiers yes
|
||||
#
|
||||
#
|
||||
# Copyright 2014 - 2015, Roman Inflianskas <infroma@gmail.com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
@@ -150,8 +168,7 @@ function __fish.task.list.attr_value_by_name
|
||||
__fish.task.combos_simple $attr (__fish.task.list $attr)
|
||||
# case 'description' 'due' 'entry' 'end' 'start' 'project' 'recur' 'until' 'wait'
|
||||
case '*'
|
||||
# BUG: remove in 2.4.0
|
||||
if echo (commandline -ct) | grep -q '\.'
|
||||
if [ "$task_complete_attribute_modifiers" = 'yes' ]; and echo (commandline -ct) | grep -q '\.'
|
||||
__fish.task.combos_with_mods $attr (__fish.task.list $attr)
|
||||
else
|
||||
__fish.task.combos_simple $attr (__fish.task.list $attr)
|
||||
@@ -195,7 +212,7 @@ function __fish.task.list.id
|
||||
end
|
||||
end
|
||||
|
||||
# BUG: remove in 2.4.0
|
||||
# Attribure modifiers (DEPRECATED since 2.4.0)
|
||||
function __fish.task.list.mod
|
||||
for mod in 'before' 'after' 'over' 'under' 'none' 'is' 'isnt' 'has' 'hasnt' 'startswith' 'endswith' 'word' 'noword'
|
||||
echo $mod
|
||||
@@ -266,7 +283,7 @@ function __fish.task.combos_simple
|
||||
end
|
||||
end
|
||||
|
||||
# BUG: remove in 2.4.0
|
||||
# Attribure modifiers (DEPRECATED since 2.4.0)
|
||||
function __fish.task.combos_with_mods
|
||||
__fish.task.combos_simple $argv
|
||||
for mod in (__fish.task.list.mod)
|
||||
@@ -290,16 +307,10 @@ __fish.task.complete attr_value
|
||||
__fish.task.complete attr_name
|
||||
__fish.task.complete config
|
||||
|
||||
# Uncomment the following line if you want tab-completion of task descriptions.
|
||||
# Warning: This often creates a list of suggestions which spans several pages,
|
||||
# and it usually pushes some of the commands and attributes to the end of the
|
||||
# list.
|
||||
if [ "$task_complete_task" = 'yes' ]
|
||||
__fish.task.complete task
|
||||
end
|
||||
|
||||
#__fish.task.complete task
|
||||
|
||||
# Uncomment the following line if you want tab-completion of task IDs outside
|
||||
# of the "depends" attribute. Warning: This often creates a list of
|
||||
# suggestions which spans several pages, and it pushes all commands and
|
||||
# attributes to the end of the list.
|
||||
|
||||
#__fish.task.complete id with_description
|
||||
if [ "$task_complete_id" = 'yes' ]
|
||||
__fish.task.complete id with_description
|
||||
end
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
# The on-add event is triggered separately for each task added
|
||||
# The on-add event is triggered separately for each task added. This hook
|
||||
# script can accept/reject the addition. Processing will continue.
|
||||
|
||||
# Input:
|
||||
# - line of JSON for the task added
|
||||
|
||||
# Output:
|
||||
# - all emitted JSON lines are added/modified as tasks, if the exit code is
|
||||
# zero, otherwise ignored.
|
||||
# - minimal new task: {"description":"Buy milk"}
|
||||
# - to modify a task include complete JSON
|
||||
# - all emitted non-JSON lines are considered feedback messages if the exit
|
||||
# code is zero, otherwise they are considered errors.
|
||||
|
||||
# - Line of JSON for proposed new task.
|
||||
read new_task
|
||||
|
||||
# Output:
|
||||
# - JSON, modified or unmodified.
|
||||
# - Optional feedback/error.
|
||||
echo $new_task
|
||||
echo 'on-add'
|
||||
|
||||
# Status:
|
||||
# - 0: JSON accepted, non-JSON is feedback.
|
||||
# - non-0: JSON ignored, non-JSON is error.
|
||||
exit 0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
read new_task
|
||||
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
# The on-exit event is triggered once, after all processing is complete, i.e.
|
||||
# last
|
||||
|
||||
# Input:
|
||||
# - read-only line of JSON for each task added/modified
|
||||
# The on-exit event is triggered once, after all processing is complete.
|
||||
# This hooks script has no effect on processing.
|
||||
|
||||
# Output:
|
||||
# - any emitted JSON is ignored
|
||||
# - all emitted non-JSON lines are considered feedback messages if the exit
|
||||
# code is zero, otherwise they are considered errors.
|
||||
# - Optional feedback/error.
|
||||
|
||||
while read -t 1 modified_task
|
||||
n=0
|
||||
while read modified_task
|
||||
do
|
||||
# Scan task
|
||||
n=$(($n + 1))
|
||||
done
|
||||
|
||||
echo 'on-exit'
|
||||
echo "on-exit: Counted $n added/modified tasks."
|
||||
|
||||
# Status:
|
||||
# - 0: Non-JSON is feedback.
|
||||
# - non-0: Non-JSON is error.
|
||||
exit 0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# This hook script replaces the shadow file feature, found in Taskwarrior
|
||||
# prior to version 2.4.0.
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
# The on-launch event is triggered once, after initialization, before any
|
||||
# processing occurs, i.e first
|
||||
# processing occurs. This hooks script has no effect on processing.
|
||||
|
||||
# Input:
|
||||
# - none
|
||||
# - None
|
||||
|
||||
# Output:
|
||||
# - all emitted JSON lines are added/modified as tasks, if the exit code is
|
||||
# zero, otherwise ignored.
|
||||
# - minimal new task: {"description":"Buy milk"}
|
||||
# - to modify a task include complete JSON
|
||||
# - all emitted non-JSON lines are considered feedback messages if the exit
|
||||
# code is zero, otherwise they are considered errors.
|
||||
|
||||
# - Optional feedback/error.
|
||||
echo 'on-launch'
|
||||
|
||||
# Status:
|
||||
# - 0: JSON ignored, non-JSON is feedback.
|
||||
# - non-0: JSON ignored, non-JSON is error.
|
||||
exit 0
|
||||
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
# The on-modify event is triggered separately for each task added or modified
|
||||
# The on-modify event is triggered separately for each task modified. This hook
|
||||
# script can accept/reject the modification. Processing will continue.
|
||||
|
||||
# Input:
|
||||
# - line of JSON for the original task
|
||||
# - line of JSON for the modified task, the diff being the modification
|
||||
|
||||
# Output:
|
||||
# - all emitted JSON lines are added/modified as tasks, if the exit code is
|
||||
# zero, otherwise ignored.
|
||||
# - minimal new task: {"description":"Buy milk"}
|
||||
# - to modify a task include complete JSON
|
||||
# - all emitted non-JSON lines are considered feedback messages if the exit
|
||||
# code is zero, otherwise they are considered errors.
|
||||
|
||||
read original_task
|
||||
read modified_task
|
||||
|
||||
# Output:
|
||||
# - JSON, modified or unmodified.
|
||||
# - Optional feedback/error.
|
||||
echo $modified_task
|
||||
echo 'on-modify'
|
||||
|
||||
# Status:
|
||||
# - 0: JSON accepted, non-JSON is feedback.
|
||||
# - non-0: JSON ignored, non-JSON is error.
|
||||
exit 0
|
||||
|
||||
@@ -72,10 +72,9 @@ syn match taskrcGoodKey '^\s*\Vcolor.history.add='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vcolor.history.delete='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vcolor.history.done='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vcolor.overdue='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vcolor.pri.H='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vcolor.pri.L='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vcolor.pri.M='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vcolor.pri.none='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vcolor.uda.priority.H='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vcolor.uda.priority.L='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vcolor.uda.priority.M='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vcolor.recurring='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vcolor.scheduled='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vcolor.summary.background='he=e-1
|
||||
@@ -154,7 +153,9 @@ syn match taskrcGoodKey '^\s*\Vurgency.blocking.coefficient='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vurgency.due.coefficient='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vurgency.inherit.coefficient='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vurgency.next.coefficient='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vurgency.priority.coefficient='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vurgency.uda.priority.H.coefficient='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vurgency.uda.priority.M.coefficient='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vurgency.uda.priority.L.coefficient='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vurgency.project.coefficient='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vurgency.scheduled.coefficient='he=e-1
|
||||
syn match taskrcGoodKey '^\s*\Vurgency.tags.coefficient='he=e-1
|
||||
|
||||
1
src/.gitignore
vendored
1
src/.gitignore
vendored
@@ -3,3 +3,4 @@ Makefile.in
|
||||
tw-*
|
||||
args
|
||||
calc
|
||||
lex
|
||||
|
||||
138
src/CLI.cpp
138
src/CLI.cpp
@@ -220,16 +220,14 @@ const std::string A::dump () const
|
||||
// Static method.
|
||||
void CLI::getOverride (int argc, const char** argv, std::string& home, File& rc)
|
||||
{
|
||||
bool terminated = false;
|
||||
for (int i = 0; i < argc; ++i)
|
||||
{
|
||||
std::string raw = argv[i];
|
||||
|
||||
if (raw == "--")
|
||||
terminated = true;
|
||||
return;
|
||||
|
||||
if (! terminated &&
|
||||
raw.length () > 3 &&
|
||||
if (raw.length () > 3 &&
|
||||
raw.substr (0, 3) == "rc:")
|
||||
{
|
||||
rc = raw.substr (3);
|
||||
@@ -351,7 +349,6 @@ void CLI::initialize (int argc, const char** argv)
|
||||
_terminated = false;
|
||||
|
||||
_original_args.push_back (argv[0]);
|
||||
bool terminated = false;
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (isTerminator (argv[i]))
|
||||
@@ -374,6 +371,63 @@ void CLI::add (const std::string& arg)
|
||||
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)
|
||||
{
|
||||
// TODO This looks wrong.
|
||||
if (a->hasTag ("FILTER") &&
|
||||
a->hasTag ("ATTRIBUTE") &&
|
||||
! a->hasTag ("TERMINATED") &&
|
||||
! a->hasTag ("WORD") &&
|
||||
(a->attribute ("raw") == "id" || a->attribute ("raw") == "uuid"))
|
||||
{
|
||||
context.debug (format ("UUID/ID lexeme found '{1}', not applying context.", a->attribute ("raw")));
|
||||
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
|
||||
// analysis. Analysis is also performed directly after the above, because there
|
||||
@@ -388,7 +442,7 @@ void CLI::analyze (bool parse /* = true */, bool strict /* = false */)
|
||||
// For propagation.
|
||||
_strict = strict;
|
||||
|
||||
for (int i = 0; i < _original_args.size (); ++i)
|
||||
for (unsigned int i = 0; i < _original_args.size (); ++i)
|
||||
{
|
||||
std::string raw = _original_args[i];
|
||||
A a ("arg", raw);
|
||||
@@ -474,8 +528,14 @@ void CLI::applyOverrides ()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 = "";
|
||||
if (_args.size ())
|
||||
{
|
||||
@@ -500,6 +560,7 @@ const std::string CLI::getFilter ()
|
||||
filter = "( " + filter + " )";
|
||||
}
|
||||
|
||||
context.debug("Derived filter: '" + filter + "'");
|
||||
return filter;
|
||||
}
|
||||
|
||||
@@ -627,7 +688,7 @@ const std::string CLI::dump (const std::string& title /* = "CLI Parser" */) cons
|
||||
// be lexed from those that need to be left alone.
|
||||
//
|
||||
// Either the arg is appended to _original_args intact, or the lexemes are.
|
||||
void CLI::addArg (const std::string& arg)
|
||||
void CLI::addArg (const std::string& arg, Lexer::Type type /* = Lexer::Type::word */)
|
||||
{
|
||||
std::string raw = trim (arg);
|
||||
|
||||
@@ -653,8 +714,8 @@ void CLI::addArg (const std::string& arg)
|
||||
_original_args.push_back (raw);
|
||||
}
|
||||
|
||||
// The argument may require lexing. Lex anyway, and analyze before comitting
|
||||
// that.
|
||||
// The argument may require lexing. Lex anyway, and analyze before comitting
|
||||
// to that.
|
||||
else
|
||||
{
|
||||
// Lex each remaining argument. The apply a series of disqualifying tests
|
||||
@@ -665,7 +726,7 @@ void CLI::addArg (const std::string& arg)
|
||||
Lexer lex (raw);
|
||||
lex.ambiguity (false);
|
||||
|
||||
std::vector <std::pair <std::string, Lexer::Type> > lexemes;
|
||||
std::vector <std::pair <std::string, Lexer::Type>> lexemes;
|
||||
while (lex.token (lexeme, type))
|
||||
lexemes.push_back (std::pair <std::string, Lexer::Type> (lexeme, type));
|
||||
|
||||
@@ -681,7 +742,7 @@ void CLI::addArg (const std::string& arg)
|
||||
{
|
||||
// How often have I said to you that when you have eliminated the
|
||||
// impossible, whatever remains, however improbable, must be the truth?
|
||||
std::vector <std::pair <std::string, Lexer::Type> >::iterator l;
|
||||
std::vector <std::pair <std::string, Lexer::Type>>::iterator l;
|
||||
for (l = lexemes.begin (); l != lexemes.end (); ++l)
|
||||
_original_args.push_back (l->first);
|
||||
}
|
||||
@@ -713,9 +774,7 @@ void CLI::aliasExpansion ()
|
||||
{
|
||||
if (_aliases.find (raw) != _aliases.end ())
|
||||
{
|
||||
std::vector <std::string> lexed;
|
||||
Lexer::token_split (lexed, _aliases[raw]);
|
||||
|
||||
std::vector <std::string> lexed = Lexer::split (_aliases[raw]);
|
||||
std::vector <std::string>::iterator l;
|
||||
for (l = lexed.begin (); l != lexed.end (); ++l)
|
||||
{
|
||||
@@ -851,7 +910,7 @@ void CLI::categorize ()
|
||||
a->tag ("MODIFICATION");
|
||||
|
||||
// If the argument contains a space, it was quoted. Record that.
|
||||
if (! noSpaces (raw))
|
||||
if (! Lexer::isOneWord (raw))
|
||||
a->tag ("QUOTED");
|
||||
|
||||
changes = true;
|
||||
@@ -861,7 +920,7 @@ void CLI::categorize ()
|
||||
a->tag ("FILTER");
|
||||
|
||||
// If the argument contains a space, it was quoted. Record that.
|
||||
if (! noSpaces (raw))
|
||||
if (! Lexer::isOneWord (raw))
|
||||
a->tag ("QUOTED");
|
||||
|
||||
changes = true;
|
||||
@@ -1175,7 +1234,7 @@ void CLI::desugarFilterAttributeModifiers ()
|
||||
}
|
||||
else if (modifier == "isnt" || modifier == "not")
|
||||
{
|
||||
op.attribute ("raw", "!=");
|
||||
op.attribute ("raw", "!==");
|
||||
rhs.attribute ("raw", "'" + value + "'");
|
||||
rhs.tag ("LITERAL");
|
||||
}
|
||||
@@ -1324,14 +1383,12 @@ void CLI::findIDs ()
|
||||
{
|
||||
if (a->hasTag ("FILTER"))
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
// IDs have a limited character set.
|
||||
std::string raw = a->attribute ("raw");
|
||||
if (raw.find_first_not_of ("0123456789,-") == std::string::npos)
|
||||
{
|
||||
// Container for min/max ID ranges.
|
||||
std::vector <std::pair <int, int> > ranges;
|
||||
std::vector <std::pair <int, int>> ranges;
|
||||
|
||||
// Split the ID list into elements.
|
||||
std::vector <std::string> elements;
|
||||
@@ -1347,7 +1404,7 @@ void CLI::findIDs ()
|
||||
|
||||
if (terms.size () == 1)
|
||||
{
|
||||
if (! digitsOnly (terms[0]))
|
||||
if (! Lexer::isAllDigits (terms[0]))
|
||||
{
|
||||
is_an_id = false;
|
||||
break;
|
||||
@@ -1368,8 +1425,8 @@ void CLI::findIDs ()
|
||||
}
|
||||
else if (terms.size () == 2)
|
||||
{
|
||||
if (! digitsOnly (terms[0]) ||
|
||||
! digitsOnly (terms[1]))
|
||||
if (! Lexer::isAllDigits (terms[0]) ||
|
||||
! Lexer::isAllDigits (terms[1]))
|
||||
{
|
||||
is_an_id = false;
|
||||
break;
|
||||
@@ -1410,7 +1467,7 @@ void CLI::findIDs ()
|
||||
a->tag ("ID");
|
||||
|
||||
// Save the ranges.
|
||||
std::vector <std::pair <int, int> >::iterator r;
|
||||
std::vector <std::pair <int, int>>::iterator r;
|
||||
for (r = ranges.begin (); r != ranges.end (); ++r)
|
||||
_id_ranges.push_back (*r);
|
||||
}
|
||||
@@ -1519,7 +1576,7 @@ void CLI::insertIDExpr ()
|
||||
reconstructed.push_back (openParen);
|
||||
|
||||
// Add all ID ranges.
|
||||
std::vector <std::pair <int, int> >::iterator r;
|
||||
std::vector <std::pair <int, int>>::iterator r;
|
||||
for (r = _id_ranges.begin (); r != _id_ranges.end (); ++r)
|
||||
{
|
||||
if (r != _id_ranges.begin ())
|
||||
@@ -1814,8 +1871,7 @@ void CLI::injectDefaults ()
|
||||
if (defaultCommand != "")
|
||||
{
|
||||
// Split the defaultCommand into separate args.
|
||||
std::vector <std::string> tokens;
|
||||
Lexer::token_split (tokens, defaultCommand);
|
||||
std::vector <std::string> tokens = Lexer::split (defaultCommand);
|
||||
|
||||
// Modify _args to be: <args0> [<def0> ...] <args1> [...]
|
||||
std::vector <A> reconstructed;
|
||||
@@ -2209,7 +2265,7 @@ bool CLI::isIDSequence (const std::string& raw) const
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CLI::isID (const std::string& raw) const
|
||||
{
|
||||
return digitsOnly (raw);
|
||||
return Lexer::isAllDigits (raw);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -2303,11 +2359,11 @@ bool CLI::isName (const std::string& raw) const
|
||||
{
|
||||
if (raw != "")
|
||||
{
|
||||
for (int i = 0; i < raw.length (); ++i)
|
||||
for (unsigned int i = 0; i < raw.length (); ++i)
|
||||
{
|
||||
if (i == 0 && ! Lexer::is_ident_start (raw[i]))
|
||||
if (i == 0 && ! Lexer::isIdentifierStart (raw[i]))
|
||||
return false;
|
||||
else if (! Lexer::is_ident (raw[i]))
|
||||
else if (! Lexer::isIdentifierNext (raw[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2319,19 +2375,19 @@ bool CLI::isName (const std::string& raw) const
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CLI::disqualifyInsufficientTerms (
|
||||
const std::vector <std::pair <std::string, Lexer::Type> >& lexemes) const
|
||||
const std::vector <std::pair <std::string, Lexer::Type>>& lexemes) const
|
||||
{
|
||||
return lexemes.size () < 3 ? true : false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CLI::disqualifyNoOps (
|
||||
const std::vector <std::pair <std::string, Lexer::Type> >& lexemes) const
|
||||
const std::vector <std::pair <std::string, Lexer::Type>>& lexemes) const
|
||||
{
|
||||
bool foundOP = false;
|
||||
std::vector <std::pair <std::string, Lexer::Type> >::const_iterator l;
|
||||
std::vector <std::pair <std::string, Lexer::Type>>::const_iterator l;
|
||||
for (l = lexemes.begin (); l != lexemes.end (); ++l)
|
||||
if (l->second == Lexer::typeOperator)
|
||||
if (l->second == Lexer::Type::op)
|
||||
foundOP = true;
|
||||
|
||||
return ! foundOP;
|
||||
@@ -2339,16 +2395,16 @@ bool CLI::disqualifyNoOps (
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool CLI::disqualifyOnlyParenOps (
|
||||
const std::vector <std::pair <std::string, Lexer::Type> >& lexemes) const
|
||||
const std::vector <std::pair <std::string, Lexer::Type>>& lexemes) const
|
||||
{
|
||||
int opCount = 0;
|
||||
int opSugarCount = 0;
|
||||
int opParenCount = 0;
|
||||
|
||||
std::vector <std::pair <std::string, Lexer::Type> >::const_iterator l;
|
||||
std::vector <std::pair <std::string, Lexer::Type>>::const_iterator l;
|
||||
for (l = lexemes.begin (); l != lexemes.end (); ++l)
|
||||
{
|
||||
if (l->second == Lexer::typeOperator)
|
||||
if (l->second == Lexer::Type::op)
|
||||
{
|
||||
++opCount;
|
||||
|
||||
@@ -2375,7 +2431,7 @@ bool CLI::disqualifyOnlyParenOps (
|
||||
// as there are no operators in between, which includes syntactic sugar that
|
||||
// hides operators.
|
||||
bool CLI::disqualifyFirstLastBinary (
|
||||
const std::vector <std::pair <std::string, Lexer::Type> >& lexemes) const
|
||||
const std::vector <std::pair <std::string, Lexer::Type>>& lexemes) const
|
||||
{
|
||||
bool firstBinary = false;
|
||||
bool lastBinary = false;
|
||||
@@ -2394,7 +2450,7 @@ bool CLI::disqualifyFirstLastBinary (
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Disqualify terms when there operators hidden by syntactic sugar.
|
||||
bool CLI::disqualifySugarFree (
|
||||
const std::vector <std::pair <std::string, Lexer::Type> >& lexemes) const
|
||||
const std::vector <std::pair <std::string, Lexer::Type>>& lexemes) const
|
||||
{
|
||||
bool sugared = true;
|
||||
for (unsigned int i = 1; i < lexemes.size () - 1; ++i)
|
||||
|
||||
18
src/CLI.h
18
src/CLI.h
@@ -77,9 +77,11 @@ public:
|
||||
void entity (const std::string&, const std::string&);
|
||||
void initialize (int, const char**);
|
||||
void add (const std::string&);
|
||||
void addContextFilter ();
|
||||
void addRawFilter (const std::string& arg);
|
||||
void analyze (bool parse = true, bool strict = false);
|
||||
void applyOverrides ();
|
||||
const std::string getFilter ();
|
||||
const std::string getFilter (bool applyContext = true);
|
||||
const std::vector <std::string> getWords ();
|
||||
bool canonicalize (std::string&, const std::string&, const std::string&) const;
|
||||
std::string getBinary () const;
|
||||
@@ -88,7 +90,7 @@ public:
|
||||
const std::string dump (const std::string& title = "CLI Parser") const;
|
||||
|
||||
private:
|
||||
void addArg (const std::string&);
|
||||
void addArg (const std::string&, Lexer::Type type = Lexer::Type::word);
|
||||
void aliasExpansion ();
|
||||
void findOverrides ();
|
||||
void categorize ();
|
||||
@@ -126,11 +128,11 @@ private:
|
||||
bool isOperator (const std::string&) const;
|
||||
bool isName (const std::string&) const;
|
||||
|
||||
bool disqualifyInsufficientTerms (const std::vector <std::pair <std::string, Lexer::Type> >&) const;
|
||||
bool disqualifyNoOps (const std::vector <std::pair <std::string, Lexer::Type> >&) const;
|
||||
bool disqualifyOnlyParenOps (const std::vector <std::pair <std::string, Lexer::Type> >&) const;
|
||||
bool disqualifyFirstLastBinary (const std::vector <std::pair <std::string, Lexer::Type> >&) const;
|
||||
bool disqualifySugarFree (const std::vector <std::pair <std::string, Lexer::Type> >&) const;
|
||||
bool disqualifyInsufficientTerms (const std::vector <std::pair <std::string, Lexer::Type>>&) const;
|
||||
bool disqualifyNoOps (const std::vector <std::pair <std::string, Lexer::Type>>&) const;
|
||||
bool disqualifyOnlyParenOps (const std::vector <std::pair <std::string, Lexer::Type>>&) const;
|
||||
bool disqualifyFirstLastBinary (const std::vector <std::pair <std::string, Lexer::Type>>&) const;
|
||||
bool disqualifySugarFree (const std::vector <std::pair <std::string, Lexer::Type>>&) const;
|
||||
|
||||
public:
|
||||
std::multimap <std::string, std::string> _entities;
|
||||
@@ -138,7 +140,7 @@ public:
|
||||
std::vector <std::string> _original_args;
|
||||
std::vector <A> _args;
|
||||
|
||||
std::vector <std::pair <int, int> > _id_ranges;
|
||||
std::vector <std::pair <int, int>> _id_ranges;
|
||||
std::vector <std::string> _uuid_list;
|
||||
bool _strict;
|
||||
bool _terminated;
|
||||
|
||||
@@ -48,16 +48,19 @@ set (task_SRCS CLI.cpp CLI.h
|
||||
add_library (task STATIC ${task_SRCS})
|
||||
add_executable (task_executable main.cpp)
|
||||
add_executable (calc_executable calc.cpp)
|
||||
add_executable (lex_executable lex.cpp)
|
||||
|
||||
# Yes, 'task' is included twice, otherwise linking fails on assorted OSes.
|
||||
target_link_libraries (task_executable task commands columns task ${TASK_LIBRARIES})
|
||||
target_link_libraries (calc_executable task commands columns task ${TASK_LIBRARIES})
|
||||
target_link_libraries (lex_executable task commands columns task ${TASK_LIBRARIES})
|
||||
|
||||
set_property (TARGET task_executable PROPERTY OUTPUT_NAME "task")
|
||||
|
||||
install (TARGETS task_executable DESTINATION ${TASK_BINDIR})
|
||||
|
||||
set_property (TARGET calc_executable PROPERTY OUTPUT_NAME "calc")
|
||||
set_property (TARGET lex_executable PROPERTY OUTPUT_NAME "lex")
|
||||
|
||||
#SET(CMAKE_BUILD_TYPE gcov)
|
||||
#SET(CMAKE_CXX_FLAGS_GCOV "--coverage")
|
||||
|
||||
@@ -82,6 +82,7 @@ std::string Config::_defaults =
|
||||
"# # Comma-separated list. May contain any subset of:\n"
|
||||
"#verbose=blank,header,footnote,label,new-id,new-uuid,affected,edit,special,project,sync,filter\n"
|
||||
"confirmation=yes # Confirmation on delete, big changes\n"
|
||||
"recurrence=yes # Enable recurrence\n"
|
||||
"recurrence.confirmation=prompt # Confirmation for propagating changes among recurring tasks (yes/no/prompt)\n"
|
||||
"allow.empty.filter=yes # An empty filter gets a warning and requires confirmation\n"
|
||||
"indent.annotation=2 # Indent spaces for annotations\n"
|
||||
@@ -116,6 +117,7 @@ std::string Config::_defaults =
|
||||
"dateformat.info=Y-M-D H:N:S # Preferred display date format for information\n"
|
||||
"dateformat.report= # Preferred display date format for reports\n"
|
||||
"dateformat.annotation= # Preferred display date format for annotations\n"
|
||||
"date.iso=yes # Enable ISO date support\n"
|
||||
"weekstart="
|
||||
STRING_DATE_SUNDAY_LONG
|
||||
" # Sunday or Monday only\n"
|
||||
@@ -145,7 +147,6 @@ std::string Config::_defaults =
|
||||
"urgency.next.coefficient=15.0 # Urgency coefficient for 'next' special tag\n"
|
||||
"urgency.due.coefficient=12.0 # Urgency coefficient for due dates\n"
|
||||
"urgency.blocking.coefficient=8.0 # Urgency coefficient for blocking tasks\n"
|
||||
"urgency.priority.coefficient=6.0 # Urgency coefficient for priorities\n"
|
||||
"urgency.active.coefficient=4.0 # Urgency coefficient for active tasks\n"
|
||||
"urgency.scheduled.coefficient=5.0 # Urgency coefficient for scheduled tasks\n"
|
||||
"urgency.age.coefficient=2.0 # Urgency coefficient for age\n"
|
||||
@@ -163,38 +164,37 @@ std::string Config::_defaults =
|
||||
"\n"
|
||||
"# Color controls.\n"
|
||||
"color=on # Enable color\n"
|
||||
#ifdef LINUX
|
||||
#if defined(LINUX) || defined(DARWIN)
|
||||
"\n"
|
||||
"rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.\n"
|
||||
"rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.\n"
|
||||
"\n"
|
||||
"# General decoration\n"
|
||||
"color.label=\n"
|
||||
"color.label.sort=\n"
|
||||
"color.alternate=on gray1\n"
|
||||
"color.alternate=on gray2\n"
|
||||
"color.header=color3\n"
|
||||
"color.footnote=color3\n"
|
||||
"color.warning=bold red\n"
|
||||
"color.error=color3\n"
|
||||
"color.debug=color3\n"
|
||||
"color.error=white on red\n"
|
||||
"color.debug=color4\n"
|
||||
"\n"
|
||||
"# Task state\n"
|
||||
"color.completed=rgb010 on white\n"
|
||||
"color.deleted=rgb100 on white\n"
|
||||
"color.completed=\n"
|
||||
"color.deleted=\n"
|
||||
"color.active=rgb555 on rgb410\n"
|
||||
"color.recurring=rgb013\n"
|
||||
"color.scheduled=on rgb001\n"
|
||||
"color.until=\n"
|
||||
"color.blocked=white on color8\n"
|
||||
"color.blocking=white on color15\n"
|
||||
"color.blocking=black on color15\n"
|
||||
"\n"
|
||||
"# Project\n"
|
||||
"color.project.none=\n"
|
||||
"\n"
|
||||
"# Priority\n"
|
||||
"color.pri.H=color255\n"
|
||||
"color.pri.L=color245\n"
|
||||
"color.pri.M=color250\n"
|
||||
"color.pri.none=\n"
|
||||
"# Priority UDA\n"
|
||||
"color.uda.priority.H=color255\n"
|
||||
"color.uda.priority.L=color245\n"
|
||||
"color.uda.priority.M=color250\n"
|
||||
"\n"
|
||||
"# Tags\n"
|
||||
"color.tag.next=rgb440\n"
|
||||
@@ -240,7 +240,7 @@ std::string Config::_defaults =
|
||||
"\n"
|
||||
#else
|
||||
"\n"
|
||||
"rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.\n"
|
||||
"rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.\n"
|
||||
"\n"
|
||||
"# General decoration\n"
|
||||
"color.label=\n"
|
||||
@@ -249,15 +249,15 @@ std::string Config::_defaults =
|
||||
"color.header=yellow\n"
|
||||
"color.footnote=yellow\n"
|
||||
"color.warning=bold red\n"
|
||||
"color.error=yellow\n"
|
||||
"color.debug=yellow\n"
|
||||
"color.error=white on red\n"
|
||||
"color.debug=blue\n"
|
||||
"\n"
|
||||
"# Task state\n"
|
||||
"color.completed=green on white\n"
|
||||
"color.deleted=red on white\n"
|
||||
"color.completed=\n"
|
||||
"color.deleted=\n"
|
||||
"color.active=black on bright green\n"
|
||||
"color.recurring=magenta\n"
|
||||
"color.scheduled=on green\n"
|
||||
"color.scheduled=white on green\n"
|
||||
"color.until=\n"
|
||||
"color.blocked=black on white\n"
|
||||
"color.blocking=black on bright white\n"
|
||||
@@ -265,11 +265,10 @@ std::string Config::_defaults =
|
||||
"# Project\n"
|
||||
"color.project.none=\n"
|
||||
"\n"
|
||||
"# Priority\n"
|
||||
"color.pri.H=bold white\n"
|
||||
"color.pri.M=white\n"
|
||||
"color.pri.L=\n"
|
||||
"color.pri.none=\n"
|
||||
"# Priority UDA\n"
|
||||
"color.uda.priority.H=bold white\n"
|
||||
"color.uda.priority.M=white\n"
|
||||
"color.uda.priority.L=\n"
|
||||
"\n"
|
||||
"# Tags\n"
|
||||
"color.tag.next=bold yellow\n"
|
||||
@@ -317,22 +316,33 @@ std::string Config::_defaults =
|
||||
"color.undo.before=red\n"
|
||||
"\n"
|
||||
#endif
|
||||
"# UDA priority\n"
|
||||
"uda.priority.type=string # UDA priority is a string type\n"
|
||||
"uda.priority.label=Priority # UDA priority has a display label'\n"
|
||||
"uda.priority.values=H,M,L, # UDA priority values are 'H', 'M', 'L' or ''\n"
|
||||
" # UDA priority sorting is 'H' > 'M' > 'L' > '' (highest to lowest)\n"
|
||||
"#uda.priority.default=M # UDA priority default value of 'M'\n"
|
||||
"urgency.uda.priority.H.coefficient=6.0 # UDA priority coefficient for value 'H'\n"
|
||||
"urgency.uda.priority.M.coefficient=3.9 # UDA priority coefficient for value 'M'\n"
|
||||
"urgency.uda.priority.L.coefficient=1.8 # UDA priority coefficient for value 'L'\n"
|
||||
"\n"
|
||||
"# Here is the rule precedence order, highest to lowest.\n"
|
||||
"# Note that these are just the color rule names, without the leading 'color.'\n"
|
||||
"# and any trailing '.value'.\n"
|
||||
"rule.precedence.color=deleted,completed,active,keyword.,tag.,uda.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,pri.\n"
|
||||
"rule.precedence.color=deleted,completed,active,keyword.,tag.,project.,overdue,scheduled,due.today,due,blocked,blocking,recurring,tagged,uda.\n"
|
||||
"\n"
|
||||
"#default.project=foo # Default project for 'add' command\n"
|
||||
"#default.priority=M # Default priority for 'add' command\n"
|
||||
"#default.due=eom # Default due date for 'add' command\n"
|
||||
"default.command=next # When no arguments are specified\n"
|
||||
"\n"
|
||||
"_forcecolor=no # Forces color to be on, even for non TTY output\n"
|
||||
"complete.all.tags=no # Include old tag names in '_ags' command\n"
|
||||
"list.all.projects=no # Include old project names in 'projects' command\n"
|
||||
"summary.all.projects=no # Include old project names in 'summary' command\n"
|
||||
"list.all.tags=no # Include old tag names in 'tags' command\n"
|
||||
"print.empty.columns=no # Print columns which have no data for any task\n"
|
||||
"debug=no # Display diagnostics\n"
|
||||
"obfuscate=no # Obfuscate data for error reporting\n"
|
||||
"fontunderline=yes # Uses underlines rather than -------\n"
|
||||
"shell.prompt=task> # Prompt used by the shell command\n"
|
||||
"\n"
|
||||
@@ -358,19 +368,19 @@ std::string Config::_defaults =
|
||||
"\n"
|
||||
"report.long.description=All details of tasks\n"
|
||||
"report.long.labels=ID,A,Created,Mod,Deps,P,Project,Tags,Recur,Wait,Sched,Due,Until,Description\n"
|
||||
"report.long.columns=id,start.active,entry,modified.age,depends,priority,project,tags,recur,wait.age,scheduled,due,until,description\n"
|
||||
"report.long.columns=id,start.active,entry,modified.age,depends,priority,project,tags,recur,wait.remaining,scheduled,due,until,description\n"
|
||||
"report.long.filter=status:pending\n"
|
||||
"report.long.sort=modified-\n"
|
||||
"\n"
|
||||
"report.list.description=Most details of tasks\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.age,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.sort=start-,due+,project+/,urgency-\n"
|
||||
"report.list.sort=start-,due+,project+,urgency-\n"
|
||||
"\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.columns=id,start.active,depends.indicator,project,tags,recur.indicator,wait.age,scheduled.countdown,due.countdown,until.countdown,description.count\n"
|
||||
"report.ls.columns=id,start.active,depends.indicator,project,tags,recur.indicator,wait.remaining,scheduled.countdown,due.countdown,until.countdown,description.count\n"
|
||||
"report.ls.filter=status:pending\n"
|
||||
"report.ls.sort=start-,description+\n"
|
||||
"\n"
|
||||
@@ -382,13 +392,13 @@ std::string Config::_defaults =
|
||||
"\n"
|
||||
"report.newest.description=Newest tasks\n"
|
||||
"report.newest.labels=ID,Active,Created,Age,Mod,D,P,Project,Tags,R,Wait,Sch,Due,Until,Description\n"
|
||||
"report.newest.columns=id,start.age,entry,entry.age,modified.age,depends.indicator,priority,project,tags,recur.indicator,wait.age,scheduled.countdown,due,until.age,description\n"
|
||||
"report.newest.filter=(status:pending or status:waiting) and recur.none:\n"
|
||||
"report.newest.columns=id,start.age,entry,entry.age,modified.age,depends.indicator,priority,project,tags,recur.indicator,wait.remaining,scheduled.countdown,due,until.age,description\n"
|
||||
"report.newest.filter=(status:pending or status:waiting)\n"
|
||||
"report.newest.sort=entry-\n"
|
||||
"\n"
|
||||
"report.oldest.description=Oldest tasks\n"
|
||||
"report.oldest.labels=ID,Active,Created,Age,Mod,D,P,Project,Tags,R,Wait,Sch,Due,Until,Description\n"
|
||||
"report.oldest.columns=id,start.age,entry,entry.age,modified.age,depends.indicator,priority,project,tags,recur.indicator,wait.age,scheduled.countdown,due,until.age,description\n"
|
||||
"report.oldest.columns=id,start.age,entry,entry.age,modified.age,depends.indicator,priority,project,tags,recur.indicator,wait.remaining,scheduled.countdown,due,until.age,description\n"
|
||||
"report.oldest.filter=(status:pending or status:waiting)\n"
|
||||
"report.oldest.sort=entry+\n"
|
||||
"\n"
|
||||
@@ -400,7 +410,7 @@ std::string Config::_defaults =
|
||||
"\n"
|
||||
"report.active.description=Active tasks\n"
|
||||
"report.active.labels=ID,Started,Active,Age,D,P,Project,Tags,Recur,W,Sch,Due,Until,Description\n"
|
||||
"report.active.columns=id,start,start.age,entry.age,depends.indicator,priority,project,tags,recur,wait.indicator,scheduled.age,due,until,description\n"
|
||||
"report.active.columns=id,start,start.age,entry.age,depends.indicator,priority,project,tags,recur,wait.indicator,scheduled.remaining,due,until,description\n"
|
||||
"report.active.filter=status:pending and +ACTIVE\n"
|
||||
"report.active.sort=project+,start+\n"
|
||||
"\n"
|
||||
@@ -412,30 +422,30 @@ std::string Config::_defaults =
|
||||
"\n"
|
||||
"report.recurring.description=Recurring Tasks\n"
|
||||
"report.recurring.labels=ID,Active,Age,D,P,Project,Tags,Recur,Sch,Due,Until,Description,Urg\n"
|
||||
"report.recurring.columns=id,start.age,entry.age,depends.indicator,priority,project,tags,recur,scheduled.countdown,due,until.age,description,urgency\n"
|
||||
"report.recurring.columns=id,start.age,entry.age,depends.indicator,priority,project,tags,recur,scheduled.countdown,due,until.remaining,description,urgency\n"
|
||||
"report.recurring.filter=(status:pending or status:waiting) and (+PARENT or +CHILD)\n"
|
||||
"report.recurring.sort=due+,urgency-,entry+\n"
|
||||
"\n"
|
||||
"report.waiting.description=Waiting (hidden) tasks\n"
|
||||
"report.waiting.labels=ID,A,Age,D,P,Project,Tags,R,Wait,for,Sched,Due,Until,Description\n"
|
||||
"report.waiting.columns=id,start.active,entry.age,depends.indicator,priority,project,tags,recur.indicator,wait,wait.age,scheduled,due,until,description\n"
|
||||
"report.waiting.columns=id,start.active,entry.age,depends.indicator,priority,project,tags,recur.indicator,wait,wait.remaining,scheduled,due,until,description\n"
|
||||
"report.waiting.filter=+WAITING\n"
|
||||
"report.waiting.sort=due+,wait+,entry+\n"
|
||||
"\n"
|
||||
"report.all.description=All tasks\n"
|
||||
"report.all.labels=ID,St,UUID,A,Age,Done,D,P,Project,Tags,R,Wait,Sch,Due,Until,Description\n"
|
||||
"report.all.columns=id,status.short,uuid.short,start.active,entry.age,end.age,depends.indicator,priority,project.parent,tags.count,recur.indicator,wait.age,scheduled.age,due,until.age,description\n"
|
||||
"report.all.columns=id,status.short,uuid.short,start.active,entry.age,end.age,depends.indicator,priority,project.parent,tags.count,recur.indicator,wait.remaining,scheduled.remaining,due,until.remaining,description\n"
|
||||
"report.all.sort=entry-\n"
|
||||
"\n"
|
||||
"report.next.description=Most urgent tasks\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.age,until.age,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.sort=start-,urgency-\n"
|
||||
"report.next.sort=urgency-\n"
|
||||
"\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.columns=id,start.age,entry.age,depends.indicator,priority,project,tags,recur.indicator,scheduled.countdown,due.countdown,until.age,description,urgency\n"
|
||||
"report.ready.columns=id,start.age,entry.age,depends.indicator,priority,project,tags,recur.indicator,scheduled.countdown,due.countdown,until.remaining,description,urgency\n"
|
||||
"report.ready.filter=+READY\n"
|
||||
"report.ready.sort=start-,urgency-\n"
|
||||
"\n"
|
||||
@@ -453,7 +463,7 @@ std::string Config::_defaults =
|
||||
"\n"
|
||||
"report.blocking.description=Blocking tasks\n"
|
||||
"report.blocking.labels=ID,UUID,A,Deps,Project,Tags,R,W,Sch,Due,Until,Description,Urg\n"
|
||||
"report.blocking.columns=id,uuid.short,start.active,depends,project,tags,recur,wait.indicator,scheduled.age,due.age,until.age,description.count,urgency\n"
|
||||
"report.blocking.columns=id,uuid.short,start.active,depends,project,tags,recur,wait.indicator,scheduled.remaining,due.remaining,until.remaining,description.count,urgency\n"
|
||||
"report.blocking.sort=urgency-,due+,entry+\n"
|
||||
"report.blocking.filter= status:pending +BLOCKING\n"
|
||||
"\n";
|
||||
|
||||
@@ -65,33 +65,6 @@ static const char* modifierNames[] =
|
||||
|
||||
#define NUM_MODIFIER_NAMES (sizeof (modifierNames) / sizeof (modifierNames[0]))
|
||||
|
||||
static const char* attributeNames[] =
|
||||
{
|
||||
"depends",
|
||||
"description",
|
||||
"due",
|
||||
"end",
|
||||
"entry",
|
||||
"id",
|
||||
"imask",
|
||||
"mask",
|
||||
"modified",
|
||||
"parent",
|
||||
"priority",
|
||||
"project",
|
||||
"recur",
|
||||
"scheduled",
|
||||
"start",
|
||||
"status",
|
||||
"tags",
|
||||
"until",
|
||||
"urgency",
|
||||
"uuid",
|
||||
"wait"
|
||||
};
|
||||
|
||||
#define NUM_ATTRIBUTE_NAMES (sizeof (attributeNames) / sizeof (attributeNames[0]))
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Context::Context ()
|
||||
: rc_file ("~/.taskrc")
|
||||
@@ -101,6 +74,7 @@ Context::Context ()
|
||||
, dom ()
|
||||
, determine_color_use (true)
|
||||
, use_color (true)
|
||||
, run_gc (true)
|
||||
, verbosity_legacy (false)
|
||||
, terminal_width (0)
|
||||
, terminal_height (0)
|
||||
@@ -275,7 +249,7 @@ int Context::initialize (int argc, const char** argv)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// [8] Run on.launch hooks.
|
||||
// [8] Initialize hooks.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -478,7 +452,14 @@ int Context::dispatch (std::string &out)
|
||||
// GC is invoked prior to running any command that displays task IDs, if
|
||||
// possible.
|
||||
if (c->displays_id () && !tdb2.read_only ())
|
||||
{
|
||||
run_gc = config.getBoolean ("gc");
|
||||
tdb2.gc ();
|
||||
}
|
||||
else
|
||||
{
|
||||
run_gc = false;
|
||||
}
|
||||
|
||||
/*
|
||||
// Only read-only commands can be run when TDB2 is read-only.
|
||||
@@ -504,7 +485,7 @@ bool Context::color ()
|
||||
use_color = config.getBoolean ("color");
|
||||
|
||||
// Only tty's support color.
|
||||
if (! isatty (fileno (stdout)))
|
||||
if (! isatty (STDOUT_FILENO))
|
||||
{
|
||||
// No ioctl.
|
||||
config.set ("detection", "off");
|
||||
@@ -652,18 +633,32 @@ void Context::staticInitialization ()
|
||||
CLI::minimumMatchLength = config.getInteger ("abbreviation.minimum");
|
||||
|
||||
Task::defaultProject = config.get ("default.project");
|
||||
Task::defaultPriority = config.get ("default.priority");
|
||||
Task::defaultDue = config.get ("default.due");
|
||||
|
||||
Task::searchCaseSensitive = Variant::searchCaseSensitive = config.getBoolean ("search.case.sensitive");
|
||||
Task::regex = Variant::searchUsingRegex = config.getBoolean ("regex");
|
||||
Lexer::dateFormat = Variant::dateFormat = config.get ("dateformat");
|
||||
Lexer::isoEnabled = Variant::isoEnabled = config.getBoolean ("date.iso");
|
||||
|
||||
Config::const_iterator rc;
|
||||
for (rc = config.begin (); rc != config.end (); ++rc)
|
||||
{
|
||||
if (rc->first.substr (0, 4) == "uda." &&
|
||||
rc->first.substr (rc->first.length () - 7, 7) == ".values")
|
||||
{
|
||||
std::string name = rc->first.substr (4, rc->first.length () - 7 - 4);
|
||||
std::vector <std::string> values;
|
||||
split (values, rc->second, ',');
|
||||
|
||||
for (auto r = values.rbegin(); r != values.rend (); ++r)
|
||||
Task::customOrder[name].push_back (*r);
|
||||
}
|
||||
}
|
||||
|
||||
std::map <std::string, Column*>::iterator i;
|
||||
for (i = columns.begin (); i != columns.end (); ++i)
|
||||
Task::attributes[i->first] = i->second->type ();
|
||||
|
||||
Task::urgencyPriorityCoefficient = config.getReal ("urgency.priority.coefficient");
|
||||
Task::urgencyProjectCoefficient = config.getReal ("urgency.project.coefficient");
|
||||
Task::urgencyActiveCoefficient = config.getReal ("urgency.active.coefficient");
|
||||
Task::urgencyScheduledCoefficient = config.getReal ("urgency.scheduled.coefficient");
|
||||
@@ -770,7 +765,7 @@ void Context::clear ()
|
||||
// this output?'.
|
||||
void Context::updateXtermTitle ()
|
||||
{
|
||||
if (config.getBoolean ("xterm.title") && isatty (fileno (stdout)))
|
||||
if (config.getBoolean ("xterm.title") && isatty (STDOUT_FILENO))
|
||||
{
|
||||
std::string command = cli.getCommand ();
|
||||
std::string title;
|
||||
|
||||
@@ -94,6 +94,8 @@ public:
|
||||
bool determine_color_use;
|
||||
bool use_color;
|
||||
|
||||
bool run_gc;
|
||||
|
||||
bool verbosity_legacy;
|
||||
std::vector <std::string> verbosity;
|
||||
std::vector <std::string> headers;
|
||||
|
||||
64
src/DOM.cpp
64
src/DOM.cpp
@@ -116,16 +116,16 @@ bool DOM::get (const std::string& name, Variant& value)
|
||||
}
|
||||
else if (name == "context.width")
|
||||
{
|
||||
value = Variant (context.terminal_width
|
||||
? context.terminal_width
|
||||
: context.getWidth ());
|
||||
value = Variant (static_cast<int> (context.terminal_width
|
||||
? context.terminal_width
|
||||
: context.getWidth ()));
|
||||
return true;
|
||||
}
|
||||
else if (name == "context.height")
|
||||
{
|
||||
value = Variant (context.terminal_height
|
||||
? context.terminal_height
|
||||
: context.getHeight ());
|
||||
value = Variant (static_cast<int> (context.terminal_height
|
||||
? context.terminal_height
|
||||
: context.getHeight ()));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -218,7 +218,7 @@ bool DOM::get (const std::string& name, const Task& task, Variant& value)
|
||||
// <attr>
|
||||
if (task.size () && name == "id")
|
||||
{
|
||||
value = Variant (task.id);
|
||||
value = Variant (static_cast<int> (task.id));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -240,6 +240,12 @@ bool DOM::get (const std::string& name, const Task& task, Variant& value)
|
||||
Column* column = context.columns[canonical];
|
||||
if (column)
|
||||
{
|
||||
if (column->is_uda () && ! task.has (canonical))
|
||||
{
|
||||
value = Variant ("''");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (column->type () == "date")
|
||||
value = Variant (task.get_date (canonical), Variant::type_date);
|
||||
else if (column->type () == "duration" || canonical == "recur")
|
||||
@@ -290,7 +296,7 @@ bool DOM::get (const std::string& name, const Task& task, Variant& value)
|
||||
{
|
||||
if (elements[1] == "id")
|
||||
{
|
||||
value = Variant (ref.id);
|
||||
value = Variant (static_cast<int> (ref.id));
|
||||
return true;
|
||||
}
|
||||
else if (elements[1] == "urgency")
|
||||
@@ -307,6 +313,12 @@ bool DOM::get (const std::string& name, const Task& task, Variant& value)
|
||||
Column* column = context.columns[canonical];
|
||||
if (column)
|
||||
{
|
||||
if (column->is_uda () && ! ref.has (canonical))
|
||||
{
|
||||
value = Variant ("''");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (column->type () == "date")
|
||||
value = Variant (ref.get_date (canonical), Variant::type_date);
|
||||
else if (column->type () == "duration")
|
||||
@@ -341,15 +353,15 @@ bool DOM::get (const std::string& name, const Task& task, Variant& value)
|
||||
// <date>.minute
|
||||
// <date>.second
|
||||
Date date (ref.get_date (canonical));
|
||||
if (elements[2] == "year") { value = Variant (date.year ()); return true; }
|
||||
else if (elements[2] == "month") { value = Variant (date.month ()); return true; }
|
||||
else if (elements[2] == "day") { value = Variant (date.day ()); return true; }
|
||||
else if (elements[2] == "week") { value = Variant (date.week ()); return true; }
|
||||
else if (elements[2] == "weekday") { value = Variant (date.dayOfWeek ()); return true; }
|
||||
else if (elements[2] == "julian") { value = Variant (date.dayOfYear ()); return true; }
|
||||
else if (elements[2] == "hour") { value = Variant (date.hour ()); return true; }
|
||||
else if (elements[2] == "minute") { value = Variant (date.minute ()); return true; }
|
||||
else if (elements[2] == "second") { value = Variant (date.second ()); return true; }
|
||||
if (elements[2] == "year") { value = Variant (static_cast<int> (date.year ())); return true; }
|
||||
else if (elements[2] == "month") { value = Variant (static_cast<int> (date.month ())); return true; }
|
||||
else if (elements[2] == "day") { value = Variant (static_cast<int> (date.day ())); return true; }
|
||||
else if (elements[2] == "week") { value = Variant (static_cast<int> (date.week ())); return true; }
|
||||
else if (elements[2] == "weekday") { value = Variant (static_cast<int> (date.dayOfWeek ())); return true; }
|
||||
else if (elements[2] == "julian") { value = Variant (static_cast<int> (date.dayOfYear ())); return true; }
|
||||
else if (elements[2] == "hour") { value = Variant (static_cast<int> (date.hour ())); return true; }
|
||||
else if (elements[2] == "minute") { value = Variant (static_cast<int> (date.minute ())); return true; }
|
||||
else if (elements[2] == "second") { value = Variant (static_cast<int> (date.second ())); return true; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -408,15 +420,15 @@ bool DOM::get (const std::string& name, const Task& task, Variant& value)
|
||||
// <annotations>.<N>.entry.minute
|
||||
// <annotations>.<N>.entry.second
|
||||
Date date (i->first.substr (11));
|
||||
if (elements[4] == "year") { value = Variant (date.year ()); return true; }
|
||||
else if (elements[4] == "month") { value = Variant (date.month ()); return true; }
|
||||
else if (elements[4] == "day") { value = Variant (date.day ()); return true; }
|
||||
else if (elements[4] == "week") { value = Variant (date.week ()); return true; }
|
||||
else if (elements[4] == "weekday") { value = Variant (date.dayOfWeek ()); return true; }
|
||||
else if (elements[4] == "julian") { value = Variant (date.dayOfYear ()); return true; }
|
||||
else if (elements[4] == "hour") { value = Variant (date.hour ()); return true; }
|
||||
else if (elements[4] == "minute") { value = Variant (date.minute ()); return true; }
|
||||
else if (elements[4] == "second") { value = Variant (date.second ()); return true; }
|
||||
if (elements[4] == "year") { value = Variant (static_cast<int> (date.year ())); return true; }
|
||||
else if (elements[4] == "month") { value = Variant (static_cast<int> (date.month ())); return true; }
|
||||
else if (elements[4] == "day") { value = Variant (static_cast<int> (date.day ())); return true; }
|
||||
else if (elements[4] == "week") { value = Variant (static_cast<int> (date.week ())); return true; }
|
||||
else if (elements[4] == "weekday") { value = Variant (static_cast<int> (date.dayOfWeek ())); return true; }
|
||||
else if (elements[4] == "julian") { value = Variant (static_cast<int> (date.dayOfYear ())); return true; }
|
||||
else if (elements[4] == "hour") { value = Variant (static_cast<int> (date.hour ())); return true; }
|
||||
else if (elements[4] == "minute") { value = Variant (static_cast<int> (date.minute ())); return true; }
|
||||
else if (elements[4] == "second") { value = Variant (static_cast<int> (date.second ())); return true; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,13 +31,13 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <Nibbler.h>
|
||||
#include <Date.h>
|
||||
#include <Variant.h>
|
||||
#include <Dates.h>
|
||||
#include <text.h>
|
||||
#include <util.h>
|
||||
#include <utf8.h>
|
||||
#include <i18n.h>
|
||||
#include <Context.h>
|
||||
|
||||
@@ -823,7 +823,7 @@ void Date::operator++ (int)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Date::isEpoch (const std::string& input)
|
||||
{
|
||||
if (digitsOnly (input) &&
|
||||
if (Lexer::isAllDigits (input) &&
|
||||
input.length () <= 10 )
|
||||
{
|
||||
_t = (time_t) atoi (input.c_str ());
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <text.h>
|
||||
#include <Dates.h>
|
||||
#include <Date.h>
|
||||
#include <Lexer.h>
|
||||
#include <i18n.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -354,7 +355,7 @@ bool namedDates (const std::string& name, Variant& value)
|
||||
// 4th
|
||||
else if ((
|
||||
name.length () == 3 &&
|
||||
isdigit (name[0]) &&
|
||||
Lexer::isDigit (name[0]) &&
|
||||
((name[1] == 's' && name[2] == 't') ||
|
||||
(name[1] == 'n' && name[2] == 'd') ||
|
||||
(name[1] == 'r' && name[2] == 'd') ||
|
||||
@@ -363,8 +364,8 @@ bool namedDates (const std::string& name, Variant& value)
|
||||
||
|
||||
(
|
||||
name.length () == 4 &&
|
||||
isdigit (name[0]) &&
|
||||
isdigit (name[1]) &&
|
||||
Lexer::isDigit (name[0]) &&
|
||||
Lexer::isDigit (name[1]) &&
|
||||
((name[2] == 's' && name[3] == 't') ||
|
||||
(name[2] == 'n' && name[3] == 'd') ||
|
||||
(name[2] == 'r' && name[3] == 'd') ||
|
||||
@@ -375,7 +376,7 @@ bool namedDates (const std::string& name, Variant& value)
|
||||
int number;
|
||||
std::string ordinal;
|
||||
|
||||
if (isdigit (name[1]))
|
||||
if (Lexer::isDigit (name[1]))
|
||||
{
|
||||
number = strtol (name.substr (0, 2).c_str (), NULL, 10);
|
||||
ordinal = lowerCase (name.substr (2));
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <Directory.h>
|
||||
|
||||
#if defined SOLARIS || defined NETBSD
|
||||
#if defined SOLARIS || defined NETBSD || defined FREEBSD
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -61,31 +61,49 @@ static struct
|
||||
{"fortnight", 14 * DAY, true},
|
||||
{"hours", 1 * HOUR, false},
|
||||
{"hour", 1 * HOUR, true},
|
||||
{"hrs", 1 * HOUR, false},
|
||||
{"hr", 1 * HOUR, true},
|
||||
{"h", 1 * HOUR, false},
|
||||
{"minutes", 1 * MINUTE, false},
|
||||
{"minute", 1 * MINUTE, false},
|
||||
{"min", 1 * MINUTE, false},
|
||||
{"minute", 1 * MINUTE, true},
|
||||
{"mins", 1 * MINUTE, false},
|
||||
{"min", 1 * MINUTE, true},
|
||||
{"monthly", 30 * DAY, true},
|
||||
{"months", 30 * DAY, false},
|
||||
{"month", 30 * DAY, true},
|
||||
{"mo", 30 * DAY, false},
|
||||
{"mnths", 30 * DAY, false},
|
||||
{"mths", 30 * DAY, false},
|
||||
{"mth", 30 * DAY, true},
|
||||
{"mos", 30 * DAY, false},
|
||||
{"mo", 30 * DAY, true},
|
||||
{"m", 30 * DAY, false},
|
||||
{"quarterly", 91 * DAY, true},
|
||||
{"quarters", 91 * DAY, false},
|
||||
{"quarter", 91 * DAY, true},
|
||||
{"qrtrs", 91 * DAY, false},
|
||||
{"qrtr", 91 * DAY, true},
|
||||
{"qtrs", 91 * DAY, false},
|
||||
{"qtr", 91 * DAY, true},
|
||||
{"q", 91 * DAY, false},
|
||||
{"semiannual", 183 * DAY, true},
|
||||
{"sennight", 14 * DAY, false},
|
||||
{"seconds", 1 * SECOND, false},
|
||||
{"second", 1 * SECOND, true},
|
||||
{"secs", 1 * SECOND, false},
|
||||
{"sec", 1 * SECOND, true},
|
||||
{"s", 1 * SECOND, false},
|
||||
{"weekdays", 1 * DAY, true},
|
||||
{"weekly", 7 * DAY, true},
|
||||
{"weeks", 7 * DAY, false},
|
||||
{"week", 7 * DAY, true},
|
||||
{"wks", 7 * DAY, false},
|
||||
{"wk", 7 * DAY, true},
|
||||
{"w", 7 * DAY, false},
|
||||
{"yearly", 365 * DAY, true},
|
||||
{"years", 365 * DAY, false},
|
||||
{"year", 365 * DAY, true},
|
||||
{"yrs", 365 * DAY, false},
|
||||
{"yr", 365 * DAY, true},
|
||||
{"y", 365 * DAY, false},
|
||||
};
|
||||
|
||||
@@ -107,7 +125,7 @@ Duration::Duration (time_t input)
|
||||
Duration::Duration (const std::string& input)
|
||||
: _secs (0)
|
||||
{
|
||||
if (digitsOnly (input))
|
||||
if (Lexer::isAllDigits (input))
|
||||
{
|
||||
time_t value = (time_t) strtol (input.c_str (), NULL, 10);
|
||||
if (value == 0 || value > 60)
|
||||
@@ -284,10 +302,11 @@ bool Duration::parse (const std::string& input, std::string::size_type& start)
|
||||
std::string::size_type original_start = start;
|
||||
Nibbler n (input.substr (start));
|
||||
|
||||
// TODO This can be made static, and so preserved between calls.
|
||||
std::vector <std::string> units;
|
||||
for (int i = 0; i < NUM_DURATIONS; i++)
|
||||
units.push_back (durations[i].unit);
|
||||
// Static and so preserved between calls.
|
||||
static std::vector <std::string> units;
|
||||
if (units.size () == 0)
|
||||
for (unsigned int i = 0; i < NUM_DURATIONS; i++)
|
||||
units.push_back (durations[i].unit);
|
||||
|
||||
std::string number;
|
||||
std::string unit;
|
||||
@@ -295,13 +314,12 @@ bool Duration::parse (const std::string& input, std::string::size_type& start)
|
||||
if (n.getOneOf (units, unit))
|
||||
{
|
||||
if (n.depleted () ||
|
||||
Lexer::is_ws (n.next ()))
|
||||
Lexer::isWhitespace (n.next ()))
|
||||
{
|
||||
start = original_start + n.cursor ();
|
||||
|
||||
// Linear lookup - should be logarithmic.
|
||||
double seconds = 1;
|
||||
for (int i = 0; i < NUM_DURATIONS; i++)
|
||||
for (unsigned int i = 0; i < NUM_DURATIONS; i++)
|
||||
{
|
||||
if (durations[i].unit == unit &&
|
||||
durations[i].standalone == true)
|
||||
@@ -319,14 +337,14 @@ bool Duration::parse (const std::string& input, std::string::size_type& start)
|
||||
if (n.getOneOf (units, unit))
|
||||
{
|
||||
if (n.depleted () ||
|
||||
Lexer::is_ws (n.next ()))
|
||||
Lexer::isWhitespace (n.next ()))
|
||||
{
|
||||
start = original_start + n.cursor ();
|
||||
double quantity = strtod (number.c_str (), NULL);
|
||||
|
||||
// Linear lookup - should be logarithmic.
|
||||
double seconds = 1;
|
||||
for (int i = 0; i < NUM_DURATIONS; i++)
|
||||
for (unsigned int i = 0; i < NUM_DURATIONS; i++)
|
||||
{
|
||||
if (durations[i].unit == unit)
|
||||
{
|
||||
|
||||
186
src/Eval.cpp
186
src/Eval.cpp
@@ -127,7 +127,7 @@ void Eval::evaluateInfixExpression (const std::string& e, Variant& v) const
|
||||
// Reduce e to a vector of tokens.
|
||||
Lexer l (e);
|
||||
l.ambiguity (_ambiguity);
|
||||
std::vector <std::pair <std::string, Lexer::Type> > tokens;
|
||||
std::vector <std::pair <std::string, Lexer::Type>> tokens;
|
||||
std::string token;
|
||||
Lexer::Type type;
|
||||
while (l.token (token, type))
|
||||
@@ -155,7 +155,7 @@ void Eval::evaluatePostfixExpression (const std::string& e, Variant& v) const
|
||||
// Reduce e to a vector of tokens.
|
||||
Lexer l (e);
|
||||
l.ambiguity (_ambiguity);
|
||||
std::vector <std::pair <std::string, Lexer::Type> > tokens;
|
||||
std::vector <std::pair <std::string, Lexer::Type>> tokens;
|
||||
std::string token;
|
||||
Lexer::Type type;
|
||||
while (l.token (token, type))
|
||||
@@ -179,7 +179,7 @@ void Eval::compileExpression (const std::string& e)
|
||||
while (l.token (token, type))
|
||||
{
|
||||
if (_debug)
|
||||
context.debug ("Lexer '" + token + "' " + Lexer::type_name (type));
|
||||
context.debug ("Lexer '" + token + "' " + Lexer::typeToString (type));
|
||||
_compiled.push_back (std::pair <std::string, Lexer::Type> (token, type));
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ void Eval::getBinaryOperators (std::vector <std::string>& all)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Eval::evaluatePostfixStack (
|
||||
const std::vector <std::pair <std::string, Lexer::Type> >& tokens,
|
||||
const std::vector <std::pair <std::string, Lexer::Type>>& tokens,
|
||||
Variant& result) const
|
||||
{
|
||||
if (tokens.size () == 0)
|
||||
@@ -245,11 +245,11 @@ void Eval::evaluatePostfixStack (
|
||||
// This is stack used by the postfix evaluator.
|
||||
std::vector <Variant> values;
|
||||
|
||||
std::vector <std::pair <std::string, Lexer::Type> >::const_iterator token;
|
||||
std::vector <std::pair <std::string, Lexer::Type>>::const_iterator token;
|
||||
for (token = tokens.begin (); token != tokens.end (); ++token)
|
||||
{
|
||||
// Unary operators.
|
||||
if (token->second == Lexer::typeOperator &&
|
||||
if (token->second == Lexer::Type::op &&
|
||||
token->first == "!")
|
||||
{
|
||||
if (values.size () < 1)
|
||||
@@ -262,7 +262,7 @@ void Eval::evaluatePostfixStack (
|
||||
if (_debug)
|
||||
context.debug (format ("Eval {1} ↓'{2}' → ↑'{3}'", token->first, (std::string) right, (std::string) result));
|
||||
}
|
||||
else if (token->second == Lexer::typeOperator &&
|
||||
else if (token->second == Lexer::Type::op &&
|
||||
token->first == "_neg_")
|
||||
{
|
||||
if (values.size () < 1)
|
||||
@@ -278,7 +278,7 @@ void Eval::evaluatePostfixStack (
|
||||
if (_debug)
|
||||
context.debug (format ("Eval {1} ↓'{2}' → ↑'{3}'", token->first, (std::string) right, (std::string) result));
|
||||
}
|
||||
else if (token->second == Lexer::typeOperator &&
|
||||
else if (token->second == Lexer::Type::op &&
|
||||
token->first == "_pos_")
|
||||
{
|
||||
// The _pos_ operator is a NOP.
|
||||
@@ -287,7 +287,7 @@ void Eval::evaluatePostfixStack (
|
||||
}
|
||||
|
||||
// Binary operators.
|
||||
else if (token->second == Lexer::typeOperator)
|
||||
else if (token->second == Lexer::Type::op)
|
||||
{
|
||||
if (values.size () < 2)
|
||||
throw std::string (STRING_EVAL_NO_EVAL);
|
||||
@@ -338,24 +338,28 @@ void Eval::evaluatePostfixStack (
|
||||
Variant v (token->first);
|
||||
switch (token->second)
|
||||
{
|
||||
case Lexer::typeNumber:
|
||||
case Lexer::typeHex:
|
||||
v.cast (Variant::type_integer);
|
||||
if (_debug)
|
||||
context.debug (format ("Eval literal number ↑'{1}'", (std::string) v));
|
||||
case Lexer::Type::number:
|
||||
if (Lexer::isAllDigits (token->first))
|
||||
{
|
||||
v.cast (Variant::type_integer);
|
||||
if (_debug)
|
||||
context.debug (format ("Eval literal number ↑'{1}'", (std::string) v));
|
||||
}
|
||||
else
|
||||
{
|
||||
v.cast (Variant::type_real);
|
||||
if (_debug)
|
||||
context.debug (format ("Eval literal decimal ↑'{1}'", (std::string) v));
|
||||
}
|
||||
break;
|
||||
|
||||
case Lexer::typeDecimal:
|
||||
v.cast (Variant::type_real);
|
||||
if (_debug)
|
||||
context.debug (format ("Eval literal decimal ↑'{1}'", (std::string) v));
|
||||
break;
|
||||
|
||||
case Lexer::typeOperator:
|
||||
case Lexer::Type::op:
|
||||
throw std::string (STRING_EVAL_OP_EXPECTED);
|
||||
break;
|
||||
|
||||
case Lexer::typeIdentifier:
|
||||
case Lexer::Type::dom:
|
||||
case Lexer::Type::identifier:
|
||||
{
|
||||
bool found = false;
|
||||
std::vector <bool (*)(const std::string&, Variant&)>::const_iterator source;
|
||||
@@ -380,20 +384,33 @@ void Eval::evaluatePostfixStack (
|
||||
}
|
||||
break;
|
||||
|
||||
case Lexer::typeDate:
|
||||
case Lexer::Type::date:
|
||||
v.cast (Variant::type_date);
|
||||
if (_debug)
|
||||
context.debug (format ("Eval literal date ↑'{1}'", (std::string) v));
|
||||
break;
|
||||
|
||||
case Lexer::typeDuration:
|
||||
case Lexer::Type::duration:
|
||||
v.cast (Variant::type_duration);
|
||||
if (_debug)
|
||||
context.debug (format ("Eval literal duration ↑'{1}'", (std::string) v));
|
||||
break;
|
||||
|
||||
// Nothing to do.
|
||||
case Lexer::typeString:
|
||||
/*
|
||||
case Lexer::Type::uuid:
|
||||
case Lexer::Type::hex:
|
||||
case Lexer::Type::list:
|
||||
case Lexer::Type::url:
|
||||
case Lexer::Type::pair:
|
||||
case Lexer::Type::separator:
|
||||
case Lexer::Type::tag:
|
||||
case Lexer::Type::path:
|
||||
case Lexer::Type::substitution:
|
||||
case Lexer::Type::pattern:
|
||||
case Lexer::Type::word:
|
||||
*/
|
||||
case Lexer::Type::string:
|
||||
default:
|
||||
if (_debug)
|
||||
context.debug (format ("Eval literal string ↑'{1}'", (std::string) v));
|
||||
@@ -427,26 +444,26 @@ void Eval::evaluatePostfixStack (
|
||||
// Primitive --> "(" Logical ")" | Variant
|
||||
//
|
||||
void Eval::infixParse (
|
||||
std::vector <std::pair <std::string, Lexer::Type> >& infix) const
|
||||
std::vector <std::pair <std::string, Lexer::Type>>& infix) const
|
||||
{
|
||||
int i = 0;
|
||||
unsigned int i = 0;
|
||||
parseLogical (infix, i);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Logical --> Regex {( "and" | "or" | "xor" ) Regex}
|
||||
bool Eval::parseLogical (
|
||||
std::vector <std::pair <std::string, Lexer::Type> >& infix,
|
||||
int &i) const
|
||||
std::vector <std::pair <std::string, Lexer::Type>>& infix,
|
||||
unsigned int &i) const
|
||||
{
|
||||
if (i < infix.size () &&
|
||||
parseRegex (infix, i))
|
||||
{
|
||||
while (i < infix.size () &&
|
||||
infix[i].second == Lexer::Type::op &&
|
||||
(infix[i].first == "and" ||
|
||||
infix[i].first == "or" ||
|
||||
infix[i].first == "xor") &&
|
||||
infix[i].second == Lexer::typeOperator)
|
||||
infix[i].first == "xor"))
|
||||
{
|
||||
++i;
|
||||
if (! parseRegex (infix, i))
|
||||
@@ -462,16 +479,16 @@ bool Eval::parseLogical (
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Regex --> Equality {( "~" | "!~" ) Equality}
|
||||
bool Eval::parseRegex (
|
||||
std::vector <std::pair <std::string, Lexer::Type> >& infix,
|
||||
int &i) const
|
||||
std::vector <std::pair <std::string, Lexer::Type>>& infix,
|
||||
unsigned int &i) const
|
||||
{
|
||||
if (i < infix.size () &&
|
||||
parseEquality (infix, i))
|
||||
{
|
||||
while (i < infix.size () &&
|
||||
infix[i].second == Lexer::Type::op &&
|
||||
(infix[i].first == "~" ||
|
||||
infix[i].first == "!~") &&
|
||||
infix[i].second == Lexer::typeOperator)
|
||||
infix[i].first == "!~"))
|
||||
{
|
||||
++i;
|
||||
if (! parseEquality (infix, i))
|
||||
@@ -487,18 +504,18 @@ bool Eval::parseRegex (
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Equality --> Comparative {( "==" | "=" | "!==" | "!=" ) Comparative}
|
||||
bool Eval::parseEquality (
|
||||
std::vector <std::pair <std::string, Lexer::Type> >& infix,
|
||||
int &i) const
|
||||
std::vector <std::pair <std::string, Lexer::Type>>& infix,
|
||||
unsigned int &i) const
|
||||
{
|
||||
if (i < infix.size () &&
|
||||
parseComparative (infix, i))
|
||||
{
|
||||
while (i < infix.size () &&
|
||||
infix[i].second == Lexer::Type::op &&
|
||||
(infix[i].first == "==" ||
|
||||
infix[i].first == "=" ||
|
||||
infix[i].first == "!==" ||
|
||||
infix[i].first == "!=") &&
|
||||
infix[i].second == Lexer::typeOperator)
|
||||
infix[i].first == "!="))
|
||||
{
|
||||
++i;
|
||||
if (! parseComparative (infix, i))
|
||||
@@ -514,18 +531,18 @@ bool Eval::parseEquality (
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Comparative --> Arithmetic {( "<=" | "<" | ">=" | ">" ) Arithmetic}
|
||||
bool Eval::parseComparative (
|
||||
std::vector <std::pair <std::string, Lexer::Type> >& infix,
|
||||
int &i) const
|
||||
std::vector <std::pair <std::string, Lexer::Type>>& infix,
|
||||
unsigned int &i) const
|
||||
{
|
||||
if (i < infix.size () &&
|
||||
parseArithmetic (infix, i))
|
||||
{
|
||||
while (i < infix.size () &&
|
||||
infix[i].second == Lexer::Type::op &&
|
||||
(infix[i].first == "<=" ||
|
||||
infix[i].first == "<" ||
|
||||
infix[i].first == ">=" ||
|
||||
infix[i].first == ">") &&
|
||||
infix[i].second == Lexer::typeOperator)
|
||||
infix[i].first == ">"))
|
||||
{
|
||||
++i;
|
||||
if (! parseArithmetic (infix, i))
|
||||
@@ -541,16 +558,16 @@ bool Eval::parseComparative (
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Arithmetic --> Geometric {( "+" | "-" ) Geometric}
|
||||
bool Eval::parseArithmetic (
|
||||
std::vector <std::pair <std::string, Lexer::Type> >& infix,
|
||||
int &i) const
|
||||
std::vector <std::pair <std::string, Lexer::Type>>& infix,
|
||||
unsigned int &i) const
|
||||
{
|
||||
if (i < infix.size () &&
|
||||
parseGeometric (infix, i))
|
||||
{
|
||||
while (i < infix.size () &&
|
||||
infix[i].second == Lexer::Type::op &&
|
||||
(infix[i].first == "+" ||
|
||||
infix[i].first == "-") &&
|
||||
infix[i].second == Lexer::typeOperator)
|
||||
infix[i].first == "-"))
|
||||
{
|
||||
++i;
|
||||
if (! parseGeometric (infix, i))
|
||||
@@ -566,17 +583,17 @@ bool Eval::parseArithmetic (
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Geometric --> Tag {( "*" | "/" | "%" ) Tag}
|
||||
bool Eval::parseGeometric (
|
||||
std::vector <std::pair <std::string, Lexer::Type> >& infix,
|
||||
int &i) const
|
||||
std::vector <std::pair <std::string, Lexer::Type>>& infix,
|
||||
unsigned int &i) const
|
||||
{
|
||||
if (i < infix.size () &&
|
||||
parseTag (infix, i))
|
||||
{
|
||||
while (i < infix.size () &&
|
||||
infix[i].second == Lexer::Type::op &&
|
||||
(infix[i].first == "*" ||
|
||||
infix[i].first == "/" ||
|
||||
infix[i].first == "%") &&
|
||||
infix[i].second == Lexer::typeOperator)
|
||||
infix[i].first == "%"))
|
||||
{
|
||||
++i;
|
||||
if (! parseTag (infix, i))
|
||||
@@ -592,16 +609,16 @@ bool Eval::parseGeometric (
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Tag --> Unary {( "_hastag_" | "_notag_" ) Unary}
|
||||
bool Eval::parseTag (
|
||||
std::vector <std::pair <std::string, Lexer::Type> >& infix,
|
||||
int &i) const
|
||||
std::vector <std::pair <std::string, Lexer::Type>>& infix,
|
||||
unsigned int &i) const
|
||||
{
|
||||
if (i < infix.size () &&
|
||||
parseUnary (infix, i))
|
||||
{
|
||||
while (i < infix.size () &&
|
||||
infix[i].second == Lexer::Type::op &&
|
||||
(infix[i].first == "_hastag_" ||
|
||||
infix[i].first == "_notag_") &&
|
||||
infix[i].second == Lexer::typeOperator)
|
||||
infix[i].first == "_notag_"))
|
||||
{
|
||||
++i;
|
||||
if (! parseUnary (infix, i))
|
||||
@@ -617,8 +634,8 @@ bool Eval::parseTag (
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Unary --> [( "-" | "+" | "!" )] Exponent
|
||||
bool Eval::parseUnary (
|
||||
std::vector <std::pair <std::string, Lexer::Type> >& infix,
|
||||
int &i) const
|
||||
std::vector <std::pair <std::string, Lexer::Type>>& infix,
|
||||
unsigned int &i) const
|
||||
{
|
||||
if (i < infix.size ())
|
||||
{
|
||||
@@ -644,15 +661,15 @@ bool Eval::parseUnary (
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Exponent --> Primitive ["^" Primitive]
|
||||
bool Eval::parseExponent (
|
||||
std::vector <std::pair <std::string, Lexer::Type> >& infix,
|
||||
int &i) const
|
||||
std::vector <std::pair <std::string, Lexer::Type>>& infix,
|
||||
unsigned int& i) const
|
||||
{
|
||||
if (i < infix.size () &&
|
||||
parsePrimitive (infix, i))
|
||||
{
|
||||
while (i < infix.size () &&
|
||||
infix[i].first == "^" &&
|
||||
infix[i].second == Lexer::typeOperator)
|
||||
infix[i].second == Lexer::Type::op &&
|
||||
infix[i].first == "^")
|
||||
{
|
||||
++i;
|
||||
if (! parsePrimitive (infix, i))
|
||||
@@ -668,8 +685,8 @@ bool Eval::parseExponent (
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Primitive --> "(" Logical ")" | Variant
|
||||
bool Eval::parsePrimitive (
|
||||
std::vector <std::pair <std::string, Lexer::Type> >& infix,
|
||||
int &i) const
|
||||
std::vector <std::pair <std::string, Lexer::Type>>& infix,
|
||||
unsigned int &i) const
|
||||
{
|
||||
if (i < infix.size ())
|
||||
{
|
||||
@@ -706,7 +723,7 @@ bool Eval::parsePrimitive (
|
||||
++i;
|
||||
return true;
|
||||
}
|
||||
else if (infix[i].second != Lexer::typeOperator)
|
||||
else if (infix[i].second != Lexer::Type::op)
|
||||
{
|
||||
++i;
|
||||
return true;
|
||||
@@ -750,32 +767,32 @@ bool Eval::parsePrimitive (
|
||||
// Exit.
|
||||
//
|
||||
void Eval::infixToPostfix (
|
||||
std::vector <std::pair <std::string, Lexer::Type> >& infix) const
|
||||
std::vector <std::pair <std::string, Lexer::Type>>& infix) const
|
||||
{
|
||||
// Short circuit.
|
||||
if (infix.size () == 1)
|
||||
return;
|
||||
|
||||
// Result.
|
||||
std::vector <std::pair <std::string, Lexer::Type> > postfix;
|
||||
std::vector <std::pair <std::string, Lexer::Type>> postfix;
|
||||
|
||||
// Shunting yard.
|
||||
std::vector <std::pair <std::string, Lexer::Type> > op_stack;
|
||||
std::vector <std::pair <std::string, Lexer::Type>> op_stack;
|
||||
|
||||
// Operator characteristics.
|
||||
char type;
|
||||
int precedence;
|
||||
unsigned int precedence;
|
||||
char associativity;
|
||||
|
||||
std::vector <std::pair <std::string, Lexer::Type> >::iterator token;
|
||||
std::vector <std::pair <std::string, Lexer::Type>>::iterator token;
|
||||
for (token = infix.begin (); token != infix.end (); ++token)
|
||||
{
|
||||
if (token->second == Lexer::typeOperator &&
|
||||
if (token->second == Lexer::Type::op &&
|
||||
token->first == "(")
|
||||
{
|
||||
op_stack.push_back (*token);
|
||||
}
|
||||
else if (token->second == Lexer::typeOperator &&
|
||||
else if (token->second == Lexer::Type::op &&
|
||||
token->first == ")")
|
||||
{
|
||||
while (op_stack.size () &&
|
||||
@@ -790,11 +807,11 @@ void Eval::infixToPostfix (
|
||||
else
|
||||
throw std::string ("Mismatched parentheses in expression");
|
||||
}
|
||||
else if (token->second == Lexer::typeOperator &&
|
||||
else if (token->second == Lexer::Type::op &&
|
||||
identifyOperator (token->first, type, precedence, associativity))
|
||||
{
|
||||
char type2;
|
||||
int precedence2;
|
||||
unsigned int precedence2;
|
||||
char associativity2;
|
||||
while (op_stack.size () > 0 &&
|
||||
identifyOperator (op_stack.back ().first, type2, precedence2, associativity2) &&
|
||||
@@ -830,7 +847,7 @@ void Eval::infixToPostfix (
|
||||
bool Eval::identifyOperator (
|
||||
const std::string& op,
|
||||
char& type,
|
||||
int& precedence,
|
||||
unsigned int& precedence,
|
||||
char& associativity) const
|
||||
{
|
||||
for (unsigned int i = 0; i < NUM_OPERATORS; ++i)
|
||||
@@ -849,22 +866,21 @@ bool Eval::identifyOperator (
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Eval::dump (
|
||||
std::vector <std::pair <std::string, Lexer::Type> >& tokens) const
|
||||
std::vector <std::pair <std::string, Lexer::Type>>& tokens) const
|
||||
{
|
||||
// Set up a color mapping.
|
||||
std::map <Lexer::Type, Color> color_map;
|
||||
color_map[Lexer::typeNone] = Color ("rgb000 on gray6");
|
||||
color_map[Lexer::typeOperator] = Color ("gray14 on gray6");
|
||||
color_map[Lexer::typeNumber] = Color ("rgb530 on gray6");
|
||||
color_map[Lexer::typeHex] = Color ("rgb303 on gray6");
|
||||
color_map[Lexer::typeDecimal] = Color ("rgb530 on gray6");
|
||||
color_map[Lexer::typeString] = Color ("rgb550 on gray6");
|
||||
color_map[Lexer::typeIdentifier] = Color ("rgb035 on gray6");
|
||||
color_map[Lexer::typeDate] = Color ("rgb150 on gray6");
|
||||
color_map[Lexer::typeDuration] = Color ("rgb531 on gray6");
|
||||
color_map[Lexer::Type::op] = Color ("gray14 on gray6");
|
||||
color_map[Lexer::Type::number] = Color ("rgb530 on gray6");
|
||||
color_map[Lexer::Type::hex] = Color ("rgb303 on gray6");
|
||||
color_map[Lexer::Type::string] = Color ("rgb550 on gray6");
|
||||
color_map[Lexer::Type::dom] = Color ("rgb045 on gray6");
|
||||
color_map[Lexer::Type::identifier] = Color ("rgb035 on gray6");
|
||||
color_map[Lexer::Type::date] = Color ("rgb150 on gray6");
|
||||
color_map[Lexer::Type::duration] = Color ("rgb531 on gray6");
|
||||
|
||||
std::string output;
|
||||
std::vector <std::pair <std::string, Lexer::Type> >::const_iterator i;
|
||||
std::vector <std::pair <std::string, Lexer::Type>>::const_iterator i;
|
||||
for (i = tokens.begin (); i != tokens.end (); ++i)
|
||||
{
|
||||
if (i != tokens.begin ())
|
||||
@@ -874,7 +890,7 @@ std::string Eval::dump (
|
||||
if (color_map[i->second].nontrivial ())
|
||||
c = color_map[i->second];
|
||||
else
|
||||
c = color_map[Lexer::typeNone];
|
||||
c = Color ("rgb000 on gray6");
|
||||
|
||||
output += c.colorize (i->first);
|
||||
}
|
||||
|
||||
32
src/Eval.h
32
src/Eval.h
@@ -53,28 +53,28 @@ public:
|
||||
static void getBinaryOperators (std::vector <std::string>&);
|
||||
|
||||
private:
|
||||
void evaluatePostfixStack (const std::vector <std::pair <std::string, Lexer::Type> >&, Variant&) const;
|
||||
void infixToPostfix (std::vector <std::pair <std::string, Lexer::Type> >&) const;
|
||||
void infixParse (std::vector <std::pair <std::string, Lexer::Type> >&) const;
|
||||
bool parseLogical (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
|
||||
bool parseRegex (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
|
||||
bool parseEquality (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
|
||||
bool parseComparative (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
|
||||
bool parseArithmetic (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
|
||||
bool parseGeometric (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
|
||||
bool parseTag (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
|
||||
bool parseUnary (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
|
||||
bool parseExponent (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
|
||||
bool parsePrimitive (std::vector <std::pair <std::string, Lexer::Type> >&, int &) const;
|
||||
bool identifyOperator (const std::string&, char&, int&, char&) const;
|
||||
void evaluatePostfixStack (const std::vector <std::pair <std::string, Lexer::Type>>&, Variant&) const;
|
||||
void infixToPostfix (std::vector <std::pair <std::string, Lexer::Type>>&) const;
|
||||
void infixParse (std::vector <std::pair <std::string, Lexer::Type>>&) const;
|
||||
bool parseLogical (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
|
||||
bool parseRegex (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
|
||||
bool parseEquality (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
|
||||
bool parseComparative (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
|
||||
bool parseArithmetic (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
|
||||
bool parseGeometric (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
|
||||
bool parseTag (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
|
||||
bool parseUnary (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
|
||||
bool parseExponent (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
|
||||
bool parsePrimitive (std::vector <std::pair <std::string, Lexer::Type>>&, unsigned int &) const;
|
||||
bool identifyOperator (const std::string&, char&, unsigned int&, char&) const;
|
||||
|
||||
std::string dump (std::vector <std::pair <std::string, Lexer::Type> >&) const;
|
||||
std::string dump (std::vector <std::pair <std::string, Lexer::Type>>&) const;
|
||||
|
||||
private:
|
||||
std::vector <bool (*)(const std::string&, Variant&)> _sources;
|
||||
bool _ambiguity;
|
||||
bool _debug;
|
||||
std::vector <std::pair <std::string, Lexer::Type> > _compiled;
|
||||
std::vector <std::pair <std::string, Lexer::Type>> _compiled;
|
||||
};
|
||||
|
||||
|
||||
|
||||
48
src/File.cpp
48
src/File.cpp
@@ -28,14 +28,10 @@
|
||||
#include <fstream>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef SOLARIS
|
||||
#include <fcntl.h> // for flock() replacement
|
||||
#include <string.h> // for memset()
|
||||
#else
|
||||
#include <sys/file.h>
|
||||
#endif
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <File.h>
|
||||
#include <text.h>
|
||||
#include <util.h>
|
||||
@@ -151,6 +147,9 @@ void File::close ()
|
||||
{
|
||||
if (_fh)
|
||||
{
|
||||
if (_locked)
|
||||
unlock ();
|
||||
|
||||
fclose (_fh);
|
||||
_fh = NULL;
|
||||
_h = -1;
|
||||
@@ -161,38 +160,31 @@ void File::close ()
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool File::lock ()
|
||||
{
|
||||
_locked = false;
|
||||
if (_fh && _h != -1)
|
||||
{
|
||||
// Try three times before failing.
|
||||
int retry = 0;
|
||||
while (flock (_h, LOCK_NB | LOCK_EX) && ++retry <= 3)
|
||||
;
|
||||
|
||||
if (retry <= 3)
|
||||
{
|
||||
// l_type l_whence l_start l_len l_pid
|
||||
struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0 };
|
||||
fl.l_pid = getpid ();
|
||||
if (fcntl (_h, F_SETLKW, &fl) == 0)
|
||||
_locked = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
_locked = false;
|
||||
return false;
|
||||
return _locked;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool File::waitForLock ()
|
||||
void File::unlock ()
|
||||
{
|
||||
if (_locked)
|
||||
return true;
|
||||
{
|
||||
// l_type l_whence l_start l_len l_pid
|
||||
struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0 };
|
||||
fl.l_pid = getpid ();
|
||||
|
||||
if (_fh && _h != -1)
|
||||
if (flock (_h, LOCK_EX) == 0)
|
||||
{
|
||||
_locked = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
fcntl (_h, F_SETLK, &fl);
|
||||
_locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
void close ();
|
||||
|
||||
bool lock ();
|
||||
bool waitForLock ();
|
||||
void unlock ();
|
||||
|
||||
void read (std::string&);
|
||||
void read (std::vector <std::string>&);
|
||||
|
||||
@@ -67,7 +67,7 @@ Filter::~Filter ()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 ();
|
||||
_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)
|
||||
context.debug (context.cli.dump ("Filter::subset"));
|
||||
|
||||
std::string filterExpr = context.cli.getFilter ();
|
||||
std::string filterExpr = context.cli.getFilter (applyContext);
|
||||
if (filterExpr.length ())
|
||||
{
|
||||
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.
|
||||
void Filter::subset (std::vector <Task>& output)
|
||||
void Filter::subset (std::vector <Task>& output, bool applyContext /* = true */)
|
||||
{
|
||||
context.timer_filter.start ();
|
||||
|
||||
@@ -119,7 +119,7 @@ void Filter::subset (std::vector <Task>& output)
|
||||
context.debug (context.cli.dump ("Filter::subset"));
|
||||
|
||||
bool shortcut = false;
|
||||
std::string filterExpr = context.cli.getFilter ();
|
||||
std::string filterExpr = context.cli.getFilter (applyContext);
|
||||
if (filterExpr.length ())
|
||||
{
|
||||
context.timer_filter.stop ();
|
||||
|
||||
@@ -40,8 +40,8 @@ public:
|
||||
Filter ();
|
||||
~Filter ();
|
||||
|
||||
void subset (const std::vector <Task>&, std::vector <Task>&);
|
||||
void subset (std::vector <Task>&);
|
||||
void subset (const std::vector <Task>&, std::vector <Task>&, bool applyContext = true);
|
||||
void subset (std::vector <Task>&, bool applyContext = true);
|
||||
bool pendingOnly ();
|
||||
void safety ();
|
||||
|
||||
|
||||
436
src/Hooks.cpp
436
src/Hooks.cpp
@@ -38,8 +38,10 @@
|
||||
#include <Context.h>
|
||||
#include <JSON.h>
|
||||
#include <Hooks.h>
|
||||
#include <Timer.h>
|
||||
#include <text.h>
|
||||
#include <util.h>
|
||||
#include <i18n.h>
|
||||
|
||||
extern Context context;
|
||||
|
||||
@@ -73,7 +75,17 @@ void Hooks::initialize ()
|
||||
{
|
||||
std::vector <std::string>::iterator i;
|
||||
for (i = _scripts.begin (); i != _scripts.end (); ++i)
|
||||
context.debug ("Found hook script " + *i);
|
||||
{
|
||||
Path p (*i);
|
||||
std::string name = p.name ();
|
||||
if (name.substr (0, 6) == "on-add" ||
|
||||
name.substr (0, 9) == "on-modify" ||
|
||||
name.substr (0, 9) == "on-launch" ||
|
||||
name.substr (0, 7) == "on-exit")
|
||||
context.debug ("Found hook script " + *i);
|
||||
else
|
||||
context.debug ("Found misnamed hook script " + *i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_debug >= 1)
|
||||
@@ -98,8 +110,7 @@ bool Hooks::enable (bool value)
|
||||
// - none
|
||||
//
|
||||
// Output:
|
||||
// - all emitted JSON lines are added/modified as tasks, if the exit code is
|
||||
// zero, otherwise ignored.
|
||||
// - JSON not allowed.
|
||||
// - all emitted non-JSON lines are considered feedback or error messages
|
||||
// depending on the status code.
|
||||
//
|
||||
@@ -120,29 +131,28 @@ void Hooks::onLaunch ()
|
||||
std::vector <std::string> output;
|
||||
int status = callHookScript (*script, input, output);
|
||||
|
||||
std::vector <std::string>::iterator line;
|
||||
for (line = output.begin (); line != output.end (); ++line)
|
||||
{
|
||||
if (isJSON (*line))
|
||||
{
|
||||
if (status == 0)
|
||||
{
|
||||
// Only 'add' is possible.
|
||||
Task newTask (*line);
|
||||
context.tdb2.add (newTask);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (status == 0)
|
||||
context.header (*line);
|
||||
else
|
||||
context.error (*line);
|
||||
}
|
||||
}
|
||||
std::vector <std::string> outputJSON;
|
||||
std::vector <std::string> outputFeedback;
|
||||
separateOutput (output, outputJSON, outputFeedback);
|
||||
|
||||
assertNTasks (outputJSON, 0);
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
std::vector <std::string>::iterator message;
|
||||
for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message)
|
||||
context.footnote (*message);
|
||||
}
|
||||
else
|
||||
{
|
||||
assertFeedback (outputFeedback);
|
||||
|
||||
std::vector <std::string>::iterator message;
|
||||
for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message)
|
||||
context.error (*message);
|
||||
|
||||
if (status)
|
||||
throw 0; // This is how hooks silently terminate processing.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +167,7 @@ void Hooks::onLaunch ()
|
||||
// - read-only line of JSON for each task added/modified
|
||||
//
|
||||
// Output:
|
||||
// - any emitted JSON is ignored
|
||||
// - all emitted JSON is ignored
|
||||
// - all emitted non-JSON lines are considered feedback or error messages
|
||||
// depending on the status code.
|
||||
//
|
||||
@@ -188,24 +198,28 @@ void Hooks::onExit ()
|
||||
std::vector <std::string> output;
|
||||
int status = callHookScript (*script, input, output);
|
||||
|
||||
std::vector <std::string>::iterator line;
|
||||
for (line = output.begin (); line != output.end (); ++line)
|
||||
{
|
||||
if (isJSON (*line))
|
||||
{
|
||||
context.error ("JSON output ignored: {1}");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (status == 0)
|
||||
context.footnote (*line);
|
||||
else
|
||||
context.error (*line);
|
||||
}
|
||||
}
|
||||
std::vector <std::string> outputJSON;
|
||||
std::vector <std::string> outputFeedback;
|
||||
separateOutput (output, outputJSON, outputFeedback);
|
||||
|
||||
assertNTasks (outputJSON, 0);
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
std::vector <std::string>::iterator message;
|
||||
for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message)
|
||||
context.footnote (*message);
|
||||
}
|
||||
else
|
||||
{
|
||||
assertFeedback (outputFeedback);
|
||||
|
||||
std::vector <std::string>::iterator message;
|
||||
for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message)
|
||||
context.error (*message);
|
||||
|
||||
if (status)
|
||||
throw 0; // This is how hooks silently terminate processing.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,14 +233,14 @@ void Hooks::onExit ()
|
||||
// - line of JSON for the task added
|
||||
//
|
||||
// Output:
|
||||
// - all emitted JSON lines are added/modified as tasks, if the exit code is
|
||||
// zero, otherwise ignored.
|
||||
// - emitted JSON for the input task is added, if the exit code is zero,
|
||||
// otherwise ignored.
|
||||
// - all emitted non-JSON lines are considered feedback or error messages
|
||||
// depending on the status code.
|
||||
//
|
||||
void Hooks::onAdd (std::vector <Task>& tasks)
|
||||
void Hooks::onAdd (Task& task)
|
||||
{
|
||||
if (! _enabled || tasks.size () < 1)
|
||||
if (! _enabled)
|
||||
return;
|
||||
|
||||
context.timer_hooks.start ();
|
||||
@@ -234,9 +248,9 @@ void Hooks::onAdd (std::vector <Task>& tasks)
|
||||
std::vector <std::string> matchingScripts = scripts ("on-add");
|
||||
if (matchingScripts.size ())
|
||||
{
|
||||
// Convert vector of tasks to a vector of strings.
|
||||
// Convert task to a vector of strings.
|
||||
std::vector <std::string> input;
|
||||
input.push_back (tasks[0].composeJSON ());
|
||||
input.push_back (task.composeJSON ());
|
||||
|
||||
// Call the hook scripts.
|
||||
std::vector <std::string>::iterator script;
|
||||
@@ -245,33 +259,37 @@ void Hooks::onAdd (std::vector <Task>& tasks)
|
||||
std::vector <std::string> output;
|
||||
int status = callHookScript (*script, input, output);
|
||||
|
||||
input.clear ();
|
||||
std::vector <std::string>::iterator line;
|
||||
for (line = output.begin (); line != output.end (); ++line)
|
||||
{
|
||||
if (isJSON (*line))
|
||||
{
|
||||
if (status == 0)
|
||||
input.push_back (*line);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (status == 0)
|
||||
context.footnote (*line);
|
||||
else
|
||||
context.error (*line);
|
||||
}
|
||||
}
|
||||
std::vector <std::string> outputJSON;
|
||||
std::vector <std::string> outputFeedback;
|
||||
separateOutput (output, outputJSON, outputFeedback);
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
assertNTasks (outputJSON, 1);
|
||||
assertValidJSON (outputJSON);
|
||||
assertSameTask (outputJSON, task);
|
||||
|
||||
// Propagate forward to the next script.
|
||||
input[0] = outputJSON[0];
|
||||
|
||||
std::vector <std::string>::iterator message;
|
||||
for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message)
|
||||
context.footnote (*message);
|
||||
}
|
||||
else
|
||||
{
|
||||
assertFeedback (outputFeedback);
|
||||
|
||||
std::vector <std::string>::iterator message;
|
||||
for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message)
|
||||
context.error (*message);
|
||||
|
||||
if (status)
|
||||
throw 0; // This is how hooks silently terminate processing.
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer the modified task lines back to the original task list.
|
||||
tasks.clear ();
|
||||
std::vector <std::string>::iterator i;
|
||||
for (i = input.begin (); i != input.end (); ++i)
|
||||
tasks.push_back (Task (*i));
|
||||
// Transfer the modified task back to the original task.
|
||||
task = Task (input[0]);
|
||||
}
|
||||
|
||||
context.timer_hooks.stop ();
|
||||
@@ -285,14 +303,14 @@ void Hooks::onAdd (std::vector <Task>& tasks)
|
||||
// - line of JSON for the modified task, the diff being the modification
|
||||
//
|
||||
// Output:
|
||||
// - all emitted JSON lines are added/modified as tasks, if the exit code is
|
||||
// zero, otherwise ignored.
|
||||
// - emitted JSON for the input task is saved, if the exit code is zero,
|
||||
// otherwise ignored.
|
||||
// - all emitted non-JSON lines are considered feedback or error messages
|
||||
// depending on the status code.
|
||||
//
|
||||
void Hooks::onModify (const Task& before, std::vector <Task>& tasks)
|
||||
void Hooks::onModify (const Task& before, Task& after)
|
||||
{
|
||||
if (! _enabled || tasks.size () < 1)
|
||||
if (! _enabled)
|
||||
return;
|
||||
|
||||
context.timer_hooks.start ();
|
||||
@@ -300,61 +318,48 @@ void Hooks::onModify (const Task& before, std::vector <Task>& tasks)
|
||||
std::vector <std::string> matchingScripts = scripts ("on-modify");
|
||||
if (matchingScripts.size ())
|
||||
{
|
||||
// Prepare invariants.
|
||||
std::string beforeJSON = before.composeJSON ();
|
||||
std::string uuidPattern = "\"uuid\":\"" + before.get ("uuid") + "\"";
|
||||
|
||||
// Convert vector of tasks to a vector of strings.
|
||||
std::vector <std::string> input;
|
||||
input.push_back (beforeJSON); // [0] original, never changes
|
||||
input.push_back (tasks[0].composeJSON ()); // [1] original'
|
||||
input.push_back (before.composeJSON ()); // [line 0] original, never changes
|
||||
input.push_back (after.composeJSON ()); // [line 1] modified
|
||||
|
||||
// Call the hook scripts.
|
||||
std::vector <std::string>::iterator script;
|
||||
for (script = matchingScripts.begin (); script != matchingScripts.end (); ++script)
|
||||
{
|
||||
std::vector <std::string> firstTwoOnly;
|
||||
firstTwoOnly.push_back (input[0]);
|
||||
firstTwoOnly.push_back (input[1]);
|
||||
|
||||
std::vector <std::string> output;
|
||||
int status = callHookScript (*script, firstTwoOnly, output);
|
||||
int status = callHookScript (*script, input, output);
|
||||
|
||||
// Start from scratch.
|
||||
input[1] = ""; // [1] placeholder for original'
|
||||
std::vector <std::string> outputJSON;
|
||||
std::vector <std::string> outputFeedback;
|
||||
separateOutput (output, outputJSON, outputFeedback);
|
||||
|
||||
std::vector <std::string>::iterator line;
|
||||
for (line = output.begin (); line != output.end (); ++line)
|
||||
if (status == 0)
|
||||
{
|
||||
if (isJSON (*line))
|
||||
{
|
||||
if (status == 0)
|
||||
{
|
||||
if (line->find (uuidPattern) != std::string::npos)
|
||||
input[1] = *line; // [1] original'
|
||||
else
|
||||
input.push_back (*line); // [n > 1] extras
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (status == 0)
|
||||
context.footnote (*line);
|
||||
else
|
||||
context.error (*line);
|
||||
}
|
||||
}
|
||||
assertNTasks (outputJSON, 1);
|
||||
assertValidJSON (outputJSON);
|
||||
assertSameTask (outputJSON, before);
|
||||
|
||||
// Propagate accepted changes forward to the next script.
|
||||
input[1] = outputJSON[0];
|
||||
|
||||
std::vector <std::string>::iterator message;
|
||||
for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message)
|
||||
context.footnote (*message);
|
||||
}
|
||||
else
|
||||
{
|
||||
assertFeedback (outputFeedback);
|
||||
|
||||
std::vector <std::string>::iterator message;
|
||||
for (message = outputFeedback.begin (); message != outputFeedback.end (); ++message)
|
||||
context.error (*message);
|
||||
|
||||
if (status)
|
||||
throw 0; // This is how hooks silently terminate processing.
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer the modified task lines back to the original task list.
|
||||
tasks.clear ();
|
||||
std::vector <std::string>::iterator i;
|
||||
for (i = input.begin (); i != input.end (); ++i)
|
||||
if (i != input.begin ())
|
||||
tasks.push_back (Task (*i));
|
||||
after = Task (input[1]);
|
||||
}
|
||||
|
||||
context.timer_hooks.stop ();
|
||||
@@ -384,65 +389,162 @@ std::vector <std::string> Hooks::scripts (const std::string& event)
|
||||
return matching;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Hooks::separateOutput (
|
||||
const std::vector <std::string>& output,
|
||||
std::vector <std::string>& json,
|
||||
std::vector <std::string>& feedback) const
|
||||
{
|
||||
std::vector <std::string>::const_iterator i;
|
||||
for (i = output.begin (); i != output.end (); ++i)
|
||||
{
|
||||
if (isJSON (*i))
|
||||
json.push_back (*i);
|
||||
else
|
||||
feedback.push_back (*i);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Hooks::isJSON (const std::string& input) const
|
||||
{
|
||||
// Does it even look like JSON? {...}
|
||||
if (input.length () > 2 &&
|
||||
input[0] == '{' &&
|
||||
input[input.length () - 1] == '}')
|
||||
return input.length () > 2 &&
|
||||
input[0] == '{' &&
|
||||
input[input.length () - 1] == '}';
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Hooks::assertValidJSON (const std::vector <std::string>& input) const
|
||||
{
|
||||
std::vector <std::string>::const_iterator i;
|
||||
for (i = input.begin (); i != input.end (); i++)
|
||||
{
|
||||
if (i->length () < 3 ||
|
||||
(*i)[0] != '{' ||
|
||||
(*i)[i->length () - 1] != '}')
|
||||
{
|
||||
context.error (STRING_HOOK_ERROR_OBJECT);
|
||||
throw 0;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// The absolute minimum a task needs is:
|
||||
bool foundDescription = false;
|
||||
|
||||
// Parse the whole thing.
|
||||
json::value* root = json::parse (input);
|
||||
if (root->type () == json::j_object)
|
||||
json::value* root = json::parse (*i);
|
||||
if (root->type () != json::j_object)
|
||||
{
|
||||
json::object* root_obj = (json::object*)root;
|
||||
|
||||
// For each object element...
|
||||
json_object_iter i;
|
||||
for (i = root_obj->_data.begin ();
|
||||
i != root_obj->_data.end ();
|
||||
++i)
|
||||
{
|
||||
// If the attribute is a recognized column.
|
||||
std::string type = Task::attributes[i->first];
|
||||
if (type == "string" && i->first == "description")
|
||||
foundDescription = true;
|
||||
}
|
||||
context.error (STRING_HOOK_ERROR_OBJECT);
|
||||
throw 0;
|
||||
}
|
||||
else
|
||||
throw std::string ("Object expected.");
|
||||
|
||||
// It's JSON, but is it a task?
|
||||
if (! foundDescription)
|
||||
throw std::string ("Missing 'description' attribute, of type 'string'.");
|
||||
if (((json::object*)root)->_data.find ("description") == ((json::object*)root)->_data.end ())
|
||||
{
|
||||
context.error (STRING_HOOK_ERROR_NODESC);
|
||||
throw 0;
|
||||
}
|
||||
|
||||
// Yep, looks like a JSON task.
|
||||
return true;
|
||||
if (((json::object*)root)->_data.find ("uuid") == ((json::object*)root)->_data.end ())
|
||||
{
|
||||
context.error (STRING_HOOK_ERROR_NOUUID);
|
||||
throw 0;
|
||||
}
|
||||
}
|
||||
|
||||
catch (const std::string& e)
|
||||
{
|
||||
if (_debug >= 1)
|
||||
context.error ("Hook output looks like JSON, but is not a valid task.");
|
||||
|
||||
if (_debug >= 2)
|
||||
context.error ("JSON " + e);
|
||||
context.error (format (STRING_HOOK_ERROR_SYNTAX, *i));
|
||||
if (_debug)
|
||||
context.error (STRING_HOOK_ERROR_JSON + e);
|
||||
throw 0;
|
||||
}
|
||||
|
||||
catch (...)
|
||||
{
|
||||
if (_debug >= 1)
|
||||
context.error ("Hook output looks like JSON, but fails to parse.");
|
||||
context.error (STRING_HOOK_ERROR_NOPARSE + *i);
|
||||
throw 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Hooks::assertNTasks (const std::vector <std::string>& input, unsigned int n) const
|
||||
{
|
||||
if (input.size () != n)
|
||||
{
|
||||
context.error (format (STRING_HOOK_ERROR_BAD_NUM, n, (int) input.size ()));
|
||||
throw 0;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Hooks::assertSameTask (const std::vector <std::string>& input, const Task& task) const
|
||||
{
|
||||
std::string uuid = task.get ("uuid");
|
||||
|
||||
std::vector <std::string>::const_iterator i;
|
||||
for (i = input.begin (); i != input.end (); i++)
|
||||
{
|
||||
json::object* root_obj = (json::object*)json::parse (*i);
|
||||
|
||||
// If there is no UUID at all.
|
||||
json_object_iter u = root_obj->_data.find ("uuid");
|
||||
if (u == root_obj->_data.end () ||
|
||||
u->second->type () != json::j_string)
|
||||
{
|
||||
context.error (format (STRING_HOOK_ERROR_SAME1, uuid));
|
||||
throw 0;
|
||||
}
|
||||
|
||||
json::string* up = (json::string*) u->second;
|
||||
std::string json_uuid = json::decode (unquoteText (up->dump ()));
|
||||
if (json_uuid != uuid)
|
||||
{
|
||||
context.error (format (STRING_HOOK_ERROR_SAME2, uuid, json_uuid));
|
||||
throw 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Hooks::assertFeedback (const std::vector <std::string>& input) const
|
||||
{
|
||||
bool foundSomething = false;
|
||||
std::vector <std::string>::const_iterator i;
|
||||
for (i = input.begin (); i != input.end (); ++i)
|
||||
if (nontrivial (*i))
|
||||
foundSomething = true;
|
||||
|
||||
if (! foundSomething)
|
||||
{
|
||||
context.error (STRING_HOOK_ERROR_NOFEEDBACK);
|
||||
throw 0;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::vector <std::string>& Hooks::buildHookScriptArgs (std::vector <std::string>& args)
|
||||
{
|
||||
Variant v;
|
||||
|
||||
// Hooks API version.
|
||||
args.push_back ("api:2");
|
||||
|
||||
// Command line Taskwarrior was called with.
|
||||
context.dom.get ("context.args", v);
|
||||
args.push_back ("args:" + std::string (v));
|
||||
|
||||
// Command to be executed.
|
||||
args.push_back ("command:" + context.cli.getCommand ());
|
||||
|
||||
// rc file used after applying all overrides.
|
||||
args.push_back ("rc:" + context.rc_file._data);
|
||||
|
||||
// Directory containing *.data files.
|
||||
args.push_back ("data:" + context.data_dir._data);
|
||||
|
||||
// Taskwarrior version, same as returned by "task --version"
|
||||
args.push_back ("version:" + std::string(VERSION));
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -452,11 +554,11 @@ int Hooks::callHookScript (
|
||||
std::vector <std::string>& output)
|
||||
{
|
||||
if (_debug >= 1)
|
||||
context.debug ("Hooks: Calling " + script);
|
||||
context.debug ("Hook: Calling " + script);
|
||||
|
||||
if (_debug >= 2)
|
||||
{
|
||||
context.debug ("Hooks: input");
|
||||
context.debug ("Hook: input");
|
||||
std::vector <std::string>::const_iterator i;
|
||||
for (i = input.begin (); i != input.end (); ++i)
|
||||
context.debug (" " + *i);
|
||||
@@ -467,21 +569,39 @@ int Hooks::callHookScript (
|
||||
for (i = input.begin (); i != input.end (); ++i)
|
||||
inputStr += *i + "\n";
|
||||
|
||||
std::string outputStr;
|
||||
std::vector <std::string> args;
|
||||
int status = execute (script, args, inputStr, outputStr);
|
||||
buildHookScriptArgs (args);
|
||||
if (_debug >= 2)
|
||||
{
|
||||
context.debug ("Hooks: args");
|
||||
for (auto arg: args)
|
||||
context.debug (" " + arg);
|
||||
}
|
||||
|
||||
// Measure time for each hook if running in debug
|
||||
int status;
|
||||
std::string outputStr;
|
||||
if (_debug >= 2)
|
||||
{
|
||||
Timer timer_per_hook("Hooks::execute (" + script + ")");
|
||||
timer_per_hook.start();
|
||||
|
||||
status = execute (script, args, inputStr, outputStr);
|
||||
}
|
||||
else
|
||||
status = execute (script, args, inputStr, outputStr);
|
||||
|
||||
split (output, outputStr, '\n');
|
||||
|
||||
if (_debug >= 2)
|
||||
{
|
||||
context.debug ("Hooks: output");
|
||||
context.debug ("Hook: output");
|
||||
std::vector <std::string>::iterator i;
|
||||
for (i = output.begin (); i != output.end (); ++i)
|
||||
if (*i != "")
|
||||
context.debug (" " + *i);
|
||||
|
||||
context.debug (format ("Hooks: Completed with status {1}", status));
|
||||
context.debug (format ("Hook: Completed with status {1}", status));
|
||||
context.debug (" "); // Blank line
|
||||
}
|
||||
|
||||
|
||||
10
src/Hooks.h
10
src/Hooks.h
@@ -44,14 +44,20 @@ public:
|
||||
|
||||
void onLaunch ();
|
||||
void onExit ();
|
||||
void onAdd (std::vector <Task>&);
|
||||
void onModify (const Task&, std::vector <Task>&);
|
||||
void onAdd (Task&);
|
||||
void onModify (const Task&, Task&);
|
||||
|
||||
std::vector <std::string> list ();
|
||||
|
||||
private:
|
||||
std::vector <std::string> scripts (const std::string&);
|
||||
void separateOutput (const std::vector <std::string>&, std::vector <std::string>&, std::vector <std::string>&) const;
|
||||
bool isJSON (const std::string&) const;
|
||||
void assertValidJSON (const std::vector <std::string>&) const;
|
||||
void assertNTasks (const std::vector <std::string>&, unsigned int) const;
|
||||
void assertSameTask (const std::vector <std::string>&, const Task&) const;
|
||||
void assertFeedback (const std::vector <std::string>&) const;
|
||||
std::vector <std::string>& buildHookScriptArgs (std::vector <std::string>&);
|
||||
int callHookScript (const std::string&, const std::vector <std::string>&, std::vector <std::string>&);
|
||||
|
||||
private:
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmake.h>
|
||||
#include <Lexer.h>
|
||||
#include <ISO8601.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -196,7 +197,7 @@ bool ISO8601d::parse_date_time_ext (Nibbler& n)
|
||||
else if (parse_off_ext (n))
|
||||
;
|
||||
|
||||
if (! isdigit (n.next ()))
|
||||
if (! Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -228,16 +229,16 @@ bool ISO8601d::parse_date_time (Nibbler& n)
|
||||
if (n.skip ('Z'))
|
||||
{
|
||||
_utc = true;
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
else if (parse_off (n))
|
||||
{
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -277,13 +278,13 @@ bool ISO8601d::parse_date_ext (Nibbler& n)
|
||||
}
|
||||
|
||||
_year = year;
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
else if (n.getDigit3 (_julian))
|
||||
{
|
||||
_year = year;
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
else if (n.getDigit2 (month) &&
|
||||
@@ -293,7 +294,7 @@ bool ISO8601d::parse_date_ext (Nibbler& n)
|
||||
_year = year;
|
||||
_month = month;
|
||||
_day = day;
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -327,7 +328,7 @@ bool ISO8601d::parse_date (Nibbler& n, bool ambiguous)
|
||||
_weekday = day;
|
||||
|
||||
_year = year;
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -336,7 +337,7 @@ bool ISO8601d::parse_date (Nibbler& n, bool ambiguous)
|
||||
if (n.getDigit2 (_month))
|
||||
{
|
||||
_year = year;
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -345,13 +346,13 @@ bool ISO8601d::parse_date (Nibbler& n, bool ambiguous)
|
||||
_year = year;
|
||||
_month = month / 100;
|
||||
_day = month % 100;
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
else if (ambiguous && n.getDigit3 (_julian))
|
||||
{
|
||||
_year = year;
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -382,7 +383,7 @@ bool ISO8601d::parse_off_ext (Nibbler& n)
|
||||
offset += mm * 60;
|
||||
|
||||
_offset = (sign == "-") ? -offset : offset;
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -412,7 +413,7 @@ bool ISO8601d::parse_off (Nibbler& n)
|
||||
offset += mm * 60;
|
||||
|
||||
_offset = (sign == "-") ? -offset : offset;
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -453,7 +454,7 @@ bool ISO8601d::parse_time_ext (Nibbler& n)
|
||||
if (_ambiguity)
|
||||
{
|
||||
_seconds = seconds;
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -487,7 +488,7 @@ bool ISO8601d::parse_time (Nibbler& n, bool ambiguous)
|
||||
}
|
||||
|
||||
_seconds = seconds;
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -504,7 +505,7 @@ bool ISO8601d::parse_time_utc_ext (Nibbler& n)
|
||||
n.skip ('Z'))
|
||||
{
|
||||
_utc = true;
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -521,7 +522,7 @@ bool ISO8601d::parse_time_utc (Nibbler& n)
|
||||
n.skip ('Z'))
|
||||
{
|
||||
_utc = true;
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -537,7 +538,7 @@ bool ISO8601d::parse_time_off_ext (Nibbler& n)
|
||||
if (parse_time_ext (n) &&
|
||||
parse_off_ext (n))
|
||||
{
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -553,7 +554,7 @@ bool ISO8601d::parse_time_off (Nibbler& n)
|
||||
if (parse_time (n, true) &&
|
||||
parse_off (n))
|
||||
{
|
||||
if (!isdigit (n.next ()))
|
||||
if (!Lexer::isDigit (n.next ()))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -702,7 +703,7 @@ void ISO8601d::resolve ()
|
||||
t.tm_min = (seconds % 3600) / 60;
|
||||
t.tm_sec = seconds % 60;
|
||||
|
||||
_value = utc ? timegm (&t) : timelocal (&t);
|
||||
_value = utc ? timegm (&t) : mktime (&t);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
1655
src/Lexer.cpp
1655
src/Lexer.cpp
File diff suppressed because it is too large
Load Diff
135
src/Lexer.h
135
src/Lexer.h
@@ -27,91 +27,86 @@
|
||||
#ifndef INCLUDED_LEXER
|
||||
#define INCLUDED_LEXER
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
|
||||
// Lexer: A UTF8 lexical analyzer for every construct used on the Taskwarrior
|
||||
// command line, with additional recognized types for disambiguation.
|
||||
|
||||
class Lexer
|
||||
{
|
||||
public:
|
||||
// These are overridable.
|
||||
static std::string dateFormat;
|
||||
static bool isoEnabled;
|
||||
|
||||
enum Type
|
||||
{
|
||||
typeNone = 0,
|
||||
typeString,
|
||||
typeIdentifier,
|
||||
typeIdentifierEscape, // Intermediate
|
||||
typeEscape, // Intermediate
|
||||
typeEscapeHex, // Intermediate
|
||||
typeEscapeUnicode, // Intermediate
|
||||
typeNumber,
|
||||
typeDecimal,
|
||||
typeExponentIndicator, // Intermediate
|
||||
typeExponent, // Intermediate
|
||||
typeHex,
|
||||
typeOperator,
|
||||
typeDate,
|
||||
typeDuration,
|
||||
typeTag,
|
||||
/*
|
||||
Recognizing more types means that Lexer::*_split and Lexer::token approach
|
||||
the ideal form, whereby the command line becomes just one string that is
|
||||
lexed into tokens. Those tokens are then simply dissected by type..
|
||||
|
||||
typeUUID,
|
||||
typePattern,
|
||||
typeSubstitution,
|
||||
typeNameValue,
|
||||
*/
|
||||
};
|
||||
enum class Type { uuid, number, hex,
|
||||
string,
|
||||
list, url, pair, separator,
|
||||
tag,
|
||||
path,
|
||||
substitution, pattern,
|
||||
op,
|
||||
dom, identifier, word,
|
||||
date, duration };
|
||||
|
||||
Lexer (const std::string&);
|
||||
virtual ~Lexer ();
|
||||
Lexer (const Lexer&); // Not implemented.
|
||||
Lexer& operator= (const Lexer&); // Not implemented.
|
||||
bool operator== (const Lexer&); // Not implemented.
|
||||
bool token (std::string&, Type&);
|
||||
bool word (std::string&, Type&);
|
||||
~Lexer ();
|
||||
void ambiguity (bool);
|
||||
bool token (std::string&, Lexer::Type&);
|
||||
static std::vector <std::pair <std::string, Lexer::Type>> tokens (const std::string&);
|
||||
static std::vector <std::string> split (const std::string&);
|
||||
static std::string typeToString (Lexer::Type);
|
||||
static bool isAllDigits (const std::string&);
|
||||
static bool isOneWord (const std::string&);
|
||||
|
||||
static const std::string type_name (const Type&);
|
||||
static bool is_ws (int);
|
||||
static bool is_ident_start (int);
|
||||
static bool is_ident (int);
|
||||
static bool is_single_op (int);
|
||||
static bool is_dec_digit (int);
|
||||
static bool boundary (int, int);
|
||||
static void word_split (std::vector <std::string>&, const std::string&);
|
||||
static void token_split (std::vector <std::string>&, const std::string&);
|
||||
static void token_split (std::vector <std::pair <std::string, Lexer::Type> >&, const std::string&);
|
||||
// Static helpers.
|
||||
static const std::string typeName (const Lexer::Type&);
|
||||
static bool isWhitespace (int);
|
||||
static bool isAlpha (int);
|
||||
static bool isDigit (int);
|
||||
static bool isHexDigit (int);
|
||||
static bool isIdentifierStart (int);
|
||||
static bool isIdentifierNext (int);
|
||||
static bool isSingleCharOperator (int);
|
||||
static bool isDoubleCharOperator (int, int, int);
|
||||
static bool isTripleCharOperator (int, int, int, int);
|
||||
static bool isBoundary (int, int);
|
||||
static bool isPunctuation (int);
|
||||
static void dequote (std::string&);
|
||||
|
||||
private:
|
||||
bool is_date (std::string&);
|
||||
bool is_duration (std::string&);
|
||||
bool is_punct (int) const;
|
||||
bool is_num (int) const;
|
||||
bool is_triple_op (int, int, int) const;
|
||||
bool is_double_op (int, int, int) const;
|
||||
bool is_hex_digit (int) const;
|
||||
int decode_escape (int) const;
|
||||
int hex_to_int (int) const;
|
||||
int hex_to_int (int, int) const;
|
||||
int hex_to_int (int, int, int, int) const;
|
||||
void shift ();
|
||||
// Helpers.
|
||||
bool isEOS () const;
|
||||
int hexToInt (int) const;
|
||||
int hexToInt (int, int) const;
|
||||
int hexToInt (int, int, int, int) const;
|
||||
|
||||
// Classifiers.
|
||||
bool isString (std::string&, Lexer::Type&, int quote);
|
||||
bool isDate (std::string&, Lexer::Type&);
|
||||
bool isDuration (std::string&, Lexer::Type&);
|
||||
bool isUUID (std::string&, Lexer::Type&);
|
||||
bool isNumber (std::string&, Lexer::Type&);
|
||||
bool isHexNumber (std::string&, Lexer::Type&);
|
||||
bool isSeparator (std::string&, Lexer::Type&);
|
||||
bool isList (std::string&, Lexer::Type&);
|
||||
bool isURL (std::string&, Lexer::Type&);
|
||||
bool isPair (std::string&, Lexer::Type&);
|
||||
bool isTag (std::string&, Lexer::Type&);
|
||||
bool isPath (std::string&, Lexer::Type&);
|
||||
bool isSubstitution (std::string&, Lexer::Type&);
|
||||
bool isPattern (std::string&, Lexer::Type&);
|
||||
bool isOperator (std::string&, Lexer::Type&);
|
||||
bool isDOM (std::string&, Lexer::Type&);
|
||||
bool isIdentifier (std::string&, Lexer::Type&);
|
||||
bool isWord (std::string&, Lexer::Type&);
|
||||
|
||||
private:
|
||||
const std::string _input;
|
||||
std::string::size_type _i;
|
||||
std::string::size_type _shift_counter;
|
||||
int _n0;
|
||||
int _n1;
|
||||
int _n2;
|
||||
int _n3;
|
||||
bool _boundary01;
|
||||
bool _boundary12;
|
||||
bool _boundary23;
|
||||
bool _ambiguity;
|
||||
std::string _text;
|
||||
std::size_t _cursor;
|
||||
std::size_t _eos;
|
||||
bool _ambiguity;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
154
src/Nibbler.cpp
154
src/Nibbler.cpp
@@ -27,9 +27,9 @@
|
||||
#include <cmake.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <inttypes.h>
|
||||
#include <Lexer.h>
|
||||
#include <Nibbler.h>
|
||||
#ifdef NIBBLER_FEATURE_DATE
|
||||
#include <Date.h>
|
||||
@@ -284,7 +284,7 @@ bool Nibbler::getQuoted (
|
||||
bool Nibbler::getDigit (int& result)
|
||||
{
|
||||
if (_cursor < _length &&
|
||||
isdigit (_input[_cursor]))
|
||||
Lexer::isDigit (_input[_cursor]))
|
||||
{
|
||||
result = _input[_cursor++] - '0';
|
||||
return true;
|
||||
@@ -300,12 +300,12 @@ bool Nibbler::getDigit6 (int& result)
|
||||
if (i < _length &&
|
||||
_length - i >= 6)
|
||||
{
|
||||
if (isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]) &&
|
||||
isdigit (_input[i + 2]) &&
|
||||
isdigit (_input[i + 3]) &&
|
||||
isdigit (_input[i + 4]) &&
|
||||
isdigit (_input[i + 5]))
|
||||
if (Lexer::isDigit (_input[i + 0]) &&
|
||||
Lexer::isDigit (_input[i + 1]) &&
|
||||
Lexer::isDigit (_input[i + 2]) &&
|
||||
Lexer::isDigit (_input[i + 3]) &&
|
||||
Lexer::isDigit (_input[i + 4]) &&
|
||||
Lexer::isDigit (_input[i + 5]))
|
||||
{
|
||||
result = strtoimax (_input.substr (_cursor, 6).c_str (), NULL, 10);
|
||||
_cursor += 6;
|
||||
@@ -323,10 +323,10 @@ bool Nibbler::getDigit4 (int& result)
|
||||
if (i < _length &&
|
||||
_length - i >= 4)
|
||||
{
|
||||
if (isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]) &&
|
||||
isdigit (_input[i + 2]) &&
|
||||
isdigit (_input[i + 3]))
|
||||
if (Lexer::isDigit (_input[i + 0]) &&
|
||||
Lexer::isDigit (_input[i + 1]) &&
|
||||
Lexer::isDigit (_input[i + 2]) &&
|
||||
Lexer::isDigit (_input[i + 3]))
|
||||
{
|
||||
result = strtoimax (_input.substr (_cursor, 4).c_str (), NULL, 10);
|
||||
_cursor += 4;
|
||||
@@ -344,9 +344,9 @@ bool Nibbler::getDigit3 (int& result)
|
||||
if (i < _length &&
|
||||
_length - i >= 3)
|
||||
{
|
||||
if (isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]) &&
|
||||
isdigit (_input[i + 2]))
|
||||
if (Lexer::isDigit (_input[i + 0]) &&
|
||||
Lexer::isDigit (_input[i + 1]) &&
|
||||
Lexer::isDigit (_input[i + 2]))
|
||||
{
|
||||
result = strtoimax (_input.substr (_cursor, 3).c_str (), NULL, 10);
|
||||
_cursor += 3;
|
||||
@@ -364,8 +364,8 @@ bool Nibbler::getDigit2 (int& result)
|
||||
if (i < _length &&
|
||||
_length - i >= 2)
|
||||
{
|
||||
if (isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]))
|
||||
if (Lexer::isDigit (_input[i + 0]) &&
|
||||
Lexer::isDigit (_input[i + 1]))
|
||||
{
|
||||
result = strtoimax (_input.substr (_cursor, 2).c_str (), NULL, 10);
|
||||
_cursor += 2;
|
||||
@@ -390,7 +390,7 @@ bool Nibbler::getInt (int& result)
|
||||
}
|
||||
|
||||
// TODO Potential for use of find_first_not_of
|
||||
while (i < _length && isdigit (_input[i]))
|
||||
while (i < _length && Lexer::isDigit (_input[i]))
|
||||
++i;
|
||||
|
||||
if (i > _cursor)
|
||||
@@ -403,39 +403,12 @@ bool Nibbler::getInt (int& result)
|
||||
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)
|
||||
{
|
||||
std::string::size_type i = _cursor;
|
||||
// TODO Potential for use of find_first_not_of
|
||||
while (i < _length && isdigit (_input[i]))
|
||||
while (i < _length && Lexer::isDigit (_input[i]))
|
||||
++i;
|
||||
|
||||
if (i > _cursor)
|
||||
@@ -473,11 +446,11 @@ bool Nibbler::getNumber (std::string& result)
|
||||
++i;
|
||||
|
||||
// digit+
|
||||
if (i < _length && isdigit (_input[i]))
|
||||
if (i < _length && Lexer::isDigit (_input[i]))
|
||||
{
|
||||
++i;
|
||||
|
||||
while (i < _length && isdigit (_input[i]))
|
||||
while (i < _length && Lexer::isDigit (_input[i]))
|
||||
++i;
|
||||
|
||||
// ( . digit+ )?
|
||||
@@ -485,7 +458,7 @@ bool Nibbler::getNumber (std::string& result)
|
||||
{
|
||||
++i;
|
||||
|
||||
while (i < _length && isdigit (_input[i]))
|
||||
while (i < _length && Lexer::isDigit (_input[i]))
|
||||
++i;
|
||||
}
|
||||
|
||||
@@ -497,11 +470,11 @@ bool Nibbler::getNumber (std::string& result)
|
||||
if (i < _length && (_input[i] == '+' || _input[i] == '-'))
|
||||
++i;
|
||||
|
||||
if (i < _length && isdigit (_input[i]))
|
||||
if (i < _length && Lexer::isDigit (_input[i]))
|
||||
{
|
||||
++i;
|
||||
|
||||
while (i < _length && isdigit (_input[i]))
|
||||
while (i < _length && Lexer::isDigit (_input[i]))
|
||||
++i;
|
||||
|
||||
result = _input.substr (_cursor, i - _cursor);
|
||||
@@ -555,11 +528,11 @@ bool Nibbler::getUnsignedNumber (double& result)
|
||||
std::string::size_type i = _cursor;
|
||||
|
||||
// digit+
|
||||
if (i < _length && isdigit (_input[i]))
|
||||
if (i < _length && Lexer::isDigit (_input[i]))
|
||||
{
|
||||
++i;
|
||||
|
||||
while (i < _length && isdigit (_input[i]))
|
||||
while (i < _length && Lexer::isDigit (_input[i]))
|
||||
++i;
|
||||
|
||||
// ( . digit+ )?
|
||||
@@ -567,7 +540,7 @@ bool Nibbler::getUnsignedNumber (double& result)
|
||||
{
|
||||
++i;
|
||||
|
||||
while (i < _length && isdigit (_input[i]))
|
||||
while (i < _length && Lexer::isDigit (_input[i]))
|
||||
++i;
|
||||
}
|
||||
|
||||
@@ -579,11 +552,11 @@ bool Nibbler::getUnsignedNumber (double& result)
|
||||
if (i < _length && (_input[i] == '+' || _input[i] == '-'))
|
||||
++i;
|
||||
|
||||
if (i < _length && isdigit (_input[i]))
|
||||
if (i < _length && Lexer::isDigit (_input[i]))
|
||||
{
|
||||
++i;
|
||||
|
||||
while (i < _length && isdigit (_input[i]))
|
||||
while (i < _length && Lexer::isDigit (_input[i]))
|
||||
++i;
|
||||
|
||||
result = strtof (_input.substr (_cursor, i - _cursor).c_str (), NULL);
|
||||
@@ -737,21 +710,21 @@ bool Nibbler::getDateISO (time_t& t)
|
||||
if (i < _length &&
|
||||
_length - i >= 16)
|
||||
{
|
||||
if (isdigit (_input[i + 0]) &&
|
||||
isdigit (_input[i + 1]) &&
|
||||
isdigit (_input[i + 2]) &&
|
||||
isdigit (_input[i + 3]) &&
|
||||
isdigit (_input[i + 4]) &&
|
||||
isdigit (_input[i + 5]) &&
|
||||
isdigit (_input[i + 6]) &&
|
||||
isdigit (_input[i + 7]) &&
|
||||
if (Lexer::isDigit (_input[i + 0]) &&
|
||||
Lexer::isDigit (_input[i + 1]) &&
|
||||
Lexer::isDigit (_input[i + 2]) &&
|
||||
Lexer::isDigit (_input[i + 3]) &&
|
||||
Lexer::isDigit (_input[i + 4]) &&
|
||||
Lexer::isDigit (_input[i + 5]) &&
|
||||
Lexer::isDigit (_input[i + 6]) &&
|
||||
Lexer::isDigit (_input[i + 7]) &&
|
||||
_input[i + 8] == 'T' &&
|
||||
isdigit (_input[i + 9]) &&
|
||||
isdigit (_input[i + 10]) &&
|
||||
isdigit (_input[i + 11]) &&
|
||||
isdigit (_input[i + 12]) &&
|
||||
isdigit (_input[i + 13]) &&
|
||||
isdigit (_input[i + 14]) &&
|
||||
Lexer::isDigit (_input[i + 9]) &&
|
||||
Lexer::isDigit (_input[i + 10]) &&
|
||||
Lexer::isDigit (_input[i + 11]) &&
|
||||
Lexer::isDigit (_input[i + 12]) &&
|
||||
Lexer::isDigit (_input[i + 13]) &&
|
||||
Lexer::isDigit (_input[i + 14]) &&
|
||||
_input[i + 15] == 'Z')
|
||||
{
|
||||
_cursor += 16;
|
||||
@@ -817,7 +790,7 @@ bool Nibbler::parseDigits(std::string::size_type& i,
|
||||
// Check that 'f' of them are digits
|
||||
unsigned int g;
|
||||
for (g = 0; g < f; g++)
|
||||
if (! isdigit (_input[i + g]))
|
||||
if (! Lexer::isDigit (_input[i + g]))
|
||||
break;
|
||||
// Parse the integer when it is the case
|
||||
if (g == f)
|
||||
@@ -908,9 +881,9 @@ bool Nibbler::getDate (const std::string& format, time_t& t)
|
||||
case 'a':
|
||||
case 'A':
|
||||
if (i + 3 <= _length &&
|
||||
! isdigit (_input[i + 0]) &&
|
||||
! isdigit (_input[i + 1]) &&
|
||||
! isdigit (_input[i + 2]))
|
||||
! Lexer::isDigit (_input[i + 0]) &&
|
||||
! Lexer::isDigit (_input[i + 1]) &&
|
||||
! Lexer::isDigit (_input[i + 2]))
|
||||
{
|
||||
wday = Date::dayOfWeek (_input.substr (i, 3).c_str ());
|
||||
i += (format[f] == 'a') ? 3 : Date::dayName (wday).size ();
|
||||
@@ -922,9 +895,9 @@ bool Nibbler::getDate (const std::string& format, time_t& t)
|
||||
case 'b':
|
||||
case 'B':
|
||||
if (i + 3 <= _length &&
|
||||
! isdigit (_input[i + 0]) &&
|
||||
! isdigit (_input[i + 1]) &&
|
||||
! isdigit (_input[i + 2]))
|
||||
! Lexer::isDigit (_input[i + 0]) &&
|
||||
! Lexer::isDigit (_input[i + 1]) &&
|
||||
! Lexer::isDigit (_input[i + 2]))
|
||||
{
|
||||
if (month != -1)
|
||||
return false;
|
||||
@@ -1030,14 +1003,14 @@ bool Nibbler::getName (std::string& result)
|
||||
|
||||
if (i < _length)
|
||||
{
|
||||
if (! isdigit (_input[i]) &&
|
||||
if (! Lexer::isDigit (_input[i]) &&
|
||||
! ispunct (_input[i]) &&
|
||||
! Lexer::is_ws (_input[i]))
|
||||
! Lexer::isWhitespace (_input[i]))
|
||||
{
|
||||
++i;
|
||||
while (i < _length &&
|
||||
(_input[i] == '_' || ! ispunct (_input[i])) &&
|
||||
! Lexer::is_ws (_input[i]))
|
||||
! Lexer::isWhitespace (_input[i]))
|
||||
{
|
||||
++i;
|
||||
}
|
||||
@@ -1062,9 +1035,9 @@ bool Nibbler::getWord (std::string& result)
|
||||
|
||||
if (i < _length)
|
||||
{
|
||||
while (!isdigit (_input[i]) &&
|
||||
!isPunctuation (_input[i]) &&
|
||||
!Lexer::is_ws (_input[i]))
|
||||
while (!Lexer::isDigit (_input[i]) &&
|
||||
!Lexer::isPunctuation (_input[i]) &&
|
||||
!Lexer::isWhitespace (_input[i]))
|
||||
{
|
||||
++i;
|
||||
}
|
||||
@@ -1254,21 +1227,6 @@ bool Nibbler::depleted ()
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Override of ispunct, that considers #, $, _ and @ not to be punctuation.
|
||||
//
|
||||
// ispunct: ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~
|
||||
// Punctuation: ! " % & ' ( ) * + , - . / : ; < = > ? [ \ ] ^ _ ` { | } ~
|
||||
// delta: # $ @
|
||||
//
|
||||
bool Nibbler::isPunctuation (char c)
|
||||
{
|
||||
if (c == '@' || c == '#' || c == '$' || c == '_')
|
||||
return false;
|
||||
|
||||
return ispunct (c);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Nibbler::dump ()
|
||||
{
|
||||
|
||||
@@ -68,7 +68,6 @@ public:
|
||||
bool getDigit3 (int&);
|
||||
bool getDigit2 (int&);
|
||||
bool getInt (int&);
|
||||
bool getHex (int&);
|
||||
bool getUnsignedInt (int&);
|
||||
bool getNumber (std::string&);
|
||||
bool getNumber (double&);
|
||||
@@ -111,7 +110,6 @@ public:
|
||||
|
||||
bool depleted ();
|
||||
|
||||
static bool isPunctuation (char);
|
||||
std::string dump ();
|
||||
|
||||
private:
|
||||
|
||||
173
src/TDB2.cpp
173
src/TDB2.cpp
@@ -102,7 +102,7 @@ bool TF2::get (int id, Task& task)
|
||||
// pending.data file, the task in question cannot appear earlier than line
|
||||
// (id - 1) in the file. It can, however, appear significantly later because
|
||||
// it is not known how recent a GC operation was run.
|
||||
for (int i = id - 1; i < _tasks.size (); ++i)
|
||||
for (unsigned int i = id - 1; i < _tasks.size (); ++i)
|
||||
{
|
||||
if (_tasks[i].id == id)
|
||||
{
|
||||
@@ -226,7 +226,7 @@ void TF2::commit ()
|
||||
if (_file.open ())
|
||||
{
|
||||
if (context.config.getBoolean ("locking"))
|
||||
_file.waitForLock ();
|
||||
_file.lock ();
|
||||
|
||||
// Write out all the added tasks.
|
||||
std::vector <Task>::iterator task;
|
||||
@@ -258,7 +258,7 @@ void TF2::commit ()
|
||||
if (_file.open ())
|
||||
{
|
||||
if (context.config.getBoolean ("locking"))
|
||||
_file.waitForLock ();
|
||||
_file.lock ();
|
||||
|
||||
// Truncate the file and rewrite.
|
||||
_file.truncate ();
|
||||
@@ -316,9 +316,15 @@ void TF2::load_tasks ()
|
||||
++line_number;
|
||||
Task task (*i);
|
||||
|
||||
// Some tasks gets an ID.
|
||||
// Some tasks get an ID.
|
||||
if (_has_ids)
|
||||
task.id = context.tdb2.next_id ();
|
||||
{
|
||||
Task::status status = task.getStatus ();
|
||||
// Completed / deleted tasks in pending.data get an ID if GC is off.
|
||||
if (!context.run_gc ||
|
||||
(status != Task::completed && status != Task::deleted))
|
||||
task.id = context.tdb2.next_id ();
|
||||
}
|
||||
|
||||
_tasks.push_back (task);
|
||||
|
||||
@@ -352,7 +358,7 @@ void TF2::load_lines ()
|
||||
if (_file.open ())
|
||||
{
|
||||
if (context.config.getBoolean ("locking"))
|
||||
_file.waitForLock ();
|
||||
_file.lock ();
|
||||
|
||||
_file.read (_lines);
|
||||
_file.close ();
|
||||
@@ -462,9 +468,13 @@ void TF2::dependency_scan ()
|
||||
{
|
||||
if (right->get ("uuid") == *d)
|
||||
{
|
||||
Task::status status = right->getStatus ();
|
||||
if (status != Task::completed &&
|
||||
status != Task::deleted)
|
||||
// GC hasn't run yet, check both tasks for their current status
|
||||
Task::status lstatus = left->getStatus ();
|
||||
Task::status rstatus = right->getStatus ();
|
||||
if (lstatus != Task::completed &&
|
||||
lstatus != Task::deleted &&
|
||||
rstatus != Task::completed &&
|
||||
rstatus != Task::deleted)
|
||||
{
|
||||
left->is_blocked = true;
|
||||
right->is_blocking = true;
|
||||
@@ -559,7 +569,9 @@ void TDB2::set_location (const std::string& location)
|
||||
void TDB2::add (Task& task, bool add_to_backlog /* = true */)
|
||||
{
|
||||
// Ensure the task is consistent, and provide defaults if necessary.
|
||||
task.validate ();
|
||||
// bool argument to validate() is "applyDefault". Pass add_to_backlog through
|
||||
// in order to not apply defaults to synchronized tasks.
|
||||
task.validate (add_to_backlog);
|
||||
std::string uuid = task.get ("uuid");
|
||||
|
||||
// If the tasks are loaded, then verify that this uuid is not already in
|
||||
@@ -567,32 +579,30 @@ void TDB2::add (Task& task, bool add_to_backlog /* = true */)
|
||||
if (!verifyUniqueUUID (uuid))
|
||||
throw format (STRING_TDB2_UUID_NOT_UNIQUE, uuid);
|
||||
|
||||
// Create a vector tasks, as hooks can cause them to multiply.
|
||||
std::vector <Task> changes;
|
||||
changes.push_back (task);
|
||||
context.hooks.onAdd (changes);
|
||||
// Only locally-added tasks trigger hooks. This means that tasks introduced
|
||||
// via 'sync' do not trigger hooks.
|
||||
if (add_to_backlog)
|
||||
context.hooks.onAdd (task);
|
||||
|
||||
update (uuid, task, add_to_backlog, changes);
|
||||
update (uuid, task, add_to_backlog, true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void TDB2::modify (Task& task, bool add_to_backlog /* = true */)
|
||||
{
|
||||
// Ensure the task is consistent, and provide defaults if necessary.
|
||||
// Ensure the task is consistent.
|
||||
task.validate (false);
|
||||
task.upgradeLegacyValues ();
|
||||
std::string uuid = task.get ("uuid");
|
||||
|
||||
// Get the unmodified task as reference, so the hook can compare.
|
||||
Task original;
|
||||
get (uuid, original);
|
||||
if (add_to_backlog)
|
||||
{
|
||||
Task original;
|
||||
get (uuid, original);
|
||||
context.hooks.onModify (original, task);
|
||||
}
|
||||
|
||||
// Create a vector tasks, as hooks can cause them to multiply.
|
||||
std::vector <Task> changes;
|
||||
changes.push_back (task);
|
||||
context.hooks.onModify (original, changes);
|
||||
|
||||
update (uuid, task, add_to_backlog, changes);
|
||||
update (uuid, task, add_to_backlog);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -600,61 +610,57 @@ void TDB2::update (
|
||||
const std::string& uuid,
|
||||
Task& task,
|
||||
const bool add_to_backlog,
|
||||
std::vector <Task>& changes)
|
||||
const bool addition /* = false */)
|
||||
{
|
||||
std::vector <Task>::iterator i;
|
||||
for (i = changes.begin (); i != changes.end (); ++i)
|
||||
// Validate to add metadata.
|
||||
task.validate (false);
|
||||
|
||||
// If the task already exists, it is a modification, else addition.
|
||||
Task original;
|
||||
if (not addition && get (task.get ("uuid"), original))
|
||||
{
|
||||
// Validate to add metadata.
|
||||
i->validate (false);
|
||||
|
||||
// If the task already exists, it is a modification, else addition.
|
||||
Task original;
|
||||
if (get (i->get ("uuid"), original))
|
||||
{
|
||||
// Update the task, wherever it is.
|
||||
if (!pending.modify_task (*i))
|
||||
completed.modify_task (*i);
|
||||
|
||||
// time <time>
|
||||
// old <task>
|
||||
// new <task>
|
||||
// ---
|
||||
undo.add_line ("time " + Date ().toEpochString () + "\n");
|
||||
undo.add_line ("old " + original.composeF4 () + "\n");
|
||||
undo.add_line ("new " + i->composeF4 () + "\n");
|
||||
undo.add_line ("---\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Re-validate to add default values.
|
||||
i->validate ();
|
||||
|
||||
// Add new task to either pending or completed.
|
||||
std::string status = i->get ("status");
|
||||
if (status == "completed" ||
|
||||
status == "deleted")
|
||||
completed.add_task (*i);
|
||||
else
|
||||
pending.add_task (*i);
|
||||
|
||||
// Add undo data lines:
|
||||
// time <time>
|
||||
// new <task>
|
||||
// ---
|
||||
undo.add_line ("time " + Date ().toEpochString () + "\n");
|
||||
undo.add_line ("new " + i->composeF4 () + "\n");
|
||||
undo.add_line ("---\n");
|
||||
}
|
||||
|
||||
// Add task to backlog.
|
||||
if (add_to_backlog)
|
||||
backlog.add_line (i->composeJSON () + "\n");
|
||||
{
|
||||
// All locally modified tasks are timestamped, implicitly overwriting any
|
||||
// changes the user or hooks tried to apply to the "modified" attribute.
|
||||
task.setAsNow ("modified");
|
||||
}
|
||||
|
||||
// The original task may be further referenced by the caller.
|
||||
if (i->get ("uuid") == uuid)
|
||||
task = *i;
|
||||
// Update the task, wherever it is.
|
||||
if (!pending.modify_task (task))
|
||||
completed.modify_task (task);
|
||||
|
||||
// time <time>
|
||||
// old <task>
|
||||
// new <task>
|
||||
// ---
|
||||
undo.add_line ("time " + Date ().toEpochString () + "\n");
|
||||
undo.add_line ("old " + original.composeF4 () + "\n");
|
||||
undo.add_line ("new " + task.composeF4 () + "\n");
|
||||
undo.add_line ("---\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add new task to either pending or completed.
|
||||
std::string status = task.get ("status");
|
||||
if (status == "completed" ||
|
||||
status == "deleted")
|
||||
completed.add_task (task);
|
||||
else
|
||||
pending.add_task (task);
|
||||
|
||||
// Add undo data lines:
|
||||
// time <time>
|
||||
// new <task>
|
||||
// ---
|
||||
undo.add_line ("time " + Date ().toEpochString () + "\n");
|
||||
undo.add_line ("new " + task.composeF4 () + "\n");
|
||||
undo.add_line ("---\n");
|
||||
}
|
||||
|
||||
// Add task to backlog.
|
||||
if (add_to_backlog)
|
||||
backlog.add_line (task.composeJSON () + "\n");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -979,6 +985,9 @@ void TDB2::show_diff (
|
||||
view.add (Column::factory ("string", STRING_TDB2_UNDO_PRIOR));
|
||||
view.add (Column::factory ("string", STRING_TDB2_UNDO_CURRENT));
|
||||
|
||||
Color label (context.config.get ("color.label"));
|
||||
view.colorHeader (label);
|
||||
|
||||
Task after (current);
|
||||
|
||||
if (prior != "")
|
||||
@@ -1189,18 +1198,21 @@ int TDB2::gc ()
|
||||
// Allowed as an override, but not recommended.
|
||||
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 ();
|
||||
|
||||
// TODO Assume pending < completed, therefore there is room here to process
|
||||
// data before joining with the completed.data thread.
|
||||
|
||||
bool pending_changes = false;
|
||||
bool completed_changes = false;
|
||||
|
||||
std::vector <Task> pending_tasks_after;
|
||||
std::vector <Task> completed_tasks_after;
|
||||
|
||||
// Reduce unnecessary allocation/copies.
|
||||
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
|
||||
// completed, or need to be 'woken'.
|
||||
@@ -1237,6 +1249,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
|
||||
// pending.
|
||||
for (task = completed_tasks.begin ();
|
||||
|
||||
@@ -128,7 +128,7 @@ public:
|
||||
|
||||
private:
|
||||
void gather_changes ();
|
||||
void update (const std::string&, Task&, const bool, std::vector <Task>&);
|
||||
void update (const std::string&, Task&, const bool, const bool addition = false);
|
||||
bool verifyUniqueUUID (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&);
|
||||
|
||||
@@ -298,7 +298,6 @@ int TLSClient::verify_certificate () const
|
||||
// This verification function uses the trusted CAs in the credentials
|
||||
// structure. So you must have installed one or more CA certificates.
|
||||
unsigned int status = 0;
|
||||
|
||||
const char* hostname = _host.c_str();
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030104
|
||||
if (_trust == TLSClient::ignore_hostname)
|
||||
@@ -350,7 +349,7 @@ int TLSClient::verify_certificate () const
|
||||
if (_debug)
|
||||
std::cout << "c: ERROR x509 cert import. " << gnutls_strerror (ret) << "\n";
|
||||
gnutls_x509_crt_deinit(cert);
|
||||
status = GNUTLS_E_CERTIFICATE_ERROR;
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
if (gnutls_x509_crt_check_hostname (cert, hostname) == 0)
|
||||
@@ -366,7 +365,7 @@ int TLSClient::verify_certificate () const
|
||||
}
|
||||
#endif
|
||||
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030105
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030104
|
||||
gnutls_certificate_type_t type = gnutls_certificate_type_get (_session);
|
||||
gnutls_datum_t out;
|
||||
ret = gnutls_certificate_verification_status_print (status, type, &out, 0);
|
||||
@@ -377,6 +376,8 @@ int TLSClient::verify_certificate () const
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
if (_debug)
|
||||
std::cout << "c: INFO " << out.data << "\n";
|
||||
gnutls_free (out.data);
|
||||
#endif
|
||||
|
||||
|
||||
189
src/Task.cpp
189
src/Task.cpp
@@ -65,14 +65,12 @@ static const float epsilon = 0.000001;
|
||||
#endif
|
||||
|
||||
std::string Task::defaultProject = "";
|
||||
std::string Task::defaultPriority = "";
|
||||
std::string Task::defaultDue = "";
|
||||
bool Task::searchCaseSensitive = true;
|
||||
bool Task::regex = false;
|
||||
std::map <std::string, std::string> Task::attributes;
|
||||
|
||||
std::map <std::string, float> Task::coefficients;
|
||||
float Task::urgencyPriorityCoefficient = 0.0;
|
||||
float Task::urgencyProjectCoefficient = 0.0;
|
||||
float Task::urgencyActiveCoefficient = 0.0;
|
||||
float Task::urgencyScheduledCoefficient = 0.0;
|
||||
@@ -87,6 +85,8 @@ float Task::urgencyBlockingCoefficient = 0.0;
|
||||
float Task::urgencyAgeCoefficient = 0.0;
|
||||
float Task::urgencyAgeMax = 0.0;
|
||||
|
||||
std::map <std::string, std::vector <std::string>> Task::customOrder;
|
||||
|
||||
static const std::string dummy ("");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -565,7 +565,6 @@ void Task::parse (const std::string& input)
|
||||
nl.getQuoted ('"', value))
|
||||
{
|
||||
legacyAttributeMap (name);
|
||||
legacyValueMap (name, value);
|
||||
|
||||
if (name.substr (0, 11) == "annotation_")
|
||||
++annotation_count;
|
||||
@@ -586,8 +585,6 @@ void Task::parse (const std::string& input)
|
||||
parseJSON (copy);
|
||||
else
|
||||
throw std::string (STRING_RECORD_NOT_FF4);
|
||||
|
||||
upgradeLegacyValues ();
|
||||
}
|
||||
|
||||
catch (const std::string&)
|
||||
@@ -636,8 +633,9 @@ void Task::parseJSON (const std::string& line)
|
||||
// Dates are converted from ISO to epoch.
|
||||
else if (type == "date")
|
||||
{
|
||||
Date d (unquoteText (i->second->dump ()));
|
||||
set (i->first, d.toEpochString ());
|
||||
std::string text = unquoteText (i->second->dump ());
|
||||
Date d (text);
|
||||
set (i->first, text == "" ? "" : d.toEpochString ());
|
||||
}
|
||||
|
||||
// Tags are an array of JSON strings.
|
||||
@@ -718,8 +716,6 @@ void Task::parseJSON (const std::string& line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
upgradeLegacyValues ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -804,6 +800,10 @@ std::string Task::composeJSON (bool decorate /*= false*/) const
|
||||
if (i->first.substr (0, 11) == "annotation_")
|
||||
continue;
|
||||
|
||||
// If value is an empty string, do not ever output it
|
||||
if (i->second == "")
|
||||
continue;
|
||||
|
||||
if (attributes_written)
|
||||
out << ",";
|
||||
|
||||
@@ -815,16 +815,22 @@ std::string Task::composeJSON (bool decorate /*= false*/) const
|
||||
if (type == "date")
|
||||
{
|
||||
Date d (i->second);
|
||||
if (i->first == "modification")
|
||||
out << "\"modified\":\""
|
||||
<< d.toISO ()
|
||||
<< "\"";
|
||||
else
|
||||
out << "\""
|
||||
<< i->first
|
||||
<< "\":\""
|
||||
<< d.toISO ()
|
||||
<< "\"";
|
||||
out << "\""
|
||||
<< (i->first == "modification" ? "modified" : i->first)
|
||||
<< "\":\""
|
||||
// Date was deleted, do not export parsed empty string
|
||||
<< (i->second == "" ? "" : d.toISO ())
|
||||
<< "\"";
|
||||
|
||||
++attributes_written;
|
||||
}
|
||||
|
||||
else if (type == "numeric")
|
||||
{
|
||||
out << "\""
|
||||
<< i->first
|
||||
<< "\":"
|
||||
<< i->second;
|
||||
|
||||
++attributes_written;
|
||||
}
|
||||
@@ -847,6 +853,8 @@ std::string Task::composeJSON (bool decorate /*= false*/) const
|
||||
}
|
||||
|
||||
out << "]";
|
||||
|
||||
++attributes_written;
|
||||
}
|
||||
|
||||
// Everything else is a quoted value.
|
||||
@@ -894,9 +902,8 @@ std::string Task::composeJSON (bool decorate /*= false*/) const
|
||||
// Include urgency.
|
||||
if (decorate)
|
||||
out << ","
|
||||
<< "\"urgency\":\""
|
||||
<< urgency_c ()
|
||||
<<"\"";
|
||||
<< "\"urgency\":"
|
||||
<< urgency_c ();
|
||||
#endif
|
||||
|
||||
out << "}";
|
||||
@@ -1093,6 +1100,7 @@ int Task::getTagCount () const
|
||||
bool Task::hasTag (const std::string& tag) const
|
||||
{
|
||||
// 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 == "UNBLOCKED") return !is_blocked;
|
||||
if (tag == "BLOCKING") return is_blocking;
|
||||
@@ -1112,10 +1120,10 @@ bool Task::hasTag (const std::string& tag) const
|
||||
if (tag == "SCHEDULED") return has ("scheduled");
|
||||
if (tag == "CHILD") return has ("parent");
|
||||
if (tag == "UNTIL") return has ("until");
|
||||
if (tag == "WAITING") return has ("wait");
|
||||
if (tag == "ANNOTATED") return hasAnnotations ();
|
||||
if (tag == "TAGGED") return has ("tags");
|
||||
if (tag == "PARENT") return has ("mask");
|
||||
if (tag == "WAITING") return get ("status") == "waiting";
|
||||
if (tag == "PENDING") return get ("status") == "pending";
|
||||
if (tag == "COMPLETED") return get ("status") == "completed";
|
||||
if (tag == "DELETED") return get ("status") == "deleted";
|
||||
@@ -1376,7 +1384,7 @@ void Task::validate (bool applyDefault /* = true */)
|
||||
if (!has ("modified") || get ("modified") == "")
|
||||
setAsNow ("modified");
|
||||
|
||||
if (applyDefault)
|
||||
if (applyDefault && (! has ("parent") || get ("parent") == ""))
|
||||
{
|
||||
// Override with default.project, if not specified.
|
||||
if (Task::defaultProject != "" &&
|
||||
@@ -1386,14 +1394,6 @@ void Task::validate (bool applyDefault /* = true */)
|
||||
set ("project", Task::defaultProject);
|
||||
}
|
||||
|
||||
// Override with default.priority, if not specified.
|
||||
if (Task::defaultPriority != "" &&
|
||||
! has ("priority"))
|
||||
{
|
||||
if (context.columns["priority"]->validate (Task::defaultPriority))
|
||||
set ("priority", Task::defaultPriority);
|
||||
}
|
||||
|
||||
// Override with default.due, if not specified.
|
||||
if (Task::defaultDue != "" &&
|
||||
! has ("due"))
|
||||
@@ -1479,17 +1479,6 @@ void Task::validate (bool applyDefault /* = true */)
|
||||
throw std::string (format (STRING_TASK_VALID_RECUR, value));
|
||||
}
|
||||
}
|
||||
|
||||
// Priorities must be valid.
|
||||
if (has ("priority"))
|
||||
{
|
||||
std::string priority = get ("priority");
|
||||
if (priority != "H" &&
|
||||
priority != "M" &&
|
||||
priority != "L" &&
|
||||
priority != "")
|
||||
throw format (STRING_TASK_VALID_PRIORITY, priority);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1647,7 +1636,6 @@ float Task::urgency_c () const
|
||||
{
|
||||
float value = 0.0;
|
||||
#ifdef PRODUCT_TASKWARRIOR
|
||||
value += fabsf (Task::urgencyPriorityCoefficient) > epsilon ? (urgency_priority () * Task::urgencyPriorityCoefficient) : 0.0;
|
||||
value += fabsf (Task::urgencyProjectCoefficient) > epsilon ? (urgency_project () * Task::urgencyProjectCoefficient) : 0.0;
|
||||
value += fabsf (Task::urgencyActiveCoefficient) > epsilon ? (urgency_active () * Task::urgencyActiveCoefficient) : 0.0;
|
||||
value += fabsf (Task::urgencyScheduledCoefficient) > epsilon ? (urgency_scheduled () * Task::urgencyScheduledCoefficient) : 0.0;
|
||||
@@ -1689,6 +1677,16 @@ float Task::urgency_c () const
|
||||
if (hasTag (tag))
|
||||
value += var->second;
|
||||
}
|
||||
|
||||
// urgency.user.keyword.<keyword>.coefficient
|
||||
if (var->first.substr (13, 8) == "keyword." &&
|
||||
(end = var->first.find (".coefficient")) != std::string::npos)
|
||||
{
|
||||
std::string keyword = var->first.substr (21, end - 21);
|
||||
|
||||
if (get ("description").find (keyword) != std::string::npos)
|
||||
value += var->second;
|
||||
}
|
||||
}
|
||||
else if (var->first.substr (0, 12) == "urgency.uda.")
|
||||
{
|
||||
@@ -1734,18 +1732,6 @@ float Task::urgency ()
|
||||
return urgency_value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
float Task::urgency_priority () const
|
||||
{
|
||||
const std::string& value = get_ref ("priority");
|
||||
|
||||
if (value == "H") return 1.0;
|
||||
else if (value == "M") return 0.65;
|
||||
else if (value == "L") return 0.3;
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
float Task::urgency_inherit () const
|
||||
{
|
||||
@@ -1767,7 +1753,6 @@ float Task::urgency_inherit () const
|
||||
v += it->urgency_annotations ();
|
||||
v += it->urgency_due ();
|
||||
v += it->urgency_next ();
|
||||
v += it->urgency_priority ();
|
||||
v += it->urgency_scheduled ();
|
||||
v += it->urgency_waiting ();
|
||||
|
||||
@@ -1948,17 +1933,13 @@ void Task::modify (modType type, bool text_required /* = false */)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Some columns are not modifiable.
|
||||
if (name == "uuid" ||
|
||||
name == "id" ||
|
||||
name == "mask" ||
|
||||
name == "imask" ||
|
||||
name == "parent")
|
||||
throw format (STRING_INVALID_MOD, name, value);
|
||||
|
||||
// Get the column info.
|
||||
Column* column = context.columns[name];
|
||||
|
||||
// Some columns are not modifiable.
|
||||
if (! column->modifiable ())
|
||||
throw format (STRING_INVALID_MOD, name, value);
|
||||
|
||||
// Dependencies are specified as IDs.
|
||||
if (name == "depends")
|
||||
{
|
||||
@@ -2068,9 +2049,6 @@ void Task::modify (modType type, bool text_required /* = false */)
|
||||
if (v.type () == Variant::type_string)
|
||||
throw format (STRING_UDA_NUMERIC, v.get_string ());
|
||||
|
||||
v.cast (Variant::type_real);
|
||||
v.cast (Variant::type_string);
|
||||
|
||||
set (name, v);
|
||||
++modCount;
|
||||
}
|
||||
@@ -2209,78 +2187,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.
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -37,13 +37,12 @@ class Task : public std::map <std::string, std::string>
|
||||
{
|
||||
public:
|
||||
static std::string defaultProject;
|
||||
static std::string defaultPriority;
|
||||
static std::string defaultDue;
|
||||
static bool searchCaseSensitive;
|
||||
static bool regex;
|
||||
static std::map <std::string, std::string> attributes; // name -> type
|
||||
static std::map <std::string, float> coefficients;
|
||||
static float urgencyPriorityCoefficient;
|
||||
static std::map <std::string, std::vector <std::string>> customOrder;
|
||||
static float urgencyProjectCoefficient;
|
||||
static float urgencyActiveCoefficient;
|
||||
static float urgencyScheduledCoefficient;
|
||||
@@ -154,7 +153,6 @@ public:
|
||||
|
||||
enum modType {modReplace, modPrepend, modAppend, modAnnotate};
|
||||
void modify (modType, bool text_required = false);
|
||||
void upgradeLegacyValues ();
|
||||
|
||||
private:
|
||||
int determineVersion (const std::string&);
|
||||
@@ -163,10 +161,8 @@ private:
|
||||
void validate_before (const std::string&, const std::string&);
|
||||
const std::string encode (const std::string&) const;
|
||||
const std::string decode (const std::string&) const;
|
||||
void upgradeLegacyValue (std::string&);
|
||||
|
||||
public:
|
||||
float urgency_priority () const;
|
||||
float urgency_project () const;
|
||||
float urgency_active () const;
|
||||
float urgency_scheduled () const;
|
||||
|
||||
124
src/Variant.cpp
124
src/Variant.cpp
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <cmake.h>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
@@ -41,6 +42,7 @@
|
||||
std::string Variant::dateFormat = "";
|
||||
bool Variant::searchCaseSensitive = true;
|
||||
bool Variant::searchUsingRegex = true;
|
||||
bool Variant::isoEnabled = true;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Variant::Variant ()
|
||||
@@ -134,7 +136,7 @@ Variant::Variant (const char* value)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Variant::Variant (const time_t value, const enum type new_type /*=type_date*/)
|
||||
Variant::Variant (const time_t value, const enum type new_type)
|
||||
: _type (new_type)
|
||||
, _bool (false)
|
||||
, _integer (0)
|
||||
@@ -165,7 +167,7 @@ void Variant::source (const std::string& input)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Variant::source () const
|
||||
const std::string& Variant::source () const
|
||||
{
|
||||
return _source;
|
||||
}
|
||||
@@ -313,19 +315,25 @@ bool Variant::operator< (const Variant& other) const
|
||||
return left._string < right._string;
|
||||
|
||||
case type_string:
|
||||
if (left.source () == "priority" || right.source () == "priority")
|
||||
{
|
||||
if (left._string != "H" && right._string == "H") return true;
|
||||
else if (left._string == "L" && right._string == "M") return true;
|
||||
else if (left._string == "" && right._string != "") return true;
|
||||
else return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (left.trivial () || right.trivial ())
|
||||
if (left._string == right._string)
|
||||
return false;
|
||||
|
||||
return left._string < right._string;
|
||||
auto order = Task::customOrder.find (left.source ());
|
||||
if (order != Task::customOrder.end ())
|
||||
{
|
||||
// Guaranteed to be found, because of ColUDA::validate ().
|
||||
auto posLeft = std::find (order->second.begin (), order->second.end (), left._string);
|
||||
auto posRight = std::find (order->second.begin (), order->second.end (), right._string);
|
||||
return posLeft < posRight;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (left.trivial () || right.trivial ())
|
||||
return false;
|
||||
|
||||
return left._string < right._string;
|
||||
}
|
||||
}
|
||||
|
||||
case type_date:
|
||||
@@ -458,20 +466,25 @@ bool Variant::operator<= (const Variant& other) const
|
||||
return left._string <= right._string;
|
||||
|
||||
case type_string:
|
||||
if (left.source () == "priority" || right.source () == "priority")
|
||||
{
|
||||
if (left._string == right._string ) return true;
|
||||
else if ( right._string == "H") return true;
|
||||
else if (left._string == "L" && right._string == "M") return true;
|
||||
else if (left._string == "" ) return true;
|
||||
else return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (left.trivial () || right.trivial ())
|
||||
return false;
|
||||
if (left._string == right._string)
|
||||
return true;
|
||||
|
||||
return left._string <= right._string;
|
||||
auto order = Task::customOrder.find (left.source ());
|
||||
if (order != Task::customOrder.end ())
|
||||
{
|
||||
// Guaranteed to be found, because of ColUDA::validate ().
|
||||
auto posLeft = std::find (order->second.begin (), order->second.end (), left._string);
|
||||
auto posRight = std::find (order->second.begin (), order->second.end (), right._string);
|
||||
return posLeft <= posRight;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (left.trivial () || right.trivial ())
|
||||
return false;
|
||||
|
||||
return left._string <= right._string;
|
||||
}
|
||||
}
|
||||
|
||||
case type_date:
|
||||
@@ -604,20 +617,27 @@ bool Variant::operator> (const Variant& other) const
|
||||
return left._string > right._string;
|
||||
|
||||
case type_string:
|
||||
if (left.source () == "priority" || right.source () == "priority")
|
||||
{
|
||||
if (left._string == "H" && right._string != "H") return true;
|
||||
else if (left._string == "M" && right._string == "L") return true;
|
||||
else if (left._string != "" && right._string == "") return true;
|
||||
else return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (left.trivial () || right.trivial ())
|
||||
if (left._string == right._string)
|
||||
return false;
|
||||
|
||||
return left._string> right._string;
|
||||
auto order = Task::customOrder.find (left.source ());
|
||||
if (order != Task::customOrder.end ())
|
||||
{
|
||||
// Guaranteed to be found, because of ColUDA::validate ().
|
||||
auto posLeft = std::find (order->second.begin (), order->second.end (), left._string);
|
||||
auto posRight = std::find (order->second.begin (), order->second.end (), right._string);
|
||||
return posLeft > posRight;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (left.trivial () || right.trivial ())
|
||||
return false;
|
||||
|
||||
return left._string > right._string;
|
||||
}
|
||||
}
|
||||
|
||||
case type_date:
|
||||
if (left.trivial () || right.trivial ())
|
||||
return false;
|
||||
@@ -748,20 +768,25 @@ bool Variant::operator>= (const Variant& other) const
|
||||
return left._string >= right._string;
|
||||
|
||||
case type_string:
|
||||
if (left.source () == "priority" || right.source () == "priority")
|
||||
{
|
||||
if (left._string == right._string ) return true;
|
||||
else if (left._string == "H" ) return true;
|
||||
else if (left._string == "M" && right._string == "L") return true;
|
||||
else if ( right._string == "" ) return true;
|
||||
else return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (left.trivial () || right.trivial ())
|
||||
return false;
|
||||
if (left._string == right._string)
|
||||
return true;
|
||||
|
||||
return left._string >= right._string;
|
||||
auto order = Task::customOrder.find (left.source ());
|
||||
if (order != Task::customOrder.end ())
|
||||
{
|
||||
// Guaranteed to be found, because of ColUDA::validate ().
|
||||
auto posLeft = std::find (order->second.begin (), order->second.end (), left._string);
|
||||
auto posRight = std::find (order->second.begin (), order->second.end (), right._string);
|
||||
return posLeft >= posRight;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (left.trivial () || right.trivial ())
|
||||
return false;
|
||||
|
||||
return left._string >= right._string;
|
||||
}
|
||||
}
|
||||
|
||||
case type_date:
|
||||
@@ -1963,6 +1988,8 @@ Variant::operator std::string () const
|
||||
case type_unknown:
|
||||
throw std::string (STRING_VARIANT_RENDER_UNK);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -2065,7 +2092,8 @@ void Variant::cast (const enum type new_type)
|
||||
|
||||
ISO8601d iso;
|
||||
std::string::size_type pos = 0;
|
||||
if (iso.parse (_string, pos) &&
|
||||
if (isoEnabled &&
|
||||
iso.parse (_string, pos) &&
|
||||
pos == _string.length ())
|
||||
{
|
||||
_date = (time_t) iso;
|
||||
@@ -2170,7 +2198,7 @@ double Variant::get_real () const
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Variant::get_string () const
|
||||
const std::string& Variant::get_string () const
|
||||
{
|
||||
return _string;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#ifndef INCLUDED_VARIANT
|
||||
#define INCLUDED_VARIANT
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
#include <Task.h>
|
||||
@@ -37,6 +38,7 @@ public:
|
||||
static std::string dateFormat;
|
||||
static bool searchCaseSensitive;
|
||||
static bool searchUsingRegex;
|
||||
static bool isoEnabled;
|
||||
|
||||
enum type {type_unknown, type_boolean, type_integer, type_real, type_string,
|
||||
type_date, type_duration};
|
||||
@@ -48,11 +50,11 @@ public:
|
||||
Variant (const double);
|
||||
Variant (const std::string&);
|
||||
Variant (const char*);
|
||||
Variant (const time_t, const enum type new_type = type_date);
|
||||
Variant (const time_t, const enum type);
|
||||
~Variant ();
|
||||
|
||||
void source (const std::string&);
|
||||
std::string source () const;
|
||||
const std::string& source () const;
|
||||
|
||||
Variant& operator= (const Variant&);
|
||||
|
||||
@@ -98,12 +100,12 @@ public:
|
||||
int type ();
|
||||
bool trivial () const;
|
||||
|
||||
bool get_bool () const;
|
||||
int get_integer () const;
|
||||
double get_real () const;
|
||||
std::string get_string () const;
|
||||
time_t get_date () const;
|
||||
time_t get_duration () const;
|
||||
bool get_bool () const;
|
||||
int get_integer () const;
|
||||
double get_real () const;
|
||||
const std::string& get_string () const;
|
||||
time_t get_date () const;
|
||||
time_t get_duration () const;
|
||||
|
||||
private:
|
||||
enum type _type;
|
||||
|
||||
@@ -114,6 +114,7 @@ std::string ViewTask::render (std::vector <Task>& data, std::vector <int>& seque
|
||||
{
|
||||
context.timer_render.start ();
|
||||
|
||||
bool const obfuscate = context.config.getBoolean ("obfuscate");
|
||||
bool const print_empty_columns = context.config.getBoolean ("print.empty.columns");
|
||||
std::vector <Column*> nonempty_columns;
|
||||
std::vector <bool> nonempty_sort;
|
||||
@@ -143,6 +144,11 @@ std::string ViewTask::render (std::vector <Task>& data, std::vector <int>& seque
|
||||
|
||||
if (min > global_min) global_min = min;
|
||||
if (ideal > global_ideal) global_ideal = ideal;
|
||||
|
||||
// If a fixed-width column was just measured, there is no point repeating
|
||||
// the measurement for all tasks.
|
||||
if (_columns[i]->is_fixed_width ())
|
||||
break;
|
||||
}
|
||||
|
||||
if (print_empty_columns || global_min != 0)
|
||||
@@ -237,7 +243,7 @@ std::string ViewTask::render (std::vector <Task>& data, std::vector <int>& seque
|
||||
|
||||
// Compose column headers.
|
||||
unsigned int max_lines = 0;
|
||||
std::vector <std::vector <std::string> > headers;
|
||||
std::vector <std::vector <std::string>> headers;
|
||||
for (unsigned int c = 0; c < _columns.size (); ++c)
|
||||
{
|
||||
headers.push_back (std::vector <std::string> ());
|
||||
@@ -290,7 +296,7 @@ std::string ViewTask::render (std::vector <Task>& data, std::vector <int>& seque
|
||||
|
||||
// Compose, render columns, in sequence.
|
||||
_rows = 0;
|
||||
std::vector <std::vector <std::string> > cells;
|
||||
std::vector <std::vector <std::string>> cells;
|
||||
std::vector <int>::iterator s;
|
||||
for (unsigned int s = 0; s < sequence.size (); ++s)
|
||||
{
|
||||
@@ -316,6 +322,11 @@ std::string ViewTask::render (std::vector <Task>& data, std::vector <int>& seque
|
||||
|
||||
if (cells[c].size () > max_lines)
|
||||
max_lines = cells[c].size ();
|
||||
|
||||
if (obfuscate)
|
||||
if (_columns[c]->type () == "string")
|
||||
for (unsigned int line = 0; line < cells[c].size (); ++line)
|
||||
cells[c][line] = obfuscateText (cells[c][line]);
|
||||
}
|
||||
|
||||
// Listing breaks are simply blank lines inserted when a column value
|
||||
|
||||
@@ -114,6 +114,8 @@ void ViewText::set (int row, int col, Color color)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string ViewText::render ()
|
||||
{
|
||||
bool const obfuscate = context.config.getBoolean ("obfuscate");
|
||||
|
||||
// Determine minimal, ideal column widths.
|
||||
std::vector <int> minimal;
|
||||
std::vector <int> ideal;
|
||||
@@ -132,6 +134,11 @@ std::string ViewText::render ()
|
||||
|
||||
if (min > global_min) global_min = min;
|
||||
if (ideal > global_ideal) global_ideal = ideal;
|
||||
|
||||
// If a fixed-width column was just measured, there is no point repeating
|
||||
// the measurement for all tasks.
|
||||
if (_columns[col]->is_fixed_width ())
|
||||
break;
|
||||
}
|
||||
|
||||
minimal.push_back (global_min);
|
||||
@@ -181,7 +188,7 @@ std::string ViewText::render ()
|
||||
|
||||
// Compose column headers.
|
||||
unsigned int max_lines = 0;
|
||||
std::vector <std::vector <std::string> > headers;
|
||||
std::vector <std::vector <std::string>> headers;
|
||||
for (unsigned int c = 0; c < _columns.size (); ++c)
|
||||
{
|
||||
headers.push_back (std::vector <std::string> ());
|
||||
@@ -233,7 +240,7 @@ std::string ViewText::render ()
|
||||
|
||||
// Compose, render columns, in sequence.
|
||||
_rows = 0;
|
||||
std::vector <std::vector <std::string> > cells;
|
||||
std::vector <std::vector <std::string>> cells;
|
||||
for (unsigned int row = 0; row < _data.size (); ++row)
|
||||
{
|
||||
max_lines = 0;
|
||||
@@ -260,6 +267,11 @@ std::string ViewText::render ()
|
||||
|
||||
if (cells[col].size () > max_lines)
|
||||
max_lines = cells[col].size ();
|
||||
|
||||
if (obfuscate)
|
||||
if (_columns[col]->type () == "string")
|
||||
for (unsigned int line = 0; line < cells[col].size (); ++line)
|
||||
cells[col][line] = obfuscateText (cells[col][line]);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < max_lines; ++i)
|
||||
|
||||
@@ -68,24 +68,24 @@ public:
|
||||
std::string render ();
|
||||
|
||||
private:
|
||||
std::vector <std::vector <std::string> > _data;
|
||||
std::vector <std::vector <Color> > _color;
|
||||
std::vector <Column*> _columns;
|
||||
int _width;
|
||||
int _left_margin;
|
||||
Color _header;
|
||||
Color _odd;
|
||||
Color _even;
|
||||
int _intra_padding;
|
||||
Color _intra_odd;
|
||||
Color _intra_even;
|
||||
int _extra_padding;
|
||||
Color _extra_odd;
|
||||
Color _extra_even;
|
||||
int _truncate_lines;
|
||||
int _truncate_rows;
|
||||
int _lines;
|
||||
int _rows;
|
||||
std::vector <std::vector <std::string>> _data;
|
||||
std::vector <std::vector <Color>> _color;
|
||||
std::vector <Column*> _columns;
|
||||
int _width;
|
||||
int _left_margin;
|
||||
Color _header;
|
||||
Color _odd;
|
||||
Color _even;
|
||||
int _intra_padding;
|
||||
Color _intra_odd;
|
||||
Color _intra_even;
|
||||
int _extra_padding;
|
||||
Color _extra_odd;
|
||||
Color _extra_even;
|
||||
int _truncate_lines;
|
||||
int _truncate_rows;
|
||||
int _lines;
|
||||
int _rows;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -135,7 +135,6 @@ int main (int argc, const char** argv)
|
||||
cli.entity ("attribute", "mask");
|
||||
cli.entity ("attribute", "modified");
|
||||
cli.entity ("attribute", "parent");
|
||||
cli.entity ("attribute", "priority");
|
||||
cli.entity ("attribute", "project");
|
||||
cli.entity ("attribute", "recur");
|
||||
cli.entity ("attribute", "scheduled");
|
||||
|
||||
@@ -57,7 +57,7 @@ int main (int argc, char** argv)
|
||||
try
|
||||
{
|
||||
bool infix = true;
|
||||
bool ambiguous = true;
|
||||
bool ambiguous = false;
|
||||
|
||||
// Add a source for constants.
|
||||
Eval e;
|
||||
@@ -77,8 +77,8 @@ int main (int argc, char** argv)
|
||||
<< " -d|--debug Debug mode\n"
|
||||
<< " -i|--infix Infix expression (default)\n"
|
||||
<< " -p|--postfix Postfix expression\n"
|
||||
<< " -a|--ambiguous Choose dates over numbers when ambiguous (default)\n"
|
||||
<< " -n|--noambiguous Choose numbers over dates when ambiguous\n"
|
||||
<< " -a|--ambiguous Choose dates over numbers when ambiguous\n"
|
||||
<< " -n|--noambiguous Choose numbers over dates when ambiguous (default)\n"
|
||||
<< "\n";
|
||||
exit (1);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ set (columns_SRCS Column.cpp Column.h
|
||||
ColMask.cpp ColMask.h
|
||||
ColModified.cpp ColModified.h
|
||||
ColParent.cpp ColParent.h
|
||||
ColPriority.cpp ColPriority.h
|
||||
ColProject.cpp ColProject.h
|
||||
ColRecur.cpp ColRecur.h
|
||||
ColScheduled.cpp ColScheduled.h
|
||||
|
||||
@@ -207,8 +207,6 @@ void ColumnDate::render (
|
||||
color.colorize (
|
||||
rightJustify (
|
||||
Duration (date - now).format (), width)));
|
||||
else
|
||||
lines.push_back (rightJustify ("", width));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class ColumnDate : public Column
|
||||
{
|
||||
public:
|
||||
ColumnDate ();
|
||||
~ColumnDate ();
|
||||
virtual ~ColumnDate ();
|
||||
|
||||
virtual bool validate (std::string&);
|
||||
virtual void measure (Task&, unsigned int&, unsigned int&);
|
||||
|
||||
@@ -83,8 +83,15 @@ void ColumnDepends::measure (Task& task, unsigned int& minimum, unsigned int& ma
|
||||
std::vector <Task> blocking;
|
||||
dependencyGetBlocking (task, blocking);
|
||||
|
||||
if (_style == "indicator") minimum = maximum = utf8_width (context.config.get ("dependency.indicator"));
|
||||
else if (_style == "count") minimum = maximum = 2 + format ((int) blocking.size ()).length ();
|
||||
if (_style == "indicator")
|
||||
{
|
||||
minimum = maximum = utf8_width (context.config.get ("dependency.indicator"));
|
||||
_fixed_width = true;
|
||||
}
|
||||
else if (_style == "count")
|
||||
{
|
||||
minimum = maximum = 2 + format ((int) blocking.size ()).length ();
|
||||
}
|
||||
else if (_style == "default" ||
|
||||
_style == "list")
|
||||
{
|
||||
|
||||
@@ -62,11 +62,16 @@ bool ColumnIMask::validate (std::string& value)
|
||||
// Set the minimum and maximum widths for the value.
|
||||
void ColumnIMask::measure (Task& task, unsigned int& minimum, unsigned int& maximum)
|
||||
{
|
||||
minimum = maximum = task.get ("imask").length ();
|
||||
minimum = maximum = 0;
|
||||
|
||||
if (_style != "default" &&
|
||||
_style != "number")
|
||||
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
|
||||
if (task.has (_name))
|
||||
{
|
||||
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,
|
||||
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)));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -62,10 +62,14 @@ bool ColumnMask::validate (std::string& value)
|
||||
// Set the minimum and maximum widths for the value.
|
||||
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")
|
||||
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
|
||||
if (_style != "default")
|
||||
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -75,7 +79,8 @@ void ColumnMask::render (
|
||||
int width,
|
||||
Color& color)
|
||||
{
|
||||
lines.push_back (color.colorize (task.get ("mask")));
|
||||
if (task.has (_name))
|
||||
lines.push_back (color.colorize (task.get ("mask")));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -62,12 +62,17 @@ bool ColumnParent::validate (std::string& 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;
|
||||
else if (_style == "short") minimum = maximum = 8;
|
||||
else
|
||||
throw format (STRING_COLUMN_BAD_FORMAT, _name, _style);
|
||||
minimum = maximum = 0;
|
||||
|
||||
if (task.has (_name))
|
||||
{
|
||||
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,
|
||||
Color& color)
|
||||
{
|
||||
// f30cb9c3-3fc0-483f-bfb2-3bf134f00694 default
|
||||
// 34f00694 short
|
||||
if (_style == "default" ||
|
||||
_style == "long")
|
||||
if (task.has (_name))
|
||||
{
|
||||
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")
|
||||
{
|
||||
if (task.has (_name))
|
||||
lines.push_back (color.colorize (leftJustify (task.get (_name).substr (28), width)));
|
||||
else
|
||||
lines.push_back (color.colorize (leftJustify ("", width)));
|
||||
else if (_style == "short")
|
||||
{
|
||||
if (task.has (_name))
|
||||
lines.push_back (color.colorize (leftJustify (task.get (_name).substr (28), width)));
|
||||
else
|
||||
lines.push_back (color.colorize (leftJustify ("", width)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user