forked from pterm/pterm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
interactive_confirm_printer.go
186 lines (161 loc) · 4.91 KB
/
interactive_confirm_printer.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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package pterm
import (
"fmt"
"strings"
"atomicgo.dev/cursor"
"atomicgo.dev/keyboard"
"atomicgo.dev/keyboard/keys"
"github.com/pterm/pterm/internal"
)
// DefaultInteractiveConfirm is the default InteractiveConfirm printer.
// Pressing "y" will return true, "n" will return false.
// Pressing enter without typing "y" or "n" will return the configured default value (by default set to "no").
var DefaultInteractiveConfirm = InteractiveConfirmPrinter{
DefaultValue: false,
DefaultText: "Please confirm",
TextStyle: &ThemeDefault.PrimaryStyle,
ConfirmText: "Yes",
ConfirmStyle: &ThemeDefault.SuccessMessageStyle,
RejectText: "No",
RejectStyle: &ThemeDefault.ErrorMessageStyle,
SuffixStyle: &ThemeDefault.SecondaryStyle,
Delimiter: ": ",
}
// InteractiveConfirmPrinter is a printer for interactive confirm prompts.
type InteractiveConfirmPrinter struct {
DefaultValue bool
DefaultText string
Delimiter string
TextStyle *Style
ConfirmText string
ConfirmStyle *Style
RejectText string
RejectStyle *Style
SuffixStyle *Style
OnInterruptFunc func()
}
// WithDefaultText sets the default text.
func (p InteractiveConfirmPrinter) WithDefaultText(text string) *InteractiveConfirmPrinter {
p.DefaultText = text
return &p
}
// WithDefaultValue sets the default value, which will be returned when the user presses enter without typing "y" or "n".
func (p InteractiveConfirmPrinter) WithDefaultValue(value bool) *InteractiveConfirmPrinter {
p.DefaultValue = value
return &p
}
// WithTextStyle sets the text style.
func (p InteractiveConfirmPrinter) WithTextStyle(style *Style) *InteractiveConfirmPrinter {
p.TextStyle = style
return &p
}
// WithConfirmText sets the confirm text.
func (p InteractiveConfirmPrinter) WithConfirmText(text string) *InteractiveConfirmPrinter {
p.ConfirmText = text
return &p
}
// WithConfirmStyle sets the confirm style.
func (p InteractiveConfirmPrinter) WithConfirmStyle(style *Style) *InteractiveConfirmPrinter {
p.ConfirmStyle = style
return &p
}
// WithRejectText sets the reject text.
func (p InteractiveConfirmPrinter) WithRejectText(text string) *InteractiveConfirmPrinter {
p.RejectText = text
return &p
}
// WithRejectStyle sets the reject style.
func (p InteractiveConfirmPrinter) WithRejectStyle(style *Style) *InteractiveConfirmPrinter {
p.RejectStyle = style
return &p
}
// WithSuffixStyle sets the suffix style.
func (p InteractiveConfirmPrinter) WithSuffixStyle(style *Style) *InteractiveConfirmPrinter {
p.SuffixStyle = style
return &p
}
// OnInterrupt sets the function to execute on exit of the input reader
func (p InteractiveConfirmPrinter) WithOnInterruptFunc(exitFunc func()) *InteractiveConfirmPrinter {
p.OnInterruptFunc = exitFunc
return &p
}
// WithDelimiter sets the delimiter between the message and the input.
func (p InteractiveConfirmPrinter) WithDelimiter(delimiter string) *InteractiveConfirmPrinter {
p.Delimiter = delimiter
return &p
}
// Show shows the confirm prompt.
//
// Example:
//
// result, _ := pterm.DefaultInteractiveConfirm.Show("Are you sure?")
// pterm.Println(result)
func (p InteractiveConfirmPrinter) Show(text ...string) (bool, error) {
// should be the first defer statement to make sure it is executed last
// and all the needed cleanup can be done before
cancel, exit := internal.NewCancelationSignal(p.OnInterruptFunc)
defer exit()
var result bool
if len(text) == 0 || text[0] == "" {
text = []string{p.DefaultText}
}
p.TextStyle.Print(text[0] + " " + p.getSuffix() + p.Delimiter)
y, n := p.getShortHandles()
var interrupted bool
err := keyboard.Listen(func(keyInfo keys.Key) (stop bool, err error) {
key := keyInfo.Code
char := strings.ToLower(keyInfo.String())
if err != nil {
return false, fmt.Errorf("failed to get key: %w", err)
}
switch key {
case keys.RuneKey:
switch char {
case y:
p.ConfirmStyle.Print(p.ConfirmText)
Println()
result = true
return true, nil
case n:
p.RejectStyle.Print(p.RejectText)
Println()
result = false
return true, nil
}
case keys.Enter:
if p.DefaultValue {
p.ConfirmStyle.Print(p.ConfirmText)
} else {
p.RejectStyle.Print(p.RejectText)
}
Println()
result = p.DefaultValue
return true, nil
case keys.CtrlC:
cancel()
interrupted = true
return true, nil
}
return false, nil
})
if !interrupted {
cursor.StartOfLine()
}
return result, err
}
// getShortHandles returns the short hand answers for the confirmation prompt
func (p InteractiveConfirmPrinter) getShortHandles() (string, string) {
y := strings.ToLower(string([]rune(p.ConfirmText)[0]))
n := strings.ToLower(string([]rune(p.RejectText)[0]))
return y, n
}
// getSuffix returns the confirmation prompt suffix
func (p InteractiveConfirmPrinter) getSuffix() string {
y, n := p.getShortHandles()
if p.DefaultValue {
y = strings.ToUpper(y)
} else {
n = strings.ToUpper(n)
}
return p.SuffixStyle.Sprintf("[%s/%s]", y, n)
}