output_vt100.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. package prompt
  2. import (
  3. "bytes"
  4. "strconv"
  5. )
  6. // VT100Writer generates VT100 escape sequences.
  7. type VT100Writer struct {
  8. buffer []byte
  9. }
  10. // WriteRaw to write raw byte array
  11. func (w *VT100Writer) WriteRaw(data []byte) {
  12. w.buffer = append(w.buffer, data...)
  13. }
  14. // Write to write safety byte array by removing control sequences.
  15. func (w *VT100Writer) Write(data []byte) {
  16. w.WriteRaw(bytes.Replace(data, []byte{0x1b}, []byte{'?'}, -1))
  17. }
  18. // WriteRawStr to write raw string
  19. func (w *VT100Writer) WriteRawStr(data string) {
  20. w.WriteRaw([]byte(data))
  21. }
  22. // WriteStr to write safety string by removing control sequences.
  23. func (w *VT100Writer) WriteStr(data string) {
  24. w.Write([]byte(data))
  25. }
  26. /* Erase */
  27. // EraseScreen erases the screen with the background colour and moves the cursor to home.
  28. func (w *VT100Writer) EraseScreen() {
  29. w.WriteRaw([]byte{0x1b, '[', '2', 'J'})
  30. }
  31. // EraseUp erases the screen from the current line up to the top of the screen.
  32. func (w *VT100Writer) EraseUp() {
  33. w.WriteRaw([]byte{0x1b, '[', '1', 'J'})
  34. }
  35. // EraseDown erases the screen from the current line down to the bottom of the screen.
  36. func (w *VT100Writer) EraseDown() {
  37. w.WriteRaw([]byte{0x1b, '[', 'J'})
  38. }
  39. // EraseStartOfLine erases from the current cursor position to the start of the current line.
  40. func (w *VT100Writer) EraseStartOfLine() {
  41. w.WriteRaw([]byte{0x1b, '[', '1', 'K'})
  42. }
  43. // EraseEndOfLine erases from the current cursor position to the end of the current line.
  44. func (w *VT100Writer) EraseEndOfLine() {
  45. w.WriteRaw([]byte{0x1b, '[', 'K'})
  46. }
  47. // EraseLine erases the entire current line.
  48. func (w *VT100Writer) EraseLine() {
  49. w.WriteRaw([]byte{0x1b, '[', '2', 'K'})
  50. }
  51. /* Cursor */
  52. // ShowCursor stops blinking cursor and show.
  53. func (w *VT100Writer) ShowCursor() {
  54. w.WriteRaw([]byte{0x1b, '[', '?', '1', '2', 'l', 0x1b, '[', '?', '2', '5', 'h'})
  55. }
  56. // HideCursor hides cursor.
  57. func (w *VT100Writer) HideCursor() {
  58. w.WriteRaw([]byte{0x1b, '[', '?', '2', '5', 'l'})
  59. }
  60. // CursorGoTo sets the cursor position where subsequent text will begin.
  61. func (w *VT100Writer) CursorGoTo(row, col int) {
  62. if row == 0 && col == 0 {
  63. // If no row/column parameters are provided (ie. <ESC>[H), the cursor will move to the home position.
  64. w.WriteRaw([]byte{0x1b, '[', 'H'})
  65. return
  66. }
  67. r := strconv.Itoa(row)
  68. c := strconv.Itoa(col)
  69. w.WriteRaw([]byte{0x1b, '['})
  70. w.WriteRaw([]byte(r))
  71. w.WriteRaw([]byte{';'})
  72. w.WriteRaw([]byte(c))
  73. w.WriteRaw([]byte{'H'})
  74. }
  75. // CursorUp moves the cursor up by 'n' rows; the default count is 1.
  76. func (w *VT100Writer) CursorUp(n int) {
  77. if n == 0 {
  78. return
  79. } else if n < 0 {
  80. w.CursorDown(-n)
  81. return
  82. }
  83. s := strconv.Itoa(n)
  84. w.WriteRaw([]byte{0x1b, '['})
  85. w.WriteRaw([]byte(s))
  86. w.WriteRaw([]byte{'A'})
  87. }
  88. // CursorDown moves the cursor down by 'n' rows; the default count is 1.
  89. func (w *VT100Writer) CursorDown(n int) {
  90. if n == 0 {
  91. return
  92. } else if n < 0 {
  93. w.CursorUp(-n)
  94. return
  95. }
  96. s := strconv.Itoa(n)
  97. w.WriteRaw([]byte{0x1b, '['})
  98. w.WriteRaw([]byte(s))
  99. w.WriteRaw([]byte{'B'})
  100. }
  101. // CursorForward moves the cursor forward by 'n' columns; the default count is 1.
  102. func (w *VT100Writer) CursorForward(n int) {
  103. if n == 0 {
  104. return
  105. } else if n < 0 {
  106. w.CursorBackward(-n)
  107. return
  108. }
  109. s := strconv.Itoa(n)
  110. w.WriteRaw([]byte{0x1b, '['})
  111. w.WriteRaw([]byte(s))
  112. w.WriteRaw([]byte{'C'})
  113. }
  114. // CursorBackward moves the cursor backward by 'n' columns; the default count is 1.
  115. func (w *VT100Writer) CursorBackward(n int) {
  116. if n == 0 {
  117. return
  118. } else if n < 0 {
  119. w.CursorForward(-n)
  120. return
  121. }
  122. s := strconv.Itoa(n)
  123. w.WriteRaw([]byte{0x1b, '['})
  124. w.WriteRaw([]byte(s))
  125. w.WriteRaw([]byte{'D'})
  126. }
  127. // AskForCPR asks for a cursor position report (CPR).
  128. func (w *VT100Writer) AskForCPR() {
  129. // CPR: Cursor Position Request.
  130. w.WriteRaw([]byte{0x1b, '[', '6', 'n'})
  131. }
  132. // SaveCursor saves current cursor position.
  133. func (w *VT100Writer) SaveCursor() {
  134. w.WriteRaw([]byte{0x1b, '[', 's'})
  135. }
  136. // UnSaveCursor restores cursor position after a Save Cursor.
  137. func (w *VT100Writer) UnSaveCursor() {
  138. w.WriteRaw([]byte{0x1b, '[', 'u'})
  139. }
  140. /* Scrolling */
  141. // ScrollDown scrolls display down one line.
  142. func (w *VT100Writer) ScrollDown() {
  143. w.WriteRaw([]byte{0x1b, 'D'})
  144. }
  145. // ScrollUp scroll display up one line.
  146. func (w *VT100Writer) ScrollUp() {
  147. w.WriteRaw([]byte{0x1b, 'M'})
  148. }
  149. /* Title */
  150. // SetTitle sets a title of terminal window.
  151. func (w *VT100Writer) SetTitle(title string) {
  152. titleBytes := []byte(title)
  153. patterns := []struct {
  154. from []byte
  155. to []byte
  156. }{
  157. {
  158. from: []byte{0x13},
  159. to: []byte{},
  160. },
  161. {
  162. from: []byte{0x07},
  163. to: []byte{},
  164. },
  165. }
  166. for i := range patterns {
  167. titleBytes = bytes.Replace(titleBytes, patterns[i].from, patterns[i].to, -1)
  168. }
  169. w.WriteRaw([]byte{0x1b, ']', '2', ';'})
  170. w.WriteRaw(titleBytes)
  171. w.WriteRaw([]byte{0x07})
  172. }
  173. // ClearTitle clears a title of terminal window.
  174. func (w *VT100Writer) ClearTitle() {
  175. w.WriteRaw([]byte{0x1b, ']', '2', ';', 0x07})
  176. }
  177. /* Font */
  178. // SetColor sets text and background colors. and specify whether text is bold.
  179. func (w *VT100Writer) SetColor(fg, bg Color, bold bool) {
  180. if bold {
  181. w.SetDisplayAttributes(fg, bg, DisplayBold)
  182. } else {
  183. // If using `DisplayDefualt`, it will be broken in some environment.
  184. // Details are https://github.com/c-bata/go-prompt/pull/85
  185. w.SetDisplayAttributes(fg, bg, DisplayReset)
  186. }
  187. }
  188. // SetDisplayAttributes to set VT100 display attributes.
  189. func (w *VT100Writer) SetDisplayAttributes(fg, bg Color, attrs ...DisplayAttribute) {
  190. w.WriteRaw([]byte{0x1b, '['}) // control sequence introducer
  191. defer w.WriteRaw([]byte{'m'}) // final character
  192. var separator byte = ';'
  193. for i := range attrs {
  194. p, ok := displayAttributeParameters[attrs[i]]
  195. if !ok {
  196. continue
  197. }
  198. w.WriteRaw(p)
  199. w.WriteRaw([]byte{separator})
  200. }
  201. f, ok := foregroundANSIColors[fg]
  202. if !ok {
  203. f = foregroundANSIColors[DefaultColor]
  204. }
  205. w.WriteRaw(f)
  206. w.WriteRaw([]byte{separator})
  207. b, ok := backgroundANSIColors[bg]
  208. if !ok {
  209. b = backgroundANSIColors[DefaultColor]
  210. }
  211. w.WriteRaw(b)
  212. }
  213. var displayAttributeParameters = map[DisplayAttribute][]byte{
  214. DisplayReset: {'0'},
  215. DisplayBold: {'1'},
  216. DisplayLowIntensity: {'2'},
  217. DisplayItalic: {'3'},
  218. DisplayUnderline: {'4'},
  219. DisplayBlink: {'5'},
  220. DisplayRapidBlink: {'6'},
  221. DisplayReverse: {'7'},
  222. DisplayInvisible: {'8'},
  223. DisplayCrossedOut: {'9'},
  224. DisplayDefaultFont: {'1', '0'},
  225. }
  226. var foregroundANSIColors = map[Color][]byte{
  227. DefaultColor: {'3', '9'},
  228. // Low intensity.
  229. Black: {'3', '0'},
  230. DarkRed: {'3', '1'},
  231. DarkGreen: {'3', '2'},
  232. Brown: {'3', '3'},
  233. DarkBlue: {'3', '4'},
  234. Purple: {'3', '5'},
  235. Cyan: {'3', '6'},
  236. LightGray: {'3', '7'},
  237. // High intensity.
  238. DarkGray: {'9', '0'},
  239. Red: {'9', '1'},
  240. Green: {'9', '2'},
  241. Yellow: {'9', '3'},
  242. Blue: {'9', '4'},
  243. Fuchsia: {'9', '5'},
  244. Turquoise: {'9', '6'},
  245. White: {'9', '7'},
  246. }
  247. var backgroundANSIColors = map[Color][]byte{
  248. DefaultColor: {'4', '9'},
  249. // Low intensity.
  250. Black: {'4', '0'},
  251. DarkRed: {'4', '1'},
  252. DarkGreen: {'4', '2'},
  253. Brown: {'4', '3'},
  254. DarkBlue: {'4', '4'},
  255. Purple: {'4', '5'},
  256. Cyan: {'4', '6'},
  257. LightGray: {'4', '7'},
  258. // High intensity
  259. DarkGray: {'1', '0', '0'},
  260. Red: {'1', '0', '1'},
  261. Green: {'1', '0', '2'},
  262. Yellow: {'1', '0', '3'},
  263. Blue: {'1', '0', '4'},
  264. Fuchsia: {'1', '0', '5'},
  265. Turquoise: {'1', '0', '6'},
  266. White: {'1', '0', '7'},
  267. }