// // Copyright (c) 2016-2020 The Aurora Authors. All rights reserved. // This program is free software. It comes without any warranty, // to the extent permitted by applicable law. You can redistribute // it and/or modify it under the terms of the Unlicense. See LICENSE // file for more details or see below. // // // This is free and unencumbered software released into the public domain. // // Anyone is free to copy, modify, publish, use, compile, sell, or // distribute this software, either in source code form or as a compiled // binary, for any purpose, commercial or non-commercial, and by any // means. // // In jurisdictions that recognize copyright laws, the author or authors // of this software dedicate any and all copyright interest in the // software to the public domain. We make this dedication for the benefit // of the public at large and to the detriment of our heirs and // successors. We intend this dedication to be an overt act of // relinquishment in perpetuity of all present and future rights to this // software under copyright law. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // For more information, please refer to // package aurora import ( "fmt" "strconv" "unicode/utf8" ) // A Value represents any printable value // with it's color type Value interface { // String returns string with colors. If there are any color // or format the string will be terminated with \033[0m fmt.Stringer // Format implements fmt.Formatter interface fmt.Formatter // Color returns value's color Color() Color // Value returns value's value (welcome to the tautology club) Value() interface{} // internals tail() Color setTail(Color) Value // Bleach returns copy of original value without colors // // Deprecated: use Reset instead. Bleach() Value // Reset colors and formats Reset() Value // // Formats // // // Bold or increased intensity (1). Bold() Value // Faint, decreased intensity, reset the Bold (2). Faint() Value // // DoublyUnderline or Bold off, double-underline // per ECMA-48 (21). It depends. DoublyUnderline() Value // Fraktur, rarely supported (20). Fraktur() Value // // Italic, not widely supported, sometimes // treated as inverse (3). Italic() Value // Underline (4). Underline() Value // // SlowBlink, blinking less than 150 // per minute (5). SlowBlink() Value // RapidBlink, blinking 150+ per minute, // not widely supported (6). RapidBlink() Value // Blink is alias for the SlowBlink. Blink() Value // // Reverse video, swap foreground and // background colors (7). Reverse() Value // Inverse is alias for the Reverse Inverse() Value // // Conceal, hidden, not widely supported (8). Conceal() Value // Hidden is alias for the Conceal Hidden() Value // // CrossedOut, characters legible, but // marked for deletion (9). CrossedOut() Value // StrikeThrough is alias for the CrossedOut. StrikeThrough() Value // // Framed (51). Framed() Value // Encircled (52). Encircled() Value // // Overlined (53). Overlined() Value // // Foreground colors // // // Black foreground color (30) Black() Value // Red foreground color (31) Red() Value // Green foreground color (32) Green() Value // Yellow foreground color (33) Yellow() Value // Brown foreground color (33) // // Deprecated: use Yellow instead, following specification Brown() Value // Blue foreground color (34) Blue() Value // Magenta foreground color (35) Magenta() Value // Cyan foreground color (36) Cyan() Value // White foreground color (37) White() Value // // Bright foreground colors // // BrightBlack foreground color (90) BrightBlack() Value // BrightRed foreground color (91) BrightRed() Value // BrightGreen foreground color (92) BrightGreen() Value // BrightYellow foreground color (93) BrightYellow() Value // BrightBlue foreground color (94) BrightBlue() Value // BrightMagenta foreground color (95) BrightMagenta() Value // BrightCyan foreground color (96) BrightCyan() Value // BrightWhite foreground color (97) BrightWhite() Value // // Other // // Index of pre-defined 8-bit foreground color // from 0 to 255 (38;5;n). // // 0- 7: standard colors (as in ESC [ 30–37 m) // 8- 15: high intensity colors (as in ESC [ 90–97 m) // 16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5) // 232-255: grayscale from black to white in 24 steps // Index(n uint8) Value // Gray from 0 to 24. Gray(n uint8) Value // // Background colors // // // BgBlack background color (40) BgBlack() Value // BgRed background color (41) BgRed() Value // BgGreen background color (42) BgGreen() Value // BgYellow background color (43) BgYellow() Value // BgBrown background color (43) // // Deprecated: use BgYellow instead, following specification BgBrown() Value // BgBlue background color (44) BgBlue() Value // BgMagenta background color (45) BgMagenta() Value // BgCyan background color (46) BgCyan() Value // BgWhite background color (47) BgWhite() Value // // Bright background colors // // BgBrightBlack background color (100) BgBrightBlack() Value // BgBrightRed background color (101) BgBrightRed() Value // BgBrightGreen background color (102) BgBrightGreen() Value // BgBrightYellow background color (103) BgBrightYellow() Value // BgBrightBlue background color (104) BgBrightBlue() Value // BgBrightMagenta background color (105) BgBrightMagenta() Value // BgBrightCyan background color (106) BgBrightCyan() Value // BgBrightWhite background color (107) BgBrightWhite() Value // // Other // // BgIndex of 8-bit pre-defined background color // from 0 to 255 (48;5;n). // // 0- 7: standard colors (as in ESC [ 40–47 m) // 8- 15: high intensity colors (as in ESC [100–107 m) // 16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5) // 232-255: grayscale from black to white in 24 steps // BgIndex(n uint8) Value // BgGray from 0 to 24. BgGray(n uint8) Value // // Special // // Colorize removes existing colors and // formats of the argument and applies given. Colorize(color Color) Value } // Value without colors type valueClear struct { value interface{} } func (vc valueClear) String() string { return fmt.Sprint(vc.value) } func (vc valueClear) Color() Color { return 0 } func (vc valueClear) Value() interface{} { return vc.value } func (vc valueClear) tail() Color { return 0 } func (vc valueClear) setTail(Color) Value { return vc } func (vc valueClear) Bleach() Value { return vc } func (vc valueClear) Reset() Value { return vc } func (vc valueClear) Bold() Value { return vc } func (vc valueClear) Faint() Value { return vc } func (vc valueClear) DoublyUnderline() Value { return vc } func (vc valueClear) Fraktur() Value { return vc } func (vc valueClear) Italic() Value { return vc } func (vc valueClear) Underline() Value { return vc } func (vc valueClear) SlowBlink() Value { return vc } func (vc valueClear) RapidBlink() Value { return vc } func (vc valueClear) Blink() Value { return vc } func (vc valueClear) Reverse() Value { return vc } func (vc valueClear) Inverse() Value { return vc } func (vc valueClear) Conceal() Value { return vc } func (vc valueClear) Hidden() Value { return vc } func (vc valueClear) CrossedOut() Value { return vc } func (vc valueClear) StrikeThrough() Value { return vc } func (vc valueClear) Framed() Value { return vc } func (vc valueClear) Encircled() Value { return vc } func (vc valueClear) Overlined() Value { return vc } func (vc valueClear) Black() Value { return vc } func (vc valueClear) Red() Value { return vc } func (vc valueClear) Green() Value { return vc } func (vc valueClear) Yellow() Value { return vc } func (vc valueClear) Brown() Value { return vc } func (vc valueClear) Blue() Value { return vc } func (vc valueClear) Magenta() Value { return vc } func (vc valueClear) Cyan() Value { return vc } func (vc valueClear) White() Value { return vc } func (vc valueClear) BrightBlack() Value { return vc } func (vc valueClear) BrightRed() Value { return vc } func (vc valueClear) BrightGreen() Value { return vc } func (vc valueClear) BrightYellow() Value { return vc } func (vc valueClear) BrightBlue() Value { return vc } func (vc valueClear) BrightMagenta() Value { return vc } func (vc valueClear) BrightCyan() Value { return vc } func (vc valueClear) BrightWhite() Value { return vc } func (vc valueClear) Index(uint8) Value { return vc } func (vc valueClear) Gray(uint8) Value { return vc } func (vc valueClear) BgBlack() Value { return vc } func (vc valueClear) BgRed() Value { return vc } func (vc valueClear) BgGreen() Value { return vc } func (vc valueClear) BgYellow() Value { return vc } func (vc valueClear) BgBrown() Value { return vc } func (vc valueClear) BgBlue() Value { return vc } func (vc valueClear) BgMagenta() Value { return vc } func (vc valueClear) BgCyan() Value { return vc } func (vc valueClear) BgWhite() Value { return vc } func (vc valueClear) BgBrightBlack() Value { return vc } func (vc valueClear) BgBrightRed() Value { return vc } func (vc valueClear) BgBrightGreen() Value { return vc } func (vc valueClear) BgBrightYellow() Value { return vc } func (vc valueClear) BgBrightBlue() Value { return vc } func (vc valueClear) BgBrightMagenta() Value { return vc } func (vc valueClear) BgBrightCyan() Value { return vc } func (vc valueClear) BgBrightWhite() Value { return vc } func (vc valueClear) BgIndex(uint8) Value { return vc } func (vc valueClear) BgGray(uint8) Value { return vc } func (vc valueClear) Colorize(Color) Value { return vc } func (vc valueClear) Format(s fmt.State, verb rune) { // it's enough for many cases (%-+020.10f) // % - 1 // availFlags - 3 (5) // width - 2 // prec - 3 (.23) // verb - 1 // -------------- // 10 format := make([]byte, 1, 10) format[0] = '%' var f byte for i := 0; i < len(availFlags); i++ { if f = availFlags[i]; s.Flag(int(f)) { format = append(format, f) } } var width, prec int var ok bool if width, ok = s.Width(); ok { format = strconv.AppendInt(format, int64(width), 10) } if prec, ok = s.Precision(); ok { format = append(format, '.') format = strconv.AppendInt(format, int64(prec), 10) } if verb > utf8.RuneSelf { format = append(format, string(verb)...) } else { format = append(format, byte(verb)) } fmt.Fprintf(s, string(format), vc.value) } // Value within colors type value struct { value interface{} // value as it color Color // this color tailColor Color // tail color } func (v value) String() string { if v.color != 0 { if v.tailColor != 0 { return esc + v.color.Nos(true) + "m" + fmt.Sprint(v.value) + esc + v.tailColor.Nos(true) + "m" } return esc + v.color.Nos(false) + "m" + fmt.Sprint(v.value) + clear } return fmt.Sprint(v.value) } func (v value) Color() Color { return v.color } func (v value) Bleach() Value { v.color, v.tailColor = 0, 0 return v } func (v value) Reset() Value { v.color, v.tailColor = 0, 0 return v } func (v value) tail() Color { return v.tailColor } func (v value) setTail(t Color) Value { v.tailColor = t return v } func (v value) Value() interface{} { return v.value } func (v value) Format(s fmt.State, verb rune) { // it's enough for many cases (%-+020.10f) // % - 1 // availFlags - 3 (5) // width - 2 // prec - 3 (.23) // verb - 1 // -------------- // 10 // + // \033[ 5 // 0;1;3;4;5;7;8;9;20;21;51;52;53 30 // 38;5;216 8 // 48;5;216 8 // m 1 // + // \033[0m 7 // // x2 (possible tail color) // // 10 + 59 * 2 = 128 format := make([]byte, 0, 128) if v.color != 0 { format = append(format, esc...) format = v.color.appendNos(format, v.tailColor != 0) format = append(format, 'm') } format = append(format, '%') var f byte for i := 0; i < len(availFlags); i++ { if f = availFlags[i]; s.Flag(int(f)) { format = append(format, f) } } var width, prec int var ok bool if width, ok = s.Width(); ok { format = strconv.AppendInt(format, int64(width), 10) } if prec, ok = s.Precision(); ok { format = append(format, '.') format = strconv.AppendInt(format, int64(prec), 10) } if verb > utf8.RuneSelf { format = append(format, string(verb)...) } else { format = append(format, byte(verb)) } if v.color != 0 { if v.tailColor != 0 { // set next (previous) format clearing current one format = append(format, esc...) format = v.tailColor.appendNos(format, true) format = append(format, 'm') } else { format = append(format, clear...) // just clear } } fmt.Fprintf(s, string(format), v.value) } func (v value) Bold() Value { v.color = (v.color &^ FaintFm) | BoldFm return v } func (v value) Faint() Value { v.color = (v.color &^ BoldFm) | FaintFm return v } func (v value) DoublyUnderline() Value { v.color |= DoublyUnderlineFm return v } func (v value) Fraktur() Value { v.color |= FrakturFm return v } func (v value) Italic() Value { v.color |= ItalicFm return v } func (v value) Underline() Value { v.color |= UnderlineFm return v } func (v value) SlowBlink() Value { v.color = (v.color &^ RapidBlinkFm) | SlowBlinkFm return v } func (v value) RapidBlink() Value { v.color = (v.color &^ SlowBlinkFm) | RapidBlinkFm return v } func (v value) Blink() Value { return v.SlowBlink() } func (v value) Reverse() Value { v.color |= ReverseFm return v } func (v value) Inverse() Value { return v.Reverse() } func (v value) Conceal() Value { v.color |= ConcealFm return v } func (v value) Hidden() Value { return v.Conceal() } func (v value) CrossedOut() Value { v.color |= CrossedOutFm return v } func (v value) StrikeThrough() Value { return v.CrossedOut() } func (v value) Framed() Value { v.color |= FramedFm return v } func (v value) Encircled() Value { v.color |= EncircledFm return v } func (v value) Overlined() Value { v.color |= OverlinedFm return v } func (v value) Black() Value { v.color = (v.color &^ maskFg) | BlackFg return v } func (v value) Red() Value { v.color = (v.color &^ maskFg) | RedFg return v } func (v value) Green() Value { v.color = (v.color &^ maskFg) | GreenFg return v } func (v value) Yellow() Value { v.color = (v.color &^ maskFg) | YellowFg return v } func (v value) Brown() Value { return v.Yellow() } func (v value) Blue() Value { v.color = (v.color &^ maskFg) | BlueFg return v } func (v value) Magenta() Value { v.color = (v.color &^ maskFg) | MagentaFg return v } func (v value) Cyan() Value { v.color = (v.color &^ maskFg) | CyanFg return v } func (v value) White() Value { v.color = (v.color &^ maskFg) | WhiteFg return v } func (v value) BrightBlack() Value { v.color = (v.color &^ maskFg) | BrightFg | BlackFg return v } func (v value) BrightRed() Value { v.color = (v.color &^ maskFg) | BrightFg | RedFg return v } func (v value) BrightGreen() Value { v.color = (v.color &^ maskFg) | BrightFg | GreenFg return v } func (v value) BrightYellow() Value { v.color = (v.color &^ maskFg) | BrightFg | YellowFg return v } func (v value) BrightBlue() Value { v.color = (v.color &^ maskFg) | BrightFg | BlueFg return v } func (v value) BrightMagenta() Value { v.color = (v.color &^ maskFg) | BrightFg | MagentaFg return v } func (v value) BrightCyan() Value { v.color = (v.color &^ maskFg) | BrightFg | CyanFg return v } func (v value) BrightWhite() Value { v.color = (v.color &^ maskFg) | BrightFg | WhiteFg return v } func (v value) Index(n uint8) Value { v.color = (v.color &^ maskFg) | (Color(n) << shiftFg) | flagFg return v } func (v value) Gray(n uint8) Value { if n > 23 { n = 23 } v.color = (v.color &^ maskFg) | (Color(232+n) << shiftFg) | flagFg return v } func (v value) BgBlack() Value { v.color = (v.color &^ maskBg) | BlackBg return v } func (v value) BgRed() Value { v.color = (v.color &^ maskBg) | RedBg return v } func (v value) BgGreen() Value { v.color = (v.color &^ maskBg) | GreenBg return v } func (v value) BgYellow() Value { v.color = (v.color &^ maskBg) | YellowBg return v } func (v value) BgBrown() Value { return v.BgYellow() } func (v value) BgBlue() Value { v.color = (v.color &^ maskBg) | BlueBg return v } func (v value) BgMagenta() Value { v.color = (v.color &^ maskBg) | MagentaBg return v } func (v value) BgCyan() Value { v.color = (v.color &^ maskBg) | CyanBg return v } func (v value) BgWhite() Value { v.color = (v.color &^ maskBg) | WhiteBg return v } func (v value) BgBrightBlack() Value { v.color = (v.color &^ maskBg) | BrightBg | BlackBg return v } func (v value) BgBrightRed() Value { v.color = (v.color &^ maskBg) | BrightBg | RedBg return v } func (v value) BgBrightGreen() Value { v.color = (v.color &^ maskBg) | BrightBg | GreenBg return v } func (v value) BgBrightYellow() Value { v.color = (v.color &^ maskBg) | BrightBg | YellowBg return v } func (v value) BgBrightBlue() Value { v.color = (v.color &^ maskBg) | BrightBg | BlueBg return v } func (v value) BgBrightMagenta() Value { v.color = (v.color &^ maskBg) | BrightBg | MagentaBg return v } func (v value) BgBrightCyan() Value { v.color = (v.color &^ maskBg) | BrightBg | CyanBg return v } func (v value) BgBrightWhite() Value { v.color = (v.color &^ maskBg) | BrightBg | WhiteBg return v } func (v value) BgIndex(n uint8) Value { v.color = (v.color &^ maskBg) | (Color(n) << shiftBg) | flagBg return v } func (v value) BgGray(n uint8) Value { if n > 23 { n = 23 } v.color = (v.color &^ maskBg) | (Color(232+n) << shiftBg) | flagBg return v } func (v value) Colorize(color Color) Value { v.color = color return v }