/
color.go
275 lines (225 loc) · 5.95 KB
/
color.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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
/*
Package color is Command line color library.
Support rich color rendering output, universal API method, compatible with Windows system
Source code and other details for the project are available at GitHub:
https://github.com/gookit/color
More usage please see README and tests.
*/
package color
import (
"fmt"
"io"
"os"
"regexp"
)
// console color mode
// const (
// ModeNormal = iota
// Mode256 // 8 bite
// ModeRGB // 24 bite
// ModeGrayscale
// )
// color render templates
// ESC 操作的表示:
// "\033"(Octal 8进制) = "\x1b"(Hexadecimal 16进制) = 27 (10进制)
const (
SettingTpl = "\x1b[%sm"
FullColorTpl = "\x1b[%sm%s\x1b[0m"
)
// ResetSet Close all properties.
const ResetSet = "\x1b[0m"
// CodeExpr regex to clear color codes eg "\033[1;36mText\x1b[0m"
const CodeExpr = `\033\[[\d;?]+m`
var (
// Enable switch color render and display
Enable = true
// RenderTag render HTML tag on call color.Xprint, color.PrintX
RenderTag = true
// errors on windows render OR print to io.Writer
errors []error
// output the default io.Writer message print
output io.Writer = os.Stdout
// mark current env, It's like in `cmd.exe`
// if not in windows, is's always is False.
isLikeInCmd bool
// match color codes
codeRegex = regexp.MustCompile(CodeExpr)
// mark current env is support color.
// Always: isLikeInCmd != supportColor
supportColor = IsSupportColor()
)
/*************************************************************
* global settings
*************************************************************/
// Set set console color attributes
func Set(colors ...Color) (int, error) {
if !Enable { // not enable
return 0, nil
}
if !supportColor {
return 0, nil
}
return fmt.Printf(SettingTpl, Colors2code(colors...))
}
// Reset reset console color attributes
func Reset() (int, error) {
if !Enable { // not enable
return 0, nil
}
if !supportColor {
return 0, nil
}
return fmt.Print(ResetSet)
}
// Disable disable color output
func Disable() bool {
oldVal := Enable
Enable = false
return oldVal
}
// NotRenderTag on call color.Xprint, color.PrintX
func NotRenderTag() {
RenderTag = false
}
// SetOutput set default colored text output
func SetOutput(w io.Writer) {
output = w
}
// ResetOutput reset output
func ResetOutput() {
output = os.Stdout
}
// ResetOptions reset all package option setting
func ResetOptions() {
RenderTag = true
Enable = true
output = os.Stdout
}
// SupportColor of the current ENV
func SupportColor() bool {
return supportColor
}
// ForceColor force open color render
func ForceColor() bool {
return ForceOpenColor()
}
// ForceOpenColor force open color render
func ForceOpenColor() bool {
oldVal := supportColor
supportColor = true
return oldVal
}
// IsLikeInCmd check result
func IsLikeInCmd() bool {
return isLikeInCmd
}
// GetErrors info
func GetErrors() []error {
return errors
}
/*************************************************************
* render color code
*************************************************************/
// RenderCode render message by color code.
// Usage:
// msg := RenderCode("3;32;45", "some", "message")
func RenderCode(code string, args ...interface{}) string {
var message string
if ln := len(args); ln == 0 {
return ""
}
message = fmt.Sprint(args...)
if len(code) == 0 {
return message
}
// disabled OR not support color
if !Enable || !supportColor {
return ClearCode(message)
}
return fmt.Sprintf(FullColorTpl, code, message)
}
// RenderWithSpaces Render code with spaces.
// If the number of args is > 1, a space will be added between the args
func RenderWithSpaces(code string, args ...interface{}) string {
message := formatArgsForPrintln(args)
if len(code) == 0 {
return message
}
// disabled OR not support color
if !Enable || !supportColor {
return ClearCode(message)
}
return fmt.Sprintf(FullColorTpl, code, message)
}
// RenderString render a string with color code.
// Usage:
// msg := RenderString("3;32;45", "a message")
func RenderString(code string, str string) string {
if len(code) == 0 || str == "" {
return str
}
// disabled OR not support color
if !Enable || !supportColor {
return ClearCode(str)
}
return fmt.Sprintf(FullColorTpl, code, str)
}
// ClearCode clear color codes.
// eg:
// "\033[36;1mText\x1b[0m" -> "Text"
func ClearCode(str string) string {
return codeRegex.ReplaceAllString(str, "")
}
/*************************************************************
* colored message Printer
*************************************************************/
// PrinterFace interface
type PrinterFace interface {
fmt.Stringer
Sprint(a ...interface{}) string
Sprintf(format string, a ...interface{}) string
Print(a ...interface{})
Printf(format string, a ...interface{})
Println(a ...interface{})
}
// Printer a generic color message printer.
// Usage:
// p := &Printer{"32;45;3"}
// p.Print("message")
type Printer struct {
// ColorCode color code string. eg "32;45;3"
ColorCode string
}
// NewPrinter instance
func NewPrinter(colorCode string) *Printer {
return &Printer{colorCode}
}
// String returns color code string. eg: "32;45;3"
func (p *Printer) String() string {
// panic("implement me")
return p.ColorCode
}
// Sprint returns rendering colored messages
func (p *Printer) Sprint(a ...interface{}) string {
return RenderCode(p.String(), a...)
}
// Sprintf returns format and rendering colored messages
func (p *Printer) Sprintf(format string, a ...interface{}) string {
return RenderString(p.String(), fmt.Sprintf(format, a...))
}
// Print rendering colored messages
func (p *Printer) Print(a ...interface{}) {
doPrintV2(p.String(), fmt.Sprint(a...))
}
// Printf format and rendering colored messages
func (p *Printer) Printf(format string, a ...interface{}) {
doPrintV2(p.String(), fmt.Sprintf(format, a...))
}
// Println rendering colored messages with newline
func (p *Printer) Println(a ...interface{}) {
doPrintlnV2(p.ColorCode, a)
}
// IsEmpty color code
func (p *Printer) IsEmpty() bool {
return p.ColorCode == ""
}