123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- #!/bin/bash
-
- OVERDUER_FILTER=${OVERDUER_FILTER:-"( +OVERDUE or +WEEK )"}
-
- usage() {
- local self
- self=$(basename "$0")
- echo "usage: $self [--] [FILTER]" >&2
- echo "usage: $self --help" >&2
- exit 2
- }
-
- help() {
- local self
- self=$(basename "$0")
- echo "Usage:"
- echo " $self [-H] [-i] [--] [FILTER...]"
- echo ""
- echo "TaskWarrior wrapper to help manage (approaching!) due dates."
- echo ""
- echo "Options:"
- echo ""
- echo " -- Stop processing options; treat rest of arguments as"
- echo " TaskWarrior filter expression."
- echo ""
- echo " -n Do not modify any tasks; just show command that would do so."
- echo " Note: this does not turn off listing commands which, by design"
- echo " of TaskWarrior, can change numeric task IDs (not UUIDs)."
- echo ""
- echo " -H Do not include help messages in the template."
- echo ""
- echo " -i Include details of each task (\`task info\`) inside the"
- echo " template."
- echo ""
- echo "$self will use listing of TaskWarrior tasks past or close to their"
- echo "due date to create a template that will be automatically opened in"
- echo "your favorite editor. By editing the template and exiting the"
- echo "editor, you can assign new due dates to any of these tasks."
- echo "(Read instructions embedded inside the template for details.)"
- echo ""
- echo "If any tasks are modified, their new state is printed after the"
- echo "fact. (Hint: use \`task undo\` to revert last change)."
- echo ""
- echo "By default, filter '( +OVERDUE or +WEEK )' is used. This can be"
- echo "overriden by setting environment variable OVERDUER_FILTER or"
- echo "specifying filter expression directly on command line."
- echo ""
- echo "You need to have vipe (from moreutils) installed and set EDITOR"
- echo "environment variable, see vipe(1) for details."
- exit 0
- }
-
- warn() {
- local msg
- for msg in "$@";
- do
- echo "$msg" >& 2
- done
- }
-
- distill() {
- #
- # Remove comments and everything except due expression and UUID from stdin
- #
- local due
- local rest
- local uuid
- grep -v "^[[:space:]]*#" \
- | while read -r due rest;
- do
- test -n "$due" || continue
- uuid=${rest##* }
- test -n "$uuid" || continue
- echo "$due $uuid"
- done
- }
-
- maybe_do() {
- #
- # Maybe do it, maybe just say it
- #
- case $Dry in
- true) warn "$*" ;;
- false) "$@" ;;
- esac
- }
-
- apply() {
- #
- # Apply each pair of DUE UUID on stdin
- #
- local due
- local uuid
- local es=0
- while read -r due uuid;
- do
- task info "$uuid" >/dev/null || {
- warn "ignoring invalid UUID: $due for $uuid"
- es=3
- continue
- }
- task calc "$due" >/dev/null || {
- warn "ignoring invalid due date: $due for $uuid"
- es=3
- continue
- }
- maybe_do task "$uuid" modify "due:$due"
- task "$uuid" info
- done
- return $es
- }
-
- mkhelp1() {
- #
- # Print first part (before listing) of the help text
- #
- $AddHelp || return 0
- echo "#"
- echo "# Edit due dates below to your liking. The resulting format"
- echo "# must be:"
- echo "#"
- echo "# TIME [anything] UUID"
- echo "#"
- echo "# where TIME is a valid TaskWarrior time expression (hint: use"
- echo "# \`task calc TIME\`) and UUID, well, a valid task UUID. The"
- echo "# [anything] part is provided only for your convenience and will"
- echo "# be ignored."
- echo "#"
- echo "# What will also be ignored:"
- echo "#"
- echo "# * comments like this,"
- echo "# * empty lines,"
- echo "# * template lines that were left unchanged."
- echo "#"
- echo
- echo "#"
- echo "# CUR_DUE ID DESCRIPTION UUID"
- echo
- }
-
- mkhelp2() {
- #
- # Print second part (after the listing) of the help text
- #
- $AddHelp || return 0
- echo
- echo "#"
- echo "# Note that CUR_DUE is ONLY DATE, NOT TIME, while actual due"
- echo "# time may be set more precisely. If that matters, consult"
- echo "# full task info using syntax such as \`task ID info\` or -i."
- echo "# switch."
- echo "#"
- }
-
- mklisting() {
- #
- # Print task listing in form of "CUR_DUE If DESCRIPTION UUID"
- #
- task rc.detection:off rc.verbose:nothing \
- rc.defaultwidth:120 \
- rc.report.OVERDUER.columns:due,id,description,uuid \
- rc.report.OVERDUER.labels:DUE,ID,DESC,UUID \
- "${TaskFilter[@]}" \
- OVERDUER 2>/dev/null \
- | grep '^[^ ]' \
- | grep -v "^[[:space:]]*-" \
- | grep -v "^[[:space:]]*[A-Z]" \
- | sort
- }
-
- mkinfos() {
- #
- # Print extra info for each listed task; all commented out
- #
- local uuid
- $AddInfos || return 0
- echo ""
- echo ""
- echo "# #"
- echo "# Task details #"
- echo "# #"
- echo ""
- mklisting \
- | rev | cut -d' ' -f1 | rev \
- | while read -r uuid;
- do
- task "$uuid" info 2>/dev/null \
- | sed "s/^/# /"
- echo
- done
- }
-
- mktemplate() {
- #
- # Construct template text
- #
- mkhelp1
- mklisting
- mkhelp2
- mkinfos
- }
-
- main() {
- local Dry=false
- local tmp
- local es=0
- local AddHelp=true
- local AddInfos=false
- local TaskFilter=()
- while true; do case $1 in
- -n) Dry=true; shift ;;
- -H) AddHelp=false; shift ;;
- -i) AddInfos=true; shift ;;
- --) shift; break ;;
- --help) help ;;
- -*) usage ;;
- *) break ;;
- esac done
- which vipe >/dev/null || {
- warn "fatal: vipe is not installed"
- exit 3
- }
- TaskFilter=("$@")
- test -n "${TaskFilter[*]}" || TaskFilter=("$OVERDUER_FILTER")
- tmp=$(mktemp -d -t overduer.main.XXXXXXXX)
- mktemplate \
- | tee "$tmp/old" \
- | vipe > "$tmp/new"
- <"$tmp/old" distill | sort >"$tmp/old.distilled"
- <"$tmp/new" distill | sort >"$tmp/new.distilled"
- comm -13 "$tmp/old.distilled" "$tmp/new.distilled" > "$tmp/changes"
- if test -s "$tmp/changes";
- then
- <"$tmp/changes" apply; es=$?
- else
- warn "no changes detected; nothing to do"
- es=1
- fi
- rm -r "$tmp"
- return $es
- }
-
- main "$@"
|