mirror of
https://github.com/tw93/Mole.git
synced 2026-02-15 05:15:10 +00:00
Symbol specification output
This commit is contained in:
@@ -25,10 +25,10 @@ readonly MIN_SMALL_FILE_SIZE="10000000" # 10MB
|
|||||||
|
|
||||||
# Emoji badges for list displays only
|
# Emoji badges for list displays only
|
||||||
readonly BADGE_DIR="🍞"
|
readonly BADGE_DIR="🍞"
|
||||||
readonly BADGE_FILE="📔"
|
readonly BADGE_FILE="🍚"
|
||||||
readonly BADGE_MEDIA="🌁"
|
readonly BADGE_MEDIA="🥟"
|
||||||
readonly BADGE_BUNDLE="🥜"
|
readonly BADGE_BUNDLE="🥜"
|
||||||
readonly BADGE_LOG="📝"
|
readonly BADGE_LOG="🍹"
|
||||||
readonly BADGE_APP="🐣"
|
readonly BADGE_APP="🐣"
|
||||||
|
|
||||||
# Global state
|
# Global state
|
||||||
@@ -662,9 +662,9 @@ display_cleanup_suggestions_compact() {
|
|||||||
echo ""
|
echo ""
|
||||||
if [[ -n "$action_command" ]]; then
|
if [[ -n "$action_command" ]]; then
|
||||||
if [[ "$action_command" == "mole clean" ]]; then
|
if [[ "$action_command" == "mole clean" ]]; then
|
||||||
echo " ${GRAY}→ Run${NC} ${YELLOW}mole clean${NC} ${GRAY}to cleanup system files${NC}"
|
echo " ${GRAY}${ICON_NAV_RIGHT} Run${NC} ${YELLOW}mole clean${NC} ${GRAY}to cleanup system files${NC}"
|
||||||
else
|
else
|
||||||
echo " ${GRAY}→ Review and ${NC}${YELLOW}$action_command${NC}"
|
echo " ${GRAY}${ICON_NAV_RIGHT} Review and ${NC}${YELLOW}$action_command${NC}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
@@ -740,7 +740,7 @@ display_cleanup_suggestions() {
|
|||||||
echo ""
|
echo ""
|
||||||
echo " Tip: Run 'mole clean' to perform cleanup operations"
|
echo " Tip: Run 'mole clean' to perform cleanup operations"
|
||||||
else
|
else
|
||||||
echo " ${GREEN}✓${NC} No obvious cleanup opportunities found"
|
echo " ${GREEN}${ICON_SUCCESS}${NC} No obvious cleanup opportunities found"
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
@@ -971,14 +971,14 @@ display_recommendations() {
|
|||||||
echo " ${YELLOW}Quick Actions:${NC}"
|
echo " ${YELLOW}Quick Actions:${NC}"
|
||||||
|
|
||||||
if [[ "$CURRENT_PATH" == "$HOME/Downloads"* ]]; then
|
if [[ "$CURRENT_PATH" == "$HOME/Downloads"* ]]; then
|
||||||
echo " → Delete ${RED}[Can Delete]${NC} items (installers/DMG)"
|
echo " ${ICON_NAV_RIGHT} Delete ${RED}[Can Delete]${NC} items (installers/DMG)"
|
||||||
echo " → Review ${YELLOW}[Review]${NC} items (videos/archives)"
|
echo " ${ICON_NAV_RIGHT} Review ${YELLOW}[Review]${NC} items (videos/archives)"
|
||||||
elif [[ "$CURRENT_PATH" == "$HOME/Library"* ]]; then
|
elif [[ "$CURRENT_PATH" == "$HOME/Library"* ]]; then
|
||||||
echo " → Run ${GREEN}mole clean${NC} to clear caches safely"
|
echo " ${ICON_NAV_RIGHT} Run ${GREEN}mole clean${NC} to clear caches safely"
|
||||||
echo " → Check Xcode/developer caches if applicable"
|
echo " ${ICON_NAV_RIGHT} Check Xcode/developer caches if applicable"
|
||||||
else
|
else
|
||||||
echo " → Review ${RED}[Can Delete]${NC} and ${YELLOW}[Review]${NC} items"
|
echo " ${ICON_NAV_RIGHT} Review ${RED}[Can Delete]${NC} and ${YELLOW}[Review]${NC} items"
|
||||||
echo " → Run ${GREEN}mole analyze ~/Library${NC} to check caches"
|
echo " ${ICON_NAV_RIGHT} Run ${GREEN}mole analyze ~/Library${NC} to check caches"
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
@@ -1124,7 +1124,7 @@ display_directory_list() {
|
|||||||
|
|
||||||
# Highlight selected line
|
# Highlight selected line
|
||||||
if [[ $idx -eq $cursor_pos ]]; then
|
if [[ $idx -eq $cursor_pos ]]; then
|
||||||
printf " ${BLUE}▶${NC} %s [${GREEN}%s${NC}] %5s%% %s\n" \
|
printf " ${BLUE}${ICON_ARROW}${NC} %s [${GREEN}%s${NC}] %5s%% %s\n" \
|
||||||
"$bar" "$human_size" "$percentage" "$dirname"
|
"$bar" "$human_size" "$percentage" "$dirname"
|
||||||
else
|
else
|
||||||
printf " %s [${BLUE}%s${NC}] %5s%% %s\n" \
|
printf " %s [${BLUE}%s${NC}] %5s%% %s\n" \
|
||||||
@@ -1183,7 +1183,7 @@ display_interactive_menu() {
|
|||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Show navigation hints
|
# Show navigation hints
|
||||||
echo "${GRAY}↑↓ Navigate | → Drill Down | ← Go Back | f Files | t Types | q Quit${NC}"
|
echo "${GRAY}${ICON_NAV_UP}${ICON_NAV_DOWN} Navigate | ${ICON_NAV_RIGHT} Drill Down | ${ICON_NAV_LEFT} Go Back | f Files | t Types | q Quit${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Display results based on view mode
|
# Display results based on view mode
|
||||||
@@ -1526,7 +1526,7 @@ show_volumes_overview() {
|
|||||||
# Build line (simple display without size)
|
# Build line (simple display without size)
|
||||||
local line=""
|
local line=""
|
||||||
if [[ $idx -eq $cursor ]]; then
|
if [[ $idx -eq $cursor ]]; then
|
||||||
line=$(printf " ${GREEN}▶${NC} ${BLUE}%s${NC}" "$display_name")
|
line=$(printf " ${GREEN}${ICON_ARROW}${NC} ${BLUE}%s${NC}" "$display_name")
|
||||||
else
|
else
|
||||||
line=$(printf " ${GRAY}%s${NC}" "$display_name")
|
line=$(printf " ${GRAY}%s${NC}" "$display_name")
|
||||||
fi
|
fi
|
||||||
@@ -1817,7 +1817,7 @@ interactive_drill_down() {
|
|||||||
# Build line with emoji badge, size, and name
|
# Build line with emoji badge, size, and name
|
||||||
local line
|
local line
|
||||||
if [[ $idx -eq $cursor ]]; then
|
if [[ $idx -eq $cursor ]]; then
|
||||||
line=$(printf " ${GREEN}▶${NC} %s%s${NC} %10s %s${NC}" "$color" "$badge" "$human_size" "$name")
|
line=$(printf " ${GREEN}${ICON_ARROW}${NC} %s%s${NC} %10s %s${NC}" "$color" "$badge" "$human_size" "$name")
|
||||||
else
|
else
|
||||||
line=$(printf " %s%s${NC} %10s %s${NC}" "$color" "$badge" "$human_size" "$name")
|
line=$(printf " %s%s${NC} %10s %s${NC}" "$color" "$badge" "$human_size" "$name")
|
||||||
fi
|
fi
|
||||||
@@ -1842,7 +1842,7 @@ interactive_drill_down() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Bottom help bar
|
# Bottom help bar
|
||||||
output+=" ${GRAY}↑/↓${NC} Navigate ${GRAY}|${NC} ${GRAY}Enter${NC} Open ${GRAY}|${NC} ${GRAY}←${NC} Back ${GRAY}|${NC} ${GRAY}Del${NC} Delete ${GRAY}|${NC} ${GRAY}O${NC} Finder ${GRAY}|${NC} ${GRAY}Q/ESC${NC} Quit"$'\n'
|
output+=" ${GRAY}${ICON_NAV_UP}/${ICON_NAV_DOWN}${NC} Navigate ${GRAY}|${NC} ${GRAY}Enter${NC} Open ${GRAY}|${NC} ${GRAY}${ICON_NAV_LEFT}${NC} Back ${GRAY}|${NC} ${GRAY}Del${NC} Delete ${GRAY}|${NC} ${GRAY}O${NC} Finder ${GRAY}|${NC} ${GRAY}Q/ESC${NC} Quit"$'\n'
|
||||||
|
|
||||||
# Output everything at once (single write = no flicker)
|
# Output everything at once (single write = no flicker)
|
||||||
printf "%b" "$output" >&2
|
printf "%b" "$output" >&2
|
||||||
@@ -1925,7 +1925,7 @@ interactive_drill_down() {
|
|||||||
open "$selected_path" 2>/dev/null && open_success=true
|
open "$selected_path" 2>/dev/null && open_success=true
|
||||||
if [[ "$open_success" == "true" ]]; then
|
if [[ "$open_success" == "true" ]]; then
|
||||||
echo ""
|
echo ""
|
||||||
echo " ${GREEN}✓${NC} File opened in external app"
|
echo " ${GREEN}${ICON_SUCCESS}${NC} File opened in external app"
|
||||||
sleep 0.8
|
sleep 0.8
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -1946,7 +1946,7 @@ interactive_drill_down() {
|
|||||||
# Show brief success message
|
# Show brief success message
|
||||||
if [[ "$open_success" == "true" ]]; then
|
if [[ "$open_success" == "true" ]]; then
|
||||||
echo ""
|
echo ""
|
||||||
echo " ${GREEN}✓${NC} File opened in external app"
|
echo " ${GREEN}${ICON_SUCCESS}${NC} File opened in external app"
|
||||||
sleep 0.8
|
sleep 0.8
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -1992,7 +1992,7 @@ interactive_drill_down() {
|
|||||||
"OPEN")
|
"OPEN")
|
||||||
if command -v open >/dev/null 2>&1; then
|
if command -v open >/dev/null 2>&1; then
|
||||||
if open "$current_path" >/dev/null 2>&1; then
|
if open "$current_path" >/dev/null 2>&1; then
|
||||||
status_message="${GREEN}✓${NC} Finder opened: ${GRAY}$current_path${NC}"
|
status_message="${GREEN}${ICON_SUCCESS}${NC} Finder opened: ${GRAY}$current_path${NC}"
|
||||||
else
|
else
|
||||||
status_message="${YELLOW}Warning:${NC} Could not open ${GRAY}$current_path${NC}"
|
status_message="${YELLOW}Warning:${NC} Could not open ${GRAY}$current_path${NC}"
|
||||||
fi
|
fi
|
||||||
@@ -2048,7 +2048,7 @@ interactive_drill_down() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${PURPLE}☛${NC} Press ${GREEN}Enter${NC} to delete, ${GRAY}ESC${NC} to cancel"
|
echo -e " ${PURPLE}${ICON_ARROW}${NC} Press ${GREEN}Enter${NC} to delete, ${GRAY}ESC${NC} to cancel"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Read confirmation
|
# Read confirmation
|
||||||
@@ -2063,7 +2063,7 @@ interactive_drill_down() {
|
|||||||
echo ""
|
echo ""
|
||||||
if ! request_sudo_access "Admin access required to delete this item"; then
|
if ! request_sudo_access "Admin access required to delete this item"; then
|
||||||
echo ""
|
echo ""
|
||||||
echo " ${RED}✗ Admin access denied${NC}"
|
echo " ${RED}${ICON_ERROR} Admin access denied${NC}"
|
||||||
sleep 1.5
|
sleep 1.5
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
@@ -2088,7 +2088,7 @@ interactive_drill_down() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$delete_success" == "true" ]]; then
|
if [[ "$delete_success" == "true" ]]; then
|
||||||
echo " ${GREEN}✓ Deleted successfully (freed $human_size)${NC}"
|
echo " ${GREEN}${ICON_SUCCESS} Deleted successfully (freed $human_size)${NC}"
|
||||||
sleep 0.8
|
sleep 0.8
|
||||||
|
|
||||||
# Clear cache to force rescan
|
# Clear cache to force rescan
|
||||||
@@ -2104,12 +2104,12 @@ interactive_drill_down() {
|
|||||||
((cursor--))
|
((cursor--))
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo " ${RED}✗ Failed to delete${NC}"
|
echo " ${RED}${ICON_ERROR} Failed to delete${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo " ${YELLOW}Possible reasons:${NC}"
|
echo " ${YELLOW}Possible reasons:${NC}"
|
||||||
echo " • File is being used by another application"
|
echo " ${ICON_LIST} File is being used by another application"
|
||||||
echo " • Insufficient permissions"
|
echo " ${ICON_LIST} Insufficient permissions"
|
||||||
echo " • System protection (SIP) prevents deletion"
|
echo " ${ICON_LIST} System protection (SIP) prevents deletion"
|
||||||
echo ""
|
echo ""
|
||||||
echo " ${GRAY}Press any key to continue...${NC}"
|
echo " ${GRAY}Press any key to continue...${NC}"
|
||||||
read_key >/dev/null 2>&1
|
read_key >/dev/null 2>&1
|
||||||
@@ -2298,20 +2298,20 @@ main() {
|
|||||||
echo "Interactive disk space explorer - Navigate folders sorted by size"
|
echo "Interactive disk space explorer - Navigate folders sorted by size"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Keyboard Controls:"
|
echo "Keyboard Controls:"
|
||||||
echo " ↑/↓ Navigate items"
|
echo " ${ICON_NAV_UP}/${ICON_NAV_DOWN} Navigate items"
|
||||||
echo " Enter / → Open selected folder"
|
echo " Enter / ${ICON_NAV_RIGHT} Open selected folder"
|
||||||
echo " ← Go back to parent directory"
|
echo " ${ICON_NAV_LEFT} Go back to parent directory"
|
||||||
echo " Delete Delete selected file/folder (requires confirmation)"
|
echo " Delete Delete selected file/folder (requires confirmation)"
|
||||||
echo " O Reveal current directory in Finder"
|
echo " O Reveal current directory in Finder"
|
||||||
echo " Q / ESC Quit the explorer"
|
echo " Q / ESC Quit the explorer"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Features:"
|
echo "Features:"
|
||||||
echo " • Files and folders sorted by size (largest first)"
|
echo " ${ICON_LIST} Files and folders sorted by size (largest first)"
|
||||||
echo " • Shows top 16 items per directory"
|
echo " ${ICON_LIST} Shows top 16 items per directory"
|
||||||
echo " • Fast parallel scanning with smart timeout"
|
echo " ${ICON_LIST} Fast parallel scanning with smart timeout"
|
||||||
echo " • Session cache for instant navigation"
|
echo " ${ICON_LIST} Session cache for instant navigation"
|
||||||
echo " • Color coding for large folders (Red >10GB, Yellow >1GB)"
|
echo " ${ICON_LIST} Color coding for large folders (Red >10GB, Yellow >1GB)"
|
||||||
echo " • Safe deletion with confirmation"
|
echo " ${ICON_LIST} Safe deletion with confirmation"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Examples:"
|
echo "Examples:"
|
||||||
echo " mole analyze Start exploring from home directory"
|
echo " mole analyze Start exploring from home directory"
|
||||||
|
|||||||
@@ -28,21 +28,21 @@ show_help() {
|
|||||||
echo "Interactive application uninstaller - Remove apps completely"
|
echo "Interactive application uninstaller - Remove apps completely"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Keyboard Controls:"
|
echo "Keyboard Controls:"
|
||||||
echo " ↑/↓ Navigate items"
|
echo " ${ICON_NAV_UP}/${ICON_NAV_DOWN} Navigate items"
|
||||||
echo " Space Select/deselect"
|
echo " Space Select/deselect"
|
||||||
echo " Enter Confirm and uninstall"
|
echo " Enter Confirm and uninstall"
|
||||||
echo " Q / ESC Quit"
|
echo " Q / ESC Quit"
|
||||||
echo ""
|
echo ""
|
||||||
echo "What gets cleaned:"
|
echo "What gets cleaned:"
|
||||||
echo " • Application bundle"
|
echo " ${ICON_LIST} Application bundle"
|
||||||
echo " • Application Support data (12+ locations)"
|
echo " ${ICON_LIST} Application Support data (12+ locations)"
|
||||||
echo " • Cache files"
|
echo " ${ICON_LIST} Cache files"
|
||||||
echo " • Preference files"
|
echo " ${ICON_LIST} Preference files"
|
||||||
echo " • Log files"
|
echo " ${ICON_LIST} Log files"
|
||||||
echo " • Saved application state"
|
echo " ${ICON_LIST} Saved application state"
|
||||||
echo " • Container data (sandboxed apps)"
|
echo " ${ICON_LIST} Container data (sandboxed apps)"
|
||||||
echo " • WebKit storage, HTTP storage, cookies"
|
echo " ${ICON_LIST} WebKit storage, HTTP storage, cookies"
|
||||||
echo " • Extensions, plugins, services"
|
echo " ${ICON_LIST} Extensions, plugins, services"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Examples:"
|
echo "Examples:"
|
||||||
echo " mole uninstall Launch interactive uninstaller"
|
echo " mole uninstall Launch interactive uninstaller"
|
||||||
@@ -390,7 +390,7 @@ uninstall_applications() {
|
|||||||
local total_size_freed=0
|
local total_size_freed=0
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${PURPLE}▶ Uninstalling selected applications${NC}"
|
echo -e "${PURPLE}${ICON_ARROW} Uninstalling selected applications${NC}"
|
||||||
|
|
||||||
if [[ ${#selected_apps[@]} -eq 0 ]]; then
|
if [[ ${#selected_apps[@]} -eq 0 ]]; then
|
||||||
log_warning "No applications selected for uninstallation"
|
log_warning "No applications selected for uninstallation"
|
||||||
@@ -404,14 +404,14 @@ uninstall_applications() {
|
|||||||
|
|
||||||
# Check if app is running (use app path for precise matching)
|
# Check if app is running (use app path for precise matching)
|
||||||
if pgrep -f "$app_path" >/dev/null 2>&1; then
|
if pgrep -f "$app_path" >/dev/null 2>&1; then
|
||||||
echo -e "${YELLOW}⚠ $app_name is currently running${NC}"
|
echo -e "${YELLOW}${ICON_ERROR} $app_name is currently running${NC}"
|
||||||
read -p " Force quit $app_name? (y/N): " -n 1 -r
|
read -p " Force quit $app_name? (y/N): " -n 1 -r
|
||||||
echo
|
echo
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
pkill -f "$app_path" 2>/dev/null || true
|
pkill -f "$app_path" 2>/dev/null || true
|
||||||
sleep 2
|
sleep 2
|
||||||
else
|
else
|
||||||
echo -e " ${BLUE}○${NC} Skipped $app_name"
|
echo -e " ${BLUE}${ICON_EMPTY}${NC} Skipped $app_name"
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -429,18 +429,18 @@ uninstall_applications() {
|
|||||||
local total_kb=$((app_size_kb + related_size_kb + system_size_kb))
|
local total_kb=$((app_size_kb + related_size_kb + system_size_kb))
|
||||||
|
|
||||||
# Show what will be removed
|
# Show what will be removed
|
||||||
echo -e "${BLUE}◎${NC} $app_name - Files to be removed:"
|
echo -e "${BLUE}${ICON_CONFIRM}${NC} $app_name - Files to be removed:"
|
||||||
echo -e " ${GREEN}✓${NC} Application: $(echo "$app_path" | sed "s|$HOME|~|")"
|
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Application: $(echo "$app_path" | sed "s|$HOME|~|")"
|
||||||
|
|
||||||
# Show user-level files
|
# Show user-level files
|
||||||
while IFS= read -r file; do
|
while IFS= read -r file; do
|
||||||
[[ -n "$file" && -e "$file" ]] && echo -e " ${GREEN}✓${NC} $(echo "$file" | sed "s|$HOME|~|")"
|
[[ -n "$file" && -e "$file" ]] && echo -e " ${GREEN}${ICON_SUCCESS}${NC} $(echo "$file" | sed "s|$HOME|~|")"
|
||||||
done <<< "$related_files"
|
done <<< "$related_files"
|
||||||
|
|
||||||
# Show system-level files
|
# Show system-level files
|
||||||
if [[ -n "$system_files" ]]; then
|
if [[ -n "$system_files" ]]; then
|
||||||
while IFS= read -r file; do
|
while IFS= read -r file; do
|
||||||
[[ -n "$file" && -e "$file" ]] && echo -e " ${BLUE}●${NC} System: $file"
|
[[ -n "$file" && -e "$file" ]] && echo -e " ${BLUE}${ICON_SOLID}${NC} System: $file"
|
||||||
done <<< "$system_files"
|
done <<< "$system_files"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -461,9 +461,9 @@ uninstall_applications() {
|
|||||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
# Remove the application
|
# Remove the application
|
||||||
if rm -rf "$app_path" 2>/dev/null; then
|
if rm -rf "$app_path" 2>/dev/null; then
|
||||||
echo -e " ${GREEN}✓${NC} Removed application"
|
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Removed application"
|
||||||
else
|
else
|
||||||
echo -e " ${RED}✗${NC} Failed to remove $app_path"
|
echo -e " ${RED}${ICON_ERROR}${NC} Failed to remove $app_path"
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -471,20 +471,20 @@ uninstall_applications() {
|
|||||||
while IFS= read -r file; do
|
while IFS= read -r file; do
|
||||||
if [[ -n "$file" && -e "$file" ]]; then
|
if [[ -n "$file" && -e "$file" ]]; then
|
||||||
if rm -rf "$file" 2>/dev/null; then
|
if rm -rf "$file" 2>/dev/null; then
|
||||||
echo -e " ${GREEN}✓${NC} Removed $(echo "$file" | sed "s|$HOME|~|" | xargs basename)"
|
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Removed $(echo "$file" | sed "s|$HOME|~|" | xargs basename)"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done <<< "$related_files"
|
done <<< "$related_files"
|
||||||
|
|
||||||
# Remove system-level files (requires sudo)
|
# Remove system-level files (requires sudo)
|
||||||
if [[ -n "$system_files" ]]; then
|
if [[ -n "$system_files" ]]; then
|
||||||
echo -e " ${BLUE}●${NC} Admin access required for system files"
|
echo -e " ${BLUE}${ICON_SOLID}${NC} Admin access required for system files"
|
||||||
while IFS= read -r file; do
|
while IFS= read -r file; do
|
||||||
if [[ -n "$file" && -e "$file" ]]; then
|
if [[ -n "$file" && -e "$file" ]]; then
|
||||||
if sudo rm -rf "$file" 2>/dev/null; then
|
if sudo rm -rf "$file" 2>/dev/null; then
|
||||||
echo -e " ${GREEN}✓${NC} Removed $(basename "$file")"
|
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Removed $(basename "$file")"
|
||||||
else
|
else
|
||||||
echo -e " ${YELLOW}⚠${NC} Failed to remove: $file"
|
echo -e " ${YELLOW}${ICON_ERROR}${NC} Failed to remove: $file"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done <<< "$system_files"
|
done <<< "$system_files"
|
||||||
@@ -494,14 +494,14 @@ uninstall_applications() {
|
|||||||
((files_cleaned++))
|
((files_cleaned++))
|
||||||
((total_items++))
|
((total_items++))
|
||||||
|
|
||||||
echo -e " ${GREEN}✓${NC} $app_name uninstalled successfully"
|
echo -e " ${GREEN}${ICON_SUCCESS}${NC} $app_name uninstalled successfully"
|
||||||
else
|
else
|
||||||
echo -e " ${BLUE}○${NC} Skipped $app_name"
|
echo -e " ${BLUE}${ICON_EMPTY}${NC} Skipped $app_name"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Show final summary
|
# Show final summary
|
||||||
echo -e "${PURPLE}▶ Uninstallation Summary${NC}"
|
echo -e "${PURPLE}${ICON_ARROW} Uninstallation Summary${NC}"
|
||||||
|
|
||||||
if [[ $total_size_freed -gt 0 ]]; then
|
if [[ $total_size_freed -gt 0 ]]; then
|
||||||
if [[ $total_size_freed -gt 1048576 ]]; then # > 1GB
|
if [[ $total_size_freed -gt 1048576 ]]; then # > 1GB
|
||||||
@@ -512,10 +512,10 @@ uninstall_applications() {
|
|||||||
local freed_display="${total_size_freed}KB"
|
local freed_display="${total_size_freed}KB"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e " ${GREEN}✓${NC} Freed $freed_display of disk space"
|
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Freed $freed_display of disk space"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e " ${GREEN}✓${NC} Applications uninstalled: $files_cleaned"
|
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Applications uninstalled: $files_cleaned"
|
||||||
((total_size_cleaned += total_size_freed))
|
((total_size_cleaned += total_size_freed))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -632,7 +632,7 @@ main() {
|
|||||||
local extra=$((selection_count-3))
|
local extra=$((selection_count-3))
|
||||||
local list="${names[*]}"
|
local list="${names[*]}"
|
||||||
[[ $extra -gt 0 ]] && list+=" +${extra}"
|
[[ $extra -gt 0 ]] && list+=" +${extra}"
|
||||||
echo -e "${BLUE}◎${NC} ${selection_count} apps: ${list}"
|
echo -e "${BLUE}${ICON_CONFIRM}${NC} ${selection_count} apps: ${list}"
|
||||||
|
|
||||||
# Execute batch uninstallation (handles confirmation)
|
# Execute batch uninstallation (handles confirmation)
|
||||||
batch_uninstall_applications
|
batch_uninstall_applications
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ VERBOSE=1
|
|||||||
readonly ICON_SUCCESS="✓"
|
readonly ICON_SUCCESS="✓"
|
||||||
readonly ICON_ADMIN="●"
|
readonly ICON_ADMIN="●"
|
||||||
readonly ICON_CONFIRM="◎"
|
readonly ICON_CONFIRM="◎"
|
||||||
readonly ICON_ERROR="✗"
|
readonly ICON_ERROR="☻"
|
||||||
|
|
||||||
# Logging functions
|
# Logging functions
|
||||||
log_info() { [[ ${VERBOSE} -eq 1 ]] && echo -e "${BLUE}$1${NC}"; }
|
log_info() { [[ ${VERBOSE} -eq 1 ]] && echo -e "${BLUE}$1${NC}"; }
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ batch_uninstall_applications() {
|
|||||||
local app_size_display=$(bytes_to_human "$((total_kb * 1024))")
|
local app_size_display=$(bytes_to_human "$((total_kb * 1024))")
|
||||||
|
|
||||||
echo -e "${BLUE}${ICON_CONFIRM}${NC} ${app_name} ${GRAY}(${app_size_display})${NC}"
|
echo -e "${BLUE}${ICON_CONFIRM}${NC} ${app_name} ${GRAY}(${app_size_display})${NC}"
|
||||||
echo -e " ${GREEN}✓${NC} $(echo "$app_path" | sed "s|$HOME|~|")"
|
echo -e " ${GREEN}${ICON_SUCCESS}${NC} $(echo "$app_path" | sed "s|$HOME|~|")"
|
||||||
|
|
||||||
# Show related files (limit to 5 most important ones for brevity)
|
# Show related files (limit to 5 most important ones for brevity)
|
||||||
local file_count=0
|
local file_count=0
|
||||||
@@ -76,7 +76,7 @@ batch_uninstall_applications() {
|
|||||||
while IFS= read -r file; do
|
while IFS= read -r file; do
|
||||||
if [[ -n "$file" && -e "$file" ]]; then
|
if [[ -n "$file" && -e "$file" ]]; then
|
||||||
if [[ $file_count -lt $max_files ]]; then
|
if [[ $file_count -lt $max_files ]]; then
|
||||||
echo -e " ${GREEN}✓${NC} $(echo "$file" | sed "s|$HOME|~|")"
|
echo -e " ${GREEN}${ICON_SUCCESS}${NC} $(echo "$file" | sed "s|$HOME|~|")"
|
||||||
fi
|
fi
|
||||||
((file_count++))
|
((file_count++))
|
||||||
fi
|
fi
|
||||||
@@ -100,7 +100,7 @@ batch_uninstall_applications() {
|
|||||||
if [[ ${#running_apps[@]} -gt 0 ]]; then
|
if [[ ${#running_apps[@]} -gt 0 ]]; then
|
||||||
removal_note+=" - will force quit: ${running_apps[*]}"
|
removal_note+=" - will force quit: ${running_apps[*]}"
|
||||||
fi
|
fi
|
||||||
echo -ne "${PURPLE}☛${NC} ${removal_note}. Press ${GREEN}Enter${NC} to confirm, ${GRAY}ESC${NC} to cancel: "
|
echo -ne "${PURPLE}${ICON_ARROW}${NC} ${removal_note}. Press ${GREEN}Enter${NC} to confirm, ${GRAY}ESC${NC} to cancel: "
|
||||||
|
|
||||||
IFS= read -r -s -n1 key || key=""
|
IFS= read -r -s -n1 key || key=""
|
||||||
case "$key" in
|
case "$key" in
|
||||||
|
|||||||
@@ -20,16 +20,20 @@ readonly RED="${ESC}[0;31m"
|
|||||||
readonly GRAY="${ESC}[0;90m"
|
readonly GRAY="${ESC}[0;90m"
|
||||||
readonly NC="${ESC}[0m"
|
readonly NC="${ESC}[0m"
|
||||||
|
|
||||||
# Icon definitions
|
# Icon definitions (shared across modules)
|
||||||
readonly ICON_CONFIRM="◎" # Confirm operation
|
readonly ICON_CONFIRM="◎" # Confirm operation / spinner text
|
||||||
readonly ICON_ADMIN="⚙" # Admin permission
|
readonly ICON_ADMIN="⚙" # Gear indicator for admin/settings/system info
|
||||||
readonly ICON_SUCCESS="✓" # Success
|
readonly ICON_SUCCESS="✓" # Success mark
|
||||||
readonly ICON_ERROR="✗" # Error
|
readonly ICON_ERROR="☻" # Error / warning mark
|
||||||
readonly ICON_EMPTY="○" # Empty state
|
readonly ICON_EMPTY="○" # Hollow circle (empty state / unchecked)
|
||||||
readonly ICON_LIST="-" # List item
|
readonly ICON_SOLID="●" # Solid circle (selected / system marker)
|
||||||
readonly ICON_MENU="▸" # Menu item
|
readonly ICON_LIST="•" # Basic list bullet
|
||||||
readonly ICON_SYSTEM="❤︎" # System/Architecture info
|
readonly ICON_ARROW="➤" # Pointer / prompt indicator
|
||||||
readonly ICON_SETTINGS="⚙" # Settings/Configuration
|
readonly ICON_WARNING="☻" # Warning marker (shares glyph with error)
|
||||||
|
readonly ICON_NAV_UP="↑" # Navigation up
|
||||||
|
readonly ICON_NAV_DOWN="↓" # Navigation down
|
||||||
|
readonly ICON_NAV_LEFT="←" # Navigation left
|
||||||
|
readonly ICON_NAV_RIGHT="→" # Navigation right
|
||||||
|
|
||||||
# Spinner character helpers (ASCII by default, overridable via env)
|
# Spinner character helpers (ASCII by default, overridable via env)
|
||||||
mo_spinner_chars() {
|
mo_spinner_chars() {
|
||||||
@@ -81,7 +85,7 @@ log_error() {
|
|||||||
|
|
||||||
log_header() {
|
log_header() {
|
||||||
rotate_log
|
rotate_log
|
||||||
echo -e "\n${PURPLE}${ICON_MENU} $1${NC}"
|
echo -e "\n${PURPLE}${ICON_ARROW} $1${NC}"
|
||||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] SECTION: $1" >> "$LOG_FILE" 2>/dev/null || true
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] SECTION: $1" >> "$LOG_FILE" 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +117,7 @@ icon_list() {
|
|||||||
icon_menu() {
|
icon_menu() {
|
||||||
local num="$1"
|
local num="$1"
|
||||||
local text="$2"
|
local text="$2"
|
||||||
echo -e "${BLUE}${ICON_MENU} ${num}. ${text}${NC}"
|
echo -e "${BLUE}${ICON_ARROW} ${num}. ${text}${NC}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Consistent summary blocks for command results
|
# Consistent summary blocks for command results
|
||||||
@@ -267,7 +271,7 @@ show_menu_option() {
|
|||||||
local selected="$3"
|
local selected="$3"
|
||||||
|
|
||||||
if [[ "$selected" == "true" ]]; then
|
if [[ "$selected" == "true" ]]; then
|
||||||
echo -e "${BLUE}▶ $number. $text${NC}"
|
echo -e "${BLUE}${ICON_ARROW} $number. $text${NC}"
|
||||||
else
|
else
|
||||||
echo " $number. $text"
|
echo " $number. $text"
|
||||||
fi
|
fi
|
||||||
@@ -376,7 +380,7 @@ request_sudo_access() {
|
|||||||
|
|
||||||
# If Touch ID is supported and not forced to use password
|
# If Touch ID is supported and not forced to use password
|
||||||
if [[ "$force_password" != "true" ]] && check_touchid_support; then
|
if [[ "$force_password" != "true" ]] && check_touchid_support; then
|
||||||
echo -e "${GRAY}${ICON_ADMIN}${NC} ${GRAY}${prompt_msg} (Touch ID or password)${NC}"
|
echo -e "${PURPLE}${ICON_ARROW}${NC} ${prompt_msg} ${GRAY}(Touch ID or password)${NC}"
|
||||||
if sudo -v 2>/dev/null; then
|
if sudo -v 2>/dev/null; then
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
@@ -384,8 +388,8 @@ request_sudo_access() {
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# Traditional password method
|
# Traditional password method
|
||||||
echo -e "${GRAY}${ICON_ADMIN}${NC} ${GRAY}${prompt_msg}${NC}"
|
echo -e "${PURPLE}${ICON_ARROW}${NC} ${prompt_msg}"
|
||||||
echo -ne "${GRAY}${ICON_MENU}${NC} Password: "
|
echo -ne "${PURPLE}${ICON_ARROW}${NC} Password: "
|
||||||
read -s password
|
read -s password
|
||||||
echo ""
|
echo ""
|
||||||
if [[ -n "$password" ]] && echo "$password" | sudo -S true 2>/dev/null; then
|
if [[ -n "$password" ]] && echo "$password" | sudo -S true 2>/dev/null; then
|
||||||
@@ -439,7 +443,7 @@ update_via_homebrew() {
|
|||||||
# Get current version
|
# Get current version
|
||||||
local current_version
|
local current_version
|
||||||
current_version=$(brew list --versions mole 2>/dev/null | awk '{print $2}')
|
current_version=$(brew list --versions mole 2>/dev/null | awk '{print $2}')
|
||||||
echo -e "${GREEN}✓${NC} Already on latest version (${current_version:-$version})"
|
echo -e "${GREEN}${ICON_SUCCESS}${NC} Already on latest version (${current_version:-$version})"
|
||||||
elif echo "$upgrade_output" | grep -q "Error:"; then
|
elif echo "$upgrade_output" | grep -q "Error:"; then
|
||||||
log_error "Homebrew upgrade failed"
|
log_error "Homebrew upgrade failed"
|
||||||
echo "$upgrade_output" | grep "Error:" >&2
|
echo "$upgrade_output" | grep "Error:" >&2
|
||||||
@@ -450,7 +454,7 @@ update_via_homebrew() {
|
|||||||
# Get new version
|
# Get new version
|
||||||
local new_version
|
local new_version
|
||||||
new_version=$(brew list --versions mole 2>/dev/null | awk '{print $2}')
|
new_version=$(brew list --versions mole 2>/dev/null | awk '{print $2}')
|
||||||
echo -e "${GREEN}✓${NC} Updated to latest version (${new_version:-$version})"
|
echo -e "${GREEN}${ICON_SUCCESS}${NC} Updated to latest version (${new_version:-$version})"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Clear version check cache
|
# Clear version check cache
|
||||||
@@ -555,9 +559,9 @@ stop_spinner() {
|
|||||||
|
|
||||||
if [[ -n "$result_message" ]]; then
|
if [[ -n "$result_message" ]]; then
|
||||||
if [[ -t 1 ]]; then
|
if [[ -t 1 ]]; then
|
||||||
printf "\r${MOLE_SPINNER_PREFIX:-}${GREEN}✓${NC} %s\n" "$result_message"
|
printf "\r${MOLE_SPINNER_PREFIX:-}${GREEN}${ICON_SUCCESS}${NC} %s\n" "$result_message"
|
||||||
else
|
else
|
||||||
echo " ✓ $result_message"
|
echo " ${ICON_SUCCESS} $result_message"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -687,7 +691,7 @@ with_spinner() {
|
|||||||
local exit_code=$?
|
local exit_code=$?
|
||||||
if [[ -t 1 ]]; then stop_inline_spinner; fi
|
if [[ -t 1 ]]; then stop_inline_spinner; fi
|
||||||
# Exit code 124 means timeout
|
# Exit code 124 means timeout
|
||||||
[[ $exit_code -eq 124 ]] && echo -e " ${YELLOW}⚠${NC} $msg timed out (skipped)" >&2
|
[[ $exit_code -eq 124 ]] && echo -e " ${YELLOW}${ICON_WARNING}${NC} $msg timed out (skipped)" >&2
|
||||||
return $exit_code
|
return $exit_code
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -700,7 +704,7 @@ with_spinner() {
|
|||||||
kill -TERM $cmd_pid 2>/dev/null || true
|
kill -TERM $cmd_pid 2>/dev/null || true
|
||||||
wait $cmd_pid 2>/dev/null || true
|
wait $cmd_pid 2>/dev/null || true
|
||||||
if [[ -t 1 ]]; then stop_inline_spinner; fi
|
if [[ -t 1 ]]; then stop_inline_spinner; fi
|
||||||
echo -e " ${YELLOW}⚠${NC} $msg timed out (skipped)" >&2
|
echo -e " ${YELLOW}${ICON_WARNING}${NC} $msg timed out (skipped)" >&2
|
||||||
return 124
|
return 124
|
||||||
fi
|
fi
|
||||||
sleep 1
|
sleep 1
|
||||||
@@ -729,12 +733,12 @@ clean_tool_cache() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
if MOLE_SPINNER_PREFIX=" " with_spinner "$label" "$@"; then
|
if MOLE_SPINNER_PREFIX=" " with_spinner "$label" "$@"; then
|
||||||
echo -e " ${GREEN}✓${NC} $label"
|
echo -e " ${GREEN}${ICON_SUCCESS}${NC} $label"
|
||||||
else
|
else
|
||||||
local exit_code=$?
|
local exit_code=$?
|
||||||
# Timeout returns 124, don't show error message (already shown by with_spinner)
|
# Timeout returns 124, don't show error message (already shown by with_spinner)
|
||||||
if [[ $exit_code -ne 124 ]]; then
|
if [[ $exit_code -ne 124 ]]; then
|
||||||
echo -e " ${YELLOW}⚠${NC} $label failed (skipped)" >&2
|
echo -e " ${YELLOW}${ICON_WARNING}${NC} $label failed (skipped)" >&2
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
return 0 # Always return success to continue cleanup
|
return 0 # Always return success to continue cleanup
|
||||||
@@ -752,7 +756,7 @@ prompt_action() {
|
|||||||
local cancel="${2:-cancel}"
|
local cancel="${2:-cancel}"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -ne "${PURPLE}☛${NC} Press ${GREEN}Enter${NC} to ${action}, ${GRAY}ESC${NC} to ${cancel}: "
|
echo -ne "${PURPLE}${ICON_ARROW}${NC} Press ${GREEN}Enter${NC} to ${action}, ${GRAY}ESC${NC} to ${cancel}: "
|
||||||
IFS= read -r -s -n1 key || key=""
|
IFS= read -r -s -n1 key || key=""
|
||||||
|
|
||||||
case "$key" in
|
case "$key" in
|
||||||
@@ -1024,13 +1028,13 @@ start_section() {
|
|||||||
TRACK_SECTION=1
|
TRACK_SECTION=1
|
||||||
SECTION_ACTIVITY=0
|
SECTION_ACTIVITY=0
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${PURPLE}▶ $1${NC}"
|
echo -e "${PURPLE}${ICON_ARROW} $1${NC}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# End a section (show "Nothing to tidy" if no activity)
|
# End a section (show "Nothing to tidy" if no activity)
|
||||||
end_section() {
|
end_section() {
|
||||||
if [[ $TRACK_SECTION -eq 1 && $SECTION_ACTIVITY -eq 0 ]]; then
|
if [[ $TRACK_SECTION -eq 1 && $SECTION_ACTIVITY -eq 0 ]]; then
|
||||||
echo -e " ${BLUE}○${NC} Nothing to tidy"
|
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Nothing to tidy"
|
||||||
fi
|
fi
|
||||||
TRACK_SECTION=0
|
TRACK_SECTION=0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,11 +94,11 @@ paginated_multi_select() {
|
|||||||
|
|
||||||
render_item() {
|
render_item() {
|
||||||
local idx=$1 is_current=$2
|
local idx=$1 is_current=$2
|
||||||
local checkbox="○"
|
local checkbox="$ICON_EMPTY"
|
||||||
[[ ${selected[idx]} == true ]] && checkbox="●"
|
[[ ${selected[idx]} == true ]] && checkbox="$ICON_SOLID"
|
||||||
|
|
||||||
if [[ $is_current == true ]]; then
|
if [[ $is_current == true ]]; then
|
||||||
printf "\r\033[2K${BLUE}> %s %s${NC}\n" "$checkbox" "${items[idx]}" >&2
|
printf "\r\033[2K${BLUE}${ICON_ARROW} %s %s${NC}\n" "$checkbox" "${items[idx]}" >&2
|
||||||
else
|
else
|
||||||
printf "\r\033[2K %s %s\n" "$checkbox" "${items[idx]}" >&2
|
printf "\r\033[2K %s %s\n" "$checkbox" "${items[idx]}" >&2
|
||||||
fi
|
fi
|
||||||
@@ -168,7 +168,7 @@ paginated_multi_select() {
|
|||||||
|
|
||||||
# Clear any remaining lines at bottom
|
# Clear any remaining lines at bottom
|
||||||
printf "${clear_line}\n" >&2
|
printf "${clear_line}\n" >&2
|
||||||
printf "${clear_line}${GRAY}↑/↓${NC} Navigate ${GRAY}|${NC} ${GRAY}Space${NC} Select ${GRAY}|${NC} ${GRAY}Enter${NC} Confirm ${GRAY}|${NC} ${GRAY}Q/ESC${NC} Quit\n" >&2
|
printf "${clear_line}${GRAY}${ICON_NAV_UP}/${ICON_NAV_DOWN}${NC} Navigate ${GRAY}|${NC} ${GRAY}Space${NC} Select ${GRAY}|${NC} ${GRAY}Enter${NC} Confirm ${GRAY}|${NC} ${GRAY}Q/ESC${NC} Quit\n" >&2
|
||||||
|
|
||||||
# Clear one more line to ensure no artifacts
|
# Clear one more line to ensure no artifacts
|
||||||
printf "${clear_line}" >&2
|
printf "${clear_line}" >&2
|
||||||
@@ -177,14 +177,14 @@ paginated_multi_select() {
|
|||||||
# Show help screen
|
# Show help screen
|
||||||
show_help() {
|
show_help() {
|
||||||
printf "\033[H\033[J" >&2
|
printf "\033[H\033[J" >&2
|
||||||
cat >&2 << 'EOF'
|
cat >&2 <<EOF
|
||||||
Help - Navigation Controls
|
Help - Navigation Controls
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
↑ / ↓ Navigate up/down
|
${ICON_NAV_UP} / ${ICON_NAV_DOWN} Navigate up/down
|
||||||
Space Select/deselect item
|
Space Select/deselect item
|
||||||
Enter Confirm selection
|
Enter Confirm selection
|
||||||
Q / ESC Exit
|
Q / ESC Exit
|
||||||
|
|
||||||
Press any key to continue...
|
Press any key to continue...
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
21
mole
21
mole
@@ -22,7 +22,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||||||
source "$SCRIPT_DIR/lib/common.sh"
|
source "$SCRIPT_DIR/lib/common.sh"
|
||||||
|
|
||||||
# Version info
|
# Version info
|
||||||
VERSION="1.7.8"
|
VERSION="1.7.9"
|
||||||
MOLE_TAGLINE="can dig deep to clean your Mac."
|
MOLE_TAGLINE="can dig deep to clean your Mac."
|
||||||
|
|
||||||
# Get latest version from remote repository
|
# Get latest version from remote repository
|
||||||
@@ -36,12 +36,13 @@ get_latest_version() {
|
|||||||
check_for_updates() {
|
check_for_updates() {
|
||||||
local cache="$HOME/.cache/mole/version_check"
|
local cache="$HOME/.cache/mole/version_check"
|
||||||
local msg_cache="$HOME/.cache/mole/update_message"
|
local msg_cache="$HOME/.cache/mole/update_message"
|
||||||
|
local ttl="${MO_UPDATE_CHECK_TTL:-3600}"
|
||||||
mkdir -p "$(dirname "$cache")" 2>/dev/null
|
mkdir -p "$(dirname "$cache")" 2>/dev/null
|
||||||
|
|
||||||
# Skip if checked within 3 hours
|
# Skip if checked recently
|
||||||
if [[ -f "$cache" ]]; then
|
if [[ -f "$cache" ]]; then
|
||||||
local age=$(($(date +%s) - $(stat -f%m "$cache" 2>/dev/null || echo 0)))
|
local age=$(($(date +%s) - $(stat -f%m "$cache" 2>/dev/null || echo 0)))
|
||||||
[[ $age -lt 10800 ]] && return
|
[[ $age -lt $ttl ]] && return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Background version check (save to file, don't output)
|
# Background version check (save to file, don't output)
|
||||||
@@ -49,7 +50,7 @@ check_for_updates() {
|
|||||||
local latest=$(get_latest_version)
|
local latest=$(get_latest_version)
|
||||||
|
|
||||||
if [[ -n "$latest" && "$VERSION" != "$latest" && "$(printf '%s\n' "$VERSION" "$latest" | sort -V | head -1)" == "$VERSION" ]]; then
|
if [[ -n "$latest" && "$VERSION" != "$latest" && "$(printf '%s\n' "$VERSION" "$latest" | sort -V | head -1)" == "$VERSION" ]]; then
|
||||||
echo -e "${YELLOW}New version ${GREEN}${latest}${YELLOW} available (current: ${VERSION})\n${YELLOW}Run ${GREEN}mo update${YELLOW} to upgrade${NC}" > "$msg_cache"
|
printf "\nUpdate available: %s → %s, run %smo update%s\n\n" "$VERSION" "$latest" "$GREEN" "$NC" > "$msg_cache"
|
||||||
else
|
else
|
||||||
echo -n > "$msg_cache"
|
echo -n > "$msg_cache"
|
||||||
fi
|
fi
|
||||||
@@ -163,7 +164,7 @@ update_mole() {
|
|||||||
|
|
||||||
if [[ "$VERSION" == "$latest" ]]; then
|
if [[ "$VERSION" == "$latest" ]]; then
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${GREEN}✓${NC} Already on latest version (${VERSION})"
|
echo -e "${GREEN}${ICON_SUCCESS}${NC} Already on latest version (${VERSION})"
|
||||||
echo ""
|
echo ""
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
@@ -229,7 +230,7 @@ update_mole() {
|
|||||||
if ! printf '%s\n' "$install_output" | grep -Eq "Updated to latest version|Already on latest version"; then
|
if ! printf '%s\n' "$install_output" | grep -Eq "Updated to latest version|Already on latest version"; then
|
||||||
local new_version
|
local new_version
|
||||||
new_version=$("$mole_path" --version 2>/dev/null | awk 'NF {print $NF}' || echo "")
|
new_version=$("$mole_path" --version 2>/dev/null | awk 'NF {print $NF}' || echo "")
|
||||||
printf '\n%s\n\n' "${GREEN}✓${NC} Updated to latest version (${new_version:-unknown})"
|
printf '\n%s\n\n' "${GREEN}${ICON_SUCCESS}${NC} Updated to latest version (${new_version:-unknown})"
|
||||||
else
|
else
|
||||||
printf '\n'
|
printf '\n'
|
||||||
fi
|
fi
|
||||||
@@ -245,7 +246,7 @@ update_mole() {
|
|||||||
if ! printf '%s\n' "$install_output" | grep -Eq "Updated to latest version|Already on latest version"; then
|
if ! printf '%s\n' "$install_output" | grep -Eq "Updated to latest version|Already on latest version"; then
|
||||||
local new_version
|
local new_version
|
||||||
new_version=$("$mole_path" --version 2>/dev/null | awk 'NF {print $NF}' || echo "")
|
new_version=$("$mole_path" --version 2>/dev/null | awk 'NF {print $NF}' || echo "")
|
||||||
printf '\n%s\n\n' "${GREEN}✓${NC} Updated to latest version (${new_version:-unknown})"
|
printf '\n%s\n\n' "${GREEN}${ICON_SUCCESS}${NC} Updated to latest version (${new_version:-unknown})"
|
||||||
else
|
else
|
||||||
printf '\n'
|
printf '\n'
|
||||||
fi
|
fi
|
||||||
@@ -330,7 +331,7 @@ remove_mole() {
|
|||||||
done
|
done
|
||||||
echo " - ~/.config/mole"
|
echo " - ~/.config/mole"
|
||||||
echo " - ~/.cache/mole"
|
echo " - ~/.cache/mole"
|
||||||
echo -ne "${PURPLE}☛${NC} Press ${GREEN}Enter${NC} to confirm, ${GRAY}ESC${NC} to cancel: "
|
echo -ne "${PURPLE}${ICON_ARROW}${NC} Press ${GREEN}Enter${NC} to confirm, ${GRAY}ESC${NC} to cancel: "
|
||||||
|
|
||||||
# Read single key
|
# Read single key
|
||||||
IFS= read -r -s -n1 key || key=""
|
IFS= read -r -s -n1 key || key=""
|
||||||
@@ -385,9 +386,9 @@ remove_mole() {
|
|||||||
# Show final result
|
# Show final result
|
||||||
local final_message
|
local final_message
|
||||||
if [[ "$has_error" == "true" ]]; then
|
if [[ "$has_error" == "true" ]]; then
|
||||||
final_message="${YELLOW}⚠ Mole uninstalled with some errors, thank you for using Mole!${NC}"
|
final_message="${YELLOW}${ICON_ERROR} Mole uninstalled with some errors, thank you for using Mole!${NC}"
|
||||||
else
|
else
|
||||||
final_message="${GREEN}✓ Mole uninstalled successfully, thank you for using Mole!${NC}"
|
final_message="${GREEN}${ICON_SUCCESS} Mole uninstalled successfully, thank you for using Mole!${NC}"
|
||||||
fi
|
fi
|
||||||
printf '\n%s\n\n' "$final_message"
|
printf '\n%s\n\n' "$final_message"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user