mirror of
https://github.com/tw93/Mole.git
synced 2026-02-04 20:54:50 +00:00
feat: improve purge display with full paths and size sorting (#311)
- Show full project paths (~/www/project) instead of just project names - Sort artifacts by size descending (largest first) - Increase path display width for better readability - Support CMD+Click to open folders in terminal
This commit is contained in:
@@ -898,6 +898,70 @@ clean_project_artifacts() {
|
||||
echo "$result"
|
||||
}
|
||||
|
||||
# Helper to get project path (more complete than just project name)
|
||||
# For ~/www/pake/src-tauri/target -> returns "~/www/pake"
|
||||
# For ~/work/code/MyProject/node_modules -> returns "~/work/code/MyProject"
|
||||
# Shows the full path relative to HOME with ~ prefix for better clarity
|
||||
get_project_path() {
|
||||
local path="$1"
|
||||
|
||||
local current_dir
|
||||
current_dir=$(dirname "$path")
|
||||
local monorepo_root=""
|
||||
local project_root=""
|
||||
|
||||
# Single pass: check both monorepo and project indicators
|
||||
while [[ "$current_dir" != "/" && "$current_dir" != "$HOME" && -n "$current_dir" ]]; do
|
||||
# First check for monorepo indicators (higher priority)
|
||||
if [[ -z "$monorepo_root" ]]; then
|
||||
for indicator in "${MONOREPO_INDICATORS[@]}"; do
|
||||
if [[ -e "$current_dir/$indicator" ]]; then
|
||||
monorepo_root="$current_dir"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Then check for project indicators (save first match)
|
||||
if [[ -z "$project_root" ]]; then
|
||||
for indicator in "${PROJECT_INDICATORS[@]}"; do
|
||||
if [[ -e "$current_dir/$indicator" ]]; then
|
||||
project_root="$current_dir"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# If we found monorepo, we can stop (monorepo always wins)
|
||||
if [[ -n "$monorepo_root" ]]; then
|
||||
break
|
||||
fi
|
||||
|
||||
# If we found project but still checking for monorepo above
|
||||
local depth=$(echo "${current_dir#"$HOME"}" | LC_ALL=C tr -cd '/' | wc -c | tr -d ' ')
|
||||
if [[ -n "$project_root" && $depth -lt 2 ]]; then
|
||||
break
|
||||
fi
|
||||
|
||||
current_dir=$(dirname "$current_dir")
|
||||
done
|
||||
|
||||
# Determine result: monorepo > project > fallback
|
||||
local result=""
|
||||
if [[ -n "$monorepo_root" ]]; then
|
||||
result="$monorepo_root"
|
||||
elif [[ -n "$project_root" ]]; then
|
||||
result="$project_root"
|
||||
else
|
||||
# Fallback: use parent directory of artifact
|
||||
result=$(dirname "$path")
|
||||
fi
|
||||
|
||||
# Convert to ~ format for cleaner display
|
||||
result="${result/#$HOME/~}"
|
||||
echo "$result"
|
||||
}
|
||||
|
||||
# Helper to get artifact display name
|
||||
# For duplicate artifact names within same project, include parent directory for context
|
||||
get_artifact_display_name() {
|
||||
@@ -927,28 +991,28 @@ clean_project_artifacts() {
|
||||
}
|
||||
# Format display with alignment (like app_selector)
|
||||
format_purge_display() {
|
||||
local project_name="$1"
|
||||
local project_path="$1"
|
||||
local artifact_type="$2"
|
||||
local size_str="$3"
|
||||
# Terminal width for alignment
|
||||
local terminal_width=$(tput cols 2> /dev/null || echo 80)
|
||||
local fixed_width=38 # Reserve for type, size, and potential "| Recent" (28 + 10)
|
||||
local fixed_width=28 # Reserve for size and artifact type (9 + 3 + 16)
|
||||
local available_width=$((terminal_width - fixed_width))
|
||||
# Bounds: 24-35 chars for project name
|
||||
[[ $available_width -lt 24 ]] && available_width=24
|
||||
[[ $available_width -gt 35 ]] && available_width=35
|
||||
# Truncate project name if needed
|
||||
local truncated_name=$(truncate_by_display_width "$project_name" "$available_width")
|
||||
local current_width=$(get_display_width "$truncated_name")
|
||||
local char_count=${#truncated_name}
|
||||
# Bounds: 30-50 chars for project path (increased to accommodate full paths)
|
||||
[[ $available_width -lt 30 ]] && available_width=30
|
||||
[[ $available_width -gt 50 ]] && available_width=50
|
||||
# Truncate project path if needed
|
||||
local truncated_path=$(truncate_by_display_width "$project_path" "$available_width")
|
||||
local current_width=$(get_display_width "$truncated_path")
|
||||
local char_count=${#truncated_path}
|
||||
local padding=$((available_width - current_width))
|
||||
local printf_width=$((char_count + padding))
|
||||
# Format: "project_name size | artifact_type"
|
||||
printf "%-*s %9s | %-13s" "$printf_width" "$truncated_name" "$size_str" "$artifact_type"
|
||||
# Format: "project_path size | artifact_type"
|
||||
printf "%-*s %9s | %-13s" "$printf_width" "$truncated_path" "$size_str" "$artifact_type"
|
||||
}
|
||||
# Build menu options - one line per artifact
|
||||
for item in "${safe_to_clean[@]}"; do
|
||||
local project_name=$(get_project_name "$item")
|
||||
local project_path=$(get_project_path "$item")
|
||||
local artifact_type=$(get_artifact_display_name "$item")
|
||||
local size_kb=$(get_dir_size_kb "$item")
|
||||
|
||||
@@ -966,11 +1030,48 @@ clean_project_artifacts() {
|
||||
break
|
||||
fi
|
||||
done
|
||||
menu_options+=("$(format_purge_display "$project_name" "$artifact_type" "$size_human")")
|
||||
menu_options+=("$(format_purge_display "$project_path" "$artifact_type" "$size_human")")
|
||||
item_paths+=("$item")
|
||||
item_sizes+=("$size_kb")
|
||||
item_recent_flags+=("$is_recent")
|
||||
done
|
||||
|
||||
# Sort by size descending (largest first) - requested in issue #311
|
||||
# Use external sort for better performance with many items
|
||||
if [[ ${#item_sizes[@]} -gt 0 ]]; then
|
||||
# Create temporary file with index|size pairs
|
||||
local sort_temp
|
||||
sort_temp=$(mktemp)
|
||||
for ((i = 0; i < ${#item_sizes[@]}; i++)); do
|
||||
printf '%d|%d\n' "$i" "${item_sizes[i]}"
|
||||
done > "$sort_temp"
|
||||
|
||||
# Sort by size (field 2) descending, extract indices
|
||||
local -a sorted_indices=()
|
||||
while IFS='|' read -r idx size; do
|
||||
sorted_indices+=("$idx")
|
||||
done < <(sort -t'|' -k2,2nr "$sort_temp")
|
||||
rm -f "$sort_temp"
|
||||
|
||||
# Rebuild arrays in sorted order
|
||||
local -a sorted_menu_options=()
|
||||
local -a sorted_item_paths=()
|
||||
local -a sorted_item_sizes=()
|
||||
local -a sorted_item_recent_flags=()
|
||||
|
||||
for idx in "${sorted_indices[@]}"; do
|
||||
sorted_menu_options+=("${menu_options[idx]}")
|
||||
sorted_item_paths+=("${item_paths[idx]}")
|
||||
sorted_item_sizes+=("${item_sizes[idx]}")
|
||||
sorted_item_recent_flags+=("${item_recent_flags[idx]}")
|
||||
done
|
||||
|
||||
# Replace original arrays with sorted versions
|
||||
menu_options=("${sorted_menu_options[@]}")
|
||||
item_paths=("${sorted_item_paths[@]}")
|
||||
item_sizes=("${sorted_item_sizes[@]}")
|
||||
item_recent_flags=("${sorted_item_recent_flags[@]}")
|
||||
fi
|
||||
if [[ -t 1 ]]; then
|
||||
stop_inline_spinner
|
||||
fi
|
||||
@@ -1014,7 +1115,7 @@ clean_project_artifacts() {
|
||||
for idx in "${selected_indices[@]}"; do
|
||||
local item_path="${item_paths[idx]}"
|
||||
local artifact_type=$(basename "$item_path")
|
||||
local project_name=$(get_project_name "$item_path")
|
||||
local project_path=$(get_project_path "$item_path")
|
||||
local size_kb="${item_sizes[idx]}"
|
||||
local size_human=$(bytes_to_human "$((size_kb * 1024))")
|
||||
# Safety checks
|
||||
@@ -1022,7 +1123,7 @@ clean_project_artifacts() {
|
||||
continue
|
||||
fi
|
||||
if [[ -t 1 ]]; then
|
||||
start_inline_spinner "Cleaning $project_name/$artifact_type..."
|
||||
start_inline_spinner "Cleaning $project_path/$artifact_type..."
|
||||
fi
|
||||
if [[ -e "$item_path" ]]; then
|
||||
safe_remove "$item_path" true
|
||||
@@ -1034,7 +1135,7 @@ clean_project_artifacts() {
|
||||
fi
|
||||
if [[ -t 1 ]]; then
|
||||
stop_inline_spinner
|
||||
echo -e "${GREEN}${ICON_SUCCESS}${NC} $project_name - $artifact_type ${GREEN}($size_human)${NC}"
|
||||
echo -e "${GREEN}${ICON_SUCCESS}${NC} $project_path - $artifact_type ${GREEN}($size_human)${NC}"
|
||||
fi
|
||||
done
|
||||
# Update count
|
||||
|
||||
Reference in New Issue
Block a user