task_cli/t.sh

2233 lines
58 KiB
Bash
Raw Permalink Normal View History

2022-06-13 21:04:59 +10:00
#!/opt/homebrew/bin/bash
2022-03-23 19:06:56 +11:00
#set -x
2021-06-03 08:56:54 +10:00
trap "exit 1" TERM
export MYPID=$$
2022-06-13 21:04:59 +10:00
if [[ ${BASH_VERSION:0:1} == 5 ]]; then
b5=1
declare -A idmap
else
b5=0
fi
2022-03-23 19:06:56 +11:00
. ${HOME}/code/bashtools/bashtools.sh
if [[ -z $HAVE_BASHTOOLS ]]; then
2022-03-23 19:06:56 +11:00
echo "ERROR: bashtools not installed download from https://git.nethack.net/rob/bashtools" >/dev/stderr
exit 1
fi
INFORMCOL="$GREEN"
INFORMCOLB="$GREEN$BOLD"
2021-06-03 08:56:54 +10:00
brack="$CYAN"
brackfold="$CYAN"
HILITE="\033[43;1m"
GREYBG="\033[48;2;30;30;30m"
TOPTITLE="\033[44;1m"
LEFTTITLE="\033[31;1m"
FOLDBG="$BOLDD"
2022-06-13 21:04:59 +10:00
function genidx() {
local idxname=$1 x
shift
local -a vals=("$@")
unset ${idxname}
declare -g -A ${idxname}
for x in "${!vals[@]}"; do
#echo "setting ${idxname}[${vals[$x]}] to $x" >/dev/stderr
eval ${idxname}["${vals[$x]}"]=$x
done
}
2021-06-03 08:56:54 +10:00
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"
2021-06-26 09:29:29 +10:00
echo "usage: $0 COMMAND [OPTIONS] [commandopts]"
echo
2021-11-21 10:54:25 +11:00
echo " -c Select calendar to use (use '$0 showcals' to list)"
echo " -f Assume 'yes' to all questions."
echo " -l xx Specify name of local vdirsyncer storage name (default: $DEFAULT_VDS_LOCAL)"
2022-06-13 21:04:59 +10:00
echo " -m Maintenance mode - find and fix bad idmapping entries, then exit."
echo " -p Enable profiling"
echo " -r xx Specify name of remote vdirsyncer storage name (default: $DEFAULT_VDS_REMOTE)"
echo " -s Auto-sync with server when complete."
2021-11-08 18:20:37 +11:00
echo " -S Sort tasks and subtasks alphabetically"
2021-06-03 08:56:54 +10:00
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
2022-06-13 21:04:59 +10:00
if [[ $b5 ]]; then
if [[ "${i_idmap[$1]}" ]]; then
echo "${i_idmap[$1]}"
return 0
2021-06-03 08:56:54 +10:00
fi
2022-06-13 21:04:59 +10:00
return 1
else
for id in ${!idmap[@]}; do
if [[ ${idmap[$id]} == $1 ]]; then
echo "$id"
return 0
fi
done
fi
return 1
2021-06-03 08:56:54 +10:00
}
function getuid() {
local res id
id=$1
res=${idmap[$id]}
if [[ -z $res ]]; then
return 1
fi
echo $res
return 0
}
function updatenextid() {
local nextid2=1
local db=0
nextid2=1
if [[ $b5 -eq 1 ]]; then
while [[ " ${i_idmap[@]}" == *\ $nextid2* ]]; do
nextid2=$((nextid2 + 1))
done
else
while [[ " ${taskid[@]}" == *\ $nextid2* ]]; do
nextid2=$((nextid2 + 1))
done
fi
nextid=$nextid2
}
function addidmap() { #1=id 2=uid
local id="$1" uid="$2"
idmap[$id]=$uid
[[ $b5 -eq 1 ]] && eval i_idmap["$uid"]=$id
}
2021-06-03 08:56:54 +10:00
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
profile "start"
2022-06-13 21:04:59 +10:00
# check for duplicate id mappings
sort -o $idfile -t: -k1,1 --stable --unique "$idfile"
2022-06-13 21:04:59 +10:00
profile "finished removing dupes"
2021-06-03 08:56:54 +10:00
max=0
while read LINE; do
uid=${LINE%:*}
id=${LINE#*:}
#uid=$(echo "$LINE" | sed 's/:.*$//g')
#id=$(echo "$LINE" | sed 's/^.*://g')
addidmap $id $uid
2021-06-03 08:56:54 +10:00
if [[ -z $uid || -z $id ]]; then
error "invalid idmapping line: '$LINE'"
profile "end"
2021-06-03 08:56:54 +10:00
return 1
fi
[[ $id -gt $max ]] && max=$id
count=$((count + 1))
done < "$idfile"
updatenextid
profile "end"
2021-06-03 08:56:54 +10:00
dblog "got $count IDs from $idfile"
2022-06-13 21:04:59 +10:00
2021-06-03 08:56:54 +10:00
return 0
}
function saveids() {
local id verbose=0
local ess nids=0
[[ $1 == "-v" ]] && verbose=1
if [[ ${#idmap[@]} -gt 0 ]]; then
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"
nids=$((nids + 1))
done
[[ $nids -eq 1 ]] && ess="" || ess="s"
[[ $verbose -eq 1 ]] && inform "Saved $nids ID mapping$ess to $idfile."
else
[[ $verbose -eq 1 ]] && warn "No ID mappings found to save"
return 1
fi
return 0
2021-06-03 08:56:54 +10:00
}
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
local verbose=0
2022-06-13 21:04:59 +10:00
profile "start"
2021-06-03 08:56:54 +10:00
maxid=-1
maxindent=-1
maxtaskwidth=-1
ntasks=0
while [[ $# -ge 1 ]]; do
[[ $1 == "-v" ]] && verbose=1 && shift 1
done
2021-06-03 08:56:54 +10:00
dblog "Loading tasks..."
for f in "$dir"/*.vcf; do
2021-06-03 08:56:54 +10:00
dblog "--> loading from $f"
loadtask "$f" || return 1
2021-06-03 08:56:54 +10:00
ntasks=$((ntasks + 1))
done
numwid=${#maxid}
profile "finished loadtask calls"
2021-06-03 08:56:54 +10:00
updatenextid
2022-06-13 21:04:59 +10:00
2021-06-03 08:56:54 +10:00
dblog "Calculating max indent level"
2022-06-13 21:04:59 +10:00
# figure out max indent level and next id
2021-06-03 08:56:54 +10:00
for x in ${!taskuid[@]}; do
show=1
par=${taskparent[$x]}
if [[ -n $par ]]; then
2021-06-03 08:56:54 +10:00
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
profile "got max indent"
2021-06-03 08:56:54 +10:00
[[ $ntasks -eq 1 ]] && ess="" || ess="s"
[[ $verbose -eq 1 ]] && inform "Finished loading $ntasks task$ess."
2022-06-13 21:04:59 +10:00
2021-06-03 08:56:54 +10:00
dblog "Finished loading $ntasks task$ess."
profile "end"
2021-06-03 08:56:54 +10:00
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 " parent uid: [$parentuid] id: [$thisid]"
2021-06-03 08:56:54 +10:00
level=$((level + 1))
fi
done
echo $level
}
function dblog() {
[[ $DEBUG -eq 1 ]] && echo "$(date) ${FUNCNAME[1]}() $*" >/dev/stderr
2021-06-03 08:56:54 +10:00
}
function confirm() {
local yn
2021-09-05 08:06:52 +10:00
if [[ $AUTOYES -eq 1 ]]; then
return 0
fi
2021-06-03 08:56:54 +10:00
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
local blockreason
local didalloc=0
#local re
#if iscached "$1"; then
#fi
2021-06-03 08:56:54 +10:00
dblog "open $1"
2021-06-03 08:56:54 +10:00
file="$1"
#re="^(CATEGORIES:|DESCRIPTION:|REQUEST-STATUS:4.1;|RELATED-TO|X-OC-HIDESUBTASKS:1|STATUS:)"
res=$(cat "$file" | mawk -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); } /^REQUEST-STATUS:4.1;/ { sub("REQUEST-STATUS:4.1;",""); printf("breason©%s©",$0);} /^RELATED-TO/ { sub("^RELATED-TO.*:",""); printf("parent©%s©",$0); } /^X-OC-HIDESUBTASKS:1/ { folded=1; } /^STATUS:/ { stat=substr($0,8); if (stat == "COMPLETED") { checked=2; } else if (stat == "NEEDS-inform") { checked=3; } else if (stat == "IN-PROCESS") { checked = 1 } } END { printf("checked©%d©folded©%d\n",checked,folded); }' )
2021-06-03 08:56:54 +10:00
toadd2="REQUEST-STATUS:4.1;$reason"
2021-06-03 08:56:54 +10:00
IFS='©'
read -ra tok <<< "$res"
parent=""
i=0
while [[ ! -z ${tok[$i]} ]]; do
dblog "process token '${tok[$i]}'"
2021-06-03 08:56:54 +10:00
if [[ ${tok[$i]} == "uid" ]]; then
uid=${tok[$((i + 1))]}
id=$(getid $uid)
if [[ -z $id ]]; then
id=$nextid
addidmap $nextid $uid
didalloc=1
needsave=1
fi
2021-06-03 08:56:54 +10:00
elif [[ ${tok[$i]} == "sum" ]]; then
sum="${tok[$((i + 1))]}"
elif [[ ${tok[$i]} == "cats" ]]; then
cats="${tok[$((i + 1))]}"
elif [[ ${tok[$i]} == "breason" ]]; then
blockreason="${tok[$((i + 1))]}"
2021-06-03 08:56:54 +10:00
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
taskblockreason[$id]="$blockreason"
2021-06-03 08:56:54 +10:00
taskdesc[$id]=$desc
taskchecked[$id]=$checked
taskfolded[$id]=$folded
taskparent[$id]=$parent
if [[ $DEBUG -eq 1 ]]; then
echo "taskuid[$id]=$uid"
echo "taskid[$id]=$id"
echo "tasksum[$id]=$sum"
echo "taskcats[$id]=$cats"
echo "taskblockreason[$id]=$blockreason"
echo "taskdesc[$id]=$desc"
echo "taskchecked[$id]=$checked"
echo "taskfolded[$id]=$folded"
echo "taskparent[$id]=$parent"
fi
2021-06-03 08:56:54 +10:00
[[ $id -gt $maxid ]] && maxid=$id
[[ ${#sum} -gt $taskwid ]] && taskwid=${#sum}
[[ ${#desc} -gt $taskwid ]] && taskwid=${#desc}
[[ $didalloc -eq 1 ]] && updatenextid
2021-06-03 08:56:54 +10:00
if [[ -z $uid ]]; then
error "task has no uid:"
echo "$res"
return 1
fi
# cache it
#cachetask "$file"
2021-06-03 08:56:54 +10:00
return 0
}
function cachetask() { #1=cardfile
stat -f "%Uc" "$1" >${cachedir}/$(basename "$1")
}
function iscached() { #1=cardfile
local changetime cachetime
changetime=$(stat -f "%Uc" "$1")
cachetime=$(cat ${cachedir}/$(basename "$1"))
if [[ $changetime -eq $cachetime ]]; then
return 1;
fi
return 0;
}
2021-06-03 08:56:54 +10:00
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"
2021-11-25 20:02:23 +11:00
#sed -i '/^COMPLETED:/d;/^STATUS:COMPLETED/d;/PERCENT-COMPLETE:100/d' "$file"
#sed -i '/^COMPLETED:/d;/^STATUS:/d;/PERCENT-COMPLETE:/d' "$file"
clearstatus "$file"
2021-06-03 08:56:54 +10:00
sedrv=$((sedrv + $?))
set_lastmodified $uid
sedrv=$((sedrv + $?))
if [[ $sedrv -eq 0 ]]; then
inform "Marked $noun #${id} as unfinished."
2021-06-03 08:56:54 +10:00
processed="$processed ${uid} "
loadtask "$file"
2021-06-03 08:56:54 +10:00
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"
2021-06-03 08:56:54 +10:00
id=$(getid $uid)
unset idmap[$id]
count=$((count + 1))
done
saveids
[[ $count -eq 1 ]] && ess="" || ess="s"
inform "$count task$ess removed."
2021-06-03 08:56:54 +10:00
else
inform "Aborted."
2021-06-03 08:56:54 +10:00
rv=1
fi
return $rv
}
function set_lastmodified() {
local uid file now
uid=$1
file="$dir/$uid.vcf"
2021-06-03 08:56:54 +10:00
now=$(date -u +'%Y%m%dT%H%M%SZ')
sed -i "s/^LAST-MODIFIED:.*/LAST-MODIFIED:$now/" "$file"
2021-06-03 08:56:54 +10:00
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"
2021-06-03 08:56:54 +10:00
sed -i "s/^RELATED-TO.*/RELATED-TO;RELTYPE=PARENT:${taskparent[$id]}/" "$file"
2021-06-03 08:56:54 +10:00
sedrv=$?
set_lastmodified $uid
sedrv=$((sedrv + $?))
if [[ $sedrv -eq 0 ]]; then
inform "Shifted task #${id} upwards/left."
loadtask "$file"
2021-06-03 08:56:54 +10:00
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
if [[ $newparent == "-" ]]; then
newparent=""
newparentid=""
else
newparentid=$(getid $newparent)
fi
2021-06-03 08:56:54 +10:00
rv=0
taskparent[$id]="$newparent"
file="$dir/$uid.vcf"
if [[ -z $newparent ]]; then
sed -i "/^RELATED-TO.*/d" "$file"
sedrv=$?
2021-06-03 08:56:54 +10:00
else
2021-11-21 10:54:25 +11:00
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
2021-06-03 08:56:54 +10:00
fi
set_lastmodified $uid
sedrv=$((sedrv + $?))
if [[ $sedrv -eq 0 ]]; then
if [[ -z $newparent ]]; then
str="to toplevel."
else
str="underneath #${newparentid} ('${tasksum[$newparentid]}')."
fi
inform "Shifted task #${id} $str"
loadtask "$file"
2021-06-03 08:56:54 +10:00
showit ${taskparent[$id]} $uid
rv=0
else
if [[ -z $newparent ]]; then
str="to toplevel."
else
str="under #${newparentid}."
fi
error "Failed to shift task #${id} $str"
2021-06-03 08:56:54 +10:00
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"
2021-06-03 08:56:54 +10:00
if grep -q ^DESCRIPTION: "$file"; then
sed -i "s/^DESCRIPTION:.*/DESCRIPTION:$newnote/" "$file"
2021-06-03 08:56:54 +10:00
sedrv=$?
else
str="END:VTODO"
toadd="DESCRIPTION:$newnote"
sed -i "/$str/i $toadd\n" "$file"
2021-06-03 08:56:54 +10:00
sedrv=$?
fi
set_lastmodified $uid
sedrv=$((sedrv + $?))
if [[ $sedrv -eq 0 ]]; then
if [[ -z $newnote ]]; then
inform "Removed note from task #${id}."
2021-06-03 08:56:54 +10:00
else
inform "Set note of task #${id} to '$newnote'."
2021-06-03 08:56:54 +10:00
fi
loadtask "$file"
2021-06-03 08:56:54 +10:00
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 inform x catarr newcat
2021-06-03 08:56:54 +10:00
uid=$1
id=$(getid $uid)
rv=0
shift
inform=$1
2021-06-03 08:56:54 +10:00
shift
arg="$*"
file="$dir/$uid.vcf"
2021-06-03 08:56:54 +10:00
if [[ -z $arg ]]; then
if [[ $inform == "del" ]]; then
sed -i "/^CATEGORIES:/d" "$file"
2021-06-03 08:56:54 +10:00
sedrv=$?
else
error "No tag specified to add."
return 1
fi
else
IFS=","
catarr=( ${taskcats[$id]} )
IFS=" "
for x in ${!catarr[@]} ; do
if [[ $inform == "add" || ${catarr[$x]} != $arg ]]; then
2021-06-03 08:56:54 +10:00
[[ -z $newcat ]] && newcat="${catarr[$x]}" || newcat="$newcat,${catarr[$x]}"
fi
done
if [[ $inform == "add" ]]; then
2021-06-03 08:56:54 +10:00
[[ -z $newcat ]] && newcat="${arg}" || newcat="$newcat,$arg"
fi
if grep -q ^CATEGORIES: "$file"; then
sed -i "s/^CATEGORIES:.*/CATEGORIES:${newcat}/" "$file"
2021-06-03 08:56:54 +10:00
sedrv=$?
else
str="END:VTODO"
toadd="CATEGORIES:${newcat}"
sed -i "/$str/i $toadd\n" "$file"
2021-06-03 08:56:54 +10:00
sedrv=$?
fi
fi
set_lastmodified $uid
sedrv=$((sedrv + $?))
if [[ $sedrv -eq 0 ]]; then
if [[ $inform == "del" ]]; then
2021-06-03 08:56:54 +10:00
if [[ -z $arg ]]; then
inform "Removed all tags from task #${id}."
2021-06-03 08:56:54 +10:00
else
inform "Removed tag '$arg' from task #${id}."
2021-06-03 08:56:54 +10:00
fi
else
inform "Added tag '$arg' to task #${id}."
2021-06-03 08:56:54 +10:00
fi
loadtask "$file"
2021-06-03 08:56:54 +10:00
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"
2021-06-03 08:56:54 +10:00
sed -i "s/^SUMMARY:.*/SUMMARY:$newname/" "$file"
2021-06-03 08:56:54 +10:00
sedrv=$?
set_lastmodified $uid
sedrv=$((sedrv + $?))
if [[ $sedrv -eq 0 ]]; then
inform "Renamed task #${id} to '$newname'."
loadtask "$file"
2021-06-03 08:56:54 +10:00
rv=0
else
error "failed to rename task #${id}."
rv=1
fi
return $rv
}
function sedmod() { # sedmod uid 'sed command'
local uid sedscript newname sedrv rv file
local id one two cur new
uid=$1
id=$(getid $uid)
rv=0
shift
if [[ $# -ge 2 ]]; then
sedscript="s/$1/$2/g"
else
sedscript="$*"
fi
newname=$(echo "${tasksum[$id]}" | sed "$sedscript" 2>/dev/null )
if [[ $? -ne 0 ]]; then
error "Invalid sed script: $BOLD$sedscript"
return 1
fi
cur="${tasksum[$id]}"
new="${newname}"
if [[ $sedscript =~ ^s\/.*\/.*\/.*$ ]]; then
one=$(echo "$sedscript" | awk -F/ '{ print $2 }')
two=$(echo "$sedscript" | awk -F/ '{ print $3 }')
# ooo
cur=${cur/$one/$BOLD$STRIKE$RED$one^p^b}
new=${new/$two/$BOLD$GREEN$two^b}
fi
info "Current name: ${BOLD}${cur}"
info "New name: ${BOLD}${new}"
confirm "Is this correct"
if [[ $? -ne 0 ]]; then
inform "Aborted."
return 1
fi
file="$dir/$uid.vcf"
sed -i "s/^SUMMARY:.*/SUMMARY:$newname/" "$file"
sedrv=$?
set_lastmodified $uid
sedrv=$((sedrv + $?))
if [[ $sedrv -eq 0 ]]; then
inform "Renamed task #${id} to '$newname'."
loadtask "$file"
rv=0
else
error "failed to rename task #${id}."
rv=1
fi
return $rv
}
2021-06-03 08:56:54 +10:00
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"
2021-06-03 08:56:54 +10:00
str="END:VTODO"
if grep -q ^X-OC-HIDESUBTASKS: "$file" ; then
sed -i "s/X-OC-HIDESUBTASKS:.*/X-OC-HIDESUBTASKS:1/" "$file"
2021-06-03 08:56:54 +10:00
sedrv=$?
else
sed -i "/$str/i X-OC-HIDESUBTASKS:1" "$file"
2021-06-03 08:56:54 +10:00
sedrv=$?
fi
set_lastmodified $uid
sedrv=$((sedrv + $?))
if [[ $sedrv -eq 0 ]]; then
inform "Folded task #${id}."
2021-06-03 08:56:54 +10:00
processed="$processed ${uid} "
loadtask "$file"
2021-06-03 08:56:54 +10:00
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"
2021-06-03 08:56:54 +10:00
str="END:VTODO"
if grep -q ^X-OC-HIDESUBTASKS: "$file" ; then
sed -i "s/X-OC-HIDESUBTASKS:.*/X-OC-HIDESUBTASKS:0/" "$file"
2021-06-03 08:56:54 +10:00
sedrv=$?
else
sed -i "/$str/i X-OC-HIDESUBTASKS:0" "$file"
2021-06-03 08:56:54 +10:00
sedrv=$?
fi
set_lastmodified $uid
sedrv=$((sedrv + $?))
if [[ $sedrv -eq 0 ]]; then
inform "Unfolded task #${id}."
2021-06-03 08:56:54 +10:00
processed="$processed ${uid} "
loadtask "$file"
2021-06-03 08:56:54 +10:00
rv=0
else
failed="$failed ${uid} "
error "failed to unfold task #${id}"
rv=1
fi
return $rv
}
function clearstatus() {
local file
file="$1"
[[ -e $file ]] && sed -i '/^COMPLETED:/d;/^STATUS:COMPLETED/d;/PERCENT-COMPLETE:/d;/^STATUS:IN-PROCESS:/d;/^STATUS:NEEDS-inform/d;/^$/d;/^REQUEST-STATUS:/d;/^STATUS:IN-PROCESS/d' "$file"
}
function markblocked() { # $1=uid $2=reason
local uid sedrv rv file toadd1 str now
local children childuid ischild noun id
uid=$1
reason="$2"
id=$(getid $uid)
[[ $# -gt 1 ]] && ischild=1 || ischild=0
[[ $ischild -eq 1 ]] && noun=subtask || noun=task
# already blocked?
if [[ ${taskchecked[$id]} -eq 3 ]]; then
if [[ ${taskblockreason[$id]} == "$reason" ]]; then
error "$noun #${id} is already blocked"
return 1
fi
fi
str="END:VTODO"
now=$(date -u +'%Y%m%dT%H%M%SZ')
file="$dir/$uid.vcf"
# first remove any existing completion
#sed -i '/^COMPLETED:/d;/^STATUS:COMPLETED/d;/PERCENT-COMPLETE:/d;/STATUS:IN-PROCESS:/d;/STATUS:NEEDS-inform/d' "$file"
clearstatus "$file"
# then add blocked
toadd1="STATUS:NEEDS-inform"
sed -i "/$str/i $toadd1\n" "$file"
sedrv=$?
if [[ -n $reason ]]; then
toadd2="REQUEST-STATUS:4.1;$reason"
sed -i "/$str/i $toadd2\n" "$file"
sedrv=$((sedrv + $?))
fi
set_lastmodified $uid
sedrv=$((sedrv + $?))
if [[ $sedrv -eq 0 ]]; then
local txt
txt="Marked $noun #${id} as blocked"
if [[ -n $reason ]]; then
txt="${txt} due to ${BOLD}$reason$PLAIN"
fi
txt="${txt}."
inform "$txt"
processed="$processed ${uid} "
loadtask "$file"
rv=0
# dont block children
#children=$(getchildren $uid)
#for childuid in ${children}; do
# markblocked $childuid noprint
# rv=$((rv + $?))
#done
#echo "file: $file"
#cat $file
else
failed="$failed ${uid} "
error "failed to mark $noun #${id} as blocked"
rv=1
fi
return $rv
}
2021-11-25 20:02:23 +11:00
function markinprogress() {
local uid sedrv rv file toadd1 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 in progress?
if [[ ${taskchecked[$id]} -eq 1 ]]; then
error "$noun #${id} is already in progress"
return 1
fi
str="END:VTODO"
now=$(date -u +'%Y%m%dT%H%M%SZ')
file="$dir/$uid.vcf"
# first remove any existing completion
#sed -i '/^COMPLETED:/d;/^STATUS:COMPLETED/d;/PERCENT-COMPLETE:/d;/STATUS:NEEDS-inform/d;' "$file"
clearstatus "$file"
2021-11-25 20:02:23 +11:00
# then add partial completion
toadd1="STATUS:IN-PROCESS"
sed -i "/$str/i $toadd1\n" "$file"
sedrv=$?
set_lastmodified $uid
sedrv=$((sedrv + $?))
if [[ $sedrv -eq 0 ]]; then
inform "Marked $noun #${id} as in-progress."
2021-11-25 20:02:23 +11:00
processed="$processed ${uid} "
loadtask "$file"
rv=0
children=$(getchildren $uid)
for childuid in ${children}; do
markinprogress $childuid noprint
rv=$((rv + $?))
done
else
failed="$failed ${uid} "
error "failed to mark $noun #${id} as in-progress"
rv=1
fi
return $rv
}
2021-06-03 08:56:54 +10:00
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?
2021-11-25 20:02:23 +11:00
if [[ ${taskchecked[$id]} -eq 2 ]]; then
2021-06-03 08:56:54 +10:00
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"
clearstatus "$file"
sed -i "/$str/i $toadd1\n$toadd2\n$toadd3" "$file"
2021-06-03 08:56:54 +10:00
sedrv=$?
set_lastmodified $uid
sedrv=$((sedrv + $?))
if [[ $sedrv -eq 0 ]]; then
inform "Marked $noun #${id} as completed."
2021-06-03 08:56:54 +10:00
processed="$processed ${uid} "
loadtask "$file"
2021-06-03 08:56:54 +10:00
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"
2021-06-03 08:56:54 +10:00
inform "Viewing task #$id ($file):"
cat "$file" | sed -e 's/^/ /'
2021-06-03 08:56:54 +10:00
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
addidmap $thisid $uid
2021-06-03 08:56:54 +10:00
taskid[$thisid]=$thisid
taskuid[$thisid]=$uid
tasksum[$thisid]="$*"
taskdesc[$thisid]=""
taskchecked[$thisid]=0
taskfolded[$thisid]=0
taskparent[$thisid]=$parentuid
file="$dir/$uid.vcf"
2021-06-03 08:56:54 +10:00
now=$(date -u +'%Y%m%dT%H%M%SZ')
cat >"$file" <<EOF
2021-06-03 08:56:54 +10:00
BEGIN:VCALENDAR
VERSION:2.0
PRODID:+//IDN tasks.org//android-111003//EN
BEGIN:VTODO
DTSTAMP:$now
UID:$uid
CREATED:$now
LAST-MODIFIED:$now
SUMMARY:${tasksum[$thisid]}
EOF
if [[ ! -z ${taskparent[$thisid]} ]]; then
echo "RELATED-TO;RELTYPE=PARENT:${taskparent[$thisid]}" >>"$file"
2021-06-03 08:56:54 +10:00
fi
cat >>"$file" <<EOF2
2021-06-03 08:56:54 +10:00
PRIORITY:9
X-APPLE-SORT-ORDER:611376630
X-OC-HIDESUBTASKS:0
END:VTODO
END:VCALENDAR
EOF2
updatenextid
2021-06-03 08:56:54 +10:00
saveids
needtitle=1
if [[ -z ${parentuid} ]]; then
inform "Created new task #${taskid[$thisid]}."
2021-06-03 08:56:54 +10:00
showit $uid
else
inform "Created new subtask #${taskid[$thisid]} under '${tasksum[${parentid}]}'."
2021-06-03 08:56:54 +10:00
showit ${taskparent[$thisid]} $uid
fi
}
function nextline() {
local dummy morestring rv=0
2021-06-03 08:56:54 +10:00
morestring="<------ more ------>"
printed=$((printed + 1));
2021-11-08 18:20:37 +11:00
if [[ $USEPAGER -eq 1 ]]; then
if [[ $printed -ge $((rows - 2)) ]]; then
echo -en "${CYAN}${morestring}${PLAIN}"
read -n1 -s dummy
[[ $dummy == "q" ]] && { echo; exit 0; }
2021-11-08 18:20:37 +11:00
printf "\r%*s\r" ${#morestring}
printed=0
needtitle=1
fi
2021-06-03 08:56:54 +10:00
fi
}
function showit() {
local uid childuid children char hilite col wid screenwid id ilev
local children nchildren charcol
local notecol bcol bl br space pre end
local showkids
2021-11-25 20:02:23 +11:00
local reset catstr catcol lrogcol
local blockedcol blockedrcol blockstr
2021-06-03 08:56:54 +10:00
reset="$PLAIN"
catcol="\033[38;2;255;165;0m"
2021-11-25 20:02:23 +11:00
progcol="\033[38;2;212;0;255m"
blockedcol="\033[38;2;212;0;0m"
blockedrcol="$blockedcol$BOLD"
2021-06-03 08:56:54 +10:00
showkids=1
if [[ $1 == "--nochildren" ]]; then
showkids=0
shift
fi
uid=$1
id=$(getid $uid)
children=$(getchildren $uid)
childrenarray=( $children )
nchildren=${#childrenarray[@]}
if [[ $# -ge 2 ]]; then
hilite=$2
fi
if [[ $needtitle -eq 1 ]]; then
cols=$(tput cols)
screenwid=$((cols - $numwid - 2 - 1))
wid=$(echo "scale=0; 4 + ($maxindent * $indentamt) + $maxtaskwidth + 3" | bc)
[[ $wid -gt $screenwid ]] && wid=$screenwid
printf "$TOPTITLE%-${numwid}s %-${wid}s$reset\n" "ID" "Task"
needtitle=0
fi
col="$reset"
2022-03-06 19:42:04 +11:00
donecol="$GREY"
2021-06-03 08:56:54 +10:00
notecol="$YELLOW"
2021-11-25 20:02:23 +11:00
end=""
if [[ ${taskchecked[$id]} -eq 2 ]]; then
2021-06-03 08:56:54 +10:00
char="✓"
2021-11-25 20:02:23 +11:00
charcol="$GREEN"
2022-03-06 19:42:04 +11:00
col="$donecol$STRIKE"
2021-06-03 08:56:54 +10:00
notecol="$notecol$STRIKE"
2021-11-25 20:02:23 +11:00
elif [[ ${taskchecked[$id]} -eq 1 ]]; then
char="&"
charcol="$progcol"
end="${progcol}...${reset}"
elif [[ ${taskchecked[$id]} -eq 3 ]]; then
2022-03-06 19:42:04 +11:00
#char="🛑"
#char="⛔"
char="⬣"
charcol="$blockedcol"
col="$blockedcol"
2021-06-03 08:56:54 +10:00
else
char=" "
2021-11-25 20:02:23 +11:00
charcol="$GREEN"
2021-06-03 08:56:54 +10:00
fi
if [[ $uid == $hilite ]]; then
col="$col$HILITE"
notecol="$notecol$HILITE"
fi
if [[ $nchildren -gt 0 && ${taskfolded[$id]} -eq 1 ]]; then
bcol=$brackfold
bl="("
br=")"
#col="$col$FOLDBG"
space=" "
pre=""
2021-11-25 20:02:23 +11:00
end=" $end$reset$CYAN${BOLD}[$nchildren subtasks]"
2021-06-03 08:56:54 +10:00
if [[ $char == " " ]]; then
char="+"
charcol="$BOLD$CYAN"
fi
else
bcol=$brack
bl="["
br="]"
space=" "
pre=""
fi
if [[ -z ${taskblockreason[$id]} ]]; then
blockstr=""
else
blockstr="${blockedrcol} (${taskblockreason[$id]}$reset$blockedrcol)"
fi
2021-06-03 08:56:54 +10:00
if [[ -z ${taskcats[$id]} ]]; then
catstr=""
else
catstr="${catcol} (${taskcats[$id]}$reset$catcol)"
fi
printf "${LEFTTITLE}%-${numwid}d${reset}" ${id}
printf "$space$space"
if [[ $space == " " ]]; then
printf "%*s" $indent
elif [[ $indent -gt 0 ]]; then
for x in $(eval echo {1..${indent} ); do
echo -n "$space"
done
fi
ilev=$(getindentlevel $id)
printf "$reset"
printf "$bcol$bl$reset$charcol%s$reset$bcol$br$reset ${col}${pre}%s$end${reset}${blockstr}${reset}${catstr}${reset}\n" "${char}" "${tasksum[$id]}"
2021-06-03 08:56:54 +10:00
nextline
if [[ ! -z ${taskdesc[$id]} ]]; then
printf "${LEFTTITLE}%*s${reset} " $numwid
printf "%*s" $(( $indent + 4))
printf "${notecol}${ITALIC}%s${reset}\n" "${taskdesc[$id]}"
nextline
fi
if [[ $showkids -eq 1 && ${taskfolded[$id]} -ne 1 ]]; then
inc
for childuid in ${children}; do
showit $childuid $hilite
done
dec
fi
}
function addcmd() { # name usage description alt1|alt2|etc supportsall
local cmd usage desc alts
cmd="$1"
usage="$2"
desc="$3"
alts="$4"
[[ -z $valid_modes ]] && valid_modes=$cmd || valid_modes="$valid_modes $cmd"
eval "usage_${cmd}=\"${usage}\""
eval "desc_${cmd}=\"${desc}\""
eval "words_${cmd}=\"${alts}\""
if [[ $* == *SUPPORTS_ALL* ]]; then
2021-06-03 08:56:54 +10:00
if [[ -z $modes_that_support_all ]]; then
modes_that_support_all="$cmd"
else
modes_that_support_all="$modes_that_support_all|$cmd"
fi
fi
if [[ $* == *PASSIVE* ]]; then
if [[ -z $passive_modes ]]; then
passive_modes="$cmd"
else
passive_modes="$passive_modes|$cmd"
fi
fi
2021-06-03 08:56:54 +10:00
}
2021-11-07 10:48:34 +11:00
function sortuidlist() { # sort a list of task uids by task summng aries
local unsorted uidandsum withnl sorted_arr sorted unsorted_arr uid
unsorted="$1"
# change "123 456 789" to
# ("123#do something" "234#other task" "789#something#)
unsorted_arr=""
for uid in ${unsorted}; do
id=$(getid $uid)
unsorted_arr+=("${taskuid[$id]}#${tasksum[$id]}")
done
IFS=$'\n'
withnl=("${unsorted_arr[*]}")
sorted_arr=($(sort -df -t '#' -k2 <<<"${withnl[*]}"))
sorted=""
for uidandsum in ${sorted_arr[@]}; do
sorted="$sorted ${uidandsum%#*}"
done
unset IFS
echo "$sorted"
}
function getchildren() { # parentuid
2021-06-03 08:56:54 +10:00
local uid childuid children id
uid=$1
children=""
for id in ${!taskid[@]}; do
2021-11-07 10:48:34 +11:00
if [[ ${taskparent[$id]} == $uid ]]; then
children="$children ${taskuid[$id]}"
fi
2021-06-03 08:56:54 +10:00
done
[[ -z $children ]] && return 1
2021-11-07 10:48:34 +11:00
if [[ $WANTSORT -eq 1 ]]; then
children=$(sortuidlist "$children")
fi
2021-06-03 08:56:54 +10:00
echo "$children"
return 0
}
function makedir() {
local d
d="$1"
if [[ -d "$d" ]]; then
info "Directory $d already exists"
else
mkdir -p "${d}"
if [[ $? -eq 0 ]]; then
inform "Created directory ${BOLD}$d${PLAIN}"
else
error "Couldn't mkdir ${BOLD}$d${PLAIN}${RED}"
return 1
fi
fi
return 0
}
function init() {
local gotvdconf=0 d url count cals cals_arr thiscal selcal
inform "Initialising configration"
if ! which -s vdirsyncer; then
error "Can't find ${BOLD}vdirsyncer${PLAIN}${RED} - please install it."
return 1
fi
if [[ -e $vdirsyncconfig ]]; then
confirm "Use existing vdirsyncer config in ${BOLD}$vdirsyncconfig${PLAIN}${MAGENTA}"
if [[ $? -eq 0 ]]; then
gotvdconf=1
fi
fi
if [[ $gotvdconf -ne 1 ]]; then
for d in "$vdirsyncdir" "$vdircaldir" "$vdirstatdir"; do
makedir "$d" || return 1
done
echo -e "${MAGENTA}Please provide the URL of your caldav server.${PLAIN}"
echo -en "${BOLD}${MAGENTA}==> ${PLAIN}"
read url
if [[ ! $url =~ ^http.* ]]; then
error "Provided URL 'url' appears invalid."
return 1
fi
echo -en "${BOLD}${MAGENTA}Caldav username: ${PLAIN}"
read u
echo -en "${BOLD}${MAGENTA}Caldav password: ${PLAIN}"
read -s p
cat >"${vdirsyncconfig}" <<EOF
[general]
status_path = "$vdirstatdir"
[pair cal]
a = "cal_local"
b = "cal_remote"
collections = ["from a", "from b"]
[storage cal_local]
type = "filesystem"
path = "$vdircaldir"
fileext = ".vcf"
[storage cal_remote]
type = "caldav"
url = "$url"
username = "$u"
password = "$p"
EOF
unset u
unset p
info "Created vdirsyncer config in ${vdirsyncconfig}"
fi
cals=$(ls -1q $vdircaldir 2>/dev/null)
count=$(echo "$cals" | wc -l | tr -d ' ')
if [[ $count -eq 0 ]]; then
inform "Running initial vdirsyncer discover..."
vdirsyncer discover
inform "Running initial vdirsyncer sync..."
vdirsyncer sync
fi
getcals count cals_arr
makedir "$confdir" || return 1
if [[ -e "${allcalsdir}" ]] ; then
warn "Calendar symlink ${allcalsdir} already exists. Not overwriting it."
else
ln -s "${vdircaldir}" "${allcalsdir}"
inform "Created symlink to $vdircaldir"
fi
if [[ ! -e "${defaultcalfile}" ]] ; then
selcal=""
if [[ $count -gt 0 ]]; then
local sel
echo
for d in ${!cals_arr[@]}; do
echo -e "${MAGENTA}${BOLD}$((d + 1)). ${PLAIN}${MAGENTA}${cals_arr[$d]}${PLAIN}"
done
sel=-1
while [[ $sel -le 0 || $sel -gt ${#cals_arr[@]} ]]; do
echo -en "${MAGENTA}${BOLD}Select calendar: ${PLAIN}"
read sel
done
selcal=${cals_arr[$(($sel - 1))]}
echo "$selcal" >"$defaultcalfile"
else
warn "No calendars found."
fi
fi
if [[ -z $selcal ]]; then
warn "No calendar selected "
echo "${YELLOW}Please put default calendar name in ${defaultcalfile}"
echo "${YELLOW}then: touch \"${idfile}_\$(cat $defaultcalfile)\""
selcal=""
else
selcal=${selcal// /_}
if [[ -e "${idfile}_${selcal}" ]]; then
warn "ID mapping file for $selcal already exists. Not overwriting it."
else
touch "${idfile}_${selcal}"
fi
fi
info "Initialisation complete"
[[ -z $selcal ]] && selcal="<none>"
echo -e "${CYAN} vdirsyncer config is in ${BOLD}${vdirsyncdir}${PLAIN}"
echo -e "${CYAN} task_cli config is in ${BOLD}${confdir}${PLAIN}"
echo -e "${CYAN} selected calendar is '${BOLD}${selcal}${PLAIN}'"
echo
}
2021-06-26 09:29:29 +10:00
function tasksync() {
2022-03-29 18:05:55 +11:00
local res upcount downcount noun="Sync" mode="sync"
2021-06-26 09:29:29 +10:00
2022-03-29 18:05:55 +11:00
while [[ $# -ge 1 ]]; do
if [[ $1 == "-a" ]]; then
noun="Auto-sync"
elif [[ $1 == "push" ]]; then
mode="push"
noun="Push"
elif [[ $1 == "pull" ]]; then
mode="pull"
noun="Pull"
fi
shift
done
notify "${noun}ing tasks"
# adjust conflict resolution
## remove existing setting
sed -i '/^conflict/ s/^/#/' $vdirsyncconfig
## add new one
if [[ $mode == "push" ]]; then
sed -i '/conflict.*a wins/ s/^#\+//' $vdirsyncconfig
elif [[ $mode == "pull" ]]; then
sed -i '/conflict.*b wins/ s/^#\+//' $vdirsyncconfig
2021-06-26 09:29:29 +10:00
fi
2022-03-29 18:05:55 +11:00
2021-06-26 09:29:29 +10:00
res=$(${VDIRSYNCER} sync 2>&1)
rv=$?
2022-03-23 19:06:56 +11:00
[[ $rv -eq 0 ]] && ok || fail
2021-06-26 09:29:29 +10:00
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
inform "$noun complete - no changes."
2021-06-26 09:29:29 +10:00
elif [[ $upcount -eq 0 ]]; then
inform "$noun complete - $downcount change$downess pulled."
2021-06-26 09:29:29 +10:00
elif [[ $downcount -eq 0 ]]; then
inform "$noun complete - $upcount change$upess pushed."
2021-06-26 09:29:29 +10:00
else
inform "$noun complete - $upcount change$upess pushed, $downcount change$downess pulled."
2021-06-26 09:29:29 +10:00
fi
else
2022-03-29 18:05:55 +11:00
errmsg="$noun failed."
if [[ $mode == "sync" ]]; then
errmsg="${errmsg} Try ^bt push^p or ^bt pull^p."
fi
error "$errmsg"
if [[ $mode != "sync" ]]; then
cecho -s "$RED" "^bDetails:^p"
cecho -s "$RED" "$res" | sed -e 's/^/ /'
echo
cecho -s "$RED" "^bConflict settings:^p"
errmsg=$(grep "conflict" $vdirsyncconfig 2>&1)
cecho -s "$YELLOW" "$errmsg" | sed -e 's/^/ /'
fi
2021-06-26 09:29:29 +10:00
fi
2022-03-29 18:05:55 +11:00
## remove conflict setting again
sed -i '/^conflict/ s/^/#/' $vdirsyncconfig
2021-06-26 09:29:29 +10:00
}
function getcals() { # countvar arrayvar
local loc_cals loc_count thiscal
local countvar arrayvar
countvar=$1
arrayvar=$2
loc_cals=$(ls -1q $vdircaldir 2>/dev/null)
loc_count=$(echo "$loc_cals" | wc -l | tr -d ' ')
eval "$countvar=$loc_count"
eval "$arrayvar=()"
while read thiscal; do
eval "$arrayvar+=(\"$thiscal\")"
done <<< "$loc_cals"
}
function getcalname() { # cal_name_or_number
local lc larr d found=""
getcals lc larr
for d in ${!larr[@]}; do
if [[ ${larr[$d]} == $1 ]]; then
found="${larr[$d]}"
break
elif [[ $1 =~ ^[0-9]+$ && $d -eq $(($1 - 1)) ]]; then
# make this the default
found="${larr[$d]}"
break
fi
done
echo "$found"
if [[ -z $found ]]; then
return 1
fi
return 0
}
2021-06-03 08:56:54 +10:00
# Should be in config file:
#basedir=/Users/rpearce/scripts/t
#dir=$basedir/docs
#idfile=$basedir/idmappings.txt
#VDS_LOCAL=$cal_local
#VDS_REMOTE=$cal_remote
#VDIRSYNCER=/usr/local/bin/vdirsyncer
#VDS_BASEDIR="~/.config/vdirsyncer"
#VDS_CONFIG="${VDS_BASEDIR}/config"
#VDS_STATUSDIR="${VDS_BASEDIR}/status"
#VDS_CALDIR="${VDS_BASEDIR}/calendar"
# Base vdirsycner config in ${VDS_CONFIG}:
#[general]
#status_path = "${VDS_STATUSDIR}/"
#
#[pair cal]
#a = "${VDS_LOCAL}"
#b = "${VDS_REMOTE}"
#collections = ["from a", "from b"]
#
#[storage ${VDS_LOCAL}]
#type = "filesystem"
#path = "${VDS_CALDIR}/"
#fileext = ".vcf"
#
#[storage ${VDS_REMOTE}]
#type = "caldav"
#url = "https://tasks.haven.family/caldav.php/haven/"
#username = "xxx"
#password = "xxx"
###
#
#
# Ask:
# - where is this script located?
# - remote<->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]
DEFAULT_VDS_LOCAL=cal_local
DEFAULT_VDS_REMOTE=cal_remote
2021-06-03 08:56:54 +10:00
basedir=/Users/rpearce/code/task_cli
confdir="${HOME}/.task_cli"
cachedir="${confdir}/cache"
allcalsdir="$confdir/allcals" # symlink to vdirsyncer/calendar/
defaultcalfile="$confdir/defaultcal"
idfile="$confdir/idmappings"
2021-06-03 08:56:54 +10:00
nextid=1
indent=0
indentamt=4
needsave=0
mode=list
modes_that_support_all=""
passive_modes="" # modes that do not change data
2021-06-03 08:56:54 +10:00
vdirsyncdir="${HOME}/.config/vdirsyncer"
vdircaldir="${HOME}/.config/vdirsyncer/calendar"
vdirstatdir="${HOME}/.config/vdirsyncer/status"
vdirsyncconfig="${vdirsyncdir}/config"
2021-06-03 08:56:54 +10:00
# for pager
printed=0
rows=$(tput lines)
addcmd "list" "list [id1] .. [idX]" "List [just the specified] tasks" "list|ls|show" SUPPORTS_ALL PASSIVE
2021-06-03 08:56:54 +10:00
addcmd "fold" "fold <id>" "Fold a parent task (hide its children)" "fold|f|zc" SUPPORTS_ALL
addcmd "unfold" "unfold <id>" "Unfold a parent task (show its children)" "unfold|u|zo" SUPPORTS_ALL
addcmd "toggle" "toggle <id>" "Fold/Unfold a parent task" "toggle|z|zz" SUPPORTS_ALL
2021-06-03 08:56:54 +10:00
addcmd "done" "done <taskid>" "Complete a task" "done|x|complete" SUPPORTS_ALL
addcmd "notdone" "notdone <taskid>" "Uncomplete a task" "notdone|o|incomplete|uncomplete|clear" SUPPORTS_ALL
2021-11-25 20:02:23 +11:00
addcmd "inprogress" "inprogress <taskid>" "Mark a task as in progress" "inprogress|progress|inp|prog|i|p" SUPPORTS_ALL
addcmd "blocked" "blocked <taskid>" "Mark a task as blocked" "blocked|block|b" SUPPORTS_ALL
2021-06-03 08:56:54 +10:00
addcmd "add" "add [parent] <name>" "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 <id> <newname>" "Rename given task" "rename"
addcmd "mod" "mod <id> (<sed_script>|<lookfor> <replacewith>)" "Rename given task using sed script" "mod|sed"
2021-06-03 08:56:54 +10:00
addcmd "left" "left <id>" "Decrease indent of given task" "left|h|out|up"
addcmd "right" "right <id> <parent>" "Move task below the given parent" "right|l|mv|in"
addcmd "note" "note <id> <notes>" "Change notes for given task" "note|desc|description|comment"
addcmd "tag" "tag <id> <tag>" "Add a tag to the given task" "tag|t"
addcmd "untag" "untag <id> <tag>" "Remove a tag from the given task" "untag|ut"
addcmd "sync" "sync" "Sync tasks using vdirsyncer" "sync"
2022-03-29 18:05:55 +11:00
addcmd "push" "push" "Push all tasks to server" "push"
addcmd "view" "view <id>" "Show detailed info for given task" "v|view|info|vcal" PASSIVE
addcmd "showcals" "showcals" "List available calendars" "cals|showcals|cls" PASSIVE
addcmd "setcal" "setcal" "Set the default calendar." "setcal|sc"
addcmd "renumber" "renumber" "Re-generate IDs for all tasks with lowest possible numbers" "rn|gen"
2021-06-03 08:56:54 +10:00
[[ ! -e $cachedir ]] && mkdir -p "$cachedir"
2021-06-03 08:56:54 +10:00
DEBUG=0
TESTMODE=0
2021-06-26 09:29:29 +10:00
AUTOSYNC=0
CALID=$(cat "$confdir/defaultcal")
2021-11-07 10:48:34 +11:00
WANTSORT=0
2021-11-08 18:20:37 +11:00
USEPAGER=1
2022-06-13 21:04:59 +10:00
MAINTMODE=0
2021-06-03 08:56:54 +10:00
2022-06-13 21:04:59 +10:00
ARGS="fhic:dmnsStyl:r:p"
2021-06-03 08:56:54 +10:00
while getopts "$ARGS" i; do
case "$i" in
2022-06-13 21:04:59 +10:00
m)
MAINTMODE=1
;;
2021-06-03 08:56:54 +10:00
h)
usage;
exit 1;
;;
i)
init
exit $?
;;
c)
CALID="$OPTARG"
;;
l)
VDS_LOCAL="$OPTARG"
;;
2021-11-08 18:20:37 +11:00
n)
USEPAGER=0
;;
p)
__PROFILE=1
;;
r)
VDS_REMOTE="$OPTARG"
;;
2021-06-03 08:56:54 +10:00
d)
DEBUG=1
;;
2021-06-26 09:29:29 +10:00
s)
AUTOSYNC=1
;;
2021-11-07 10:48:34 +11:00
S)
WANTSORT=1
;;
2021-06-03 08:56:54 +10:00
t)
DEBUG=1
TESTMODE=1
;;
2021-09-05 08:06:52 +10:00
y|f)
AUTOYES=1
;;
2021-06-03 08:56:54 +10:00
*)
error "invalid argument: $i";
usage;
exit 1
;;
esac
done
shift $((OPTIND - 1))
2021-11-21 10:54:25 +11:00
# Make sure vdirsyncer is installed
if ! which -s vdirsyncer; then
error "Can't find ${BOLD}vdirsyncer${PLAIN}${RED} - please install it."
return 1
fi
VDIRSYNCER=$(which vdirsyncer)
# validate CALID
foundcal=$(getcalname "$CALID")
if [[ -n $foundcal ]]; then
CALID="$foundcal"
else
error "Calendar '$CALID' does not exist."
exit 1
fi
dir=$allcalsdir/$CALID
idfile="$confdir/idmappings_${CALID// /_}"
if [[ ! -e $idfile ]]; then
warn "No ID mapping file found for calendar '$CALID' ($idfile)"
confirm "Create one from existing tasks?"
if [[ $? -eq 0 ]]; then
loadtasks -v
saveids -v || exit 1
else
die
fi
fi
2021-06-03 08:56:54 +10:00
[[ -z $VDS_LOCAL ]] && VDS_LOCAL="$DEFAULT_VDS_LOCAL"
[[ -z $VDS_REMOTE ]] && VDS_REMOTE="$DEFAULT_VDS_REMOTE"
2021-06-03 08:56:54 +10:00
mode=""
for x in $valid_modes; do
thisone="words_$x"
tomatch=${!thisone}
if [[ $1 =~ ^(${tomatch})$ ]]; then
mode=$x
shift
break
2021-06-03 08:56:54 +10:00
fi
done
if [[ -z $mode ]]; then
mode=list
fi
# Commands that don't need tasks loaded
if [[ $mode == "sync" ]]; then
2021-06-26 09:29:29 +10:00
tasksync
2021-06-03 08:56:54 +10:00
exit $rv
2022-03-29 18:05:55 +11:00
elif [[ $mode == "push" ]]; then
tasksync push
exit $rv
elif [[ $mode == "renumber" ]]; then
idfilebackup="$idfile.bak.$(date +%Y%m%d%H%M%S)"
idfilenew=$(mktemp /tmp/newid.XXXXXXXX)
# figure out what summing program to use
sumprog=""
for x in md5 md5sum; do
which $x >/dev/null 2>&1
if [[ $? -eq 0 ]]; then
sumprog="$x"
break
fi
done
if [[ -n $sumprog ]]; then
notify "Checking current task IDs"
cat "$idfile" | awk 'BEGIN { id=1; FS=":"; } /.*:.*/{ print $1 ":" id++; } ' > "$idfilenew"
md5old=$($sumprog "$idfile")
md5new=$($sumprog "$idfilenew")
if [[ $sumprog == "md5" ]]; then
md5old=$(echo "$md5old" | awk '{ print $NF }')
md5new=$(echo "$md5new" | awk '{ print $NF }')
else
md5old=$(echo "$md5old" | awk '{ print $1 }')
md5new=$(echo "$md5new" | awk '{ print $1 }')
fi
ok
if [[ $md5old == $md5new ]]; then
inform "No changes required based on checksums."
echo "old: $md5sumold"
echo "new: $md5sumnew"
exit 0
fi
else
warn "No checksumming program found - install md5 or md5sum."
fi
oldmin=$(cat "$idfile" | cut -d: -f2 | sort -nr | tail -1)
oldmax=$(cat "$idfile" | cut -d: -f2 | sort -n | tail -1)
min=$(cat "$idfilenew" | cut -d: -f2 | sort -nr | tail -1)
max=$(cat "$idfilenew" | cut -d: -f2 | sort -n | tail -1)
if [[ $oldmin -eq $min && $newmin -eq $min ]]; then
inform "No changes required based on task IDs."
exit 0
fi
inform "This process will renumber all tasks:"
inform " Current ID range: ^b$oldmin^p-^b$oldmax^p"
inform " New ID range: ^b$min^p-^b$max^p"
confirm "Really proceed"
if [[ $? -ne 0 ]]; then
inform "Aborted."
exit 1
fi
notify "Backing up mapping file to ^b$idfilebackup^p"
cp -a "$idfile" "$idfilebackup"
[[ $? -eq 0 ]] && ok || { fail; exit 1; }
notify "Re-generating task IDs"
mv -f "$idfilenew" "$idfile"
[[ $? -eq 0 ]] && ok || { fail; exit 1; }
inform "Task ID renumbering complete."
exit 0
2021-06-03 08:56:54 +10:00
fi
2022-03-23 19:06:56 +11:00
notify "Processing"
2021-06-03 08:56:54 +10:00
loadids || exit 1
loadtasks || exit 1
2022-03-23 19:06:56 +11:00
ok
2021-06-03 08:56:54 +10:00
2022-06-13 21:04:59 +10:00
if [[ $MAINTMODE -eq 1 ]]; then
# check for id mappings with missing tasks
notify "Checking ID mappings"
nbad=0
for x in ${!idmap[@]}; do
if (! IFS=$'\n'; echo "${taskid[*]}" ) | grep -qFx "${idmap[$x]}" ; then
warn "idmap has missing task ${idmap[$x]}"
tofix="$tofix $x "
nbad=$(( nbad + 1))
fi
done
[[ $nbad -ge 1 ]] && partial "$nbad need fixing" || ok
if [[ -n $tofix ]]; then
notify "Fixing ID mappings for missing tasks"
for x in $tofix; do
[[ $b5 -eq 1 ]] && unset i_idmap[${idmap[$x]}];
unset idmap[$x]
done
ok
idfilebackup="$idfile.bak.$(date +%Y%m%d%H%M%S)"
inform "idmap backup is in $idfilebackup"
cp -a "$idfile" "$idfilebackup"
saveids
fi
exit 0
fi
2021-06-03 08:56:54 +10:00
[[ $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 == "showcals" ]]; then
getcals count cals_arr
if [[ $count -gt 0 ]]; then
echo -e "${BOLD}${MAGENTA}Available Calendars:$PLAIN"
for d in ${!cals_arr[@]}; do
echo -en "${MAGENTA}${BOLD}$((d + 1)). ${PLAIN}${MAGENTA}${cals_arr[$d]}${PLAIN}"
[[ ${cals_arr[$d]} == $CALID ]] && echo -e "$BOLD$MAGENTA <- default$PLAIN" || echo
done
else
error "No calendars found."
fi
elif [[ $mode == "setcal" ]]; then
if [[ -z $1 ]]; then
error "No calendar name provided."
exit 1
fi
foundcal=$(getcalname $1)
if [[ -n $foundcal ]]; then
inform "Default calendar set to '${foundcal}'"
echo "${foundcal}" > "$defaultcalfile"
else
error "Calendar '$1' not found"
fi
2021-06-03 08:56:54 +10:00
elif [[ $mode == "rename" ]]; then
uid=$(getuid_witherror $1)
shift
rename $uid "$*"
elif [[ $mode == "mod" ]]; then
uid=$(getuid_witherror $1)
shift
if [[ $# -ge 2 ]]; then
sedmod $uid "$1" "$2"
else
sedmod $uid "$*"
fi
2021-06-03 08:56:54 +10:00
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 == "blocked" ]]; then
uid=$(getuid_witherror $1)
shift
markblocked $uid "$*"
2021-06-03 08:56:54 +10:00
elif [[ $mode == "right" ]]; then
2021-11-21 10:54:25 +11:00
pid=$BASH_ARGV
if [[ $puid != "-" ]]; then
puid=$(getuid_witherror $pid "parent task")
fi
2021-11-21 10:54:25 +11:00
while [[ $# -gt 1 ]]; do
2021-11-21 17:44:48 +11:00
if [[ $1 =~ ^[0-9]+-[0-9]+$ ]]; then
s=${1%-*}
e=${1#*-}
for ((w2=s; w2<=e; w2++)); do
uid=$(getuid_witherror $w2)
move_right $uid $puid
done
else
uid=$(getuid_witherror $1)
move_right $uid $puid
fi
2021-11-21 10:54:25 +11:00
shift
done
2021-06-03 08:56:54 +10:00
elif [[ $mode == "view" ]]; then
uid=$(getuid_witherror $1)
viewtask $uid
elif [[ $mode == "cleanup" ]]; then
inform "Deleting all completed tasks."
2021-06-03 08:56:54 +10:00
for id in ${!taskuid[@]}; do
uid=$(getuid $id)
2021-11-25 20:02:23 +11:00
[[ ${taskchecked[$id]} -eq 2 ]] && delq_add $uid
2021-06-03 08:56:54 +10:00
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
filter=all
fi
if [[ $filter == "all" ]]; then
2021-06-03 08:56:54 +10:00
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 ${taskparent[$id]} ]] && hasparent=0 || hasparent=1
2021-06-03 08:56:54 +10:00
[[ -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"
2021-11-25 20:02:23 +11:00
elif [[ $mode == "done" && ${taskchecked[$id]} -ne 2 ]]; then
match=1
elif [[ $mode == "notdone" && ${taskchecked[$id]} -ne 0 ]]; then
2021-06-03 08:56:54 +10:00
match=1
2021-11-25 20:02:23 +11:00
elif [[ $mode == "inprogress" && ${taskchecked[$id]} -ne 1 ]]; then
2021-06-03 08:56:54 +10:00
match=1
elif [[ $mode == "blocked" && ${taskchecked[$id]} -ne 3 ]]; then
match=1
elif [[ $mode == "list" && $hasparent -eq 0 ]]; then
match=1
2021-06-03 08:56:54 +10:00
fi
if [[ $match -eq 1 ]]; then
uids="$uids ${taskuid[$id]}"
fi
done
2021-11-07 10:48:34 +11:00
if [[ $WANTSORT -eq 1 ]]; then
uids=$(sortuidlist "$uids")
fi
if [[ ! $mode =~ $passive_modes ]]; then
info "About to run '$mode' on the following tasks:"
needtitle=0
for uid in $uids; do
2021-06-03 08:56:54 +10:00
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
inform "Aborted."
exit 1
2021-06-03 08:56:54 +10:00
fi
fi
2021-11-21 17:44:48 +11:00
elif [[ $filter =~ ^[0-9\ \-]+$ ]]; then
2021-06-03 08:56:54 +10:00
# list of task IDs
for wantid in $filter; do
2021-11-21 17:44:48 +11:00
if [[ $wantid =~ ^[0-9]+-[0-9]+$ ]]; then
s=${wantid%-*}
e=${wantid#*-}
for ((w2=s; w2<=e; w2++)); do
uids="$uids ${taskuid[$w2]}"
done
else
uids="$uids ${taskuid[$wantid]}"
fi
2021-06-03 08:56:54 +10:00
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
2022-03-23 19:06:56 +11:00
2021-06-03 08:56:54 +10:00
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
2021-11-25 20:02:23 +11:00
elif [[ $mode == "inprogress" ]]; then
markinprogress $uid
2021-06-03 08:56:54 +10:00
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 informs
2021-06-03 08:56:54 +10:00
if [[ $mode == "del" ]]; then
delq_process
fi
# remove duplicates where list contains both parent
# and child of parent
if [[ ! -z $processed ]]; then
for uid in ${processed}; do
thisid=$(getid $uid)
parentuid=${taskparent[$thisid]}
# is this NOT the child of something in the list
if [[ -z $parentuid || $processed != *$parentuid* ]]; then
newprocessed="$newprocessed $uid"
fi
done
processed="$newprocessed"
fi
2021-06-03 08:56:54 +10:00
if [[ ! -z $processed ]]; then
# show results
2021-06-03 08:56:54 +10:00
for uid in ${processed}; do
showit $uid
done
fi
fi
fi
2021-06-26 09:29:29 +10:00
if [[ $AUTOSYNC -eq 1 && $mode != "sync" ]]; then
tasksync -a
fi