]>
Commit | Line | Data |
---|---|---|
107c1cdb ND |
1 | package color |
2 | ||
3 | import ( | |
4 | "fmt" | |
5 | "io" | |
6 | "os" | |
7 | "strconv" | |
8 | "strings" | |
9 | "sync" | |
10 | ||
11 | "github.com/mattn/go-colorable" | |
12 | "github.com/mattn/go-isatty" | |
13 | ) | |
14 | ||
15 | var ( | |
16 | // NoColor defines if the output is colorized or not. It's dynamically set to | |
17 | // false or true based on the stdout's file descriptor referring to a terminal | |
18 | // or not. This is a global option and affects all colors. For more control | |
19 | // over each color block use the methods DisableColor() individually. | |
20 | NoColor = os.Getenv("TERM") == "dumb" || | |
21 | (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) | |
22 | ||
23 | // Output defines the standard output of the print functions. By default | |
24 | // os.Stdout is used. | |
25 | Output = colorable.NewColorableStdout() | |
26 | ||
27 | // Error defines a color supporting writer for os.Stderr. | |
28 | Error = colorable.NewColorableStderr() | |
29 | ||
30 | // colorsCache is used to reduce the count of created Color objects and | |
31 | // allows to reuse already created objects with required Attribute. | |
32 | colorsCache = make(map[Attribute]*Color) | |
33 | colorsCacheMu sync.Mutex // protects colorsCache | |
34 | ) | |
35 | ||
36 | // Color defines a custom color object which is defined by SGR parameters. | |
37 | type Color struct { | |
38 | params []Attribute | |
39 | noColor *bool | |
40 | } | |
41 | ||
42 | // Attribute defines a single SGR Code | |
43 | type Attribute int | |
44 | ||
45 | const escape = "\x1b" | |
46 | ||
47 | // Base attributes | |
48 | const ( | |
49 | Reset Attribute = iota | |
50 | Bold | |
51 | Faint | |
52 | Italic | |
53 | Underline | |
54 | BlinkSlow | |
55 | BlinkRapid | |
56 | ReverseVideo | |
57 | Concealed | |
58 | CrossedOut | |
59 | ) | |
60 | ||
61 | // Foreground text colors | |
62 | const ( | |
63 | FgBlack Attribute = iota + 30 | |
64 | FgRed | |
65 | FgGreen | |
66 | FgYellow | |
67 | FgBlue | |
68 | FgMagenta | |
69 | FgCyan | |
70 | FgWhite | |
71 | ) | |
72 | ||
73 | // Foreground Hi-Intensity text colors | |
74 | const ( | |
75 | FgHiBlack Attribute = iota + 90 | |
76 | FgHiRed | |
77 | FgHiGreen | |
78 | FgHiYellow | |
79 | FgHiBlue | |
80 | FgHiMagenta | |
81 | FgHiCyan | |
82 | FgHiWhite | |
83 | ) | |
84 | ||
85 | // Background text colors | |
86 | const ( | |
87 | BgBlack Attribute = iota + 40 | |
88 | BgRed | |
89 | BgGreen | |
90 | BgYellow | |
91 | BgBlue | |
92 | BgMagenta | |
93 | BgCyan | |
94 | BgWhite | |
95 | ) | |
96 | ||
97 | // Background Hi-Intensity text colors | |
98 | const ( | |
99 | BgHiBlack Attribute = iota + 100 | |
100 | BgHiRed | |
101 | BgHiGreen | |
102 | BgHiYellow | |
103 | BgHiBlue | |
104 | BgHiMagenta | |
105 | BgHiCyan | |
106 | BgHiWhite | |
107 | ) | |
108 | ||
109 | // New returns a newly created color object. | |
110 | func New(value ...Attribute) *Color { | |
111 | c := &Color{params: make([]Attribute, 0)} | |
112 | c.Add(value...) | |
113 | return c | |
114 | } | |
115 | ||
116 | // Set sets the given parameters immediately. It will change the color of | |
117 | // output with the given SGR parameters until color.Unset() is called. | |
118 | func Set(p ...Attribute) *Color { | |
119 | c := New(p...) | |
120 | c.Set() | |
121 | return c | |
122 | } | |
123 | ||
124 | // Unset resets all escape attributes and clears the output. Usually should | |
125 | // be called after Set(). | |
126 | func Unset() { | |
127 | if NoColor { | |
128 | return | |
129 | } | |
130 | ||
131 | fmt.Fprintf(Output, "%s[%dm", escape, Reset) | |
132 | } | |
133 | ||
134 | // Set sets the SGR sequence. | |
135 | func (c *Color) Set() *Color { | |
136 | if c.isNoColorSet() { | |
137 | return c | |
138 | } | |
139 | ||
140 | fmt.Fprintf(Output, c.format()) | |
141 | return c | |
142 | } | |
143 | ||
144 | func (c *Color) unset() { | |
145 | if c.isNoColorSet() { | |
146 | return | |
147 | } | |
148 | ||
149 | Unset() | |
150 | } | |
151 | ||
152 | func (c *Color) setWriter(w io.Writer) *Color { | |
153 | if c.isNoColorSet() { | |
154 | return c | |
155 | } | |
156 | ||
157 | fmt.Fprintf(w, c.format()) | |
158 | return c | |
159 | } | |
160 | ||
161 | func (c *Color) unsetWriter(w io.Writer) { | |
162 | if c.isNoColorSet() { | |
163 | return | |
164 | } | |
165 | ||
166 | if NoColor { | |
167 | return | |
168 | } | |
169 | ||
170 | fmt.Fprintf(w, "%s[%dm", escape, Reset) | |
171 | } | |
172 | ||
173 | // Add is used to chain SGR parameters. Use as many as parameters to combine | |
174 | // and create custom color objects. Example: Add(color.FgRed, color.Underline). | |
175 | func (c *Color) Add(value ...Attribute) *Color { | |
176 | c.params = append(c.params, value...) | |
177 | return c | |
178 | } | |
179 | ||
180 | func (c *Color) prepend(value Attribute) { | |
181 | c.params = append(c.params, 0) | |
182 | copy(c.params[1:], c.params[0:]) | |
183 | c.params[0] = value | |
184 | } | |
185 | ||
186 | // Fprint formats using the default formats for its operands and writes to w. | |
187 | // Spaces are added between operands when neither is a string. | |
188 | // It returns the number of bytes written and any write error encountered. | |
189 | // On Windows, users should wrap w with colorable.NewColorable() if w is of | |
190 | // type *os.File. | |
191 | func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) { | |
192 | c.setWriter(w) | |
193 | defer c.unsetWriter(w) | |
194 | ||
195 | return fmt.Fprint(w, a...) | |
196 | } | |
197 | ||
198 | // Print formats using the default formats for its operands and writes to | |
199 | // standard output. Spaces are added between operands when neither is a | |
200 | // string. It returns the number of bytes written and any write error | |
201 | // encountered. This is the standard fmt.Print() method wrapped with the given | |
202 | // color. | |
203 | func (c *Color) Print(a ...interface{}) (n int, err error) { | |
204 | c.Set() | |
205 | defer c.unset() | |
206 | ||
207 | return fmt.Fprint(Output, a...) | |
208 | } | |
209 | ||
210 | // Fprintf formats according to a format specifier and writes to w. | |
211 | // It returns the number of bytes written and any write error encountered. | |
212 | // On Windows, users should wrap w with colorable.NewColorable() if w is of | |
213 | // type *os.File. | |
214 | func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { | |
215 | c.setWriter(w) | |
216 | defer c.unsetWriter(w) | |
217 | ||
218 | return fmt.Fprintf(w, format, a...) | |
219 | } | |
220 | ||
221 | // Printf formats according to a format specifier and writes to standard output. | |
222 | // It returns the number of bytes written and any write error encountered. | |
223 | // This is the standard fmt.Printf() method wrapped with the given color. | |
224 | func (c *Color) Printf(format string, a ...interface{}) (n int, err error) { | |
225 | c.Set() | |
226 | defer c.unset() | |
227 | ||
228 | return fmt.Fprintf(Output, format, a...) | |
229 | } | |
230 | ||
231 | // Fprintln formats using the default formats for its operands and writes to w. | |
232 | // Spaces are always added between operands and a newline is appended. | |
233 | // On Windows, users should wrap w with colorable.NewColorable() if w is of | |
234 | // type *os.File. | |
235 | func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { | |
236 | c.setWriter(w) | |
237 | defer c.unsetWriter(w) | |
238 | ||
239 | return fmt.Fprintln(w, a...) | |
240 | } | |
241 | ||
242 | // Println formats using the default formats for its operands and writes to | |
243 | // standard output. Spaces are always added between operands and a newline is | |
244 | // appended. It returns the number of bytes written and any write error | |
245 | // encountered. This is the standard fmt.Print() method wrapped with the given | |
246 | // color. | |
247 | func (c *Color) Println(a ...interface{}) (n int, err error) { | |
248 | c.Set() | |
249 | defer c.unset() | |
250 | ||
251 | return fmt.Fprintln(Output, a...) | |
252 | } | |
253 | ||
254 | // Sprint is just like Print, but returns a string instead of printing it. | |
255 | func (c *Color) Sprint(a ...interface{}) string { | |
256 | return c.wrap(fmt.Sprint(a...)) | |
257 | } | |
258 | ||
259 | // Sprintln is just like Println, but returns a string instead of printing it. | |
260 | func (c *Color) Sprintln(a ...interface{}) string { | |
261 | return c.wrap(fmt.Sprintln(a...)) | |
262 | } | |
263 | ||
264 | // Sprintf is just like Printf, but returns a string instead of printing it. | |
265 | func (c *Color) Sprintf(format string, a ...interface{}) string { | |
266 | return c.wrap(fmt.Sprintf(format, a...)) | |
267 | } | |
268 | ||
269 | // FprintFunc returns a new function that prints the passed arguments as | |
270 | // colorized with color.Fprint(). | |
271 | func (c *Color) FprintFunc() func(w io.Writer, a ...interface{}) { | |
272 | return func(w io.Writer, a ...interface{}) { | |
273 | c.Fprint(w, a...) | |
274 | } | |
275 | } | |
276 | ||
277 | // PrintFunc returns a new function that prints the passed arguments as | |
278 | // colorized with color.Print(). | |
279 | func (c *Color) PrintFunc() func(a ...interface{}) { | |
280 | return func(a ...interface{}) { | |
281 | c.Print(a...) | |
282 | } | |
283 | } | |
284 | ||
285 | // FprintfFunc returns a new function that prints the passed arguments as | |
286 | // colorized with color.Fprintf(). | |
287 | func (c *Color) FprintfFunc() func(w io.Writer, format string, a ...interface{}) { | |
288 | return func(w io.Writer, format string, a ...interface{}) { | |
289 | c.Fprintf(w, format, a...) | |
290 | } | |
291 | } | |
292 | ||
293 | // PrintfFunc returns a new function that prints the passed arguments as | |
294 | // colorized with color.Printf(). | |
295 | func (c *Color) PrintfFunc() func(format string, a ...interface{}) { | |
296 | return func(format string, a ...interface{}) { | |
297 | c.Printf(format, a...) | |
298 | } | |
299 | } | |
300 | ||
301 | // FprintlnFunc returns a new function that prints the passed arguments as | |
302 | // colorized with color.Fprintln(). | |
303 | func (c *Color) FprintlnFunc() func(w io.Writer, a ...interface{}) { | |
304 | return func(w io.Writer, a ...interface{}) { | |
305 | c.Fprintln(w, a...) | |
306 | } | |
307 | } | |
308 | ||
309 | // PrintlnFunc returns a new function that prints the passed arguments as | |
310 | // colorized with color.Println(). | |
311 | func (c *Color) PrintlnFunc() func(a ...interface{}) { | |
312 | return func(a ...interface{}) { | |
313 | c.Println(a...) | |
314 | } | |
315 | } | |
316 | ||
317 | // SprintFunc returns a new function that returns colorized strings for the | |
318 | // given arguments with fmt.Sprint(). Useful to put into or mix into other | |
319 | // string. Windows users should use this in conjunction with color.Output, example: | |
320 | // | |
321 | // put := New(FgYellow).SprintFunc() | |
322 | // fmt.Fprintf(color.Output, "This is a %s", put("warning")) | |
323 | func (c *Color) SprintFunc() func(a ...interface{}) string { | |
324 | return func(a ...interface{}) string { | |
325 | return c.wrap(fmt.Sprint(a...)) | |
326 | } | |
327 | } | |
328 | ||
329 | // SprintfFunc returns a new function that returns colorized strings for the | |
330 | // given arguments with fmt.Sprintf(). Useful to put into or mix into other | |
331 | // string. Windows users should use this in conjunction with color.Output. | |
332 | func (c *Color) SprintfFunc() func(format string, a ...interface{}) string { | |
333 | return func(format string, a ...interface{}) string { | |
334 | return c.wrap(fmt.Sprintf(format, a...)) | |
335 | } | |
336 | } | |
337 | ||
338 | // SprintlnFunc returns a new function that returns colorized strings for the | |
339 | // given arguments with fmt.Sprintln(). Useful to put into or mix into other | |
340 | // string. Windows users should use this in conjunction with color.Output. | |
341 | func (c *Color) SprintlnFunc() func(a ...interface{}) string { | |
342 | return func(a ...interface{}) string { | |
343 | return c.wrap(fmt.Sprintln(a...)) | |
344 | } | |
345 | } | |
346 | ||
347 | // sequence returns a formatted SGR sequence to be plugged into a "\x1b[...m" | |
348 | // an example output might be: "1;36" -> bold cyan | |
349 | func (c *Color) sequence() string { | |
350 | format := make([]string, len(c.params)) | |
351 | for i, v := range c.params { | |
352 | format[i] = strconv.Itoa(int(v)) | |
353 | } | |
354 | ||
355 | return strings.Join(format, ";") | |
356 | } | |
357 | ||
358 | // wrap wraps the s string with the colors attributes. The string is ready to | |
359 | // be printed. | |
360 | func (c *Color) wrap(s string) string { | |
361 | if c.isNoColorSet() { | |
362 | return s | |
363 | } | |
364 | ||
365 | return c.format() + s + c.unformat() | |
366 | } | |
367 | ||
368 | func (c *Color) format() string { | |
369 | return fmt.Sprintf("%s[%sm", escape, c.sequence()) | |
370 | } | |
371 | ||
372 | func (c *Color) unformat() string { | |
373 | return fmt.Sprintf("%s[%dm", escape, Reset) | |
374 | } | |
375 | ||
376 | // DisableColor disables the color output. Useful to not change any existing | |
377 | // code and still being able to output. Can be used for flags like | |
378 | // "--no-color". To enable back use EnableColor() method. | |
379 | func (c *Color) DisableColor() { | |
380 | c.noColor = boolPtr(true) | |
381 | } | |
382 | ||
383 | // EnableColor enables the color output. Use it in conjunction with | |
384 | // DisableColor(). Otherwise this method has no side effects. | |
385 | func (c *Color) EnableColor() { | |
386 | c.noColor = boolPtr(false) | |
387 | } | |
388 | ||
389 | func (c *Color) isNoColorSet() bool { | |
390 | // check first if we have user setted action | |
391 | if c.noColor != nil { | |
392 | return *c.noColor | |
393 | } | |
394 | ||
395 | // if not return the global option, which is disabled by default | |
396 | return NoColor | |
397 | } | |
398 | ||
399 | // Equals returns a boolean value indicating whether two colors are equal. | |
400 | func (c *Color) Equals(c2 *Color) bool { | |
401 | if len(c.params) != len(c2.params) { | |
402 | return false | |
403 | } | |
404 | ||
405 | for _, attr := range c.params { | |
406 | if !c2.attrExists(attr) { | |
407 | return false | |
408 | } | |
409 | } | |
410 | ||
411 | return true | |
412 | } | |
413 | ||
414 | func (c *Color) attrExists(a Attribute) bool { | |
415 | for _, attr := range c.params { | |
416 | if attr == a { | |
417 | return true | |
418 | } | |
419 | } | |
420 | ||
421 | return false | |
422 | } | |
423 | ||
424 | func boolPtr(v bool) *bool { | |
425 | return &v | |
426 | } | |
427 | ||
428 | func getCachedColor(p Attribute) *Color { | |
429 | colorsCacheMu.Lock() | |
430 | defer colorsCacheMu.Unlock() | |
431 | ||
432 | c, ok := colorsCache[p] | |
433 | if !ok { | |
434 | c = New(p) | |
435 | colorsCache[p] = c | |
436 | } | |
437 | ||
438 | return c | |
439 | } | |
440 | ||
441 | func colorPrint(format string, p Attribute, a ...interface{}) { | |
442 | c := getCachedColor(p) | |
443 | ||
444 | if !strings.HasSuffix(format, "\n") { | |
445 | format += "\n" | |
446 | } | |
447 | ||
448 | if len(a) == 0 { | |
449 | c.Print(format) | |
450 | } else { | |
451 | c.Printf(format, a...) | |
452 | } | |
453 | } | |
454 | ||
455 | func colorString(format string, p Attribute, a ...interface{}) string { | |
456 | c := getCachedColor(p) | |
457 | ||
458 | if len(a) == 0 { | |
459 | return c.SprintFunc()(format) | |
460 | } | |
461 | ||
462 | return c.SprintfFunc()(format, a...) | |
463 | } | |
464 | ||
465 | // Black is a convenient helper function to print with black foreground. A | |
466 | // newline is appended to format by default. | |
467 | func Black(format string, a ...interface{}) { colorPrint(format, FgBlack, a...) } | |
468 | ||
469 | // Red is a convenient helper function to print with red foreground. A | |
470 | // newline is appended to format by default. | |
471 | func Red(format string, a ...interface{}) { colorPrint(format, FgRed, a...) } | |
472 | ||
473 | // Green is a convenient helper function to print with green foreground. A | |
474 | // newline is appended to format by default. | |
475 | func Green(format string, a ...interface{}) { colorPrint(format, FgGreen, a...) } | |
476 | ||
477 | // Yellow is a convenient helper function to print with yellow foreground. | |
478 | // A newline is appended to format by default. | |
479 | func Yellow(format string, a ...interface{}) { colorPrint(format, FgYellow, a...) } | |
480 | ||
481 | // Blue is a convenient helper function to print with blue foreground. A | |
482 | // newline is appended to format by default. | |
483 | func Blue(format string, a ...interface{}) { colorPrint(format, FgBlue, a...) } | |
484 | ||
485 | // Magenta is a convenient helper function to print with magenta foreground. | |
486 | // A newline is appended to format by default. | |
487 | func Magenta(format string, a ...interface{}) { colorPrint(format, FgMagenta, a...) } | |
488 | ||
489 | // Cyan is a convenient helper function to print with cyan foreground. A | |
490 | // newline is appended to format by default. | |
491 | func Cyan(format string, a ...interface{}) { colorPrint(format, FgCyan, a...) } | |
492 | ||
493 | // White is a convenient helper function to print with white foreground. A | |
494 | // newline is appended to format by default. | |
495 | func White(format string, a ...interface{}) { colorPrint(format, FgWhite, a...) } | |
496 | ||
497 | // BlackString is a convenient helper function to return a string with black | |
498 | // foreground. | |
499 | func BlackString(format string, a ...interface{}) string { return colorString(format, FgBlack, a...) } | |
500 | ||
501 | // RedString is a convenient helper function to return a string with red | |
502 | // foreground. | |
503 | func RedString(format string, a ...interface{}) string { return colorString(format, FgRed, a...) } | |
504 | ||
505 | // GreenString is a convenient helper function to return a string with green | |
506 | // foreground. | |
507 | func GreenString(format string, a ...interface{}) string { return colorString(format, FgGreen, a...) } | |
508 | ||
509 | // YellowString is a convenient helper function to return a string with yellow | |
510 | // foreground. | |
511 | func YellowString(format string, a ...interface{}) string { return colorString(format, FgYellow, a...) } | |
512 | ||
513 | // BlueString is a convenient helper function to return a string with blue | |
514 | // foreground. | |
515 | func BlueString(format string, a ...interface{}) string { return colorString(format, FgBlue, a...) } | |
516 | ||
517 | // MagentaString is a convenient helper function to return a string with magenta | |
518 | // foreground. | |
519 | func MagentaString(format string, a ...interface{}) string { | |
520 | return colorString(format, FgMagenta, a...) | |
521 | } | |
522 | ||
523 | // CyanString is a convenient helper function to return a string with cyan | |
524 | // foreground. | |
525 | func CyanString(format string, a ...interface{}) string { return colorString(format, FgCyan, a...) } | |
526 | ||
527 | // WhiteString is a convenient helper function to return a string with white | |
528 | // foreground. | |
529 | func WhiteString(format string, a ...interface{}) string { return colorString(format, FgWhite, a...) } | |
530 | ||
531 | // HiBlack is a convenient helper function to print with hi-intensity black foreground. A | |
532 | // newline is appended to format by default. | |
533 | func HiBlack(format string, a ...interface{}) { colorPrint(format, FgHiBlack, a...) } | |
534 | ||
535 | // HiRed is a convenient helper function to print with hi-intensity red foreground. A | |
536 | // newline is appended to format by default. | |
537 | func HiRed(format string, a ...interface{}) { colorPrint(format, FgHiRed, a...) } | |
538 | ||
539 | // HiGreen is a convenient helper function to print with hi-intensity green foreground. A | |
540 | // newline is appended to format by default. | |
541 | func HiGreen(format string, a ...interface{}) { colorPrint(format, FgHiGreen, a...) } | |
542 | ||
543 | // HiYellow is a convenient helper function to print with hi-intensity yellow foreground. | |
544 | // A newline is appended to format by default. | |
545 | func HiYellow(format string, a ...interface{}) { colorPrint(format, FgHiYellow, a...) } | |
546 | ||
547 | // HiBlue is a convenient helper function to print with hi-intensity blue foreground. A | |
548 | // newline is appended to format by default. | |
549 | func HiBlue(format string, a ...interface{}) { colorPrint(format, FgHiBlue, a...) } | |
550 | ||
551 | // HiMagenta is a convenient helper function to print with hi-intensity magenta foreground. | |
552 | // A newline is appended to format by default. | |
553 | func HiMagenta(format string, a ...interface{}) { colorPrint(format, FgHiMagenta, a...) } | |
554 | ||
555 | // HiCyan is a convenient helper function to print with hi-intensity cyan foreground. A | |
556 | // newline is appended to format by default. | |
557 | func HiCyan(format string, a ...interface{}) { colorPrint(format, FgHiCyan, a...) } | |
558 | ||
559 | // HiWhite is a convenient helper function to print with hi-intensity white foreground. A | |
560 | // newline is appended to format by default. | |
561 | func HiWhite(format string, a ...interface{}) { colorPrint(format, FgHiWhite, a...) } | |
562 | ||
563 | // HiBlackString is a convenient helper function to return a string with hi-intensity black | |
564 | // foreground. | |
565 | func HiBlackString(format string, a ...interface{}) string { | |
566 | return colorString(format, FgHiBlack, a...) | |
567 | } | |
568 | ||
569 | // HiRedString is a convenient helper function to return a string with hi-intensity red | |
570 | // foreground. | |
571 | func HiRedString(format string, a ...interface{}) string { return colorString(format, FgHiRed, a...) } | |
572 | ||
573 | // HiGreenString is a convenient helper function to return a string with hi-intensity green | |
574 | // foreground. | |
575 | func HiGreenString(format string, a ...interface{}) string { | |
576 | return colorString(format, FgHiGreen, a...) | |
577 | } | |
578 | ||
579 | // HiYellowString is a convenient helper function to return a string with hi-intensity yellow | |
580 | // foreground. | |
581 | func HiYellowString(format string, a ...interface{}) string { | |
582 | return colorString(format, FgHiYellow, a...) | |
583 | } | |
584 | ||
585 | // HiBlueString is a convenient helper function to return a string with hi-intensity blue | |
586 | // foreground. | |
587 | func HiBlueString(format string, a ...interface{}) string { return colorString(format, FgHiBlue, a...) } | |
588 | ||
589 | // HiMagentaString is a convenient helper function to return a string with hi-intensity magenta | |
590 | // foreground. | |
591 | func HiMagentaString(format string, a ...interface{}) string { | |
592 | return colorString(format, FgHiMagenta, a...) | |
593 | } | |
594 | ||
595 | // HiCyanString is a convenient helper function to return a string with hi-intensity cyan | |
596 | // foreground. | |
597 | func HiCyanString(format string, a ...interface{}) string { return colorString(format, FgHiCyan, a...) } | |
598 | ||
599 | // HiWhiteString is a convenient helper function to return a string with hi-intensity white | |
600 | // foreground. | |
601 | func HiWhiteString(format string, a ...interface{}) string { | |
602 | return colorString(format, FgHiWhite, a...) | |
603 | } |