From aa1a4368622b52f831a893bea7bc6a588e18f88c Mon Sep 17 00:00:00 2001 From: tw93 Date: Thu, 26 Feb 2026 16:36:06 +0800 Subject: [PATCH] fix(clean): improve loading feedback and spinner output --- lib/clean/dev.sh | 10 ++++++++++ lib/clean/system.sh | 9 ++++++++- lib/clean/user.sh | 20 ++++++++++++++++++-- lib/core/ui.sh | 35 +++++++++++++++++++++++++++++++++-- 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/lib/clean/dev.sh b/lib/clean/dev.sh index 8d02498..edb8157 100644 --- a/lib/clean/dev.sh +++ b/lib/clean/dev.sh @@ -7,7 +7,17 @@ clean_tool_cache() { local description="$1" shift if [[ "$DRY_RUN" != "true" ]]; then + local command_succeeded=false + if [[ -t 1 ]]; then + start_section_spinner "Cleaning $description..." + fi if "$@" > /dev/null 2>&1; then + command_succeeded=true + fi + if [[ -t 1 ]]; then + stop_section_spinner + fi + if [[ "$command_succeeded" == "true" ]]; then echo -e " ${GREEN}${ICON_SUCCESS}${NC} $description" fi else diff --git a/lib/clean/system.sh b/lib/clean/system.sh index dbe4a44..5cc5e93 100644 --- a/lib/clean/system.sh +++ b/lib/clean/system.sh @@ -5,6 +5,7 @@ set -euo pipefail clean_deep_system() { stop_section_spinner local cache_cleaned=0 + start_section_spinner "Cleaning system caches..." # Optimized: Single pass for /Library/Caches (3 patterns in 1 scan) if sudo test -d "/Library/Caches" 2> /dev/null; then while IFS= read -r -d '' file; do @@ -20,6 +21,7 @@ clean_deep_system() { \( -name "*.log" -mtime "+$MOLE_LOG_AGE_DAYS" \) \ \) -print0 2> /dev/null || true) fi + stop_section_spinner [[ $cache_cleaned -eq 1 ]] && log_success "System caches" start_section_spinner "Cleaning system temporary files..." local tmp_cleaned=0 @@ -147,7 +149,7 @@ clean_deep_system() { done stop_section_spinner [[ $installer_cleaned -gt 0 ]] && debug_log "Cleaned $installer_cleaned macOS installer(s)" - start_section_spinner "Scanning system caches..." + start_section_spinner "Scanning browser code signature caches..." local code_sign_cleaned=0 while IFS= read -r -d '' cache_dir; do if safe_sudo_remove "$cache_dir"; then @@ -158,11 +160,16 @@ clean_deep_system() { [[ $code_sign_cleaned -gt 0 ]] && log_success "Browser code signature caches, $code_sign_cleaned items" local diag_base="/private/var/db/diagnostics" + start_section_spinner "Cleaning system diagnostic logs..." safe_sudo_find_delete "$diag_base" "*" "$MOLE_LOG_AGE_DAYS" "f" || true safe_sudo_find_delete "$diag_base" "*.tracev3" "30" "f" || true safe_sudo_find_delete "/private/var/db/DiagnosticPipeline" "*" "$MOLE_LOG_AGE_DAYS" "f" || true + stop_section_spinner log_success "System diagnostic logs" + + start_section_spinner "Cleaning power logs..." safe_sudo_find_delete "/private/var/db/powerlog" "*" "$MOLE_LOG_AGE_DAYS" "f" || true + stop_section_spinner log_success "Power logs" start_section_spinner "Cleaning memory exception reports..." local mem_reports_dir="/private/var/db/reportmemoryexception/MemoryLimitViolations" diff --git a/lib/clean/user.sh b/lib/clean/user.sh index 722eecd..8a6f585 100644 --- a/lib/clean/user.sh +++ b/lib/clean/user.sh @@ -76,8 +76,13 @@ _clean_mail_downloads() { ) local count=0 local cleaned_kb=0 + local spinner_active=false for target_path in "${mail_dirs[@]}"; do if [[ -d "$target_path" ]]; then + if [[ "$spinner_active" == "false" && -t 1 ]]; then + start_section_spinner "Cleaning old Mail attachments..." + spinner_active=true + fi local dir_size_kb=0 dir_size_kb=$(get_path_size_kb "$target_path") if ! [[ "$dir_size_kb" =~ ^[0-9]+$ ]]; then @@ -102,6 +107,9 @@ _clean_mail_downloads() { done < <(command find "$target_path" -type f -mtime +"$mail_age_days" -print0 2> /dev/null || true) fi done + if [[ "$spinner_active" == "true" ]]; then + stop_section_spinner + fi if [[ $count -gt 0 ]]; then local cleaned_mb cleaned_mb=$(echo "$cleaned_kb" | awk '{printf "%.1f", $1/1024}' || echo "0.0") @@ -832,8 +840,12 @@ clean_application_support_logs() { local current_time current_time=$(get_epoch_seconds) if [[ "$current_time" =~ ^[0-9]+$ ]] && ((current_time - last_progress_update >= 1)); then + local app_label="$app_name" + if [[ ${#app_label} -gt 24 ]]; then + app_label="${app_label:0:21}..." + fi stop_section_spinner - start_section_spinner "Scanning Application Support... $app_count/$total_apps ($app_name: $candidate_item_count items)" + start_section_spinner "Scanning Application Support... $app_count/$total_apps [$app_label, $candidate_item_count items]" last_progress_update=$current_time fi fi @@ -883,8 +895,12 @@ clean_application_support_logs() { local current_time current_time=$(get_epoch_seconds) if [[ "$current_time" =~ ^[0-9]+$ ]] && ((current_time - last_progress_update >= 1)); then + local container_label="$container" + if [[ ${#container_label} -gt 24 ]]; then + container_label="${container_label:0:21}..." + fi stop_section_spinner - start_section_spinner "Scanning Application Support... group container ($container: $candidate_item_count items)" + start_section_spinner "Scanning Application Support... group [$container_label, $candidate_item_count items]" last_progress_update=$current_time fi fi diff --git a/lib/core/ui.sh b/lib/core/ui.sh index eb0c76c..2834091 100755 --- a/lib/core/ui.sh +++ b/lib/core/ui.sh @@ -287,9 +287,40 @@ show_menu_option() { INLINE_SPINNER_PID="" INLINE_SPINNER_STOP_FILE="" +# Keep spinner message on one line and avoid wrapping/noisy output on narrow terminals. +format_spinner_message() { + local message="$1" + message="${message//$'\r'/ }" + message="${message//$'\n'/ }" + + local cols=80 + if command -v tput > /dev/null 2>&1; then + cols=$(tput cols 2> /dev/null || echo "80") + fi + [[ "$cols" =~ ^[0-9]+$ ]] || cols=80 + + # Reserve space for prefix + spinner char + spacing. + local available=$((cols - 8)) + if [[ $available -lt 20 ]]; then + available=20 + fi + + if [[ ${#message} -gt $available ]]; then + if [[ $available -gt 3 ]]; then + message="${message:0:$((available - 3))}..." + else + message="${message:0:$available}" + fi + fi + + printf "%s" "$message" +} + start_inline_spinner() { stop_inline_spinner 2> /dev/null || true local message="$1" + local display_message + display_message=$(format_spinner_message "$message") if [[ -t 1 ]]; then # Create unique stop flag file for this spinner instance @@ -309,7 +340,7 @@ start_inline_spinner() { while [[ ! -f "$stop_file" ]]; do local c="${chars:$((i % ${#chars})):1}" # Output to stderr to avoid interfering with stdout - printf "\r${MOLE_SPINNER_PREFIX:-}${BLUE}%s${NC} %s" "$c" "$message" >&2 || break + printf "\r${MOLE_SPINNER_PREFIX:-}${BLUE}%s${NC} %s" "$c" "$display_message" >&2 || break ((i++)) sleep 0.05 done @@ -321,7 +352,7 @@ start_inline_spinner() { INLINE_SPINNER_PID=$! disown "$INLINE_SPINNER_PID" 2> /dev/null || true else - echo -n " ${BLUE}|${NC} $message" >&2 || true + echo -n " ${BLUE}|${NC} $display_message" >&2 || true fi }