Compare commits

..

20 Commits

Author SHA1 Message Date
Ingo Karkat
faf86c88cb nobacktick code check: Skip entire comment lines, too. 2011-07-10 14:43:06 +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
7 changed files with 170 additions and 37 deletions

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

@@ -0,0 +1,17 @@
#!/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 '/\d96/{=;p}' "$(which todo.sh)"
EOF
# Note: Must encode backtick as \d96 to avoid error in the test framework.
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

@@ -55,7 +55,7 @@ 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 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,7 +66,7 @@ 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 >>> todo.sh -p listpri
2 (A) notice the sunflowers 2 (A) notice the sunflowers

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

@@ -0,0 +1,71 @@
#!/bin/sh
test_description='list priority functionality
'
. ./test-lib.sh
test_todo_session 'listpri usage' <<EOF
>>> todo.sh listpri ?
usage: todo.sh listpri PRIORITY
note: PRIORITY must a single letter from A to Z.
=== 1
EOF
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' <<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
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

71
todo.sh
View File

@@ -58,7 +58,7 @@ shorthelp()
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
move|mv ITEM# DEST [SRC] move|mv ITEM# DEST [SRC]
prepend|prep ITEM# "TEXT TO PREPEND" prepend|prep ITEM# "TEXT TO PREPEND"
@@ -143,10 +143,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
@@ -325,8 +326,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
@@ -532,7 +533,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 +620,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
@@ -917,15 +918,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 sed "$item!d" "$TODO_FILE" | grep "^(.) " > /dev/null; 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 +931,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 +944,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 +952,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 +963,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
@@ -1013,22 +1011,22 @@ case $action in
;; ;;
"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:-}" ] if [ "${1:-}" ]
then then
## A priority was specified ## A priority was specified
pri=$( printf "%s\n" "$1" | tr 'a-z' 'A-Z' | grep '^[A-Z]$' ) || { pri=$( printf "%s\n" "$1" | tr 'a-z' 'A-Z' | grep '^[A-Z]$' ) || {
die "usage: $TODO_SH listpri PRIORITY die "usage: $TODO_SH listpri PRIORITY
note: PRIORITY must a single letter from A to Z." note: PRIORITY must a single letter from A to Z."
} }
else else
## No priority specified; show all priority tasks ## No priority specified; show all priority tasks
pri="[[:upper:]]" pri="[A-Z]"
fi fi
pri="($pri)"
_list "$TODO_FILE" "$pri" post_filter_command="grep '^ *[0-9]\+ (${pri}) '"
_list "$TODO_FILE" "$@"
;; ;;
"move" | "mv" ) "move" | "mv" )
@@ -1090,18 +1088,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
;; ;;