mirror of
https://github.com/tw93/Mole.git
synced 2026-03-22 20:15:07 +00:00
fix(purge): rewrite spinner for /dev/tty reliability and fix cursor position
- Capture terminal width in parent before forking; avoids unreliable tput calls inside the background subshell - Write spinner output directly to /dev/tty to prevent stdout state contention between parent and background processes - Use \033[2K (erase entire line) instead of \033[K (erase to EOL) - Add handle_interrupt() so Ctrl-C cleanly stops spinner, restores cursor, and exits 130 - cleanup_monitor now writes \r\033[2K\n so subsequent output starts on a clean line rather than on the cleared spinner line
This commit is contained in:
109
bin/purge.sh
109
bin/purge.sh
@@ -50,7 +50,6 @@ start_purge() {
|
|||||||
if [[ -t 1 ]]; then
|
if [[ -t 1 ]]; then
|
||||||
printf '\033[2J\033[H'
|
printf '\033[2J\033[H'
|
||||||
fi
|
fi
|
||||||
printf '\n'
|
|
||||||
|
|
||||||
# Initialize stats file in user cache directory
|
# Initialize stats file in user cache directory
|
||||||
local stats_dir="${XDG_CACHE_HOME:-$HOME/.cache}/mole"
|
local stats_dir="${XDG_CACHE_HOME:-$HOME/.cache}/mole"
|
||||||
@@ -83,87 +82,89 @@ perform_purge() {
|
|||||||
wait "$monitor_pid" 2> /dev/null || true
|
wait "$monitor_pid" 2> /dev/null || true
|
||||||
fi
|
fi
|
||||||
if [[ -t 1 ]]; then
|
if [[ -t 1 ]]; then
|
||||||
printf '\r\033[K\n\033[K\033[A'
|
printf '\r\033[2K\n' > /dev/tty 2> /dev/null || true
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Set up trap for cleanup
|
# Ensure Ctrl-C/TERM always stops spinner(s) and exits immediately.
|
||||||
trap cleanup_monitor INT TERM
|
handle_interrupt() {
|
||||||
|
cleanup_monitor
|
||||||
|
stop_inline_spinner 2> /dev/null || true
|
||||||
|
show_cursor 2> /dev/null || true
|
||||||
|
printf '\n' >&2
|
||||||
|
exit 130
|
||||||
|
}
|
||||||
|
|
||||||
# Show scanning with spinner on same line as title
|
# Set up trap for cleanup + abort
|
||||||
|
trap handle_interrupt INT TERM
|
||||||
|
|
||||||
|
# Show scanning with spinner below the title line
|
||||||
if [[ -t 1 ]]; then
|
if [[ -t 1 ]]; then
|
||||||
# Print title first
|
# Print title ONCE with newline; spinner occupies the line below
|
||||||
printf '%s' "${PURPLE_BOLD}Purge Project Artifacts${NC} "
|
printf '%s\n' "${PURPLE_BOLD}Purge Project Artifacts${NC}"
|
||||||
|
|
||||||
# Start background monitor with ASCII spinner
|
# Capture terminal width in parent (most reliable before forking)
|
||||||
|
local _parent_cols=80
|
||||||
|
local _stty_out
|
||||||
|
if _stty_out=$(stty size < /dev/tty 2> /dev/null); then
|
||||||
|
_parent_cols="${_stty_out##* }" # "rows cols" -> take cols
|
||||||
|
else
|
||||||
|
_parent_cols=$(tput cols 2> /dev/null || echo 80)
|
||||||
|
fi
|
||||||
|
[[ "$_parent_cols" =~ ^[0-9]+$ && $_parent_cols -gt 0 ]] || _parent_cols=80
|
||||||
|
|
||||||
|
# Start background monitor: writes directly to /dev/tty to avoid stdout state issues
|
||||||
(
|
(
|
||||||
local spinner_chars="|/-\\"
|
local spinner_chars="|/-\\"
|
||||||
local spinner_idx=0
|
local spinner_idx=0
|
||||||
local last_path=""
|
local last_path=""
|
||||||
|
# Use parent-captured width; never refresh inside the loop (avoids unreliable tput in bg)
|
||||||
|
local term_cols="$_parent_cols"
|
||||||
|
# Visible prefix "| Scanning " = 11 chars; reserve 25 total for safety margin
|
||||||
|
local max_path_len=$((term_cols - 25))
|
||||||
|
((max_path_len < 5)) && max_path_len=5
|
||||||
|
|
||||||
# Set up trap to exit cleanly
|
# Set up trap to exit cleanly (erase the spinner line via /dev/tty)
|
||||||
trap 'exit 0' INT TERM
|
trap 'printf "\r\033[2K" >/dev/tty 2>/dev/null; exit 0' INT TERM
|
||||||
|
|
||||||
# Function to truncate path in the middle
|
# Truncate path to guaranteed fit
|
||||||
truncate_path() {
|
truncate_path() {
|
||||||
local path="$1"
|
local path="$1"
|
||||||
local term_cols
|
if [[ ${#path} -le $max_path_len ]]; then
|
||||||
term_cols=$(tput cols 2> /dev/null || echo 80)
|
|
||||||
# Reserve some space for the spinner and text (approx 20 chars)
|
|
||||||
local max_len=$((term_cols - 20))
|
|
||||||
# Ensure a reasonable minimum width
|
|
||||||
if ((max_len < 40)); then
|
|
||||||
max_len=40
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${#path} -le $max_len ]]; then
|
|
||||||
echo "$path"
|
echo "$path"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
local side_len=$(((max_path_len - 3) / 2))
|
||||||
# Calculate how much to show on each side
|
echo "${path:0:$side_len}...${path: -$side_len}"
|
||||||
local side_len=$(((max_len - 3) / 2))
|
|
||||||
local start="${path:0:$side_len}"
|
|
||||||
local end="${path: -$side_len}"
|
|
||||||
echo "${start}...${end}"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while [[ -f "$stats_dir/purge_scanning" ]]; do
|
while [[ -f "$stats_dir/purge_scanning" ]]; do
|
||||||
local current_path=$(cat "$stats_dir/purge_scanning" 2> /dev/null || echo "")
|
local current_path
|
||||||
local display_path=""
|
current_path=$(cat "$stats_dir/purge_scanning" 2> /dev/null || echo "")
|
||||||
|
|
||||||
if [[ -n "$current_path" ]]; then
|
if [[ -n "$current_path" ]]; then
|
||||||
display_path="${current_path/#$HOME/~}"
|
local display_path="${current_path/#$HOME/~}"
|
||||||
display_path=$(truncate_path "$display_path")
|
display_path=$(truncate_path "$display_path")
|
||||||
last_path="$display_path"
|
last_path="$display_path"
|
||||||
elif [[ -n "$last_path" ]]; then
|
|
||||||
display_path="$last_path"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get current spinner character
|
|
||||||
local spin_char="${spinner_chars:$spinner_idx:1}"
|
local spin_char="${spinner_chars:$spinner_idx:1}"
|
||||||
spinner_idx=$(((spinner_idx + 1) % ${#spinner_chars}))
|
spinner_idx=$(((spinner_idx + 1) % ${#spinner_chars}))
|
||||||
|
|
||||||
# Show title on first line, spinner and scanning info on second line
|
# Write directly to /dev/tty: \033[2K clears entire current line, \r goes to start
|
||||||
if [[ -n "$display_path" ]]; then
|
if [[ -n "$last_path" ]]; then
|
||||||
# Line 1: Move to start, clear, print title
|
printf '\r\033[2K%s %sScanning %s%s' \
|
||||||
printf '\r\033[K%s\n' "${PURPLE_BOLD}Purge Project Artifacts${NC}"
|
|
||||||
# Line 2: Move to start, clear, print scanning info
|
|
||||||
printf '\r\033[K%s %sScanning %s' \
|
|
||||||
"${BLUE}${spin_char}${NC}" \
|
"${BLUE}${spin_char}${NC}" \
|
||||||
"${GRAY}" "$display_path"
|
"${GRAY}" "$last_path" "${NC}" > /dev/tty 2> /dev/null
|
||||||
# Move up THEN to start (important order!)
|
|
||||||
printf '\033[A\r'
|
|
||||||
else
|
else
|
||||||
printf '\r\033[K%s\n' "${PURPLE_BOLD}Purge Project Artifacts${NC}"
|
printf '\r\033[2K%s %sScanning...%s' \
|
||||||
printf '\r\033[K%s %sScanning...' \
|
|
||||||
"${BLUE}${spin_char}${NC}" \
|
"${BLUE}${spin_char}${NC}" \
|
||||||
"${GRAY}"
|
"${GRAY}" "${NC}" > /dev/tty 2> /dev/null
|
||||||
printf '\033[A\r'
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
sleep 0.05
|
sleep 0.05
|
||||||
done
|
done
|
||||||
|
printf '\r\033[2K' > /dev/tty 2> /dev/null
|
||||||
exit 0
|
exit 0
|
||||||
) &
|
) &
|
||||||
monitor_pid=$!
|
monitor_pid=$!
|
||||||
@@ -178,10 +179,6 @@ perform_purge() {
|
|||||||
trap - INT TERM
|
trap - INT TERM
|
||||||
cleanup_monitor
|
cleanup_monitor
|
||||||
|
|
||||||
if [[ -t 1 ]]; then
|
|
||||||
echo -e "${PURPLE_BOLD}Purge Project Artifacts${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Exit codes:
|
# Exit codes:
|
||||||
# 0 = success, show summary
|
# 0 = success, show summary
|
||||||
# 1 = user cancelled
|
# 1 = user cancelled
|
||||||
@@ -212,15 +209,13 @@ perform_purge() {
|
|||||||
local freed_gb
|
local freed_gb
|
||||||
freed_gb=$(echo "$total_size_cleaned" | awk '{printf "%.2f", $1/1024/1024}')
|
freed_gb=$(echo "$total_size_cleaned" | awk '{printf "%.2f", $1/1024/1024}')
|
||||||
|
|
||||||
summary_details+=("Space freed: ${GREEN}${freed_gb}GB${NC}")
|
local summary_line="Space freed: ${GREEN}${freed_gb}GB${NC}"
|
||||||
summary_details+=("Free space now: $(get_free_space)")
|
[[ $total_items_cleaned -gt 0 ]] && summary_line+=" | Items: $total_items_cleaned"
|
||||||
|
summary_line+=" | Free: $(get_free_space)"
|
||||||
if [[ $total_items_cleaned -gt 0 ]]; then
|
summary_details+=("$summary_line")
|
||||||
summary_details+=("Items cleaned: $total_items_cleaned")
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
summary_details+=("No old project artifacts to clean.")
|
summary_details+=("No old project artifacts to clean.")
|
||||||
summary_details+=("Free space now: $(get_free_space)")
|
summary_details+=("Free space: $(get_free_space)")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Log session end
|
# Log session end
|
||||||
|
|||||||
Reference in New Issue
Block a user