forked from pterm/pterm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinteractive_confirm_printer.go
172 lines (150 loc) · 4.4 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
package pterm
import (
"fmt"
"strings"
"atomicgo.dev/cursor"
"atomicgo.dev/keyboard"
"atomicgo.dev/keyboard/keys"
"github.com/pterm/pterm/internal"
)
var (
// 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").
DefaultInteractiveConfirm = InteractiveConfirmPrinter{
DefaultValue: false,
DefaultText: "Please confirm",
TextStyle: &ThemeDefault.PrimaryStyle,
ConfirmText: "Yes",
ConfirmStyle: &ThemeDefault.SuccessMessageStyle,
RejectText: "No",
RejectStyle: &ThemeDefault.ErrorMessageStyle,
SuffixStyle: &ThemeDefault.SecondaryStyle,
}
)
// InteractiveConfirmPrinter is a printer for interactive confirm prompts.
type InteractiveConfirmPrinter struct {
DefaultValue bool
DefaultText string
TextStyle *Style
ConfirmText string
ConfirmStyle *Style
RejectText string
RejectStyle *Style
SuffixStyle *Style
}
// 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
}
// 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()
defer exit()
var result bool
if len(text) == 0 || text[0] == "" {
text = []string{p.DefaultText}
}
p.TextStyle.Print(text[0] + " " + p.getSuffix() + ": ")
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)
}