7 t [-aD] [-s REGEX_STRING] [-d [INTEGER|REGEX_STRING]]
9 t [-T] [-t [+|-]VAL[ymwd]] STRING
12 t print incomplete todos
14 t -D print all done todos
15 t -s call print all todos matching "call"
17 t -s "call|email" print all todos matching "call" or "email"
18 t -D -s read print all done todos matching "read"
19 t -d 12 mark todo item 12 as done
20 t -s read -d 3 mark todo item 3 within todos matching "read" as done
21 t -d burn mark all todos matching "burn" as done
22 t -s burn -d . same as above
23 t -k 7 delete todo item 7
24 t -k bunnies delete all todos matching "bunnies"
25 t -s bunnies -k . same as above
26 t -e edit $TODO_FILE in $EDITOR
27 t -T sell horse add todo "sell horse" due today
28 t -t 20d celebrate add todo "celebrate" due on the 20th of this month
29 t -t +1w buy racecar add todo "buy racecar" due a week from today
30 (for date syntax, see date manual entry)
31 t -n print unnumbered output (suitable for redirection)
40 re_todofile='[Tt][Oo][Dd][Oo](\.[^.]+)?'
43 re_either='^- \[[ xX]] '
44 re_date='[0-9]{4}-[0-9]{2}-[0-9]{2}'
49 [[ $file =~ $re_todofile ]] && todofile="$file"
52 if [[ ! $todofile && -r $TODO_FILE ]]
53 then todofile="$TODO_FILE"
54 elif [[ ! $todofile ]]
55 then printf 'No todo file found or environment variable TODO_FILE not set!\n'
71 [[ ! $* =~ [A-Z] ]] && casematch='-i'
72 todo_list=($(grep -E $casematch "$re_prefix.*($*)" "$todofile"))
75 for i in "${!todo_list[@]}"
77 if [[ ${todo_list[i]} =~ $re_date ]]
79 item="${todo_list[i]}"
85 due_list=($(printf "%s\n" "${due_list[@]}" | sed -E "s/.*($re_date).*/\1&/" | sort -g | sed -E "s/^$re_date//"))
86 todo_list=(${due_list[@]} ${todo_list[@]})
93 local buffer=$(mktemp)
94 local n_total=${#todo_list[@]}
95 local n_width=${#n_total}
97 for todo in "${todo_list[@]}"
99 if [[ $todo =~ $re_todo && $todo =~ $re_date ]]
101 local date=${BASH_REMATCH//-}
102 local today=$(date +%Y%m%d)
103 (( date <= today )) && todo=$(sed -E "s/($re_prefix)(.*)/\1** \2 **/" <<< "$todo")
108 printf "%s\n" "${todo}" >> "$buffer"
110 printf "%${n_width}s %s\n" "$n" "${todo#- }" >> "$buffer"
115 if (( lines <= n_total ))
116 then ${PAGER:-less} -X < "$buffer"
124 if [[ $1 =~ ^[0-9]+$ ]]
126 selection=${todo_list[(( $1 - 1 ))]}
129 [[ ! $@ =~ [A-Z] ]] && casematch='-i'
130 selection=($(printf "%s\n" "${todo_list[@]}" | grep $casematch "$@" ))
138 for todo in "${selection[@]}"
140 todo=$(sed 's/[][\/$*.^|]/\\&/g' <<< "$todo")
141 sed -i'' "/$todo/s/^- \[ ]/- \[X]/" "$todofile"
149 for todo in "${selection[@]}"
151 todo=$(sed 's/[][\/$*.^|]/\\&/g' <<< "$todo")
152 sed -i '' "/$todo/d" "$todofile"
160 for todo in "${selection[@]}"
162 if [[ $todo =~ $re_done ]]
164 todo=$(sed 's/[][\/$*.^|]/\\&/g' <<< "$todo")
165 sed -i '' "/$todo/s/^- \[[xX]]/- [ ]/" "$todofile"
166 elif [[ $todo =~ $re_todo ]]
168 todo=$(sed 's/[][\/$*.^|]/\\&/g' <<< "$todo")
169 sed -i '' "/$todo/s/^- \[ ]/- [X]/" "$todofile"
178 urls=($(printf "%s\n" "${selection[@]}" | grep -Eo "https?://[^ ]+"))
179 for url in "${urls[@]}"
181 open "$url" && echo "t: opening ${url} ..."
185 while getopts ':heaDns:k:d:z:u:Tt:' opt
189 (e) ${EDITOR:-vi} "$todofile"
196 (d) markdone=$OPTARG;;
198 (u) openurl=$OPTARG;;
199 (T) due=" $(date +%F)";;
200 (t) due=" $(date -v $OPTARG +%F)";;
201 (:) printf "t: option -%s requires an argument\n" "$OPTARG"
203 (*) printf "t: unrecognized option -%s\n\n" "$OPTARG"
208 shift "$(( OPTIND - 1 ))"
210 [[ $@ =~ ^\/ ]] && query="${*#/}"
215 elif [[ -n $markdone ]]
218 elif [[ -n $toggle ]]
229 todo="$str_prefix$*$due"
230 echo $todo >> "$todofile"