1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-16 00:21:11 +00:00

🎨 Better analysis experience

This commit is contained in:
Tw93
2025-10-05 16:40:43 +08:00
parent d8909053e8
commit f7a88558d5
3 changed files with 81 additions and 61 deletions

View File

@@ -1256,7 +1256,7 @@ scan_directory_contents_fast() {
# Show initial scanning message # Show initial scanning message
if [[ "$show_progress" == "true" ]]; then if [[ "$show_progress" == "true" ]]; then
printf "\033[H\033[J" >&2 printf "\033[?25l\033[H\033[J" >&2
echo "" >&2 echo "" >&2
printf " ${BLUE}📊 ⠋ Scanning...${NC}\r" >&2 printf " ${BLUE}📊 ⠋ Scanning...${NC}\r" >&2
fi fi
@@ -1336,6 +1336,8 @@ scan_directory_contents_fast() {
fi fi
done done
printf "\r\033[K" >&2 printf "\r\033[K" >&2
# Ensure cursor stays hidden after clearing spinner
printf "\033[?25l" >&2
fi fi
# Wait for completion (non-blocking if already killed) # Wait for completion (non-blocking if already killed)
@@ -1410,83 +1412,64 @@ combine_initial_scan_results() {
show_volumes_overview() { show_volumes_overview() {
local temp_volumes="$TEMP_PREFIX.volumes" local temp_volumes="$TEMP_PREFIX.volumes"
# Collect all mounted volumes # Collect most useful locations (quick display, no size calculation)
{ {
# Root volume # Priority order for display (prioritized by typical usefulness)
local root_size=$(df -k / 2>/dev/null | tail -1 | awk '{print $3}') [[ -d "$HOME" ]] && echo "1000|$HOME|🏠 Home Directory"
echo "$((root_size * 1024))|/|Macintosh HD (Root)" [[ -d "$HOME/Downloads" ]] && echo "900|$HOME/Downloads|📥 Downloads"
[[ -d "/Applications" ]] && echo "800|/Applications|📦 Applications"
[[ -d "$HOME/Library" ]] && echo "700|$HOME/Library|📚 User Library"
[[ -d "/Library" ]] && echo "600|/Library|📚 System Library"
# External volumes # External volumes (if any)
if [[ -d "/Volumes" ]]; then if [[ -d "/Volumes" ]]; then
local vol_priority=500
find /Volumes -mindepth 1 -maxdepth 1 -type d 2>/dev/null | while IFS= read -r vol; do find /Volumes -mindepth 1 -maxdepth 1 -type d 2>/dev/null | while IFS= read -r vol; do
local vol_size=$(df -k "$vol" 2>/dev/null | tail -1 | awk '{print $3}')
local vol_name=$(basename "$vol") local vol_name=$(basename "$vol")
echo "$((vol_size * 1024))|$vol|$vol_name" echo "$((vol_priority))|$vol|🔌 $vol_name"
((vol_priority--))
done done
fi fi
# Common user directories
for dir in "$HOME" "$HOME/Downloads" "$HOME/Documents" "$HOME/Library"; do
if [[ -d "$dir" ]]; then
local dir_size=$(du -sk "$dir" 2>/dev/null | cut -f1)
local dir_name=$(echo "$dir" | sed "s|^$HOME|~|")
echo "$((dir_size * 1024))|$dir|$dir_name"
fi
done
} | sort -t'|' -k1 -rn > "$temp_volumes" } | sort -t'|' -k1 -rn > "$temp_volumes"
# Setup alternate screen # Setup alternate screen and hide cursor (keep hidden throughout)
tput smcup 2>/dev/null || true tput smcup 2>/dev/null || true
printf "\033[?25l" # Hide cursor printf "\033[?25l" >&2 # Hide cursor
cleanup_volumes() { cleanup_volumes() {
printf "\033[?25h" # Show cursor printf "\033[?25h" >&2 # Show cursor
tput rmcup 2>/dev/null || true tput rmcup 2>/dev/null || true
} }
trap cleanup_volumes EXIT INT TERM trap cleanup_volumes EXIT INT TERM
# Force cursor hidden at the start
stty -echo 2>/dev/null || true
local cursor=0 local cursor=0
local total_items=$(wc -l < "$temp_volumes" | tr -d ' ') local total_items=$(wc -l < "$temp_volumes" | tr -d ' ')
while true; do while true; do
# Ensure cursor is always hidden
printf "\033[?25l" >&2
# Drain burst input (trackpad scroll -> many arrows) # Drain burst input (trackpad scroll -> many arrows)
type drain_pending_input >/dev/null 2>&1 && drain_pending_input type drain_pending_input >/dev/null 2>&1 && drain_pending_input
# Build output buffer to reduce flicker # Build output buffer to reduce flicker
local output="" local output=""
output+="\033[?25l" # Hide cursor
output+="\033[H\033[J" output+="\033[H\033[J"
output+=$'\n' output+=$'\n'
output+="\033[0;35m💾 Select a location to explore\033[0m"$'\n' output+="\033[0;35m💾 Select a location to explore\033[0m"$'\n'
output+=$'\n' output+=$'\n'
local idx=0 local idx=0
while IFS='|' read -r size path display_name; do while IFS='|' read -r priority path display_name; do
local human_size=$(bytes_to_human "$size") # Build line (simple display without size)
# Determine icon
local icon="💾"
local color="${NC}"
if [[ "$path" == "/" ]]; then
icon="💿"
color="${BLUE}"
elif [[ "$path" == /Volumes/* ]]; then
icon="🔌"
color="${YELLOW}"
elif [[ "$path" == "$HOME" ]]; then
icon="🏠"
color="${GREEN}"
elif [[ "$path" == *"/Library" ]]; then
icon="📚"
color="${GRAY}"
else
icon="📁"
fi
# Build line
local line="" local line=""
if [[ $idx -eq $cursor ]]; then if [[ $idx -eq $cursor ]]; then
line=$(printf " ${GREEN}${NC} ${color}%-4s %-10s %s${NC}" "$icon" "$human_size" "$display_name") line=$(printf " ${GREEN}${NC} ${BLUE}%s${NC}" "$display_name")
else else
line=$(printf " ${color}%-4s %-10s %s${NC}" "$icon" "$human_size" "$display_name") line=$(printf " ${GRAY}%s${NC}" "$display_name")
fi fi
output+="$line"$'\n' output+="$line"$'\n'
@@ -1513,7 +1496,7 @@ show_volumes_overview() {
# Get selected path and enter it # Get selected path and enter it
local selected_path="" local selected_path=""
idx=0 idx=0
while IFS='|' read -r size path display_name; do while IFS='|' read -r priority path display_name; do
if [[ $idx -eq $cursor ]]; then if [[ $idx -eq $cursor ]]; then
selected_path="$path" selected_path="$path"
break break
@@ -1522,10 +1505,24 @@ show_volumes_overview() {
done < "$temp_volumes" done < "$temp_volumes"
if [[ -n "$selected_path" ]] && [[ -d "$selected_path" ]]; then if [[ -n "$selected_path" ]] && [[ -d "$selected_path" ]]; then
cleanup_volumes # Save cursor for potential return
local saved_cursor=$cursor
# Don't cleanup yet - stay in alternate screen
trap - EXIT INT TERM trap - EXIT INT TERM
interactive_drill_down "$selected_path" ""
return # Enter drill-down, check return value
if interactive_drill_down "$selected_path" ""; then
# User quit (Q/ESC) - cleanup and exit
cleanup_volumes
return 0
else
# User went back (LEFT at root) - return to menu
# Restore trap
trap cleanup_volumes EXIT INT TERM
cursor=$saved_cursor
# Just continue loop to redraw menu
fi
fi fi
;; ;;
"LEFT") "LEFT")
@@ -1565,8 +1562,8 @@ interactive_drill_down() {
local cache_dir="$TEMP_PREFIX.cache.$$" local cache_dir="$TEMP_PREFIX.cache.$$"
mkdir -p "$cache_dir" 2>/dev/null || true mkdir -p "$cache_dir" 2>/dev/null || true
# Setup alternate screen and hide cursor # Note: We're already in alternate screen from show_volumes_overview
tput smcup 2>/dev/null || true # Enter alternate screen # Just hide cursor, don't re-enter alternate screen
printf "\033[?25l" # Hide cursor printf "\033[?25l" # Hide cursor
# Save terminal settings and disable echo # Save terminal settings and disable echo
@@ -1576,14 +1573,14 @@ interactive_drill_down() {
stty -echo 2>/dev/null || true stty -echo 2>/dev/null || true
fi fi
# Cleanup on exit # Cleanup on exit (but don't exit alternate screen - may return to menu)
cleanup_drill_down() { cleanup_drill_down() {
# Restore terminal settings # Restore terminal settings
if [[ -n "${old_tty_settings:-}" ]]; then if [[ -n "${old_tty_settings:-}" ]]; then
stty "$old_tty_settings" 2>/dev/null || true stty "$old_tty_settings" 2>/dev/null || true
fi fi
printf "\033[?25h" # Show cursor printf "\033[?25h" # Show cursor
tput rmcup 2>/dev/null || true # Exit alternate screen # Don't call tput rmcup - we may be returning to volumes menu
[[ -d "${cache_dir:-}" ]] && rm -rf "$cache_dir" 2>/dev/null || true # Clean up cache [[ -d "${cache_dir:-}" ]] && rm -rf "$cache_dir" 2>/dev/null || true # Clean up cache
} }
trap cleanup_drill_down EXIT INT TERM trap cleanup_drill_down EXIT INT TERM
@@ -1592,6 +1589,9 @@ interactive_drill_down() {
type drain_pending_input >/dev/null 2>&1 && drain_pending_input type drain_pending_input >/dev/null 2>&1 && drain_pending_input
while true; do while true; do
# Ensure cursor is always hidden during navigation
printf "\033[?25l" >&2
# Drain any burst input (e.g. trackpad scroll converted to many arrow keys) # Drain any burst input (e.g. trackpad scroll converted to many arrow keys)
type drain_pending_input >/dev/null 2>&1 && drain_pending_input type drain_pending_input >/dev/null 2>&1 && drain_pending_input
# Only scan if needed (directory changed or refresh requested) # Only scan if needed (directory changed or refresh requested)
@@ -1691,6 +1691,7 @@ interactive_drill_down() {
# Build output buffer once for smooth rendering # Build output buffer once for smooth rendering
local output="" local output=""
output+="\033[?25l" # Hide cursor
output+="\033[H\033[J" # Clear screen output+="\033[H\033[J" # Clear screen
output+=$'\n' output+=$'\n'
output+="\033[0;35m📊 Disk space explorer > $(echo "$current_path" | sed "s|^$HOME|~|")\033[0m"$'\n' output+="\033[0;35m📊 Disk space explorer > $(echo "$current_path" | sed "s|^$HOME|~|")\033[0m"$'\n'
@@ -1879,10 +1880,17 @@ interactive_drill_down() {
current_path="${path_stack[$last_index]}" current_path="${path_stack[$last_index]}"
unset "path_stack[$last_index]" unset "path_stack[$last_index]"
cursor=0 cursor=0
scroll_offset=0
need_scan=true need_scan=true
else else
# Already at root/start path - do nothing (don't quit) # Already at start path - return to volumes menu
: # Don't show cursor or exit screen - menu will handle it
if [[ -n "${old_tty_settings:-}" ]]; then
stty "$old_tty_settings" 2>/dev/null || true
fi
[[ -d "${cache_dir:-}" ]] && rm -rf "$cache_dir" 2>/dev/null || true
trap - EXIT INT TERM
return 1 # Return to menu
fi fi
;; ;;
"DELETE") "DELETE")
@@ -1997,7 +2005,9 @@ interactive_drill_down() {
;; ;;
"QUIT"|"q") "QUIT"|"q")
# Quit the explorer # Quit the explorer
break cleanup_drill_down
trap - EXIT INT TERM
return 0 # Return true to indicate normal exit
;; ;;
*) *)
# Unknown key - ignore it # Unknown key - ignore it
@@ -2006,6 +2016,7 @@ interactive_drill_down() {
done done
# Cleanup is handled by trap # Cleanup is handled by trap
return 0 # Normal exit if loop ends
} }
# Main interactive loop # Main interactive loop
@@ -2212,8 +2223,8 @@ main() {
# Create cache directory # Create cache directory
mkdir -p "$CACHE_DIR" 2>/dev/null || true mkdir -p "$CACHE_DIR" 2>/dev/null || true
# Start interactive drill-down mode (no volumes view, no export) # Start with volumes overview to let user choose location
interactive_drill_down "$target_path" "" show_volumes_overview
} }
# Run if executed directly # Run if executed directly

View File

@@ -114,6 +114,7 @@ read_key() {
'd'|'D') echo "DELETE" ;; 'd'|'D') echo "DELETE" ;;
'r'|'R') echo "RETRY" ;; 'r'|'R') echo "RETRY" ;;
'?') echo "HELP" ;; '?') echo "HELP" ;;
$'\x03') echo "QUIT" ;; # Ctrl+C
$'\x7f'|$'\x08') echo "DELETE" ;; # Delete key (labeled "delete" on Mac, actually backspace) $'\x7f'|$'\x08') echo "DELETE" ;; # Delete key (labeled "delete" on Mac, actually backspace)
$'\x1b') $'\x1b')
# ESC sequence - could be arrow key, delete key, or ESC alone # ESC sequence - could be arrow key, delete key, or ESC alone

View File

@@ -48,10 +48,18 @@ paginated_multi_select() {
stty echo icanon 2>/dev/null || true stty echo icanon 2>/dev/null || true
leave_alt_screen leave_alt_screen
} }
trap cleanup EXIT INT TERM
# Setup terminal # Interrupt handler
stty -echo -icanon 2>/dev/null || true handle_interrupt() {
cleanup
exit 130 # Standard exit code for Ctrl+C
}
trap cleanup EXIT
trap handle_interrupt INT TERM
# Setup terminal - preserve interrupt character
stty -echo -icanon intr ^C 2>/dev/null || true
enter_alt_screen enter_alt_screen
hide_cursor hide_cursor