-
Notifications
You must be signed in to change notification settings - Fork 316
/
ui.go
184 lines (155 loc) · 5.13 KB
/
ui.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
package terminal
import (
"errors"
"io"
"github.com/fatih/color"
)
const (
HeaderStyle = "header"
ErrorStyle = "error"
ErrorBoldStyle = "error-bold"
WarningStyle = "warning"
WarningBoldStyle = "warning-bold"
InfoStyle = "info"
LibraryStyle = "library"
SuccessStyle = "success"
SuccessBoldStyle = "success-bold"
DiffUnchangedStyle = "diff-unchanged"
DiffAddedStyle = "diff-added"
DiffRemovedStyle = "diff-removed"
)
var (
colorHeader = color.New(color.Bold)
colorInfo = color.New()
colorError = color.New(color.FgRed)
colorErrorBold = color.New(color.FgRed, color.Bold)
colorLibrary = color.New(color.FgCyan)
colorSuccess = color.New(color.FgGreen)
colorSuccessBold = color.New(color.FgGreen, color.Bold)
colorWarning = color.New(color.FgYellow)
colorWarningBold = color.New(color.FgYellow, color.Bold)
colorDiffUnchanged = color.New()
colorDiffAdded = color.New(color.FgGreen)
colorDiffRemoved = color.New(color.FgRed)
)
// ErrNonInteractive is returned when Input is called on a non-Interactive UI.
var ErrNonInteractive = errors.New("noninteractive UI doesn't support this operation")
// Passed to UI.NamedValues to provide a nicely formatted key: value output.
type NamedValue struct {
Name string
Value interface{}
}
// UI is the primary interface for interacting with a user via the CLI.
//
// Some of the methods on this interface return values that have a lifetime
// such as Status and StepGroup. While these are still active (haven't called
// the close or equivalent method on these values), no other method on the
// UI should be called.
type UI interface {
// Input asks the user for input. This will immediately return an error
// if the UI doesn't support interaction. You can test for interaction
// ahead of time with Interactive().
Input(*Input) (string, error)
// Interactive returns true if this prompt supports user interaction.
// If this is false, Input will always error.
Interactive() bool
// Output outputs a message directly to the terminal. The remaining
// arguments should be interpolations for the format string. After the
// interpolations you may add Options.
Output(string, ...interface{})
// Output data as a table of data. Each entry is a row which will be output
// with the columns lined up nicely.
NamedValues([]NamedValue, ...Option)
// OutputWriters returns stdout and stderr writers. These are usually
// but not always TTYs. This is useful for subprocesses, network requests,
// etc. Note that writing to these is not thread-safe by default so
// you must take care that there is only ever one writer.
OutputWriters() (stdout, stderr io.Writer, err error)
// Table outputs the information formatted into a Table structure.
Table(*Table, ...Option)
}
// Input is the configuration for an input.
type Input struct {
// Prompt is a single-line prompt to give the user such as "Continue?"
// The user will input their answer after this prompt.
Prompt string
// Style is the style to apply to the input. If this is blank,
// the output won't be colorized in any way.
Style string
// True if this input is a secret. The input will be masked.
Secret bool
}
type config struct {
// Writer is where the message will be written to.
Writer io.Writer
// The style the output should take on
Style string
}
// Option controls output styling.
type Option func(*config)
// WithHeaderStyle styles the output like a header denoting a new section
// of execution. This should only be used with single-line output. Multi-line
// output will not look correct.
func WithHeaderStyle() Option {
return func(c *config) {
c.Style = HeaderStyle
}
}
// WithInfoStyle styles the output like it's formatted information.
func WithInfoStyle() Option {
return func(c *config) {
c.Style = InfoStyle
}
}
// WithErrorStyle styles the output as an error message.
func WithErrorStyle() Option {
return func(c *config) {
c.Style = ErrorStyle
}
}
// WithWarningStyle styles the output as an warning message.
func WithWarningStyle() Option {
return func(c *config) {
c.Style = WarningStyle
}
}
// WithSuccessStyle styles the output as a success message.
func WithSuccessStyle() Option {
return func(c *config) {
c.Style = SuccessStyle
}
}
// WithLibraryStyle styles the output with an arrow pointing to a section.
func WithLibraryStyle() Option {
return func(c *config) {
c.Style = LibraryStyle
}
}
// WithDiffUnchangedStyle colors the diff style in white.
func WithDiffUnchangedStyle() Option {
return func(c *config) {
c.Style = DiffUnchangedStyle
}
}
// WithDiffAddedStyle colors the output in green.
func WithDiffAddedStyle() Option {
return func(c *config) {
c.Style = DiffAddedStyle
}
}
// WithDiffRemovedStyle colors the output in red.
func WithDiffRemovedStyle() Option {
return func(c *config) {
c.Style = DiffRemovedStyle
}
}
// WithStyle allows for setting a style by passing a string.
func WithStyle(style string) Option {
return func(c *config) {
c.Style = style
}
}
// WithWriter specifies the writer for the output.
func WithWriter(w io.Writer) Option {
return func(c *config) { c.Writer = w }
}