forked from AlecAivazis/survey
-
Notifications
You must be signed in to change notification settings - Fork 0
/
confirm.go
153 lines (139 loc) · 3.56 KB
/
confirm.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package survey
import (
"fmt"
"regexp"
)
// Confirm is a regular text input that accept yes/no answers. Response type is a bool.
type Confirm struct {
Renderer
Message string
Default bool
Help string
}
// data available to the templates when processing
type ConfirmTemplateData struct {
Confirm
Answer string
ShowHelp bool
Config *PromptConfig
}
// Templates with Color formatting. See Documentation: https://github.com/mgutz/ansi#style-format
var ConfirmQuestionTemplate = `
{{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}}
{{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}}
{{- color "default+hb"}}{{ .Message }} {{color "reset"}}
{{- if .Answer}}
{{- color "cyan"}}{{.Answer}}{{color "reset"}}{{"\n"}}
{{- else }}
{{- if and .Help (not .ShowHelp)}}{{color "cyan"}}[{{ .Config.HelpInput }} for help]{{color "reset"}} {{end}}
{{- color "white"}}{{if .Default}}(Y/n) {{else}}(y/N) {{end}}{{color "reset"}}
{{- end}}`
// the regex for answers
var (
yesRx = regexp.MustCompile("^(?i:y(?:es)?)$")
noRx = regexp.MustCompile("^(?i:n(?:o)?)$")
)
func yesNo(t bool) string {
if t {
return "Yes"
}
return "No"
}
func (c *Confirm) getBool(showHelp bool, config *PromptConfig) (bool, error) {
cursor := c.NewCursor()
rr := c.NewRuneReader()
rr.SetTermMode()
defer rr.RestoreTermMode()
// start waiting for input
for {
line, err := rr.ReadLine(0)
if err != nil {
return false, err
}
// move back up a line to compensate for the \n echoed from terminal
cursor.PreviousLine(1)
val := string(line)
// get the answer that matches the
var answer bool
switch {
case yesRx.Match([]byte(val)):
answer = true
case noRx.Match([]byte(val)):
answer = false
case val == "":
answer = c.Default
case val == config.HelpInput && c.Help != "":
err := c.Render(
ConfirmQuestionTemplate,
ConfirmTemplateData{
Confirm: *c,
ShowHelp: true,
Config: config,
},
)
if err != nil {
// use the default value and bubble up
return c.Default, err
}
showHelp = true
continue
default:
// we didnt get a valid answer, so print error and prompt again
if err := c.Error(config, fmt.Errorf("%q is not a valid answer, please try again.", val)); err != nil {
return c.Default, err
}
err := c.Render(
ConfirmQuestionTemplate,
ConfirmTemplateData{
Confirm: *c,
ShowHelp: showHelp,
Config: config,
},
)
if err != nil {
// use the default value and bubble up
return c.Default, err
}
continue
}
return answer, nil
}
// should not get here
return c.Default, nil
}
/*
Prompt prompts the user with a simple text field and expects a reply followed
by a carriage return.
likesPie := false
prompt := &survey.Confirm{ Message: "What is your name?" }
survey.AskOne(prompt, &likesPie)
*/
func (c *Confirm) Prompt(config *PromptConfig) (interface{}, error) {
// render the question template
err := c.Render(
ConfirmQuestionTemplate,
ConfirmTemplateData{
Confirm: *c,
Config: config,
},
)
if err != nil {
return "", err
}
// get input and return
return c.getBool(false, config)
}
// Cleanup overwrite the line with the finalized formatted version
func (c *Confirm) Cleanup(config *PromptConfig, val interface{}) error {
// if the value was previously true
ans := yesNo(val.(bool))
// render the template
return c.Render(
ConfirmQuestionTemplate,
ConfirmTemplateData{
Confirm: *c,
Answer: ans,
Config: config,
},
)
}