Compare commits

..

41 Commits

Author SHA1 Message Date
Ingo Karkat
d2e0f6e38d FIX: Support $HOME and $TODOTXT_ACTIONS_DIR containing spaces.
And document a minor discrepancy in action completion to todo.sh.
2011-11-20 15:17:50 +01:00
Ingo Karkat
b1d894f65d Add recently added "shorthelp" built-in command. 2011-11-20 15:17:50 +01:00
Ingo Karkat
f5270be463 ENH: Append task text as shell comment when completing task number.
This is useful for the paranoid before a destructive todo.txt operation. Appending the text as a shell comment doesn't affect the todo.txt command itself, but shows that the task number corresponds to the task you had in mind.
2011-11-20 15:17:45 +01:00
Ingo Karkat
8cba7533b9 Avoid leaking internal variables into the shell + robustness against add-ons.
Use "local" to avoid that the internal completion variables are accessible from the user's shell.
Use "todo.sh command" for the context/project lookups to avoid interference with custom add-ons of the same name, and reset TODOTXT_VERBOSE to avoid adding any message output (currently there is none).
2011-11-20 14:53:18 +01:00
Ingo Karkat
285d5039f2 Add shebang line and check for Bash.
The shebang is ignored when sourcing the script (but still helps many text editors auto-detect the file type), and will cause an error when the script is mistakenly executed.
The Bash check allows to have this called from a generic place (e.g. .profile), and do no harm when under a different shell.
2011-11-20 14:26:52 +01:00
Ingo Karkat
9b67a76833 Do not automatically complete for guessed aliases.
Don't infringe against the principle of least astonishment (they user may have completely unrelated aliases). Rather, if the user sets up his own alias, make him apply the same to todo_completion.
2011-11-20 14:22:48 +01:00
Ingo Karkat
2b0921f4ec Add todo_completion to todo.txt distribution. 2011-11-20 14:20:25 +01:00
Ingo Karkat
202f892e85 Include todo Bash completion from the todo.txt Wiki.
This is f32aba2 of https://github.com/ginatrapani/todo.txt-cli/wiki/Tips-and-Tricks, last edited 30-Oct-2011.
2011-11-20 14:17:22 +01:00
Ingo Karkat
417e86ae7a FIX: Handle special shell characters when filtering TERM.
The double quotes used in the filter_command erroneously expand $VARIABLE, and due to missing quoting in the eval() of filter_command, multiple spaces are condensed into a single space.
Introduce a new function shellquote() to correctly quote each filter TERM.
2011-11-10 14:21:47 -08:00
Ingo Karkat
cb982391de Implement listproj with factored out filtercommand() function.
_list() is way too large and monolithic for many (re-)use cases. As a first step, factor out the building of the filter_command and reuse that for the listproj filtering.
Enhance the listproj test with special cases that show the problems with the previous implementation directly using _list: Option -+, custom final filters, and non-ANSI colors cause it to break.
2011-11-10 14:21:47 -08:00
jmoore
b8244792cc Accept filters for lsprj 2011-11-10 14:21:47 -08:00
Ingo Karkat
a433c5828e shorthelp consistency
- Restore alphabetical order for "addto".
- Keep "depri" shorthand after the long form as all other.
Closes #50

Implement shorthelp listing add-on action one-line usage.
-h and an additional new "shorthelp" action list not just the usage of the built-in actions, but also from add-ons. This assumes that add-ons use the same usage indentation structure as todo.sh. (They should, anyway, for consistency of the full help message.)
Closes #12
2011-11-10 14:16:05 -08:00
Ingo Karkat
7742d3c115 Restructure help text to put built-in and add-on actions together.
I find it annoying that the built-in actions are printed first, and the add-on actions last, although for the user, the distinction is hardly important. Therefore, moving the "options" block first (as it is short and contains the stuff most difficult to memorize), then built-in, then add-on actions.
As environment variables are hardly used in day-to-day operations, only once for customizing the config, they are now omitted by default and only included when -vv is given.
2011-11-10 14:11:31 -08:00
Gina Trapani
7ca2b4c687 Merge pull request #49 from inkarkat/bug-disable-filter-not-propagating
BUG: disable filter not propagating to add-ons
2011-11-10 13:33:46 -08:00
Gina Trapani
239f7234ab Merge pull request #48 from inkarkat/bug-unrestrained-pri-matching
BUG: unrestrained pri "(X)" matching
2011-11-10 13:33:28 -08:00
Ingo Karkat
e3fce6f12b Revert to safer POSIX AWK regexp.
AWK from Ubuntu 8.04 (mawk) doesn't support [[:space:]]; so for backwards compatibility use a plain ASCII space instead.
2011-11-03 18:37:36 +01:00
Ingo Karkat
65d39319f1 TODOTXT_DISABLE_FILTER missing from help text.
Should be in there for consistency; corresponding option is -x.
2011-09-30 09:15:56 +02:00
Ingo Karkat
62d3ff2977 BUG: Option -x isn't propagated to custom actions.
Somehow, no default is set for TODOTXT_DISABLE_FILTER, so that it isn't exported, and therefore does not apply to the sourced actions, so you cannot disable filtering for "myaction" via todo.sh -x myaction.
2011-09-30 09:11:54 +02:00
Ingo Karkat
227b9d2c0a BUG: Pattern "(X) " anywhere hidden with -P.
The regular expression HIDE_PRIORITY_SUBSTITUTION is not anchored, so strings that look like a priority but are not at the beginning are filtered, too.
Anchoring the regexp in the step after the highlighting has been applied is problematic due to the prepended dynamic priority highlighting string, and it also cannot be done before that because highlighting needs the information. Therefore, the filtering is moved into the AWK highlighting itself.
2011-09-23 16:27:30 +02:00
Ingo Karkat
99fa15da36 BUG: Pattern "(X)" anywhere highlighted as prioritized.
According to the "Todo.txt Format" specs, "Rule 1: If a priority exists, it ALWAYS appears first."

Adapt AWK filtering to match priorities only directly after the task number added by the _list processing, and also matching the required trailing space.
2011-09-23 15:40:23 +02:00
Ingo Karkat
72fe73f3d8 nobacktick test: Use literal backtick
* Fix sed error on Mac OS, also ignore entire commented lines.
* With proper quoting, the non-POSIX \d96 escape isn't necessary, and the check should work also on Mac OS.
2011-08-04 10:15:54 -07:00
Ingo Karkat
8f6070e702 Re-applying the listpri stuff still missing from the pull requests. 2011-07-10 22:04:51 +02:00
Ingo Karkat
2891472630 Add test to enforce use of $(...) code style in todo.sh.
Pull request #26 by trajano (e24777fa2c) changed `...` to $(...), but the following commit 7900ad7e1b already added another old-style one. I think the tests can also be used for some simple enforcement of coding style, so here is a first shot at it.

