shortcuts for select-option
This commit is contained in:
@@ -7,11 +7,23 @@ function select_option {
|
|||||||
printf -v nformat "%%%dd. " ${#optcount}
|
printf -v nformat "%%%dd. " ${#optcount}
|
||||||
local max_opt=0
|
local max_opt=0
|
||||||
local multiselected=()
|
local multiselected=()
|
||||||
|
local choices=()
|
||||||
|
local shortcuts=()
|
||||||
|
local idx=0
|
||||||
|
local clean_opt
|
||||||
for opt; do
|
for opt; do
|
||||||
if [[ "${#opt}" -gt $max_opt ]]; then
|
|
||||||
max_opt=${#opt}
|
|
||||||
fi
|
|
||||||
multiselected+=(0)
|
multiselected+=(0)
|
||||||
|
if [[ "$opt" =~ ^\[.\]* ]]; then # choice starts with [x]
|
||||||
|
shortcuts+=( "${opt:1:1}" )
|
||||||
|
choices+=( "${opt:3}" )
|
||||||
|
else
|
||||||
|
shortcuts+=( "${opt:0:1}" )
|
||||||
|
choices+=( "$opt" )
|
||||||
|
fi
|
||||||
|
if [[ "${#choices[$idx]}" -gt $max_opt ]]; then
|
||||||
|
max_opt="${#choices[$idx]}"
|
||||||
|
fi
|
||||||
|
((idx++))
|
||||||
done
|
done
|
||||||
|
|
||||||
# little helpers for terminal print control and key input
|
# little helpers for terminal print control and key input
|
||||||
@@ -20,20 +32,25 @@ function select_option {
|
|||||||
cursor_blink_off() { printf "$ESC[?25l"; }
|
cursor_blink_off() { printf "$ESC[?25l"; }
|
||||||
cursor_to() { printf "$ESC[$1;${2:-1}H"; }
|
cursor_to() { printf "$ESC[$1;${2:-1}H"; }
|
||||||
if [[ $SELECT_MONOCHROME -eq 1 ]]; then
|
if [[ $SELECT_MONOCHROME -eq 1 ]]; then
|
||||||
print_option() { printf " $ESC[30m%s $ESC[0m %s $ESC[30m%s$ESC[0m " "$2" "$1" "$3"; }
|
print_option() { printf " $ESC[30m%s $ESC[0m%s %s $ESC[30m%s$ESC[0m$ESC[K" "$1" "$2" "$3" "$4"; }
|
||||||
print_selected() { printf " $ESC[30m%s$ESC[0m{ $ESC[1m%s$ESC[0m }$ESC[30m%s$ESC[0m " "$2" "$1" "$3"; }
|
print_selected() { printf " $ESC[30m%s $ESC[0m%s{ $ESC[1m%s$ESC[0m } $ESC[30m%s$ESC[0m$ESC[K" "$1" "$2" "$3" "$4"; }
|
||||||
print_multiselected() { printf "$ESC[30;1m*$ESC[0m"; }
|
print_multiselected() { printf "$ESC[30;1m*$ESC[0m"; }
|
||||||
else
|
else
|
||||||
print_option() { printf " $ESC[30m%s $ESC[33m %s $ESC[0m $ESC[30m%s$ESC[0m " "$2" "$1" "$3"; }
|
print_option() { printf " $ESC[30m%s $ESC[33m%s %s$ESC[0m $ESC[30m%s$ESC[0m$ESC[K" "$1" "$2" "$3" "$4"; }
|
||||||
print_selected() { printf " $ESC[30m%s$ESC[35;1m{$ESC[37;1m %s $ESC[0;35;1m}$ESC[0;30m%s$ESC[0m " "$2" "$1" "$3"; }
|
print_selected() { printf " $ESC[30m%s $ESC[35;1m%s{ $ESC[37;1m%s$ESC[0;35;1m } $ESC[0;30m%s$ESC[0m$ESC[K" "$1" "$2" "$3" "$4"; }
|
||||||
print_multiselected() { printf "$ESC[32;1m*$ESC[0m"; }
|
print_multiselected() { printf "$ESC[32;1m*$ESC[0m"; }
|
||||||
fi
|
fi
|
||||||
get_cursor_row() { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${ROW#*[}; }
|
get_cursor_row() { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${ROW#*[}; }
|
||||||
key_input() { read -s -n1 key1 2>/dev/null >&2
|
key_input() { read -s -n1 key1 2>/dev/null >&2
|
||||||
read -s -n2 -t 0.1 key2 2>/dev/null >&2
|
read -s -n2 -t 0.1 key2 2>/dev/null >&2
|
||||||
if [[ "$key1" =~ ^[0-9]+$ ]]; then
|
local idx=$selected
|
||||||
echo $key1; return;
|
while true; do
|
||||||
fi
|
idx=$(( ($idx + 1) % $optcount ))
|
||||||
|
if [[ "$key1" = "${shortcuts[$idx]}" ]]; then
|
||||||
|
echo $idx; return;
|
||||||
|
fi
|
||||||
|
if [[ $idx -eq $selected ]]; then break; fi
|
||||||
|
done
|
||||||
if [[ $key1$key2 = $ESC[A ]]; then echo up; return; fi
|
if [[ $key1$key2 = $ESC[A ]]; then echo up; return; fi
|
||||||
if [[ $key1$key2 = $ESC[B ]]; then echo down; return; fi
|
if [[ $key1$key2 = $ESC[B ]]; then echo down; return; fi
|
||||||
if [[ $key1$key2 = $ESC[C ]]; then echo left; return; fi
|
if [[ $key1$key2 = $ESC[C ]]; then echo left; return; fi
|
||||||
@@ -64,15 +81,29 @@ function select_option {
|
|||||||
cursor_blink_off
|
cursor_blink_off
|
||||||
|
|
||||||
local selected=0
|
local selected=0
|
||||||
|
local bottomlength=$(( 10 + $max_opt ))
|
||||||
|
local multiselect_pos=6
|
||||||
|
if [[ $SELECT_NUMBERS -eq 1 ]]; then
|
||||||
|
bottomlength=$(( $bottomlength + 3 ))
|
||||||
|
multiselect_pos=$(( $multiselect_pos + 3 ))
|
||||||
|
fi
|
||||||
|
if [[ $SELECT_SHORTCUTS -eq 1 ]]; then
|
||||||
|
bottomlength=$(( $bottomlength + 3 ))
|
||||||
|
multiselect_pos=$(( $multiselect_pos + 3 ))
|
||||||
|
fi
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
# print options by overwriting the last lines
|
# print options by overwriting the last lines
|
||||||
local idx=0
|
local idx=0
|
||||||
local nidx
|
local nidx
|
||||||
|
local shortcut
|
||||||
cursor_to $startrow
|
cursor_to $startrow
|
||||||
printf " $ESC[30m%s$ESC[0m" "$toprow"
|
if [ $selected -lt 0 ]; then selected=$(($# - 1)); fi
|
||||||
|
if [ $selected -ge $# ]; then selected=0; fi
|
||||||
|
printf " $ESC[30m%s$ESC[0m$ESC[K " "$toprow"
|
||||||
|
|
||||||
for opt; do
|
for opt; do
|
||||||
|
opt="${choices[$idx]}"
|
||||||
local lborder="${lborderchars:$idx:1}"
|
local lborder="${lborderchars:$idx:1}"
|
||||||
if [ -z "$lborder" ]; then lborder=" "; fi
|
if [ -z "$lborder" ]; then lborder=" "; fi
|
||||||
local rborder="${rborderchars:$(( $optcount - $idx - 1)):1}"
|
local rborder="${rborderchars:$(( $optcount - $idx - 1)):1}"
|
||||||
@@ -80,37 +111,40 @@ function select_option {
|
|||||||
if [[ $SELECT_UNDERSCORES -eq 1 ]]; then
|
if [[ $SELECT_UNDERSCORES -eq 1 ]]; then
|
||||||
opt=${opt//_/ }
|
opt=${opt//_/ }
|
||||||
fi
|
fi
|
||||||
if [[ $SELECT_NUMBERS -eq 1 ]]; then
|
if [[ $SELECT_NUMBERS -eq 1 ]]; then
|
||||||
printf -v nidx "$nformat" $(( idx + 1 ))
|
printf -v nidx "$nformat" $(( idx + 1 ))
|
||||||
fi
|
fi
|
||||||
|
if [[ $SELECT_SHORTCUTS -eq 1 ]]; then
|
||||||
|
printf -v shortcut "%s) " "${shortcuts[$idx]}"
|
||||||
|
fi
|
||||||
printf -v padopt "%-${max_opt}s" "$opt"
|
printf -v padopt "%-${max_opt}s" "$opt"
|
||||||
cursor_to $(($startrow + $idx + 1))
|
cursor_to $(($startrow + $idx + 1))
|
||||||
if [ $idx -eq $selected ]; then
|
if [ $idx -eq $selected ]; then
|
||||||
print_selected "$nidx$padopt" "$lborder" "$rborder"
|
print_selected "$lborder" "$nidx$shortcut" "$padopt" "$rborder"
|
||||||
else
|
else
|
||||||
print_option "$nidx$padopt" "${lborder}" "$rborder"
|
print_option "$lborder" "$nidx$shortcut" "$padopt" "$rborder"
|
||||||
fi
|
fi
|
||||||
if (( ${multiselected[$idx]} )); then
|
if (( ${multiselected[$idx]} )); then
|
||||||
cursor_to $(($startrow + $idx + 1)) 5
|
cursor_to $(($startrow + $idx + 1)) $multiselect_pos
|
||||||
print_multiselected
|
print_multiselected
|
||||||
fi
|
fi
|
||||||
((idx++))
|
((idx++))
|
||||||
done
|
done
|
||||||
cursor_to $(($startrow + $idx + 1))
|
cursor_to $(($startrow + $idx + 1))
|
||||||
local bottomlength=$(( 8 + $max_opt + ${#nidx} ))
|
printf "$ESC[K$ESC[30m%${bottomlength}s$ESC[0m " "$bottomrow"
|
||||||
printf "$ESC[30m%${bottomlength}s$ESC[0m" "$bottomrow"
|
|
||||||
|
|
||||||
# user key control
|
# user key control
|
||||||
local user_input=`key_input`
|
local user_input=`key_input`
|
||||||
case "$user_input" in
|
case "$user_input" in
|
||||||
enter) break;;
|
enter) break;;
|
||||||
esc) reset_display; exit 1;;
|
esc) reset_display; exit 1;;
|
||||||
up) ((selected--));
|
up) ((selected--));;
|
||||||
if [ $selected -lt 0 ]; then selected=$(($# - 1)); fi;;
|
down) ((selected++));;
|
||||||
down) ((selected++));
|
multiselect) if (( $SELECT_MULTI )); then
|
||||||
if [ $selected -ge $# ]; then selected=0; fi;;
|
multiselected[$selected]=$(( 1 - ${multiselected[$selected]} ));
|
||||||
multiselect) if (( $SELECT_MULTI )); then multiselected[$selected]=$(( 1 - ${multiselected[$selected]} )); fi;;
|
((selected++));
|
||||||
[0-9]) selected=$(( $user_input - 1 )) ;;
|
fi;;
|
||||||
|
?) selected=$user_input;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -123,7 +157,7 @@ function select_option {
|
|||||||
if [[ -n "$SELECT_TOFILE" ]]; then printf "" > "$SELECT_TOFILE"; fi
|
if [[ -n "$SELECT_TOFILE" ]]; then printf "" > "$SELECT_TOFILE"; fi
|
||||||
for opt; do
|
for opt; do
|
||||||
if (( ${multiselected[$idx]} )); then
|
if (( ${multiselected[$idx]} )); then
|
||||||
if [[ -n "$SELECT_TOFILE" ]]; then echo "$opt" >> "$SELECT_TOFILE"; fi
|
if [[ -n "$SELECT_TOFILE" ]]; then echo "${choices[$idx]}" >> "$SELECT_TOFILE"; fi
|
||||||
returnvalue=$(( $returnvalue + 2**$idx ))
|
returnvalue=$(( $returnvalue + 2**$idx ))
|
||||||
fi
|
fi
|
||||||
((idx++))
|
((idx++))
|
||||||
@@ -132,12 +166,7 @@ function select_option {
|
|||||||
# Single choice
|
# Single choice
|
||||||
returnvalue=$selected
|
returnvalue=$selected
|
||||||
if [[ -n "$SELECT_TOFILE" ]]; then
|
if [[ -n "$SELECT_TOFILE" ]]; then
|
||||||
for opt; do
|
echo "${choices[$selected]}" > "$SELECT_TOFILE"
|
||||||
if [ $idx -eq $selected ]; then
|
|
||||||
echo "$opt" > "$SELECT_TOFILE"
|
|
||||||
fi
|
|
||||||
((idx++))
|
|
||||||
done
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -151,43 +180,49 @@ _help() {
|
|||||||
echo "Select Option [Pure BASH]
|
echo "Select Option [Pure BASH]
|
||||||
Adapted from: https://unix.stackexchange.com/questions/146570/arrow-key-enter-menu
|
Adapted from: https://unix.stackexchange.com/questions/146570/arrow-key-enter-menu
|
||||||
|
|
||||||
Usage: $SELF [-n] [--nc] [-o File] [-_] list of options
|
Usage: $SELF [-nms_] [--nc] [-o File] list of options
|
||||||
-n Numbered list
|
-n Show item number
|
||||||
-m Multiple choice selection. Note that only 7 options can be encoded
|
-m Multiple choice selection. Note that only 7 options can be encoded
|
||||||
reliably in return value. Use File output for more options.
|
reliably in return value. Use File output for more options.
|
||||||
|
-s Show shortcuts
|
||||||
--nc No colors
|
--nc No colors
|
||||||
-o File Save the choice(s) in a file.
|
-o File Save the choice(s) in a file.
|
||||||
-_ Print spaces instead of underscores, workaround for
|
-_ Print spaces instead of underscores, workaround for
|
||||||
shell arguments with spaces.
|
shell arguments containing spaces.
|
||||||
|
--package Special option to base64 encode this program, to be
|
||||||
|
used in your own programs
|
||||||
|
|
||||||
User interface:
|
User interface:
|
||||||
Enter Select option
|
Enter Select option
|
||||||
Esc / Ctrl-c Exit
|
Esc / Ctrl-c Exit
|
||||||
x Multi-selection
|
x Multi-selection
|
||||||
|
other keys Shortcut, defaults to first letter of choice
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Single selection:
|
Single selection:
|
||||||
(10 + index) of selection (first option = 10)
|
- (10 + index) of selection (first option = 10)
|
||||||
1 if ctrl-c or ESC pressed
|
- 1 if ctrl-c or ESC pressed
|
||||||
If output file is defined, choice is printed there.
|
- If output file is defined, choice is printed there.
|
||||||
Multiple selection:
|
Multiple selection:
|
||||||
(10 + 2**index) encoded multiple values (no options = 10). See example.
|
- (10 + 2**index) encoded multiple values (no options = 10). See example.
|
||||||
1 if ctrl-c or ESC pressed
|
- 1 if ctrl-c or ESC pressed
|
||||||
All choices separately in the output File.
|
- All choices separately in the output File.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
Single choice:
|
Single choice:
|
||||||
$SELF -n one two three
|
> $SELF -n one two three
|
||||||
EC=\$?
|
> EC=\$?
|
||||||
[[ \$EC -lt 10 ]] && { echo Exited..; } || { echo You selected \$(( \$EC - 9 )); }
|
> [[ \$EC -lt 10 ]] && { echo Exited..; } || { echo You selected \$(( \$EC - 9 )); }
|
||||||
|
Single choice with shortcuts, press 1 2 3 or c to move in the menu:
|
||||||
|
> $SELF -s [1]One [2]Two [3]Three [c]Cancel
|
||||||
|
|
||||||
Multi choice:
|
Multi choice:
|
||||||
$SELF -m one two three four five six seven -o choice.txt
|
> $SELF -m one two three four five six seven -o choice.txt
|
||||||
C=\$?; C=\$(( \$C - 10 ))
|
> C=\$?; C=\$(( \$C - 10 ))
|
||||||
if (( \$C == 0 )); then printf 'No selection'; else printf 'Selections: '; fi
|
> if (( \$C == 0 )); then printf 'No selection'; else printf 'Selections: '; fi
|
||||||
for b in 7 6 5 4 3 2 1 0; do
|
> for b in 7 6 5 4 3 2 1 0; do
|
||||||
if (( \$C >= 2**\$b )); then printf '%d, ' \$(( \$b + 1 )); C=\$(( \$C - 2**\$b )); fi
|
> if (( \$C >= 2**\$b )); then printf '%d, ' \$(( \$b + 1 )); C=\$(( \$C - 2**\$b )); fi
|
||||||
done; printf '\\n'
|
> done; printf '\\n'
|
||||||
|
|
||||||
"
|
"
|
||||||
exit
|
exit
|
||||||
@@ -203,6 +238,7 @@ _package_self() {
|
|||||||
|
|
||||||
|
|
||||||
SELECT_MONOCHROME=0
|
SELECT_MONOCHROME=0
|
||||||
|
SELECT_SHORTCUTS=0
|
||||||
SELECT_NUMBERS=0
|
SELECT_NUMBERS=0
|
||||||
SELECT_UNDERSCORES=0
|
SELECT_UNDERSCORES=0
|
||||||
SELECT_MULTI=0
|
SELECT_MULTI=0
|
||||||
@@ -210,14 +246,22 @@ SELECT_TOFILE=""
|
|||||||
for (( i=1; i<=$#; i++ )); do
|
for (( i=1; i<=$#; i++ )); do
|
||||||
value=${!i}
|
value=${!i}
|
||||||
j=$(( i + 1 ))
|
j=$(( i + 1 ))
|
||||||
[[ "$value" = "-h" ]] && _help
|
|
||||||
[[ "$value" = "--help" ]] && _help
|
[[ "$value" = "--help" ]] && _help
|
||||||
[[ "$value" = "--nc" ]] && { SELECT_MONOCHROME=1; continue; }
|
[[ "$value" = "--nc" ]] && { SELECT_MONOCHROME=1; continue; }
|
||||||
[[ "$value" = "-m" ]] && { SELECT_MULTI=1; continue; }
|
|
||||||
[[ "$value" = "-n" ]] && { SELECT_NUMBERS=1; continue; }
|
|
||||||
[[ "$value" = "-_" ]] && { SELECT_UNDERSCORES=1; continue; }
|
|
||||||
[[ "$value" = "-o" ]] && { SELECT_TOFILE="${!j}"; ((i++)); continue; }
|
|
||||||
[[ "$value" = "--package" ]] && { _package_self; exit; }
|
[[ "$value" = "--package" ]] && { _package_self; exit; }
|
||||||
|
[[ "${value}" = "-"* ]] && {
|
||||||
|
[[ "$value" =~ -.*h ]] && { _help; }
|
||||||
|
[[ "$value" =~ -.*m ]] && { SELECT_MULTI=1; }
|
||||||
|
[[ "$value" =~ -.*s ]] && { SELECT_SHORTCUTS=1; }
|
||||||
|
[[ "$value" =~ -.*n ]] && { SELECT_NUMBERS=1; }
|
||||||
|
[[ "$value" =~ -.*_ ]] && { SELECT_UNDERSCORES=1; }
|
||||||
|
[[ "$value" =~ -.*o ]] && {
|
||||||
|
SELECT_TOFILE="${!j}"; ((i++));
|
||||||
|
[[ -z "$SELECT_TOFILE" ]] && { echo Output file name missing; exit 1; }
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
opts+=( "$value" )
|
opts+=( "$value" )
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user