sync from MirBSD CVS
[shellsnippets/shellsnippets.git] / mksh / uhr
index 4ad4c99..929d867 100644 (file)
--- a/mksh/uhr
+++ b/mksh/uhr
@@ -1,8 +1,8 @@
 #!/bin/mksh
-# $MirOS: contrib/hosted/tg/uhr,v 1.14 2013/02/19 18:07:46 tg Exp $
+# $MirOS: contrib/hosted/tg/uhr,v 1.17 2015/11/29 21:34:06 tg Exp $
 #-
-# Copyright © 2012, 2013
-#      Thorsten Glaser <tg@mirbsd.org>
+# Copyright © 2012, 2013, 2015
+#      mirabilos <m@mirbsd.org>
 #
 # Provided that these terms and disclaimer and all copyright notices
 # are retained or reproduced in an accompanying document, permission
@@ -33,17 +33,95 @@ typeset -Z6 tosleep
 bcopt=
 bc --help >/dev/null 2>&1 && bcopt=-q
 
+# global variables used by progress bar
+_cnt_progress_bar=0
+_cur_progress_bar=0
+isin_progress_bar=0
+nlin_progress_bar=0
+
+# args: $1 = number of draw_progress_bar calls to make up 100%
+function init_progress_bar {
+       global -i _cnt_progress_bar=$1 _cur_progress_bar=0
+       global -i nlin_progress_bar=$LINES isin_progress_bar=1
+
+       trap 'done_progress_bar' EXIT
+       # newline; up one line (to ensure we are not in the last line);
+       # save position; set scrolling region; restore position
+       print -n "\\n\\e[A\\e7\\e[1;$((# nlin_progress_bar - 1))r\\e8"
+}
+
+function sigwinch_uhr {
+       got_sigwinch=1
+       (( isin_progress_bar )) || return 0
+
+       # get new terminal size
+       nlin_progress_bar=$LINES
+       # newline; up one line (to ensure we are not in the last line);
+       # save position; set scrolling region; restore position
+       print -n "\\n\\e[A\\e7\\e[1;$((# nlin_progress_bar - 1))r\\e8"
+}
+
+function done_progress_bar {
+       (( isin_progress_bar )) || return 0
+       # save position; clear scrolling region;
+       # go to last line; delete line; restore position
+       print "\\e7\\e[0;0r\\e[$nlin_progress_bar;0H\\e[M\\e8"
+       isin_progress_bar=0
+       trap - EXIT
+}
+
+function draw_progress_bar {
+       local bar num w=$COLUMNS
+
+       ((# num = (++_cur_progress_bar * w * 8) / _cnt_progress_bar ))
+       while ((# num >= 8 )); do
+               bar+=█
+               ((# num -= 8 ))
+       done
+       case $num {
+       (7) bar+=▉ ;;
+       (6) bar+=▊ ;;
+       (5) bar+=▋ ;;
+       (4) bar+=▌ ;;
+       (3) bar+=▍ ;;
+       (2) bar+=▎ ;;
+       (1) bar+=▏ ;;
+       }
+       # fill complete line, right-align completion percentage display
+       local -R$w spc="$((# _cur_progress_bar * 100 / _cnt_progress_bar))%"
+       # elide percentage when it stops fitting
+       ((# (_cur_progress_bar * w / _cnt_progress_bar) > (w - 4) )) && spc=
+       # save position; go to last line; set colours;
+       # output a line full of spaces (and completion percentage);
+       # jump to first column; output bar (line præfix); restore position
+       print -n -- "\\e7\\e[$nlin_progress_bar;0H\\e[0;1;33;44m$spc\\r$bar\\e8"
+}
+
 function graceful {
        print -n '\033[;H\033[J'
        exit 0
 }
 trap graceful INT TERM HUP
 
-trap got_sigwinch=1 WINCH
+trap sigwinch_uhr WINCH
 while :; do
 got_sigwinch=0
 
-print "\e[0m\nPregenerating arrays, please wait..."
+init_progress_bar 135
+draw_progress_bar
+S='Pregenerating arrays, please wait...'
+if (( (r = (COLUMNS - ${%S}) / 2 - 2) < 1 )); then
+       d="\\e[0m\\n$S"
+else
+       d=
+       (( n = ${%S} + 2 ))
+       while (( n-- )); do
+               d+=─
+       done
+       d="\\e[0m\\e[$((LINES / 2 - 1));${r}H\\e7┌$d┐\\e8\\e[B│ $S │\\e8\\e[2B└$d┘"
+fi
+print "$d"
+
 (( r = LINES * 2 ))
 (( r = (r > COLUMNS ? COLUMNS : r) / 2 - 1))
 (( n = 2 * r + 1 ))
@@ -95,7 +173,7 @@ function refresh {
 # put arrayname x y
 function put {
        local _x=$(($2)) _y=$(($3)) _i
-       nameref _c=$4 _px=$1
+       nameref _px=$1
 
        (( _i = (r - _y) * n + _x + r ))
        _px+=($_i)
@@ -113,6 +191,8 @@ function retrace {
        px+=("${_px[@]}")
 }
 
+draw_progress_bar
+
 # precalculate all lines’ endpoints with bc and paths with Bresenham
 integer x y dx sx dy sy e f
 bc -l $bcopt |&
@@ -128,6 +208,7 @@ print -p 'define p(t) {
 # minutes and seconds – full length, 60 items
 i=-1
 while (( ++i < 60 )); do
+       draw_progress_bar
        eval set -A lms$i
        print -p "r * c(p($i * 6))"
        read -p S; [[ $S = ?(-).* ]] && S=0
@@ -158,6 +239,7 @@ done
 print -p 'r = o * 2 / 3'
 i=-1
 while (( ++i < 60 )); do
+       draw_progress_bar
        eval set -A lh$i
        print -p "r * c(p($i * 6))"
        read -p S; [[ $S = ?(-).* ]] && S=0
@@ -190,6 +272,7 @@ i=-1
 set -A mkx
 set -A mky
 while (( ++i < 12 )); do
+       draw_progress_bar
        print -p "r * c(p($i * 30))"
        read -p S; [[ $S = ?(-).* ]] && S=0
        mkx[i]=${S%%.*}
@@ -199,6 +282,7 @@ while (( ++i < 12 )); do
 done
 exec 3>&p; exec 3>&-
 
+draw_progress_bar
 (( L = LINES >= (COLUMNS / 2) ? (COLUMNS / 2) : LINES ))
 # fine-tuning of roman numeral position via screen size
 (( ++mkx[7] ))
@@ -241,6 +325,7 @@ case $L {
        ;;
 }
 (( mky[0] += 2 * (L & 1) ))
+done_progress_bar
 
 # clear framebuffer and screen
 set -A fb