fix(logging): render AUR progress animations to clean logs via terminal emulator
pacman/paru download progress is a multi-line terminal animation: it repaints lines in place using ANSI cursor-movement (ESC[<n>A) and erase-line (ESC[K) sequences, not just carriage returns. The previous line-wise regex approaches could not reconstruct this — frames either concatenated into one giant line (CR removed) or collapsed to blanks (CR kept), discarding the final 100% frame. Add scripts/clean_progress_log.py, a small dependency-free terminal screen-buffer emulator that replays the cursor movements against an in-memory grid and dumps the final static frame, preserving SGR color so logs still render with color in ov/bat/less -R. It also drops the script(1) header/footer. Both wrappers now pipe the raw PTY capture through this cleaner (bumped to version 5), falling back to stripping only the script(1) header when python3 is unavailable. Document the scripts/ dir and mechanism in AGENTS.md and docs/fish-config.md.
This commit is contained in:
@@ -2,8 +2,9 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# Generates ~/.local/bin/paru on first run (and on version bump) when
|
||||
# /usr/bin/paru is installed. The wrapper tees paru output to a
|
||||
# timestamped log file and prunes old logs, mirroring smart_exit behavior.
|
||||
# /usr/bin/paru is installed. The wrapper runs paru in a PTY so progress
|
||||
# bars are preserved, renders the captured animation to a clean static log
|
||||
# (via scripts/clean_progress_log.py), and prunes old logs.
|
||||
|
||||
# Auto-generating a wrapper in ~/.local/bin is opinionated (C2 auto-exec).
|
||||
# Wrapper generation is also gated by C5 (Logging & Capture).
|
||||
@@ -20,7 +21,7 @@ end
|
||||
|
||||
set -l _paru_real /usr/bin/paru
|
||||
set -l _paru_wrapper "$HOME/.local/bin/paru"
|
||||
set -l _paru_wrapper_version 4
|
||||
set -l _paru_wrapper_version 5
|
||||
|
||||
# Skip entirely if the real paru binary isn't present
|
||||
test -x $_paru_real; or return
|
||||
@@ -38,8 +39,8 @@ printf '%s\n' \
|
||||
'#!/usr/bin/env bash' \
|
||||
"# paru-wrapper-version: $_paru_wrapper_version" \
|
||||
'# Auto-generated by conf.d/paru-wrapper.fish — do not edit by hand.' \
|
||||
'# Runs paru in a PTY via script(1) so progress bars are preserved,' \
|
||||
'# then strips escape sequences from the captured log file.' \
|
||||
'# Runs paru in a PTY via script(1) so progress bars are preserved on screen,' \
|
||||
'# then renders the captured terminal animation to a clean static log.' \
|
||||
'' \
|
||||
'log_dir="${SCROLLBACK_HISTORY_DIR:-$HOME/.terminal_history}"' \
|
||||
'mkdir -p "$log_dir"' \
|
||||
@@ -54,8 +55,15 @@ printf '%s\n' \
|
||||
'script -q -e -c "$cmd_str" "$log_file"' \
|
||||
'exit_code=$?' \
|
||||
'' \
|
||||
'# Collapse CR-redrawn frames; keep ANSI codes for ov rendering; strip script(1) headers.' \
|
||||
'perl -ne '"'"'next if /^Script (started|done)/; s/\r$//; s/.*\r([^\r]+)$/$1/; print'"'"' < "$log_file" > "${log_file}.tmp" 2>/dev/null && mv "${log_file}.tmp" "$log_file" || rm -f "${log_file}.tmp"' \
|
||||
'# Render the captured terminal animation (progress bars repaint in place via' \
|
||||
'# cursor moves) down to its final static frame, preserving ANSI color. Falls' \
|
||||
'# back to dropping only the script(1) header/footer when python3 is missing.' \
|
||||
'cleaner="${XDG_CONFIG_HOME:-$HOME/.config}/fish/scripts/clean_progress_log.py"' \
|
||||
'if command -v python3 >/dev/null 2>&1 && [[ -f "$cleaner" ]]; then' \
|
||||
' python3 "$cleaner" < "$log_file" > "${log_file}.tmp" 2>/dev/null && mv "${log_file}.tmp" "$log_file" || rm -f "${log_file}.tmp"' \
|
||||
'else' \
|
||||
' sed -i "/^Script \(started\|done\) on /d" "$log_file" 2>/dev/null || true' \
|
||||
'fi' \
|
||||
'' \
|
||||
'max_files="${SCROLLBACK_HISTORY_MAX_FILES:-100}"' \
|
||||
'mapfile -t logs < <(ls -1t "$log_dir"/paru_*.log 2>/dev/null)' \
|
||||
|
||||
+15
-7
@@ -2,8 +2,9 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
#
|
||||
# Generates ~/.local/bin/yay on first run (and on version bump) when
|
||||
# /usr/bin/yay is installed. The wrapper tees yay output to a
|
||||
# timestamped log file and prunes old logs, mirroring smart_exit behavior.
|
||||
# /usr/bin/yay is installed. The wrapper runs yay in a PTY so progress
|
||||
# bars are preserved, renders the captured animation to a clean static log
|
||||
# (via scripts/clean_progress_log.py), and prunes old logs.
|
||||
|
||||
# Auto-generating a wrapper in ~/.local/bin is opinionated (C2 auto-exec).
|
||||
# Wrapper generation is also gated by C5 (Logging & Capture).
|
||||
@@ -20,7 +21,7 @@ end
|
||||
|
||||
set -l _yay_real /usr/bin/yay
|
||||
set -l _yay_wrapper "$HOME/.local/bin/yay"
|
||||
set -l _yay_wrapper_version 4
|
||||
set -l _yay_wrapper_version 5
|
||||
|
||||
# Skip entirely if the real yay binary isn't present
|
||||
test -x $_yay_real; or return
|
||||
@@ -38,8 +39,8 @@ printf '%s\n' \
|
||||
'#!/usr/bin/env bash' \
|
||||
"# yay-wrapper-version: $_yay_wrapper_version" \
|
||||
'# Auto-generated by conf.d/yay-wrapper.fish — do not edit by hand.' \
|
||||
'# Runs yay in a PTY via script(1) so progress bars are preserved,' \
|
||||
'# then strips escape sequences from the captured log file.' \
|
||||
'# Runs yay in a PTY via script(1) so progress bars are preserved on screen,' \
|
||||
'# then renders the captured terminal animation to a clean static log.' \
|
||||
'' \
|
||||
'log_dir="${SCROLLBACK_HISTORY_DIR:-$HOME/.terminal_history}"' \
|
||||
'mkdir -p "$log_dir"' \
|
||||
@@ -54,8 +55,15 @@ printf '%s\n' \
|
||||
'script -q -e -c "$cmd_str" "$log_file"' \
|
||||
'exit_code=$?' \
|
||||
'' \
|
||||
'# Collapse CR-redrawn frames; keep ANSI codes for ov rendering; strip script(1) headers.' \
|
||||
'perl -ne '"'"'next if /^Script (started|done)/; s/\r$//; s/.*\r([^\r]+)$/$1/; print'"'"' < "$log_file" > "${log_file}.tmp" 2>/dev/null && mv "${log_file}.tmp" "$log_file" || rm -f "${log_file}.tmp"' \
|
||||
'# Render the captured terminal animation (progress bars repaint in place via' \
|
||||
'# cursor moves) down to its final static frame, preserving ANSI color. Falls' \
|
||||
'# back to dropping only the script(1) header/footer when python3 is missing.' \
|
||||
'cleaner="${XDG_CONFIG_HOME:-$HOME/.config}/fish/scripts/clean_progress_log.py"' \
|
||||
'if command -v python3 >/dev/null 2>&1 && [[ -f "$cleaner" ]]; then' \
|
||||
' python3 "$cleaner" < "$log_file" > "${log_file}.tmp" 2>/dev/null && mv "${log_file}.tmp" "$log_file" || rm -f "${log_file}.tmp"' \
|
||||
'else' \
|
||||
' sed -i "/^Script \(started\|done\) on /d" "$log_file" 2>/dev/null || true' \
|
||||
'fi' \
|
||||
'' \
|
||||
'max_files="${SCROLLBACK_HISTORY_MAX_FILES:-100}"' \
|
||||
'mapfile -t logs < <(ls -1t "$log_dir"/yay_*.log 2>/dev/null)' \
|
||||
|
||||
Reference in New Issue
Block a user