#!/usr/bin/env bash # Renders a text based list of options that can be selected by the # user using up, down and enter keys and returns the chosen option. # # Arguments : list of options, maximum of 256 # "opt1" "opt2" ... # Return value: selected index (0 for opt1, 1 for opt2 ...) function select_option { # little helpers for terminal print control and key input ESC=$( printf "\033") cursor_blink_on() { printf "$ESC[?25h"; } cursor_blink_off() { printf "$ESC[?25l"; } cursor_to() { printf "$ESC[$1;${2:-1}H"; } print_option() { printf " $1 "; } print_selected() { printf "$ESC[7m $1 $ESC[27m"; } get_cursor_row() { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${ROW#*[}; } key_input() { read -s -n3 key 2>/dev/null >&2 if [[ $key = $ESC[A ]]; then echo up; fi if [[ $key = $ESC[B ]]; then echo down; fi if [[ $key = "" ]]; then echo enter; fi; } # initially print empty new lines (scroll down if at bottom of screen) for opt; do printf "\n"; done # determine current screen position for overwriting the options local lastrow=`get_cursor_row` local startrow=$(($lastrow - $#)) # ensure cursor and input echoing back on upon a ctrl+c during read -s trap "cursor_blink_on; stty echo; printf '\n'; exit" 2 cursor_blink_off local selected=0 while true; do # print options by overwriting the last lines local idx=0 for opt; do cursor_to $(($startrow + $idx)) if [ $idx -eq $selected ]; then print_selected "$opt" else print_option "$opt" fi ((idx++)) done # user key control case `key_input` in enter) break;; up) ((selected--)); if [ $selected -lt 0 ]; then selected=$(($# - 1)); fi;; down) ((selected++)); if [ $selected -ge $# ]; then selected=0; fi;; esac done # cursor position back to normal cursor_to $lastrow printf "\n" cursor_blink_on return $selected } function multi_select_option { # little helpers for terminal print control and key input ESC=$( printf "\033") cursor_blink_on() { printf "$ESC[?25h"; } cursor_blink_off() { printf "$ESC[?25l"; } cursor_to() { printf "$ESC[$1;${2:-1}H"; } print_option() { in=$1 c=$2 if [[ $in != "Wipe" && $in != "Exit" ]]; then printf " [${choices[$c]}] $in "; else printf " $in " fi } print_selected() { in=$1 if [[ $in != "Wipe" && $in != "Exit" ]]; then printf "$ESC[7m [${choices[$2]}] $1$ESC[27m"; else printf "$ESC[7m $1$ESC[27m"; fi } get_cursor_row() { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${ROW#*[}; } key_input() { read -s -n3 key 2>/dev/null >&2 if [[ $key = $ESC[A ]]; then echo up; fi if [[ $key = $ESC[B ]]; then echo down; fi if [[ $key = "" ]]; then echo enter; fi; } checker() { idx=$1; if [[ "${choices[$idx]}" != " " && \ "${choices[$idx]}" != "*" \ ]]; then choices[$idx]=" " fi } local wipe_part=false local stop_loop=false # initially print empty new lines (scroll down if at bottom of screen) for opt; do printf "\n"; done # determine current screen position for overwriting the options local lastrow=`get_cursor_row` local startrow=$(($lastrow - $#)) # ensure cursor and input echoing back on upon a ctrl+c during read -s trap "cursor_blink_on; stty echo; printf '\n'; exit" 2 cursor_blink_off local selected=0 while true; do # print options by overwriting the last lines local idx=0 for opt; do cursor_to $(($startrow + $idx)) checker $idx if [ $idx -eq $selected ]; then print_selected "$opt" "$idx" else print_option "$opt" "$idx" fi ((idx++)) done # user key control case `key_input` in enter) if [[ $selected == $(($idx-1)) ]]; then stop_loop=true elif [[ $selected == $(($idx-2)) ]]; then printf "\n" confirm_question if [[ $? -eq 0 ]];then wipe_part=true; stop_loop=true else choices=() wipe_part=false main fi else [[ "${choices[selected]}" == "*" ]] && choices[selected]=" " || \ choices[selected]='*' fi ;; up) ((selected--)); if [ $selected -lt 0 ]; then selected=$(($# - 1)); fi;; down) ((selected++)); if [ $selected -ge $# ]; then selected=0; fi;; esac if [[ $stop_loop == true ]]; then break fi done # cursor position back to normal cursor_to $lastrow printf "\n" cursor_blink_on if [[ $wipe_part == true ]];then return 0 else return 1 fi }