diff --git a/tests/t1900-archive.sh b/tests/t1900-archive.sh new file mode 100755 index 0000000..9cc3ae6 --- /dev/null +++ b/tests/t1900-archive.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +test_description='archive functionality + +Ensure we can archive items successfully. +' +. ./test-lib.sh + +cat > todo.txt <>> todo.sh archive +x done +TODO: $HOME/todo.txt archived. +EOF + +test_todo_session 'list after archive' <>> todo.sh ls +5 four +1 one +4 one +3 three +2 two +-- +TODO: 5 of 5 tasks shown +EOF + +test_done diff --git a/tests/t1910-deduplicate.sh b/tests/t1910-deduplicate.sh new file mode 100755 index 0000000..be225e8 --- /dev/null +++ b/tests/t1910-deduplicate.sh @@ -0,0 +1,103 @@ +#!/bin/sh + +test_description='deduplicate functionality + +Ensure we can deduplicate items successfully. +' +. ./test-lib.sh + +cat > todo.txt <>> 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' <>> todo.sh deduplicate +TODO: No duplicate tasks found +EOF + +cat > todo.txt <>> 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 <>> 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 <>> 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 diff --git a/tests/t1950-report.sh b/tests/t1950-report.sh new file mode 100755 index 0000000..46bbf97 --- /dev/null +++ b/tests/t1950-report.sh @@ -0,0 +1,96 @@ +#!/bin/sh + +test_description='report functionality + +This test checks the reporting and the format of the report file. +' +. ./test-lib.sh + +cat > todo.txt <>> todo.sh report +TODO: $HOME/todo.txt archived. +2009-02-13T04:40:00 5 0 +TODO: Report file updated. + +>>> todo.sh -p list +1 (B) smell the uppercase Roses +flowers @outside +4 make the coffee +wakeup +3 smell the coffee +wakeup +2 stop and think +5 visit http://example.com +-- +TODO: 5 of 5 tasks shown +EOF + +test_todo_session 'report of done tasks' <>> todo.sh -A do 3 +3 x 2009-02-13 smell the coffee +wakeup +TODO: 3 marked as done. +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. + +>>> todo.sh -p list +1 (B) smell the uppercase Roses +flowers @outside +3 make the coffee +wakeup +2 stop and think +4 visit http://example.com +-- +TODO: 4 of 4 tasks shown +EOF + +test_todo_session 'report performs archiving' <>> todo.sh -a do 3 +3 x 2009-02-13 make the coffee +wakeup +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. + +>>> todo.sh -p list +1 (B) smell the uppercase Roses +flowers @outside +2 stop and think +3 visit http://example.com +-- +TODO: 3 of 3 tasks shown + +>>> todo.sh -p listfile done.txt +2 x 2009-02-13 make the coffee +wakeup +1 x 2009-02-13 smell the coffee +wakeup +-- +DONE: 2 of 2 tasks shown +EOF + +test_todo_session 'report is unchanged when no changes' <>> cat report.txt +2009-02-13T04:40:00 5 0 +2009-02-13T04:40:00 4 1 +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. + +>>> cat report.txt +2009-02-13T04:40:00 5 0 +2009-02-13T04:40:00 4 1 +2009-02-13T04:40:00 3 2 +EOF + +test_done diff --git a/tests/t9999-testsuite_example.sh b/tests/t9999-testsuite_example.sh index 24df132..0c7efbe 100755 --- a/tests/t9999-testsuite_example.sh +++ b/tests/t9999-testsuite_example.sh @@ -85,13 +85,9 @@ 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. -2009-02-13-04:40:00 5 1 - ->>> todo.sh report -TODO: Report file updated. -2009-02-13-04:40:00 5 1 -2009-02-13-04:40:00 5 1 >>> todo.sh append g a usage: todo.sh append ITEM# "TEXT TO APPEND" diff --git a/todo.sh b/todo.sh index 337bbea..2c03377 100755 --- a/todo.sh +++ b/todo.sh @@ -50,6 +50,7 @@ shorthelp() append|app ITEM# "TEXT TO APPEND" archive command [ACTIONS] + deduplicate del|rm ITEM# [TERM] depri|dp ITEM#[, ITEM#, ITEM#, ...] do ITEM#[, ITEM#, ITEM#, ...] @@ -181,6 +182,9 @@ help() 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. @@ -363,20 +367,6 @@ 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 @@ -948,7 +938,15 @@ case $action in ;; "archive" ) - 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 + ;; "del" | "rm" ) # replace deleted line with a blank line when TODOTXT_PRESERVE_LINE_NUMBERS is 1 @@ -1050,7 +1048,9 @@ case $action in done if [ $TODOTXT_AUTO_ARCHIVE = 1 ]; then - archive + # Recursively invoke the script to allow overriding of the archive + # action. + "$TODO_FULL_SH" archive fi ;; @@ -1215,22 +1215,69 @@ note: PRIORITY must be anywhere from A to Z." ;; "report" ) - #archive first - sed '/^x /!d' "$TODO_FILE" >> "$DONE_FILE" - sed -i.bak '/^x /d' "$TODO_FILE" + # archive first + # Recursively invoke the script to allow overriding of the archive + # action. + "$TODO_FULL_SH" archive - NUMLINES=$( sed -n '$ =' "$TODO_FILE" ) - if [ ${NUMLINES:-0} = "0" ]; then - echo "datetime todos dones" >> "$REPORT_FILE" - fi - #now report TOTAL=$( sed -n '$ =' "$TODO_FILE" ) TDONE=$( sed -n '$ =' "$DONE_FILE" ) - TECHO=$(echo $(date +%Y-%m-%d-%T); echo ' '; echo ${TOTAL:-0}; echo ' '; - echo ${TDONE:-0}) - echo $TECHO >> "$REPORT_FILE" - [ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: Report file updated." - cat "$REPORT_FILE" + NEWDATA="${TOTAL:-0} ${TDONE:-0}" + LASTREPORT=$(sed -ne '$p' "$REPORT_FILE") + LASTDATA=${LASTREPORT#* } # Strip timestamp. + if [ "$LASTDATA" = "$NEWDATA" ]; then + echo "$LASTREPORT" + [ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: Report file is up-to-date." + else + NEWREPORT="$(date +%Y-%m-%dT%T) ${NEWDATA}" + echo "${NEWREPORT}" >> "$REPORT_FILE" + echo "${NEWREPORT}" + [ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: Report file updated." + 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 ;; * )