#!/bin/bash function prompt_for_multiselect { # little helpers for terminal print control and key input GREEN='\033[00;32m' YELLOW='\033[00;33m' RESTORE='\033[0m' 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 $RESTORE"; } print_active() { printf "$YELLOW$2 $ESC[7m $1 $RESTORE$ESC[27m"; } get_cursor_row() { IFS=';' read -sdR -p $'\E[6n' ROW COL; echo ${ROW#*[}; } 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 = $'\x1b' ]]; then read -rsn2 key if [[ $key = [A ]]; then echo up; fi; if [[ $key = [B ]]; then echo down; fi; fi } toggle_option() { local arr_name=$1 eval "local arr=(\"\${${arr_name}[@]}\")" local option=$2 if [[ ${arr[option]} == true ]]; then arr[option]= else arr[option]=true fi eval $arr_name='("${arr[@]}")' } local retval=$1 local options local defaults IFS=';' read -r -a options <<< "$2" if [[ -z $3 ]]; then defaults=() else IFS=';' read -r -a defaults <<< "$3" fi local selected=() for ((i=0; i<${#options[@]}; i++)); do selected+=("${defaults[i]:-false}") 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 local active=0 while true; do # print options by overwriting the last lines local idx=0 for option in "${options[@]}"; do local prefix="$RESET ◻︎" if [[ ${selected[idx]} == true ]]; then prefix="$GREEN ◼︎" fi cursor_to $(($startrow + $idx)) if [ $idx -eq $active ]; then print_active "$option" "$prefix" else print_inactive "$option" "$prefix" fi ((idx++)) done # user key control case `key_input` in space) toggle_option selected $active;; enter) 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 $retval='("${selected[@]}")' } exec < /dev/tty echo 'Please select from the authors list:' AUTHORS=$(git shortlog -sce | cut -c8-) AUTHORS_LIST=() while read -r line; do if ! [[ "$line" =~ ^.*\|.*$ ]]; then AUTHORS_LIST+=("${line}") OPTIONS_STRING+="${line};" fi done <<< "$AUTHORS" prompt_for_multiselect SELECTED "$OPTIONS_STRING" MESSAGE="\n\n" for i in "${!SELECTED[@]}"; do if [ "${SELECTED[$i]}" == "true" ]; then MESSAGE="${MESSAGE}Co-authored-by: ${AUTHORS_LIST[$i]}\n" fi done exec <&- sed -i.bak -e "1s/$/$MESSAGE/" $1