From 8db9a070b7e63da034a0925788c8550d58000950 Mon Sep 17 00:00:00 2001 From: emmett1 Date: Sat, 30 May 2026 23:51:26 +0800 Subject: yes no box for file deletion confirmation --- sfm | 175 ++++++++++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 119 insertions(+), 56 deletions(-) diff --git a/sfm b/sfm index 9b181c9..061c68a 100755 --- a/sfm +++ b/sfm @@ -1214,75 +1214,138 @@ do_open() { esac } +# --- confirm overlay (yes/no popup) --- +confirm_overlay() { + _co_rows=$(term_rows); _co_cols=$(term_cols) + _co_yes=" Yes " + _co_no=" No " + _co_gap=" " + _co_content="${_co_yes}${_co_gap}${_co_no}" + + # size box to fit prompt or buttons, whichever is wider + _co_w=$(( ${#_prompt} + 4 )) + [ "$_co_w" -lt $(( ${#_co_content} + 4 )) ] && _co_w=$(( ${#_co_content} + 4 )) + [ "$_co_w" -gt "$_co_cols" ] && _co_w=$((_co_cols - 2)) + _co_iw=$((_co_w - 2)) + _co_hl=$(printf '%*s' "$_co_iw" '' | tr ' ' '-') + + _co_x=$(( (_co_cols - _co_w) / 2 )); [ "$_co_x" -lt 0 ] && _co_x=0 + _co_y=$(( (_co_rows - 5) / 2 )); [ "$_co_y" -lt 1 ] && _co_y=1 + _co_sel=2 # 1=Yes, 2=No (default No for safety) + + while true; do + # draw box top + goto "$_co_y" "$_co_x" + printf '%s+%s+%s' "${BOLD}${CYAN}" "$_co_hl" "${RESET}" + # prompt line + goto "$((_co_y+1))" "$_co_x" + _co_pl=$((_co_iw - ${#_prompt})) + [ "$_co_pl" -lt 0 ] && _co_pl=0 + _co_pad=$(printf '%*s' "$_co_pl" '') + printf '%s|%s%s%s%s|%s' "${BOLD}${CYAN}" "${RESET}" "$_prompt" "$_co_pad" "${BOLD}${CYAN}" "${RESET}" + # separator + goto "$((_co_y+2))" "$_co_x" + printf '%s|%s|%s' "${BOLD}${CYAN}" "$_co_hl" "${RESET}" + # yes/no buttons + goto "$((_co_y+3))" "$_co_x" + _co_cpad=$(( (_co_iw - ${#_co_content}) / 2 )) + [ "$_co_cpad" -lt 0 ] && _co_cpad=0 + _co_left=$(printf '%*s' "$_co_cpad" '') + _co_cpad=$(( _co_iw - ${#_co_content} - _co_cpad )) + [ "$_co_cpad" -lt 0 ] && _co_cpad=0 + _co_right=$(printf '%*s' "$_co_cpad" '') + printf '%s|%s%s' "${BOLD}${CYAN}" "${RESET}" "$_co_left" + if [ "$_co_sel" -eq 1 ]; then + printf '%s%s%s' "${REV}${GREEN}${BOLD}" "$_co_yes" "${RESET}" + else + printf '%s' "$_co_yes" + fi + printf '%s' "$_co_gap" + if [ "$_co_sel" -eq 2 ]; then + printf '%s%s%s' "${REV}${RED}${BOLD}" "$_co_no" "${RESET}" + else + printf '%s' "$_co_no" + fi + printf '%s%s|%s' "$_co_right" "${BOLD}${CYAN}" "${RESET}" + # box bottom + goto "$((_co_y+4))" "$_co_x" + printf '%s+%s+%s' "${BOLD}${CYAN}" "$_co_hl" "${RESET}" + + # read key + IFS= read -r -n1 _co_ch 2>/dev/null || IFS= read -r _co_ch + case "$_co_ch" in + "$(printf '\033')") + IFS= read -r -n2 -t 0.1 _co_seq 2>/dev/null || _co_seq="" + case "$_co_seq" in + '[D'|'[C') # left/right arrow + if [ "$_co_sel" -eq 1 ]; then _co_sel=2; else _co_sel=1; fi ;; + *) return 1 ;; # bare esc or unrecognised sequence + esac ;; + h) _co_sel=1 ;; + l) _co_sel=2 ;; + j) _co_sel=2 ;; + k) _co_sel=1 ;; + y|Y) return 0 ;; + n|N) return 1 ;; + "$(printf '\n')"|"$(printf '\r')") + if [ "$_co_sel" -eq 1 ]; then return 0; else return 1; fi ;; + esac + done +} + do_delete() { INFO_MSG="" _c=$(count_selected) if [ "$_c" -gt 0 ]; then # --- bulk delete selected --- - restore_term; show_cursor - goto "$(term_rows)" 1 - printf '%s%s Delete %d selected items? [y/N] %s' \ - "${ERASE_LINE}" "${RED}${BOLD}" "$_c" "${RESET}" - IFS= read -r ans - setup_term; hide_cursor - case "$ans" in - y|Y) - _rest="$SELECTED" - while [ -n "$_rest" ]; do - _line="${_rest%% + _prompt="Delete ${_c} selected items?" + confirm_overlay; _yes=$? + if [ "$_yes" -eq 0 ]; then + _rest="$SELECTED" + while [ -n "$_rest" ]; do + _line="${_rest%% *}" - _next="${_rest#* + _next="${_rest#* }" - [ "$_next" = "$_rest" ] && _next="" - _rest="$_next" - [ -z "$_line" ] && continue - _name="${_line%@}"; _name="${_name%/}" - _t="${CWD}/${_name}" - if [ -d "$_t" ]; then rm -rf "$_t"; else rm -f "$_t"; fi - done - SELECTED="" - [ "$SEL" -ge "$((COUNT - 1))" ] && SEL=$((COUNT - 2)) - [ "$SEL" -lt 0 ] && SEL=0 - load_entries - ;; - *) NEED_FULL_REDRAW=1 ;; - esac + [ "$_next" = "$_rest" ] && _next="" + _rest="$_next" + [ -z "$_line" ] && continue + _name="${_line%@}"; _name="${_name%/}" + _t="${CWD}/${_name}" + if [ -d "$_t" ]; then rm -rf "$_t"; else rm -f "$_t"; fi + done + SELECTED="" + [ "$SEL" -ge "$((COUNT - 1))" ] && SEL=$((COUNT - 2)) + [ "$SEL" -lt 0 ] && SEL=0 + load_entries + else + NEED_FULL_REDRAW=1 + fi else # --- single delete --- entry=$(get_entry "$SEL") _name="${entry%@}"; _name="${_name%/}" target="${CWD}/${_name}" - restore_term; show_cursor - goto "$(term_rows)" 1 - printf '%s%s Delete "%s"? [y/N] %s' "${ERASE_LINE}" "${RED}${BOLD}" "$entry" "${RESET}" - IFS= read -r ans - setup_term; hide_cursor - case "$ans" in - y|Y) - if [ -d "$target" ]; then - if [ -n "$(ls -A "$target" 2>/dev/null)" ]; then - restore_term; show_cursor - goto "$(term_rows)" 1 - printf '%s%s "%s" not empty. Delete ALL? [y/N] %s' \ - "${ERASE_LINE}" "${RED}${BOLD}" "$entry" "${RESET}" - IFS= read -r ans2 - setup_term; hide_cursor - case "$ans2" in - y|Y) rm -rf "$target" ;; - *) NEED_FULL_REDRAW=1; return ;; - esac - else - rm -rf "$target" - fi - else - rm -f "$target" + _prompt="Delete \"${entry}\"?" + confirm_overlay; _yes=$? + if [ "$_yes" -ne 0 ]; then + NEED_FULL_REDRAW=1; return + fi + if [ -d "$target" ]; then + if [ -n "$(ls -A "$target" 2>/dev/null)" ]; then + _prompt="\"${entry}\" not empty. Delete ALL?" + confirm_overlay; _yes2=$? + if [ "$_yes2" -ne 0 ]; then + NEED_FULL_REDRAW=1; return fi - [ "$SEL" -ge "$((COUNT - 1))" ] && SEL=$((COUNT - 2)) - [ "$SEL" -lt 0 ] && SEL=0 - load_entries - ;; - *) NEED_FULL_REDRAW=1 ;; - esac + fi + rm -rf "$target" + else + rm -f "$target" + fi + [ "$SEL" -ge "$((COUNT - 1))" ] && SEL=$((COUNT - 2)) + [ "$SEL" -lt 0 ] && SEL=0 + load_entries fi } -- cgit v1.2.3