Compare commits

..

7 Commits

Author SHA1 Message Date
Ingo Karkat
cb53da0c96 Create dedicated test file for report tests. 2012-01-14 21:48:48 +01:00
Ingo Karkat
8e3f2712a8 ENH: Only add new data to report.
When the last reported values are identical to the current values, do not append the same information (just with a new timestamp) to the report. Instead, just print the last report line.

With this, the report action can be scheduled periodically (e.g. via cron) without artificially inflating the report file.
2012-01-14 15:21:53 +01:00
Ingo Karkat
20b7ef6964 Align report order with other actions.
Like "add" or "do", first the object, then (in verbose mode) the status message is printed.
2012-01-14 15:10:22 +01:00
Ingo Karkat
45e9dc7550 Use ISO 8601 timestamp format.
IMO 2012-01-14T14:49 looks better than the messy -*-*-*- of 2012-01-14-14:49, and is more aligned with standards.
2012-01-14 15:04:55 +01:00
Ingo Karkat
a8df23ec3c Simplify writing of report line. 2012-01-14 14:58:58 +01:00
Ingo Karkat
6d860d2506 Only print the added report line, not entire report.
I think this makes much more sense, especially once the report gets very long. (One can always use "cat" to view the entire report.)
2012-01-14 14:56:03 +01:00
Ingo Karkat
a686659985 Remove inactive broken report header.
This was meant to write a report header on the initial report run, but as it mistakenly used TODO_FILE instead of REPORT_FILE, it was inactive, and also missing in the tests. Let's just remove it; the format is simple, anyway.
2012-01-14 14:41:58 +01:00
51 changed files with 238 additions and 1579 deletions

3
.gitignore vendored
View File

@@ -1,6 +1,3 @@
VERSION-FILE
tests/test-results
tests/trash\ directory.*
done.txt
report.txt
todo.txt

View File

@@ -21,7 +21,6 @@ h2. Quick Links
* Original anemic release by "Gina Trapani":http://ginatrapani.org on 5/11/2006.
* Raised to great heights by "brainy and dedicated volunteers":http://github.com/ginatrapani/todo.txt-cli/network.
* Licensed under the "GPL":http://www.gnu.org/copyleft/gpl.html
* "Add-on Directory":https://github.com/ginatrapani/todo.txt-cli/wiki/Todo.sh-Add-on-Directory
https://github.com/ginatrapani/todo.txt-cli/wiki/Creating-and-Installing-Add-ons
* "Add-on Directory":http://wiki.github.com/ginatrapani/todo.txt-cli/todosh-add-on-directory
* "Changelog":http://wiki.github.com/ginatrapani/todo.txt-cli/todosh-changelog
* "Known Bugs":http://github.com/ginatrapani/todo.txt-cli/issues
* "Known Bugs":http://github.com/ginatrapani/todo.txt-cli/issues

View File

@@ -125,10 +125,10 @@ Writing Tests
-------------
The test script is written as a shell script. It should start
with the standard "#!/bin/bash" with copyright notices, and an
with the standard "#!/bin/sh" with copyright notices, and an
assignment to variable 'test_description', like this:
#!/bin/bash
#!/bin/sh
#
# Copyright (c) 2005 Junio C Hamano
#
@@ -186,24 +186,6 @@ library for your script to use.
expected output. (See below for how to generate transcripts
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. If any completion
contains whitespace, quote it; the entire <completions>
argument is eval()'ed.
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_todo_custom_completion <completefunc> <message> <cmdline> <completions>
Same as above, but in addition allows to specify a custom
completion function.
- test_tick [interval]
The test harness has an internal view of time which is
@@ -223,13 +205,6 @@ library for your script to use.
'git-write-tree should be able to write an empty tree.' \
'tree=$(git-write-tree)'
- test_expect_code <code> <message> <script>
This takes an exit status and two strings as parameter, and
evaluates the <script>. If it yields <code>, test is
considered successful. <message> should state what it is
testing.
- test_expect_failure <message> <script>
This is NOT the opposite of test_expect_success, but is used

View File

@@ -1,18 +0,0 @@
#!/bin/bash
make_action()
{
unset TODO_ACTIONS_DIR
[ -d .todo.actions.d ] || mkdir .todo.actions.d
cat > ".todo.actions.d/$1" <<EOF
#!/bin/bash
[ "\$1" = "usage" ] && {
echo " $1 ITEM#[, ITEM#, ...] [TERM...]"
echo " This custom action does $1."
echo ""
exit
}
echo "custom action $1"
EOF
chmod +x ".todo.actions.d/$1"
}

View File

@@ -1,57 +1,4 @@
#!/bin/bash
[ "x$TERM" != "xdumb" ] && (
export TERM &&
[ -t 1 ] &&
tput bold >/dev/null 2>&1 &&
tput setaf 1 >/dev/null 2>&1 &&
tput sgr0 >/dev/null 2>&1
) &&
color=t
case "$1" in
--no-color)
color=; shift ;;
esac
if test -n "$color"; then
say_color () {
(
export TERM
case "$1" in
error) tput bold; tput setaf 1;; # bold red
skip) tput bold; tput setaf 2;; # bold green
pass) tput setaf 2;; # green
info) tput setaf 3;; # brown
*) test -n "$quiet" && return;;
esac
shift
printf "* %s" "$*"
tput sgr0
echo
)
}
else
say_color() {
test -z "$1" && test -n "$quiet" && return
shift
echo "* $*"
}
fi
get_color()
{
# Only use the supplied color if there are actually instances of that
# type, so that a clean test run does not distract the user by the
# appearance of the error highlighting.
if [ ${1:?} -eq 0 ]
then
echo 'info'
else
echo "${2:-info}"
fi
}
#!/bin/sh
fixed=0
success=0
@@ -80,8 +27,8 @@ do
done <"$file"
done
say_color 'info' "$(printf "%-8s%d\n" fixed $fixed)"
say_color "$(get_color "$success" 'pass')" "$(printf "%-8s%d\n" success $success)"
say_color "$(get_color "$failed" 'error')" "$(printf "%-8s%d\n" failed $failed)"
say_color "$(get_color "$broken" 'error')" "$(printf "%-8s%d\n" broken $broken)"
say_color 'info' "$(printf "%-8s%d\n" total $total)"
printf "%-8s%d\n" fixed $fixed
printf "%-8s%d\n" success $success
printf "%-8s%d\n" failed $failed
printf "%-8s%d\n" broken $broken
printf "%-8s%d\n" total $total

View File

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

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
test_description='todo.sh basic null functionality test.
@@ -45,8 +45,6 @@ test_expect_success 'null listpri a' '
cat > expect <<EOF
--
TODO: 0 of 0 tasks shown
DONE: 0 of 0 tasks shown
total 0 of 0 tasks shown
EOF
test_expect_success 'null lsa' '

View File

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

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
test_description='no old-style backtick command substitution
@@ -9,15 +9,8 @@ On failure, it will print each offending line number and line.
'
. ./test-lib.sh
backtick_check()
{
sed -n -e 's/\(^\|[ \t]\)#.*//' -e '/`/{' -e '=;p' -e '}' "$@"
}
test_todo_session 'no old-style backtick command substitution' <<EOF
>>> backtick_check bin/todo.sh
>>> backtick_check ../../todo.cfg
>>> sed -n -e 's/\(^\|[ \t]\)#.*//' -e '/\`/{' -e '=;p' -e '}' "$(which todo.sh)"
EOF
test_done

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
test_description='basic replace functionality
@@ -164,12 +164,4 @@ TODO: Replaced task with:
1 (A) 2010-07-04 this also has a new date
EOF
echo '2009-02-13 this is just a new one' > todo.txt
test_todo_session 'replace with prepended priority and date replaces existing date' <<EOF
>>> todo.sh replace 1 '(B) 2010-07-04 this also has a new date'
1 2009-02-13 this is just a new one
TODO: Replaced task with:
1 (B) 2010-07-04 this also has a new date
EOF
test_done

