commit a64c7d8f6187c61a6923e157b921fee3348236c4 from: Paul W. Rankin date: Fri Oct 04 09:53:44 2024 UTC t_done.sh: rewrite in POSIX sh commit - ef761c9ffe6105587fa6357cda72814dc5c609b5 commit + a64c7d8f6187c61a6923e157b921fee3348236c4 blob - bfdec4fce808e6c34c559561adcee1867f3a63f5 blob + 5b02a1b184ca5d91ef8e8b3573071f1f63783992 --- t_done.sh +++ t_done.sh @@ -1,233 +1,195 @@ -#! /usr/bin/env bash +#! /bin/sh usage() { - cat < /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