Commit Diff


commit - f4953d174779a298ffbc77ec7b9da04d3024f921
commit + c7704fb66b24220a3116d460ea9e97b6a5d95319
blob - /dev/null
blob + bfdec4fce808e6c34c559561adcee1867f3a63f5 (mode 755)
--- /dev/null
+++ t_done.sh
@@ -0,0 +1,233 @@
+#! /usr/bin/env bash
+
+usage() {
+    cat <<EOF
+usage:
+    t [-aD]
+    t [-aD] [-s REGEX_STRING] [-d [INTEGER|REGEX_STRING]]
+    t /REGEX_STRING
+    t [-T] [-t [+|-]VAL[ymwd]] STRING
+
+examples:
+    t                     print incomplete todos
+    t -a                  print all todos
+    t -D                  print all done todos
+    t -s call             print all todos matching "call"
+    t /call               same as above
+    t -s "call|email"     print all todos matching "call" or "email"
+    t -D -s read          print all done todos matching "read"
+    t -d 12               mark todo item 12 as done
+    t -s read -d 3        mark todo item 3 within todos matching "read" as done
+    t -d burn             mark all todos matching "burn" as done
+    t -s burn -d .        same as above
+    t -k 7                delete todo item 7
+    t -k bunnies          delete all todos matching "bunnies"
+    t -s bunnies -k .     same as above
+    t -e                  edit $TODO_FILE in $EDITOR
+    t -T sell horse       add todo "sell horse" due today
+    t -t 20d celebrate    add todo "celebrate" due on the 20th of this month
+    t -t +1w buy racecar  add todo "buy racecar" due a week from today
+                            (for date syntax, see date manual entry)
+    t -n                  print unnumbered output (suitable for redirection)
+EOF
+    exit 1
+}
+
+IFS=$'\n'
+red='\e[0;31m'
+clear='\e[0m'
+str_prefix='- [ ] '
+re_todofile='[Tt][Oo][Dd][Oo](\.[^.]+)?'
+re_todo='^- \[ ] '
+re_done='^- \[[xX]] '
+re_either='^- \[[ xX]] '
+re_date='[0-9]{4}-[0-9]{2}-[0-9]{2}'
+lines=$(tput lines)
+
+for file in *
+do
+    [[ $file =~ $re_todofile ]] && todofile="$file"
+done
+
+if [[ ! $todofile && -r $TODO_FILE ]]
+then todofile="$TODO_FILE"
+elif [[ ! $todofile ]]
+then printf 'No todo file found or environment variable TODO_FILE not set!\n'
+     exit 3
+fi
+
+t_read() {
+    if [[ $onlydone ]]
+    then
+        re_prefix=$re_done
+    elif [[ $showall ]]
+    then
+        re_prefix=$re_either
+    else
+        re_prefix=$re_todo
+    fi
+
+    local casematch
+    [[ ! $* =~ [A-Z] ]] && casematch='-i'
+    todo_list=($(grep -E $casematch "$re_prefix.*($*)" "$todofile"))
+    local due_list
+    local item
+    for i in "${!todo_list[@]}"
+    do
+        if [[ ${todo_list[i]} =~ $re_date ]]
+        then
+            item="${todo_list[i]}"
+            due_list+=("$item")
+            unset todo_list[i]
+        fi
+    done
+
+    due_list=($(printf "%s\n" "${due_list[@]}" | sed -E "s/.*($re_date).*/\1&/" | sort -g | sed -E "s/^$re_date//"))
+    todo_list=(${due_list[@]} ${todo_list[@]})
+}
+
+t_print() {
+    t_read "$query"
+
+    local n=1
+    local buffer=$(mktemp)
+    local n_total=${#todo_list[@]}
+    local n_width=${#n_total}
+
+    for todo in "${todo_list[@]}"
+    do
+        if [[ $todo =~ $re_todo && $todo =~ $re_date ]]
+        then
+            local date=${BASH_REMATCH//-}
+            local today=$(date +%Y%m%d)
+            (( date <= today )) && todo=$(sed -E "s/($re_prefix)(.*)/\1** \2 **/" <<< "$todo")
+        fi
+
+        if [[ $export ]]
+        then
+            printf "%s\n" "${todo}" >> "$buffer"
+        else
+            printf "%${n_width}s %s\n" "$n" "${todo#- }" >> "$buffer"
+        fi
+        (( n++ ))
+    done
+
+    if (( lines <= n_total ))
+    then ${PAGER:-less} -X < "$buffer"
+    else cat "$buffer"
+    fi
+
+    rm "$buffer"
+}
+
+t_select() {
+    if [[ $1 =~ ^[0-9]+$ ]]
+    then
+        selection=${todo_list[(( $1 - 1 ))]}
+    else
+        local casematch
+        [[ ! $@ =~ [A-Z] ]] && casematch='-i'
+        selection=($(printf "%s\n" "${todo_list[@]}" | grep $casematch "$@" ))
+    fi
+}
+
+t_done() {
+    t_read "$query"
+    t_select "$1"
+
+    for todo in "${selection[@]}"
+    do
+        todo=$(sed 's/[][\/$*.^|]/\\&/g' <<< "$todo")
+        sed -i'' "/$todo/s/^- \[ ]/- \[X]/" "$todofile"
+    done
+}
+
+t_kill() {
+    t_read "$query"
+    t_select "$1"
+
+    for todo in "${selection[@]}"
+    do
+        todo=$(sed 's/[][\/$*.^|]/\\&/g' <<< "$todo")
+        sed -i '' "/$todo/d" "$todofile"
+    done
+}
+
+t_toggle() {
+    t_read "$query"
+    t_select "$1"
+
+    for todo in "${selection[@]}"
+    do
+        if [[ $todo =~ $re_done ]]
+        then
+            todo=$(sed 's/[][\/$*.^|]/\\&/g' <<< "$todo")
+            sed -i '' "/$todo/s/^- \[[xX]]/- [ ]/" "$todofile"
+        elif [[ $todo =~ $re_todo ]]
+        then
+            todo=$(sed 's/[][\/$*.^|]/\\&/g' <<< "$todo")
+            sed -i '' "/$todo/s/^- \[ ]/- [X]/" "$todofile"
+        fi
+    done
+}
+
+t_openurl() {
+    t_read "$query"
+    t_select "$1"
+
+    urls=($(printf "%s\n" "${selection[@]}" | grep -Eo "https?://[^ ]+"))
+    for url in "${urls[@]}"
+    do
+        open "$url" && echo "t: opening ${url} ..."
+    done
+}
+
+while getopts ':heaDns:k:d:z:u:Tt:' opt
+do
+    case $opt in
+        (h) usage ;;
+        (e) ${EDITOR:-vi} "$todofile"
+            exit 0;;
+        (a) showall=0;;
+        (D) onlydone=0;;
+        (n) export=0;;
+        (s) query=$OPTARG;;
+        (k) kill=$OPTARG;;
+        (d) markdone=$OPTARG;;
+        (z) toggle=$OPTARG;;
+        (u) openurl=$OPTARG;;
+        (T) due=" $(date +%F)";;
+        (t) due=" $(date -v $OPTARG +%F)";;
+        (:) printf "t: option -%s requires an argument\n" "$OPTARG"
+            exit 2 ;;
+        (*) printf "t: unrecognized option -%s\n\n" "$OPTARG"
+            usage ;;
+    esac
+done
+
+shift "$(( OPTIND - 1 ))"
+
+[[ $@ =~ ^\/ ]] && query="${*#/}"
+
+if [[ -n $openurl ]]
+then
+    t_openurl "$openurl"
+elif [[ -n $markdone ]]
+then
+    t_done "$markdone"
+elif [[ -n $toggle ]]
+then
+    t_toggle "$toggle"
+elif [[ -n $kill ]]
+then
+    t_kill "$kill"
+elif [[ -n $query ]]
+then
+    t_print "$query"
+elif [[ -n $@ ]]
+then
+    todo="$str_prefix$*$due"
+    echo $todo >> "$todofile"
+else
+    t_print
+fi