View File

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

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
test_description='list priority functionality
'
@@ -61,42 +61,6 @@ TODO: 0 of 5 tasks shown
TODO: 0 of 5 tasks shown
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
(B) ccc xxx this line should be third.
ccc xxx this line should be third.

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

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
#
test_description='list functionality
@@ -53,18 +53,6 @@ test_todo_session 'checking TODOTXT_FINAL_FILTER' <<EOF
TODO: 3 of 3 tasks shown
EOF
#
# check the custom hiding
#
test_todo_session 'checking HIDE_CUSTOM_SUBSTITUTION' <<EOF
>>> HIDE_CUSTOM_SUBSTITUTION='[tT]h' todo.sh ls
2 aaa zzz is line should be first.
3 bbb yyy is line should be second.
1 ccc xxx is line should be ird.
--
TODO: 3 of 3 tasks shown
EOF
#
# check the filtering of TERM
#

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
#
test_description='listcon functionality
@@ -55,33 +55,4 @@ test_todo_session 'listcon e-mail address test' <<EOF
@con02
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 'listcon with project' <<EOF
>>> todo.sh listcon +landscape
@garden
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

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
#
test_description='listproj functionality
@@ -55,63 +55,4 @@ test_todo_session 'listproj embedded + test' <<EOF
+prj02
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

View File

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

View File

@@ -1,150 +0,0 @@
#!/bin/bash
test_description='listall functionality
'
. ./test-lib.sh
cat > todo.txt <<EOF
smell the uppercase Roses +flowers @outside
x 2011-08-08 tend the garden @outside
notice the sunflowers
x 2011-12-26 go outside +wakeup
(A) stop
EOF
cat > done.txt <<EOF
x 2011-12-01 eat breakfast
x 2011-12-05 smell the coffee +wakeup
EOF
test_todo_session 'basic listall' <<EOF
>>> todo.sh -p listall
5 (A) stop
3 notice the sunflowers
1 smell the uppercase Roses +flowers @outside
2 x 2011-08-08 tend the garden @outside
0 x 2011-12-01 eat breakfast
0 x 2011-12-05 smell the coffee +wakeup
4 x 2011-12-26 go outside +wakeup
--
TODO: 5 of 5 tasks shown
DONE: 2 of 2 tasks shown
total 7 of 7 tasks shown
EOF
test_todo_session 'listall highlighting' <<EOF
>>> todo.sh listall
5 (A) stop
3 notice the sunflowers
1 smell the uppercase Roses +flowers @outside
2 x 2011-08-08 tend the garden @outside
0 x 2011-12-01 eat breakfast
0 x 2011-12-05 smell the coffee +wakeup
4 x 2011-12-26 go outside +wakeup
--
TODO: 5 of 5 tasks shown
DONE: 2 of 2 tasks shown
total 7 of 7 tasks shown
EOF
test_todo_session 'listall nonverbose' <<EOF
>>> TODOTXT_VERBOSE=0 todo.sh -p listall
5 (A) stop
3 notice the sunflowers
1 smell the uppercase Roses +flowers @outside
2 x 2011-08-08 tend the garden @outside
0 x 2011-12-01 eat breakfast
0 x 2011-12-05 smell the coffee +wakeup
4 x 2011-12-26 go outside +wakeup
EOF
test_todo_session 'listall filtering' <<EOF
>>> todo.sh -p listall @outside
1 smell the uppercase Roses +flowers @outside
2 x 2011-08-08 tend the garden @outside
--
TODO: 2 of 5 tasks shown
DONE: 0 of 2 tasks shown
total 2 of 7 tasks shown
>>> todo.sh -p listall the
3 notice the sunflowers
1 smell the uppercase Roses +flowers @outside
2 x 2011-08-08 tend the garden @outside
0 x 2011-12-05 smell the coffee +wakeup
--
TODO: 3 of 5 tasks shown
DONE: 1 of 2 tasks shown
total 4 of 7 tasks shown
>>> todo.sh -p listall breakfast
0 x 2011-12-01 eat breakfast
--
TODO: 0 of 5 tasks shown
DONE: 1 of 2 tasks shown
total 1 of 7 tasks shown
>>> todo.sh -p listall doesnotmatch
--
TODO: 0 of 5 tasks shown
DONE: 0 of 2 tasks shown
total 0 of 7 tasks shown
EOF
cat >> done.txt <<EOF
x 2010-01-01 old task 1
x 2010-01-01 old task 2
x 2010-01-01 old task 3
x 2010-01-01 old task 4
EOF
test_todo_session 'listall number width' <<EOF
>>> todo.sh -p listall
5 (A) stop
3 notice the sunflowers
1 smell the uppercase Roses +flowers @outside
0 x 2010-01-01 old task 1
0 x 2010-01-01 old task 2
0 x 2010-01-01 old task 3
0 x 2010-01-01 old task 4
2 x 2011-08-08 tend the garden @outside
0 x 2011-12-01 eat breakfast
0 x 2011-12-05 smell the coffee +wakeup
4 x 2011-12-26 go outside +wakeup
--
TODO: 5 of 5 tasks shown
DONE: 6 of 6 tasks shown
total 11 of 11 tasks shown
>>> TODOTXT_VERBOSE=0 todo.sh add new task 1
>>> TODOTXT_VERBOSE=0 todo.sh add new task 2
>>> TODOTXT_VERBOSE=0 todo.sh add new task 3
>>> TODOTXT_VERBOSE=0 todo.sh add new task 4
>>> TODOTXT_VERBOSE=0 todo.sh add new task 5
>>> todo.sh -p listall
05 (A) stop
06 new task 1
07 new task 2
08 new task 3
09 new task 4
10 new task 5
03 notice the sunflowers
01 smell the uppercase Roses +flowers @outside
00 x 2010-01-01 old task 1
00 x 2010-01-01 old task 2
00 x 2010-01-01 old task 3
00 x 2010-01-01 old task 4
02 x 2011-08-08 tend the garden @outside
00 x 2011-12-01 eat breakfast
00 x 2011-12-05 smell the coffee +wakeup
04 x 2011-12-26 go outside +wakeup
--
TODO: 10 of 10 tasks shown
DONE: 6 of 6 tasks shown
total 16 of 16 tasks shown
EOF
test_done

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,35 +0,0 @@
#!/bin/bash
test_description='archive functionality
Ensure we can archive items successfully.
'
. ./test-lib.sh
cat > todo.txt <<EOF
one
two
three
one
x done
four
EOF
test_todo_session 'archive with duplicates' <<EOF
>>> todo.sh archive
x done
TODO: $HOME/todo.txt archived.
EOF
test_todo_session 'list after archive' <<EOF
>>> todo.sh ls
5 four
1 one
4 one
3 three
2 two
--
TODO: 5 of 5 tasks shown
EOF
test_done

View File

