Compare commits

...

16 Commits

Author SHA1 Message Date
Ingo Karkat
c1dcd0ed78 test-lib: Also check completion exit code.
The completion may unexpectedly abort somewhere.

Additionally, reformat the failure messages (don't prepend a "*", this should be reserved to mark the individual test runs) and use "compreply" instead of "output", so that it's already clear from the diff output that the completion is being tested.
2012-02-23 09:14:42 +01:00
Ingo Karkat
c9d1993dc8 test-lib: Avoid empty line in diff when no completion.
There should be a trailing newline when there are completions (to avoid diff complaining about "no trailing newline", but not when there are no completions at all.
2012-02-23 09:14:42 +01:00
Ingo Karkat
451dbdda6b Merge duplicate test files for listproj.
t1260-listprj.sh was accidentally created; the tests should be in t1320-listproj.sh.
2012-02-23 09:14:42 +01:00
Ingo Karkat
060e81aa05 ENH: completion offers projects and contexts from done.txt.
This is useful when there are no open projects/contexts any more, but one wants to re-use an existing name.
2012-02-23 09:14:42 +01:00
Ingo Karkat
296bad334d Add tests for project and context completion. 2012-02-23 09:14:42 +01:00
Ingo Karkat
3b90d09b27 Add testing of todo_completion.
Before adding any more features to todo_completion, I feel like I need test coverage, so this is a first stab at testing the completion results, via a new test function test_todo_completion.
Some basic tests showcase the capabilities.

Note: test-lib.sh now uses arrays, therefore all tests must use /bin/bash, not /bin/sh to avoid errors when sourcing test-lib. For consistency with todo.sh, we should have used Bash everywhere, anyway. Also note that t2000-multiline.sh needs some more quoting to avoid "Bash: ambiguous redirect" errors.
2012-02-23 09:14:41 +01:00
Ingo Karkat
46afb7f46a ENH: TODOTXT_SOURCEVAR enables different source file for listproj. 2012-02-23 09:14:41 +01:00
Ingo Karkat
9e13dfd290 ENH: TODOTXT_SOURCEVAR enables different source file for listcon.
To be used by todo_completion (to offer candidates from done.txt when there are no matches in todo.txt), and maybe by custom addons.
2012-02-23 09:14:41 +01:00
Gina Trapani
fbee428e75 Merge pull request #76 from inkarkat/reintroduce-mawk-support
Revert to safer POSIX AWK regexp.
2012-02-21 11:44:37 -08:00
Ingo Karkat
3b960a2e3c 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.
2012-02-21 09:18:39 +01:00
Gina Trapani
ad1ca6c2c9 Merge pull request #75 from inkarkat/rid-tmp-file
Split up _list() and get rid of $TMP_FILE and cleanup().
2012-02-14 21:59:10 -08:00
Gina Trapani
36e018fd86 Merge pull request #74 from inkarkat/listpri-pri-range
ENH: Allow listpri filtering with priority ranges.
2012-02-14 21:58:26 -08:00
Ingo Karkat
be0a0265d1 Also get rid of TMP_FILE in todo.cfg.
There's a slight chance that some add-on has used this (undocumented, unofficial) configuration value for its own purposes (and maybe also relied on the unexposed cleanup() infrastructure), but detecting and fixing that problem (by moving the cleanup into the add-on itself) is pretty straightforward.
2012-01-26 16:21:46 +01:00
Ingo Karkat
cf7f7531be Break up _list(), get rid of TMP_FILE.
Extract a new function _format() (and getPadding(), both also exported for add-ons) from _list(), which includes the main formatting and filtering pipeline, without the file handling and verbose summary. This can receive the todo file via stdin, so the listall action is able to format the concatenated files without going through a temporary file.

Eventually, after further refactorings, _format() could be used for actual formatted verbose messages in all commands; currently, the raw, unformatted task is printed.
2012-01-26 16:18:30 +01:00
Ingo Karkat
28ec5a06f2 Get rid of cleanup, only use TMP_FILE in listall.
After the recent refactorings, the temporary file is only needed for the listall action. Therefore, the creation-checks and eventual cleanup can be restricted to the listall action, which should slightly speed up the overall script execution.
2012-01-26 14:48:29 +01:00
Ingo Karkat
dfec12e2a4 ENH: Allow listpri filtering with priority ranges.
So far, the listpri action only supports a single priority. Allowing priority ranges (e.g. todo.sh listpri A-C @work) is a simple but useful enhancement.

Note: The syntax extension only clashes with the [TERM] filtering in a few corner cases, and this can be worked around (e.g. "todo.sh listpri A-Z A-Z" lists all prioritized tasks containing the text A-Z).
2012-01-26 13:17:31 +01:00
37 changed files with 368 additions and 133 deletions

View File

@@ -125,10 +125,10 @@ Writing Tests
------------- -------------
The test script is written as a shell script. It should start The test script is written as a shell script. It should start
with the standard "#!/bin/sh" with copyright notices, and an with the standard "#!/bin/bash" with copyright notices, and an
assignment to variable 'test_description', like this: assignment to variable 'test_description', like this:
#!/bin/sh #!/bin/bash
# #
# Copyright (c) 2005 Junio C Hamano # Copyright (c) 2005 Junio C Hamano
# #
@@ -186,6 +186,17 @@ library for your script to use.
expected output. (See below for how to generate transcripts expected output. (See below for how to generate transcripts
easily.) easily.)
- test_todo_completion <message> <cmdline> <completions>
This takes three strings as parameter. Based on <cmdline>,
the todo_completion script is triggered in the current test
environment and completions are compared with <completions>,
which should be a space-separated list. Include a trailing
space in <cmdline> when you want to check new argument
completion; otherwise, completion is triggered with the
context of the last argument. <message> should state what it
is testing.
- test_tick [interval] - test_tick [interval]
The test harness has an internal view of time which is The test harness has an internal view of time which is

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='todo.sh configuration file location test_description='todo.sh configuration file location

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='todo.sh basic null functionality test. test_description='todo.sh basic null functionality test.

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='todo.sh actions.d test_description='todo.sh actions.d

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='no old-style backtick command substitution test_description='no old-style backtick command substitution

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='basic add and list functionality test_description='basic add and list functionality

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='test the date on add feature test_description='test the date on add feature

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='basic addto and list functionality test_description='basic addto and list functionality

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='test the date on addto feature test_description='test the date on addto feature

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='basic replace functionality test_description='basic replace functionality

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='basic priority functionality test_description='basic priority functionality
' '

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='list priority functionality test_description='list priority functionality
' '
@@ -61,6 +61,42 @@ TODO: 0 of 5 tasks shown
TODO: 0 of 5 tasks shown TODO: 0 of 5 tasks shown
EOF EOF
cat > todo.txt <<EOF
(B) smell the uppercase Roses +flowers @outside
(X) clean the house from A-Z
(C) notice the sunflowers
(X) listen to music
buy more records from artists A-Z
EOF
test_todo_session 'listpri filtering priority ranges' <<EOF
>>> todo.sh -p listpri a-c
1 (B) smell the uppercase Roses +flowers @outside
3 (C) notice the sunflowers
--
TODO: 2 of 5 tasks shown
>>> todo.sh -p listpri c-Z
3 (C) notice the sunflowers
2 (X) clean the house from A-Z
4 (X) listen to music
--
TODO: 3 of 5 tasks shown
>>> todo.sh -p listpri A-
2 (X) clean the house from A-Z
--
TODO: 1 of 5 tasks shown
>>> todo.sh -p listpri A-C A-Z
--
TODO: 0 of 5 tasks shown
>>> todo.sh -p listpri X A-Z
2 (X) clean the house from A-Z
--
TODO: 1 of 5 tasks shown
EOF
cat > todo.txt <<EOF cat > todo.txt <<EOF
(B) ccc xxx this line should be third. (B) ccc xxx this line should be third.
ccc xxx this line should be third. ccc xxx this line should be third.

View File

@@ -1,42 +0,0 @@
#!/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

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
# #
test_description='list functionality test_description='list functionality

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
# #
test_description='listcon functionality test_description='listcon functionality
@@ -55,4 +55,23 @@ test_todo_session 'listcon e-mail address test' <<EOF
@con02 @con02
EOF EOF
cat > todo.txt <<EOF
@con01 -- Some context 1 task
EOF
cat > done.txt <<EOF
x 2012-02-21 @done01 -- Some context 1 done task
x 2012-02-21 @done02 -- Some context 2 done task
EOF
test_todo_session 'listcon from done tasks' <<'EOF'
>>> TODOTXT_SOURCEVAR=\$DONE_FILE todo.sh listcon
@done01
@done02
EOF
test_todo_session 'listcon from combined open + done tasks' <<'EOF'
>>> TODOTXT_SOURCEVAR='("$TODO_FILE" "$DONE_FILE")' todo.sh listcon
@con01
@done01
@done02
EOF
test_done test_done

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
# #
test_description='listproj functionality test_description='listproj functionality
@@ -55,4 +55,63 @@ test_todo_session 'listproj embedded + test' <<EOF
+prj02 +prj02
EOF EOF
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
cat > todo.txt <<EOF
+prj01 -- Some project 1 task
EOF
cat > done.txt <<EOF
x 2012-02-21 +done01 -- Special project 1 done task
x 2012-02-21 +done02 -- Some project 2 done task
EOF
test_todo_session 'listproj from done tasks' <<'EOF'
>>> TODOTXT_SOURCEVAR=\$DONE_FILE todo.sh listproj
+done01
+done02
EOF
test_todo_session 'listproj from done tasks with filtering' <<'EOF'
>>> TODOTXT_SOURCEVAR=\$DONE_FILE todo.sh listproj Special
+done01
EOF
test_todo_session 'listproj from combined open + done tasks' <<'EOF'
>>> TODOTXT_SOURCEVAR='("$TODO_FILE" "$DONE_FILE")' todo.sh listproj
+done01
+done02
+prj01
EOF
test_done test_done

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
# #
test_description='list highlighting test_description='list highlighting

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='listall functionality test_description='listall functionality
' '

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='basic prepend functionality test_description='basic prepend functionality
' '

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='do functionality test_description='do functionality
' '

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='basic append functionality test_description='basic append functionality

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='basic depriority functionality test_description='basic depriority functionality
' '

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='basic del functionality test_description='basic del functionality
' '

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='archive functionality test_description='archive functionality

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='deduplicate functionality test_description='deduplicate functionality

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='report functionality test_description='report functionality

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='Multi-line functionality' test_description='Multi-line functionality'
@@ -8,18 +8,18 @@ test_description='Multi-line functionality'
# Create the expected file # Create the expected file
echo "1 smell the cheese echo "1 smell the cheese
TODO: Replaced task with: TODO: Replaced task with:
1 eat apples eat oranges drink milk">$HOME/expect.multi 1 eat apples eat oranges drink milk">"$HOME/expect.multi"
test_expect_success 'multiline squash item replace' ' test_expect_success 'multiline squash item replace' '
( (
# Prepare single line todo file # Prepare single line todo file
cat /dev/null > $HOME/todo.txt cat /dev/null > "$HOME/todo.txt"
"$HOME/bin/todo.sh" add smell the cheese "$HOME/bin/todo.sh" add smell the cheese
# Run replace # Run replace
"$HOME/bin/todo.sh" replace 1 "eat apples "$HOME/bin/todo.sh" replace 1 "eat apples
eat oranges eat oranges
drink milk" > $HOME/output.multi drink milk" > "$HOME/output.multi"
# Test output against expected # Test output against expected
diff "$HOME/output.multi" "$HOME/expect.multi" diff "$HOME/output.multi" "$HOME/expect.multi"
@@ -34,18 +34,18 @@ fi
## Add test ## Add test
# Create the expected file # Create the expected file
echo "2 eat apples eat oranges drink milk echo "2 eat apples eat oranges drink milk
TODO: 2 added.">$HOME/expect.multi TODO: 2 added.">"$HOME/expect.multi"
test_expect_success 'multiline squash item add' ' test_expect_success 'multiline squash item add' '
( (
# Prepare single line todo file # Prepare single line todo file
cat /dev/null > $HOME/todo.txt cat /dev/null > "$HOME/todo.txt"
"$HOME/bin/todo.sh" add smell the cheese "$HOME/bin/todo.sh" add smell the cheese
# Run add # Run add
"$HOME/bin/todo.sh" add "eat apples "$HOME/bin/todo.sh" add "eat apples
eat oranges eat oranges
drink milk" > $HOME/output.multi drink milk" > "$HOME/output.multi"
# Test output against expected # Test output against expected
diff "$HOME/output.multi" "$HOME/expect.multi" diff "$HOME/output.multi" "$HOME/expect.multi"
@@ -59,18 +59,18 @@ fi
## Append test ## Append test
# Create the expected file # Create the expected file
echo "1 smell the cheese eat apples eat oranges drink milk">$HOME/expect.multi echo "1 smell the cheese eat apples eat oranges drink milk">"$HOME/expect.multi"
test_expect_success 'multiline squash item append' ' test_expect_success 'multiline squash item append' '
( (
# Prepare single line todo file # Prepare single line todo file
cat /dev/null > $HOME/todo.txt cat /dev/null > "$HOME/todo.txt"
"$HOME/bin/todo.sh" add smell the cheese "$HOME/bin/todo.sh" add smell the cheese
# Run append # Run append
"$HOME/bin/todo.sh" append 1 "eat apples "$HOME/bin/todo.sh" append 1 "eat apples
eat oranges eat oranges
drink milk" > $HOME/output.multi drink milk" > "$HOME/output.multi"
# Test output against expected # Test output against expected
diff "$HOME/output.multi" "$HOME/expect.multi" diff "$HOME/output.multi" "$HOME/expect.multi"
@@ -84,18 +84,18 @@ fi
## Prepend test ## Prepend test
# Create the expected file # Create the expected file
echo "1 eat apples eat oranges drink milk smell the cheese">$HOME/expect.multi echo "1 eat apples eat oranges drink milk smell the cheese">"$HOME/expect.multi"
test_expect_success 'multiline squash item prepend' ' test_expect_success 'multiline squash item prepend' '
( (
# Prepare single line todo file # Prepare single line todo file
cat /dev/null > $HOME/todo.txt cat /dev/null > "$HOME/todo.txt"
"$HOME/bin/todo.sh" add smell the cheese "$HOME/bin/todo.sh" add smell the cheese
# Run prepend # Run prepend
"$HOME/bin/todo.sh" prepend 1 "eat apples "$HOME/bin/todo.sh" prepend 1 "eat apples
eat oranges eat oranges
drink milk" > $HOME/output.multi drink milk" > "$HOME/output.multi"
# Test output against expected # Test output against expected
diff "$HOME/output.multi" "$HOME/expect.multi" diff "$HOME/output.multi" "$HOME/expect.multi"
@@ -110,18 +110,18 @@ fi
## Multiple line addition ## Multiple line addition
# Create the expected file # Create the expected file
echo "2 eat apples echo "2 eat apples
TODO: 2 added." > $HOME/expect.multi TODO: 2 added." > "$HOME/expect.multi"
echo "3 eat oranges echo "3 eat oranges
TODO: 3 added." >>$HOME/expect.multi TODO: 3 added." >>"$HOME/expect.multi"
echo "4 drink milk echo "4 drink milk
TODO: 4 added." >> $HOME/expect.multi TODO: 4 added." >>"$HOME/expect.multi"
test_expect_success 'actual multiline add' ' test_expect_success 'actual multiline add' '
( (
# Run addm # Run addm
"$HOME/bin/todo.sh" addm "eat apples "$HOME/bin/todo.sh" addm "eat apples
eat oranges eat oranges
drink milk" > $HOME/output.multi drink milk" > "$HOME/output.multi"
# Test output against expected # Test output against expected
diff "$HOME/output.multi" "$HOME/expect.multi" diff "$HOME/output.multi" "$HOME/expect.multi"

18
tests/t6000-completion.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/bin/bash
#
test_description='Bash completion functionality
This test checks basic todo_completion of actions and options
'
. ./test-lib.sh
readonly ACTIONS='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'
readonly OPTIONS='-@ -@@ -+ -++ -d -f -h -p -P -PP -a -n -t -v -vv -V -x'
test_todo_completion 'all arguments' 'todo.sh ' "$ACTIONS $OPTIONS"
test_todo_completion 'arguments beginning with a' 'todo.sh a' 'add a addto addm append app archive'
test_todo_completion 'all options' 'todo.sh -' "$OPTIONS"
test_todo_completion 'all actions after command action' 'todo.sh command ' "$ACTIONS"
test_done

View File

@@ -0,0 +1,27 @@
#!/bin/bash
#
test_description='Bash context completion functionality
This test checks todo_completion of contexts
'
. ./test-lib.sh
cat > todo.txt <<EOF
(B) smell the +roses @outside @outdoor +shared
notice the sunflowers +sunflowers @outside @garden +shared +landscape
stop
EOF
cat > done.txt <<EOF
x 2012-02-21 +herbs @oriental buy spices
x 2012-02-21 +slack @home watch tv
EOF
test_todo_completion 'all contexts' 'todo.sh list @' '@garden @outdoor @outside'
test_todo_completion 'contexts beginning with o' 'todo.sh list @o' '@outdoor @outside'
test_todo_completion 'contexts beginning with outs' 'todo.sh list @outs' '@outside'
test_todo_completion 'contexts beginning with x' 'todo.sh list @x' ''
test_todo_completion 'contexts from done tasks beginning with h' 'todo.sh list @h' '@home'
test_todo_completion 'contexts from done tasks beginning with or' 'todo.sh list @or' '@oriental'
test_done

View File

@@ -0,0 +1,27 @@
#!/bin/bash
#
test_description='Bash project completion functionality
This test checks todo_completion of projects
'
. ./test-lib.sh
cat > todo.txt <<EOF
(B) smell the +roses @outside @outdoor +shared
notice the sunflowers +sunflowers @outside @garden +shared +landscape
stop
EOF
cat > done.txt <<EOF
x 2012-02-21 +herbs @oriental buy spices
x 2012-02-21 +slack @home watch tv
EOF
test_todo_completion 'all projects' 'todo.sh list +' '+landscape +roses +shared +sunflowers'
test_todo_completion 'projects beginning with s' 'todo.sh list +s' '+shared +sunflowers'
test_todo_completion 'projects beginning with ro' 'todo.sh list +ro' '+roses'
test_todo_completion 'projects beginning with x' 'todo.sh list +x' ''
test_todo_completion 'projects from done tasks beginning with h' 'todo.sh list +h' '+herbs'
test_todo_completion 'projects from done tasks beginning with sl' 'todo.sh list +sl' '+slack'
test_done

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='custom actions functionality test_description='custom actions functionality

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='basic tests imported from previous framework test_description='basic tests imported from previous framework
' '

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
# #
# Copyright (c) 2005 Junio C Hamano # Copyright (c) 2005 Junio C Hamano
# #
@@ -305,7 +305,7 @@ $cmp_output"
else else
cmp_output=$(test_cmp expect output) cmp_output=$(test_cmp expect output)
test_failure_ "$2" "$3" " test_failure_ "$2" "$3" "
* expected exit code $1, actual ${eval_ret}${cmp_output:+ expected exit code $1, actual ${eval_ret}${cmp_output:+
}${cmp_output}" }${cmp_output}"
fi fi
fi fi
@@ -324,7 +324,7 @@ test_expect_code () {
test_ok_ "$2" test_ok_ "$2"
else else
test_failure_ "$2" "$3" " test_failure_ "$2" "$3" "
* expected exit code $1, actual ${eval_ret}" expected exit code $1, actual ${eval_ret}"
fi fi
fi fi
echo >&3 "" echo >&3 ""
@@ -632,6 +632,59 @@ EOF
exit 0 exit 0
} }
test_todo_completion () {
test "$#" = 3 ||
error "bug in the test script: not 3 parameters to test_todo_completion"
if ! test_skip "$@"
then
description=$1
expected=$3
if [ "${2: -1}" = ' ' ]
then
offset=0
say >&3 "expecting completions after: '$2'"
else
offset=1
say >&3 "expecting context completions for: '$2'"
fi
SAVEIFS=$IFS
IFS=' ' set -- $2
COMP_WORDS=("$@")
COMP_CWORD=$(($# - $offset))
IFS=' ' set -- $expected
EXPECT=("$@")
source "$TEST_DIRECTORY/../todo_completion"
_todo
ret=$?
if [ "$ret" = 0 ]
then
IFS=$'\n'
printf "%s${EXPECT:+\\n}" "${EXPECT[*]}" > expect
printf "%s${COMPREPLY:+\\n}" "${COMPREPLY[*]}" > compreply
IFS=$SAVEIFS
if [ ${#COMPREPLY[@]} -eq ${#EXPECT[@]} ]
then
if [ "${COMPREPLY[*]}" = "${EXPECT[*]}" ]
then
test_ok_ "$description"
else
test_failure_ "$description" "$(test_cmp expect compreply)"
fi
else
test_failure_ "$description" "expected ${#EXPECT[@]} completion(s), got ${#COMPREPLY[@]}:
$(test_cmp expect compreply)"
fi
else
test_failure_ "$description" "expected completions, actual exit code $ret"
fi
fi
echo >&3 ""
}
test_init_todo "$test" test_init_todo "$test"
# Use -P to resolve symlinks in our working directory so that the pwd # Use -P to resolve symlinks in our working directory so that the pwd
# in subprocesses equals our $PWD (for pathname comparisons). # in subprocesses equals our $PWD (for pathname comparisons).

View File

@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/bash
test_description='Providing an interactive shell in the proper environment' test_description='Providing an interactive shell in the proper environment'
. ./test-lib.sh . ./test-lib.sh

View File

@@ -8,7 +8,6 @@ export TODO_DIR=`dirname "$0"`
export TODO_FILE="$TODO_DIR/todo.txt" export TODO_FILE="$TODO_DIR/todo.txt"
export DONE_FILE="$TODO_DIR/done.txt" export DONE_FILE="$TODO_DIR/done.txt"
export REPORT_FILE="$TODO_DIR/report.txt" export REPORT_FILE="$TODO_DIR/report.txt"
export TMP_FILE="$TODO_DIR/todo.tmp"
# You can customize your actions directory location # You can customize your actions directory location
#export TODO_ACTIONS_DIR="$HOME/.todo.actions.d" #export TODO_ACTIONS_DIR="$HOME/.todo.actions.d"

96
todo.sh
View File

@@ -59,7 +59,7 @@ shorthelp()
listall|lsa [TERM...] listall|lsa [TERM...]
listcon|lsc listcon|lsc
listfile|lf [SRC [TERM...]] listfile|lf [SRC [TERM...]]
listpri|lsp [PRIORITY] [TERM...] listpri|lsp [PRIORITIES] [TERM...]
listproj|lsprj [TERM...] 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"
@@ -136,7 +136,7 @@ help()
EndOptionsHelp EndOptionsHelp
[ $TODOTXT_VERBOSE -gt 1 ] && cat <<-EndVerboseHelp [ $TODOTXT_VERBOSE -gt 1 ] && cat <<-'EndVerboseHelp'
Environment variables: Environment variables:
TODOTXT_AUTO_ARCHIVE is same as option -a (0)/-A (1) TODOTXT_AUTO_ARCHIVE is same as option -a (0)/-A (1)
TODOTXT_CFG_FILE=CONFIG_FILE is same as option -d CONFIG_FILE TODOTXT_CFG_FILE=CONFIG_FILE is same as option -d CONFIG_FILE
@@ -149,6 +149,7 @@ help()
TODOTXT_DEFAULT_ACTION="" run this when called with no arguments TODOTXT_DEFAULT_ACTION="" run this when called with no arguments
TODOTXT_SORT_COMMAND="sort ..." customize list output TODOTXT_SORT_COMMAND="sort ..." customize list output
TODOTXT_FINAL_FILTER="sed ..." customize list after color, P@+ hiding TODOTXT_FINAL_FILTER="sed ..." customize list after color, P@+ hiding
TODOTXT_SOURCEVAR=\$DONE_FILE use another source for listcon, listproj
EndVerboseHelp EndVerboseHelp
@@ -231,10 +232,11 @@ help()
Without any arguments, the names of all text files in the todo.txt Without any arguments, the names of all text files in the todo.txt
directory are listed. directory are listed.
listpri [PRIORITY] [TERM...] listpri [PRIORITIES] [TERM...]
lsp [PRIORITY] [TERM...] lsp [PRIORITIES] [TERM...]
Displays all tasks prioritized PRIORITY. Displays all tasks prioritized PRIORITIES.
If no PRIORITY specified, lists all prioritized tasks. PRIORITIES can be a single one (A) or a range (A-C).
If no PRIORITIES specified, lists all prioritized tasks.
If TERM specified, lists only prioritized tasks that contain TERM(s). If TERM specified, lists only prioritized tasks that contain TERM(s).
Hides all tasks that contain TERM(s) preceded by a minus sign Hides all tasks that contain TERM(s) preceded by a minus sign
(i.e. -TERM). (i.e. -TERM).
@@ -302,12 +304,6 @@ die()
exit 1 exit 1
} }
cleanup()
{
[ -f "$TMP_FILE" ] && rm "$TMP_FILE"
return 0
}
cleaninput() cleaninput()
{ {
# Parameters: When $1 = "for sed", performs additional escaping for use # Parameters: When $1 = "for sed", performs additional escaping for use
@@ -670,7 +666,6 @@ ACTION=${1:-$TODOTXT_DEFAULT_ACTION}
[ -d "$TODO_DIR" ] || die "Fatal Error: $TODO_DIR is not a directory" [ -d "$TODO_DIR" ] || die "Fatal Error: $TODO_DIR is not a directory"
( cd "$TODO_DIR" ) || die "Fatal Error: Unable to cd to $TODO_DIR" ( cd "$TODO_DIR" ) || die "Fatal Error: Unable to cd to $TODO_DIR"
[ -w "$TMP_FILE" ] || echo -n > "$TMP_FILE" || die "Fatal Error: Unable to write to $TMP_FILE"
[ -f "$TODO_FILE" ] || cp /dev/null "$TODO_FILE" [ -f "$TODO_FILE" ] || cp /dev/null "$TODO_FILE"
[ -f "$DONE_FILE" ] || cp /dev/null "$DONE_FILE" [ -f "$DONE_FILE" ] || cp /dev/null "$DONE_FILE"
[ -f "$REPORT_FILE" ] || cp /dev/null "$REPORT_FILE" [ -f "$REPORT_FILE" ] || cp /dev/null "$REPORT_FILE"
@@ -760,13 +755,32 @@ _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
## Build the filter. _format "$src" '' "$@"
filter_command=$(filtercommand "${pre_filter_command:-}" "${post_filter_command:-}" "$@")
## Figure out how much padding we need to use if [ $TODOTXT_VERBOSE -gt 0 ]; then
## We need one level of padding for each power of 10 $LINES uses echo "--"
LINES=$( sed -n '$ =' "$src" ) echo "$(getPrefix "$src"): ${NUMTASKS:-0} of ${TOTALTASKS:-0} tasks shown"
PADDING=${#LINES} fi
}
getPadding()
{
## We need one level of padding for each power of 10 $LINES uses.
LINES=$(sed -n '$ =' "${1:-$TODO_FILE}")
printf %s ${#LINES}
}
_format()
{
# Parameters: $1: todo input file; when empty formats stdin
# $2: ITEM# number width; if empty auto-detects from $1 / $TODO_FILE.
# Precondition: None
# Postcondition: $NUMTASKS and $TOTALTASKS contain statistics (unless $TODOTXT_VERBOSE=0).
FILE=$1
shift
## Figure out how much padding we need to use, unless this was passed to us.
PADDING=${1:-$(getPadding "$FILE")}
shift
## Number the file, then run the filter command, ## Number the file, then run the filter command,
## then sort and mangle output some more ## then sort and mangle output some more
@@ -774,7 +788,11 @@ _list() {
TODOTXT_FINAL_FILTER="cat" TODOTXT_FINAL_FILTER="cat"
fi fi
items=$( items=$(
sed = "$src" \ if [ "$FILE" ]; then
sed = "$FILE"
else
sed =
fi \
| sed -e ''' | sed -e '''
N N
s/^/ / s/^/ /
@@ -782,6 +800,9 @@ _list() {
/^[ 0-9]\{1,\} *$/d /^[ 0-9]\{1,\} *$/d
''' '''
) )
## Build and apply the filter.
filter_command=$(filtercommand "${pre_filter_command:-}" "${post_filter_command:-}" "$@")
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
@@ -806,7 +827,7 @@ _list() {
{ {
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 (match($0, /^[0-9]+ \([A-Z]\)[[:space:]]/)) { } else if (match($0, /^[0-9]+ \([A-Z]\) /)) {
clr = highlight("PRI_" substr($0, RSTART + RLENGTH - 3, 1)) clr = highlight("PRI_" substr($0, RSTART + RLENGTH - 3, 1))
print \ print \
(clr ? clr : highlight("PRI_X")) \ (clr ? clr : highlight("PRI_X")) \
@@ -827,16 +848,13 @@ _list() {
if [ $TODOTXT_VERBOSE -gt 0 ]; then if [ $TODOTXT_VERBOSE -gt 0 ]; then
NUMTASKS=$( echo -n "$filtered_items" | sed -n '$ =' ) NUMTASKS=$( echo -n "$filtered_items" | sed -n '$ =' )
TOTALTASKS=$( echo -n "$items" | sed -n '$ =' ) TOTALTASKS=$( echo -n "$items" | sed -n '$ =' )
echo "--"
echo "$(getPrefix "$FILE"): ${NUMTASKS:-0} of ${TOTALTASKS:-0} tasks shown"
fi fi
if [ $TODOTXT_VERBOSE -gt 1 ]; then if [ $TODOTXT_VERBOSE -gt 1 ]; then
echo "TODO DEBUG: Filter Command was: ${filter_command:-cat}" echo "TODO DEBUG: Filter Command was: ${filter_command:-cat}"
fi fi
} }
export -f cleaninput getPrefix getTodo getNewtodo shellquote filtercommand _list die export -f cleaninput getPrefix getTodo getNewtodo shellquote filtercommand _list getPadding _format 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' )
@@ -854,9 +872,7 @@ then
elif [ -d "$TODO_ACTIONS_DIR" -a -x "$TODO_ACTIONS_DIR/$action" ] elif [ -d "$TODO_ACTIONS_DIR" -a -x "$TODO_ACTIONS_DIR/$action" ]
then then
"$TODO_ACTIONS_DIR/$action" "$@" "$TODO_ACTIONS_DIR/$action" "$@"
status=$? exit $?
cleanup
exit $status
fi fi
## Only run if $action isn't found in .todo.actions.d ## Only run if $action isn't found in .todo.actions.d
@@ -1082,16 +1098,16 @@ case $action in
"listall" | "lsa" ) "listall" | "lsa" )
shift ## Was lsa; new $1 is first search term shift ## Was lsa; new $1 is first search term
cat "$TODO_FILE" "$DONE_FILE" > "$TMP_FILE"
TOTAL=$( sed -n '$ =' "$TODO_FILE" ) TOTAL=$( sed -n '$ =' "$TODO_FILE" )
PADDING=${#TOTAL}
post_filter_command="awk -v TOTAL=$TOTAL -v PADDING=${#TOTAL} '{ \$1 = sprintf(\"%\" PADDING \"d\", (\$1 > TOTAL ? 0 : \$1)); print }' " post_filter_command="awk -v TOTAL=$TOTAL -v PADDING=$PADDING '{ \$1 = sprintf(\"%\" PADDING \"d\", (\$1 > TOTAL ? 0 : \$1)); print }' "
TODOTXT_VERBOSE=0 _list "$TMP_FILE" "$@" cat "$TODO_FILE" "$DONE_FILE" | TODOTXT_VERBOSE=0 _format '' "$PADDING" "$@"
if [ $TODOTXT_VERBOSE -gt 0 ]; then if [ $TODOTXT_VERBOSE -gt 0 ]; then
TDONE=$( sed -n '$ =' "$DONE_FILE" ) TDONE=$( sed -n '$ =' "$DONE_FILE" )
TASKNUM=$(TODOTXT_PLAIN=1 TODOTXT_VERBOSE=0 _list "$TODO_FILE" "$@" | sed -n '$ =') TASKNUM=$(TODOTXT_PLAIN=1 TODOTXT_VERBOSE=0 _format "$TODO_FILE" 1 "$@" | sed -n '$ =')
DONENUM=$(TODOTXT_PLAIN=1 TODOTXT_VERBOSE=0 _list "$DONE_FILE" "$@" | sed -n '$ =') DONENUM=$(TODOTXT_PLAIN=1 TODOTXT_VERBOSE=0 _format "$DONE_FILE" 1 "$@" | sed -n '$ =')
echo "--" echo "--"
echo "$(getPrefix "$TODO_FILE"): ${TASKNUM:-0} of ${TOTAL:-0} tasks shown" echo "$(getPrefix "$TODO_FILE"): ${TASKNUM:-0} of ${TOTAL:-0} tasks shown"
echo "$(getPrefix "$DONE_FILE"): ${DONENUM:-0} of ${TDONE:-0} tasks shown" echo "$(getPrefix "$DONE_FILE"): ${DONENUM:-0} of ${TDONE:-0} tasks shown"
@@ -1113,19 +1129,23 @@ case $action in
;; ;;
"listcon" | "lsc" ) "listcon" | "lsc" )
grep -o '[^ ]*@[^ ]\+' "$TODO_FILE" | grep '^@' | sort -u FILE=$TODO_FILE
[ "$TODOTXT_SOURCEVAR" ] && eval "FILE=$TODOTXT_SOURCEVAR"
grep -ho '[^ ]*@[^ ]\+' "${FILE[@]}" | grep '^@' | sort -u
;; ;;
"listproj" | "lsprj" ) "listproj" | "lsprj" )
FILE=$TODO_FILE
[ "$TODOTXT_SOURCEVAR" ] && eval "FILE=$TODOTXT_SOURCEVAR"
shift shift
eval "$(filtercommand 'cat "$TODO_FILE"' '' "$@")" | grep -o '[^ ]*+[^ ]\+' | grep '^+' | sort -u eval "$(filtercommand 'cat "${FILE[@]}"' '' "$@")" | grep -o '[^ ]*+[^ ]\+' | grep '^+' | sort -u
;; ;;
"listpri" | "lsp" ) "listpri" | "lsp" )
shift ## was "listpri", new $1 is priority to list or first TERM shift ## was "listpri", new $1 is priority to list or first TERM
pri=$(printf "%s\n" "$1" | tr 'a-z' 'A-Z' | grep '^[A-Z]$') && shift || pri="[A-Z]" pri=$(printf "%s\n" "$1" | tr 'a-z' 'A-Z' | grep -e '^[A-Z]$' -e '^[A-Z]-[A-Z]$') && shift || pri="A-Z"
post_filter_command="grep '^ *[0-9]\+ (${pri}) '" post_filter_command="grep '^ *[0-9]\+ ([${pri}]) '"
_list "$TODO_FILE" "$@" _list "$TODO_FILE" "$@"
;; ;;
@@ -1283,5 +1303,3 @@ note: PRIORITY must be anywhere from A to Z."
* ) * )
usage;; usage;;
esac esac
cleanup

View File

@@ -35,8 +35,18 @@ _todo()
completions=$(TODOTXT_VERBOSE=0 todo.sh command listfile);; completions=$(TODOTXT_VERBOSE=0 todo.sh command listfile);;
-*) completions="$allCommands $OPTS";; -*) completions="$allCommands $OPTS";;
*) case "$cur" in *) case "$cur" in
+*) completions=$(TODOTXT_VERBOSE=0 todo.sh command listproj);; +*) completions=$(TODOTXT_VERBOSE=0 todo.sh command listproj)
@*) completions=$(TODOTXT_VERBOSE=0 todo.sh command listcon);; COMPREPLY=( $( compgen -W "$completions" -- $cur ))
[ ${#COMPREPLY[@]} -gt 0 ] && return 0
# Fall back to projects extracted from done tasks.
completions=$(TODOTXT_VERBOSE=0 TODOTXT_SOURCEVAR=\$DONE_FILE todo.sh command listproj)
;;
@*) completions=$(TODOTXT_VERBOSE=0 todo.sh command listcon)
COMPREPLY=( $( compgen -W "$completions" -- $cur ))
[ ${#COMPREPLY[@]} -gt 0 ] && return 0
# Fall back to contexts extracted from done tasks.
completions=$(TODOTXT_VERBOSE=0 TODOTXT_SOURCEVAR=\$DONE_FILE todo.sh command listcon)
;;
*) if [[ "$cur" =~ ^[0-9]+$ ]]; then *) if [[ "$cur" =~ ^[0-9]+$ ]]; then
# Remove the (padded) task number; we prepend the # Remove the (padded) task number; we prepend the
# user-provided $cur instead. # user-provided $cur instead.