From 5546c477acb95700d2f6c511146e0872a557a302 Mon Sep 17 00:00:00 2001 From: pyr0ball Date: Tue, 22 Mar 2022 13:40:50 -0700 Subject: [PATCH] added multi-select function --- lib/skel/.bashrc.d/functions | 111 ++++++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/lib/skel/.bashrc.d/functions b/lib/skel/.bashrc.d/functions index 28b80a1..2032a9c 100644 --- a/lib/skel/.bashrc.d/functions +++ b/lib/skel/.bashrc.d/functions @@ -224,4 +224,113 @@ select_opt(){ # 0) echo "selected Yes";; # 1) echo "selected No";; # *) echo "selected ${options[$?]}";; -#esac \ No newline at end of file +#esac + +multiselect(){ + # 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_inactive() { printf "$2 $1 "; } + print_active() { printf "$2 $ESC[7m $1 $ESC[27m"; } + get_cursor_row() { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${ROW#*[}; } + + local return_value=$1 + local -n options=$2 + local -n defaults=$3 + + local selected=() + for ((i=0; i<${#options[@]}; i++)); do + if [[ ${defaults[i]} = "true" ]]; then + selected+=("true") + else + selected+=("false") + fi + printf "\n" + done + + # determine current screen position for overwriting the options + local lastrow=`get_cursor_row` + local startrow=$(($lastrow - ${#options[@]})) + + # 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 + + key_input() { + local key + IFS= read -rsn1 key 2>/dev/null >&2 + if [[ $key = "" ]]; then echo enter; fi; + if [[ $key = $'\x20' ]]; then echo space; fi; + if [[ $key = "k" ]]; then echo up; fi; + if [[ $key = "j" ]]; then echo down; fi; + if [[ $key = $'\x1b' ]]; then + read -rsn2 key + if [[ $key = [A || $key = k ]]; then echo up; fi; + if [[ $key = [B || $key = j ]]; then echo down; fi; + fi + } + + toggle_option() { + local option=$1 + if [[ ${selected[option]} == true ]]; then + selected[option]=false + else + selected[option]=true + fi + } + + print_options() { + # print options by overwriting the last lines + local idx=0 + for option in "${options[@]}"; do + local prefix="[ ]" + if [[ ${selected[idx]} == true ]]; then + prefix="[\e[38;5;46m✔\e[0m]" + fi + + cursor_to $(($startrow + $idx)) + if [ $idx -eq $1 ]; then + print_active "$option" "$prefix" + else + print_inactive "$option" "$prefix" + fi + ((idx++)) + done + } + + local active=0 + while true; do + print_options $active + + # user key control + case `key_input` in + space) toggle_option $active;; + enter) print_options -1; break;; + up) ((active--)); + if [ $active -lt 0 ]; then active=$((${#options[@]} - 1)); fi;; + down) ((active++)); + if [ $active -ge ${#options[@]} ]; then active=0; fi;; + esac + done + + # cursor position back to normal + cursor_to $lastrow + printf "\n" + cursor_blink_on + + eval $return_value='("${selected[@]}")' +} + +# Example for above multiselect functions +#my_options=( "Option 1" "Option 2" "Option 3" ) +#preselection=( "true" "true" "false" ) + +#multiselect result my_options preselection + +#idx=0 +#for option in "${my_options[@]}"; do +# echo -e "$option\t=> ${result[idx]}" +# ((idx++)) +#done \ No newline at end of file