2 # $MirOS: contrib/hosted/tg/progress-bar,v 1.6 2020/05/11 14:28:31 tg Exp $
4 # Copyright © 2018, 2020
5 # mirabilos <m@mirbsd.org>
7 # mirabilos <t.glaser@tarent.de>
8 # Copyright © 2015, 2017
9 # mirabilos <thorsten.glaser@teckids.org>
11 # Provided that these terms and disclaimer and all copyright notices
12 # are retained or reproduced in an accompanying document, permission
13 # is granted to deal in this work without restriction, including un‐
14 # limited rights to use, publicly perform, distribute, sell, modify,
15 # merge, give away, or sublicence.
17 # This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
18 # the utmost extent permitted by applicable law, neither express nor
19 # implied; without malicious intent or gross negligence. In no event
20 # may a licensor, author or contributor be held liable for indirect,
21 # direct, other damage, loss, or other issues arising in any way out
22 # of dealing in the work, even if advised of the possibility of such
23 # damage or existence of a defect, except proven that it results out
24 # of said person’s immediate fault when using the work as intended.
26 # Shell library for easy display of a progress bar
29 # – before: init_progress_bar $n
30 # – $n times: draw_progress_bar
31 # – after: done_progress_bar
33 # init_progress_bar trashes the EXIT and SIGWINCH traps, which later
34 # are cleared, again, by done_progress_bar; note this forces using a
35 # “while [[ -n $(jobs) ]]; do wait; done” loop instead of just wait.
36 # Use “redo_progress_bar [±]$n” to rerender updating the estimate.
38 # global variables used by this library
45 [[ $KSH_VERSION = '@(''#)MIRBSD KSH R'@(4[0-9]|5[0-4])\ * ]] || \
46 alias global='typeset -g'
48 # args: $1 = number of draw_progress_bar calls to make up 100%
49 function init_progress_bar {
50 global -i _cnt_progress_bar=$1 _cur_progress_bar=0
51 global -i nlin_progress_bar=$LINES isin_progress_bar=1
54 trap 'done_progress_bar $?' EXIT
55 trap 'sigwinch_progress_bar' WINCH
56 # set up scrolling region, draw initial empty bar
62 function sigwinch_progress_bar {
63 (( isin_progress_bar )) || return 0
65 # get new terminal size
66 nlin_progress_bar=$LINES
68 # save position; clear scrolling region; restore position; newline;
69 # up one line (to ensure we are not in the last line); save position;
70 # clear rest of screen; set new scrolling region; restore position
71 print -nu2 "\\e7\\e[0;0r\\e8\\n\\e[A\\e7\\e[J\\e[1;$((# nlin_progress_bar - 1))r\\e8"
74 draw_progress_bar_internal
77 function done_progress_bar {
78 (( isin_progress_bar )) || return 0
81 # save position; clear scrolling region; restore position;
82 # save position; clear rest of screen; restore position
83 print -nu2 "\\e7\\e[0;0r\\e8\\e7\\e[J\\e8"
86 [[ -z $1 ]] || return $1
87 (( _cur_progress_bar == _cnt_progress_bar )) || \
88 print -ru2 W: expected $_cnt_progress_bar draw_progress_bar calls, \
89 got only $_cur_progress_bar
92 function draw_progress_bar {
93 # increment current progress
94 if (( ++_cur_progress_bar > _cnt_progress_bar )); then
95 print -ru2 "W: too many draw_progress_bar calls"
96 _cur_progress_bar=$_cnt_progress_bar
98 # remaining drawing code
99 draw_progress_bar_internal
102 function redo_progress_bar {
103 if [[ $1 = +* ]]; then
104 (( (_cnt_progress_bar += ${1#+}), 1 ))
105 elif [[ $1 = -* ]]; then
106 (( (_cnt_progress_bar -= ${1#-}), 1 ))
108 (( (_cnt_progress_bar = $1), 1 ))
110 if (( _cur_progress_bar > _cnt_progress_bar )); then
111 print -ru2 W: new estimate $_cnt_progress_bar too low \
112 after $_cur_progress_bar calls
113 _cur_progress_bar=$_cnt_progress_bar
116 draw_progress_bar_internal
119 function draw_progress_bar_internal {
120 local bar num w=$COLUMNS pct
122 ((# (num = (_cur_progress_bar * w * 8) / _cnt_progress_bar), 1 ))
123 ((# (pct = _cur_progress_bar * 100 / _cnt_progress_bar), 1 ))
124 [[ $_cch_progress_bar != $num.$pct ]] || return 0
125 while ((# num >= 8 )); do
138 # fill complete line, right-align completion percentage display
139 local -R$w spc="$pct%"
140 # elide percentage when it stops fitting
141 ((# (_cur_progress_bar * w / _cnt_progress_bar) <= (w - 4) )) || spc=
142 # save position; go to last line; set colours;
143 # output a line full of spaces (and completion percentage);
144 # jump to first column; output bar (line præfix); restore position
145 print -nu2 -- "\\e7\\e[$nlin_progress_bar;1H\\e[0;1;33;44m$spc\\r$bar\\e8"
146 _cch_progress_bar=$num.$pct