/strings/ansi/ansi.go

https://gitlab.com/djui/pkg · Go · 354 lines · 248 code · 56 blank · 50 comment · 60 complexity · a5db6359b40db3c1f36be01fbf645221 MD5 · raw file

  1. package ansi
  2. import (
  3. "bytes"
  4. "fmt"
  5. "regexp"
  6. "strconv"
  7. "strings"
  8. )
  9. // Up moves the cursor up n lines.
  10. func Up(n int) string {
  11. if n <= 0 {
  12. panic("invalid argument")
  13. }
  14. return escape(strconv.Itoa(n) + "A")
  15. }
  16. // Down moves the cursor down n lines.
  17. func Down(n int) string {
  18. if n <= 0 {
  19. panic("invalid argument")
  20. }
  21. return escape(strconv.Itoa(n) + "B")
  22. }
  23. // Right moves the cursor right n columns.
  24. func Right(n int) string {
  25. if n <= 0 {
  26. panic("invalid argument")
  27. }
  28. return escape(strconv.Itoa(n) + "C")
  29. }
  30. // Left moves the cursor left n columns.
  31. func Left(n int) string {
  32. if n <= 0 {
  33. panic("invalid argument")
  34. }
  35. return escape(strconv.Itoa(n) + "D")
  36. }
  37. // Cursor moves the cursor to line y, column x. This indexes from the top left
  38. // corner of the screen.
  39. func Cursor(x, y int) string {
  40. if x <= 0 || y <= 0 {
  41. panic("invalid argument")
  42. }
  43. return escape(strconv.Itoa(y) + ";" + strconv.Itoa(x) + "H")
  44. }
  45. // Clear clears the screen and move the cursor to the top left corner.
  46. func Clear() string {
  47. return escape("H\x1B[2J")
  48. }
  49. // Erase erases everything to the left of the cursor on the line the cursor is
  50. // on.
  51. func Erase() string {
  52. return escape("0K")
  53. }
  54. // Reset resets all colours and text styles to the default.
  55. func Reset() string {
  56. return escape("0m")
  57. }
  58. // Bold formats text bold.
  59. func Bold(state bool) string {
  60. if state {
  61. return escape("1m")
  62. }
  63. return escape("22m")
  64. }
  65. // Underline formats text underlined.
  66. func Underline(state bool) string {
  67. if state {
  68. return escape("4m")
  69. }
  70. return escape("24m")
  71. }
  72. // Blink formats text blinking.
  73. func Blink(state bool) string {
  74. if state {
  75. return escape("5m")
  76. }
  77. return escape("25m")
  78. }
  79. // Reverse swaps foreground and background colour.
  80. func Reverse(state bool) string {
  81. if state {
  82. return escape("7m")
  83. }
  84. return escape("27m")
  85. }
  86. // Black colours text black.
  87. func Black() string {
  88. return escape("30m")
  89. }
  90. // Red colours text red.
  91. func Red() string {
  92. return escape("31m")
  93. }
  94. // Green colours text green.
  95. func Green() string {
  96. return escape("32m")
  97. }
  98. // Yellow colours text yellow.
  99. func Yellow() string {
  100. return escape("33m")
  101. }
  102. // Blue colours text blue.
  103. func Blue() string {
  104. return escape("34m")
  105. }
  106. // Magenta colours text magenta.
  107. func Magenta() string {
  108. return escape("35m")
  109. }
  110. // Cyan colours text cyan.
  111. func Cyan() string {
  112. return escape("36m")
  113. }
  114. // Grey colours text grey.
  115. func Grey() string {
  116. return escape("90m")
  117. }
  118. // White colours text white.
  119. func White() string {
  120. return escape("97m")
  121. }
  122. // BrightRed colours text bright red.
  123. func BrightRed() string {
  124. return escape("91m")
  125. }
  126. // BrightGreen colours text bright green.
  127. func BrightGreen() string {
  128. return escape("92m")
  129. }
  130. // BrightYellow colours text bright yellow.
  131. func BrightYellow() string {
  132. return escape("93m")
  133. }
  134. // BrightBlue colours text bright blue.
  135. func BrightBlue() string {
  136. return escape("94m")
  137. }
  138. // BrightMagenta colours text bright magenta.
  139. func BrightMagenta() string {
  140. return escape("95m")
  141. }
  142. // BrightCyan colours text bright cyan.
  143. func BrightCyan() string {
  144. return escape("96m")
  145. }
  146. // BrightGrey colours text bright grey.
  147. func BrightGrey() string {
  148. return escape("37m")
  149. }
  150. // BlackBg colours text in black background.
  151. func BlackBg() string {
  152. return escape("40m")
  153. }
  154. // RedBg colours text in red background.
  155. func RedBg() string {
  156. return escape("41m")
  157. }
  158. // GreenBg colours text in green background.
  159. func GreenBg() string {
  160. return escape("42m")
  161. }
  162. // YellowBg colours text in yellow background.
  163. func YellowBg() string {
  164. return escape("43m")
  165. }
  166. // BlueBg colours text in blue background.
  167. func BlueBg() string {
  168. return escape("44m")
  169. }
  170. // MagentaBg colours text in magenta background.
  171. func MagentaBg() string {
  172. return escape("45m")
  173. }
  174. // CyanBg colours text in cyan background.
  175. func CyanBg() string {
  176. return escape("46m")
  177. }
  178. // GreyBg colours text in grey background.
  179. func GreyBg() string {
  180. return escape("100m")
  181. }
  182. // WhiteBg colours text in white background.
  183. func WhiteBg() string {
  184. return escape("107m")
  185. }
  186. // BrightRedBg colours text in bright red background.
  187. func BrightRedBg() string {
  188. return escape("101m")
  189. }
  190. // BrightGreenBg colours text in bright green background.
  191. func BrightGreenBg() string {
  192. return escape("102m")
  193. }
  194. // BrightYellowBg colours text in bright yellow background.
  195. func BrightYellowBg() string {
  196. return escape("103m")
  197. }
  198. // BrightBlueBg colours text in bright blue background.
  199. func BrightBlueBg() string {
  200. return escape("104m")
  201. }
  202. // BrightMagentaBg colours text in bright magenta background.
  203. func BrightMagentaBg() string {
  204. return escape("105m")
  205. }
  206. // BrightCyanBg colours text in bright cyan background.
  207. func BrightCyanBg() string {
  208. return escape("106m")
  209. }
  210. // BrightGreyBg colours text in bright grey background.
  211. func BrightGreyBg() string {
  212. return escape("47m")
  213. }
  214. // RemoveEscapeSequences removes ANSI escape sequences.
  215. func RemoveEscapeSequences() {
  216. // TODO(uwe): Implement
  217. }
  218. func escape(s string) string {
  219. return "\x1B[" + s
  220. }
  221. // Colors defines the standard HTML colours for ANSI.
  222. var Colors = []string{
  223. "#000000", "#Dd0000", "#00CF12", "#C2CB00", "#3100CA", "#E100C6", "#00CBCB", "#C7C7C7",
  224. "#686868", "#FF5959", "#00FF6B", "#FAFF5C", "#775AFF", "#FF47FE", "#0FFFFF", "#FFFFFF",
  225. }
  226. // ToHTML converts ANSI escape sequences into HTML span tags.
  227. func ToHTML(text []byte) []byte {
  228. re := regexp.MustCompile("\u001B\\[([0-9A-Za-z;]+)m([^\u001B]+)")
  229. matches := re.FindAllSubmatch(text, -1)
  230. if matches == nil {
  231. return text
  232. }
  233. var buf bytes.Buffer
  234. for _, match := range matches {
  235. bg, fg := -1, -1
  236. var bold, underline, negative bool
  237. codes := bytes.Split(match[1], []byte(";"))
  238. for _, c := range codes {
  239. code, _ := strconv.Atoi(string(c))
  240. if code == 0 {
  241. bg, fg = -1, -1
  242. bold, underline, negative = false, false, false
  243. } else if code == 1 {
  244. bold = true
  245. } else if code == 4 {
  246. underline = true
  247. } else if code == 7 {
  248. negative = true
  249. } else if code == 21 {
  250. bold = false
  251. } else if code == 24 {
  252. underline = false
  253. } else if code == 27 {
  254. negative = false
  255. } else if code >= 30 && code <= 37 {
  256. fg = code - 30
  257. } else if code == 39 {
  258. fg = -1
  259. } else if code >= 40 && code <= 47 {
  260. bg = code - 40
  261. } else if code == 49 {
  262. bg = -1
  263. } else if code >= 90 && code <= 97 {
  264. fg = code - 90 + 8
  265. } else if code >= 100 && code <= 107 {
  266. bg = code - 100 + 8
  267. }
  268. }
  269. style := ""
  270. if negative {
  271. fg = bg
  272. bg = fg
  273. }
  274. if bold {
  275. fg = fg | 8
  276. style += "font-weight: bold;"
  277. }
  278. if underline {
  279. style += "text-decoration:underline"
  280. }
  281. if fg >= 0 {
  282. style += fmt.Sprintf("color: %s;", Colors[fg])
  283. }
  284. if bg >= 0 {
  285. style += fmt.Sprintf("background-color: %s;", Colors[bg])
  286. }
  287. html := string(match[2])
  288. html = strings.Replace(html, "&", "&amp;", -1)
  289. html = strings.Replace(html, "<", "&lt;", -1)
  290. html = strings.Replace(html, ">", "&gt;", -1)
  291. if style == "" {
  292. buf.WriteString(html)
  293. } else {
  294. buf.WriteString(fmt.Sprintf(`<span style="%s">%s</span>`, style, html))
  295. }
  296. }
  297. return buf.Bytes()
  298. }