ui_quiet_run now paints a TTY-safe status BLOCK: a background-coloured
SPACE (never a glyph, no font/locale dependency — the braille lesson).
busy : blue block breathing through a 256-colour ramp (48;5;17..33)
with the live dnf action after it
ok : solid green block + package count
fail : solid RED block (spec: YuKu changed the red X to a red block)
followed by the log tail
Colour-depth aware: 256-colour ramp -> 16-colour blue/bright-blue ->
plain ASCII spinner when the terminal reports no colour. LANG=C pty
run shows zero non-ASCII bytes.
Also vendors lib/ui-block.sh (the standalone helper from the Telegram
session prototype; fail changed to red block) and installs the
ui_block_close EXIT trap — with a return 0, because an EXIT trap's
status becomes the script's exit code (harness caught every-successful-
run exiting 1 through that path).
116 lines
3.0 KiB
Bash
116 lines
3.0 KiB
Bash
#!/usr/bin/env bash
|
|
# ui-block.sh - TTY-safe status "block" indicator (no special fonts)
|
|
#
|
|
# busy : blue block that "breathes" (background colour pulses)
|
|
# ok : solid green block
|
|
# fail : solid red block (changed from red X per YuKu's spec)
|
|
#
|
|
# Why this works on a bare TTY: the "block" is a BACKGROUND-COLOURED SPACE,
|
|
# not a U+2588 glyph. No fonts, no UTF-8, no locale dependency.
|
|
#
|
|
# Draws on /dev/tty, never stdout: ui_choose/ui_confirm capture stdout with $(),
|
|
# so a status line on stdout would corrupt every captured answer.
|
|
|
|
_UB_FD=""
|
|
_UB_PID=""
|
|
_UB_MSG=""
|
|
|
|
_ub_tty() {
|
|
if [[ -z "$_UB_FD" ]]; then
|
|
# probe first: a bare `exec {fd}>/dev/tty` failure still prints its error
|
|
{ : >/dev/tty; } 2>/dev/null || { _UB_FD=""; return 1; }
|
|
exec {_UB_FD}>/dev/tty 2>/dev/null || { _UB_FD=""; return 1; }
|
|
fi
|
|
[[ -n "$_UB_FD" ]]
|
|
}
|
|
|
|
_ub_depth() {
|
|
local n
|
|
n=$(tput colors 2>/dev/null || echo 0)
|
|
case "$n" in ''|*[!0-9]*) n=0 ;; esac
|
|
if [[ "$n" -ge 256 ]]; then echo 256
|
|
elif [[ "$n" -ge 8 ]]; then echo 16
|
|
else echo 0; fi
|
|
}
|
|
|
|
# paint one background-coloured block (a SPACE) + message
|
|
_ub_paint() {
|
|
printf '\r\033[%sm \033[0m %s' "$1" "$2" >&"$_UB_FD"
|
|
}
|
|
|
|
_ub_busy_loop() {
|
|
local depth pal=() i
|
|
depth=$(_ub_depth)
|
|
case "$depth" in
|
|
256) pal=(17 18 19 20 21 27 33 27 21 20 19 18) ;; # blue breathe
|
|
16) pal=(44 104 44 104) ;; # blue / bright blue
|
|
*) pal=("|" "/" "-" "\\") ;; # last-resort spinner
|
|
esac
|
|
while :; do
|
|
for i in "${pal[@]}"; do
|
|
if [[ "$depth" -eq 256 ]]; then
|
|
_ub_paint "48;5;$i" "$_UB_MSG" # 256-colour cube background
|
|
elif [[ "$depth" -eq 16 ]]; then
|
|
_ub_paint "$i" "$_UB_MSG" # plain ANSI background (44/104)
|
|
else
|
|
printf '\r[%s] %s' "$i" "$_UB_MSG" >&"$_UB_FD"
|
|
fi
|
|
sleep 0.08 || return 0
|
|
done
|
|
done
|
|
}
|
|
|
|
_ub_stop() {
|
|
if [[ -n "$_UB_PID" ]]; then
|
|
kill "$_UB_PID" 2>/dev/null
|
|
wait "$_UB_PID" 2>/dev/null
|
|
_UB_PID=""
|
|
fi
|
|
}
|
|
|
|
ui_block_start() {
|
|
_UB_MSG="${1:-Working}"
|
|
_ub_tty || return 0 # no tty: silent no-op
|
|
_ub_stop
|
|
_ub_busy_loop &
|
|
_UB_PID=$!
|
|
}
|
|
|
|
ui_block_ok() {
|
|
local msg="${1:-Done}" d
|
|
_ub_tty || return 0
|
|
_ub_stop
|
|
d=$(_ub_depth)
|
|
case "$d" in
|
|
256) _ub_paint "48;5;34" "$msg" ;;
|
|
16) _ub_paint "42" "$msg" ;;
|
|
*) printf '\r[OK] %s' "$msg" >&"$_UB_FD" ;;
|
|
esac
|
|
printf '\033[0m\n' >&"$_UB_FD"
|
|
}
|
|
|
|
ui_block_fail() {
|
|
local msg="${1:-Failed}" d
|
|
_ub_tty || return 0
|
|
_ub_stop
|
|
d=$(_ub_depth)
|
|
case "$d" in
|
|
256) printf '\r\033[48;5;196m \033[0m %s' "$msg" >&"$_UB_FD" ;;
|
|
16) printf '\r\033[41m \033[0m %s' "$msg" >&"$_UB_FD" ;;
|
|
*) printf '\r[!] %s' "$msg" >&"$_UB_FD" ;;
|
|
esac
|
|
printf '\n' >&"$_UB_FD"
|
|
}
|
|
|
|
ui_block_close() {
|
|
_ub_stop
|
|
if [[ -n "$_UB_FD" ]]; then
|
|
exec {_UB_FD}>&- 2>/dev/null
|
|
_UB_FD=""
|
|
fi
|
|
return 0 # an EXIT trap's status becomes the script's exit code — never fail here
|
|
}
|
|
|
|
# ALWAYS install a cleanup trap in the sourcing script:
|
|
# trap 'ui_block_close' EXIT INT TERM
|