multiple selection choocer
This commit is contained in:
@@ -1,22 +1,16 @@
|
||||
#!/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
|
||||
local multiselected=()
|
||||
for opt; do
|
||||
if [[ "${#opt}" -gt $max_opt ]]; then
|
||||
max_opt=${#opt}
|
||||
fi
|
||||
multiselected+=(0)
|
||||
done
|
||||
|
||||
# little helpers for terminal print control and key input
|
||||
@@ -25,11 +19,13 @@ function select_option {
|
||||
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] "; }
|
||||
print_option() { printf " $ESC[30m%s $ESC[0m %s $ESC[30m%s$ESC[0m " "$2" "$1" "$3"; }
|
||||
print_selected() { printf " $ESC[30m%s$ESC[0m{ $ESC[1m%s$ESC[0m }$ESC[30m%s$ESC[0m " "$2" "$1" "$3"; }
|
||||
print_multiselected() { printf "$ESC[30;1m*$ESC[0m"; }
|
||||
else
|
||||
print_option() { printf " $ESC[33m $1 $ESC[0m "; }
|
||||
print_selected() { printf " [$ESC[37;1m$1$ESC[0m] "; }
|
||||
print_option() { printf " $ESC[30m%s $ESC[33m %s $ESC[0m $ESC[30m%s$ESC[0m " "$2" "$1" "$3"; }
|
||||
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_multiselected() { printf "$ESC[32;1m*$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
|
||||
@@ -39,7 +35,11 @@ function select_option {
|
||||
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[C ]]; then echo left; return; fi
|
||||
if [[ $key1$key2 = $ESC[D ]]; then echo right; return; fi
|
||||
if [[ $key1 = $'\e' ]]; then echo esc; return; fi
|
||||
if [[ $key1 = x ]]; then echo multiselect; return; fi
|
||||
if [[ $key1 = q ]]; then echo esc; return; fi
|
||||
if [[ $key1 = "" ]]; then echo enter; return; fi
|
||||
}
|
||||
reset_display() {
|
||||
@@ -47,22 +47,35 @@ function select_option {
|
||||
}
|
||||
# initially print empty new lines (scroll down if at bottom of screen)
|
||||
for opt; do printf "\n"; done
|
||||
# Extras for top and bottom
|
||||
printf "\n\n"
|
||||
|
||||
# determine current screen position for overwriting the options
|
||||
local lastrow=`get_cursor_row`
|
||||
local startrow=$(($lastrow - $#))
|
||||
local startrow=$(( $lastrow - $# - 2 ))
|
||||
local toprow="+~~--"
|
||||
local bottomrow="--~~+"
|
||||
local lborderchars="|:'"
|
||||
local rborderchars="|:."
|
||||
|
||||
# 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
|
||||
cursor_to $startrow
|
||||
printf " $ESC[30m%s$ESC[0m" "$toprow"
|
||||
|
||||
for opt; do
|
||||
local lborder="${lborderchars:$idx:1}"
|
||||
if [ -z "$lborder" ]; then lborder=" "; fi
|
||||
local rborder="${rborderchars:$(( $optcount - $idx - 1)):1}"
|
||||
if [ -z "$rborder" ]; then rborder=" "; fi
|
||||
if [[ $SELECT_UNDERSCORES -eq 1 ]]; then
|
||||
opt=${opt//_/ }
|
||||
fi
|
||||
@@ -70,14 +83,21 @@ function select_option {
|
||||
printf -v nidx "$nformat" $(( idx + 1 ))
|
||||
fi
|
||||
printf -v padopt "%-${max_opt}s" "$opt"
|
||||
cursor_to $(($startrow + $idx))
|
||||
cursor_to $(($startrow + $idx + 1))
|
||||
if [ $idx -eq $selected ]; then
|
||||
print_selected "$nidx$padopt"
|
||||
print_selected "$nidx$padopt" "$lborder" "$rborder"
|
||||
else
|
||||
print_option "$nidx$padopt"
|
||||
print_option "$nidx$padopt" "${lborder}" "$rborder"
|
||||
fi
|
||||
if (( ${multiselected[$idx]} )); then
|
||||
cursor_to $(($startrow + $idx + 1)) 5
|
||||
print_multiselected
|
||||
fi
|
||||
((idx++))
|
||||
done
|
||||
cursor_to $(($startrow + $idx + 1))
|
||||
local bottomlength=$(( 8 + $max_opt + ${#nidx} ))
|
||||
printf "$ESC[30m%${bottomlength}s$ESC[0m" "$bottomrow"
|
||||
|
||||
# user key control
|
||||
local user_input=`key_input`
|
||||
@@ -88,6 +108,7 @@ function select_option {
|
||||
if [ $selected -lt 0 ]; then selected=$(($# - 1)); fi;;
|
||||
down) ((selected++));
|
||||
if [ $selected -ge $# ]; then selected=0; fi;;
|
||||
multiselect) if (( $SELECT_MULTI )); then multiselected[$selected]=$(( 1 - ${multiselected[$selected]} )); fi;;
|
||||
[0-9]) selected=$(( $user_input - 1 )) ;;
|
||||
esac
|
||||
done
|
||||
@@ -95,8 +116,21 @@ function select_option {
|
||||
# cursor position back to normal
|
||||
cursor_to $lastrow
|
||||
reset_display
|
||||
if [[ -n "$SELECT_TOFILE" ]]; then
|
||||
local returnvalue=0
|
||||
local idx=0
|
||||
if (( $SELECT_MULTI )); then
|
||||
if [[ -n "$SELECT_TOFILE" ]]; then printf "" > "$SELECT_TOFILE"; fi
|
||||
for opt; do
|
||||
if (( ${multiselected[$idx]} )); then
|
||||
if [[ -n "$SELECT_TOFILE" ]]; then echo "$opt" >> "$SELECT_TOFILE"; fi
|
||||
returnvalue=$(( $returnvalue + 2**$idx ))
|
||||
fi
|
||||
((idx++))
|
||||
done
|
||||
else
|
||||
# Single choice
|
||||
returnvalue=$selected
|
||||
if [[ -n "$SELECT_TOFILE" ]]; then
|
||||
for opt; do
|
||||
if [ $idx -eq $selected ]; then
|
||||
echo "$opt" > "$SELECT_TOFILE"
|
||||
@@ -104,28 +138,55 @@ function select_option {
|
||||
((idx++))
|
||||
done
|
||||
fi
|
||||
return $(( 10 + $selected ))
|
||||
fi
|
||||
|
||||
return $(( $returnvalue + 10 ))
|
||||
}
|
||||
|
||||
[[ $_ == $0 ]] && {
|
||||
_help() {
|
||||
SELF=$( basename "$0" )
|
||||
echo "Select Option
|
||||
echo "Select Option [Pure BASH]
|
||||
Adapted from: https://unix.stackexchange.com/questions/146570/arrow-key-enter-menu
|
||||
|
||||
Usage: $SELF [-n] [--nc] [-o File] [-_] list of options
|
||||
-n Number list
|
||||
-n Numbered list
|
||||
-m Multiple choice selection. Note that only 7 options can be encoded
|
||||
reliably in return value. Use File output for more options.
|
||||
--nc No colors
|
||||
-o File Save the choice in a file
|
||||
-_ Print spaces instead of underscores
|
||||
-o File Save the choice(s) in a file.
|
||||
-_ Print spaces instead of underscores, workaround for
|
||||
shell arguments with spaces.
|
||||
|
||||
Returns
|
||||
User interface:
|
||||
Enter Select option
|
||||
Esc / Ctrl-c Exit
|
||||
x Multi-selection
|
||||
|
||||
Returns:
|
||||
Single selection:
|
||||
(10 + index) of selection (first option = 10)
|
||||
1 if ctrl-c or ESC pressed
|
||||
If output file is defined, choice is printed there.
|
||||
Multiple selection:
|
||||
(10 + 2**index) encoded multiple values (no options = 10). See example.
|
||||
1 if ctrl-c or ESC pressed
|
||||
All choices separately in the output File.
|
||||
|
||||
Example:
|
||||
Single choice:
|
||||
$SELF -n one two three
|
||||
EC=\$?
|
||||
[[ \$EC -lt 10 ]] && { echo Exited..; } || { echo You selected \$(( \$EC - 9 )); }
|
||||
|
||||
Multi choice:
|
||||
$SELF -m one two three four five six seven -o choice.txt
|
||||
C=\$?; C=\$(( \$C - 10 ))
|
||||
if (( \$C == 0 )); then printf 'No selection'; else printf 'Selections: '; fi
|
||||
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
|
||||
done; printf '\\n'
|
||||
|
||||
"
|
||||
exit
|
||||
}
|
||||
@@ -133,6 +194,7 @@ _help() {
|
||||
SELECT_MONOCHROME=0
|
||||
SELECT_NUMBERS=0
|
||||
SELECT_UNDERSCORES=0
|
||||
SELECT_MULTI=0
|
||||
SELECT_TOFILE=""
|
||||
for (( i=1; i<=$#; i++ )); do
|
||||
value=${!i}
|
||||
@@ -140,6 +202,7 @@ for (( i=1; i<=$#; i++ )); do
|
||||
[[ "$value" = "-h" ]] && _help
|
||||
[[ "$value" = "--help" ]] && _help
|
||||
[[ "$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; }
|
||||
|
||||
Reference in New Issue
Block a user