commit - ef761c9ffe6105587fa6357cda72814dc5c609b5
commit + a64c7d8f6187c61a6923e157b921fee3348236c4
blob - bfdec4fce808e6c34c559561adcee1867f3a63f5
blob + 5b02a1b184ca5d91ef8e8b3573071f1f63783992
--- t_done.sh
+++ t_done.sh
-#! /usr/bin/env bash
+#! /bin/sh
usage() {
- cat <<EOF
+ cat <<EOF
usage:
- t [-aD]
- t [-aD] [-s REGEX_STRING] [-d [INTEGER|REGEX_STRING]]
- t /REGEX_STRING
- t [-T] [-t [+|-]VAL[ymwd]] STRING
+ t [-aDen]
+ t [-aDT] [-s REGEX_STRING] [-d [INTEGER|REGEX_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)
+ t print incomplete todos
+ t -a print all todos
+ t -D print all done todos
+ t -s call print all todos matching "call"
+ 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 -n print unnumbered output (suitable for redirection)
EOF
- exit 1
+ exit 1
}
-IFS=$'\n'
-red='\e[0;31m'
-clear='\e[0m'
-str_prefix='- [ ] '
-re_todofile='[Tt][Oo][Dd][Oo](\.[^.]+)?'
+re_todo_file='[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)
+re_date='[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
-for file in *
-do
- [[ $file =~ $re_todofile ]] && todofile="$file"
+for f in *; do
+ expr "$f" : "$re_todo_file" > /dev/null && todo_file="$f" && break
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
+if [ ! "$todo_file" ]; then
+ if [ -r "$TODO_FILE" ]; then
+ todo_file="$TODO_FILE"
+ else
+ echo 'No todo file found'
+ exit 1
+ fi
fi
+# t_read(query)
+# returns: sorted list of matching todos
t_read() {
- if [[ $onlydone ]]
- then
- re_prefix=$re_done
- elif [[ $showall ]]
- then
- re_prefix=$re_either
- else
- re_prefix=$re_todo
- fi
+ query="$*"
+ casematch=
+ expr "$query" : '\(.*[A-Z].*\)' > /dev/null && casematch='-i'
+ todo_list=$(grep $casematch "$re_prefix.*$*" "$todo_file")
- 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
+ if [ -n "$todo_list" ]; then
+ due_list=$(echo "$todo_list" | grep "$re_date")
+ todo_list=$(echo "$todo_list" | grep -v "$re_date")
+ due_list=$(echo "$due_list" | sed -E "s/.*($re_date).*/\1&/" |
+ sort -n | sed -E "s/^$re_date//")
- 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[@]})
+ # printf '%s\n%s\n' "$due_list" "$todo_list"
+ if [ -n "$due_list" ] && [ -n "$todo_list" ]; then
+ printf '%s\n%s\n' "$due_list" "$todo_list"
+ elif [ -n "$due_list" ]; then
+ printf '%s\n' "$due_list"
+ else
+ printf '%s\n' "$todo_list"
+ fi
+ fi
}
+# t_print(prefix)
+# returns: todo list printed to stdout
t_print() {
- t_read "$query"
+ input=$(cat)
+ if [ -n "$input" ]; then
+ n=1
+ n_width=$(echo "$input" | wc -l | xargs | wc -c)
- local n=1
- local buffer=$(mktemp)
- local n_total=${#todo_list[@]}
- local n_width=${#n_total}
+ echo "$input" | while read -r todo; do
+ date=$(expr "$todo" : ".*\($re_date\)" | sed 's/-//g')
+ today=
- 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 [ -n "$date" ] && [ -z "$onlydone$showall" ]; then
+ today=$(date +%Y%m%d)
+ if [ "$date" -gt "$today" ]; then
+ todo=$(echo "$todo" |
+ sed -E "s/($re_prefix)(.*)/\1** \2 **/")
+ fi
+ 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"
+ if [ -n "$export" ]; then
+ printf "%s\n" "${todo}"
+ else
+ printf "%${n_width}s %s\n" "$n" "${todo#- }"
+ fi
+ n=$(( n + 1 ))
+ done
+ fi
}
+# t_select(number|regex)
+# returns: selected todos
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
+ if expr "$1" + 0 > /dev/null 2>&1; then
+ sed -n "$1p"
+ else
+ casematch=
+ expr "$1" : '.*[A-Z].*' > /dev/null && casematch='-i'
+ grep $casematch "$*"
+ fi
}
+# t_done(number|regex)
+# returns: altered todo_file
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_select "$1" |
+ while read -r todo; do
+ tmp=$(mktemp)
+ awk -v str="$todo" \
+ '$0 == str { gsub (/- \[ ]/, "- [x]") } { print }' \
+ "$todo_file" > "$tmp"
+ mv "$tmp" "$todo_file"
+ done
}
+# t_kill()
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_select "$1" |
+ while read -r todo; do
+ tmp=$(mktemp)
+ awk -v str="$todo" '$0 != str' "$todo_file" > "$tmp"
+ mv "$tmp" "$todo_file"
+ 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_select "$1" |
+ while read -r todo; do
+ tmp=$(mktemp)
+ check=
+ expr "$todo" : "$re_done" > /dev/null &&
+ check='- [ ]' || check='- [x]'
+ awk -v str="$todo" -v check="$check" \
+ '$0 == str { gsub (/- \[[ xX]]/, check) } { print }' \
+ "$todo_file" > "$tmp"
+ mv "$tmp" "$todo_file"
+ 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
+ t_select "$1" | grep -Eo "https?://[^ ]+" | xargs open
}
-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
+while getopts ':ab:Dd:ehk:ns:Tz:' opt; do
+ case $opt in
+ (h) usage ;;
+ (a) showall=0;;
+ (b) openurl=$OPTARG;;
+ (D) onlydone=0;;
+ (d) markdone=$OPTARG;;
+ (e) ${EDITOR:-vi} "$todo_file"; exit 0;;
+ (k) kill=$OPTARG;;
+ (n) export=0;;
+ (s) query=$OPTARG;;
+ (T) due=" $(date +%F)";;
+ (z) toggle=$OPTARG;;
+ (:) 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"
+if [ -n "$onlydone" ]; then
+ re_prefix="$re_done"
+elif [ -n "$showall" ]; then
+ re_prefix="$re_either"
else
- t_print
+ re_prefix="$re_todo"
fi
+
+if [ -n "$markdone" ]; then t_read "$query" | t_done "$markdone"
+elif [ -n "$toggle" ]; then t_read "$query" | t_toggle "$toggle"
+elif [ -n "$kill" ]; then t_read "$query" | t_kill "$kill"
+elif [ -n "$openurl" ]; then t_read "$query" | t_openurl "$openurl"
+elif [ -n "$query" ]; then t_read "$query" | t_print "$re_prefix"
+elif [ -n "$*" ]; then
+ echo "- [ ] $*${due}" >> "$todo_file"
+else t_read | t_print "$re_prefix"
+fi