diff --git a/setup/simple-install.sh b/setup/simple-install.sh index 3c7fc0b..50fcdb3 100755 --- a/setup/simple-install.sh +++ b/setup/simple-install.sh @@ -75,54 +75,153 @@ tui_input() { # tui_checklist TITLE PROMPT tag desc state tag desc state ... # state: "on" | "off" | "header" (header = section label, tag is ignored) # Prints space-separated selected tags to stdout. +# Arrow keys navigate · Space toggles · a selects all · Enter/n confirms tui_checklist() { local title="$1" prompt="$2"; shift 2 local -a _T _D _S while [[ $# -ge 3 ]]; do _T+=("$1"); _D+=("$2"); _S+=("$3"); shift 3; done local n=${#_T[@]} + local _tv _vp _cur _scr _VIS _k _k2 _k3 _k4 _i _j _f _l _chk _res _toti _posi i - while true; do + _tv=$(tput lines 2>/dev/null || echo 24) + _vp=$(( _tv - 11 )) + (( _vp < 4 )) && _vp=4 + + _toti=0 + for (( i=0; i/dev/tty; _sep + printf " ${M}${B}%s${R}\n" "$title" >/dev/tty + _sep printf " ${D}%s${R}\n\n" "$prompt" >/dev/tty - local -a sel=() - local i num=0 - for (( i=0; i/dev/tty - continue - fi - sel+=("$i"); (( num++ )) - if [[ "${_S[$i]}" == "on" ]]; then - printf " ${CY}%3d) [*] %-22s${R} %s\n" "$num" "${_T[$i]}" "${_D[$i]}" >/dev/tty + if (( i == _scr )); then + (( _l + 1 > _vp )) && break + printf " ${M}── %s${R}\n" "${_D[$i]}" >/dev/tty + (( _l++ )) + else + (( _l + 2 > _vp )) && break + printf "\n ${M}── %s${R}\n" "${_D[$i]}" >/dev/tty + (( _l+=2 )) + fi else - printf " %3d) [ ] %-22s %s\n" "$num" "${_T[$i]}" "${_D[$i]}" >/dev/tty + (( _l + 1 > _vp )) && break + _chk=" "; [[ "${_S[$i]}" == "on" ]] && _chk="*" + if (( i == _cur )); then + printf " ${CY}▶ [%s] %-22s${R} %s\n" "$_chk" "${_T[$i]}" "${_D[$i]}" >/dev/tty + else + printf " [%s] %-22s %s\n" "$_chk" "${_T[$i]}" "${_D[$i]}" >/dev/tty + fi + (( _l++ )) fi done - local total_sel=${#sel[@]} - printf "\n ${D}Number(s) to toggle · 'a' all · 'n' none · Enter confirm:${R}\n > " >/dev/tty - local inp; read -r inp /dev/tty + } - [[ -z "$inp" ]] && break - case "$inp" in - a) for (( i=0; i=0; _i-- )); do + [[ "${_S[$_i]}" != "header" ]] && { _cur=$_i; break; } + done ;; + $'\e[B') # Down arrow + for (( _i=_cur+1; _i=0; _i-- )); do + [[ "${_S[$_i]}" != "header" ]] && { _cur=$_i; _f=1; break; } + done + (( _f == 0 )) && break + done ;; + $'\e[6~') # Page Down + for (( _j=0; _j < _vp/2; _j++ )); do + _f=0 + for (( _i=_cur+1; _i=0; _i-- )); do + [[ "${_S[$_i]}" != "header" ]] && { _cur=$_i; break; } + done ;; + ' ') # Space — toggle current item + [[ "${_S[$_cur]}" == "on" ]] && _S[$_cur]="off" || _S[$_cur]="on" ;; + 'a') # Select all + for (( _i=0; _i= 0 && k < total_sel )) || continue - local idx="${sel[$k]}" - [[ "${_S[$idx]}" == "on" ]] && _S[$idx]="off" || _S[$idx]="on" - fi - done done - local res="" - for (( i=0; i