diff options
author | Michael Muré <batolettre@gmail.com> | 2020-01-07 22:06:42 +0100 |
---|---|---|
committer | Michael Muré <batolettre@gmail.com> | 2020-02-08 17:18:27 +0100 |
commit | db893494bb1492a3d9e32787a5ada1dd8f639ef3 (patch) | |
tree | ca956e6f2024d82a7600faca6d584cc3406593f0 /input/prompt.go | |
parent | 97bc5ccd229b7b438262a84e3c42783b4d4a82af (diff) | |
download | git-bug-db893494bb1492a3d9e32787a5ada1dd8f639ef3.tar.gz |
input: better reusable prompt functions
Diffstat (limited to 'input/prompt.go')
-rw-r--r-- | input/prompt.go | 106 |
1 files changed, 95 insertions, 11 deletions
diff --git a/input/prompt.go b/input/prompt.go index 6036c062..c7887abb 100644 --- a/input/prompt.go +++ b/input/prompt.go @@ -4,23 +4,36 @@ import ( "bufio" "fmt" "os" + "strconv" "strings" + "syscall" + + "golang.org/x/crypto/ssh/terminal" + + "github.com/MichaelMure/git-bug/util/interrupt" ) -func PromptValue(name string, preValue string) (string, error) { - return promptValue(name, preValue, false) +// PromptValidator is a validator for a user entry +type PromptValidator func(name string, value string) (complaint string, err error) + +// Required is a validator preventing a "" value +func Required(name string, value string) (string, error) { + if value == "" { + return fmt.Sprintf("%s is empty", name), nil + } + return "", nil } -func PromptValueRequired(name string, preValue string) (string, error) { - return promptValue(name, preValue, true) +func Prompt(prompt, name string, validators ...PromptValidator) (string, error) { + return PromptDefault(prompt, name, "", validators...) } -func promptValue(name string, preValue string, required bool) (string, error) { +func PromptDefault(prompt, name, preValue string, validators ...PromptValidator) (string, error) { for { if preValue != "" { - _, _ = fmt.Fprintf(os.Stderr, "%s [%s]: ", name, preValue) + _, _ = fmt.Fprintf(os.Stderr, "%s [%s]: ", prompt, preValue) } else { - _, _ = fmt.Fprintf(os.Stderr, "%s: ", name) + _, _ = fmt.Fprintf(os.Stderr, "%s: ", prompt) } line, err := bufio.NewReader(os.Stdin).ReadString('\n') @@ -31,14 +44,85 @@ func promptValue(name string, preValue string, required bool) (string, error) { line = strings.TrimSpace(line) if preValue != "" && line == "" { - return preValue, nil + line = preValue } - if required && line == "" { - _, _ = fmt.Fprintf(os.Stderr, "%s is empty\n", name) - continue + for _, validator := range validators { + complaint, err := validator(name, line) + if err != nil { + return "", err + } + if complaint != "" { + _, _ = fmt.Fprintln(os.Stderr, complaint) + continue + } } return line, nil } } + +func PromptPassword(prompt, name string, validators ...PromptValidator) (string, error) { + termState, err := terminal.GetState(syscall.Stdin) + if err != nil { + return "", err + } + + cancel := interrupt.RegisterCleaner(func() error { + return terminal.Restore(syscall.Stdin, termState) + }) + defer cancel() + + for { + _, _ = fmt.Fprintf(os.Stderr, "%s: ", prompt) + + bytePassword, err := terminal.ReadPassword(syscall.Stdin) + // new line for coherent formatting, ReadPassword clip the normal new line + // entered by the user + fmt.Println() + + if err != nil { + return "", err + } + + pass := string(bytePassword) + + for _, validator := range validators { + complaint, err := validator(name, pass) + if err != nil { + return "", err + } + if complaint != "" { + _, _ = fmt.Fprintln(os.Stderr, complaint) + continue + } + } + + return pass, nil + } +} + +func PromptChoice(prompt string, choices []string) (int, error) { + for { + for i, choice := range choices { + _, _ = fmt.Fprintf(os.Stderr, "[%d]: %s\n", i+1, choice) + } + _, _ = fmt.Fprintf(os.Stderr, "%s: ", prompt) + + line, err := bufio.NewReader(os.Stdin).ReadString('\n') + fmt.Println() + if err != nil { + return 0, err + } + + line = strings.TrimSpace(line) + + index, err := strconv.Atoi(line) + if err != nil || index < 1 || index > len(choices) { + fmt.Println("invalid input") + continue + } + + return index, nil + } +} |