1package color 2 3import ( 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 15var ( 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. 37type Color struct { 38 params []Attribute 39 noColor *bool 40} 41 42// Attribute defines a single SGR Code 43type Attribute int 44 45const escape = "\x1b" 46 47// Base attributes 48const ( 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 62const ( 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 74const ( 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 86const ( 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 98const ( 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. 110func 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. 118func 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(). 126func Unset() { 127 if NoColor { 128 return 129 } 130 131 fmt.Fprintf(Output, "%s[%dm", escape, Reset) 132} 133 134// Set sets the SGR sequence. 135func (c *Color) Set() *Color { 136 if c.isNoColorSet() { 137 return c 138 } 139 140 fmt.Fprintf(Output, c.format()) 141 return c 142} 143 144func (c *Color) unset() { 145 if c.isNoColorSet() { 146 return 147 } 148 149 Unset() 150} 151 152func (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 161func (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). 175func (c *Color) Add(value ...Attribute) *Color { 176 c.params = append(c.params, value...) 177 return c 178} 179 180func (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. 191func (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. 203func (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. 214func (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. 224func (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. 235func (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. 247func (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. 255func (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. 260func (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. 265func (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(). 271func (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(). 279func (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(). 287func (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(). 295func (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(). 303func (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(). 311func (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")) 323func (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. 332func (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. 341func (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 349func (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. 360func (c *Color) wrap(s string) string { 361 if c.isNoColorSet() { 362 return s 363 } 364 365 return c.format() + s + c.unformat() 366} 367 368func (c *Color) format() string { 369 return fmt.Sprintf("%s[%sm", escape, c.sequence()) 370} 371 372func (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. 379func (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. 385func (c *Color) EnableColor() { 386 c.noColor = boolPtr(false) 387} 388 389func (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. 400func (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 414func (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 424func boolPtr(v bool) *bool { 425 return &v 426} 427 428func 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 441func 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 455func 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. 467func 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. 471func 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. 475func 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. 479func 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. 483func 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. 487func 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. 491func 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. 495func 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. 499func 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. 503func 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. 507func 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. 511func 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. 515func 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. 519func 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. 525func 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. 529func 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. 533func 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. 537func 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. 541func 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. 545func 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. 549func 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. 553func 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. 557func 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. 561func 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. 565func 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. 571func 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. 575func 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. 581func 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. 587func 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. 591func 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. 597func 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. 601func HiWhiteString(format string, a ...interface{}) string { 602 return colorString(format, FgHiWhite, a...) 603} 604