|
| 1 | +#! /usr/bin/env bash |
| 2 | +# |
| 3 | +# User input prompts |
| 4 | +# |
| 5 | +# Exports: |
| 6 | +# @go.read_prompt_response |
| 7 | +# Reads a line, trims leading/trailing space, and sets a default if empty |
| 8 | +# |
| 9 | +# @go.prompt_for_input |
| 10 | +# Prompts the user for a line of input |
| 11 | +# |
| 12 | +# @go.prompt_for_yes_or_no |
| 13 | +# Prompts the user for a yes or no response |
| 14 | +# |
| 15 | +# @go.select_option |
| 16 | +# Prompts the user to select one item from a list of options |
| 17 | + |
| 18 | +. "$_GO_USE_MODULES" 'strings' 'validation' |
| 19 | + |
| 20 | +# Reads a line, trims leading/trailing space, and sets a default if empty |
| 21 | +# |
| 22 | +# Arguments: |
| 23 | +# var_name: Name of the caller's variable into which to read value |
| 24 | +# default: (Optional) Default value if the input line is empty |
| 25 | +@go.read_prompt_response() { |
| 26 | + @go.validate_identifier_or_die 'Input prompt response variable name' "$1" |
| 27 | + read -r "$1" |
| 28 | + @go.trim "$1" |
| 29 | + printf -v "$1" -- '%s' "${!1:-$2}" |
| 30 | +} |
| 31 | + |
| 32 | +# Prompts the user for a line of input |
| 33 | +# |
| 34 | +# If the prompt doesn't end with a whitespace character, a space will be added |
| 35 | +# between the prompt and the input cursor. Otherwise the existing character will |
| 36 | +# be preserved. |
| 37 | +# |
| 38 | +# If a default value is specified, a space will be added to the prompt, followed |
| 39 | +# by the default value in square brackets; the caller should not add the default |
| 40 | +# value to the prompt directly. If the prompt ends with a whitespace character, |
| 41 | +# it will be preserved and added after the default value. |
| 42 | +# |
| 43 | +# Arguments: |
| 44 | +# result_var Name of the caller-declared variable for the result |
| 45 | +# prompt Text prompt for user input |
| 46 | +# default (Optional) Default value if response is empty |
| 47 | +# fail_msg (Optional) Failure message if empty input isn't valid |
| 48 | +@go.prompt_for_input() { |
| 49 | + @go.validate_identifier_or_die 'Input prompt response variable name' "$1" |
| 50 | + |
| 51 | + if [[ "$2" =~ [[:space:]]$ ]]; then |
| 52 | + @go.printf '%s%s%s' "${2%?}" "${3:+ [default: $3]}" "${BASH_REMATCH[0]}" >&2 |
| 53 | + else |
| 54 | + @go.printf '%s %s' "$2" "${3:+[default: $3] }" >&2 |
| 55 | + fi |
| 56 | + @go.read_prompt_response "$1" "$3" |
| 57 | + |
| 58 | + if [[ -z "${!1}" && -n "$4" ]]; then |
| 59 | + @go.printf '%s\n' "$4" >&2 |
| 60 | + return 1 |
| 61 | + fi |
| 62 | +} |
| 63 | + |
| 64 | +# Prompts the user for a yes or no response |
| 65 | +# |
| 66 | +# Arguments: |
| 67 | +# prompt Text prompt for user input |
| 68 | +# default (Optional) Default response; must be 'yes' or 'no' |
| 69 | +# |
| 70 | +# Returns: |
| 71 | +# Zero on 'y' or 'yes' (case- and space- insensitive), nonzero otherwise |
| 72 | +@go.prompt_for_yes_or_no() { |
| 73 | + local prompt="$1" |
| 74 | + local default="$2" |
| 75 | + local response |
| 76 | + |
| 77 | + case "$default" in |
| 78 | + yes) |
| 79 | + @go.printf '%s [Y/n] ' "$prompt" >&2 |
| 80 | + ;; |
| 81 | + no) |
| 82 | + @go.printf '%s [y/N] ' "$prompt" >&2 |
| 83 | + ;; |
| 84 | + '') |
| 85 | + @go.printf '%s [y/n] ' "$prompt" >&2 |
| 86 | + ;; |
| 87 | + *) |
| 88 | + @go.printf 'Invalid `default` parameter "%s" for %s at:\n' \ |
| 89 | + "$default" "$FUNCNAME" >&2 |
| 90 | + @go.print_stack_trace '1' >&2 |
| 91 | + exit 1 |
| 92 | + ;; |
| 93 | + esac |
| 94 | + |
| 95 | + while true; do |
| 96 | + @go.read_prompt_response 'response' "$default" |
| 97 | + |
| 98 | + if [[ "$response" =~ ^[Yy]([Ee][Ss])?$ ]]; then |
| 99 | + return 0 |
| 100 | + elif [[ "$response" =~ ^[Nn]([Oo])?$ ]]; then |
| 101 | + return 1 |
| 102 | + else |
| 103 | + if [[ -n "$response" ]]; then |
| 104 | + @go.printf '\n"%s" is an invalid response.\n' "$response" >&2 |
| 105 | + fi |
| 106 | + @go.printf '\nPlease answer Y(es) or N(o): ' >&2 |
| 107 | + fi |
| 108 | + done |
| 109 | +} |
| 110 | + |
| 111 | +# Prompts the user to select one item from a list of options. |
| 112 | +# |
| 113 | +# This is a thin wrapper around the `select` builtin command for |
| 114 | +# straightforward, single-option user prompts. If you need to do anything more |
| 115 | +# complex, use the `select` builtin command directly. |
| 116 | +# |
| 117 | +# This will prompt the user for a single input, returned in the caller-declared |
| 118 | +# variable identified by `result_var`. If the user enters an invalid option, |
| 119 | +# this will notify the user and prompt again. If the user terminates input (via |
| 120 | +# EOF, i.e. Ctrl-D), `result_var` will remain unchanged and the function will |
| 121 | +# return nonzero. |
| 122 | +# |
| 123 | +# Globals: |
| 124 | +# PS3 environment variable defining the selection prompt |
| 125 | +# |
| 126 | +# Arguments: |
| 127 | +# result_var: Name of the caller-declared variable used to store the option |
| 128 | +# ...: Strings representing options available for the user to select |
| 129 | +# |
| 130 | +# Returns: |
| 131 | +# zero if `result_var` contains the user's selection, nonzero otherwise |
| 132 | +@go.select_option() { |
| 133 | + @go.validate_identifier_or_die 'Input selection variable name' "$1" |
| 134 | + |
| 135 | + local __go_selected_option |
| 136 | + select __go_selected_option in "${@:2}"; do |
| 137 | + case "$__go_selected_option" in |
| 138 | + '') |
| 139 | + @go.printf '"%s" is not a valid option.\n' "$REPLY" >&2 |
| 140 | + ;; |
| 141 | + *) |
| 142 | + printf -v "$1" -- '%s' "$__go_selected_option" |
| 143 | + break |
| 144 | + ;; |
| 145 | + esac |
| 146 | + done |
| 147 | + [[ -n "$__go_selected_option" ]] |
| 148 | +} |
0 commit comments