@@ -1,103 +0,0 @@
#!/bin/bash
test_description='deduplicate functionality
Ensure we can deduplicate items successfully.
'
. ./test-lib.sh
cat > todo.txt <<EOF
duplicated
two
x done
duplicated
double task
double task
three
EOF
test_todo_session 'deduplicate and preserve line numbers' <<EOF
>>> todo.sh deduplicate
TODO: 2 duplicate task(s) removed
>>> todo.sh -p ls
5 double task
1 duplicated
7 three
2 two
3 x done
--
TODO: 5 of 5 tasks shown
EOF
test_todo_session 'deduplicate without duplicates' <<EOF
>>> todo.sh deduplicate
TODO: No duplicate tasks found
EOF
cat > todo.txt <<EOF
duplicated
two
x done
duplicated
double task
double task
three
EOF
test_todo_session 'deduplicate and delete lines' <<EOF
>>> todo.sh -n deduplicate
TODO: 2 duplicate task(s) removed
>>> todo.sh -p ls
4 double task
1 duplicated
5 three
2 two
3 x done
--
TODO: 5 of 5 tasks shown
EOF
cat > todo.txt <<EOF
one
duplicated
three
duplicated
duplicated
six
duplicated
EOF
test_todo_session 'deduplicate more than two occurrences' <<EOF
>>> todo.sh deduplicate
TODO: 3 duplicate task(s) removed
>>> todo.sh -p ls
2 duplicated
1 one
6 six
3 three
--
TODO: 4 of 4 tasks shown
EOF
cat > todo.txt <<EOF
normal task
a bold task
something else
a bold task
something more
EOF
test_todo_session 'deduplicate with non-printable duplicates' <<EOF
>>> todo.sh deduplicate
TODO: 1 duplicate task(s) removed
>>> todo.sh -p ls
2 a bold task
1 normal task
3 something else
5 something more
--
TODO: 4 of 4 tasks shown
EOF
test_done

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
test_description='report functionality
@@ -16,7 +16,6 @@ EOF
test_todo_session 'create new report' <<EOF
>>> todo.sh report
TODO: $HOME/todo.txt archived.
2009-02-13T04:40:00 5 0
TODO: Report file updated.
@@ -38,7 +37,6 @@ x 2009-02-13 smell the coffee +wakeup
TODO: $HOME/todo.txt archived.
>>> todo.sh report
TODO: $HOME/todo.txt archived.
2009-02-13T04:40:00 4 1
TODO: Report file updated.
@@ -57,8 +55,6 @@ test_todo_session 'report performs archiving' <<EOF
TODO: 3 marked as done.
>>> todo.sh report
x 2009-02-13 make the coffee +wakeup
TODO: $HOME/todo.txt archived.
2009-02-13T04:40:00 3 2
TODO: Report file updated.
@@ -83,7 +79,6 @@ test_todo_session 'report is unchanged when no changes' <<EOF
2009-02-13T04:40:00 3 2
>>> todo.sh report
TODO: $HOME/todo.txt archived.
2009-02-13T04:40:00 3 2
TODO: Report file is up-to-date.

View File

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

View File

@@ -1,44 +0,0 @@
#!/bin/bash
#
test_description='help functionality
This test covers the help output.
'
. ./actions-test-lib.sh
. ./test-lib.sh
# Note: To avoid having to adapt the test whenever the help documentation
# slightly changes, only check for the section headers.
test_todo_session 'help output' <<EOF
>>> todo.sh help | sed '/^ [A-Z]/!d'
Usage: todo.sh [-fhpantvV] [-d todo_config] action [task_number] [task_description]
Options:
Built-in Actions:
EOF
test_todo_session 'verbose help output' <<EOF
>>> todo.sh -v help | sed '/^ [A-Z]/!d'
Usage: todo.sh [-fhpantvV] [-d todo_config] action [task_number] [task_description]
Options:
Built-in Actions:
EOF
test_todo_session 'very verbose help output' <<EOF
>>> todo.sh -vv help | sed '/^ [A-Z]/!d'
Usage: todo.sh [-fhpantvV] [-d todo_config] action [task_number] [task_description]
Options:
Environment variables:
Built-in Actions:
EOF
make_action "foo"
test_todo_session 'help output with custom action' <<EOF
>>> todo.sh -v help | sed '/^ [A-Z]/!d'
Usage: todo.sh [-fhpantvV] [-d todo_config] action [task_number] [task_description]
Options:
Built-in Actions:
Add-on Actions:
EOF
test_done

View File

@@ -1,66 +0,0 @@
#!/bin/bash
test_description='built-in actions help functionality
This test checks listing the usage help of a built-in action.
'
. ./test-lib.sh
test_todo_session 'nonexisting action help' <<'EOF'
>>> todo.sh help doesnotexist
TODO: No action "doesnotexist" exists.
=== 1
>>> todo.sh help hel
TODO: No action "hel" exists.
=== 1
>>> todo.sh help h
TODO: No action "h" exists.
=== 1
EOF
test_todo_session 'single action help' <<'EOF'
>>> todo.sh help shorthelp
shorthelp
List the one-line usage of all built-in and add-on actions.
\
EOF
test_todo_session 'multiple actions help' <<'EOF'
>>> todo.sh help shorthelp append
shorthelp
List the one-line usage of all built-in and add-on actions.
\
append ITEM# "TEXT TO APPEND"
app ITEM# "TEXT TO APPEND"
Adds TEXT TO APPEND to the end of the task on line ITEM#.
Quotes optional.
\
EOF
test_todo_session 'short and long form of action help' <<'EOF'
>>> todo.sh help append
append ITEM# "TEXT TO APPEND"
app ITEM# "TEXT TO APPEND"
Adds TEXT TO APPEND to the end of the task on line ITEM#.
Quotes optional.
\
>>> todo.sh help app
app ITEM# "TEXT TO APPEND"
Adds TEXT TO APPEND to the end of the task on line ITEM#.
Quotes optional.
\
EOF
test_todo_session 'mixed existing and nonexisting action help' <<'EOF'
>>> todo.sh help shorthelp doesnotexist list
shorthelp
List the one-line usage of all built-in and add-on actions.
\
TODO: No action "doesnotexist" exists.
=== 1
EOF
test_done

View File

@@ -1,22 +0,0 @@
#!/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 listaddons 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_todo_completion 'all arguments after option' 'todo.sh -a ' "$ACTIONS $OPTIONS"
test_todo_completion 'all arguments after options' 'todo.sh -a -p ' "$ACTIONS $OPTIONS"
test_todo_completion 'all options after options' 'todo.sh -a -p -' "$OPTIONS"
test_todo_completion 'nothing after action' 'todo.sh archive ' ''
test_done

View File

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

@@ -1,27 +0,0 @@
#!/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,27 +0,0 @@
#!/bin/bash
#
test_description='Bash task number completion functionality
This test checks todo_completion of a task number into the abbreviated task text.
'
. ./test-lib.sh
cat > todo.txt <<EOF
simple task
notice the sunflowers +sunflowers @outside @garden +shared +landscape
(B) smell the +roses flower @outside @outdoor +shared
(C) 2012-02-28 @outside mow the lawn
x 2012-02-21 +herbs @oriental buy spices
x 2012-02-28 2012-02-21 +slack @home watch tv
2012-02-28 +herbs buy cinnamon @grocer
EOF
test_todo_completion 'simple task' 'todo.sh list 1' '"1 # simple task"'
test_todo_completion 'remove projects and contents from task' 'todo.sh list 2' '"2 # notice the sunflowers"'
test_todo_completion 'keep priority' 'todo.sh list 3' '"3 # (B) smell the flower"'
test_todo_completion 'keep priority and remove timestamp' 'todo.sh list 4' '"4 # (C) mow the lawn"'
test_todo_completion 'keep done marker and remove done date' 'todo.sh list 5' '"5 # x buy spices"'
test_todo_completion 'keep done marker and remove timestamp and done date' 'todo.sh list 6' '"6 # x watch tv"'
test_todo_completion 'remove add date' 'todo.sh list 7' '"7 # buy cinnamon"'
test_done

View File

@@ -1,21 +0,0 @@
#!/bin/bash
#
test_description='Bash todo file completion functionality
This test checks todo_completion of files in TODO_DIR.
'
. ./test-lib.sh
> dummy.txt
readonly FILES='done.txt dummy.txt report.txt todo.txt'
test_todo_completion 'all files after addto' 'todo.sh addto ' "$FILES"
test_todo_completion 'files beginning with d after addto' 'todo.sh addto d' 'done.txt dummy.txt'
test_todo_completion 'all files after listfile' 'todo.sh listfile ' "$FILES"
test_todo_completion 'all files after lf' 'todo.sh -v lf ' "$FILES"
test_todo_completion 'nothing after move' 'todo.sh move ' ''
test_todo_completion 'all files after move ITEM#' 'todo.sh move 1 ' "$FILES"
test_todo_completion 'all files after mv ITEM#' 'todo.sh mv 1 ' "$FILES"
test_todo_completion 'all files after move ITEM# DEST' 'todo.sh move 1 todo.sh ' "$FILES"
test_done