Closes #46
2011-07-09 14:11:10 -07:00
Ingo Karkat
f3af778d3e depri: Check for unprioritized task and print message.
The existing check didn't do much good, and one could deprioritize any normal task without notice. Instead, check that the task to be deprioritized actually has a priority and alert via "TODO: 42 is not prioritized." if that is not the case.
2011-07-09 13:43:36 -07:00
Ingo Karkat
c14788e764 Cosmetics: Add TODO: prefix to todo.txt do message on already done task. 2011-07-09 13:43:26 -07:00
Ingo Karkat
32c84781d2 pri: Check for existing priority and adapt message.
The existing check (as with depri) didn't do much good. Instead, fetch the existing priority and use that information to print more specific messages:
- TODO: 42 re-prioritized from (C) to (A)
- TODO: 42 already prioritized (A)
2011-07-09 13:43:00 -07:00
Ingo Karkat
6e740f748e Consistency: Use /(.)/ as generic pattern for priority in replaceOrPrepend().
Even though Gina's todo.txt syntax reference only mentions uppercase A-Z priorities, this is handled in two different ways in the code. I think the following guideline is useful: For a user-supplied priority (in the listpri and pri commands), use a strict check for A-Z. In general list and edit operations that need to be aware of the optional priority at the beginning of a task, use the general /^(.) / regexp. This allows addons to use different priority-like markers (e.g. "(-) no do"), have them ignored as priorities, but still maintained by replacements.
2011-07-09 13:42:14 -07:00
Ingo Karkat
0fa5f6d1dd BUG: listpri picked up non-priority patterns.
The regexp for the priority wasn't anchored to the beginning of the task. (As the filtering is done inside the _list pipeline, the task number has already been prepended.)
Also, by passing the regexp directly to _list, a case-insensitive search was performed, so despite [A-Z], lowercase characters were picked up, too. Need to make use of post_filter_command to inject a separate, case-sensitive grep into the pipeline.

Bonus: Added test for highlighting of listpri command.
2011-07-09 13:41:20 -07:00
Ingo Karkat
f8b66f117a ENH: Allow listpri filtering via TERM.
This even simplified the argument handling, since there can be no invalid priority any more; all other strings are taken as TERMs. And the check for empty ${1:-} was superfluous, anyway. Apart from these simplifications, it's basically just passing $@ to _list.
2011-07-09 13:36:14 -07:00
Ingo Karkat
b00ca1074a Simplified check for done task.
Use simple comparison with slice of string (already used e.g. in _list()) instead of grep -c pipeline.

Closes #42
2011-07-07 23:29:45 -07:00
Ingo Karkat
a60dfb668d Perform cleaninput() filtering without tr.
Again, Bash's global pattern substitution can be used. This only depends on the "extquote" shell option, which is set by default, but we set this just to be sure.
2011-07-07 23:14:11 -07:00
Ingo Karkat
899687f0ef BUG: Multiple whitespace was condensed, CR/LF not turned to space.
Missing quoting inside cleaninput() condensed multiple subsequent spaces into a single space, even when the user took pains to preserve whitespace by properly quoting the task in the shell.
The 'tr' command completely removed CR and LF characters instead of replacing them with a single space.
Add test cases for the whitespace handling to the add, append, prepend and replace actions.
2011-07-07 23:14:11 -07:00
Ingo Karkat
301dbcf297 Expose cleaninput() for use in addons.
Despite its hard-coded use of $input, this can be useful in addons, too.
(I, for example, use this in a "todo.sh subst" addon that delegates to the "todo.sh replace" action after performing a sed-style replacement on the passed pattern and replacement.)
2011-07-07 23:13:47 -07:00
Ingo Karkat
e79b1629f5 Perform cleaninput() escaping without sed.
No need for invoking sed; Bash's global pattern substitution can be used.
2011-07-07 23:13:47 -07:00
Ingo Karkat
a4db95166d Escape the substitution separator in cleaninput().
Improving on the previous fix and commit, no search for an unused substitution separator is actually needed; sed supports escaping of the substitution separator. Revert the $inputSep abstraction in favor of the former, hard-coded "|" character.
2011-07-07 23:13:47 -07:00
Ingo Karkat
afe6d9dfd5 FIX: cleaninput() for sed-replacement needs more escaping and unique separator.
Commit 8e4364f5e1 removed the deletion of the "|" character from cleaninput. That was okay for the cleaninput() use in _addto(), but not in those cases that used $input for replacement via sed.

Added corresponding tests for replace, append and prepend actions similar to what was added for the add action in the above commit.

To really fix the problem (and not just remove all "|" characters from the text), a separator character must be found that is not part of $input, and this must be used in the sed expression. As cleaninput() already modifies the global $input variable, another $inputSep global variable is used to pass back this information.

In addition, backslashes must be escaped in $input, or replacements like \1 wreak havoc.
2011-07-07 23:13:47 -07:00
Ingo Karkat
ab705cd670 Configure cleaninput() sed-escaping via argument instead of magic words.
Encoding the actions that require the additional sed-escaping inside cleaninput() is cumbersome and error-prone. Instead, let the calling action tell cleaninput() that it wants this.
2011-07-07 23:13:47 -07:00
Ingo Karkat
e0ad2292a2 Remove no-op passing of $input to cleaninput().
The function actually uses and modifies the global variable directly.
2011-07-07 23:12:35 -07:00
Ingo Karkat
c4670b6502 Made replace test sessions independent from each other.
When the tests depend on the todo.txt contents from the previous sessions, errors will cascade and make it more difficult to pinpoint the problem.
2011-07-07 23:12:35 -07:00
Tom Scogland
7900ad7e1b Added sed line to allow priorities to be added on the command line with auto add date enabled.
Inserted test for this case in the t1010-add-date.sh test case.
2011-07-07 22:55:08 -07:00
Archimedes Trajano
e24777fa2c Changed backquotes to use $() instead.
$(...) has superceded the `...` notation.  This can be found by
searching in Google "command substitution superseded"

Closes #28
2011-07-07 22:05:11 -07:00
12 changed files with 541 additions and 179 deletions

View File

@@ -13,7 +13,7 @@ VERSION-FILE: .FORCE-VERSION-FILE
todo.sh: VERSION-FILE todo.sh: VERSION-FILE
# For packaging # For packaging
DISTFILES := todo.cfg DISTFILES := todo.cfg todo_completion
DISTNAME=todo.txt_cli-$(VERSION) DISTNAME=todo.txt_cli-$(VERSION)
dist: $(DISTFILES) todo.sh dist: $(DISTFILES) todo.sh

16
tests/t0100-code-nobacktick.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
test_description='no old-style backtick command substitution
This test checks the todo.sh script itself for occurrences
of old-style backtick command substitution, which should be
replaced with $(...).
On failure, it will print each offending line number and line.
'
. ./test-lib.sh
test_todo_session 'no old-style backtick command substitution' <<EOF
>>> sed -n -e 's/\(^\|[ \t]\)#.*//' -e '/\`/{' -e '=;p' -e '}' "$(which todo.sh)"
EOF
test_done

View File

@@ -21,6 +21,22 @@ TODO: 1 added.
TODO: 1 of 1 tasks shown TODO: 1 of 1 tasks shown
EOF EOF
test_todo_session 'cmd line first day with priority' <<EOF
>>> todo.sh -pt add '(A) notice the daisies'
2 (A) 2009-02-13 notice the daisies
TODO: 2 added.
>>> todo.sh -p list
2 (A) 2009-02-13 notice the daisies
1 2009-02-13 notice the daisies
--
TODO: 2 of 2 tasks shown
>>> todo.sh -npf del 2
2 (A) 2009-02-13 notice the daisies
TODO: 2 deleted.
EOF
test_tick test_tick
test_todo_session 'cmd line second day' <<EOF test_todo_session 'cmd line second day' <<EOF

