aboutsummaryrefslogtreecommitdiffstats
path: root/input/prompt.go
diff options
context:
space:
mode:
authorMichael Muré <batolettre@gmail.com>2020-01-07 22:06:42 +0100
committerMichael Muré <batolettre@gmail.com>2020-02-08 17:18:27 +0100
commitdb893494bb1492a3d9e32787a5ada1dd8f639ef3 (patch)
treeca956e6f2024d82a7600faca6d584cc3406593f0 /input/prompt.go
parent97bc5ccd229b7b438262a84e3c42783b4d4a82af (diff)
downloadgit-bug-db893494bb1492a3d9e32787a5ada1dd8f639ef3.tar.gz
input: better reusable prompt functions
Diffstat (limited to 'input/prompt.go')
-rw-r--r--input/prompt.go106
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
+ }
+}