View File

@@ -1,74 +0,0 @@
#!/bin/bash
#
test_description='Bash add-on action completion functionality
This test checks todo_completion of custom actions in .todo.actions.d
'
. ./test-lib.sh
readonly ACTIONS='add a addto addm append app archive command del rm depri dp do help list ls listaddons 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'
readonly ADDONS='bar baz foobar'
makeCustomActions()
{
set -e
mkdir "${1:?}"
for addon in $ADDONS
do
addonFile="${1}/$addon"
> "$addonFile"
chmod +x "$addonFile"
done
# Also create a subdirectory, to test that it is skipped.
mkdir "${1}/subdir"
# Also create a non-executable file, to test that it is skipped.
datafile="${1:?}/datafile"
> "$datafile"
chmod -x "$datafile"
[ -x "$datafile" ] && rm "$datafile" # Some file systems may always make files executable; then, skip this check.
set +e
}
removeCustomActions()
{
set -e
rmdir "${1}/subdir"
rm "${1:?}/"*
rmdir "$1"
set +e
}
#
# Test resolution of the default TODO_ACTIONS_DIR.
#
makeCustomActions "$HOME/.todo.actions.d"
test_todo_completion 'all arguments' 'todo.sh ' "$ACTIONS $ADDONS $OPTIONS"
test_todo_completion 'all arguments after option' 'todo.sh -a ' "$ACTIONS $ADDONS $OPTIONS"
test_todo_completion 'all arguments beginning with b' 'todo.sh b' 'bar baz'
test_todo_completion 'all arguments beginning with f after options' 'todo.sh -a -v f' 'foobar'
test_todo_completion 'nothing after addon action' 'todo.sh foobar ' ''
removeCustomActions "$HOME/.todo.actions.d"
#
# Test resolution of an alternative TODO_ACTIONS_DIR.
#
mkdir "$HOME/.todo"
makeCustomActions "$HOME/.todo/actions"
test_todo_completion 'all arguments with actions from .todo/actions/' 'todo.sh ' "$ACTIONS $ADDONS $OPTIONS"
removeCustomActions "$HOME/.todo/actions"
#
# Test resolution of a configured TODO_ACTIONS_DIR.
#
makeCustomActions "$HOME/addons"
cat >> todo.cfg <<'EOF'
export TODO_ACTIONS_DIR="$HOME/addons"
EOF
test_todo_completion 'all arguments with actions from addons/' 'todo.sh ' "$ACTIONS $ADDONS $OPTIONS"
removeCustomActions "$HOME/addons"
test_done

View File

