style.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. package ansi
  2. import (
  3. "image/color"
  4. "strconv"
  5. "strings"
  6. )
  7. // ResetStyle is a SGR (Select Graphic Rendition) style sequence that resets
  8. // all attributes.
  9. // See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
  10. const ResetStyle = "\x1b[m"
  11. // Attr is a SGR (Select Graphic Rendition) style attribute.
  12. type Attr = string
  13. // Style represents an ANSI SGR (Select Graphic Rendition) style.
  14. type Style []Attr
  15. // String returns the ANSI SGR (Select Graphic Rendition) style sequence for
  16. // the given style.
  17. func (s Style) String() string {
  18. if len(s) == 0 {
  19. return ResetStyle
  20. }
  21. return "\x1b[" + strings.Join(s, ";") + "m"
  22. }
  23. // Styled returns a styled string with the given style applied.
  24. func (s Style) Styled(str string) string {
  25. if len(s) == 0 {
  26. return str
  27. }
  28. return s.String() + str + ResetStyle
  29. }
  30. // Reset appends the reset style attribute to the style.
  31. func (s Style) Reset() Style {
  32. return append(s, ResetAttr)
  33. }
  34. // Bold appends the bold style attribute to the style.
  35. func (s Style) Bold() Style {
  36. return append(s, BoldAttr)
  37. }
  38. // Faint appends the faint style attribute to the style.
  39. func (s Style) Faint() Style {
  40. return append(s, FaintAttr)
  41. }
  42. // Italic appends the italic style attribute to the style.
  43. func (s Style) Italic() Style {
  44. return append(s, ItalicAttr)
  45. }
  46. // Underline appends the underline style attribute to the style.
  47. func (s Style) Underline() Style {
  48. return append(s, UnderlineAttr)
  49. }
  50. // DoubleUnderline appends the double underline style attribute to the style.
  51. func (s Style) DoubleUnderline() Style {
  52. return append(s, DoubleUnderlineAttr)
  53. }
  54. // CurlyUnderline appends the curly underline style attribute to the style.
  55. func (s Style) CurlyUnderline() Style {
  56. return append(s, CurlyUnderlineAttr)
  57. }
  58. // DottedUnderline appends the dotted underline style attribute to the style.
  59. func (s Style) DottedUnderline() Style {
  60. return append(s, DottedUnderlineAttr)
  61. }
  62. // DashedUnderline appends the dashed underline style attribute to the style.
  63. func (s Style) DashedUnderline() Style {
  64. return append(s, DashedUnderlineAttr)
  65. }
  66. // SlowBlink appends the slow blink style attribute to the style.
  67. func (s Style) SlowBlink() Style {
  68. return append(s, SlowBlinkAttr)
  69. }
  70. // RapidBlink appends the rapid blink style attribute to the style.
  71. func (s Style) RapidBlink() Style {
  72. return append(s, RapidBlinkAttr)
  73. }
  74. // Reverse appends the reverse style attribute to the style.
  75. func (s Style) Reverse() Style {
  76. return append(s, ReverseAttr)
  77. }
  78. // Conceal appends the conceal style attribute to the style.
  79. func (s Style) Conceal() Style {
  80. return append(s, ConcealAttr)
  81. }
  82. // Strikethrough appends the strikethrough style attribute to the style.
  83. func (s Style) Strikethrough() Style {
  84. return append(s, StrikethroughAttr)
  85. }
  86. // NoBold appends the no bold style attribute to the style.
  87. func (s Style) NoBold() Style {
  88. return append(s, NoBoldAttr)
  89. }
  90. // NormalIntensity appends the normal intensity style attribute to the style.
  91. func (s Style) NormalIntensity() Style {
  92. return append(s, NormalIntensityAttr)
  93. }
  94. // NoItalic appends the no italic style attribute to the style.
  95. func (s Style) NoItalic() Style {
  96. return append(s, NoItalicAttr)
  97. }
  98. // NoUnderline appends the no underline style attribute to the style.
  99. func (s Style) NoUnderline() Style {
  100. return append(s, NoUnderlineAttr)
  101. }
  102. // NoBlink appends the no blink style attribute to the style.
  103. func (s Style) NoBlink() Style {
  104. return append(s, NoBlinkAttr)
  105. }
  106. // NoReverse appends the no reverse style attribute to the style.
  107. func (s Style) NoReverse() Style {
  108. return append(s, NoReverseAttr)
  109. }
  110. // NoConceal appends the no conceal style attribute to the style.
  111. func (s Style) NoConceal() Style {
  112. return append(s, NoConcealAttr)
  113. }
  114. // NoStrikethrough appends the no strikethrough style attribute to the style.
  115. func (s Style) NoStrikethrough() Style {
  116. return append(s, NoStrikethroughAttr)
  117. }
  118. // DefaultForegroundColor appends the default foreground color style attribute to the style.
  119. func (s Style) DefaultForegroundColor() Style {
  120. return append(s, DefaultForegroundColorAttr)
  121. }
  122. // DefaultBackgroundColor appends the default background color style attribute to the style.
  123. func (s Style) DefaultBackgroundColor() Style {
  124. return append(s, DefaultBackgroundColorAttr)
  125. }
  126. // DefaultUnderlineColor appends the default underline color style attribute to the style.
  127. func (s Style) DefaultUnderlineColor() Style {
  128. return append(s, DefaultUnderlineColorAttr)
  129. }
  130. // ForegroundColor appends the foreground color style attribute to the style.
  131. func (s Style) ForegroundColor(c Color) Style {
  132. return append(s, ForegroundColorAttr(c))
  133. }
  134. // BackgroundColor appends the background color style attribute to the style.
  135. func (s Style) BackgroundColor(c Color) Style {
  136. return append(s, BackgroundColorAttr(c))
  137. }
  138. // UnderlineColor appends the underline color style attribute to the style.
  139. func (s Style) UnderlineColor(c Color) Style {
  140. return append(s, UnderlineColorAttr(c))
  141. }
  142. // SGR (Select Graphic Rendition) style attributes.
  143. // See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
  144. const (
  145. ResetAttr Attr = "0"
  146. BoldAttr Attr = "1"
  147. FaintAttr Attr = "2"
  148. ItalicAttr Attr = "3"
  149. UnderlineAttr Attr = "4"
  150. DoubleUnderlineAttr Attr = "4:2"
  151. CurlyUnderlineAttr Attr = "4:3"
  152. DottedUnderlineAttr Attr = "4:4"
  153. DashedUnderlineAttr Attr = "4:5"
  154. SlowBlinkAttr Attr = "5"
  155. RapidBlinkAttr Attr = "6"
  156. ReverseAttr Attr = "7"
  157. ConcealAttr Attr = "8"
  158. StrikethroughAttr Attr = "9"
  159. NoBoldAttr Attr = "21" // Some terminals treat this as double underline.
  160. NormalIntensityAttr Attr = "22"
  161. NoItalicAttr Attr = "23"
  162. NoUnderlineAttr Attr = "24"
  163. NoBlinkAttr Attr = "25"
  164. NoReverseAttr Attr = "27"
  165. NoConcealAttr Attr = "28"
  166. NoStrikethroughAttr Attr = "29"
  167. DefaultForegroundColorAttr Attr = "39"
  168. DefaultBackgroundColorAttr Attr = "49"
  169. DefaultUnderlineColorAttr Attr = "59"
  170. )
  171. // ForegroundColorAttr returns the style SGR attribute for the given foreground
  172. // color.
  173. // See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
  174. func ForegroundColorAttr(c Color) Attr {
  175. switch c := c.(type) {
  176. case BasicColor:
  177. // 3-bit or 4-bit ANSI foreground
  178. // "3<n>" or "9<n>" where n is the color number from 0 to 7
  179. if c < 8 {
  180. return "3" + string('0'+c)
  181. } else if c < 16 {
  182. return "9" + string('0'+c-8)
  183. }
  184. case ExtendedColor:
  185. // 256-color ANSI foreground
  186. // "38;5;<n>"
  187. return "38;5;" + strconv.FormatUint(uint64(c), 10)
  188. case TrueColor, color.Color:
  189. // 24-bit "true color" foreground
  190. // "38;2;<r>;<g>;<b>"
  191. r, g, b, _ := c.RGBA()
  192. return "38;2;" +
  193. strconv.FormatUint(uint64(shift(r)), 10) + ";" +
  194. strconv.FormatUint(uint64(shift(g)), 10) + ";" +
  195. strconv.FormatUint(uint64(shift(b)), 10)
  196. }
  197. return DefaultForegroundColorAttr
  198. }
  199. // BackgroundColorAttr returns the style SGR attribute for the given background
  200. // color.
  201. // See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
  202. func BackgroundColorAttr(c Color) Attr {
  203. switch c := c.(type) {
  204. case BasicColor:
  205. // 3-bit or 4-bit ANSI foreground
  206. // "4<n>" or "10<n>" where n is the color number from 0 to 7
  207. if c < 8 {
  208. return "4" + string('0'+c)
  209. } else {
  210. return "10" + string('0'+c-8)
  211. }
  212. case ExtendedColor:
  213. // 256-color ANSI foreground
  214. // "48;5;<n>"
  215. return "48;5;" + strconv.FormatUint(uint64(c), 10)
  216. case TrueColor, color.Color:
  217. // 24-bit "true color" foreground
  218. // "38;2;<r>;<g>;<b>"
  219. r, g, b, _ := c.RGBA()
  220. return "48;2;" +
  221. strconv.FormatUint(uint64(shift(r)), 10) + ";" +
  222. strconv.FormatUint(uint64(shift(g)), 10) + ";" +
  223. strconv.FormatUint(uint64(shift(b)), 10)
  224. }
  225. return DefaultBackgroundColorAttr
  226. }
  227. // UnderlineColorAttr returns the style SGR attribute for the given underline
  228. // color.
  229. // See: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
  230. func UnderlineColorAttr(c Color) Attr {
  231. switch c := c.(type) {
  232. // NOTE: we can't use 3-bit and 4-bit ANSI color codes with underline
  233. // color, use 256-color instead.
  234. //
  235. // 256-color ANSI underline color
  236. // "58;5;<n>"
  237. case BasicColor:
  238. return "58;5;" + strconv.FormatUint(uint64(c), 10)
  239. case ExtendedColor:
  240. return "58;5;" + strconv.FormatUint(uint64(c), 10)
  241. case TrueColor, color.Color:
  242. // 24-bit "true color" foreground
  243. // "38;2;<r>;<g>;<b>"
  244. r, g, b, _ := c.RGBA()
  245. return "58;2;" +
  246. strconv.FormatUint(uint64(shift(r)), 10) + ";" +
  247. strconv.FormatUint(uint64(shift(g)), 10) + ";" +
  248. strconv.FormatUint(uint64(shift(b)), 10)
  249. }
  250. return DefaultUnderlineColorAttr
  251. }
  252. func shift(v uint32) uint32 {
  253. if v > 0xff {
  254. return v >> 8
  255. }
  256. return v
  257. }