diff --git a/lib/clean/project.sh b/lib/clean/project.sh index 6e5be63..04dcb55 100644 --- a/lib/clean/project.sh +++ b/lib/clean/project.sh @@ -449,6 +449,27 @@ select_purge_categories() { # Recalculate items_per_page dynamically to handle window resize items_per_page=$(_get_items_per_page) + # Clamp pagination state to avoid cursor drifting out of view + local max_top_index=0 + if [[ $total_items -gt $items_per_page ]]; then + max_top_index=$((total_items - items_per_page)) + fi + if [[ $top_index -gt $max_top_index ]]; then + top_index=$max_top_index + fi + if [[ $top_index -lt 0 ]]; then + top_index=0 + fi + + local visible_count=$((total_items - top_index)) + [[ $visible_count -gt $items_per_page ]] && visible_count=$items_per_page + if [[ $cursor_pos -gt $((visible_count - 1)) ]]; then + cursor_pos=$((visible_count - 1)) + fi + if [[ $cursor_pos -lt 0 ]]; then + cursor_pos=0 + fi + printf "\033[H" # Calculate total size of selected items for header local selected_size=0 @@ -477,8 +498,6 @@ select_purge_categories() { IFS=',' read -r -a recent_flags <<< "${PURGE_RECENT_CATEGORIES:-}" # Calculate visible range - local visible_count=$((total_items - top_index)) - [[ $visible_count -gt $items_per_page ]] && visible_count=$items_per_page local end_index=$((top_index + visible_count)) # Draw only visible items diff --git a/lib/optimize/tasks.sh b/lib/optimize/tasks.sh index 48d38f7..6e24929 100644 --- a/lib/optimize/tasks.sh +++ b/lib/optimize/tasks.sh @@ -21,6 +21,21 @@ opt_msg() { fi } +run_launchctl_unload() { + local plist_file="$1" + local need_sudo="${2:-false}" + + if [[ "${MOLE_DRY_RUN:-0}" == "1" ]]; then + return 0 + fi + + if [[ "$need_sudo" == "true" ]]; then + sudo launchctl unload "$plist_file" 2> /dev/null || true + else + launchctl unload "$plist_file" 2> /dev/null || true + fi +} + flush_dns_cache() { # Skip actual flush in dry-run mode if [[ "${MOLE_DRY_RUN:-0}" == "1" ]]; then @@ -354,18 +369,14 @@ opt_startup_items_cleanup() { fi if [[ "$need_sudo" == "true" ]]; then - if [[ "${MOLE_DRY_RUN:-0}" != "1" ]]; then - sudo launchctl unload "$plist_file" 2> /dev/null || true - fi + run_launchctl_unload "$plist_file" "$need_sudo" if safe_sudo_remove "$plist_file"; then ((broken_count++)) else echo -e " ${YELLOW}!${NC} Failed to remove (sudo) $plist_file" fi else - if [[ "${MOLE_DRY_RUN:-0}" != "1" ]]; then - launchctl unload "$plist_file" 2> /dev/null || true - fi + run_launchctl_unload "$plist_file" "$need_sudo" if safe_remove "$plist_file" true; then ((broken_count++)) else @@ -443,9 +454,7 @@ opt_startup_items_cleanup() { debug_log "Removing orphaned helper (app not found, program missing): $plist_file" if [[ "$need_sudo" == "true" ]]; then - if [[ "${MOLE_DRY_RUN:-0}" != "1" ]]; then - sudo launchctl unload "$plist_file" 2> /dev/null || true - fi + run_launchctl_unload "$plist_file" "$need_sudo" # remove the plist safe_sudo_remove "$plist_file" @@ -453,9 +462,7 @@ opt_startup_items_cleanup() { ((broken_count++)) opt_msg "Removed orphaned helper: $(basename "$plist_file" .plist)" else - if [[ "${MOLE_DRY_RUN:-0}" != "1" ]]; then - launchctl unload "$plist_file" 2> /dev/null || true - fi + run_launchctl_unload "$plist_file" "$need_sudo" safe_remove "$plist_file" true ((broken_count++)) opt_msg "Removed orphaned helper: $(basename "$plist_file" .plist)" @@ -471,18 +478,14 @@ opt_startup_items_cleanup() { fi if [[ "$need_sudo" == "true" ]]; then - if [[ "${MOLE_DRY_RUN:-0}" != "1" ]]; then - sudo launchctl unload "$plist_file" 2> /dev/null || true - fi + run_launchctl_unload "$plist_file" "$need_sudo" if safe_sudo_remove "$plist_file"; then ((broken_count++)) else echo -e " ${YELLOW}!${NC} Failed to remove (sudo) $plist_file" fi else - if [[ "${MOLE_DRY_RUN:-0}" != "1" ]]; then - launchctl unload "$plist_file" 2> /dev/null || true - fi + run_launchctl_unload "$plist_file" "$need_sudo" if safe_remove "$plist_file" true; then ((broken_count++)) else