View File

@@ -53,9 +53,28 @@ TODO: 2 prioritized (C).
-- --
TODO: 3 of 3 tasks shown TODO: 3 of 3 tasks shown
>>> todo.sh add "smell the coffee +wakeup"
4 smell the coffee +wakeup
TODO: 4 added.
>>> todo.sh -p list
1 (B) smell the uppercase Roses +flowers @outside
2 (C) notice the sunflowers
4 smell the coffee +wakeup
3 stop
--
TODO: 4 of 4 tasks shown
EOF
cat > todo.txt <<EOF
(B) smell the uppercase Roses +flowers @outside
(C) notice the sunflowers
stop
EOF
test_todo_session 'reprioritize' <<EOF
>>> todo.sh pri 2 A >>> todo.sh pri 2 A
2 (A) notice the sunflowers 2 (A) notice the sunflowers
TODO: 2 prioritized (A). TODO: 2 re-prioritized from (C) to (A).
>>> todo.sh -p list >>> todo.sh -p list
2 (A) notice the sunflowers 2 (A) notice the sunflowers
@@ -66,25 +85,13 @@ TODO: 3 of 3 tasks shown
>>> todo.sh pri 2 a >>> todo.sh pri 2 a
2 (A) notice the sunflowers 2 (A) notice the sunflowers
TODO: 2 prioritized (A). TODO: 2 already prioritized (A).
>>> todo.sh -p listpri
2 (A) notice the sunflowers
1 (B) smell the uppercase Roses +flowers @outside
--
TODO: 2 of 3 tasks shown
>>> todo.sh add "smell the coffee +wakeup"
4 smell the coffee +wakeup
TODO: 4 added.
>>> todo.sh -p list >>> todo.sh -p list
2 (A) notice the sunflowers 2 (A) notice the sunflowers
1 (B) smell the uppercase Roses +flowers @outside 1 (B) smell the uppercase Roses +flowers @outside
4 smell the coffee +wakeup
3 stop 3 stop
-- --
TODO: 4 of 4 tasks shown TODO: 3 of 3 tasks shown
EOF EOF
test_done test_done

95
tests/t1250-listpri.sh Executable file
View File

@@ -0,0 +1,95 @@
#!/bin/sh
test_description='list priority functionality
'
. ./test-lib.sh
cat > todo.txt <<EOF
(B) smell the uppercase Roses +flowers @outside
(C) notice the sunflowers
stop
EOF
test_todo_session 'basic listpri' <<EOF
>>> todo.sh listpri A
--
TODO: 0 of 3 tasks shown
>>> todo.sh -p listpri c
2 (C) notice the sunflowers
--
TODO: 1 of 3 tasks shown
EOF
test_todo_session 'listpri highlighting' <<EOF
>>> todo.sh listpri
1 (B) smell the uppercase Roses +flowers @outside
2 (C) notice the sunflowers
--
TODO: 2 of 3 tasks shown
EOF
cat > todo.txt <<EOF
(B) smell the uppercase Roses +flowers @outside
(C) notice the sunflowers
(m)others will notice this
(n) not a prioritized task
notice the (C)opyright
EOF
test_todo_session 'listpri filtering priorities' <<EOF
>>> todo.sh -p listpri
1 (B) smell the uppercase Roses +flowers @outside
2 (C) notice the sunflowers
--
TODO: 2 of 5 tasks shown
>>> todo.sh -p listpri b
1 (B) smell the uppercase Roses +flowers @outside
--
TODO: 1 of 5 tasks shown
>>> todo.sh -p listpri c
2 (C) notice the sunflowers
--
TODO: 1 of 5 tasks shown
>>> todo.sh -p listpri m
--
TODO: 0 of 5 tasks shown
>>> todo.sh -p listpri n
--
TODO: 0 of 5 tasks shown
EOF
cat > todo.txt <<EOF
(B) ccc xxx this line should be third.
ccc xxx this line should be third.
(A) aaa zzz this line should be first.
aaa zzz this line should be first.
(B) bbb yyy this line should be second.
bbb yyy this line should be second.
EOF
test_todo_session 'listpri filtering of TERM' <<EOF
>>> todo.sh -p listpri "should be"
3 (A) aaa zzz this line should be first.
5 (B) bbb yyy this line should be second.
1 (B) ccc xxx this line should be third.
--
TODO: 3 of 6 tasks shown
>>> todo.sh -p listpri a "should be"
3 (A) aaa zzz this line should be first.
--
TODO: 1 of 6 tasks shown
>>> todo.sh -p listpri b second
5 (B) bbb yyy this line should be second.
--
TODO: 1 of 6 tasks shown
>>> todo.sh -p listpri x "should be"
--
TODO: 0 of 6 tasks shown
EOF
test_done

42
tests/t1260-listprj.sh Executable file
View File

@@ -0,0 +1,42 @@
#!/bin/sh
test_description='list project functionality
'
. ./test-lib.sh
cat > todo.txt <<EOF
(B) smell the uppercase Roses +roses @outside +shared
(C) notice the sunflowers +sunflowers @garden +shared +landscape
stop
EOF
test_todo_session 'basic listproj' <<EOF
>>> todo.sh listproj
+landscape
+roses
+shared
+sunflowers
EOF
test_todo_session 'listproj with context' <<EOF
>>> todo.sh listproj @garden
+landscape
+shared
+sunflowers
EOF
TEST_TODO_CUSTOM=todo-custom.cfg
cat todo.cfg > "$TEST_TODO_CUSTOM"
cat >> "$TEST_TODO_CUSTOM" <<'EOF'
export DEFAULT='</color>'
export PRI_B='<color type=green>'
export PRI_C='<color type=blue>'
export TODOTXT_FINAL_FILTER='grep -i roses'
EOF
test_todo_session 'listproj with context special cases' <<EOF
>>> todo.sh -+ -d "$TEST_TODO_CUSTOM" listproj @garden
+landscape
+shared
+sunflowers
EOF
test_done

View File

