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
15 changed files with 670 additions and 209 deletions

View File

@@ -13,7 +13,7 @@ VERSION-FILE: .FORCE-VERSION-FILE
todo.sh: VERSION-FILE
# For packaging
DISTFILES := todo.cfg
DISTFILES := todo.cfg todo_completion
DISTNAME=todo.txt_cli-$(VERSION)
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

@@ -77,4 +77,37 @@ TODO: 5 added.
TODO: 5 of 5 tasks shown
EOF
#
# Advanced add
#
cat /dev/null > todo.txt
test_todo_session 'add with spaces' <<EOF
>>> todo.sh add "notice the three spaces"
1 notice the three spaces
TODO: 1 added.
>>> todo.sh add notice how the spaces get lost
2 notice how the spaces get lost
TODO: 2 added.
>>> todo.sh list
2 notice how the spaces get lost
1 notice the three spaces
--
TODO: 2 of 2 tasks shown
EOF
cat /dev/null > todo.txt
test_todo_session 'add with CR' <<EOF
>>> todo.sh add "smell the
Carriage Return"
1 smell the Carriage Return
TODO: 1 added.
>>> todo.sh list
1 smell the Carriage Return
--
TODO: 1 of 1 tasks shown
EOF

View File

@@ -21,6 +21,22 @@ TODO: 1 added.
TODO: 1 of 1 tasks shown
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_todo_session 'cmd line second day' <<EOF

View File

