Status blocks replace the spinner: blue breathing / green / red

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).
This commit is contained in:
Pathfinder
2026-10-27 22:32:58 +01:00
parent 49ea36e089
commit 9c0b716758
3 changed files with 165 additions and 15 deletions
+46 -15
View File
@@ -101,43 +101,74 @@ ui_quiet_run() {
before=$(wc -l < "$log" 2>/dev/null || echo 0)
# Child writes to the log; we draw a LIVE line: spinner frame + the package
# dnf is currently working on. gum spin was tried here first but rendered
# as a frozen block on the real VM ("looks like it hangs") — this variant
# animates independently of gum and shows real progress, not just motion.
# ---- status BLOCK (TTY-safe: a background-coloured SPACE, never a glyph) --
# busy: blue block that breathes (bg-colour ramp) + current dnf action
# ok : solid green block + package count
# fail: solid RED block (spec change from the X, per YuKu)
# Colour-depth aware: 256 -> ramp, 16 -> blue/bright-blue, none -> ASCII.
local depth=0 nc
nc=$(tput colors 2>/dev/null || echo 0)
case "$nc" in ''|*[!0-9]*) nc=0 ;; esac
if (( nc >= 256 )); then depth=256
elif (( nc >= 8 )); then depth=16
fi
local -a bg=()
case "$depth" in
256) bg=( "48;5;17" "48;5;19" "48;5;21" "48;5;27" "48;5;33" "48;5;27" "48;5;21" "48;5;19" ) ;;
16) bg=( "44" "104" "44" "104" ) ;;
esac
local -a ch=( "|" "/" "-" "\\" )
"$@" >>"$log" 2>&1 &
local pid=$!
# ASCII frames ONLY: braille/em-dash are multibyte UTF-8 and rendered as
# garbage letters when the session locale is not UTF-8 (VM-proven: the
# spinner appeared as changing random chars, not as a spinner).
local frames=( '|' '/' '-' '\\' )
local f=0 cur
while kill -0 "$pid" 2>/dev/null; do
cur=$(sed -n "$((before+1)),\$p" "$log" 2>/dev/null \
| grep -E '^(Installing|Upgrading|Downgrading|Removing|Verifying|Preparing|Cleanup):' \
| tail -n 1 || true)
if [[ -n "$cur" ]]; then
printf '\r %s %s: %s' "${frames[$f]}" "$msg" "$cur" >&2
if (( depth >= 16 )); then
if [[ -n "$cur" ]]; then
printf '\r\033[%sm \033[0m %s: %s' "${bg[$(( f % ${#bg[@]} ))]}" "$msg" "$cur" >&2
else
printf '\r\033[%sm \033[0m %s' "${bg[$(( f % ${#bg[@]} ))]}" "$msg" >&2
fi
else
printf '\r %s %s' "${frames[$f]}" "$msg" >&2
if [[ -n "$cur" ]]; then
printf '\r %s %s: %s' "${ch[$(( f % ${#ch[@]} ))]}" "$msg" "$cur" >&2
else
printf '\r %s %s' "${ch[$(( f % ${#ch[@]} ))]}" "$msg" >&2
fi
fi
f=$(( (f + 1) % ${#frames[@]} ))
f=$(( f + 1 ))
sleep 0.15
done
local rc=0
wait "$pid" || rc=$?
# wipe the progress line before printing the result
printf '\r%*s\r' 100 '' >&2
if (( rc == 0 )); then
n=$(sed -n "$((before+1)),\$p" "$log" 2>/dev/null | grep -c '^Installing:' || true)
local plural="s"
(( n == 1 )) && plural=""
ok "$msg (${n} package${plural})"
if (( depth == 256 )); then
printf '\033[48;5;34m \033[0m %s (%s package%s)\n' "$msg" "$n" "$plural" >&2
elif (( depth == 16 )); then
printf '\033[42m \033[0m %s (%s package%s)\n' "$msg" "$n" "$plural" >&2
else
ok "$msg (${n} package${plural})"
fi
return 0
else
color_red " Failed: $msg"
if (( depth == 256 )); then
printf '\033[48;5;196m \033[0m %s\n' "$msg" >&2
elif (( depth == 16 )); then
printf '\033[41m \033[0m %s\n' "$msg" >&2
else
color_red " Failed: $msg"
fi
color_red " (dnf reported a transaction failure)"
color_red " Last lines from $log:"
sed -n "$((before+1)),\$p" "$log" 2>/dev/null | tail -n 20 | sed 's/^/ /' >&2
return "$rc"