From 2f6d9ae329141466da39f258460816db8c2e4086 Mon Sep 17 00:00:00 2001 From: Ingo Karkat Date: Mon, 5 Jul 2010 09:38:10 +0200 Subject: [PATCH 1/3] Factored out 'prepend' and 'replace' actions. They contained much duplication, which has been consolidated into replaceOrPrepend(). --- todo.sh | 134 +++++++++++++++++++++++--------------------------------- 1 file changed, 56 insertions(+), 78 deletions(-) diff --git a/todo.sh b/todo.sh index d2fc5de..df30a51 100755 --- a/todo.sh +++ b/todo.sh @@ -1,5 +1,8 @@ #! /bin/bash +# === HEAVY LIFTING === +shopt -s extglob + # NOTE: Todo.sh requires the .todo/config configuration file to run. # Place the .todo/config file in your home directory or use the -d option for a custom location. @@ -281,6 +284,57 @@ archive() [ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: $TODO_FILE archived." } +replaceOrPrepend() +{ + action=$1; shift + case "$action" in + replace) backref=;; + prepend) backref=' &';; + esac + shift; item=$1; shift + + [ -z "$item" ] && die "$errmsg" + [[ "$item" = +([0-9]) ]] || die "$errmsg" + + todo=$(sed "$item!d" "$TODO_FILE") + [ -z "$todo" ] && die "$item: No such task." + + if [[ -z "$1" && $TODOTXT_FORCE = 0 ]]; then + case "$action" in + replace) echo -n "Replacement: ";; + prepend) echo -n "Prepend: ";; + esac + read input + else + input=$* + fi + cleaninput $input + + # Test for then set priority + if [ `sed "$item!d" "$TODO_FILE"|grep -c "^(\\w)"` -eq 1 ]; then + priority=$(sed "$item!d" "$TODO_FILE" | awk -F '\\(|\\)' '{print $2}') + fi + + # If priority isn't set change task, if it is remove priority, change then add priority again + if [ -z $priority ]; then + sed -i.bak $item" s|^.*|${input}${backref}|" "$TODO_FILE" + else + sed -i.bak -e "$item s/^(.) //" -e "$item s|^.*|\($priority\) ${input}${backref}|" "$TODO_FILE" + fi + if [ $TODOTXT_VERBOSE -gt 0 ]; then + newtodo=$(sed "$item!d" "$TODO_FILE") + case "$action" in + replace) + echo "$item: $todo" + echo "replaced with" + echo "$item: $newtodo" + ;; + prepend) + echo "$item: $newtodo" + ;; + esac + fi +} # == PROCESS OPTIONS == while getopts ":fhpnatvVx+@Pd:" Option @@ -466,9 +520,6 @@ if [ $TODOTXT_PLAIN = 1 ]; then DEFAULT=$NONE fi -# === HEAVY LIFTING === -shopt -s extglob - _addto() { file="$1" input="$2" @@ -914,48 +965,7 @@ case $action in "prepend" | "prep" ) errmsg="usage: $TODO_SH prepend ITEM# \"TEXT TO PREPEND\"" - shift; item=$1; shift - - [ -z "$item" ] && die "$errmsg" - [[ "$item" = +([0-9]) ]] || die "$errmsg" - - todo=$(sed "$item!d" "$TODO_FILE") - [ -z "$todo" ] && die "$item: No such task." - - if [[ -z "$1" && $TODOTXT_FORCE = 0 ]]; then - echo -n "Prepend: " - read input - else - input=$* - fi - cleaninput $input - - # Test for then set priority - if [ `sed "$item!d" "$TODO_FILE"|grep -c "^(\\w)"` -eq 1 ]; then - priority=$(sed "$item!d" "$TODO_FILE" | awk -F '\\(|\\)' '{print $2}') - fi - - # If priority isn't set prepend - if [ -z $priority ]; then - if sed -i.bak $item" s|^.*|$input &|" "$TODO_FILE"; then - [ $TODOTXT_VERBOSE -gt 0 ] && { - newtodo=$(sed "$item!d" "$TODO_FILE") - echo "$item: $newtodo" - } - else - echo "TODO: Error prepending task $item." - fi - # If priority is set, remove priority, prepend and add back priority - else - if sed -i.bak -e "$item s/^(.) //" -e "$item s|^.*|\($priority\) $1 &|" "$TODO_FILE"; then - [ $TODOTXT_VERBOSE -gt 0 ] && { - newtodo=$(sed "$item!d" "$TODO_FILE") - echo "$item: $newtodo" - } - else - echo "TODO: Error prepending task $item." - fi - fi + replaceOrPrepend 'prepend' "$@" ;; "pri" | "p" ) @@ -986,39 +996,7 @@ note: PRIORITY must be anywhere from A to Z." "replace" ) errmsg="usage: $TODO_SH replace ITEM# \"UPDATED ITEM\"" - shift; item=$1; shift - - [ -z "$item" ] && die "$errmsg" - [[ "$item" = +([0-9]) ]] || die "$errmsg" - - todo=$(sed "$item!d" "$TODO_FILE") - [ -z "$todo" ] && die "$item: No such task." - - # Test for then set priority - if [ `sed "$item!d" "$TODO_FILE"|grep -c "^(\\w)"` -eq 1 ]; then - priority=$(sed "$item!d" "$TODO_FILE" | awk -F '\\(|\\)' '{print $2}') - fi - - if [[ -z "$1" && $TODOTXT_FORCE = 0 ]]; then - echo -n "Replacement: " - read input - else - input=$* - fi - cleaninput $input - - # If priority isn't set replace, if it is remove priority, replace then add priority again - if [ -z $priority ]; then - sed -i.bak $item" s|^.*|$input|" "$TODO_FILE" - else - sed -i.bak -e "$item s/^(.) //" -e "$item s|^.*|\($priority\) $input|" "$TODO_FILE" - fi - [ $TODOTXT_VERBOSE -gt 0 ] && { - NEWTODO=$(head -$item "$TODO_FILE" | tail -1) - echo "$item: $todo" - echo "replaced with" - echo "$item: $NEWTODO" - } + replaceOrPrepend 'replace' "$@" ;; "report" ) From 5e4486826155a45b31ddfd07436310fd534036fe Mon Sep 17 00:00:00 2001 From: Ingo Karkat Date: Mon, 5 Jul 2010 11:24:19 +0200 Subject: [PATCH 2/3] ENH: 'prepend' and 'replace' actions keep prepended date. Generalized and simplified the logic that already kept an existing priority to also keep a date added via todo.sh -t / TODOTXT_DATE_ON_ADD (unless the replaced text also starts with a date). --- tests/t1100-replace.sh | 41 +++++++++++++++++++++++++++++++++++++++++ tests/t1400-prepend.sh | 34 ++++++++++++++++++++++++++++++++++ todo.sh | 36 +++++++++++++++++++++--------------- 3 files changed, 96 insertions(+), 15 deletions(-) diff --git a/tests/t1100-replace.sh b/tests/t1100-replace.sh index e796052..a9f489f 100755 --- a/tests/t1100-replace.sh +++ b/tests/t1100-replace.sh @@ -77,6 +77,7 @@ replaced with replaced with 4: (A) collect the eggs EOF + test_todo_session 'replace with &' << EOF >>> todo.sh replace 3 "thrash the hay & thresh the wheat" 3: jump on hay @@ -90,4 +91,44 @@ test_todo_session 'replace error' << EOF 10: No such task. EOF +cat /dev/null > todo.txt +test_todo_session 'replace handling prepended date on add' <>> todo.sh -t add "new task" +1: 2009-02-13 new task +TODO: 1 added. + +>>> todo.sh replace 1 this is just a new one +1: 2009-02-13 new task +replaced with +1: 2009-02-13 this is just a new one + +>>> todo.sh replace 1 2010-07-04 this also has a new date +1: 2009-02-13 this is just a new one +replaced with +1: 2010-07-04 this also has a new date +EOF + +cat /dev/null > todo.txt +test_todo_session 'replace handling priority and prepended date on add' <>> todo.sh -t add "new task" +1: 2009-02-13 new task +TODO: 1 added. + +>>> todo.sh pri 1 A +1: (A) 2009-02-13 new task +TODO: 1 prioritized (A). + +>>> todo.sh replace 1 this is just a new one +1: (A) 2009-02-13 new task +replaced with +1: (A) 2009-02-13 this is just a new one +EOF + +test_todo_session 'replace with prepended date replaces existing date' <>> todo.sh replace 1 2010-07-04 this also has a new date +1: (A) 2009-02-13 this is just a new one +replaced with +1: (A) 2010-07-04 this also has a new date +EOF + test_done diff --git a/tests/t1400-prepend.sh b/tests/t1400-prepend.sh index 5a19c0b..4219b09 100755 --- a/tests/t1400-prepend.sh +++ b/tests/t1400-prepend.sh @@ -57,4 +57,38 @@ test_todo_session 'prepend with &' < todo.txt +test_todo_session 'prepend handling prepended date on add' <>> todo.sh -t add "new task" +1: 2009-02-13 new task +TODO: 1 added. + +>>> todo.sh prepend 1 "this is just a" +1: 2009-02-13 this is just a new task +EOF + +cat /dev/null > todo.txt +test_todo_session 'prepend handling priority and prepended date on add' <>> todo.sh -t add "new task" +1: 2009-02-13 new task +TODO: 1 added. + +>>> todo.sh pri 1 A +1: (A) 2009-02-13 new task +TODO: 1 prioritized (A). + +>>> todo.sh prepend 1 "this is just a" +1: (A) 2009-02-13 this is just a new task +EOF + +cat /dev/null > todo.txt +test_todo_session 'prepend with prepended date keeps both' <>> todo.sh -t add "new task" +1: 2009-02-13 new task +TODO: 1 added. + +>>> todo.sh prepend 1 "2010-07-04 this is just a" +1: 2009-02-13 2010-07-04 this is just a new task +EOF + test_done diff --git a/todo.sh b/todo.sh index df30a51..8b30d10 100755 --- a/todo.sh +++ b/todo.sh @@ -288,8 +288,14 @@ replaceOrPrepend() { action=$1; shift case "$action" in - replace) backref=;; - prepend) backref=' &';; + replace) + backref= + querytext="Replacement: " + ;; + prepend) + backref=' &' + querytext="Prepend: " + ;; esac shift; item=$1; shift @@ -300,27 +306,27 @@ replaceOrPrepend() [ -z "$todo" ] && die "$item: No such task." if [[ -z "$1" && $TODOTXT_FORCE = 0 ]]; then - case "$action" in - replace) echo -n "Replacement: ";; - prepend) echo -n "Prepend: ";; - esac + echo -n "$querytext" read input else input=$* fi cleaninput $input - # Test for then set priority - if [ `sed "$item!d" "$TODO_FILE"|grep -c "^(\\w)"` -eq 1 ]; then - priority=$(sed "$item!d" "$TODO_FILE" | awk -F '\\(|\\)' '{print $2}') + # Retrieve existing priority and prepended date + priority=$(sed -e "$item!d" -e $item's/^\(([A-Z]) \)\{0,1\}\([0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\} \)\{0,1\}.*/\1/' "$TODO_FILE") + prepdate=$(sed -e "$item!d" -e $item's/^\(([A-Z]) \)\{0,1\}\([0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\} \)\{0,1\}.*/\2/' "$TODO_FILE") + + 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 - # If priority isn't set change task, if it is remove priority, change then add priority again - if [ -z $priority ]; then - sed -i.bak $item" s|^.*|${input}${backref}|" "$TODO_FILE" - else - sed -i.bak -e "$item s/^(.) //" -e "$item s|^.*|\($priority\) ${input}${backref}|" "$TODO_FILE" - fi + # Temporarily remove any existing priority and prepended date, perform the + # change (replace/prepend) and re-insert the existing priority and prepended + # date again. + sed -i.bak -e "$item s/^${priority}${prepdate}//" -e "$item s|^.*|${priority}${prepdate}${input}${backref}|" "$TODO_FILE" if [ $TODOTXT_VERBOSE -gt 0 ]; then newtodo=$(sed "$item!d" "$TODO_FILE") case "$action" in From 2f4ba269947ef983bb0e9e2d7c10c8b2a008ebda Mon Sep 17 00:00:00 2001 From: Ingo Karkat Date: Mon, 5 Jul 2010 13:49:58 +0200 Subject: [PATCH 3/3] ENH: Sentence delimiters for append action. This fixes a personal annoyance. If the text to be appended to the task begins with one of the delimiter characters, no whitespace is inserted in between. This makes appending to an enumeration (todo.sh add 42 ", foo") syntactically correct. The list of delimiters is configurable (for personal preferences / non-English languages) via SENTENCE_DELIMITERS in the config file. --- tests/t1600-append.sh | 29 +++++++++++++++++++++++++++++ todo.sh | 12 +++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/tests/t1600-append.sh b/tests/t1600-append.sh index 885074e..57ee99e 100755 --- a/tests/t1600-append.sh +++ b/tests/t1600-append.sh @@ -44,4 +44,33 @@ test_todo_session 'append error' << EOF 10: No such task. EOF +cat > todo.txt <>> todo.sh append 1 ", lilies and roses" +1: notice the daisies, lilies and roses + +>>> todo.sh append 1 "; see the wasps" +1: notice the daisies, lilies and roses; see the wasps + +>>> todo.sh append 1 "& bees" +1: notice the daisies, lilies and roses; see the wasps & bees +EOF + +cp todo.cfg special-delimiters.cfg +cat >> special-delimiters.cfg <>> todo.sh -d special-delimiters.cfg append 1 "&beans" +1: notice the daisies, lilies and roses; see the wasps & bees&beans + +>>> todo.sh -d special-delimiters.cfg append 1 "%foo" +1: notice the daisies, lilies and roses; see the wasps & bees&beans %foo + +>>> todo.sh -d special-delimiters.cfg append 1 "*2" +1: notice the daisies, lilies and roses; see the wasps & bees&beans %foo*2 +EOF + test_done diff --git a/todo.sh b/todo.sh index 8b30d10..20dc20e 100755 --- a/todo.sh +++ b/todo.sh @@ -469,6 +469,12 @@ export PRI_B=$GREEN # color for B priority export PRI_C=$LIGHT_BLUE # color for C priority export PRI_X=$WHITE # color for rest of them +# Default sentence delimiters for todo.sh append. +# If the text to be appended to the task begins with one of these characters, no +# whitespace is inserted in between. This makes appending to an enumeration +# (todo.sh add 42 ", foo") syntactically correct. +export SENTENCE_DELIMITERS=',.:;' + [ -e "$TODOTXT_CFG_FILE" ] || { CFG_FILE_ALT="$HOME/todo.cfg" @@ -746,9 +752,13 @@ case $action in else input=$* fi + case "$input" in + [$SENTENCE_DELIMITERS]*) appendspace=;; + *) appendspace=" ";; + esac cleaninput $input - if sed -i.bak $item" s|^.*|& $input|" "$TODO_FILE"; then + if sed -i.bak $item" s|^.*|&${appendspace}${input}|" "$TODO_FILE"; then [ $TODOTXT_VERBOSE -gt 0 ] && { newtodo=$(sed "$item!d" "$TODO_FILE") echo "$item: $newtodo"