Compare commits
5 Commits
1af7405bc2
...
ffcd6135f8
Author | SHA1 | Date |
---|---|---|
Yargo | ffcd6135f8 | |
Yargo | a5a73dd773 | |
Y | fdc00271af | |
Yargo | fdf854885a | |
wiko.Y90 | b37bcf455f |
243
clikan.sh
243
clikan.sh
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
# clikan.sh -- CLI Kanban
|
||||
ver='2021-01-23/HB9KNS'
|
||||
ver='2021-09-09/HB9KNS'
|
||||
|
||||
conf="${CLIKANCONF:-$HOME/.clikanconf}"
|
||||
defkanban="$HOME/clikanban.md"
|
||||
|
@ -8,7 +8,12 @@ editor="${CLIKANEDIT:-$VISUAL}"
|
|||
editor="${editor:-$EDITOR}"
|
||||
editor="${editor:-ed}"
|
||||
myshell='/bin/sh -c'
|
||||
|
||||
filtr='.'
|
||||
# pattern for target date and estimation: @YYYYMMDD:U.U
|
||||
# (contains two groups in parentheses)
|
||||
# if changed, also adjust line after TEPATT comment further down!
|
||||
tepatt=' @\([0-9][0-9]*\):\([0-9][.0-9]*\)'
|
||||
|
||||
buff=`mktemp -t clikanbXXXXXX` || buff=${TMPDIR:-/tmp}/clikanb$$`date +%S%M%d`
|
||||
self=`mktemp -t clikantXXXXXX` || self=${TMPDIR:-/tmp}/clikant$$`date +%S%M%d`
|
||||
|
@ -29,10 +34,22 @@ EOT
|
|||
# prompt is displayed when waiting for command
|
||||
prompt |<
|
||||
# maxshow defines the maximum number of cards/lines to be displayed
|
||||
maxshow 15
|
||||
maxshow 23
|
||||
# sortdir defines order of non-calendar kanban cards
|
||||
# and can be one of up, down or none (default)
|
||||
sortdir none
|
||||
sortdir up
|
||||
# if newdate is 1, yes or true (actually, begins with'[1tTyY]'),
|
||||
# then the current date will be appended to new cards/entries
|
||||
newdate true
|
||||
# planunit defines the name used for units (purely informative)
|
||||
planunit h/day
|
||||
# total units per period of scheduled tasks, e.g hours per day
|
||||
tunits 24
|
||||
# planpart defines the percentage of time available for working on
|
||||
# scheduled/planned tasks (integer value), for example
|
||||
# '10' means 10% of total time is usable, like 2.4 h/day
|
||||
# (tunits*planpart/100)
|
||||
planpart 10
|
||||
# kanban defines a kanban file, may be given several times
|
||||
# kanban /some/path/to/jobkanban.txt
|
||||
# kanban /another/path/to/privatekanban.md
|
||||
|
@ -92,6 +109,7 @@ getselect(){
|
|||
fi
|
||||
}
|
||||
|
||||
# read config, set default values if missing
|
||||
kbs="`getlines kanban <"$conf"`"
|
||||
currkan="`echo "$kbs" | head -n 1`"
|
||||
prompt=`getlines prompt <"$conf" | head -n 1`
|
||||
|
@ -99,6 +117,17 @@ maxshow=`getlines maxshow <"$conf" | head -n 1`
|
|||
maxshow=${maxshow:-22}
|
||||
sortdir=`getlines sortdir <"$conf" | head -n 1`
|
||||
sortdir=${sortdir:-none}
|
||||
nd=`getlines newdate <"$conf" | head -n 1`
|
||||
case $nd in
|
||||
1|[yY]*|[tT]*) newdate=true ;;
|
||||
*) newdate=false ;;
|
||||
esac
|
||||
planpart=`getlines planpart <"$conf" | head -n 1`
|
||||
planpart=${planpart:-10}
|
||||
planunit=`getlines planunit <"$conf" | head -n 1`
|
||||
planunit=${planunit:-h/day}
|
||||
tunits=`getlines tunits <"$conf" | head -n 1`
|
||||
tunits=${tunits:-24}
|
||||
|
||||
showprompt(){
|
||||
if test "$prompt" != ""
|
||||
|
@ -143,17 +172,17 @@ showall(){
|
|||
fi | showselect "$f " | head -n $ms
|
||||
}
|
||||
|
||||
# replace lines (in any kanban) containing some ed pattern
|
||||
# arg.1=pattern, remainder=new line contents
|
||||
# replace lines (in any kanban) containing some string
|
||||
# arg.1=string, remainder=new line contents
|
||||
repline(){
|
||||
local patt newl
|
||||
patt="$1"
|
||||
local strg newl
|
||||
strg="$1"
|
||||
shift
|
||||
newl="$*"
|
||||
for ff in $kbs
|
||||
do cat "$ff" > $buff
|
||||
cat $buff | { while read oldl
|
||||
do if test "`echo \"$oldl\"`" = "$patt"
|
||||
do if test "`echo \"$oldl\"`" = "$strg"
|
||||
then echo "$newl"
|
||||
else echo "$oldl"
|
||||
fi
|
||||
|
@ -192,22 +221,57 @@ command keys:
|
|||
do N: put card N into doing state
|
||||
note: done/wait/do accept several arguments separated by white space
|
||||
f F: filter cards for grep pattern F (empty='.')
|
||||
p: show planning (time scheduling) for active (doing) cards containing
|
||||
@YYMMDD/U.U target date (YYMMDD) and expected duration (U.U)
|
||||
h N U.U [[YY]MMDD]: update expected duration for card N and
|
||||
optionally set new target date [YY]MMDD
|
||||
(asks for date if card is missing @YYMMDD)
|
||||
ec: directly edit config file -- DANGER!
|
||||
ek: directly edit kanban file -- DANGER!
|
||||
!: execute arguments with "$myshell"
|
||||
note: if the command does not match to any of the
|
||||
internal $0 commands, and starts with a letter,
|
||||
note: if the command does not match any of the
|
||||
internal commands, and starts with a letter,
|
||||
you can even omit the leading exclamation mark!
|
||||
EOH
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# simple date number calculation:
|
||||
# assume each month has 30 days
|
||||
datnum() {
|
||||
local dn ds
|
||||
# normalize to YYYYMMDD
|
||||
if test "${1%????}" = ""
|
||||
then ds=`date +%Y`$1
|
||||
elif test "${1%??????}" = ""
|
||||
then ds=$century$1
|
||||
else ds=$1
|
||||
fi
|
||||
# 12*YYYY
|
||||
dn=$(( 12*${ds%????} ))
|
||||
# remove leading YYYY
|
||||
ds=${ds#????}
|
||||
# add 1MM, subtract 100, multiply by 30
|
||||
dn=$(( 30*($dn+1${ds%??}-100) ))
|
||||
# add 1DD, subtract 100
|
||||
dn=$(( $dn+1${ds#??}-100 ))
|
||||
echo $dn
|
||||
}
|
||||
|
||||
showall doing
|
||||
showprompt
|
||||
|
||||
while read com coa1 coa2 coa3 coar
|
||||
do case $com in
|
||||
do
|
||||
year=`date +%y`
|
||||
longyear=`date +%Y`
|
||||
century=${longyear%??}
|
||||
month=`date +%m`
|
||||
day=`date +%d`
|
||||
today=$year-$month-$day
|
||||
stoday=$century$year$month$day
|
||||
case $com in
|
||||
q) break ;;
|
||||
d) showall doing ;;
|
||||
w) showall waiting/todo/backlog ;;
|
||||
|
@ -216,19 +280,22 @@ do|wait|done) if test "$coa1" = ""
|
|||
then echo "card number?"
|
||||
read coa1
|
||||
fi
|
||||
coar=`echo "$coa1 $coa2 $coa3 $coar" | sed -e 's/ *$/ /'`
|
||||
coar=`echo "$coa1 $coa2 $coa3 $coar" | tr -cd ' 0-9' | sed -e 's/ *$/ /'`
|
||||
if test "$coar" = " "
|
||||
then coar=''
|
||||
fi
|
||||
while test "$coar" != ""
|
||||
do
|
||||
coa1=`getlines ${coar%% *} <$self`
|
||||
stamp=''
|
||||
case $com in
|
||||
done) coa2='+'
|
||||
stamp=`date '+ // %y-%m-%d'`
|
||||
stamp=" // $today"
|
||||
;;
|
||||
wait) coa2='-' ;;
|
||||
*) coa2='*' ;;
|
||||
esac
|
||||
coa3=`echo "$coa1" | sed -e "s/^./$coa2/"`
|
||||
coa3="$coa2${coa1#?}"
|
||||
repline "$coa1" "$coa3$stamp"
|
||||
coar=${coar#* }
|
||||
done
|
||||
|
@ -241,12 +308,16 @@ k) echo "$kbs" | showselect
|
|||
n) newc=`echo "$coa1 $coa2 $coa3 $coar" | sed -e 's/ *$//'`
|
||||
if test "$newc" = ""
|
||||
then
|
||||
echo enter new card for target $currkan :
|
||||
echo enter new card for kanban file $currkan :
|
||||
read newc
|
||||
else echo adding card for target $currkan
|
||||
else echo adding card for kanban file $currkan
|
||||
fi
|
||||
if test $newdate = true
|
||||
then stamp=" // $today"
|
||||
else stamp=''
|
||||
fi
|
||||
if test "$newc" != ""
|
||||
then echo '*' "$newc" >>$currkan
|
||||
then echo '*' "$newc$stamp" >>$currkan
|
||||
else echo no content found, nothing added
|
||||
fi
|
||||
showall doing
|
||||
|
@ -258,6 +329,144 @@ ek) echo calling "$editor $currkan" ...
|
|||
"$editor" "$currkan" ;;
|
||||
f) filtr="${coa1:-.}"
|
||||
echo "filtering for grep pattern '$filtr'" ;;
|
||||
p) echo "## planning for $planpart% of $tunits $planunit"
|
||||
# generate list, but hidden
|
||||
showall doing >/dev/null
|
||||
# total current capacity in 0.1 units, to calculate limit
|
||||
# (planpart is in %=0.01 units, divide by 10 to get in 0.1)
|
||||
cap=$(( $tunits*$planpart/10 ))
|
||||
now=`datnum $stoday`
|
||||
echo "$planunit task"
|
||||
# get all tasks with planning information, sorted
|
||||
grep "$tepatt" $self | sort -k 2 | { while read nr flag task
|
||||
do
|
||||
# set weight for assigned time depending on priority value
|
||||
case $task in
|
||||
1*) w8=8 ;;
|
||||
2*) w8=6 ;;
|
||||
3*) w8=4 ;;
|
||||
4*) w8=2 ;;
|
||||
5*) w8=1 ;;
|
||||
*) w8=3 ;;
|
||||
esac
|
||||
# get target date number of task, and normalize
|
||||
tdate=`echo "$task" | sed -e "s/.*$tepatt.*/\1/"`
|
||||
tnum=`datnum $tdate`
|
||||
# difference in days
|
||||
td=$(( $tnum-$now ))
|
||||
# set minimum delta and mark
|
||||
if test $td -gt 0
|
||||
then tmark=' '
|
||||
else
|
||||
td=1
|
||||
tmark='*'
|
||||
fi
|
||||
# get estimated units for task, append '.0' to force decimal notation,
|
||||
# remove dot, keep one decimal and truncate additional figures
|
||||
# (i.e multiply by 10), remove leading 0s
|
||||
# TODO: following 2 lines are really ugly, should be simplified...
|
||||
tunits=`echo "$task" | sed -e "s/.*$tepatt.*/\2/;s/$/.0/;s/[.]\([0-9]\).*/\1/;s/^0*//"`
|
||||
# if empty, set to 0
|
||||
tunits=${tunits:-0}
|
||||
# assign 2*weight/8*tunits/days per task, but not more than estimated units
|
||||
tcap=$(( $w8/4*$tunits/$td ))
|
||||
if test $tcap -gt $tunits
|
||||
then tcap=$tunits
|
||||
# or at least 0.1
|
||||
elif test $tcap -lt 1
|
||||
then tcap=1
|
||||
fi
|
||||
# result: today's amount / (mark) / task nr / task
|
||||
tres="$tcap $tmark$nr: $task"
|
||||
if test $tcap -gt 99
|
||||
then
|
||||
# remove trailing figure for values of 10 (100) or higher
|
||||
echo "$tres" | sed -e 's/. / /'
|
||||
else
|
||||
# for smaller, insert decimal and prepend 0 if missing
|
||||
echo "$tres" | sed -e 's/\(.\) /.\1 /;s/^[.]/0./'
|
||||
fi
|
||||
if test $cap -gt 0
|
||||
then cap=$(( $cap-$tcap ))
|
||||
if test $cap -le 0
|
||||
then echo ' (capacity limit reached)'
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
;;
|
||||
h) if test "$coa1" = ""
|
||||
then echo "card number?"
|
||||
read coa1
|
||||
fi
|
||||
if test "$coa1" = ""
|
||||
then showprompt
|
||||
continue
|
||||
fi
|
||||
coa1=`echo "$coa1" | tr -cd '0-9'`
|
||||
oldl=`getlines $coa1 <$self`
|
||||
newl="$oldl"
|
||||
echo ": ${oldl#??}"
|
||||
if test "$coa2" = ""
|
||||
then echo "new estimated time requirement?"
|
||||
read coa2
|
||||
fi
|
||||
coa2=`echo "$coa2" | tr -cd '.0-9'`
|
||||
if test "$coa2" = ""
|
||||
then showprompt
|
||||
continue
|
||||
fi
|
||||
# arg.3 will override existing target date
|
||||
if test "$coa3" = ""
|
||||
then
|
||||
# search for ' @YYYYMMDD/U.U' and get YYYYMMDD
|
||||
odat=`echo "$oldl" | sed -e "s/.*$tepatt.*/\1/"`
|
||||
# if nothing found, ask for target date
|
||||
if test "$odat" = "$oldl"
|
||||
then
|
||||
echo "target date [YYYY]MMDD?"
|
||||
read coa3
|
||||
# add dummy for later pattern replacement
|
||||
newl="$newl @1:2"
|
||||
else
|
||||
coa3=$odat
|
||||
fi
|
||||
else
|
||||
# remove old pattern and add dummy for later
|
||||
newl=`echo "$oldl" | sed -e "s/\\(.*\\)$tepatt\\(.*\\)/\\1 @1:2\\4/"`
|
||||
# force if nothing yet found
|
||||
if test "$newl" = "$oldl"
|
||||
then newl="$newl @1:2"
|
||||
fi
|
||||
fi
|
||||
coa3=`echo $coa3 | tr -cd '0-9'`
|
||||
if test "$coa3" = ""
|
||||
then coa3=$stoday
|
||||
echo "(empty/malformed date, using today=$coa3 instead)"
|
||||
fi
|
||||
# handle [YY]MMDD dates
|
||||
# prepend 1 to prevent interpretation of leading 0 as octal
|
||||
# (use 9999 instead of 1231 to cope with bogus inputs)
|
||||
if test 1$coa3 -le 19999
|
||||
then
|
||||
# compare with today's MMDD
|
||||
if test 1$coa3 -lt 1$month$day
|
||||
# before, use next year, else this year
|
||||
then coa3="$(( 1+$century$year ))$coa3"
|
||||
else coa3="$century$year$coa3"
|
||||
fi
|
||||
elif test 1$coa3 -le 1999999
|
||||
# prepend century if missing
|
||||
then coa3=$century$coa3
|
||||
fi
|
||||
# TEPATT: adjust replacement string if $tepatt changed!
|
||||
# (last reference is group 4 because of two groups in tepatt)
|
||||
coar=`echo "$newl" | sed -e "s/\\(.*\\)$tepatt\\(.*\\)/\\1 @$coa3:$coa2\\4/"`
|
||||
echo was: "$oldl"
|
||||
echo now: "$coar"
|
||||
repline "$oldl" "$coar"
|
||||
showall doing
|
||||
;;
|
||||
!*) echo
|
||||
$myshell "${com#!} $coa1 $coa2 $coa3 $coar"
|
||||
echo ;;
|
||||
|
|
Loading…
Reference in New Issue