@@ -94,6 +94,40 @@ TODO: 1 of 3 tasks shown
TODO: 1 of 3 tasks shown TODO: 1 of 3 tasks shown
EOF EOF
#
# check the filtering of TERM containing characters that are special to the
# shell, like variables, quotes, and multiple subsequent spaces.
#
cat > todo.txt <<'EOF'
earn some pennies
earn some $$
earn some "money"
get money from O'Brian
just get money!
EOF
test_todo_session 'checking filtering of special characters' <<'EOF'
>>> todo.sh ls '$$'
2 earn some $$
--
TODO: 1 of 5 tasks shown
>>> todo.sh ls '"money"'
3 earn some "money"
--
TODO: 1 of 5 tasks shown
>>> todo.sh ls "O'Brian"
4 get money from O'Brian
--
TODO: 1 of 5 tasks shown
>>> todo.sh ls "get money"
5 just get money!
--
TODO: 1 of 5 tasks shown
EOF
# #
# check the x command line option # check the x command line option
# #
@@ -142,7 +176,7 @@ cat > todo.txt <<EOF
(D) @con02 +prj03 -- Some project 03 task, pri D (D) @con02 +prj03 -- Some project 03 task, pri D
(D) @con02 +prj04 -- Some project 04 task, pri D (D) @con02 +prj04 -- Some project 04 task, pri D
@con01 +prj01 -- Some project 01 task, no priority @con01 +prj01 -- Some project 01 task, no priority
@con01 +prj02 -- Some project 02 task, no priority @con01 +prj02 -- Some project(S) 02 task, no priority
@con02 +prj03 -- Some project 03 task, no priorty @con02 +prj03 -- Some project 03 task, no priorty
@con02 +prj04 -- Some project 04 task, no priority @con02 +prj04 -- Some project 04 task, no priority
EOF EOF
@@ -165,7 +199,7 @@ test_todo_session 'plain mode option' <<EOF
15 (D) @con02 +prj03 -- Some project 03 task, pri D 15 (D) @con02 +prj03 -- Some project 03 task, pri D
16 (D) @con02 +prj04 -- Some project 04 task, pri D 16 (D) @con02 +prj04 -- Some project 04 task, pri D
17 @con01 +prj01 -- Some project 01 task, no priority 17 @con01 +prj01 -- Some project 01 task, no priority
18 @con01 +prj02 -- Some project 02 task, no priority 18 @con01 +prj02 -- Some project(S) 02 task, no priority
19 @con02 +prj03 -- Some project 03 task, no priorty 19 @con02 +prj03 -- Some project 03 task, no priorty
20 @con02 +prj04 -- Some project 04 task, no priority 20 @con02 +prj04 -- Some project 04 task, no priority
-- --
@@ -189,7 +223,7 @@ TODO: 20 of 20 tasks shown
15 (D) @con02 +prj03 -- Some project 03 task, pri D 15 (D) @con02 +prj03 -- Some project 03 task, pri D
16 (D) @con02 +prj04 -- Some project 04 task, pri D 16 (D) @con02 +prj04 -- Some project 04 task, pri D
17 @con01 +prj01 -- Some project 01 task, no priority 17 @con01 +prj01 -- Some project 01 task, no priority
18 @con01 +prj02 -- Some project 02 task, no priority 18 @con01 +prj02 -- Some project(S) 02 task, no priority
19 @con02 +prj03 -- Some project 03 task, no priorty 19 @con02 +prj03 -- Some project 03 task, no priorty
20 @con02 +prj04 -- Some project 04 task, no priority 20 @con02 +prj04 -- Some project 04 task, no priority
-- --
@@ -217,7 +251,7 @@ cat > todo.txt <<EOF
(D) @con02 +prj03 -- Some project 03 task, pri D (D) @con02 +prj03 -- Some project 03 task, pri D
(D) @con02 +prj04 -- Some project 04 task, pri D (D) @con02 +prj04 -- Some project 04 task, pri D
@con01 +prj01 -- Some project 01 task, no priority @con01 +prj01 -- Some project 01 task, no priority
@con01 +prj02 -- Some project 02 task, no priority @con01 +prj02 -- Some project(S) 02 task, no priority
@con02 +prj03 -- Some project 03 task, no priorty @con02 +prj03 -- Some project 03 task, no priorty
@con02 +prj04 -- Some project 04 task, no priority @con02 +prj04 -- Some project 04 task, no priority
EOF EOF
@@ -240,7 +274,7 @@ test_todo_session 'context, project, and priority suppression' <<EOF
15 (D) @con02 +prj03 -- Some project 03 task, pri D 15 (D) @con02 +prj03 -- Some project 03 task, pri D
16 (D) @con02 +prj04 -- Some project 04 task, pri D 16 (D) @con02 +prj04 -- Some project 04 task, pri D
17 @con01 +prj01 -- Some project 01 task, no priority 17 @con01 +prj01 -- Some project 01 task, no priority
18 @con01 +prj02 -- Some project 02 task, no priority 18 @con01 +prj02 -- Some project(S) 02 task, no priority
19 @con02 +prj03 -- Some project 03 task, no priorty 19 @con02 +prj03 -- Some project 03 task, no priorty
20 @con02 +prj04 -- Some project 04 task, no priority 20 @con02 +prj04 -- Some project 04 task, no priority
-- --
@@ -256,7 +290,7 @@ TODO: 20 of 20 tasks shown
13 (D) @con01 +prj01 -- Some project 01 task, pri D 13 (D) @con01 +prj01 -- Some project 01 task, pri D
14 (D) @con01 +prj02 -- Some project 02 task, pri D 14 (D) @con01 +prj02 -- Some project 02 task, pri D
17 @con01 +prj01 -- Some project 01 task, no priority 17 @con01 +prj01 -- Some project 01 task, no priority
18 @con01 +prj02 -- Some project 02 task, no priority 18 @con01 +prj02 -- Some project(S) 02 task, no priority
-- --
TODO: 10 of 20 tasks shown TODO: 10 of 20 tasks shown
@@ -270,7 +304,7 @@ TODO: 10 of 20 tasks shown
13 @con01 +prj01 -- Some project 01 task, pri D 13 @con01 +prj01 -- Some project 01 task, pri D
14 @con01 +prj02 -- Some project 02 task, pri D 14 @con01 +prj02 -- Some project 02 task, pri D
17 @con01 +prj01 -- Some project 01 task, no priority 17 @con01 +prj01 -- Some project 01 task, no priority
18 @con01 +prj02 -- Some project 02 task, no priority 18 @con01 +prj02 -- Some project(S) 02 task, no priority
-- --
TODO: 10 of 20 tasks shown TODO: 10 of 20 tasks shown
@@ -284,7 +318,7 @@ TODO: 10 of 20 tasks shown
13 (D) @con01 -- Some project 01 task, pri D 13 (D) @con01 -- Some project 01 task, pri D
14 (D) @con01 -- Some project 02 task, pri D 14 (D) @con01 -- Some project 02 task, pri D
17 @con01 -- Some project 01 task, no priority 17 @con01 -- Some project 01 task, no priority
18 @con01 -- Some project 02 task, no priority 18 @con01 -- Some project(S) 02 task, no priority
-- --
TODO: 10 of 20 tasks shown TODO: 10 of 20 tasks shown
@@ -298,7 +332,7 @@ TODO: 10 of 20 tasks shown
13 (D) +prj01 -- Some project 01 task, pri D 13 (D) +prj01 -- Some project 01 task, pri D
14 (D) +prj02 -- Some project 02 task, pri D 14 (D) +prj02 -- Some project 02 task, pri D
17 +prj01 -- Some project 01 task, no priority 17 +prj01 -- Some project 01 task, no priority
18 +prj02 -- Some project 02 task, no priority 18 +prj02 -- Some project(S) 02 task, no priority
-- --
TODO: 10 of 20 tasks shown TODO: 10 of 20 tasks shown
@@ -312,7 +346,7 @@ TODO: 10 of 20 tasks shown
13 +prj01 -- Some project 01 task, pri D 13 +prj01 -- Some project 01 task, pri D
14 +prj02 -- Some project 02 task, pri D 14 +prj02 -- Some project 02 task, pri D
17 +prj01 -- Some project 01 task, no priority 17 +prj01 -- Some project 01 task, no priority
18 +prj02 -- Some project 02 task, no priority 18 +prj02 -- Some project(S) 02 task, no priority
-- --
TODO: 10 of 20 tasks shown TODO: 10 of 20 tasks shown
@@ -326,7 +360,7 @@ TODO: 10 of 20 tasks shown
13 (D) @con01 +prj01 -- Some project 01 task, pri D 13 (D) @con01 +prj01 -- Some project 01 task, pri D
14 (D) @con01 +prj02 -- Some project 02 task, pri D 14 (D) @con01 +prj02 -- Some project 02 task, pri D
17 @con01 +prj01 -- Some project 01 task, no priority 17 @con01 +prj01 -- Some project 01 task, no priority
18 @con01 +prj02 -- Some project 02 task, no priority 18 @con01 +prj02 -- Some project(S) 02 task, no priority
-- --
TODO: 10 of 20 tasks shown TODO: 10 of 20 tasks shown
@@ -340,7 +374,7 @@ TODO: 10 of 20 tasks shown
13 -- Some project 01 task, pri D 13 -- Some project 01 task, pri D
14 -- Some project 02 task, pri D 14 -- Some project 02 task, pri D
17 -- Some project 01 task, no priority 17 -- Some project 01 task, no priority
18 -- Some project 02 task, no priority 18 -- Some project(S) 02 task, no priority
-- --
TODO: 10 of 20 tasks shown TODO: 10 of 20 tasks shown
EOF EOF