@@ -45,6 +45,12 @@ grow some corn
thrash some hay
chase the chickens
EOF
test_todo_session 'replace error' << EOF
>>> todo.sh replace 10 "hej!"
=== 1
TODO: No task 10.
EOF
test_todo_session 'replace in multi-item file' <<EOF
>>> todo.sh replace 1 smell the cheese
1 smell the cows
@@ -62,33 +68,59 @@ TODO: Replaced task with:
4 collect the eggs
EOF
echo '(A) collect the eggs' > todo.txt
test_todo_session 'replace with priority' <<EOF
>>> todo.sh pri 4 a
4 (A) collect the eggs
TODO: 4 prioritized (A).
>>> todo.sh replace 4 "collect the bread"
4 (A) collect the eggs
>>> todo.sh replace 1 "collect the bread"
1 (A) collect the eggs
TODO: Replaced task with:
4 (A) collect the bread
1 (A) collect the bread
>>> todo.sh replace 4 collect the eggs
4 (A) collect the bread
>>> todo.sh replace 1 collect the eggs
1 (A) collect the bread
TODO: Replaced task with:
4 (A) collect the eggs
1 (A) collect the eggs
EOF
echo 'jump on hay' > todo.txt
test_todo_session 'replace with &' << EOF
>>> todo.sh replace 3 "thrash the hay & thresh the wheat"
3 jump on hay
>>> todo.sh replace 1 "thrash the hay & thrash the wheat"
1 jump on hay
TODO: Replaced task with:
3 thrash the hay & thresh the wheat
1 thrash the hay & thrash the wheat
EOF
test_todo_session 'replace error' << EOF
>>> todo.sh replace 10 "hej!"
=== 1
TODO: No task 10.
echo 'jump on hay' > todo.txt
test_todo_session 'replace with spaces' <<EOF
>>> todo.sh replace 1 "notice the three spaces"
1 jump on hay
TODO: Replaced task with:
1 notice the three spaces
EOF
cat > todo.txt <<EOF
smell the cows
grow some corn
thrash some hay
chase the chickens
EOF
test_todo_session 'replace with symbols' <<EOF
>>> todo.sh replace 1 "~@#$%^&*()-_=+[{]}|;:',<.>/?"
1 smell the cows
TODO: Replaced task with:
1 ~@#$%^&*()-_=+[{]}|;:',<.>/?
>>> todo.sh replace 2 '\`!\\"'
2 grow some corn
TODO: Replaced task with:
2 \`!\\"
>>> todo.sh list
4 chase the chickens
3 thrash some hay
2 \`!\\"
1 ~@#$%^&*()-_=+[{]}|;:',<.>/?
--
TODO: 4 of 4 tasks shown
EOF
cat /dev/null > todo.txt
@@ -124,6 +156,7 @@ TODO: Replaced task with:
1 (A) 2009-02-13 this is just a new one
EOF
echo '(A) 2009-02-13 this is just a new one' > todo.txt
test_todo_session 'replace with prepended date replaces existing date' <<EOF
>>> todo.sh replace 1 2010-07-04 this also has a new date
1 (A) 2009-02-13 this is just a new one

View File

@@ -53,9 +53,28 @@ TODO: 2 prioritized (C).
--
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
2 (A) notice the sunflowers
TODO: 2 prioritized (A).
TODO: 2 re-prioritized from (C) to (A).
>>> todo.sh -p list
2 (A) notice the sunflowers
@@ -66,25 +85,13 @@ TODO: 3 of 3 tasks shown
>>> todo.sh pri 2 a
2 (A) notice the sunflowers
TODO: 2 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: 2 already prioritized (A).
>>> todo.sh -p list
2 (A) notice the sunflowers
1 (B) smell the uppercase Roses +flowers @outside
4 smell the coffee +wakeup
3 stop
--
TODO: 4 of 4 tasks shown
TODO: 3 of 3 tasks shown
EOF
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
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
#
@@ -142,7 +176,7 @@ cat > todo.txt <<EOF
(D) @con02 +prj03 -- Some project 03 task, pri D
(D) @con02 +prj04 -- Some project 04 task, pri D
@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 +prj04 -- Some project 04 task, no priority
EOF
@@ -165,7 +199,7 @@ test_todo_session 'plain mode option' <<EOF
15 (D) @con02 +prj03 -- Some project 03 task, pri D
16 (D) @con02 +prj04 -- Some project 04 task, pri D
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
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
16 (D) @con02 +prj04 -- Some project 04 task, pri D
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
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 +prj04 -- Some project 04 task, pri D
@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 +prj04 -- Some project 04 task, no priority
EOF
@@ -240,7 +274,7 @@ test_todo_session 'context, project, and priority suppression' <<EOF
15 (D) @con02 +prj03 -- Some project 03 task, pri D
16 (D) @con02 +prj04 -- Some project 04 task, pri D
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
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
14 (D) @con01 +prj02 -- Some project 02 task, pri D
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
@@ -270,7 +304,7 @@ TODO: 10 of 20 tasks shown
13 @con01 +prj01 -- Some project 01 task, pri D
14 @con01 +prj02 -- Some project 02 task, pri D
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
@@ -284,7 +318,7 @@ TODO: 10 of 20 tasks shown
13 (D) @con01 -- Some project 01 task, pri D
14 (D) @con01 -- Some project 02 task, pri D
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
@@ -298,7 +332,7 @@ TODO: 10 of 20 tasks shown
13 (D) +prj01 -- Some project 01 task, pri D
14 (D) +prj02 -- Some project 02 task, pri D
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
@@ -312,7 +346,7 @@ TODO: 10 of 20 tasks shown
13 +prj01 -- Some project 01 task, pri D
14 +prj02 -- Some project 02 task, pri D
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
@@ -326,7 +360,7 @@ TODO: 10 of 20 tasks shown
13 (D) @con01 +prj01 -- Some project 01 task, pri D
14 (D) @con01 +prj02 -- Some project 02 task, pri D
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
@@ -340,7 +374,7 @@ TODO: 10 of 20 tasks shown
13 -- Some project 01 task, pri D
14 -- Some project 02 task, pri D
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
EOF

View File

@@ -166,4 +166,20 @@ test_todo_session 'highlighting with hidden contexts/projects' <<EOF
TODO: 4 of 4 tasks shown
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

View File

@@ -57,6 +57,34 @@ test_todo_session 'prepend with &' <<EOF
3 no running & jumping now stop
EOF
echo 'jump on hay' > todo.txt
test_todo_session 'prepend with spaces' <<EOF
>>> todo.sh prepend 1 "notice the three spaces and"
1 notice the three spaces and jump on hay
EOF
cat > todo.txt <<EOF
smell the cows
grow some corn
thrash some hay
chase the chickens
EOF
test_todo_session 'prepend with symbols' <<EOF
>>> todo.sh prepend 1 "~@#$%^&*()-_=+[{]}|;:',<.>/?"
1 ~@#$%^&*()-_=+[{]}|;:',<.>/? smell the cows
>>> todo.sh prepend 2 '\`!\\"'
2 \`!\\" grow some corn
>>> todo.sh list
4 chase the chickens
3 thrash some hay
2 \`!\\" grow some corn
1 ~@#$%^&*()-_=+[{]}|;:',<.>/? smell the cows
--
TODO: 4 of 4 tasks shown
EOF
cat /dev/null > todo.txt
test_todo_session 'prepend handling prepended date on add' <<EOF
>>> todo.sh -t add "new task"

View File

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

View File

@@ -17,6 +17,12 @@ test_todo_session 'append usage' <<EOF
usage: todo.sh append ITEM# "TEXT TO APPEND"
EOF
test_todo_session 'append error' << EOF
>>> todo.sh append 10 "hej!"
=== 1
TODO: No task 10.
EOF
test_todo_session 'basic append' <<EOF
>>> todo.sh append 1 "smell the roses"
1 notice the daisies smell the roses
@@ -37,11 +43,32 @@ test_todo_session 'basic append with &' <<EOF
TODO: 1 of 1 tasks shown
EOF
echo 'jump on hay' > todo.txt
test_todo_session 'append with spaces' <<EOF
>>> todo.sh append 1 "and notice the three spaces"
1 jump on hay and notice the three spaces
EOF
test_todo_session 'append error' << EOF
>>> todo.sh append 10 "hej!"
=== 1
TODO: No task 10.
cat > todo.txt <<EOF
smell the cows
grow some corn
thrash some hay
chase the chickens
EOF
test_todo_session 'append with symbols' <<EOF
>>> todo.sh append 1 "~@#$%^&*()-_=+[{]}|;:',<.>/?"
1 smell the cows ~@#$%^&*()-_=+[{]}|;:',<.>/?
>>> todo.sh append 2 '\`!\\"'
2 grow some corn \`!\\"
>>> todo.sh list
4 chase the chickens
2 grow some corn \`!\\"
1 smell the cows ~@#$%^&*()-_=+[{]}|;:',<.>/?
3 thrash some hay
--
TODO: 4 of 4 tasks shown
EOF
cat > todo.txt <<EOF

368
todo.sh
View File

@@ -1,7 +1,7 @@
#! /bin/bash
# === HEAVY LIFTING ===
shopt -s extglob
shopt -s extglob extquote
# NOTE: Todo.sh requires the .todo/config configuration file to run.
# Place the .todo/config file in your home directory or use the -d option for a custom location.
@@ -44,39 +44,113 @@ shorthelp()
Actions:
add|a "THING I NEED TO DO +project @context"
addto DEST "TEXT TO ADD"
addm "THINGS I NEED TO DO
MORE THINGS I NEED TO DO"
addto DEST "TEXT TO ADD"
append|app ITEM# "TEXT TO APPEND"
archive
command [ACTIONS]
del|rm ITEM# [TERM]
dp|depri ITEM#[, ITEM#, ITEM#, ...]
depri|dp ITEM#[, ITEM#, ITEM#, ...]
do ITEM#[, ITEM#, ITEM#, ...]
help
list|ls [TERM...]
listall|lsa [TERM...]
listcon|lsc
listfile|lf SRC [TERM...]
listpri|lsp [PRIORITY]
listproj|lsprj
listpri|lsp [PRIORITY] [TERM...]
listproj|lsprj [TERM...]
move|mv ITEM# DEST [SRC]
prepend|prep ITEM# "TEXT TO PREPEND"
pri|p ITEM# PRIORITY
replace ITEM# "UPDATED TODO"
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.
EndHelp
EndHelpFooter
exit 0
}
help()
{
cat <<-EndHelp
cat <<-EndOptionsHelp
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"
a "THING I NEED TO DO +project @context"
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
all lines that contain TERM in SRC file.
listpri [PRIORITY]
lsp [PRIORITY]
listpri [PRIORITY] [TERM...]
lsp [PRIORITY] [TERM...]
Displays all tasks prioritized PRIORITY.
If no PRIORITY specified, lists all prioritized tasks.
If TERM specified, lists only prioritized tasks that contain TERM.
listproj
lsprj
@@ -176,81 +251,33 @@ help()
report
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:
-@
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
EndActionsHelp
addonHelp
exit 1
}
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_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 ""
addonHelp()
{
if [ -d "$TODO_ACTIONS_DIR" ]; then
didPrintAddonActionsHeader=
for action in "$TODO_ACTIONS_DIR"/*
do
if [ -f "$action" -a -x "$action" ]
then
if [ -f "$action" -a -x "$action" ]; then
if [ ! "$didPrintAddonActionsHeader" ]; then
cat <<-EndAddonActionsHeader
Add-on Actions:
EndAddonActionsHeader
didPrintAddonActionsHeader=1
fi
"$action" usage
fi
done
echo ""
fi
exit 1
}
die()
@@ -267,16 +294,17 @@ cleanup()
cleaninput()
{
# Cleanup the input
# Replace newlines with spaces Always
input=`echo $input | tr -d '\r\n'`
# Replace CR and LF with space; tasks always comprise a single line.
input=${input//$'\r'/ }
input=${input//$'\n'/ }
action_regexp="^\(append\|app\|prepend\|prep\|replace\)$"
# Check which action we are being used in as this affects what cleaning we do
if [ `echo $action | grep -c $action_regexp` -eq 1 ]; then
# These actions use sed and & as the matched string so escape it
input=`echo $input | sed 's/\&/\\\&/g'`
if [ "$1" = "for sed" ]; then
# This action uses sed with "|" as the substitution separator, and & as
# the matched string; these must be escaped.
# Backslashes must be escaped, too, and before the other stuff.
input=${input//\\/\\\\}
input=${input//|/\\|}
input=${input//&/\\&}
fi
}
@@ -321,11 +349,11 @@ replaceOrPrepend()
else
input=$*
fi
cleaninput $input
cleaninput "for sed"
# 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")
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")
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/^\((.) \)\{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 the replaced text starts with a date, it will replace the existing
@@ -416,7 +444,10 @@ do
OVR_TODOTXT_FORCE=1
;;
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 )
OVR_TODOTXT_PRESERVE_LINE_NUMBERS=0
@@ -472,6 +503,7 @@ TODOTXT_AUTO_ARCHIVE=${TODOTXT_AUTO_ARCHIVE:-1}
TODOTXT_DATE_ON_ADD=${TODOTXT_DATE_ON_ADD:-0}
TODOTXT_DEFAULT_ACTION=${TODOTXT_DEFAULT_ACTION:-}
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}
# Export all TODOTXT_* variables
@@ -531,7 +563,7 @@ export SENTENCE_DELIMITERS=',.:;'
}
[ -e "$TODOTXT_CFG_FILE" ] || {
CFG_FILE_ALT=`dirname "$0"`"/todo.cfg"
CFG_FILE_ALT=$(dirname "$0")"/todo.cfg"
if [ -e "$CFG_FILE_ALT" ]
then
@@ -615,11 +647,11 @@ fi
_addto() {
file="$1"
input="$2"
cleaninput $input
cleaninput
if [[ $TODOTXT_DATE_ON_ADD = 1 ]]; then
now=`date '+%Y-%m-%d'`
input="$now $input"
now=$(date '+%Y-%m-%d')
input=$(echo "$input" | sed -e 's/^\(([A-Z]) \)\{0,1\}/\1'"$now /")
fi
echo "$input" >> "$file"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
@@ -631,6 +663,42 @@ _addto() {
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() {
local FILE="$1"
## If the file starts with a "/" use absolute path. Otherwise,
@@ -654,32 +722,8 @@ _list() {
## Get our search arguments, if any
shift ## was file name, new $1 is first search term
## Prefix the filter_command with the pre_filter_command
filter_command="${pre_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:-}"
}
## Build the filter.
filter_command=$(filtercommand "${pre_filter_command:-}" "${post_filter_command:-}" "$@")
## Figure out how much padding we need to use
## We need one level of padding for each power of 10 $LINES uses
@@ -697,7 +741,7 @@ _list() {
| grep -v "^[ 0-9]\+ *$"
)
if [ "${filter_command}" ]; then
filtered_items=$(echo -n "$items" | eval ${filter_command})
filtered_items=$(echo -n "$items" | eval "${filter_command}")
else
filtered_items=$items
fi
@@ -718,17 +762,18 @@ _list() {
return color
}
{
pos = match($0, /\([A-Z]\)/)
if (match($0, /^[0-9]+ x /)) {
print highlight("COLOR_DONE") $0 highlight("DEFAULT")
} else if (pos > 0) {
clr = highlight("PRI_" substr($0, pos+1, 1))
print ( clr ? clr : highlight("PRI_X") ) $0 highlight("DEFAULT")
} else if (match($0, /^[0-9]+ \([A-Z]\)[[:space:]]/)) {
clr = highlight("PRI_" substr($0, RSTART + RLENGTH - 3, 1))
print \
(clr ? clr : highlight("PRI_X")) \
(ENVIRON["HIDE_PRIORITY_SUBSTITUTION"] == "" ? $0 : substr($0, 1, RLENGTH - 4) substr($0, RSTART + RLENGTH)) \
highlight("DEFAULT")
} else { print }
}
''' \
| sed '''
s/'${HIDE_PRIORITY_SUBSTITUTION:-^}'//g
s/'${HIDE_PROJECTS_SUBSTITUTION:-^}'//g
s/'${HIDE_CONTEXTS_SUBSTITUTION:-^}'//g
''' \
@@ -750,7 +795,7 @@ _list() {
fi
}
export -f _list die
export -f cleaninput shellquote filtercommand _list die
# == HANDLE ACTION ==
action=$( printf "%s\n" "$ACTION" | tr 'A-Z' 'a-z' )
@@ -842,7 +887,7 @@ case $action in
[$SENTENCE_DELIMITERS]*) appendspace=;;
*) appendspace=" ";;
esac
cleaninput $input
cleaninput "for sed"
if sed -i.bak $item" s|^.*|&${appendspace}${input}|" "$TODO_FILE"; then
if [ $TODOTXT_VERBOSE -gt 0 ]; then
@@ -916,12 +961,12 @@ case $action in
# Split multiple depri's, if comma separated change to whitespace separated
# Loop the 'depri' function for each item
for item in `echo $* | tr ',' ' '`; do
for item in $(echo $* | tr ',' ' '); do
[[ "$item" = +([0-9]) ]] || die "$errmsg"
todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "TODO: No task $item."
if sed "$item!d" "$TODO_FILE" | grep "^(.) " > /dev/null; then
if [[ "$todo" = \(?\)\ * ]]; then
sed -i.bak -e $item"s/^(.) //" "$TODO_FILE"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
NEWTODO=$(sed "$item!d" "$TODO_FILE")
@@ -942,7 +987,7 @@ case $action in
# Split multiple do's, if comma separated change to whitespace separated
# Loop the 'do' function for each item
for item in `echo $* | tr ',' ' '`; do
for item in $(echo $* | tr ',' ' '); do
[ -z "$item" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
@@ -950,8 +995,8 @@ case $action in
[ -z "$todo" ] && die "TODO: No task $item."
# Check if this item has already been done
if [ `echo $todo | grep -c "^x "` -eq 0 ] ; then
now=`date '+%Y-%m-%d'`
if [ "${todo:0:2}" != "x " ]; then
now=$(date '+%Y-%m-%d')
# remove priority once item is done
sed -i.bak $item"s/^(.) //" "$TODO_FILE"
sed -i.bak $item"s|^|x $now |" "$TODO_FILE"
@@ -961,7 +1006,7 @@ case $action in
echo "TODO: $item marked as done."
fi
else
echo "$item is already marked done"
echo "TODO: $item is already marked done."
fi
done
@@ -980,6 +1025,16 @@ case $action in
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" )
shift ## Was ls; new $1 is first search term
_list "$TODO_FILE" "$@"
@@ -1005,26 +1060,16 @@ case $action in
;;
"listproj" | "lsprj" )
grep -o '[^ ]*+[^ ]\+' "$TODO_FILE" | grep '^+' | sort -u
shift
eval "$(filtercommand 'cat "$TODO_FILE"' '' "$@")" | grep -o '[^ ]*+[^ ]\+' | grep '^+' | sort -u
;;
"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:-}" ]
then
## A priority was specified
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"
pri=$(printf "%s\n" "$1" | tr 'a-z' 'A-Z' | grep '^[A-Z]$') && shift || pri="[A-Z]"
post_filter_command="grep '^ *[0-9]\+ (${pri}) '"
_list "$TODO_FILE" "$@"
;;
"move" | "mv" )
@@ -1086,18 +1131,23 @@ note: PRIORITY must be anywhere from A to Z."
[[ "$item" = +([0-9]) ]] || die "$errmsg"
[[ "$newpri" = @([A-Z]) ]] || die "$errmsg"
sed -e $item"s/^(.) //" -e $item"s/^/($newpri) /" "$TODO_FILE" > /dev/null 2>&1
if [ "$?" -eq 0 ]; then
#it's all good, continue
oldpri=$(sed -ne $item's/^(\(.\)) .*/\1/p' "$TODO_FILE")
if [ "$oldpri" != "$newpri" ]; then
sed -i.bak -e $item"s/^(.) //" -e $item"s/^/($newpri) /" "$TODO_FILE"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
NEWTODO=$(sed "$item!d" "$TODO_FILE")
echo "$item $NEWTODO"
echo "TODO: $item prioritized ($newpri)."
fi
else
die "$errmsg"
fi
if [ $TODOTXT_VERBOSE -gt 0 ]; then
NEWTODO=$(sed "$item!d" "$TODO_FILE")
echo "$item $NEWTODO"
if [ "$oldpri" != "$newpri" ]; then
if [ "$oldpri" ]; then
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
;;

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