# -*- mode: sh -*- #- # Copyright © 2017 # mirabilos # Copyright © 2015, 2017 # mirabilos # # Provided that these terms and disclaimer and all copyright notices # are retained or reproduced in an accompanying document, permission # is granted to deal in this work without restriction, including un‐ # limited rights to use, publicly perform, distribute, sell, modify, # merge, give away, or sublicence. # # This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to # the utmost extent permitted by applicable law, neither express nor # implied; without malicious intent or gross negligence. In no event # may a licensor, author or contributor be held liable for indirect, # direct, other damage, loss, or other issues arising in any way out # of dealing in the work, even if advised of the possibility of such # damage or existence of a defect, except proven that it results out # of said person’s immediate fault when using the work as intended. #- # Shell library for easy display of a progress bar # # Usage: # – before: init_progress_bar $n # – $n times: draw_progress_bar # – after: done_progress_bar # # init_progress_bar trashes the EXIT and SIGWINCH traps, which later # are cleared, again, by done_progress_bar. Note that signals do not # work well with “wait” except in a “while [[ -n $(jobs) ]]” loop. # global variables used by this library _cnt_progress_bar=0 _cur_progress_bar=0 isin_progress_bar=0 nlin_progress_bar=0 if [[ $KSH_VERSION = @(\@\(#\)MIRBSD KSH R)@(5[5-9]|[6-9][0-9]|[1-9][0-9][0-9])\ * ]]; then alias global='typeset -g' else alias global=global fi # 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 1' EXIT trap 'sigwinch_progress_bar' WINCH # set up scrolling region, draw initial empty bar sigwinch_progress_bar } unalias global function sigwinch_progress_bar { (( isin_progress_bar )) || return 0 # get new terminal size nlin_progress_bar=$LINES # save position; clear scrolling region; restore position; newline; # up one line (to ensure we are not in the last line); save position; # clear rest of screen; set new scrolling region; restore position print -nu2 "\\e7\\e[0;0r\\e8\\n\\e[A\\e7\\e[J\\e[1;$((# nlin_progress_bar - 1))r\\e8" # redraw progress bar draw_progress_bar_internal } function done_progress_bar { (( isin_progress_bar )) || return 0 isin_progress_bar=0 # save position; clear scrolling region; restore position; # save position; clear rest of screen; restore position print -nu2 "\\e7\\e[0;0r\\e8\\e7\\e[J\\e8" trap - WINCH trap - EXIT [[ -n $1 ]] || (( _cur_progress_bar == _cnt_progress_bar )) || \ print -ru2 W: expected $_cnt_progress_bar draw_progress_bar calls, \ got only $_cur_progress_bar } function draw_progress_bar { # increment current progress if (( ++_cur_progress_bar > _cnt_progress_bar )); then print -ru2 "W: too many draw_progress_bar calls" _cur_progress_bar=$_cnt_progress_bar fi # remaining drawing code draw_progress_bar_internal } function draw_progress_bar_internal { 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 -nu2 -- "\\e7\\e[$nlin_progress_bar;1H\\e[0;1;33;44m$spc\\r$bar\\e8" }