View File

@@ -166,4 +166,20 @@ test_todo_session 'highlighting with hidden contexts/projects' <<EOF
TODO: 4 of 4 tasks shown TODO: 4 of 4 tasks shown
EOF EOF
# check that priorities are only matched at the start of the task
#
cat > todo.txt <<EOF
(D) some prioritized task
not prioritized
should not be seen as PRIORITIZE(D) task
EOF
test_todo_session 'highlighting priority position' <<EOF
>>> todo.sh ls
1 (D) some prioritized task
2 not prioritized
3 should not be seen as PRIORITIZE(D) task
--
TODO: 3 of 3 tasks shown
EOF
test_done test_done

View File

@@ -81,6 +81,6 @@ test_todo_session 'fail multiple do attempts' <<EOF
TODO: 3 marked as done. TODO: 3 marked as done.
>>> todo.sh -a do 3 >>> todo.sh -a do 3
3 is already marked done TODO: 3 is already marked done.
EOF EOF
test_done test_done

View File

@@ -68,4 +68,30 @@ TODO: 2 deprioritized.
TODO: 3 of 3 tasks shown TODO: 3 of 3 tasks shown
EOF EOF
cat > todo.txt <<EOF
(B) smell the uppercase Roses +flowers @outside
(A) notice the sunflowers
stop
EOF
test_todo_session 'depriority of unprioritized task' <<EOF
>>> todo.sh -p list
2 (A) notice the sunflowers
1 (B) smell the uppercase Roses +flowers @outside
3 stop
--
TODO: 3 of 3 tasks shown
>>> todo.sh depri 3 2
TODO: 3 is not prioritized.
2 notice the sunflowers
TODO: 2 deprioritized.
>>> todo.sh -p list
1 (B) smell the uppercase Roses +flowers @outside
2 notice the sunflowers
3 stop
--
TODO: 3 of 3 tasks shown
EOF
test_done test_done

346
todo.sh
View File

