1package input
2
3import (
4 "bufio"
5 "fmt"
6 "os"
7 "strconv"
8 "strings"
9 "syscall"
10
11 "golang.org/x/crypto/ssh/terminal"
12
13 "github.com/MichaelMure/git-bug/util/interrupt"
14)
15
16// PromptValidator is a validator for a user entry
17type PromptValidator func(name string, value string) (complaint string, err error)
18
19// Required is a validator preventing a "" value
20func Required(name string, value string) (string, error) {
21 if value == "" {
22 return fmt.Sprintf("%s is empty", name), nil
23 }
24 return "", nil
25}
26
27func Prompt(prompt, name string, validators ...PromptValidator) (string, error) {
28 return PromptDefault(prompt, name, "", validators...)
29}
30
31func PromptDefault(prompt, name, preValue string, validators ...PromptValidator) (string, error) {
32 for {
33 if preValue != "" {
34 _, _ = fmt.Fprintf(os.Stderr, "%s [%s]: ", prompt, preValue)
35 } else {
36 _, _ = fmt.Fprintf(os.Stderr, "%s: ", prompt)
37 }
38
39 line, err := bufio.NewReader(os.Stdin).ReadString('\n')
40 if err != nil {
41 return "", err
42 }
43
44 line = strings.TrimSpace(line)
45
46 if preValue != "" && line == "" {
47 line = preValue
48 }
49
50 for _, validator := range validators {
51 complaint, err := validator(name, line)
52 if err != nil {
53 return "", err
54 }
55 if complaint != "" {
56 _, _ = fmt.Fprintln(os.Stderr, complaint)
57 continue
58 }
59 }
60
61 return line, nil
62 }
63}
64
65func PromptPassword(prompt, name string, validators ...PromptValidator) (string, error) {
66 termState, err := terminal.GetState(syscall.Stdin)
67 if err != nil {
68 return "", err
69 }
70
71 cancel := interrupt.RegisterCleaner(func() error {
72 return terminal.Restore(syscall.Stdin, termState)
73 })
74 defer cancel()
75
76 for {
77 _, _ = fmt.Fprintf(os.Stderr, "%s: ", prompt)
78
79 bytePassword, err := terminal.ReadPassword(syscall.Stdin)
80 // new line for coherent formatting, ReadPassword clip the normal new line
81 // entered by the user
82 fmt.Println()
83
84 if err != nil {
85 return "", err
86 }
87
88 pass := string(bytePassword)
89
90 for _, validator := range validators {
91 complaint, err := validator(name, pass)
92 if err != nil {
93 return "", err
94 }
95 if complaint != "" {
96 _, _ = fmt.Fprintln(os.Stderr, complaint)
97 continue
98 }
99 }
100
101 return pass, nil
102 }
103}
104
105func PromptChoice(prompt string, choices []string) (int, error) {
106 for {
107 for i, choice := range choices {
108 _, _ = fmt.Fprintf(os.Stderr, "[%d]: %s\n", i+1, choice)
109 }
110 _, _ = fmt.Fprintf(os.Stderr, "%s: ", prompt)
111
112 line, err := bufio.NewReader(os.Stdin).ReadString('\n')
113 fmt.Println()
114 if err != nil {
115 return 0, err
116 }
117
118 line = strings.TrimSpace(line)
119
120 index, err := strconv.Atoi(line)
121 if err != nil || index < 1 || index > len(choices) {
122 fmt.Println("invalid input")
123 continue
124 }
125
126 return index, nil
127 }
128}