3 ddd6e0fa 2024-10-04 rnkn # Copyright (c) 2015-2024 Paul W. Rankin <rnkn@rnkn.xyz>
5 02e4bf34 2024-10-04 rnkn # This program is free software: you can redistribute it and/or modify
6 ddd6e0fa 2024-10-04 rnkn # it under the terms of the GNU General Public License as published by
7 ddd6e0fa 2024-10-04 rnkn # the Free Software Foundation, either version 3 of the License, or
8 ddd6e0fa 2024-10-04 rnkn # (at your option) any later version.
10 ddd6e0fa 2024-10-04 rnkn # This program is distributed in the hope that it will be useful, but
11 ddd6e0fa 2024-10-04 rnkn # WITHOUT ANY WARRANTY; without even the implied warranty of
12 ddd6e0fa 2024-10-04 rnkn # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 ddd6e0fa 2024-10-04 rnkn # General Public License for more details.
15 ddd6e0fa 2024-10-04 rnkn # You should have received a copy of the GNU General Public License
16 02e4bf34 2024-10-04 rnkn # along with this program. If not, see <https://www.gnu.org/licenses/>.
22 8afb25de 2024-10-04 rnkn t [-T] STRING
23 8afb25de 2024-10-04 rnkn t [-aD] [-s REGEX_STRING] [-d [INTEGER|REGEX_STRING]]
24 8afb25de 2024-10-04 rnkn t [-aD] [-s REGEX_STRING] [-k [INTEGER|REGEX_STRING]]
25 8afb25de 2024-10-04 rnkn t [-aD] [-s REGEX_STRING] [-b [INTEGER|REGEX_STRING]]
26 8afb25de 2024-10-04 rnkn t [-aD] [-s REGEX_STRING] [-z [INTEGER|REGEX_STRING]]
29 8afb25de 2024-10-04 rnkn t print incomplete todos
30 8afb25de 2024-10-04 rnkn t -a print all todos
31 8afb25de 2024-10-04 rnkn t -D print all done todos
32 8afb25de 2024-10-04 rnkn t -s call print all todos matching "call"
33 8afb25de 2024-10-04 rnkn t -s "call|email" print all todos matching "call" or "email"
34 8afb25de 2024-10-04 rnkn t -D -s read print all done todos matching "read"
35 8afb25de 2024-10-04 rnkn t -d 12 mark todo item 12 as done
36 8afb25de 2024-10-04 rnkn t -s read -d 3 mark todo item 3 within todos matching "read" as done
37 8afb25de 2024-10-04 rnkn t -d burn mark all todos matching "burn" as done
38 8afb25de 2024-10-04 rnkn t -s burn -d . same as above
39 8afb25de 2024-10-04 rnkn t -k 7 delete todo item 7
40 8afb25de 2024-10-04 rnkn t -k bunnies delete all todos matching "bunnies"
41 8afb25de 2024-10-04 rnkn t -s bunnies -k . same as above
42 8afb25de 2024-10-04 rnkn t -e edit TODO_FILE in $EDITOR
43 8afb25de 2024-10-04 rnkn t -T sell horse add todo "sell horse" due today
44 8afb25de 2024-10-04 rnkn t -n print unnumbered output (suitable for redirection)
49 a64c7d8f 2024-10-04 rnkn re_todo_file='[Tt][Oo][Dd][Oo].*'
50 c7704fb6 2023-11-15 rnkn re_todo='^- \[ ] '
51 c7704fb6 2023-11-15 rnkn re_done='^- \[[xX]] '
52 c7704fb6 2023-11-15 rnkn re_either='^- \[[ xX]] '
53 a64c7d8f 2024-10-04 rnkn re_date='[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
55 a64c7d8f 2024-10-04 rnkn for f in *; do
56 a64c7d8f 2024-10-04 rnkn expr "$f" : "$re_todo_file" > /dev/null && todo_file="$f" && break
59 a64c7d8f 2024-10-04 rnkn if [ ! "$todo_file" ]; then
60 a64c7d8f 2024-10-04 rnkn if [ -r "$TODO_FILE" ]; then
61 a64c7d8f 2024-10-04 rnkn todo_file="$TODO_FILE"
63 a64c7d8f 2024-10-04 rnkn echo 'No todo file found'
68 a64c7d8f 2024-10-04 rnkn # t_read(query)
69 a64c7d8f 2024-10-04 rnkn # returns: sorted list of matching todos
73 24a9575d 2024-10-04 rnkn expr "$query" : '\(.*[A-Z].*\)' > /dev/null || casematch='-i'
74 f625f610 2024-10-05 rnkn todo_list=$(grep $wholeword $casematch "$re_prefix.*$*" "$todo_file")
76 a64c7d8f 2024-10-04 rnkn if [ -n "$todo_list" ]; then
77 a64c7d8f 2024-10-04 rnkn due_list=$(echo "$todo_list" | grep "$re_date")
78 a64c7d8f 2024-10-04 rnkn todo_list=$(echo "$todo_list" | grep -v "$re_date")
79 a64c7d8f 2024-10-04 rnkn due_list=$(echo "$due_list" | sed -E "s/.*($re_date).*/\1&/" |
80 a64c7d8f 2024-10-04 rnkn sort -n | sed -E "s/^$re_date//")
82 a64c7d8f 2024-10-04 rnkn # printf '%s\n%s\n' "$due_list" "$todo_list"
83 a64c7d8f 2024-10-04 rnkn if [ -n "$due_list" ] && [ -n "$todo_list" ]; then
84 a64c7d8f 2024-10-04 rnkn printf '%s\n%s\n' "$due_list" "$todo_list"
85 a64c7d8f 2024-10-04 rnkn elif [ -n "$due_list" ]; then
86 a64c7d8f 2024-10-04 rnkn printf '%s\n' "$due_list"
88 a64c7d8f 2024-10-04 rnkn printf '%s\n' "$todo_list"
93 a64c7d8f 2024-10-04 rnkn # t_print(prefix)
94 a64c7d8f 2024-10-04 rnkn # returns: todo list printed to stdout
96 a64c7d8f 2024-10-04 rnkn input=$(cat)
97 a64c7d8f 2024-10-04 rnkn if [ -n "$input" ]; then
99 a64c7d8f 2024-10-04 rnkn n_width=$(echo "$input" | wc -l | xargs | wc -c)
101 a64c7d8f 2024-10-04 rnkn echo "$input" | while read -r todo; do
102 a64c7d8f 2024-10-04 rnkn date=$(expr "$todo" : ".*\($re_date\)" | sed 's/-//g')
105 a64c7d8f 2024-10-04 rnkn if [ -n "$date" ] && [ -z "$onlydone$showall" ]; then
106 a64c7d8f 2024-10-04 rnkn today=$(date +%Y%m%d)
107 a8437432 2024-10-04 rnkn if [ "$today" -ge "$date" ]; then
108 a64c7d8f 2024-10-04 rnkn todo=$(echo "$todo" |
109 a64c7d8f 2024-10-04 rnkn sed -E "s/($re_prefix)(.*)/\1** \2 **/")
113 a64c7d8f 2024-10-04 rnkn if [ -n "$export" ]; then
114 a64c7d8f 2024-10-04 rnkn printf "%s\n" "${todo}"
116 a64c7d8f 2024-10-04 rnkn printf "%${n_width}s %s\n" "$n" "${todo#- }"
118 a64c7d8f 2024-10-04 rnkn n=$(( n + 1 ))
123 a64c7d8f 2024-10-04 rnkn # t_select(number|regex)
124 a64c7d8f 2024-10-04 rnkn # returns: selected todos
125 c7704fb6 2023-11-15 rnkn t_select() {
126 5bf861ab 2024-10-05 rnkn if expr "$1" : ^[0-9]*$ > /dev/null; then
127 a64c7d8f 2024-10-04 rnkn sed -n "$1p"
130 24a9575d 2024-10-04 rnkn expr "$1" : '.*[A-Z].*' > /dev/null || casematch='-i'
131 a64c7d8f 2024-10-04 rnkn grep $casematch "$*"
135 a64c7d8f 2024-10-04 rnkn # t_done(number|regex)
136 a64c7d8f 2024-10-04 rnkn # returns: altered todo_file
138 a64c7d8f 2024-10-04 rnkn t_select "$1" |
139 a64c7d8f 2024-10-04 rnkn while read -r todo; do
140 a64c7d8f 2024-10-04 rnkn tmp=$(mktemp)
141 a64c7d8f 2024-10-04 rnkn awk -v str="$todo" \
142 53e7b9ea 2024-10-05 rnkn '$0 == str { gsub (/- \[ ]/, "- [X]") } { print }' \
143 a64c7d8f 2024-10-04 rnkn "$todo_file" > "$tmp"
144 a64c7d8f 2024-10-04 rnkn mv "$tmp" "$todo_file"
150 a64c7d8f 2024-10-04 rnkn t_select "$1" |
151 a64c7d8f 2024-10-04 rnkn while read -r todo; do
152 a64c7d8f 2024-10-04 rnkn tmp=$(mktemp)
153 a64c7d8f 2024-10-04 rnkn awk -v str="$todo" '$0 != str' "$todo_file" > "$tmp"
154 a64c7d8f 2024-10-04 rnkn mv "$tmp" "$todo_file"
158 c7704fb6 2023-11-15 rnkn t_toggle() {
159 a64c7d8f 2024-10-04 rnkn t_select "$1" |
160 a64c7d8f 2024-10-04 rnkn while read -r todo; do
161 a64c7d8f 2024-10-04 rnkn tmp=$(mktemp)
163 a64c7d8f 2024-10-04 rnkn expr "$todo" : "$re_done" > /dev/null &&
164 53e7b9ea 2024-10-05 rnkn check='- [ ]' || check='- [X]'
165 a64c7d8f 2024-10-04 rnkn awk -v str="$todo" -v check="$check" \
166 a64c7d8f 2024-10-04 rnkn '$0 == str { gsub (/- \[[ xX]]/, check) } { print }' \
167 a64c7d8f 2024-10-04 rnkn "$todo_file" > "$tmp"
168 a64c7d8f 2024-10-04 rnkn mv "$tmp" "$todo_file"
172 c7704fb6 2023-11-15 rnkn t_openurl() {
173 a64c7d8f 2024-10-04 rnkn t_select "$1" | grep -Eo "https?://[^ ]+" | xargs open
176 1df9404e 2024-10-24 rnkn while getopts :ab:Dd:ehk:nS:s:Tz: opt; do
177 a64c7d8f 2024-10-04 rnkn case $opt in
178 a64c7d8f 2024-10-04 rnkn (h) usage ;;
179 1df9404e 2024-10-24 rnkn (a) showall=0 ;;
180 1df9404e 2024-10-24 rnkn (b) openurl=$OPTARG ;;
181 1df9404e 2024-10-24 rnkn (D) onlydone=0 ;;
182 1df9404e 2024-10-24 rnkn (d) markdone=$OPTARG ;;
183 1df9404e 2024-10-24 rnkn (e) ${EDITOR:-vi} "$todo_file"; exit 0 ;;
184 1df9404e 2024-10-24 rnkn (k) kill=$OPTARG ;;
185 1df9404e 2024-10-24 rnkn (n) export=0 ;;
186 1df9404e 2024-10-24 rnkn (S) query=$OPTARG; wholeword=-w ;;
187 1df9404e 2024-10-24 rnkn (s) query=$OPTARG ;;
188 1df9404e 2024-10-24 rnkn (T) due=" $(date +%F)" ;;
189 1df9404e 2024-10-24 rnkn (z) toggle=$OPTARG ;;
190 1df9404e 2024-10-24 rnkn (:) printf "t: option -%s requires an argument\n" "$OPTARG"; exit 2 ;;
191 1df9404e 2024-10-24 rnkn (*) printf "t: unrecognized option -%s\n\n" "$OPTARG"; usage ;;
195 c7704fb6 2023-11-15 rnkn shift "$(( OPTIND - 1 ))"
197 a64c7d8f 2024-10-04 rnkn if [ -n "$onlydone" ]; then
198 a64c7d8f 2024-10-04 rnkn re_prefix="$re_done"
199 a64c7d8f 2024-10-04 rnkn elif [ -n "$showall" ]; then
200 a64c7d8f 2024-10-04 rnkn re_prefix="$re_either"
202 a64c7d8f 2024-10-04 rnkn re_prefix="$re_todo"
205 a64c7d8f 2024-10-04 rnkn if [ -n "$markdone" ]; then t_read "$query" | t_done "$markdone"
206 a64c7d8f 2024-10-04 rnkn elif [ -n "$toggle" ]; then t_read "$query" | t_toggle "$toggle"
207 a64c7d8f 2024-10-04 rnkn elif [ -n "$kill" ]; then t_read "$query" | t_kill "$kill"
208 a64c7d8f 2024-10-04 rnkn elif [ -n "$openurl" ]; then t_read "$query" | t_openurl "$openurl"
209 a64c7d8f 2024-10-04 rnkn elif [ -n "$query" ]; then t_read "$query" | t_print "$re_prefix"
210 a64c7d8f 2024-10-04 rnkn elif [ -n "$*" ]; then
211 a64c7d8f 2024-10-04 rnkn echo "- [ ] $*${due}" >> "$todo_file"
212 a64c7d8f 2024-10-04 rnkn else t_read | t_print "$re_prefix"