@@ -44,39 +44,113 @@ shorthelp()
Actions: Actions:
add|a "THING I NEED TO DO +project @context" add|a "THING I NEED TO DO +project @context"
addto DEST "TEXT TO ADD"
addm "THINGS I NEED TO DO addm "THINGS I NEED TO DO
MORE THINGS I NEED TO DO" MORE THINGS I NEED TO DO"
addto DEST "TEXT TO ADD"
append|app ITEM# "TEXT TO APPEND" append|app ITEM# "TEXT TO APPEND"
archive archive
command [ACTIONS] command [ACTIONS]
del|rm ITEM# [TERM] del|rm ITEM# [TERM]
dp|depri ITEM#[, ITEM#, ITEM#, ...] depri|dp ITEM#[, ITEM#, ITEM#, ...]
do ITEM#[, ITEM#, ITEM#, ...] do ITEM#[, ITEM#, ITEM#, ...]
help help
list|ls [TERM...] list|ls [TERM...]
listall|lsa [TERM...] listall|lsa [TERM...]
listcon|lsc listcon|lsc
listfile|lf SRC [TERM...] listfile|lf SRC [TERM...]
listpri|lsp [PRIORITY] listpri|lsp [PRIORITY] [TERM...]
listproj|lsprj listproj|lsprj [TERM...]
move|mv ITEM# DEST [SRC] move|mv ITEM# DEST [SRC]
prepend|prep ITEM# "TEXT TO PREPEND" prepend|prep ITEM# "TEXT TO PREPEND"
pri|p ITEM# PRIORITY pri|p ITEM# PRIORITY
replace ITEM# "UPDATED TODO" replace ITEM# "UPDATED TODO"
report report
shorthelp
EndHelp
# Only list the one-line usage from the add-on actions. This assumes that
# add-ons use the same usage indentation structure as todo.sh.
addonHelp | grep -e '^ Add-on Actions:' -e '^ [[:alpha:]]'
cat <<-EndHelpFooter
See "help" for more details. See "help" for more details.
EndHelp EndHelpFooter
exit 0 exit 0
} }
help() help()
{ {
cat <<-EndHelp cat <<-EndOptionsHelp
Usage: $oneline_usage Usage: $oneline_usage
Actions: Options:
-@
Hide context names in list output. Use twice to show context
names (default).
-+
Hide project names in list output. Use twice to show project
names (default).
-c
Color mode
-d CONFIG_FILE
Use a configuration file other than the default ~/.todo/config
-f
Forces actions without confirmation or interactive input
-h
Display a short help message; same as action "shorthelp"
-p
Plain mode turns off colors
-P
Hide priority labels in list output. Use twice to show
priority labels (default).
-a
Don't auto-archive tasks automatically on completion
-A
Auto-archive tasks automatically on completion
-n
Don't preserve line numbers; automatically remove blank lines
on task deletion
-N
Preserve line numbers
-t
Prepend the current date to a task automatically
when it's added.
-T
Do not prepend the current date to a task automatically
when it's added.
-v
Verbose mode turns on confirmation messages
-vv
Extra verbose mode prints some debugging information and
additional help text
-V
Displays version, license and credits
-x
Disables TODOTXT_FINAL_FILTER
EndOptionsHelp
[ $TODOTXT_VERBOSE -gt 1 ] && cat <<-EndVerboseHelp
Environment variables:
TODOTXT_AUTO_ARCHIVE is same as option -a (0)/-A (1)
TODOTXT_CFG_FILE=CONFIG_FILE is same as option -d CONFIG_FILE
TODOTXT_FORCE=1 is same as option -f
TODOTXT_PRESERVE_LINE_NUMBERS is same as option -n (0)/-N (1)
TODOTXT_PLAIN is same as option -p (1)/-c (0)
TODOTXT_DATE_ON_ADD is same as option -t (1)/-T (0)
TODOTXT_VERBOSE=1 is same as option -v
TODOTXT_DISABLE_FILTER=1 is same as option -x
TODOTXT_DEFAULT_ACTION="" run this when called with no arguments
TODOTXT_SORT_COMMAND="sort ..." customize list output
TODOTXT_FINAL_FILTER="sed ..." customize list after color, P@+ hiding
EndVerboseHelp
cat <<-EndActionsHelp
Built-in Actions:
add "THING I NEED TO DO +project @context" add "THING I NEED TO DO +project @context"
a "THING I NEED TO DO +project @context" a "THING I NEED TO DO +project @context"
Adds THING I NEED TO DO to your todo.txt file on its own line. Adds THING I NEED TO DO to your todo.txt file on its own line.
@@ -143,10 +217,11 @@ help()
sorted by priority with line numbers. If TERM specified, lists sorted by priority with line numbers. If TERM specified, lists
all lines that contain TERM in SRC file. all lines that contain TERM in SRC file.
listpri [PRIORITY] listpri [PRIORITY] [TERM...]
lsp [PRIORITY] lsp [PRIORITY] [TERM...]
Displays all tasks prioritized PRIORITY. Displays all tasks prioritized PRIORITY.
If no PRIORITY specified, lists all prioritized tasks. If no PRIORITY specified, lists all prioritized tasks.
If TERM specified, lists only prioritized tasks that contain TERM.
listproj listproj
lsprj lsprj
@@ -176,81 +251,33 @@ help()
report report
Adds the number of open tasks and done tasks to report.txt. Adds the number of open tasks and done tasks to report.txt.
shorthelp
List the one-line usage of all built-in and add-on actions.
Options: EndActionsHelp
-@
Hide context names in list output. Use twice to show context
names (default).
-+
Hide project names in list output. Use twice to show project
names (default).
-c
Color mode
-d CONFIG_FILE
Use a configuration file other than the default ~/.todo/config
-f
Forces actions without confirmation or interactive input
-h
Display a short help message
-p
Plain mode turns off colors
-P
Hide priority labels in list output. Use twice to show
priority labels (default).
-a
Don't auto-archive tasks automatically on completion
-A
Auto-archive tasks automatically on completion
-n
Don't preserve line numbers; automatically remove blank lines
on task deletion
-N
Preserve line numbers
-t
Prepend the current date to a task automatically
when it's added.
-T
Do not prepend the current date to a task automatically
when it's added.
-v
Verbose mode turns on confirmation messages
-vv
Extra verbose mode prints some debugging information
-V
Displays version, license and credits
-x
Disables TODOTXT_FINAL_FILTER
addonHelp
exit 1
}
Environment variables: addonHelp()
TODOTXT_AUTO_ARCHIVE is same as option -a (0)/-A (1) {
TODOTXT_CFG_FILE=CONFIG_FILE is same as option -d CONFIG_FILE if [ -d "$TODO_ACTIONS_DIR" ]; then
TODOTXT_FORCE=1 is same as option -f didPrintAddonActionsHeader=
TODOTXT_PRESERVE_LINE_NUMBERS is same as option -n (0)/-N (1)
TODOTXT_PLAIN is same as option -p (1)/-c (0)
TODOTXT_DATE_ON_ADD is same as option -t (1)/-T (0)
TODOTXT_VERBOSE=1 is same as option -v
TODOTXT_DEFAULT_ACTION="" run this when called with no arguments
TODOTXT_SORT_COMMAND="sort ..." customize list output
TODOTXT_FINAL_FILTER="sed ..." customize list after color, P@+ hiding
EndHelp
if [ -d "$TODO_ACTIONS_DIR" ]
then
echo ""
for action in "$TODO_ACTIONS_DIR"/* for action in "$TODO_ACTIONS_DIR"/*
do do
if [ -f "$action" -a -x "$action" ] if [ -f "$action" -a -x "$action" ]; then
then if [ ! "$didPrintAddonActionsHeader" ]; then
cat <<-EndAddonActionsHeader
Add-on Actions:
EndAddonActionsHeader
didPrintAddonActionsHeader=1
fi
"$action" usage "$action" usage
fi fi
done done
echo ""
fi fi
exit 1
} }
die() die()
@@ -325,8 +352,8 @@ replaceOrPrepend()
cleaninput "for sed" cleaninput "for sed"
# Retrieve existing priority and prepended date # Retrieve existing priority and prepended date
priority=$(sed -e "$item!d" -e $item's/^\(([A-Z]) \)\{0,1\}\([0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\} \)\{0,1\}.*/\1/' "$TODO_FILE") priority=$(sed -e "$item!d" -e $item's/^\((.) \)\{0,1\}\([0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\} \)\{0,1\}.*/\1/' "$TODO_FILE")
prepdate=$(sed -e "$item!d" -e $item's/^\(([A-Z]) \)\{0,1\}\([0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\} \)\{0,1\}.*/\2/' "$TODO_FILE") prepdate=$(sed -e "$item!d" -e $item's/^\((.) \)\{0,1\}\([0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\} \)\{0,1\}.*/\2/' "$TODO_FILE")
if [ "$prepdate" -a "$action" = "replace" ] && [ "$(echo "$input"|sed -e 's/^\([0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\}\)\{0,1\}.*/\1/')" ]; then if [ "$prepdate" -a "$action" = "replace" ] && [ "$(echo "$input"|sed -e 's/^\([0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\}\)\{0,1\}.*/\1/')" ]; then
# If the replaced text starts with a date, it will replace the existing # If the replaced text starts with a date, it will replace the existing
@@ -417,7 +444,10 @@ do
OVR_TODOTXT_FORCE=1 OVR_TODOTXT_FORCE=1
;; ;;
h ) h )
shorthelp # Short-circuit option parsing and forward to the action.
# Cannot just invoke shorthelp() because we need the configuration
# processed to locate the add-on actions directory.
set -- '-h' 'shorthelp'
;; ;;
n ) n )
OVR_TODOTXT_PRESERVE_LINE_NUMBERS=0 OVR_TODOTXT_PRESERVE_LINE_NUMBERS=0
@@ -473,6 +503,7 @@ TODOTXT_AUTO_ARCHIVE=${TODOTXT_AUTO_ARCHIVE:-1}
TODOTXT_DATE_ON_ADD=${TODOTXT_DATE_ON_ADD:-0} TODOTXT_DATE_ON_ADD=${TODOTXT_DATE_ON_ADD:-0}
TODOTXT_DEFAULT_ACTION=${TODOTXT_DEFAULT_ACTION:-} TODOTXT_DEFAULT_ACTION=${TODOTXT_DEFAULT_ACTION:-}
TODOTXT_SORT_COMMAND=${TODOTXT_SORT_COMMAND:-env LC_COLLATE=C sort -f -k2} TODOTXT_SORT_COMMAND=${TODOTXT_SORT_COMMAND:-env LC_COLLATE=C sort -f -k2}
TODOTXT_DISABLE_FILTER=${TODOTXT_DISABLE_FILTER:-}
TODOTXT_FINAL_FILTER=${TODOTXT_FINAL_FILTER:-cat} TODOTXT_FINAL_FILTER=${TODOTXT_FINAL_FILTER:-cat}
# Export all TODOTXT_* variables # Export all TODOTXT_* variables
@@ -532,7 +563,7 @@ export SENTENCE_DELIMITERS=',.:;'
} }
[ -e "$TODOTXT_CFG_FILE" ] || { [ -e "$TODOTXT_CFG_FILE" ] || {
CFG_FILE_ALT=`dirname "$0"`"/todo.cfg" CFG_FILE_ALT=$(dirname "$0")"/todo.cfg"
if [ -e "$CFG_FILE_ALT" ] if [ -e "$CFG_FILE_ALT" ]
then then
@@ -619,8 +650,8 @@ _addto() {
cleaninput cleaninput
if [[ $TODOTXT_DATE_ON_ADD = 1 ]]; then if [[ $TODOTXT_DATE_ON_ADD = 1 ]]; then
now=`date '+%Y-%m-%d'` now=$(date '+%Y-%m-%d')
input="$now $input" input=$(echo "$input" | sed -e 's/^\(([A-Z]) \)\{0,1\}/\1'"$now /")
fi fi
echo "$input" >> "$file" echo "$input" >> "$file"
if [ $TODOTXT_VERBOSE -gt 0 ]; then if [ $TODOTXT_VERBOSE -gt 0 ]; then
@@ -632,6 +663,42 @@ _addto() {
fi fi
} }
shellquote()
{
typeset -r qq=\'; printf %s\\n "'${1//\'/${qq}\\${qq}${qq}}'";
}
filtercommand()
{
filter=${1:-}
shift
post_filter=${1:-}
shift
for search_term
do
## See if the first character of $search_term is a dash
if [ "${search_term:0:1}" != '-' ]
then
## First character isn't a dash: hide lines that don't match
## this $search_term
filter="${filter:-}${filter:+ | }grep -i $(shellquote "$search_term")"
else
## First character is a dash: hide lines that match this
## $search_term
#
## Remove the first character (-) before adding to our filter command
filter="${filter:-}${filter:+ | }grep -v -i '$(shellquote "${search_term:1}")'"
fi
done
[ -n "$post_filter" ] && {
filter="${filter:-}${filter:+ | }${post_filter:-}"
}
printf %s "$filter"
}
_list() { _list() {
local FILE="$1" local FILE="$1"
## If the file starts with a "/" use absolute path. Otherwise, ## If the file starts with a "/" use absolute path. Otherwise,
@@ -655,32 +722,8 @@ _list() {
## Get our search arguments, if any ## Get our search arguments, if any
shift ## was file name, new $1 is first search term shift ## was file name, new $1 is first search term
## Prefix the filter_command with the pre_filter_command ## Build the filter.
filter_command="${pre_filter_command:-}" filter_command=$(filtercommand "${pre_filter_command:-}" "${post_filter_command:-}" "$@")
for search_term
do
## See if the first character of $search_term is a dash
if [ "${search_term:0:1}" != '-' ]
then
## First character isn't a dash: hide lines that don't match
## this $search_term
filter_command="${filter_command:-} ${filter_command:+|} \
grep -i \"$search_term\" "
else
## First character is a dash: hide lines that match this
## $search_term
#
## Remove the first character (-) before adding to our filter command
filter_command="${filter_command:-} ${filter_command:+|} \
grep -v -i \"${search_term:1}\" "
fi
done
## If post_filter_command is set, append it to the filter_command
[ -n "$post_filter_command" ] && {
filter_command="${filter_command:-}${filter_command:+ | }${post_filter_command:-}"
}
## Figure out how much padding we need to use ## Figure out how much padding we need to use
## We need one level of padding for each power of 10 $LINES uses ## We need one level of padding for each power of 10 $LINES uses
@@ -698,7 +741,7 @@ _list() {
| grep -v "^[ 0-9]\+ *$" | grep -v "^[ 0-9]\+ *$"
) )
if [ "${filter_command}" ]; then if [ "${filter_command}" ]; then
filtered_items=$(echo -n "$items" | eval ${filter_command}) filtered_items=$(echo -n "$items" | eval "${filter_command}")
else else
filtered_items=$items filtered_items=$items
fi fi
@@ -719,17 +762,18 @@ _list() {
return color return color
} }
{ {
pos = match($0, /\([A-Z]\)/)
if (match($0, /^[0-9]+ x /)) { if (match($0, /^[0-9]+ x /)) {
print highlight("COLOR_DONE") $0 highlight("DEFAULT") print highlight("COLOR_DONE") $0 highlight("DEFAULT")
} else if (pos > 0) { } else if (match($0, /^[0-9]+ \([A-Z]\)[[:space:]]/)) {
clr = highlight("PRI_" substr($0, pos+1, 1)) clr = highlight("PRI_" substr($0, RSTART + RLENGTH - 3, 1))
print ( clr ? clr : highlight("PRI_X") ) $0 highlight("DEFAULT") print \
(clr ? clr : highlight("PRI_X")) \
(ENVIRON["HIDE_PRIORITY_SUBSTITUTION"] == "" ? $0 : substr($0, 1, RLENGTH - 4) substr($0, RSTART + RLENGTH)) \
highlight("DEFAULT")
} else { print } } else { print }
} }
''' \ ''' \
| sed ''' | sed '''
s/'${HIDE_PRIORITY_SUBSTITUTION:-^}'//g
s/'${HIDE_PROJECTS_SUBSTITUTION:-^}'//g s/'${HIDE_PROJECTS_SUBSTITUTION:-^}'//g
s/'${HIDE_CONTEXTS_SUBSTITUTION:-^}'//g s/'${HIDE_CONTEXTS_SUBSTITUTION:-^}'//g
''' \ ''' \
@@ -751,7 +795,7 @@ _list() {
fi fi
} }
export -f cleaninput _list die export -f cleaninput shellquote filtercommand _list die
# == HANDLE ACTION == # == HANDLE ACTION ==
action=$( printf "%s\n" "$ACTION" | tr 'A-Z' 'a-z' ) action=$( printf "%s\n" "$ACTION" | tr 'A-Z' 'a-z' )
@@ -917,15 +961,12 @@ case $action in
# Split multiple depri's, if comma separated change to whitespace separated # Split multiple depri's, if comma separated change to whitespace separated
# Loop the 'depri' function for each item # Loop the 'depri' function for each item
for item in `echo $* | tr ',' ' '`; do for item in $(echo $* | tr ',' ' '); do
[[ "$item" = +([0-9]) ]] || die "$errmsg" [[ "$item" = +([0-9]) ]] || die "$errmsg"
todo=$(sed "$item!d" "$TODO_FILE") todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "TODO: No task $item." [ -z "$todo" ] && die "TODO: No task $item."
sed -e $item"s/^(.) //" "$TODO_FILE" > /dev/null 2>&1 if [[ "$todo" = \(?\)\ * ]]; then
if [ "$?" -eq 0 ]; then
#it's all good, continue
sed -i.bak -e $item"s/^(.) //" "$TODO_FILE" sed -i.bak -e $item"s/^(.) //" "$TODO_FILE"
if [ $TODOTXT_VERBOSE -gt 0 ]; then if [ $TODOTXT_VERBOSE -gt 0 ]; then
NEWTODO=$(sed "$item!d" "$TODO_FILE") NEWTODO=$(sed "$item!d" "$TODO_FILE")
@@ -933,7 +974,7 @@ case $action in
echo "TODO: $item deprioritized." echo "TODO: $item deprioritized."
fi fi
else else
die "$errmsg" echo "TODO: $item is not prioritized."
fi fi
done done
;; ;;
@@ -946,7 +987,7 @@ case $action in
# Split multiple do's, if comma separated change to whitespace separated # Split multiple do's, if comma separated change to whitespace separated
# Loop the 'do' function for each item # Loop the 'do' function for each item
for item in `echo $* | tr ',' ' '`; do for item in $(echo $* | tr ',' ' '); do
[ -z "$item" ] && die "$errmsg" [ -z "$item" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg" [[ "$item" = +([0-9]) ]] || die "$errmsg"
@@ -954,8 +995,8 @@ case $action in
[ -z "$todo" ] && die "TODO: No task $item." [ -z "$todo" ] && die "TODO: No task $item."
# Check if this item has already been done # Check if this item has already been done
if [ `echo $todo | grep -c "^x "` -eq 0 ] ; then if [ "${todo:0:2}" != "x " ]; then
now=`date '+%Y-%m-%d'` now=$(date '+%Y-%m-%d')
# remove priority once item is done # remove priority once item is done
sed -i.bak $item"s/^(.) //" "$TODO_FILE" sed -i.bak $item"s/^(.) //" "$TODO_FILE"
sed -i.bak $item"s|^|x $now |" "$TODO_FILE" sed -i.bak $item"s|^|x $now |" "$TODO_FILE"
@@ -965,7 +1006,7 @@ case $action in
echo "TODO: $item marked as done." echo "TODO: $item marked as done."
fi fi
else else
echo "$item is already marked done" echo "TODO: $item is already marked done."
fi fi
done done
@@ -984,6 +1025,16 @@ case $action in
help # just in case something failed above, we go ahead and just spew to STDOUT help # just in case something failed above, we go ahead and just spew to STDOUT
;; ;;
"shorthelp" )
if [ -t 1 ] ; then # STDOUT is a TTY
if which "${PAGER:-less}" >/dev/null 2>&1; then
# we have a working PAGER (or less as a default)
shorthelp | "${PAGER:-less}" && exit 0
fi
fi
shorthelp # just in case something failed above, we go ahead and just spew to STDOUT
;;
"list" | "ls" ) "list" | "ls" )
shift ## Was ls; new $1 is first search term shift ## Was ls; new $1 is first search term
_list "$TODO_FILE" "$@" _list "$TODO_FILE" "$@"
@@ -1009,26 +1060,16 @@ case $action in
;; ;;
"listproj" | "lsprj" ) "listproj" | "lsprj" )
grep -o '[^ ]*+[^ ]\+' "$TODO_FILE" | grep '^+' | sort -u shift
eval "$(filtercommand 'cat "$TODO_FILE"' '' "$@")" | grep -o '[^ ]*+[^ ]\+' | grep '^+' | sort -u
;; ;;
"listpri" | "lsp" ) "listpri" | "lsp" )
shift ## was "listpri", new $1 is priority to list shift ## was "listpri", new $1 is priority to list or first TERM
if [ "${1:-}" ] pri=$(printf "%s\n" "$1" | tr 'a-z' 'A-Z' | grep '^[A-Z]$') && shift || pri="[A-Z]"
then post_filter_command="grep '^ *[0-9]\+ (${pri}) '"
## A priority was specified _list "$TODO_FILE" "$@"
pri=$( printf "%s\n" "$1" | tr 'a-z' 'A-Z' | grep '^[A-Z]$' ) || {
die "usage: $TODO_SH listpri PRIORITY
note: PRIORITY must a single letter from A to Z."
}
else
## No priority specified; show all priority tasks
pri="[[:upper:]]"
fi
pri="($pri)"
_list "$TODO_FILE" "$pri"
;; ;;
"move" | "mv" ) "move" | "mv" )
@@ -1090,18 +1131,23 @@ note: PRIORITY must be anywhere from A to Z."
[[ "$item" = +([0-9]) ]] || die "$errmsg" [[ "$item" = +([0-9]) ]] || die "$errmsg"
[[ "$newpri" = @([A-Z]) ]] || die "$errmsg" [[ "$newpri" = @([A-Z]) ]] || die "$errmsg"
sed -e $item"s/^(.) //" -e $item"s/^/($newpri) /" "$TODO_FILE" > /dev/null 2>&1 oldpri=$(sed -ne $item's/^(\(.\)) .*/\1/p' "$TODO_FILE")
if [ "$oldpri" != "$newpri" ]; then
if [ "$?" -eq 0 ]; then
#it's all good, continue
sed -i.bak -e $item"s/^(.) //" -e $item"s/^/($newpri) /" "$TODO_FILE" sed -i.bak -e $item"s/^(.) //" -e $item"s/^/($newpri) /" "$TODO_FILE"
if [ $TODOTXT_VERBOSE -gt 0 ]; then fi
NEWTODO=$(sed "$item!d" "$TODO_FILE") if [ $TODOTXT_VERBOSE -gt 0 ]; then
echo "$item $NEWTODO" NEWTODO=$(sed "$item!d" "$TODO_FILE")
echo "TODO: $item prioritized ($newpri)." echo "$item $NEWTODO"
fi if [ "$oldpri" != "$newpri" ]; then
else if [ "$oldpri" ]; then
die "$errmsg" echo "TODO: $item re-prioritized from ($oldpri) to ($newpri)."
else
echo "TODO: $item prioritized ($newpri)."
fi
fi
fi
if [ "$oldpri" = "$newpri" ]; then
echo "TODO: $item already prioritized ($newpri)."
fi fi
;; ;;

