You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

color.go 18KB

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