@@ -1,45 +0,0 @@
#!/bin/bash
#
test_description='Bash completion with different path functionality
This test checks that todo_completion can use a different path to todo.sh when
it is not accessible through PATH.
'
. ./test-lib.sh
cat > todo.txt <<EOF
(B) smell the +roses @outside @outdoor +shared
notice the sunflowers +sunflowers @outside @garden +shared +landscape
stop
EOF
mv bin/todo.sh bin/todo2.sh
test_expect_success 'todo2.sh executable' 'todo2.sh list'
# Define a second completion function that injects the different executable. In
# real use, this would be installed via
# complete -F _todo2 todo2.sh
_todo2()
{
local _todo_sh='todo2.sh'
_todo "$@"
}
test_todo_custom_completion _todo2 'all todo2 contexts' 'todo2 list @' '@garden @outdoor @outside'
# Remove the test environment's bin directory from the PATH, so that our test
# executable must be launched with an explicit path.
PATH=${PATH##"${PWD}/bin:"}
test_expect_code 127 'todo2.sh executable not in PATH' 'todo2.sh'
_todo2path()
{
local _todo_sh='./bin/todo2.sh'
_todo "$@"
}
test_todo_custom_completion _todo2path 'all todo2 contexts' 'todo2 list @' '@garden @outdoor @outside'
test_done

View File

@@ -1,62 +0,0 @@
#!/bin/bash
#
test_description='Bash completion with different aliases functionality
This test checks that todo_completion can use a different configuration
when another todo.sh alias is defined that uses that configuration.
'
. ./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 > todo2.txt <<EOF
+herbs @oriental buy spices
+slack @home watch tv
EOF
cp todo.cfg todo2.cfg
cat >> todo2.cfg <<'EOF'
export TODO_FILE="$TODO_DIR/todo2.txt"
EOF
# Note: We cannot use aliases within the test framework, but functions are
# equivalent and work fine.
todo1()
{
todo.sh "$@"
}
todo2()
{
todo.sh -d "$HOME/todo2.cfg" "$@"
}
# Ensure that the test fixture works as planned.
test_todo_session 'todo 1 and 2 contexts' <<EOF
>>> todo1 listcon
@garden
@outdoor
@outside
>>> todo2 listcon
@home
@oriental
EOF
# Define a second completion function that injects the different configuration
# file. In real use, this would be installed via
# complete -F _todo2 todo2
_todo2()
{
local _todo_sh='todo.sh -d "$HOME/todo2.cfg"'
_todo "$@"
}
test_todo_completion 'all todo1 contexts' 'todo1 list @' '@garden @outdoor @outside'
test_todo_custom_completion _todo2 'all todo2 contexts' 'todo2 list @' '@home @oriental'
test_done

View File

@@ -1,20 +0,0 @@
#!/bin/bash
#
test_description='Bash help completion functionality
This test checks todo_completion of actions for usage help.
'
. ./actions-test-lib.sh
. ./test-lib.sh
make_action "zany"
make_action "aardvark"
readonly ACTIONS='add a addto addm append app archive command del rm depri dp do help list ls listaddons listall lsa listcon lsc listfile lf listpri lsp listproj lsprj move mv prepend prep pri p replace report shorthelp'
readonly ADDONS='aardvark zany'
test_todo_completion 'all actions after help' 'todo.sh help ' "$ACTIONS $ADDONS"
test_todo_completion 'all actions after command help' 'todo.sh command help ' "$ACTIONS $ADDONS"
test_todo_completion 'actions beginning with a' 'todo.sh help a' 'add a addto addm append app archive aardvark'
test_done

View File

@@ -1,12 +1,22 @@
#!/bin/bash
#!/bin/sh
test_description='custom actions functionality
This test covers the contract between todo.sh and custom actions.
'
. ./actions-test-lib.sh
. ./test-lib.sh
unset TODO_ACTIONS_DIR
mkdir .todo.actions.d
make_action()
{
cat > ".todo.actions.d/$1" <<- EOF
#!/bin/bash
echo "custom action $1"
EOF
chmod +x ".todo.actions.d/$1"
}
make_action "foo"
test_todo_session 'executable action' <<EOF
>>> todo.sh foo

View File

@@ -1,44 +0,0 @@
#!/bin/bash
test_description='listaddons functionality
This test checks listing of custom actions.
'
. ./actions-test-lib.sh
. ./test-lib.sh
test_todo_session 'no custom actions' <<EOF
>>> todo.sh listaddons
EOF
make_action "foo"
test_todo_session 'one custom action' <<EOF
>>> todo.sh listaddons
foo
EOF
make_action "bar"
make_action "ls"
make_action "quux"
test_todo_session 'multiple custom actions' <<EOF
>>> todo.sh listaddons
bar
foo
ls
quux
EOF
chmod -x .todo.actions.d/foo
# On Cygwin, clearing the executable flag may have no effect, as the Windows ACL
# may still grant execution rights. In this case, we skip the test.
if [ -x .todo.actions.d/foo ]; then
SKIP_TESTS="${SKIP_TESTS}${SKIP_TESTS+ }t8010.4"
fi
test_todo_session 'nonexecutable action' <<EOF
>>> todo.sh listaddons
bar
ls
quux
EOF
test_done

View File

@@ -1,76 +0,0 @@
#!/bin/bash
test_description='custom actions help functionality
This test checks listing the usage help of a custom action.
'
. ./actions-test-lib.sh
. ./test-lib.sh
test_todo_session 'custom action help with no custom action directory' <<'EOF'
>>> todo.sh help foo
TODO: No action "foo" exists.
=== 1
EOF
make_action "foo"
make_action "bar"
make_action "ls"
make_action "quux"
test_todo_session 'custom action help' <<'EOF'
>>> todo.sh help foo
foo ITEM#[, ITEM#, ...] [TERM...]
This custom action does foo.
\
>>> todo.sh help bar
bar ITEM#[, ITEM#, ...] [TERM...]
This custom action does bar.
\
EOF
test_todo_session 'multiple custom actions help' <<'EOF'
>>> todo.sh help foo bar
foo ITEM#[, ITEM#, ...] [TERM...]
This custom action does foo.
\
bar ITEM#[, ITEM#, ...] [TERM...]
This custom action does bar.
\
EOF
test_todo_session 'nonexisting action help' <<'EOF'
>>> todo.sh help doesnotexist
TODO: No action "doesnotexist" exists.
=== 1
>>> todo.sh help foo doesnotexist bar
foo ITEM#[, ITEM#, ...] [TERM...]
This custom action does foo.
\
TODO: No action "doesnotexist" exists.
=== 1
EOF
test_todo_session 'mixed built-in and custom actions help' <<'EOF'
>>> todo.sh help foo shorthelp bar
foo ITEM#[, ITEM#, ...] [TERM...]
This custom action does foo.
\
shorthelp
List the one-line usage of all built-in and add-on actions.
\
bar ITEM#[, ITEM#, ...] [TERM...]
This custom action does bar.
\
EOF
test_todo_session 'custom override of built-in action help' <<'EOF'
>>> todo.sh help ls
ls ITEM#[, ITEM#, ...] [TERM...]
This custom action does ls.
\
EOF
test_done

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
test_description='basic tests imported from previous framework
'
@@ -85,7 +85,6 @@ TODO: $HOME/todo.txt archived.
TODO: 5 of 5 tasks shown
>>> todo.sh report
TODO: $HOME/todo.txt archived.
2009-02-13T04:40:00 5 1
TODO: Report file updated.

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
#
# Copyright (c) 2005 Junio C Hamano
#
@@ -180,7 +180,7 @@ test_failure_ () {
test_failure=$(($test_failure + 1))
say_color error "FAIL $test_count: $1"
shift
echo "$@"
echo "$@" | sed -e 's/^/ /'
test "$immediate" = "" || { trap - EXIT; exit 1; }
}
@@ -199,9 +199,8 @@ test_debug () {
}
test_run_ () {
eval > output 2>&1 "$1"
eval >&3 2>&4 "$1"
eval_ret="$?"
cat >&3 output
return 0
}
@@ -261,43 +260,6 @@ test_expect_success () {
echo >&3 ""
}
test_expect_output () {
test "$#" = 2 ||
error "bug in the test script: not 2 parameters to test-expect-output"
test_expect_code_and_output 0 "$@"
}
test_expect_code_and_output () {
test "$#" = 3 ||
error "bug in the test script: not 3 parameters to test-expect-code-and-output"
if ! test_skip "$@"
then
if [ "$1" = 0 ]; then
say >&3 "expecting success and output: $3"
else
say >&3 "expecting exit code $1 and output: $3"
fi
test_run_ "$3"
if [ "$?" = 0 -a "$eval_ret" = "$1" ]
then
cmp_output=$(test_cmp expect output)
if [ "$?" = 0 ]
then
test_ok_ "$2"
else
test_failure_ "$2" "$3" "
$cmp_output"
fi
else
cmp_output=$(test_cmp expect output)
test_failure_ "$2" "$3" "
expected exit code $1, actual ${eval_ret}${cmp_output:+
}${cmp_output}"
fi
fi
echo >&3 ""
}
test_expect_code () {
test "$#" = 3 ||
error "bug in the test script: not 3 parameters to test-expect-code"
@@ -309,8 +271,7 @@ test_expect_code () {
then
test_ok_ "$2"
else
test_failure_ "$2" "$3" "
expected exit code $1, actual ${eval_ret}"
test_failure_ "$@"
fi
fi
echo >&3 ""
@@ -552,16 +513,14 @@ test_tick () {
}
# Generate and run a series of tests based on a transcript.
# Usage: test_todo_session "description" <<'EOF'
# Usage: test_todo_session "description" <<EOF
# >>> command
# output1
# output2
#
# >>> command
# === exit status
# output3 with empty line (must be escaped here)
# \
# output5
# output3
# output4
# EOF
test_todo_session () {
test "$#" = 1 ||
@@ -570,7 +529,7 @@ test_todo_session () {
cmd=""
status=0
> expect
while IFS= read -r line
while read -r line
do
case $line in
">>> "*)
@@ -583,9 +542,9 @@ test_todo_session () {
"")
if [ ! -z "$cmd" ]; then
if [ $status = 0 ]; then
test_expect_output "$1 $subnum" "$cmd"
test_expect_success "$1 $subnum" "$cmd > output && test_cmp expect output"
else
test_expect_code_and_output "$status" "$1 $subnum" "$cmd"
test_expect_success "$1 $subnum" "$cmd > output ; test \$? = $status && test_cmp expect output"
fi
subnum=$(($subnum + 1))
@@ -594,9 +553,6 @@ test_todo_session () {
> expect
fi
;;
\\)
echo "" >> expect
;;
*)
echo "$line" >> expect
;;
@@ -604,9 +560,9 @@ test_todo_session () {
done
if [ ! -z "$cmd" ]; then
if [ $status = 0 ]; then
test_expect_output "$1 $subnum" "$cmd"
test_expect_success "$1 $subnum" "$cmd > output && test_cmp expect output"
else
test_expect_code_and_output "$status" "$1 $subnum" "$cmd"
test_expect_success "$1 $subnum" "$cmd > output ; test \$? = $status && test_cmp expect output"
fi
fi
}
@@ -623,66 +579,6 @@ EOF
exit 0
}
test_todo_custom_completion () {
test "$#" = 4 ||
error "bug in the test script: not 4 parameters to test_todo_custom_completion"
completeFunc=$1
shift
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=' ' eval "set -- $expected"
EXPECT=("$@")
source "$TEST_DIRECTORY/../todo_completion"
$completeFunc
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_todo_completion () {
test "$#" = 3 ||
error "bug in the test script: not 3 parameters to test_todo_completion"
test_todo_custom_completion _todo "$@"
}
test_init_todo "$test"
# Use -P to resolve symlinks in our working directory so that the pwd
# in subprocesses equals our $PWD (for pathname comparisons).

View File

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

View File

@@ -2,12 +2,13 @@
# Your todo.txt directory
#export TODO_DIR="/Users/gina/Documents/todo"
export TODO_DIR=$(dirname "$0")
export TODO_DIR=`dirname "$0"`
# Your todo/done/report.txt locations
export TODO_FILE="$TODO_DIR/todo.txt"
export DONE_FILE="$TODO_DIR/done.txt"
export REPORT_FILE="$TODO_DIR/report.txt"
export TMP_FILE="$TODO_DIR/todo.tmp"
# You can customize your actions directory location
#export TODO_ACTIONS_DIR="$HOME/.todo.actions.d"

338
todo.sh
View File

@@ -50,17 +50,15 @@ shorthelp()
append|app ITEM# "TEXT TO APPEND"
archive
command [ACTIONS]
deduplicate
del|rm ITEM# [TERM]
depri|dp ITEM#[, ITEM#, ITEM#, ...]
do ITEM#[, ITEM#, ITEM#, ...]
help [ACTION...]
help
list|ls [TERM...]
listall|lsa [TERM...]
listaddons
listcon|lsc [TERM...]
listcon|lsc
listfile|lf [SRC [TERM...]]
listpri|lsp [PRIORITIES] [TERM...]
listpri|lsp [PRIORITY] [TERM...]
listproj|lsprj [TERM...]
move|mv ITEM# DEST [SRC]
prepend|prep ITEM# "TEXT TO PREPEND"
@@ -69,8 +67,6 @@ shorthelp()
report
shorthelp
Actions can be added and overridden using scripts in the actions
directory.
EndHelp
# Only list the one-line usage from the add-on actions. This assumes that
@@ -91,10 +87,10 @@ help()
Options:
-@
Hide context names in list output. Use twice to show context
Hide context names in list output. Use twice to show context
names (default).
-+
Hide project names in list output. Use twice to show project
Hide project names in list output. Use twice to show project
names (default).
-c
Color mode
@@ -107,7 +103,7 @@ help()
-p
Plain mode turns off colors
-P
Hide priority labels in list output. Use twice to show
Hide priority labels in list output. Use twice to show
priority labels (default).
-a
Don't auto-archive tasks automatically on completion
@@ -137,7 +133,7 @@ help()
EndOptionsHelp
[ $TODOTXT_VERBOSE -gt 1 ] && cat <<-'EndVerboseHelp'
[ $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
@@ -150,16 +146,9 @@ help()
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
TODOTXT_SOURCEVAR=\$DONE_FILE use another source for listcon, listproj
EndVerboseHelp
actionsHelp
addonHelp
}
actionsHelp()
{
cat <<-EndActionsHelp
Built-in Actions:
add "THING I NEED TO DO +project @context"
@@ -173,6 +162,7 @@ actionsHelp()
Adds FIRST THING I NEED TO DO to your todo.txt on its own line and
Adds SECOND THING I NEED TO DO to you todo.txt on its own line.
Project and context notation optional.
Quotes optional.
addto DEST "TEXT TO ADD"
Adds a line of text to any file located in the todo.txt directory.
@@ -190,9 +180,6 @@ actionsHelp()
Runs the remaining arguments using only todo.sh builtins.
Will not call any .todo.actions.d scripts.
deduplicate
Removes duplicate lines from todo.txt.
del ITEM# [TERM]
rm ITEM# [TERM]
Deletes the task on line ITEM# in todo.txt.
@@ -206,58 +193,41 @@ actionsHelp()
do ITEM#[, ITEM#, ITEM#, ...]
Marks task(s) on line ITEM# as done in todo.txt.
help [ACTION...]
Display help about usage, options, built-in and add-on actions,
or just the usage help for the passed ACTION(s).
help
Display this help message.
list [TERM...]
ls [TERM...]
Displays all tasks that contain TERM(s) sorted by priority with line
numbers. Each task must match all TERM(s) (logical AND); to display
tasks that contain any TERM (logical OR), use
"TERM1\|TERM2\|..." (with quotes), or TERM1\\\|TERM2 (unquoted).
Hides all tasks that contain TERM(s) preceded by a
minus sign (i.e. -TERM). If no TERM specified, lists entire todo.txt.
numbers. If no TERM specified, lists entire todo.txt.
listall [TERM...]
lsa [TERM...]
Displays all the lines in todo.txt AND done.txt that contain TERM(s)
sorted by priority with line numbers. Hides all tasks that
contain TERM(s) preceded by a minus sign (i.e. -TERM). If no
TERM specified, lists entire todo.txt AND done.txt
concatenated and sorted.
sorted by priority with line numbers. If no TERM specified, lists
entire todo.txt AND done.txt concatenated and sorted.
listaddons
Lists all added and overridden actions in the actions directory.
listcon [TERM...]
lsc [TERM...]
listcon
lsc
Lists all the task contexts that start with the @ sign in todo.txt.
If TERM specified, considers only tasks that contain TERM(s).
listfile [SRC [TERM...]]
lf [SRC [TERM...]]
Displays all the lines in SRC file located in the todo.txt directory,
sorted by priority with line numbers. If TERM specified, lists
all lines that contain TERM(s) in SRC file. Hides all tasks that
contain TERM(s) preceded by a minus sign (i.e. -TERM).
all lines that contain TERM in SRC file.
Without any arguments, the names of all text files in the todo.txt
directory are listed.
listpri [PRIORITIES] [TERM...]
lsp [PRIORITIES] [TERM...]
Displays all tasks prioritized PRIORITIES.
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).
Hides all tasks that contain TERM(s) preceded by a minus sign
(i.e. -TERM).
listproj [TERM...]
lsprj [TERM...]
Lists all the projects (terms that start with a + sign) in
todo.txt.
If TERM specified, considers only tasks that contain TERM(s).
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
Lists all the projects that start with the + sign in todo.txt.
move ITEM# DEST [SRC]
mv ITEM# DEST [SRC]
@@ -275,7 +245,7 @@ actionsHelp()
p ITEM# PRIORITY
Adds PRIORITY to task on line ITEM#. If the task is already
prioritized, replaces current priority with new PRIORITY.
PRIORITY must be a letter between A and Z.
PRIORITY must be an uppercase letter between A and Z.
replace ITEM# "UPDATED TODO"
Replaces task on line ITEM# with UPDATED TODO.
@@ -286,7 +256,11 @@ actionsHelp()
shorthelp
List the one-line usage of all built-in and add-on actions.
EndActionsHelp
addonHelp
exit 1
}
addonHelp()
@@ -308,31 +282,18 @@ addonHelp()
fi
}
actionUsage()
{
for actionName
do
action="${TODO_ACTIONS_DIR}/${actionName}"
if [ -f "$action" -a -x "$action" ]; then
"$action" usage
else
builtinActionUsage=$(actionsHelp | sed -n -e "/^ ${actionName//\//\\/} /,/^\$/p" -e "/^ ${actionName//\//\\/}$/,/^\$/p")
if [ "$builtinActionUsage" ]; then
echo "$builtinActionUsage"
echo
else
die "TODO: No action \"${actionName}\" exists."
fi
fi
done
}
die()
{
echo "$*"
exit 1
}
cleanup()
{
[ -f "$TMP_FILE" ] && rm "$TMP_FILE"
return 0
}
cleaninput()
{
# Parameters: When $1 = "for sed", performs additional escaping for use
@@ -392,6 +353,20 @@ getNewtodo()
[ -z "$newtodo" ] && die "$(getPrefix "$2"): No updated task $item."
}
archive()
{
#defragment blank lines
sed -i.bak -e '/./!d' "$TODO_FILE"
[ $TODOTXT_VERBOSE -gt 0 ] && grep "^x " "$TODO_FILE"
grep "^x " "$TODO_FILE" >> "$DONE_FILE"
sed -i.bak '/^x /d' "$TODO_FILE"
cp "$TODO_FILE" "$TMP_FILE"
sed -n 'G; s/\n/&&/; /^\([ ~-]*\n\).*\n\1/d; s/\n//; h; P' "$TMP_FILE" > "$TODO_FILE"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
echo "TODO: $TODO_FILE archived."
fi
}
replaceOrPrepend()
{
action=$1; shift
@@ -414,22 +389,21 @@ replaceOrPrepend()
else
input=$*
fi
cleaninput "for sed"
# Retrieve existing priority and prepended date
local -r priAndDateExpr='^\((.) \)\{0,1\}\([0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\} \)\{0,1\}'
priority=$(sed -e "$item!d" -e "${item}s/${priAndDateExpr}.*/\\1/" "$TODO_FILE")
prepdate=$(sed -e "$item!d" -e "${item}s/${priAndDateExpr}.*/\\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/${priAndDateExpr}.*/\\1\\2/")" ]; then
# If the replaced text starts with a [priority +] date, it will replace
# the existing date, too.
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
# date, too.
prepdate=
fi
# Temporarily remove any existing priority and prepended date, perform the
# change (replace/prepend) and re-insert the existing priority and prepended
# date again.
cleaninput "for sed"
sed -i.bak -e "$item s/^${priority}${prepdate}//" -e "$item s|^.*|${priority}${prepdate}${input}${backref}|" "$TODO_FILE"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
getNewtodo "$item"
@@ -696,6 +670,7 @@ ACTION=${1:-$TODOTXT_DEFAULT_ACTION}
[ -d "$TODO_DIR" ] || die "Fatal Error: $TODO_DIR is not a directory"
( 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 "$DONE_FILE" ] || cp /dev/null "$DONE_FILE"
[ -f "$REPORT_FILE" ] || cp /dev/null "$REPORT_FILE"
@@ -785,32 +760,13 @@ _list() {
## Get our search arguments, if any
shift ## was file name, new $1 is first search term
_format "$src" '' "$@"
## Build the filter.
filter_command=$(filtercommand "${pre_filter_command:-}" "${post_filter_command:-}" "$@")
if [ $TODOTXT_VERBOSE -gt 0 ]; then
echo "--"
echo "$(getPrefix "$src"): ${NUMTASKS:-0} of ${TOTALTASKS:-0} tasks shown"
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
## Figure out how much padding we need to use
## We need one level of padding for each power of 10 $LINES uses
LINES=$( sed -n '$ =' "$src" )
PADDING=${#LINES}
## Number the file, then run the filter command,
## then sort and mangle output some more
@@ -818,21 +774,10 @@ _format()
TODOTXT_FINAL_FILTER="cat"
fi
items=$(
if [ "$FILE" ]; then
sed = "$FILE"
else
sed =
fi \
| sed -e '''
N
s/^/ /
s/ *\([ 0-9]\{'"$PADDING"',\}\)\n/\1 /
/^[ 0-9]\{1,\} *$/d
'''
sed = "$src" \
| sed "N; s/^/ /; s/ *\(.\{$PADDING,\}\)\n/\1 /" \
| grep -v "^[ 0-9]\+ *$"
)
## Build and apply the filter.
filter_command=$(filtercommand "${pre_filter_command:-}" "${post_filter_command:-}" "$@")
if [ "${filter_command}" ]; then
filtered_items=$(echo -n "$items" | eval "${filter_command}")
else
@@ -857,7 +802,7 @@ _format()
{
if (match($0, /^[0-9]+ x /)) {
print highlight("COLOR_DONE") $0 highlight("DEFAULT")
} else if (match($0, /^[0-9]+ \([A-Z]\) /)) {
} else if (match($0, /^[0-9]+ \([A-Z]\)[[:space:]]/)) {
clr = highlight("PRI_" substr($0, RSTART + RLENGTH - 3, 1))
print \
(clr ? clr : highlight("PRI_X")) \
@@ -867,9 +812,8 @@ _format()
}
''' \
| sed '''
s/'"${HIDE_PROJECTS_SUBSTITUTION:-^}"'//g
s/'"${HIDE_CONTEXTS_SUBSTITUTION:-^}"'//g
s/'"${HIDE_CUSTOM_SUBSTITUTION:-^}"'//g
s/'${HIDE_PROJECTS_SUBSTITUTION:-^}'//g
s/'${HIDE_CONTEXTS_SUBSTITUTION:-^}'//g
''' \
| eval ${TODOTXT_FINAL_FILTER} \
)
@@ -878,23 +822,16 @@ _format()
if [ $TODOTXT_VERBOSE -gt 0 ]; then
NUMTASKS=$( echo -n "$filtered_items" | sed -n '$ =' )
TOTALTASKS=$( echo -n "$items" | sed -n '$ =' )
echo "--"
echo "$(getPrefix "$FILE"): ${NUMTASKS:-0} of ${TOTALTASKS:-0} tasks shown"
fi
if [ $TODOTXT_VERBOSE -gt 1 ]; then
echo "TODO DEBUG: Filter Command was: ${filter_command:-cat}"
fi
}
listWordsWithSigil()
{
sigil=$1
shift
FILE=$TODO_FILE
[ "$TODOTXT_SOURCEVAR" ] && eval "FILE=$TODOTXT_SOURCEVAR"
eval "$(filtercommand 'cat "${FILE[@]}"' '' "$@")" | grep -o "[^ ]*${sigil}[^ ]\\+" | grep "^$sigil" | sort -u
}
export -f cleaninput getPrefix getTodo getNewtodo shellquote filtercommand _list listWordsWithSigil getPadding _format die
export -f cleaninput getPrefix getTodo getNewtodo shellquote filtercommand _list die
# == HANDLE ACTION ==
action=$( printf "%s\n" "$ACTION" | tr 'A-Z' 'a-z' )
@@ -912,7 +849,9 @@ then
elif [ -d "$TODO_ACTIONS_DIR" -a -x "$TODO_ACTIONS_DIR/$action" ]
then
"$TODO_ACTIONS_DIR/$action" "$@"
exit $?
status=$?
cleanup
exit $status
fi
## Only run if $action isn't found in .todo.actions.d
@@ -994,15 +933,7 @@ case $action in
;;
"archive" )
# defragment blank lines
sed -i.bak -e '/./!d' "$TODO_FILE"
[ $TODOTXT_VERBOSE -gt 0 ] && grep "^x " "$TODO_FILE"
grep "^x " "$TODO_FILE" >> "$DONE_FILE"
sed -i.bak '/^x /d' "$TODO_FILE"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
echo "TODO: $TODO_FILE archived."
fi
;;
archive;;
"del" | "rm" )
# replace deleted line with a blank line when TODOTXT_PRESERVE_LINE_NUMBERS is 1
@@ -1060,7 +991,7 @@ case $action in
# Split multiple depri's, if comma separated change to whitespace separated
# Loop the 'depri' function for each item
for item in ${*//,/ }; do
for item in $(echo $* | tr ',' ' '); do
getTodo "$item"
if [[ "$todo" = \(?\)\ * ]]; then
@@ -1084,7 +1015,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 ${*//,/ }; do
for item in $(echo $* | tr ',' ' '); do
getTodo "$item"
# Check if this item has already been done
@@ -1104,26 +1035,18 @@ case $action in
done
if [ $TODOTXT_AUTO_ARCHIVE = 1 ]; then
# Recursively invoke the script to allow overriding of the archive
# action.
"$TODO_FULL_SH" archive
archive
fi
;;
"help" )
shift ## Was help; new $1 is first help topic / action name
if [ $# -gt 0 ]; then
# Don't use PAGER here; we don't expect much usage output from one / few actions.
actionUsage "$@"
else
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)
help | "${PAGER:-less}" && exit 0
fi
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)
help | "${PAGER:-less}" && exit 0
fi
help # just in case something failed above, we go ahead and just spew to STDOUT
fi
help # just in case something failed above, we go ahead and just spew to STDOUT
;;
"shorthelp" )
@@ -1144,21 +1067,8 @@ case $action in
"listall" | "lsa" )
shift ## Was lsa; new $1 is first search term
TOTAL=$( sed -n '$ =' "$TODO_FILE" )
PADDING=${#TOTAL}
post_filter_command="${post_filter_command:-}${post_filter_command:+ | }awk -v TOTAL=$TOTAL -v PADDING=$PADDING '{ \$1 = sprintf(\"%\" PADDING \"d\", (\$1 > TOTAL ? 0 : \$1)); print }' "
cat "$TODO_FILE" "$DONE_FILE" | TODOTXT_VERBOSE=0 _format '' "$PADDING" "$@"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
TDONE=$( sed -n '$ =' "$DONE_FILE" )
TASKNUM=$(TODOTXT_PLAIN=1 TODOTXT_VERBOSE=0 _format "$TODO_FILE" 1 "$@" | sed -n '$ =')
DONENUM=$(TODOTXT_PLAIN=1 TODOTXT_VERBOSE=0 _format "$DONE_FILE" 1 "$@" | sed -n '$ =')
echo "--"
echo "$(getPrefix "$TODO_FILE"): ${TASKNUM:-0} of ${TOTAL:-0} tasks shown"
echo "$(getPrefix "$DONE_FILE"): ${DONENUM:-0} of ${TDONE:-0} tasks shown"
echo "total $((TASKNUM + DONENUM)) of $((TOTAL + TDONE)) tasks shown"
fi
cat "$TODO_FILE" "$DONE_FILE" > "$TMP_FILE"
_list "$TMP_FILE" "$@"
;;
"listfile" | "lf" )
@@ -1175,20 +1085,19 @@ case $action in
;;
"listcon" | "lsc" )
shift
listWordsWithSigil '@' "$@"
grep -o '[^ ]*@[^ ]\+' "$TODO_FILE" | grep '^@' | sort -u
;;
"listproj" | "lsprj" )
shift
listWordsWithSigil '+' "$@"
eval "$(filtercommand 'cat "$TODO_FILE"' '' "$@")" | grep -o '[^ ]*+[^ ]\+' | grep '^+' | sort -u
;;
"listpri" | "lsp" )
shift ## was "listpri", new $1 is priority to list or first TERM
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="${post_filter_command:-}${post_filter_command:+ | }grep '^ *[0-9]\+ ([${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" "$@"
;;
@@ -1278,10 +1187,9 @@ note: PRIORITY must be anywhere from A to Z."
;;
"report" )
# archive first
# Recursively invoke the script to allow overriding of the archive
# action.
"$TODO_FULL_SH" archive
#archive first
sed '/^x /!d' "$TODO_FILE" >> "$DONE_FILE"
sed -i.bak '/^x /d' "$TODO_FILE"
TOTAL=$( sed -n '$ =' "$TODO_FILE" )
TDONE=$( sed -n '$ =' "$DONE_FILE" )
@@ -1299,62 +1207,8 @@ note: PRIORITY must be anywhere from A to Z."
fi
;;
"deduplicate" )
if [ $TODOTXT_PRESERVE_LINE_NUMBERS = 0 ]; then
deduplicateSedCommand='d'
else
deduplicateSedCommand='s/^.*//; p'
fi
# To determine the difference when deduplicated lines are preserved, only
# non-empty lines must be counted.
originalTaskNum=$( sed -e '/./!d' "$TODO_FILE" | sed -n '$ =' )
# Look for duplicate lines and discard the second occurrence.
# We start with an empty hold space on the first line. For each line:
# G - appends newline + hold space to the pattern space
# s/\n/&&/; - double up the first new line so we catch adjacent dups
# /^\([^\n]*\n\).*\n\1/b dedup
# If the first line of the hold space shows up again later as an
# entire line, it's a duplicate. Jump to the "dedup" label, where
# either of the following is executed, depending on whether empty
# lines should be preserved:
# d - Delete the current pattern space, quit this line and
# move on to the next, or:
# s/^.*//; p - Clear the task text, print this line and move on to
# the next.
# s/\n//; - else (no duplicate), drop the doubled newline
# h; - replace the hold space with the expanded pattern space
# P; - print up to the first newline (that is, the input line)
# b - end processing of the current line
sed -i.bak -n \
-e 'G; s/\n/&&/; /^\([^\n]*\n\).*\n\1/b dedup' \
-e 's/\n//; h; P; b' \
-e ':dedup' \
-e "$deduplicateSedCommand" \
"$TODO_FILE"
newTaskNum=$( sed -e '/./!d' "$TODO_FILE" | sed -n '$ =' )
deduplicateNum=$(( originalTaskNum - newTaskNum ))
if [ $deduplicateNum -eq 0 ]; then
echo "TODO: No duplicate tasks found"
else
echo "TODO: $deduplicateNum duplicate task(s) removed"
fi
;;
"listaddons" )
if [ -d "$TODO_ACTIONS_DIR" ]; then
cd "$TODO_ACTIONS_DIR" || exit $?
for action in *
do
if [ -f "$action" -a -x "$action" ]; then
echo "$action"
fi
done
fi
;;
* )
usage;;
esac
cleanup

View File

@@ -11,65 +11,47 @@ _todo()
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 listaddons listall lsa listcon \
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"
local -r MOVE_COMMAND_PATTERN='^(move|mv)$'
local _todo_sh=${_todo_sh:-todo.sh}
# 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="$COMMANDS $(eval TODOTXT_VERBOSE=0 $_todo_sh command listaddons) $OPTS"
completions="$allCommands $OPTS"
elif [[ $COMP_CWORD -gt 2 && ( \
"${COMP_WORDS[COMP_CWORD-2]}" =~ $MOVE_COMMAND_PATTERN || \
"${COMP_WORDS[COMP_CWORD-3]}" =~ $MOVE_COMMAND_PATTERN ) ]]; then
"${COMP_WORDS[COMP_CWORD-2]}" =~ ^(move|mv)$ || \
"${COMP_WORDS[COMP_CWORD-3]}" =~ ^(move|mv)$ ) ]]; then
# "move ITEM# DEST [SRC]" has file arguments on positions 2 and 3.
completions=$(eval TODOTXT_VERBOSE=0 $_todo_sh command listfile)
completions=$(TODOTXT_VERBOSE=0 todo.sh command listfile)
else
case "$prev" in
command)
completions=$COMMANDS;;
help)
completions="$COMMANDS $(eval TODOTXT_VERBOSE=0 $_todo_sh command listaddons)";;
addto|listfile|lf)
completions=$(eval TODOTXT_VERBOSE=0 $_todo_sh command listfile);;
-*) completions="$COMMANDS $(eval TODOTXT_VERBOSE=0 $_todo_sh command listaddons) $OPTS";;
completions=$(TODOTXT_VERBOSE=0 todo.sh command listfile);;
-*) completions="$allCommands $OPTS";;
*) case "$cur" in
+*) completions=$(eval TODOTXT_VERBOSE=0 $_todo_sh command listproj)
COMPREPLY=( $( compgen -W "$completions" -- $cur ))
[ ${#COMPREPLY[@]} -gt 0 ] && return 0
# Fall back to projects extracted from done tasks.
completions=$(eval 'TODOTXT_VERBOSE=0 TODOTXT_SOURCEVAR=\$DONE_FILE' $_todo_sh command listproj)
;;
@*) completions=$(eval 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=$(eval 'TODOTXT_VERBOSE=0 TODOTXT_SOURCEVAR=\$DONE_FILE' $_todo_sh command listcon)
;;
+*) 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 instead.
# Remove the timestamp prepended by the -t option,
# and the done date (for done tasks); there's no
# todo.txt option for that yet.
# But keep priority and "x"; they're short and may
# provide useful context.
# Remove any trailing whitespace; the Bash
# completion inserts a trailing space itself.
# Finally, limit the output to a single line just as
# a safety check of the ls action output.
local todo=$( \
eval TODOTXT_VERBOSE=0 $_todo_sh '-@ -+ -p -x command ls "^ *${cur} "' | \
sed -e 's/^ *[0-9]\{1,\} //' -e 's/^\((.) \)\{0,1\}[0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\} /\1/' \
-e 's/^\([xX] \)\([0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\} \)\{1,2\}/\1/' \
-e 's/[[:space:]]*$//' \
-e '1q' \
)
# 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.
[ "$todo" ] && COMPREPLY[0]="$cur # $todo"
[ "$item" ] && COMPREPLY[0]="$cur # $item"
return 0
else
return 0
@@ -84,30 +66,6 @@ _todo()
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
# It is recommended to put this line next to your alias definition in your
# ~/.bashrc (or wherever else you're defining your alias). If you simply
# uncomment it here, you will need to redo this on every todo.txt update!
# If you have renamed the todo.sh executable, or if it is not accessible through
# PATH, you need to add and use a wrapper completion function, like this:
#_todoElsewhere()
#{
# local _todo_sh='/path/to/todo2.sh'
# _todo "$@"
#}
#complete -F _todoElsewhere /path/to/todo2.sh
# If you use aliases to use different configuration(s), you need to add and use
# a wrapper completion function for each configuration if you want to complete
# fron the actual configured task locations:
#alias todo2='todo.sh -d "$HOME/todo2.cfg"'
#_todo2()
#{
# local _todo_sh='todo.sh -d "$HOME/todo2.cfg"'
# _todo "$@"
#}
#complete -F _todo2 todo2