64
todo_completion Normal file
View File

@@ -0,0 +1,64 @@
#!/bin/bash source-this-script
[ "$BASH_VERSION" ] || return
_todo()
{
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
local -r OPTS="-@ -@@ -+ -++ -d -f -h -p -P -PP -a -n -t -v -vv -V -x"
local -r COMMANDS="\
add a addto addm append app archive command del \
rm depri dp do help list ls listall lsa listcon \
lsc listfile lf listpri lsp listproj lsprj move \
mv prepend prep pri p replace report shorthelp"
# Add custom commands from add-ons, if installed.
# TODO: Filter for executable flag of files found in $TODO_ACTIONS_DIR.
local allCommands="$COMMANDS $('ls' "${TODO_ACTIONS_DIR:-$HOME/.todo.actions.d}/" 2>/dev/null)"
local completions
if [ $COMP_CWORD -eq 1 ]; then
completions="$allCommands $OPTS"
else
case "$prev" in
command)
completions=$COMMANDS;;
-*) completions="$allCommands $OPTS";;
*) case "$cur" in
+*) completions=$(TODOTXT_VERBOSE=0 todo.sh command listproj);;
@*) completions=$(TODOTXT_VERBOSE=0 todo.sh command listcon);;
*) if [[ "$cur" =~ ^[0-9]+$ ]]; then
local item=$(TODOTXT_VERBOSE=0 todo.sh -@ -+ -p -x command ls "^ *${cur} " | head -n 1)
# Remove the (padded) task number; we prepend the
# user-provided $cur.
item=${item#* }
# Remove the timestamp prepended by the -t option;
# there's no todo.txt option for that yet.
item=${item#[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] }
# Append task text as a shell comment. This
# completion can be a safety check before a
# destructive todo.txt operation.
[ "$item" ] && COMPREPLY[0]="$cur # $item"
return 0
else
return 0
fi
;;
esac
;;
esac
fi
COMPREPLY=( $( compgen -W "$completions" -- $cur ))
return 0
}
complete -F _todo todo.sh
# If you define an alias (e.g. "t") to todo.sh, you need to explicitly enable
# completion for it, too:
#complete -F _todo t