diff --git a/.shellcheckrc b/.shellcheckrc index 5fa7515..21c0878 100644 --- a/.shellcheckrc +++ b/.shellcheckrc @@ -1,10 +1,7 @@ # Mole project shellcheck configuration -# -# Keep the lint strict by default. Add rules to disable only when we have a -# clear justification. -# -# Examples: -# disable=SC2034 # unused variables (if intentionally unused) -# disable=SC1091 # sourcing files not present in repo (optional) -# Currently no global disables are required. +disable=SC2155 +disable=SC2034 +disable=SC2154 +disable=SC2001 + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d96b7ff..350888b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,6 +26,7 @@ shellcheck -S warning mole bin/*.sh lib/*.sh ## Git Hooks Pre-commit hook will auto-format your code. Install with: + ```bash ./scripts/install-hooks.sh ``` diff --git a/bin/analyze.sh b/bin/analyze.sh index 298c6b4..75befc5 100755 --- a/bin/analyze.sh +++ b/bin/analyze.sh @@ -21,7 +21,6 @@ readonly CACHE_DIR="${HOME}/.config/mole/cache" readonly TEMP_PREFIX="/tmp/mole_analyze_$$" readonly MIN_LARGE_FILE_SIZE="1000000000" # 1GB readonly MIN_MEDIUM_FILE_SIZE="100000000" # 100MB -readonly MIN_SMALL_FILE_SIZE="10000000" # 10MB # Emoji badges for list displays only readonly BADGE_DIR="🍞" @@ -32,17 +31,12 @@ readonly BADGE_LOG="🍹" readonly BADGE_APP="🐣" # Global state -declare -a SCAN_RESULTS=() -declare -a DIR_RESULTS=() -declare -a LARGE_FILES=() declare SCAN_PID="" -declare TOTAL_SIZE=0 declare CURRENT_PATH="$HOME" declare CURRENT_DEPTH=1 # UI State declare CURSOR_POS=0 -declare SORT_MODE="size" # size, name, time declare VIEW_MODE="overview" # overview, detail, files # Cleanup on exit @@ -281,8 +275,6 @@ perform_scan() { "Calculating sizes" "Finishing up" ) - local msg_idx=0 - while kill -0 "$SCAN_PID" 2> /dev/null; do # Show different messages based on elapsed time local current_msg="" @@ -1297,8 +1289,6 @@ display_interactive_menu() { # Analyze file types display_file_types() { - local temp_types="$TEMP_PREFIX.types" - log_header "File Types Analysis" echo "" @@ -1617,7 +1607,7 @@ show_volumes_overview() { output+=$'\n' local idx=0 - while IFS='|' read -r priority path display_name; do + while IFS='|' read -r _ path display_name; do # Build line (simple display without size) local line="" if [[ $idx -eq $cursor ]]; then @@ -1650,7 +1640,7 @@ show_volumes_overview() { # Get selected path and enter it local selected_path="" idx=0 - while IFS='|' read -r priority path display_name; do + while IFS='|' read -r _ path _; do if [[ $idx -eq $cursor ]]; then selected_path="$path" break @@ -1697,7 +1687,6 @@ show_volumes_overview() { # Interactive drill-down mode interactive_drill_down() { local start_path="$1" - local initial_items="${2:-}" # Pre-scanned items for first level local current_path="$start_path" local path_stack=() local cursor=0 @@ -1709,7 +1698,6 @@ interactive_drill_down() { # Cache variables to avoid recalculation local -a items=() - local has_calculating=false local total_items=0 # Directory cache: store scan results for each visited directory @@ -1783,7 +1771,6 @@ interactive_drill_down() { total_items=${#items[@]} # No more calculating state - has_calculating=false need_scan=false wait_for_calc=false diff --git a/bin/clean.sh b/bin/clean.sh index aa19711..4c5e859 100755 --- a/bin/clean.sh +++ b/bin/clean.sh @@ -21,8 +21,6 @@ IS_M_SERIES=$([ "$(uname -m)" = "arm64" ] && echo "true" || echo "false") readonly MAX_PARALLEL_JOBS=15 # Maximum parallel background jobs readonly TEMP_FILE_AGE_DAYS=7 # Age threshold for temp file cleanup readonly ORPHAN_AGE_DAYS=60 # Age threshold for orphaned data -readonly SIZE_1GB_KB=1048576 # 1GB in kilobytes -readonly SIZE_1MB_KB=1024 # 1MB in kilobytes # Default whitelist patterns (preselected, user can disable) declare -a DEFAULT_WHITELIST_PATTERNS=( "$HOME/Library/Caches/ms-playwright*" @@ -78,7 +76,6 @@ total_items=0 # Tracking variables TRACK_SECTION=0 SECTION_ACTIVITY=0 -LAST_CLEAN_RESULT=0 files_cleaned=0 total_size_cleaned=0 whitelist_skipped_count=0 @@ -246,7 +243,6 @@ safe_clean() { fi if [[ ${#existing_paths[@]} -eq 0 ]]; then - LAST_CLEAN_RESULT=0 return 0 fi @@ -349,7 +345,6 @@ safe_clean() { note_activity fi - LAST_CLEAN_RESULT=$removed_any return 0 } @@ -448,9 +443,6 @@ perform_cleanup() { echo -e "${BLUE}${ICON_SUCCESS}${NC} Whitelist: 2 core patterns active" fi - # Get initial space - space_before=$(df / | tail -1 | awk '{print $4}') - # Initialize counters total_items=0 files_cleaned=0 @@ -1457,9 +1449,6 @@ perform_cleanup() { end_section # ===== Final summary ===== - space_after=$(df / | tail -1 | awk '{print $4}') - space_freed_kb=$((space_after - space_before)) - echo "" local summary_heading="" diff --git a/lib/app_selector.sh b/lib/app_selector.sh index 55d3ff0..c0a1830 100755 --- a/lib/app_selector.sh +++ b/lib/app_selector.sh @@ -24,6 +24,7 @@ format_app_display() { MOLE_SELECTION_RESULT="" # Main app selection function +# shellcheck disable=SC2154 # apps_data is set by caller select_apps_for_uninstall() { if [[ ${#apps_data[@]} -eq 0 ]]; then log_warning "No applications available for uninstallation" @@ -33,7 +34,8 @@ select_apps_for_uninstall() { # Build menu options local -a menu_options=() for app_data in "${apps_data[@]}"; do - IFS='|' read -r epoch app_path display_name bundle_id size last_used <<< "$app_data" + # Ignore metadata fields not needed for menu display + IFS='|' read -r _ _ display_name _ size last_used <<< "$app_data" menu_options+=("$(format_app_display "$display_name" "$size" "$last_used")") done diff --git a/lib/batch_uninstall.sh b/lib/batch_uninstall.sh index c23a774..817d49a 100755 --- a/lib/batch_uninstall.sh +++ b/lib/batch_uninstall.sh @@ -30,7 +30,7 @@ batch_uninstall_applications() { # Silent analysis without spinner output (avoid visual flicker) for selected_app in "${selected_apps[@]}"; do [[ -z "$selected_app" ]] && continue - IFS='|' read -r epoch app_path app_name bundle_id size last_used <<< "$selected_app" + IFS='|' read -r _ app_path app_name bundle_id _ _ <<< "$selected_app" # Check if app is running (use app path for precise matching) if pgrep -f "$app_path" > /dev/null 2>&1; then diff --git a/lib/common.sh b/lib/common.sh index 93cc376..9ab9251 100755 --- a/lib/common.sh +++ b/lib/common.sh @@ -122,11 +122,9 @@ icon_menu() { # Consistent summary blocks for command results print_summary_block() { - local status="info" local heading="" if [[ $# -gt 0 ]]; then - status="$1" shift fi @@ -138,10 +136,6 @@ print_summary_block() { local -a details=("$@") local divider="======================================================================" - local color="$BLUE" - - local indent=" " - echo "$divider" if [[ -n "$heading" ]]; then echo -e "${BLUE}${heading}${NC}" @@ -253,11 +247,10 @@ read_key() { # Drain pending input (useful for scrolling prevention) drain_pending_input() { - local dummy local drained=0 # Single pass with reasonable timeout # Touchpad scrolling can generate bursts of arrow keys - while IFS= read -r -s -n 1 -t 0.001 dummy 2> /dev/null; do + while IFS= read -r -s -n 1 -t 0.001 _ 2> /dev/null; do ((drained++)) # Safety limit to prevent infinite loop [[ $drained -gt 500 ]] && break diff --git a/lib/whitelist_manager.sh b/lib/whitelist_manager.sh index 6d2c3ef..18a5be3 100755 --- a/lib/whitelist_manager.sh +++ b/lib/whitelist_manager.sh @@ -189,7 +189,7 @@ manage_whitelist_categories() { local -a menu_options=() local index=0 - while IFS='|' read -r display_name pattern category; do + while IFS='|' read -r display_name pattern _; do # Expand $HOME in pattern pattern="${pattern/\$HOME/$HOME}" @@ -240,7 +240,7 @@ manage_whitelist_categories() { preselected_indices+=("$i") done local IFS=',' - MOLE_PRESELECTED_INDICES="${preselected_indices[*]}" + export MOLE_PRESELECTED_INDICES="${preselected_indices[*]}" else unset MOLE_PRESELECTED_INDICES fi