From b24bd7859411dba56cf74806cc056ae62f6cc81a Mon Sep 17 00:00:00 2001 From: Austin Horstman Date: Sun, 16 Jan 2022 15:14:12 -0600 Subject: [PATCH 1/2] Interactive select list --- startup.sh | 142 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 102 insertions(+), 40 deletions(-) diff --git a/startup.sh b/startup.sh index 76bf882..e74f9fd 100644 --- a/startup.sh +++ b/startup.sh @@ -17,6 +17,69 @@ set_option() { fi echo "${1}=${2}" >>$CONFIG_FILE # add option } +# 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 ...) +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 +} logo () { # This will be shown on every set as user is progressing echo -ne " @@ -36,17 +99,16 @@ filesystem () { # This function will handle file systems. At this movement we are handling only # btrfs and ext4. Others will be added in future. echo -ne " - Please Select your file system for both boot and root - 1) btrfs - 2) ext4 - 3) luks with btrfs - 0) exit +Please Select your file system for both boot and root " -read fs +options=("btrfs" "ext4" "luks" "exit") +select_option "${options[@]}" +fs=$? + case $fs in -1) set_option FS btrfs;; -2) set_option FS ext4;; -3) +0) set_option FS btrfs;; +1) set_option FS ext4;; +2) while true; do echo -ne "Please enter your luks password: \n" read -s luks_password # read password without echo @@ -63,54 +125,60 @@ while true; do fi done ;; -0) exit ;; +3) exit ;; *) echo "Wrong option please select again"; filesystem;; esac } timezone () { # Added this from arch wiki https://wiki.archlinux.org/title/System_time time_zone="$(curl --fail https://ipapi.co/timezone)" -echo -ne "System detected your timezone to be '$time_zone' \n" -echo -ne "Is this correct? yes/no:" -read answer -case $answer in +echo -ne " +System detected your timezone to be '$time_zone' \n" +echo -ne "Is this correct? +" +options=("Yes" "No") +select_option "${options[@]}" +choice=$? + +case ${options[$choice]} in y|Y|yes|Yes|YES) + echo "${time_zone} set as timezone" set_option TIMEZONE $time_zone;; n|N|no|NO|No) echo "Please enter your desired timezone e.g. Europe/London :" read new_timezone + echo "${new_timezone} set as timezone" set_option TIMEZONE $new_timezone;; *) echo "Wrong option. Try again";timezone;; esac } keymap () { -# These are default key maps as presented in official arch repo archinstall -options=(by ca cf cz de dk es et fa fi fr gr hu il it lt lv mk nl no pl ro ru sg ua uk us) PS3=" + Please select key board layout from this list " -select keymap in "${options[@]}" -do -# check if selection is part of list, silence error output and use else block for output -if echo -e '%s\n' "${options[@]}" | grep -Fqw $keymap 2> /dev/null; then - echo -e "\nYour key boards layout: ${keymap} \n" - set_option KEYMAP $keymap - break -else - echo -e "\nInvalid selection, please try again. \n" -fi +# These are default key maps as presented in official arch repo archinstall +options=(by ca cf cz de dk es et fa fi fr gr hu il it lt lv mk nl no pl ro ru sg ua uk us) -done +select_option "${options[@]}" +choice=$? +keymap=${options[$choice]} + +echo -ne "\nYour key boards layout: ${keymap} \n" +set_option KEYMAP $keymap } drivessd () { echo -ne " Is this an ssd? yes/no: " -read ssd_drive -case $ssd_drive in +options=("Yes" "No") +select_option "${options[@]}" +choice=$? + +case ${options[$choice]} in y|Y|yes|Yes|YES) set_option MOUNT_OPTIONS "noatime,compress=zstd,ssd,commit=120";; n|N|no|NO|No) @@ -133,19 +201,13 @@ echo -ne " PS3=' Select the disk to install on: ' options=($(lsblk -n --output TYPE,KNAME,SIZE | awk '$1=="disk"{print "/dev/"$2"|"$3}')) -select disk in "${options[@]}" -do -# check if selection is part of list, silence error output and use else block for output -if echo -e '%s\n' "${options[@]}" | grep -Fqw ${disk} 2> /dev/null; then - echo -e "\n${disk%|*} selected \n" +select_option "${options[@]}" +choice=$? +disk=${options[$choice]%|*} + +echo -e "\n${disk%|*} selected \n" set_option DISK ${disk%|*} - break -else - echo -e "\nInvalid selection, please try again. \n" -fi - -done drivessd } From 792bc5213960b4233b40e8620206edc0e5678176 Mon Sep 17 00:00:00 2001 From: Austin Horstman Date: Sun, 16 Jan 2022 21:19:40 -0600 Subject: [PATCH 2/2] Multi column lists Parameter sizing of columns --- startup.sh | 130 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 84 insertions(+), 46 deletions(-) mode change 100644 => 100755 startup.sh diff --git a/startup.sh b/startup.sh old mode 100644 new mode 100755 index e74f9fd..5ea082d --- a/startup.sh +++ b/startup.sh @@ -30,46 +30,92 @@ select_option() { 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"; } + print_option() { printf "$2 $1 "; } + print_selected() { printf "$2 $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; } + get_cursor_col() { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${COL#*[}; } + 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 = "h" ]]; then echo left; fi; + if [[ $key = "l" ]]; then echo right; fi; + if [[ $key = "a" ]]; then echo all; fi; + if [[ $key = "n" ]]; then echo none; 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; + if [[ $key = [C || $key = l ]]; then echo right; fi; + if [[ $key = [D || $key = h ]]; then echo left; fi; + fi + } + print_options_multicol() { + # print options by overwriting the last lines + local curr_col=$1 + local curr_row=$2 + local curr_idx=0 + + local idx=0 + local row=0 + local col=0 + + curr_idx=$(( $curr_col + $curr_row * $colmax )) + + for option in "${options[@]}"; do + + row=$(( $idx/$colmax )) + col=$(( $idx - $row * $colmax )) + + cursor_to $(( $startrow + $row + 1)) $(( $offset * $col + 1)) + if [ $idx -eq $curr_idx ]; then + print_selected "$option" + else + print_option "$option" + fi + ((idx++)) + done + } # 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 return_value=$1 local lastrow=`get_cursor_row` + local lastcol=`get_cursor_col` local startrow=$(($lastrow - $#)) + local startcol=1 + local lines=$( tput lines ) + local cols=$( tput cols ) + local colmax=$2 + local offset=$(( $cols / $colmax )) + + local size=$4 + shift 4 # 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 + local active_row=0 + local active_col=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 - + print_options_multicol $active_col $active_row # 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;; + enter) break;; + up) ((active_row--)); + if [ $active_row -lt 0 ]; then active_row=0; fi;; + down) ((active_row++)); + if [ $active_row -ge $(( ${#options[@]} / $colmax )) ]; then active_row=$(( ${#options[@]} / $colmax )); fi;; + left) ((active_col=$active_col - 1)); + if [ $active_col -lt 0 ]; then active_col=0; fi;; + right) ((active_col=$active_col + 1)); + if [ $active_col -ge $colmax ]; then active_col=$(( $colmax - 1 )) ; fi;; esac done @@ -78,7 +124,7 @@ select_option() { printf "\n" cursor_blink_on - return $selected + return $(( $active_col + $active_row * $colmax )) } logo () { # This will be shown on every set as user is progressing @@ -102,10 +148,9 @@ echo -ne " Please Select your file system for both boot and root " options=("btrfs" "ext4" "luks" "exit") -select_option "${options[@]}" -fs=$? +select_option $? 1 "${options[@]}" -case $fs in +case $? in 0) set_option FS btrfs;; 1) set_option FS ext4;; 2) @@ -137,10 +182,9 @@ System detected your timezone to be '$time_zone' \n" echo -ne "Is this correct? " options=("Yes" "No") -select_option "${options[@]}" -choice=$? +select_option $? 1 "${options[@]}" -case ${options[$choice]} in +case ${options[$?]} in y|Y|yes|Yes|YES) echo "${time_zone} set as timezone" set_option TIMEZONE $time_zone;; @@ -153,19 +197,15 @@ case ${options[$choice]} in esac } keymap () { -PS3=" - -Please select key board layout from this list - -" +echo -ne " +Please select key board layout from this list" # These are default key maps as presented in official arch repo archinstall options=(by ca cf cz de dk es et fa fi fr gr hu il it lt lv mk nl no pl ro ru sg ua uk us) -select_option "${options[@]}" -choice=$? -keymap=${options[$choice]} +select_option $? 4 "${options[@]}" +keymap=${options[$?]} -echo -ne "\nYour key boards layout: ${keymap} \n" +echo -ne "Your key boards layout: ${keymap} \n" set_option KEYMAP $keymap } @@ -175,10 +215,9 @@ Is this an ssd? yes/no: " options=("Yes" "No") -select_option "${options[@]}" -choice=$? +select_option $? 1 "${options[@]}" -case ${options[$choice]} in +case ${options[$?]} in y|Y|yes|Yes|YES) set_option MOUNT_OPTIONS "noatime,compress=zstd,ssd,commit=120";; n|N|no|NO|No) @@ -202,9 +241,8 @@ PS3=' Select the disk to install on: ' options=($(lsblk -n --output TYPE,KNAME,SIZE | awk '$1=="disk"{print "/dev/"$2"|"$3}')) -select_option "${options[@]}" -choice=$? -disk=${options[$choice]%|*} +select_option $? 1 "${options[@]}" +disk=${options[$?]%|*} echo -e "\n${disk%|*} selected \n" set_option DISK ${disk%|*}