From 2851d99e519e0537da10180b65fd008d25aadff0 Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Thu, 3 Jun 2021 08:56:54 +1000 Subject: [PATCH] Initial checkin --- t.sh | 1393 ++++++++++++++++++++++++++++++++++++++++++++++++++ vcftocsv.awk | 30 ++ 2 files changed, 1423 insertions(+) create mode 100755 t.sh create mode 100644 vcftocsv.awk diff --git a/t.sh b/t.sh new file mode 100755 index 0000000..f6b00c7 --- /dev/null +++ b/t.sh @@ -0,0 +1,1393 @@ +#!/bin/bash + +trap "exit 1" TERM +export MYPID=$$ + + + + +# ANSI stuff +BOLD="\033[1m" +ITALIC="\033[3m" +STRIKE="\033[9m" +PLAIN="\033[0m" + +UNDERLINE="\033[4m" +RED="\033[31m" +MAGENTA="\033[35m" +GREEN="\033[32m" +YELLOW="\033[33m" +BLUE="\033[34m" +CYAN="\033[36m" +GREY="\033[2;37m" +LINK="$BLUE$UNDERLINE" +brack="$CYAN" +brackfold="$CYAN" +HILITE="\033[43;1m" + +GREYBG="\033[48;2;30;30;30m" + +TOPTITLE="\033[44;1m" +LEFTTITLE="\033[31;1m" +#FOLDBG="\033[100m" +FOLDBG="$BOLDD" + +function die() { + kill -s TERM $MYPID +} + +function getalts() { + local verb alt var x + verb=$1 + alt="" + var="words_$verb" + IFS='|' + for x in ${!var}; do + if [[ $x != $verb ]]; then + [[ -z $alt ]] && alt=$x || alt="$alt,$x" + fi + done + IFS=' ' + echo "$alt" +} + +function usage() { + local titleformat format + local usage_var desc_var + format="%22s %-40s %s\n" + echo "usage: $0 COMMAND [commandopts]" + echo + printf "$format" "COMMAND" "DESCRIPTION" "SYNONYMS" + for x in $valid_modes; do + usage_var="usage_$x" + desc_var="desc_$x" + printf "$format" "${!usage_var}" "${!desc_var}" "$(getalts $x)" + done +} + +function inc() { + indent=$((indent + $indentamt)) +} + +function dec() { + indent=$((indent - $indentamt)) +} + +function getuid_witherror() { # [noun] + local x rv noun + if [[ $$ -ge 2 ]]; then + noun=$2 + else + noun="task" + fi + x=$(getuid $1) + rv=$? + if [[ $rv -ne 0 ]]; then + error "Specified $noun #$1 does not exist." + die + fi + echo "$x" + return $rv +} + +function getid() { + local res id uid + uid=$1 + res="" + for id in ${!idmap[@]}; do + if [[ ${idmap[$id]} == $uid ]]; then + res=${id} + break + fi + done + echo $res + if [[ -z $res ]]; then + return 1 + fi + return 0 +} + +function getuid() { + local res id + id=$1 + res=${idmap[$id]} + if [[ -z $res ]]; then + return 1 + fi + echo $res + return 0 +} + +function getorgenid() { + local res uid + uid=$1 + res=$(getid $uid) + if [[ -z $res ]]; then + res=$nextid + idmap[$nextid]=$uid + nextid=$((nextid + 1)) + needsave=1 + fi + return $res +} + +function loadids() { + local LINE n uid id max count + count=0 + if [[ ! -e $idfile ]]; then + error "No ID file found (looking here: $idfile)" + return 1 + fi + max=0 + while read LINE; do + uid=${LINE%:*} + id=${LINE#*:} + idmap[$id]=$uid + if [[ -z $uid || -z $id ]]; then + error "invalid idmapping line: '$LINE'" + return 1 + fi + [[ $id -gt $max ]] && max=$id + count=$((count + 1)) + done < "$idfile" + nextid=$((max + 1)) +dblog "got $count IDs from $idfile" + return 0 +} + +function saveids() { + local id + cp /dev/null $idfile + for id in ${!idmap[@]}; do + dblog "save to $idfile: uid ${idmap[$id]} id $id sum ${tasksum[$id]}" >> $idfile + echo "${idmap[$id]}:$id" >> $idfile + done +} + +function dumpids() { + local id + for id in ${!idmap[@]}; do + echo "$id --> ${idmap[$id]}" + done +} + +function loadtasks() { + local f ess x thislev par parid show thissum thisdesc + maxid=-1 + maxindent=-1 + maxtaskwidth=-1 + ntasks=0 + dblog "Loading tasks..." + for f in $dir/*.vcf; do + dblog "--> loading from $f" + loadtask $f || return 1 + ntasks=$((ntasks + 1)) + done + numwid=${#maxid} + + dblog "Calculating max indent level" + # figure out max indent level + for x in ${!taskuid[@]}; do + show=1 + par=${taskparent[$x]} + if [[ ! -z $par ]]; then + parid=$(getid $par) + if [[ ${taskfolded[$parid]} -eq 1 ]]; then + show=0 + fi + fi + dblog " uid $x id [${taskid[$x]}] parent [$par] parent [$parid] show [$show]" + if [[ $show -eq 1 ]]; then + dblog " ->showing $x [${tasksum[$x]}]" + thislev=$(getindentlevel $x) + dblog " ->lv: $thislev" + [[ $thislev -gt $maxindent ]] && maxindent=$thislev + thissum=${tasksum[$x]} + thisdesc=${taskdesc[$x]} + [[ ${#thissum} -gt $maxtaskwidth ]] && maxtaskwidth=${#thissum} + [[ ${#thisdesc} -gt $maxtaskwidth ]] && maxtaskwidth=${#thisdesc} + dblog " ->sum: $thissum" + fi + done + + [[ $ntasks -eq 1 ]] && ess="" || ess="s" + dblog "Finished loading $ntasks task$ess." + return 0 +} + +function getindentlevel() { ## $0 id + local id thisid parentuid parentid level + id=$1 + thisid=$id + #dblog "gil() id $id thisid $thisid" + + level=0 + + while [ ! -z $parentuid ] ; do + parentuid=${taskparent[$thisid]} + if [[ ! -z $parentuid ]]; then + thisid=$(getid $parentuid) + dblog " gil() parent uid: [$parentuid] id: [$thisid]" + level=$((level + 1)) + fi + done + + echo $level +} + +function dblog() { + [[ $DEBUG -eq 1 ]] && echo "$(date) $*" >/dev/stderr +} + +function action() { + echo -e "$BOLD$GREEN* $PLAIN$GREEN$*$PLAIN" +} + +function error() { + echo -e "$BOLD${RED}ERROR: $PLAIN$RED$*$PLAIN" >/dev/stderr +} + +function info() { + echo -e "$BOLD${CYAN}>> $PLAIN$CYAN$*$PLAIN" +} + +function confirm() { + local yn + echo -en "$BOLD${MAGENTA}CONFIRM: $PLAIN$MAGENTA$* (y/N)? $PLAIN" + read yn + if [[ $yn == "y" ]]; then + return 0 + fi + return 1 +} + +function loadtask() { + local uid sum checked folded desc file id parent res i cats + + file="$1" + res=$(cat $file | awk -F: 'BEGIN { checked=0; folded=0; } /^UID:/ { printf("uid©%s©",$2); } /^SUMMARY:/ { sub("SUMMARY:",""); printf("sum©%s©",$0); } /^CATEGORIES:/ { sub("^CATEGORIES:",""); printf("cats©%s©",$0); } /^DESCRIPTION:/ { sub("DESCRIPTION:",""); printf("desc©%s©",$0); } /^RELATED-TO/ { sub("^RELATED-TO.*:",""); printf("parent©%s©",$0); } /^X-OC-HIDESUBTASKS:1/ { folded=1; } /^STATUS:COMPLETED/ { checked=1; } END { printf("checked©%d©folded©%d\n",checked,folded); }') + + IFS='©' + read -ra tok <<< "$res" + parent="" + i=0 +#dblog "res: '$res'" +#for x in ${!tok[@]}; do +#dblog "forloop tok $x is '${tok[$x]}'" +#done +# while [[ ! -z ${tok[$i]} ]]; do +#dblog "tok $i is '${tok[$i]}'" +# i=$((i + 1)) +# done + while [[ ! -z ${tok[$i]} ]]; do +#dblog "process token '${tok[$i]}'" + if [[ ${tok[$i]} == "uid" ]]; then + uid=${tok[$((i + 1))]} +#nexti=$((i + 1)) +#dblog "i=$i tok[i]=${tok[$i]} i+1=$((i + 1)) tok[i+1]=${tok[$((i + 1))]} uid $uid id $id" +#dblog "i=$i tok[i]=${tok[$i]} i+1=$((i + 1)) tok[nexti]=${tok[$nexti]} uid $uid id $id" + getorgenid $uid + id=$? +#dblog "i=$i tok[i]=${tok[$i]} uid $uid id $id" + elif [[ ${tok[$i]} == "sum" ]]; then + sum="${tok[$((i + 1))]}" + elif [[ ${tok[$i]} == "cats" ]]; then + cats="${tok[$((i + 1))]}" + elif [[ ${tok[$i]} == "desc" ]]; then + desc="${tok[$((i + 1))]}" + elif [[ ${tok[$i]} == "parent" ]]; then + parent="${tok[$((i + 1))]}" + elif [[ ${tok[$i]} == "checked" ]]; then + checked="${tok[$((i + 1))]}" + elif [[ ${tok[$i]} == "folded" ]]; then + folded="${tok[$((i + 1))]}" + fi + i=$((i + 2)) + done + IFS=' ' + + taskuid[$id]=$uid + taskid[$id]=$id + tasksum[$id]=$sum + taskcats[$id]=$cats + taskdesc[$id]=$desc + taskchecked[$id]=$checked + taskfolded[$id]=$folded + taskparent[$id]=$parent + + [[ $id -gt $maxid ]] && maxid=$id + [[ ${#sum} -gt $taskwid ]] && taskwid=${#sum} + [[ ${#desc} -gt $taskwid ]] && taskwid=${#desc} + if [[ -z $uid ]]; then + error "task has no uid:" + echo "$res" + return 1 + fi + return 0 +} + +function marknotdone() { + local id uid rv file sedrv + local children childuid ischild noun + uid=$1 + id=$(getid $uid) + [[ $# -gt 1 ]] && ischild=1 || ischild=0 + [[ $ischild -eq 1 ]] && noun=subtask || noun=task + + + # already not done? + if [[ ${taskchecked[$id]} -eq 0 ]]; then + error "$noun #${id} is already unfinished" + return 1 + fi + file=$dir/$uid.vcf + sed -i '/^COMPLETED:/d;/^STATUS:COMPLETED/d;/PERCENT-COMPLETE:100/d' $file + sedrv=$((sedrv + $?)) + set_lastmodified $uid + sedrv=$((sedrv + $?)) + if [[ $sedrv -eq 0 ]]; then + action "Marked $noun #${id} as completed." + processed="$processed ${uid} " + loadtask $file + rv=0 + children=$(getchildren $uid) + for childuid in ${children}; do + marknotdone $childuid noprint + rv=$((rv + $?)) + done + else + failed="$failed ${uid} " + error "failed to mark $noun #${id} as unfinished" + rv=1 + fi + + return $rv +} + +function delq_clear() { + deluids="" +} + +function delq_add() { + local x + if [[ ! $deluids == *\ $1\ * ]]; then + deluids="$deluids $1" + for x in $(getchildren $1); do + delq_add $x + done + fi +} + +function delq_process() { + local uidlist uid rv yn file count ess wantshow + local od + rv=0 + + # Remove duplicates + deluids=$(echo $deluids | tr ' ' '\n' | sort -u | tr '\n' ' ') + + info "The following tasks will be removed:" + needtitle=0 + for uid in $deluids; do + wantshow=0 + id=$(getid $uid) + + # don't show if it's a subtask of one already in the list + if [[ -z ${taskparent[$id]} ]]; then + wantshow=1 + elif [[ $deluids == *${taskparent[$id]}\ * ]]; then + wantshow=0 + else + wantshow=1 + fi + + if [[ $wantshow -eq 1 ]]; then + showit $uid | sed -e 's/^/ /' + fi + done + confirm "Really remove these tasks" + if [[ $? -eq 0 ]]; then + count=0 + for uid in $deluids; do + file=$dir/$uid.vcf + rm -f $file + + id=$(getid $uid) + unset idmap[$id] + + count=$((count + 1)) + done + saveids + [[ $count -eq 1 ]] && ess="" || ess="s" + action "$count task$ess removed." + else + action "Aborted." + rv=1 + fi + + return $rv +} + +function set_lastmodified() { + local uid file now + uid=$1 + file=$dir/$uid.vcf + now=$(date -u +'%Y%m%dT%H%M%SZ') + sed -i "s/^LAST-MODIFIED:.*/LAST-MODIFIED:$now/" $file + return $? +} + +function move_left() { # move_left uid + local uid rv parent parentid parent2 sedrv + local id + + uid=$1 + id=$(getid $uid) + rv=0 + parent=${taskparent[$id]} + if [[ -z $parent ]]; then + error "Can't shift task #${id} any further left." + exit 1 + fi + parentid=$(getid ${taskparent[$id]}) + + parent2=${taskparent[$parentid]} + taskparent[$id]="$parent2" + + file=$dir/$uid.vcf + + sed -i "s/^RELATED-TO.*/RELATED-TO;RELTYPE=PARENT:${taskparent[$id]}/" $file + sedrv=$? + set_lastmodified $uid + sedrv=$((sedrv + $?)) + if [[ $sedrv -eq 0 ]]; then + action "Shifted task #${id} upwards/left." + loadtask $file + + showit ${taskparent[$id]} $uid + + rv=0 + else + error "Failed to shift task #${id} left." + rv=1 + fi + + return $rv +} + +function move_right() { # move_right uid new_parent + local uid rv newparent sedrv + local id newparentid str toadd + + uid=$1 + id=$(getid $uid) + rv=0 + newparent=$2 + newparentid=$(getid $newparent) + rv=0 + + taskparent[$id]="$newparent" + file=$dir/$uid.vcf + + if grep -q ^RELATED-TO $file; then + sed -i "s/^RELATED-TO.*/RELATED-TO;RELTYPE=PARENT:${taskparent[$id]}/" $file + sedrv=$? + else + str="END:VTODO" + toadd="RELATED-TO;RELTYPE=PARENT:${taskparent[$id]}" + sed -i "/$str/i $toadd\n" $file + sedrv=$? + fi + set_lastmodified $uid + sedrv=$((sedrv + $?)) + if [[ $sedrv -eq 0 ]]; then + action "Shifted task #${id} underneath #${newparentid} ('${tasksum[$newparentid]}')." + loadtask $file + + showit ${taskparent[$id]} $uid + + rv=0 + else + error "Failed to shift task #${id} under #${newparentid}." + rv=1 + fi + + return $rv +} + +function setnote() { # setnote uid new note goes here + local uid newnote sedrv rv file str + local id + + uid=$1 + id=$(getid $uid) + rv=0 + shift + newnote="$*" + + file=$dir/$uid.vcf + + if grep -q ^DESCRIPTION: $file; then + sed -i "s/^DESCRIPTION:.*/DESCRIPTION:$newnote/" $file + sedrv=$? + else + str="END:VTODO" + toadd="DESCRIPTION:$newnote" + sed -i "/$str/i $toadd\n" $file + sedrv=$? + fi + set_lastmodified $uid + sedrv=$((sedrv + $?)) + if [[ $sedrv -eq 0 ]]; then + if [[ -z $newnote ]]; then + action "Removed note from task #${id}." + else + action "Set note of task #${id} to '$newnote'." + fi + loadtask $file + rv=0 + else + error "Failed to set note of task #${id}." + rv=1 + fi + + return $rv +} + + +function modtag() { # setnote uid add|del new tag goes here + local uid arg sedrv rv file str + local id action x catarr newcat + + uid=$1 + id=$(getid $uid) + rv=0 + shift + action=$1 + shift + arg="$*" + + file=$dir/$uid.vcf + + if [[ -z $arg ]]; then + if [[ $action == "del" ]]; then + sed -i "/^CATEGORIES:/d" $file + sedrv=$? + else + error "No tag specified to add." + return 1 + fi + else + IFS="," + catarr=( ${taskcats[$id]} ) + IFS=" " + for x in ${!catarr[@]} ; do + if [[ $action == "add" || ${catarr[$x]} != $arg ]]; then + [[ -z $newcat ]] && newcat="${catarr[$x]}" || newcat="$newcat,${catarr[$x]}" + fi + done + if [[ $action == "add" ]]; then + [[ -z $newcat ]] && newcat="${arg}" || newcat="$newcat,$arg" + + fi + + if grep -q ^CATEGORIES: $file; then + sed -i "s/^CATEGORIES:.*/CATEGORIES:${newcat}/" $file + sedrv=$? + else + str="END:VTODO" + toadd="CATEGORIES:${newcat}" + sed -i "/$str/i $toadd\n" $file + sedrv=$? + fi + fi + set_lastmodified $uid + sedrv=$((sedrv + $?)) + if [[ $sedrv -eq 0 ]]; then + if [[ $action == "del" ]]; then + if [[ -z $arg ]]; then + action "Removed all tags from task #${id}." + else + action "Removed tag '$arg' from task #${id}." + fi + else + action "Added tag '$arg' to task #${id}." + fi + loadtask $file + rv=0 + else + error "Failed to set/remove tag on task #${id}." + rv=1 + fi + + return $rv +} + +function rename() { # rename uid new name goes here + local uid newname sedrv rv file + local id + + uid=$1 + id=$(getid $uid) + rv=0 + shift + newname="$*" + + file=$dir/$uid.vcf + + sed -i "s/^SUMMARY:.*/SUMMARY:$newname/" $file + sedrv=$? + set_lastmodified $uid + sedrv=$((sedrv + $?)) + if [[ $sedrv -eq 0 ]]; then + action "Renamed task #${id} to '$newname'." + loadtask $file + rv=0 + else + error "failed to rename task #${id}." + rv=1 + fi + + return $rv +} + +function toggle() { + local uid id rv children + uid=$1 + id=$(getid $uid) + + # already done this one? + if [[ $processed == *\ $uid\ * || $failed == *\ $uid\ * ]]; then + return 1 + fi + + # not a parent? + children=$(getchildren $uid) + if [[ -z ${children} ]]; then + error "Can't fold/unfold task #${id} with no children." + return 1 + fi + + if [[ ${taskfolded[$id]} -eq 1 ]]; then + unfold $uid + rv=$? + else + fold $uid + rv=$? + fi + + return $rv +} + +function fold() { + local uid id sedrv rv file str + local children + uid=$1 + id=$(getid $uid) + + # not a parent? + children=$(getchildren $uid) + if [[ -z ${children} ]]; then + error "Can't fold task #${id} with no children." + return 1 + fi + # already folded? + if [[ ${taskfolded[$id]} -eq 1 ]]; then + error "Task #${id} is already folded." + return 1 + fi + + file=$dir/$uid.vcf + str="END:VTODO" + if grep -q ^X-OC-HIDESUBTASKS: $file ; then + sed -i "s/X-OC-HIDESUBTASKS:.*/X-OC-HIDESUBTASKS:1/" $file + sedrv=$? + else + sed -i "/$str/i X-OC-HIDESUBTASKS:1" $file + sedrv=$? + fi + set_lastmodified $uid + sedrv=$((sedrv + $?)) + if [[ $sedrv -eq 0 ]]; then + action "Folded task #${id}." + processed="$processed ${uid} " + loadtask $file + rv=0 + else + failed="$failed ${uid} " + error "failed to fold task #${id}" + rv=1 + fi + + return $rv +} + +function unfold() { + local uid id sedrv rv file str + local children + uid=$1 + id=$(getid $uid) + + # not a parent? + children=$(getchildren $uid) + if [[ -z ${children} ]]; then + error "Can't unfold task #${id} with no children." + return 1 + fi + + # not folded? + if [[ ${taskfolded[$id]} -ne 1 ]]; then + error "Task #${id} is not folded." + return 1 + fi + + file=$dir/$uid.vcf + str="END:VTODO" + if grep -q ^X-OC-HIDESUBTASKS: $file ; then + sed -i "s/X-OC-HIDESUBTASKS:.*/X-OC-HIDESUBTASKS:0/" $file + sedrv=$? + else + sed -i "/$str/i X-OC-HIDESUBTASKS:0" $file + sedrv=$? + fi + set_lastmodified $uid + sedrv=$((sedrv + $?)) + if [[ $sedrv -eq 0 ]]; then + action "Unfolded task #${id}." + processed="$processed ${uid} " + loadtask $file + rv=0 + else + failed="$failed ${uid} " + error "failed to unfold task #${id}" + rv=1 + fi + + return $rv +} + +function markdone() { + local uid sedrv rv file toadd1 toadd2 toadd3 str now + local children childuid ischild noun id + uid=$1 + id=$(getid $uid) + [[ $# -gt 1 ]] && ischild=1 || ischild=0 + [[ $ischild -eq 1 ]] && noun=subtask || noun=task + # already complete? + if [[ ${taskchecked[$id]} -eq 1 ]]; then + error "$noun #${id} is already completed" + return 1 + fi + str="END:VTODO" + now=$(date -u +'%Y%m%dT%H%M%SZ') + toadd1="STATUS:COMPLETED" + toadd2="PERCENT-COMPLETE:100" + toadd3="COMPLETED:$now" + + file=$dir/$uid.vcf + sed -i "/$str/i $toadd1\n$toadd2\n$toadd3" $file + sedrv=$? + set_lastmodified $uid + sedrv=$((sedrv + $?)) + if [[ $sedrv -eq 0 ]]; then + action "Marked $noun #${id} as completed." + processed="$processed ${uid} " + loadtask $file + rv=0 + children=$(getchildren $uid) + for childuid in ${children}; do + markdone $childuid noprint + rv=$((rv + $?)) + done + else + failed="$failed ${uid} " + error "failed to mark $noun #${id} as completed" + rv=1 + fi + + return $rv +} + +function viewtask() { + local uid id file + uid=$1 + id=$(getid $uid) + file=$dir/$uid.vcf + + action "Viewing task #$id ($file):" + cat $file | sed -e 's/^/ /' + return 0 +} + +function randomuid() { + local dupe uid + dupe=1 + while [[ $dupe -eq 1 ]]; do + uid=$(( $RANDOM % 4 + 1)) + uid="$uid$(( $RANDOM % 5 + 1))" + while [[ ${#uid} -lt 19 ]]; do + uid="$uid$(( $RANDOM % 9 + 1))" + done + dupe=0 + for x in ${!taskuid[@]}; do + if [[ $x == $uid ]]; then + dupe=1 + break + fi + done + done + echo $uid +} + +function addtask() { + local uid parent parentid parentuid file thisid + if [[ $1 == "-p" ]]; then + parentuid=$2 + parentid=$(getid $parentuid) + shift 2 + else + parentuid="" + fi + uid=$(randomuid) + thisid=$nextid + idmap[$thisid]=$uid + taskid[$thisid]=$thisid + taskuid[$thisid]=$uid + tasksum[$thisid]="$*" + taskdesc[$thisid]="" + taskchecked[$thisid]=0 + taskfolded[$thisid]=0 + taskparent[$thisid]=$parentuid + file=$dir/$uid.vcf + now=$(date -u +'%Y%m%dT%H%M%SZ') + cat >$file <>$file + fi + cat >>$file <local task id mapping file? [default: $thisdir/idmappings.txt ] +# - url for your remote caldav +# - username for your remote caldav +# - password for your remote caldav +# - vdirsyncer dir [default ${HOME}/.config/vdirsyncer] +# - vdirsyncer status dir [default ${vdirsyncer_dir/status} +# - vdirsyncer config file [default ${vdirsyncer_dir}/config] +# - vdirsyncer calendar dir [default ${vdirsyncer_dir/calendar} + +###### - vdirsyncer name for your local calender [default cal_local] +###### - vdirsyncer name for your remote calender [default cal_remote] + + +VDIRSYNCER=/usr/local/bin/vdirsyncer +VDS_LOCAL=cal_local +VDS_REMOTE=cal_remote +basedir=/Users/rpearce/code/task_cli +dir=$basedir/docs +idfile=$basedir/idmappings.txt +nextid=1 +indent=0 +indentamt=4 +needsave=0 +mode=list +modes_that_support_all="" + +# for pager +printed=0 +rows=$(tput lines) + +addcmd "list" "list [id1] .. [idX]" "List [just the specified] tasks" "list|ls|show" +addcmd "fold" "fold " "Fold a parent task (hide its children)" "fold|f|zc" SUPPORTS_ALL +addcmd "unfold" "unfold " "Unfold a parent task (show its children)" "unfold|u|zo" SUPPORTS_ALL +addcmd "toggle" "toggle " "Fold/Unfold a parent task" "toggle|z" SUPPORTS_ALL +addcmd "done" "done " "Complete a task" "done|x|complete" SUPPORTS_ALL +addcmd "notdone" "notdone " "Uncomplete a task" "notdone|o|incomplete|uncomplete|clear" SUPPORTS_ALL +addcmd "add" "add [parent] " "Add a new task [as subtask of parent]" "a|add|new|create" +addcmd "del" "del [id1] .. [idX]" "Delete given task(s)" "del|rm|delete" +addcmd "cleanup" "cleanup" "Delete all completed tasks" "cleanup|clean|flush|dc" +addcmd "rename" "rename " "Rename given task" "rename" +addcmd "left" "left " "Decrease indent of given task" "left|h|out|up" +addcmd "right" "right " "Move task below the given parent" "right|l|mv|in" +addcmd "note" "note " "Change notes for given task" "note|desc|description|comment" +addcmd "tag" "tag " "Add a tag to the given task" "tag|t" +addcmd "untag" "untag " "Remove a tag from the given task" "untag|ut" +addcmd "sync" "sync" "Sync tasks using vdirsyncer" "sync" +addcmd "view" "view " "Show detailed info for given task" "v|view|info|vcal" + +DEBUG=0 +TESTMODE=0 + + +ARGS="hdt" +while getopts "$ARGS" i; do + case "$i" in + h) + usage; + exit 1; + ;; + d) + DEBUG=1 + ;; + t) + DEBUG=1 + TESTMODE=1 + ;; + *) + error "invalid argument: $i"; + usage; + exit 1 + ;; + esac +done +shift $((OPTIND - 1)) + + + +mode="" +for x in $valid_modes; do + thisone="words_$x" + tomatch=${!thisone} + if [[ $1 =~ ^(${tomatch})$ ]]; then + mode=$x + shift + fi +done + +if [[ -z $mode ]]; then + mode=list +fi + +# Commands that don't need tasks loaded +if [[ $mode == "sync" ]]; then + res=$(${VDIRSYNCER} sync 2>&1) + rv=$? + + if [[ $rv -eq 0 ]]; then + upcount=$(echo "$res" | grep -v ^Sync | grep -c ${VDS_REMOTE}) + downcount=$(echo "$res" | grep -v ^Sync | grep -c ${VDS_LOCAL}) + + [[ $upcount -eq 1 ]] && upess="" || upess="s" + [[ $downcount -eq 1 ]] && downess="" || downess="s" + + if [[ $upcount -eq 0 && $downcount -eq 0 ]]; then + action "Sync complete - no changes." + elif [[ $upcount -eq 0 ]]; then + action "Sync complete - $downcount change$downess pulled." + elif [[ $downcount -eq 0 ]]; then + action "Sync complete - $upcount change$upess pushed." + else + action "Sync complete - $upcount change$upess pushed, $downcount change$downess pulled." + fi + else + error "sync failed. Output:" + echo "$res" | sed -e 's/^/ /' + fi + exit $rv +fi + +loadids || exit 1 +loadtasks || exit 1 + +[[ $TESTMODE -eq 1 ]] && exit 1 + +[[ $needsave -eq 1 ]] && saveids + +# single-task commands +if [[ $mode == "add" ]]; then + if [[ $1 =~ ^[0-9]+$ ]]; then + parentid=$1 + parentuid=$(getuid_witherror $parentid "parent task") + shift 1 + else + parentid="" + parentuid="" + fi + newtasksum="$*" + + if [[ -z $parentuid ]]; then + addtask "$newtasksum" + else + addtask -p $parentuid "$newtasksum" + fi +elif [[ $mode == "rename" ]]; then + uid=$(getuid_witherror $1) + shift + rename $uid "$*" +elif [[ $mode == "note" ]]; then + uid=$(getuid_witherror $1) + shift + setnote $uid "$*" +elif [[ $mode == "tag" ]]; then + uid=$(getuid_witherror $1) + shift + modtag $uid add "$*" +elif [[ $mode == "untag" ]]; then + uid=$(getuid_witherror $1) + shift + modtag $uid del "$*" +elif [[ $mode == "left" ]]; then + uid=$(getuid_witherror $1) + shift + move_left $uid +elif [[ $mode == "right" ]]; then + uid=$(getuid_witherror $1) + puid=$(getuid_witherror $2 "parent task") + shift 2 + move_right $uid $puid +elif [[ $mode == "view" ]]; then + uid=$(getuid_witherror $1) + viewtask $uid +elif [[ $mode == "cleanup" ]]; then + action "Deleting all completed tasks." + for id in ${!taskuid[@]}; do + uid=$(getuid $id) + [[ ${taskchecked[$id]} -eq 1 ]] && delq_add $uid + done + + delq_process + # show results + if [[ ! -z $processed ]]; then + for uid in ${processed}; do + showit $uid + done + fi +else + # multi-task commands + + filter=$* + + uids="" + if [[ -z $filter ]]; then + for id in ${!taskid[@]}; do + [[ -z ${taskparent[$id]} ]] && uids="$uids ${taskuid[$id]}" + done + elif [[ $filter == "all" ]]; then + na=0 + if [[ ! $mode =~ $modes_that_support_all ]]; then + error "Command '$mode' doesn't support 'all'" + exit 1 + fi + kids="" + for id in ${!taskid[@]}; do + match=0 + uid=$(getuid $id) + children=$(getchildren $uid) + [[ -z $children ]] && haschildren=0 || haschildren=1 + if [[ $mode == "fold" && $haschildren -eq 1 && ${taskfolded[$id]} -ne 1 ]]; then + match=1 + kids="--nochildren" + elif [[ $mode == "unfold" && ${taskfolded[$id]} -eq 1 ]]; then + match=1 + kids="--nochildren" + elif [[ $mode == "done" && ${taskchecked[$id]} -eq 0 ]]; then + match=1 + elif [[ $mode == "notdone" && ${taskchecked[$id]} -eq 1 ]]; then + match=1 + fi + + if [[ $match -eq 1 ]]; then + uids="$uids ${taskuid[$id]}" + fi + done + info "About to run '$mode' on the following tasks:" + needtitle=0 + for uid in $uids; do + wantshow=0 + id=$(getid $uid) + + # don't show if it's a subtask of one already in the list + if [[ -z ${taskparent[$id]} ]]; then + wantshow=1 + elif [[ $uids == *${taskparent[$id]}\ * ]]; then + wantshow=0 + else + wantshow=1 + fi + + if [[ $wantshow -eq 1 ]]; then + showit $kids $uid | sed -e 's/^/ /' + fi + done + confirm "Really proceed" + if [[ $? -ne 0 ]]; then + action "Aborted." + exit 1 + fi + elif [[ $filter =~ ^[0-9\ ]+$ ]]; then + # list of task IDs + for wantid in $filter; do + uids="$uids ${taskuid[$wantid]}" + done + else + # text to match + a=$( echo ${filter} | tr 'A-Z' 'a-z') + for id in ${!taskid[@]}; do + b=$( echo ${tasksum[$id]} | tr 'A-Z' 'a-z') + if [[ ${b} == *"${a}"* ]]; then + uids="$uids ${taskuid[$id]}" + fi + done + fi + + needtitle=1 + + if [[ -z $uids ]]; then + error "no matching tasks found." + exit 1 + else + processed="" + failed="" + for uid in ${uids}; do + if [[ $mode == "list" ]]; then + showit $uid + elif [[ $mode == "done" ]]; then + markdone $uid + elif [[ $mode == "notdone" ]]; then + marknotdone $uid + elif [[ $mode == "fold" ]]; then + fold $uid + elif [[ $mode == "unfold" ]]; then + unfold $uid + elif [[ $mode == "toggle" ]]; then + toggle $uid + elif [[ $mode == "del" ]]; then + delq_add $uid + fi + done + + # do queued actions + if [[ $mode == "del" ]]; then + delq_process + fi + # show results + if [[ ! -z $processed ]]; then + for uid in ${processed}; do + showit $uid + done + fi + fi +fi diff --git a/vcftocsv.awk b/vcftocsv.awk new file mode 100644 index 0000000..1fa0843 --- /dev/null +++ b/vcftocsv.awk @@ -0,0 +1,30 @@ +BEGIN { + uid="" + summary="" + related="" + + FS=":" + printf("%s,%s,%s\n","uid","summary","related"); +} + +($1 == "BEGIN"){ + uid="" + summary="" + related="" +} + +($1 == "UID"){ + uid=$2 +} +($1 == "SUMMARY"){ + summary=$2 +} +($1 == "RELATED-TO"){ + related=$2 +} +($1 == "END" && uid != ""){ + printf("%s,%s,%s\n",uid,summary,related); + uid="" + summary="" + related="" +}