Blame


1 a64c7d8f 2024-10-04 rnkn #! /bin/sh
2 c7704fb6 2023-11-15 rnkn
3 c7704fb6 2023-11-15 rnkn usage() {
4 a64c7d8f 2024-10-04 rnkn cat <<EOF
5 c7704fb6 2023-11-15 rnkn usage:
6 a64c7d8f 2024-10-04 rnkn t [-aDen]
7 a64c7d8f 2024-10-04 rnkn t [-aDT] [-s REGEX_STRING] [-d [INTEGER|REGEX_STRING]]
8 c7704fb6 2023-11-15 rnkn
9 c7704fb6 2023-11-15 rnkn examples:
10 a64c7d8f 2024-10-04 rnkn t print incomplete todos
11 a64c7d8f 2024-10-04 rnkn t -a print all todos
12 a64c7d8f 2024-10-04 rnkn t -D print all done todos
13 a64c7d8f 2024-10-04 rnkn t -s call print all todos matching "call"
14 a64c7d8f 2024-10-04 rnkn t -s "call|email" print all todos matching "call" or "email"
15 a64c7d8f 2024-10-04 rnkn t -D -s read print all done todos matching "read"
16 a64c7d8f 2024-10-04 rnkn t -d 12 mark todo item 12 as done
17 a64c7d8f 2024-10-04 rnkn t -s read -d 3 mark todo item 3 within todos matching "read" as done
18 a64c7d8f 2024-10-04 rnkn t -d burn mark all todos matching "burn" as done
19 a64c7d8f 2024-10-04 rnkn t -s burn -d . same as above
20 a64c7d8f 2024-10-04 rnkn t -k 7 delete todo item 7
21 a64c7d8f 2024-10-04 rnkn t -k bunnies delete all todos matching "bunnies"
22 a64c7d8f 2024-10-04 rnkn t -s bunnies -k . same as above
23 a64c7d8f 2024-10-04 rnkn t -e edit TODO_FILE in $EDITOR
24 a64c7d8f 2024-10-04 rnkn t -T sell horse add todo "sell horse" due today
25 a64c7d8f 2024-10-04 rnkn t -n print unnumbered output (suitable for redirection)
26 c7704fb6 2023-11-15 rnkn EOF
27 a64c7d8f 2024-10-04 rnkn exit 1
28 c7704fb6 2023-11-15 rnkn }
29 c7704fb6 2023-11-15 rnkn
30 a64c7d8f 2024-10-04 rnkn re_todo_file='[Tt][Oo][Dd][Oo].*'
31 c7704fb6 2023-11-15 rnkn re_todo='^- \[ ] '
32 c7704fb6 2023-11-15 rnkn re_done='^- \[[xX]] '
33 c7704fb6 2023-11-15 rnkn re_either='^- \[[ xX]] '
34 a64c7d8f 2024-10-04 rnkn re_date='[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
35 c7704fb6 2023-11-15 rnkn
36 a64c7d8f 2024-10-04 rnkn for f in *; do
37 a64c7d8f 2024-10-04 rnkn expr "$f" : "$re_todo_file" > /dev/null && todo_file="$f" && break
38 c7704fb6 2023-11-15 rnkn done
39 c7704fb6 2023-11-15 rnkn
40 a64c7d8f 2024-10-04 rnkn if [ ! "$todo_file" ]; then
41 a64c7d8f 2024-10-04 rnkn if [ -r "$TODO_FILE" ]; then
42 a64c7d8f 2024-10-04 rnkn todo_file="$TODO_FILE"
43 a64c7d8f 2024-10-04 rnkn else
44 a64c7d8f 2024-10-04 rnkn echo 'No todo file found'
45 a64c7d8f 2024-10-04 rnkn exit 1
46 a64c7d8f 2024-10-04 rnkn fi
47 c7704fb6 2023-11-15 rnkn fi
48 c7704fb6 2023-11-15 rnkn
49 a64c7d8f 2024-10-04 rnkn # t_read(query)
50 a64c7d8f 2024-10-04 rnkn # returns: sorted list of matching todos
51 c7704fb6 2023-11-15 rnkn t_read() {
52 a64c7d8f 2024-10-04 rnkn query="$*"
53 a64c7d8f 2024-10-04 rnkn casematch=
54 a64c7d8f 2024-10-04 rnkn expr "$query" : '\(.*[A-Z].*\)' > /dev/null && casematch='-i'
55 a64c7d8f 2024-10-04 rnkn todo_list=$(grep $casematch "$re_prefix.*$*" "$todo_file")
56 c7704fb6 2023-11-15 rnkn
57 a64c7d8f 2024-10-04 rnkn if [ -n "$todo_list" ]; then
58 a64c7d8f 2024-10-04 rnkn due_list=$(echo "$todo_list" | grep "$re_date")
59 a64c7d8f 2024-10-04 rnkn todo_list=$(echo "$todo_list" | grep -v "$re_date")
60 a64c7d8f 2024-10-04 rnkn due_list=$(echo "$due_list" | sed -E "s/.*($re_date).*/\1&/" |
61 a64c7d8f 2024-10-04 rnkn sort -n | sed -E "s/^$re_date//")
62 c7704fb6 2023-11-15 rnkn
63 a64c7d8f 2024-10-04 rnkn # printf '%s\n%s\n' "$due_list" "$todo_list"
64 a64c7d8f 2024-10-04 rnkn if [ -n "$due_list" ] && [ -n "$todo_list" ]; then
65 a64c7d8f 2024-10-04 rnkn printf '%s\n%s\n' "$due_list" "$todo_list"
66 a64c7d8f 2024-10-04 rnkn elif [ -n "$due_list" ]; then
67 a64c7d8f 2024-10-04 rnkn printf '%s\n' "$due_list"
68 a64c7d8f 2024-10-04 rnkn else
69 a64c7d8f 2024-10-04 rnkn printf '%s\n' "$todo_list"
70 a64c7d8f 2024-10-04 rnkn fi
71 a64c7d8f 2024-10-04 rnkn fi
72 c7704fb6 2023-11-15 rnkn }
73 c7704fb6 2023-11-15 rnkn
74 a64c7d8f 2024-10-04 rnkn # t_print(prefix)
75 a64c7d8f 2024-10-04 rnkn # returns: todo list printed to stdout
76 c7704fb6 2023-11-15 rnkn t_print() {
77 a64c7d8f 2024-10-04 rnkn input=$(cat)
78 a64c7d8f 2024-10-04 rnkn if [ -n "$input" ]; then
79 a64c7d8f 2024-10-04 rnkn n=1
80 a64c7d8f 2024-10-04 rnkn n_width=$(echo "$input" | wc -l | xargs | wc -c)
81 c7704fb6 2023-11-15 rnkn
82 a64c7d8f 2024-10-04 rnkn echo "$input" | while read -r todo; do
83 a64c7d8f 2024-10-04 rnkn date=$(expr "$todo" : ".*\($re_date\)" | sed 's/-//g')
84 a64c7d8f 2024-10-04 rnkn today=
85 c7704fb6 2023-11-15 rnkn
86 a64c7d8f 2024-10-04 rnkn if [ -n "$date" ] && [ -z "$onlydone$showall" ]; then
87 a64c7d8f 2024-10-04 rnkn today=$(date +%Y%m%d)
88 a64c7d8f 2024-10-04 rnkn if [ "$date" -gt "$today" ]; then
89 a64c7d8f 2024-10-04 rnkn todo=$(echo "$todo" |
90 a64c7d8f 2024-10-04 rnkn sed -E "s/($re_prefix)(.*)/\1** \2 **/")
91 a64c7d8f 2024-10-04 rnkn fi
92 a64c7d8f 2024-10-04 rnkn fi
93 c7704fb6 2023-11-15 rnkn
94 a64c7d8f 2024-10-04 rnkn if [ -n "$export" ]; then
95 a64c7d8f 2024-10-04 rnkn printf "%s\n" "${todo}"
96 a64c7d8f 2024-10-04 rnkn else
97 a64c7d8f 2024-10-04 rnkn printf "%${n_width}s %s\n" "$n" "${todo#- }"
98 a64c7d8f 2024-10-04 rnkn fi
99 a64c7d8f 2024-10-04 rnkn n=$(( n + 1 ))
100 a64c7d8f 2024-10-04 rnkn done
101 a64c7d8f 2024-10-04 rnkn fi
102 c7704fb6 2023-11-15 rnkn }
103 c7704fb6 2023-11-15 rnkn
104 a64c7d8f 2024-10-04 rnkn # t_select(number|regex)
105 a64c7d8f 2024-10-04 rnkn # returns: selected todos
106 c7704fb6 2023-11-15 rnkn t_select() {
107 a64c7d8f 2024-10-04 rnkn if expr "$1" + 0 > /dev/null 2>&1; then
108 a64c7d8f 2024-10-04 rnkn sed -n "$1p"
109 a64c7d8f 2024-10-04 rnkn else
110 a64c7d8f 2024-10-04 rnkn casematch=
111 a64c7d8f 2024-10-04 rnkn expr "$1" : '.*[A-Z].*' > /dev/null && casematch='-i'
112 a64c7d8f 2024-10-04 rnkn grep $casematch "$*"
113 a64c7d8f 2024-10-04 rnkn fi
114 c7704fb6 2023-11-15 rnkn }
115 c7704fb6 2023-11-15 rnkn
116 a64c7d8f 2024-10-04 rnkn # t_done(number|regex)
117 a64c7d8f 2024-10-04 rnkn # returns: altered todo_file
118 c7704fb6 2023-11-15 rnkn t_done() {
119 a64c7d8f 2024-10-04 rnkn t_select "$1" |
120 a64c7d8f 2024-10-04 rnkn while read -r todo; do
121 a64c7d8f 2024-10-04 rnkn tmp=$(mktemp)
122 a64c7d8f 2024-10-04 rnkn awk -v str="$todo" \
123 a64c7d8f 2024-10-04 rnkn '$0 == str { gsub (/- \[ ]/, "- [x]") } { print }' \
124 a64c7d8f 2024-10-04 rnkn "$todo_file" > "$tmp"
125 a64c7d8f 2024-10-04 rnkn mv "$tmp" "$todo_file"
126 a64c7d8f 2024-10-04 rnkn done
127 c7704fb6 2023-11-15 rnkn }
128 c7704fb6 2023-11-15 rnkn
129 a64c7d8f 2024-10-04 rnkn # t_kill()
130 c7704fb6 2023-11-15 rnkn t_kill() {
131 a64c7d8f 2024-10-04 rnkn t_select "$1" |
132 a64c7d8f 2024-10-04 rnkn while read -r todo; do
133 a64c7d8f 2024-10-04 rnkn tmp=$(mktemp)
134 a64c7d8f 2024-10-04 rnkn awk -v str="$todo" '$0 != str' "$todo_file" > "$tmp"
135 a64c7d8f 2024-10-04 rnkn mv "$tmp" "$todo_file"
136 a64c7d8f 2024-10-04 rnkn done
137 c7704fb6 2023-11-15 rnkn }
138 c7704fb6 2023-11-15 rnkn
139 c7704fb6 2023-11-15 rnkn t_toggle() {
140 a64c7d8f 2024-10-04 rnkn t_select "$1" |
141 a64c7d8f 2024-10-04 rnkn while read -r todo; do
142 a64c7d8f 2024-10-04 rnkn tmp=$(mktemp)
143 a64c7d8f 2024-10-04 rnkn check=
144 a64c7d8f 2024-10-04 rnkn expr "$todo" : "$re_done" > /dev/null &&
145 a64c7d8f 2024-10-04 rnkn check='- [ ]' || check='- [x]'
146 a64c7d8f 2024-10-04 rnkn awk -v str="$todo" -v check="$check" \
147 a64c7d8f 2024-10-04 rnkn '$0 == str { gsub (/- \[[ xX]]/, check) } { print }' \
148 a64c7d8f 2024-10-04 rnkn "$todo_file" > "$tmp"
149 a64c7d8f 2024-10-04 rnkn mv "$tmp" "$todo_file"
150 a64c7d8f 2024-10-04 rnkn done
151 c7704fb6 2023-11-15 rnkn }
152 c7704fb6 2023-11-15 rnkn
153 c7704fb6 2023-11-15 rnkn t_openurl() {
154 a64c7d8f 2024-10-04 rnkn t_select "$1" | grep -Eo "https?://[^ ]+" | xargs open
155 c7704fb6 2023-11-15 rnkn }
156 c7704fb6 2023-11-15 rnkn
157 a64c7d8f 2024-10-04 rnkn while getopts ':ab:Dd:ehk:ns:Tz:' opt; do
158 a64c7d8f 2024-10-04 rnkn case $opt in
159 a64c7d8f 2024-10-04 rnkn (h) usage ;;
160 a64c7d8f 2024-10-04 rnkn (a) showall=0;;
161 a64c7d8f 2024-10-04 rnkn (b) openurl=$OPTARG;;
162 a64c7d8f 2024-10-04 rnkn (D) onlydone=0;;
163 a64c7d8f 2024-10-04 rnkn (d) markdone=$OPTARG;;
164 a64c7d8f 2024-10-04 rnkn (e) ${EDITOR:-vi} "$todo_file"; exit 0;;
165 a64c7d8f 2024-10-04 rnkn (k) kill=$OPTARG;;
166 a64c7d8f 2024-10-04 rnkn (n) export=0;;
167 a64c7d8f 2024-10-04 rnkn (s) query=$OPTARG;;
168 a64c7d8f 2024-10-04 rnkn (T) due=" $(date +%F)";;
169 a64c7d8f 2024-10-04 rnkn (z) toggle=$OPTARG;;
170 a64c7d8f 2024-10-04 rnkn (:) printf "t: option -%s requires an argument\n" "$OPTARG"
171 a64c7d8f 2024-10-04 rnkn exit 2 ;;
172 a64c7d8f 2024-10-04 rnkn (*) printf "t: unrecognized option -%s\n\n" "$OPTARG"
173 a64c7d8f 2024-10-04 rnkn usage ;;
174 a64c7d8f 2024-10-04 rnkn esac
175 c7704fb6 2023-11-15 rnkn done
176 c7704fb6 2023-11-15 rnkn
177 c7704fb6 2023-11-15 rnkn shift "$(( OPTIND - 1 ))"
178 c7704fb6 2023-11-15 rnkn
179 a64c7d8f 2024-10-04 rnkn if [ -n "$onlydone" ]; then
180 a64c7d8f 2024-10-04 rnkn re_prefix="$re_done"
181 a64c7d8f 2024-10-04 rnkn elif [ -n "$showall" ]; then
182 a64c7d8f 2024-10-04 rnkn re_prefix="$re_either"
183 c7704fb6 2023-11-15 rnkn else
184 a64c7d8f 2024-10-04 rnkn re_prefix="$re_todo"
185 c7704fb6 2023-11-15 rnkn fi
186 a64c7d8f 2024-10-04 rnkn
187 a64c7d8f 2024-10-04 rnkn if [ -n "$markdone" ]; then t_read "$query" | t_done "$markdone"
188 a64c7d8f 2024-10-04 rnkn elif [ -n "$toggle" ]; then t_read "$query" | t_toggle "$toggle"
189 a64c7d8f 2024-10-04 rnkn elif [ -n "$kill" ]; then t_read "$query" | t_kill "$kill"
190 a64c7d8f 2024-10-04 rnkn elif [ -n "$openurl" ]; then t_read "$query" | t_openurl "$openurl"
191 a64c7d8f 2024-10-04 rnkn elif [ -n "$query" ]; then t_read "$query" | t_print "$re_prefix"
192 a64c7d8f 2024-10-04 rnkn elif [ -n "$*" ]; then
193 a64c7d8f 2024-10-04 rnkn echo "- [ ] $*${due}" >> "$todo_file"
194 a64c7d8f 2024-10-04 rnkn else t_read | t_print "$re_prefix"
195 a64c7d8f 2024-10-04 rnkn fi