@@ -56,85 +56,110 @@ show_menu() {
5656 local count=${# items[@]}
5757 local last_idx=$(( count - 1 ))
5858
59- # Calculate box width from longest item (skip separators)
60- local max_len=0
61- local i
62- for (( i= 0 ; i< count ; i++ )) ; do
59+ # Build selectable items: sel_nums[i]=choice number, sel_labels[i]=label
60+ local sel_nums=() sel_labels=()
61+ local i num=0
62+ for (( i= 0 ; i< last_idx ; i++ )) ; do
6363 [[ " ${items[$i]} " == " ---" ]] && continue
64- if [[ ${ # items[$i]} -gt $max_len ]] ; then
65- max_len= ${ # items[$i]}
66- fi
64+ num= $(( num + 1 ))
65+ sel_nums+=( " $num " )
66+ sel_labels+=( " ${items[$i]} " )
6767 done
68+ sel_nums+=(0)
69+ sel_labels+=(" ${items[$last_idx]} " )
70+ local sel_total=${# sel_nums[@]}
6871
69- # Count real items (skip separators) to get max number width
70- local real_count =0
71- for (( i= 0 ; i< last_idx ; i++ )) ; do
72+ # Box dimensions
73+ local max_len =0
74+ for (( i= 0 ; i< count ; i++ )) ; do
7275 [[ " ${items[$i]} " == " ---" ]] && continue
73- real_count= $(( real_count + 1 ))
76+ [[ ${ # items[$i]} -gt $max_len ]] && max_len= ${ # items[$i]}
7477 done
78+ local real_count=$num
7579 local num_w=${# real_count}
76- # inner = " " + num + " › " + item + " "
7780 local inner_w=$(( 2 + num_w + 3 + max_len + 2 ))
7881 local title_min=$(( ${# title} + 5 ))
79- if [[ $title_min -gt $inner_w ]]; then
80- inner_w=$title_min
81- fi
82-
82+ [[ $title_min -gt $inner_w ]] && inner_w=$title_min
8383 local top_fill=$(( inner_w - ${# title} - 3 ))
8484
85- local BP=" ${BOLD}${GRAY} "
86- local R=" ${RESET} "
85+ local BP=" ${BOLD}${GRAY} " R=" ${RESET} "
86+ local total_lines=$(( last_idx + 8 ))
87+ local sel=0 first_draw=true
8788
8889 printf " \033[?25l" >&2
8990
90- printf " \n" >&2
91- # ╭─ Title ───╮
92- printf ' %b╭─ %b%s%b ' " $BP " " ${R}${BOLD}${ICE} " " $title " " ${R}${BP} " >&2
93- printf ' ─%.0s' $( seq 1 $top_fill ) >&2
94- printf ' ╮%b\n' " $R " >&2
95- # │ (empty) │
96- printf ' %b│%b%*s%b│%b\n' " $BP " " $R " " $inner_w " " " " $BP " " $R " >&2
97- # │ N › Item │ (items 1..N-1, "---" renders as blank separator line)
98- local num=0
99- for (( i= 0 ; i< last_idx; i++ )) ; do
100- if [[ " ${items[$i]} " == " ---" ]]; then
101- printf ' %b│%b%*s%b│%b\n' " $BP " " $R " " $inner_w " " " " $BP " " $R " >&2
102- continue
91+ while true ; do
92+ if $first_draw ; then
93+ first_draw=false
94+ else
95+ printf " \033[%dA\r" " $total_lines " >&2
10396 fi
104- num=$(( num + 1 ))
105- local vis=$(( 2 + num_w + 3 + ${# items[$i]} ))
97+
98+ printf " \n" >&2
99+ printf ' %b╭─ %b%s%b ' " $BP " " ${R}${BOLD}${ICE} " " $title " " ${R}${BP} " >&2
100+ printf ' ─%.0s' $( seq 1 $top_fill ) >&2
101+ printf ' ╮%b\n' " $R " >&2
102+ printf ' %b│%b%*s%b│%b\n' " $BP " " $R " " $inner_w " " " " $BP " " $R " >&2
103+
104+ local num=0 sel_idx=0
105+ for (( i= 0 ; i< last_idx; i++ )) ; do
106+ if [[ " ${items[$i]} " == " ---" ]]; then
107+ printf ' %b│%b%*s%b│%b\n' " $BP " " $R " " $inner_w " " " " $BP " " $R " >&2
108+ continue
109+ fi
110+ num=$(( num + 1 ))
111+ local vis=$(( 2 + num_w + 3 + ${# items[$i]} ))
112+ local pad=$(( inner_w - vis))
113+ if [[ $sel_idx -eq $sel ]]; then
114+ printf ' %b│%b %b%*d › %s%b%*s%b│%b\n' \
115+ " $BP " " $R " " ${BOLD}${ICE} " " $num_w " " $num " " ${items[$i]} " " $R " " $pad " " " " $BP " " $R " >&2
116+ else
117+ printf ' %b│%b %b%*d%b %b›%b %s%*s%b│%b\n' \
118+ " $BP " " $R " " $CYAN " " $num_w " " $num " " $R " " $DIM " " $R " " ${items[$i]} " " $pad " " " " $BP " " $R " >&2
119+ fi
120+ (( sel_idx++ ))
121+ done
122+
123+ printf ' %b│%b%*s%b│%b\n' " $BP " " $R " " $inner_w " " " " $BP " " $R " >&2
124+ local vis=$(( 2 + num_w + 3 + ${# items[$last_idx]} ))
106125 local pad=$(( inner_w - vis))
107- printf ' %b│%b %b%*d%b %b›%b %s%*s%b│%b\n' " $BP " " $R " " $CYAN " " $num_w " " $num " " $R " " $DIM " " $R " " ${items[$i]} " " $pad " " " " $BP " " $R " >&2
108- done
109- # │ (empty) │
110- printf ' %b│%b%*s%b│%b\n' " $BP " " $R " " $inner_w " " " " $BP " " $R " >&2
111- # │ 0 › Back │ (last item = 0)
112- local vis=$(( 2 + num_w + 3 + ${# items[$last_idx]} ))
113- local pad=$(( inner_w - vis))
114- printf ' %b│%b %b%*d › %s%b%*s%b│%b\n' " $BP " " $R " " $DIM " " $num_w " 0 " ${items[$last_idx]} " " $R " " $pad " " " " $BP " " $R " >&2
115- # │ (empty) │
116- printf ' %b│%b%*s%b│%b\n' " $BP " " $R " " $inner_w " " " " $BP " " $R " >&2
117- # ╰───────────╯
118- printf ' %b╰' " $BP " >&2
119- printf ' ─%.0s' $( seq 1 $inner_w ) >&2
120- printf ' ╯%b\n' " $R " >&2
126+ if [[ $sel_idx -eq $sel ]]; then
127+ printf ' %b│%b %b%*d › %s%b%*s%b│%b\n' \
128+ " $BP " " $R " " ${BOLD}${ICE} " " $num_w " 0 " ${items[$last_idx]} " " $R " " $pad " " " " $BP " " $R " >&2
129+ else
130+ printf ' %b│%b %b%*d › %s%b%*s%b│%b\n' \
131+ " $BP " " $R " " $DIM " " $num_w " 0 " ${items[$last_idx]} " " $R " " $pad " " " " $BP " " $R " >&2
132+ fi
121133
122- printf " \n" >&2
123- local key=" "
124- IFS= read -rsn1 key < /dev/tty || true
125-
126- if [[ " $key " == $' \x1b ' ]]; then
127- local seq=" "
128- read -rsn2 -t 1 seq < /dev/tty || true
129- if [[ " $seq " == ' [D' ]]; then
130- printf " ‹\n" >&2
131- echo " 0"
134+ printf ' %b│%b%*s%b│%b\n' " $BP " " $R " " $inner_w " " " " $BP " " $R " >&2
135+ printf ' %b╰' " $BP " >&2
136+ printf ' ─%.0s' $( seq 1 $inner_w ) >&2
137+ printf ' ╯%b\n' " $R " >&2
138+ printf " \n" >&2
139+
140+ local key=" "
141+ IFS= read -rsn1 key < /dev/tty || true
142+
143+ if [[ " $key " == $' \x1b ' ]]; then
144+ local ansi=" "
145+ read -rsn2 -t 1 ansi < /dev/tty || true
146+ case " $ansi " in
147+ ' [A' ) (( sel > 0 )) && (( sel-- )) ;;
148+ ' [B' ) (( sel < sel_total - 1 )) && (( sel++ )) ;;
149+ ' [C' |' [M' ) printf " \033[?25h" >&2 ; echo " ${sel_nums[$sel]} " ; return ;;
150+ ' [D' ) printf " ‹\n" >&2 ; printf " \033[?25h" >&2 ; echo " 0" ; return ;;
151+ esac
152+ elif [[ " $key " == " " ]]; then
153+ printf " \033[?25h" >&2
154+ echo " ${sel_nums[$sel]} "
155+ return
156+ elif [[ " $key " =~ ^[0-9]$ ]]; then
157+ printf " %s\n" " $key " >&2
158+ printf " \033[?25h" >&2
159+ echo " $key "
160+ return
132161 fi
133- elif [[ -n " $key " ]]; then
134- printf " %s\n" " $key " >&2
135- echo " $key "
136- fi
137- printf " \033[?25h" >&2
162+ done
138163}
139164
140165#
0 commit comments