@@ -895,6 +895,59 @@ _term_width() {
895895_DASH_POOL= " ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────"
896896_DOUBLE_DASH_POOL= " ════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════"
897897
898+ # Truncate an ANSI-formatted string to max visible columns, appending …
899+ # when cut. ANSI escape codes (CSI SGR) don't count toward width, and codes
900+ # that appear after the cut are preserved so that RESET / background-reset
901+ # still fire on the output line.
902+ # Sets _TRUNC.
903+ _TRUNC= " "
904+ _truncate_visible () {
905+ local max=$1 str=$2
906+
907+ # Fast path: no escape sequences
908+ if [[ " $str " != * $' \x1b ' * ]]; then
909+ if (( ${# str} <= max )) ; then
910+ _TRUNC=" $str "
911+ elif (( max < 1 )) ; then
912+ _TRUNC=" "
913+ else
914+ _TRUNC=" ${str: 0: max - 1} …"
915+ fi
916+ return
917+ fi
918+
919+ # Strip ANSI to get visible length (single parameter expansion, no subshell)
920+ local plain=" ${str// $' \x1b ' \[ [0-9;]* [a-zA-Z]/ } "
921+ if (( ${# plain} <= max )) ; then
922+ _TRUNC=" $str "
923+ return
924+ fi
925+ # Truncation needed: keep first (max-1) visible chars with their interleaved
926+ # escapes, append …, then append any escapes after the cut so that RESET
927+ # (or other terminating codes) still take effect.
928+ local prefix=" " trailing=" " keep=$(( max - 1 ))
929+ local visible=0 i=0 in_esc=0 ch
930+ local len=${# str}
931+ while (( i < len )) ; do
932+ ch=" ${str: $i : 1} "
933+ if (( in_esc )) ; then
934+ if (( visible < keep )) ; then prefix+=" $ch "
935+ else trailing+=" $ch " ; fi
936+ [[ " $ch " == [a-zA-Z] ]] && in_esc=0
937+ elif [[ " $ch " == $' \x1b ' ]]; then
938+ in_esc=1
939+ if (( visible < keep )) ; then prefix+=" $ch "
940+ else trailing+=" $ch " ; fi
941+ elif (( visible < keep )) ; then
942+ prefix+=" $ch "
943+ (( visible++ ))
944+ fi
945+ (( i++ ))
946+ done
947+
948+ _TRUNC=" ${prefix} …${trailing} "
949+ }
950+
898951# Format a section header with trailing dashes (sets _SH, no subshell)
899952# _RENDER_WIDTH defaults to _MAX_CONTENT_WIDTH; draw_picker caps it to terminal width
900953_SH= " "
@@ -1043,8 +1096,17 @@ draw_picker() {
10431096 local n_items=${# DISPLAY_LINES[@]}
10441097 local buf=" "
10451098
1046- # Helper: append a line to buf with end-of-line clear
1047- _line () { buf+=" $1 ${EL} " $' \n ' ; (( count += 1 )) ; }
1099+ # Helper: append a line to buf with end-of-line clear.
1100+ # Truncates to term_w visible cols so long lines don't wrap — wrapping would
1101+ # make physical rows exceed PICKER_LINES and break cursor-up redraws.
1102+ _line () {
1103+ local _s=" $1 "
1104+ if (( ${# _s} > term_w )) ; then
1105+ _truncate_visible " $term_w " " $_s "
1106+ _s=" $_TRUNC "
1107+ fi
1108+ buf+=" ${_s}${EL} " $' \n ' ; (( count += 1 ))
1109+ }
10481110 # Helper: append a blank line (just clear + newline)
10491111 _blank () { buf+=" ${EL} " $' \n ' ; (( count += 1 )) ; }
10501112
0 commit comments