152 lines
4.6 KiB
Bash
Executable File
152 lines
4.6 KiB
Bash
Executable File
#!/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 {
|
|
local nformat
|
|
local optcount=$#
|
|
printf -v nformat "%%%dd. " ${#optcount}
|
|
local max_opt=0
|
|
for opt; do
|
|
if [[ "${#opt}" -gt $max_opt ]]; then
|
|
max_opt=${#opt}
|
|
fi
|
|
done
|
|
|
|
# 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"; }
|
|
if [[ $SELECT_MONOCHROME -eq 1 ]]; then
|
|
print_option() { printf " $1 "; }
|
|
print_selected() { printf " [$ESC[1m$1$ESC[0m] "; }
|
|
else
|
|
print_option() { printf " $ESC[33m $1 $ESC[0m "; }
|
|
print_selected() { printf " [$ESC[37;1m$1$ESC[0m] "; }
|
|
fi
|
|
get_cursor_row() { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${ROW#*[}; }
|
|
key_input() { read -s -n1 key1 2>/dev/null >&2
|
|
read -s -n2 -t 0.1 key2 2>/dev/null >&2
|
|
if [[ "$key1" =~ ^[0-9]+$ ]]; then
|
|
echo $key1; return;
|
|
fi
|
|
if [[ $key1$key2 = $ESC[A ]]; then echo up; return; fi
|
|
if [[ $key1$key2 = $ESC[B ]]; then echo down; return; fi
|
|
if [[ $key1 = $'\e' ]]; then echo esc; return; fi
|
|
if [[ $key1 = "" ]]; then echo enter; return; fi
|
|
}
|
|
reset_display() {
|
|
cursor_blink_on; stty echo; printf '\n';
|
|
}
|
|
# 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 1" 2
|
|
cursor_blink_off
|
|
|
|
local selected=0
|
|
while true; do
|
|
# print options by overwriting the last lines
|
|
local idx=0
|
|
local nidx
|
|
|
|
for opt; do
|
|
if [[ $SELECT_UNDERSCORES -eq 1 ]]; then
|
|
opt=${opt//_/ }
|
|
fi
|
|
if [[ $SELECT_NUMBERS -eq 1 ]]; then
|
|
printf -v nidx "$nformat" $(( idx + 1 ))
|
|
fi
|
|
printf -v padopt "%-${max_opt}s" "$opt"
|
|
cursor_to $(($startrow + $idx))
|
|
if [ $idx -eq $selected ]; then
|
|
print_selected "$nidx$padopt"
|
|
else
|
|
print_option "$nidx$padopt"
|
|
fi
|
|
((idx++))
|
|
done
|
|
|
|
# user key control
|
|
local user_input=`key_input`
|
|
case "$user_input" in
|
|
enter) break;;
|
|
esc) reset_display; exit 1;;
|
|
up) ((selected--));
|
|
if [ $selected -lt 0 ]; then selected=$(($# - 1)); fi;;
|
|
down) ((selected++));
|
|
if [ $selected -ge $# ]; then selected=0; fi;;
|
|
[0-9]) selected=$(( $user_input - 1 )) ;;
|
|
esac
|
|
done
|
|
|
|
# cursor position back to normal
|
|
cursor_to $lastrow
|
|
reset_display
|
|
if [[ -n "$SELECT_TOFILE" ]]; then
|
|
local idx=0
|
|
for opt; do
|
|
if [ $idx -eq $selected ]; then
|
|
echo "$opt" > "$SELECT_TOFILE"
|
|
fi
|
|
((idx++))
|
|
done
|
|
fi
|
|
return $(( 10 + $selected ))
|
|
}
|
|
|
|
[[ $_ == $0 ]] && {
|
|
_help() {
|
|
SELF=$( basename "$0" )
|
|
echo "Select Option
|
|
|
|
Usage: $SELF [-n] [--nc] [-o File] [-_] list of options
|
|
-n Number list
|
|
--nc No colors
|
|
-o File Save the choice in a file
|
|
-_ Print spaces instead of underscores
|
|
|
|
Returns
|
|
(10 + index) of selection (first option = 10)
|
|
1 if ctrl-c or ESC pressed
|
|
|
|
Example:
|
|
$SELF -n one two three
|
|
EC=\$?
|
|
[[ \$EC -lt 10 ]] && { echo Exited..; } || { echo You selected \$(( \$EC - 9 )); }
|
|
"
|
|
exit
|
|
}
|
|
|
|
SELECT_MONOCHROME=0
|
|
SELECT_NUMBERS=0
|
|
SELECT_UNDERSCORES=0
|
|
SELECT_TOFILE=""
|
|
for (( i=1; i<=$#; i++ )); do
|
|
value=${!i}
|
|
j=$(( i + 1 ))
|
|
[[ "$value" = "-h" ]] && _help
|
|
[[ "$value" = "--help" ]] && _help
|
|
[[ "$value" = "--nc" ]] && { SELECT_MONOCHROME=1; continue; }
|
|
[[ "$value" = "-n" ]] && { SELECT_NUMBERS=1; continue; }
|
|
[[ "$value" = "-_" ]] && { SELECT_UNDERSCORES=1; continue; }
|
|
[[ "$value" = "-o" ]] && { SELECT_TOFILE="${!j}"; ((i++)); continue; }
|
|
opts+=( "$value" )
|
|
done
|
|
|
|
select_option "${opts[@]}"
|
|
exit $?
|
|
}
|