1 package prompt
2
3 import (
4 "bytes"
5 "strconv"
6 )
7
8
9 type VT100Writer struct {
10 buffer []byte
11 }
12
13
14 func (w *VT100Writer) WriteRaw(data []byte) {
15 w.buffer = append(w.buffer, data...)
16 }
17
18
19 func (w *VT100Writer) Write(data []byte) {
20 w.WriteRaw(bytes.Replace(data, []byte{0x1b}, []byte{'?'}, -1))
21 }
22
23
24 func (w *VT100Writer) WriteRawStr(data string) {
25 w.WriteRaw([]byte(data))
26 }
27
28
29 func (w *VT100Writer) WriteStr(data string) {
30 w.Write([]byte(data))
31 }
32
33
34
35
36 func (w *VT100Writer) EraseScreen() {
37 w.WriteRaw([]byte{0x1b, '[', '2', 'J'})
38 }
39
40
41 func (w *VT100Writer) EraseUp() {
42 w.WriteRaw([]byte{0x1b, '[', '1', 'J'})
43 }
44
45
46 func (w *VT100Writer) EraseDown() {
47 w.WriteRaw([]byte{0x1b, '[', 'J'})
48 }
49
50
51 func (w *VT100Writer) EraseStartOfLine() {
52 w.WriteRaw([]byte{0x1b, '[', '1', 'K'})
53 }
54
55
56 func (w *VT100Writer) EraseEndOfLine() {
57 w.WriteRaw([]byte{0x1b, '[', 'K'})
58 }
59
60
61 func (w *VT100Writer) EraseLine() {
62 w.WriteRaw([]byte{0x1b, '[', '2', 'K'})
63 }
64
65
66
67
68 func (w *VT100Writer) ShowCursor() {
69 w.WriteRaw([]byte{0x1b, '[', '?', '1', '2', 'l', 0x1b, '[', '?', '2', '5', 'h'})
70 }
71
72
73 func (w *VT100Writer) HideCursor() {
74 w.WriteRaw([]byte{0x1b, '[', '?', '2', '5', 'l'})
75 }
76
77
78 func (w *VT100Writer) CursorGoTo(row, col int) {
79 if row == 0 && col == 0 {
80
81 w.WriteRaw([]byte{0x1b, '[', 'H'})
82 return
83 }
84 r := strconv.Itoa(row)
85 c := strconv.Itoa(col)
86 w.WriteRaw([]byte{0x1b, '['})
87 w.WriteRaw([]byte(r))
88 w.WriteRaw([]byte{';'})
89 w.WriteRaw([]byte(c))
90 w.WriteRaw([]byte{'H'})
91 }
92
93
94 func (w *VT100Writer) CursorUp(n int) {
95 if n == 0 {
96 return
97 } else if n < 0 {
98 w.CursorDown(-n)
99 return
100 }
101 s := strconv.Itoa(n)
102 w.WriteRaw([]byte{0x1b, '['})
103 w.WriteRaw([]byte(s))
104 w.WriteRaw([]byte{'A'})
105 }
106
107
108 func (w *VT100Writer) CursorDown(n int) {
109 if n == 0 {
110 return
111 } else if n < 0 {
112 w.CursorUp(-n)
113 return
114 }
115 s := strconv.Itoa(n)
116 w.WriteRaw([]byte{0x1b, '['})
117 w.WriteRaw([]byte(s))
118 w.WriteRaw([]byte{'B'})
119 }
120
121
122 func (w *VT100Writer) CursorForward(n int) {
123 if n == 0 {
124 return
125 } else if n < 0 {
126 w.CursorBackward(-n)
127 return
128 }
129 s := strconv.Itoa(n)
130 w.WriteRaw([]byte{0x1b, '['})
131 w.WriteRaw([]byte(s))
132 w.WriteRaw([]byte{'C'})
133 }
134
135
136 func (w *VT100Writer) CursorBackward(n int) {
137 if n == 0 {
138 return
139 } else if n < 0 {
140 w.CursorForward(-n)
141 return
142 }
143 s := strconv.Itoa(n)
144 w.WriteRaw([]byte{0x1b, '['})
145 w.WriteRaw([]byte(s))
146 w.WriteRaw([]byte{'D'})
147 }
148
149
150 func (w *VT100Writer) AskForCPR() {
151
152 w.WriteRaw([]byte{0x1b, '[', '6', 'n'})
153 }
154
155
156 func (w *VT100Writer) SaveCursor() {
157 w.WriteRaw([]byte{0x1b, '[', 's'})
158 }
159
160
161 func (w *VT100Writer) UnSaveCursor() {
162 w.WriteRaw([]byte{0x1b, '[', 'u'})
163 }
164
165
166
167
168 func (w *VT100Writer) ScrollDown() {
169 w.WriteRaw([]byte{0x1b, 'D'})
170 }
171
172
173 func (w *VT100Writer) ScrollUp() {
174 w.WriteRaw([]byte{0x1b, 'M'})
175 }
176
177
178
179
180 func (w *VT100Writer) SetTitle(title string) {
181 titleBytes := []byte(title)
182 patterns := []struct {
183 from []byte
184 to []byte
185 }{
186 {
187 from: []byte{0x13},
188 to: []byte{},
189 },
190 {
191 from: []byte{0x07},
192 to: []byte{},
193 },
194 }
195 for i := range patterns {
196 titleBytes = bytes.Replace(titleBytes, patterns[i].from, patterns[i].to, -1)
197 }
198
199 w.WriteRaw([]byte{0x1b, ']', '2', ';'})
200 w.WriteRaw(titleBytes)
201 w.WriteRaw([]byte{0x07})
202 }
203
204
205 func (w *VT100Writer) ClearTitle() {
206 w.WriteRaw([]byte{0x1b, ']', '2', ';', 0x07})
207 }
208
209
210
211
212 func (w *VT100Writer) SetColor(fg, bg Color, bold bool) {
213 if bold {
214 w.SetDisplayAttributes(fg, bg, DisplayBold)
215 } else {
216
217
218 w.SetDisplayAttributes(fg, bg, DisplayReset)
219 }
220 }
221
222
223 func (w *VT100Writer) SetDisplayAttributes(fg, bg Color, attrs ...DisplayAttribute) {
224 w.WriteRaw([]byte{0x1b, '['})
225 defer w.WriteRaw([]byte{'m'})
226
227 var separator byte = ';'
228 for i := range attrs {
229 p, ok := displayAttributeParameters[attrs[i]]
230 if !ok {
231 continue
232 }
233 w.WriteRaw(p)
234 w.WriteRaw([]byte{separator})
235 }
236
237 f, ok := foregroundANSIColors[fg]
238 if !ok {
239 f = foregroundANSIColors[DefaultColor]
240 }
241 w.WriteRaw(f)
242 w.WriteRaw([]byte{separator})
243 b, ok := backgroundANSIColors[bg]
244 if !ok {
245 b = backgroundANSIColors[DefaultColor]
246 }
247 w.WriteRaw(b)
248 }
249
250 var displayAttributeParameters = map[DisplayAttribute][]byte{
251 DisplayReset: {'0'},
252 DisplayBold: {'1'},
253 DisplayLowIntensity: {'2'},
254 DisplayItalic: {'3'},
255 DisplayUnderline: {'4'},
256 DisplayBlink: {'5'},
257 DisplayRapidBlink: {'6'},
258 DisplayReverse: {'7'},
259 DisplayInvisible: {'8'},
260 DisplayCrossedOut: {'9'},
261 DisplayDefaultFont: {'1', '0'},
262 }
263
264 var foregroundANSIColors = map[Color][]byte{
265 DefaultColor: {'3', '9'},
266
267
268 Black: {'3', '0'},
269 DarkRed: {'3', '1'},
270 DarkGreen: {'3', '2'},
271 Brown: {'3', '3'},
272 DarkBlue: {'3', '4'},
273 Purple: {'3', '5'},
274 Cyan: {'3', '6'},
275 LightGray: {'3', '7'},
276
277
278 DarkGray: {'9', '0'},
279 Red: {'9', '1'},
280 Green: {'9', '2'},
281 Yellow: {'9', '3'},
282 Blue: {'9', '4'},
283 Fuchsia: {'9', '5'},
284 Turquoise: {'9', '6'},
285 White: {'9', '7'},
286 }
287
288 var backgroundANSIColors = map[Color][]byte{
289 DefaultColor: {'4', '9'},
290
291
292 Black: {'4', '0'},
293 DarkRed: {'4', '1'},
294 DarkGreen: {'4', '2'},
295 Brown: {'4', '3'},
296 DarkBlue: {'4', '4'},
297 Purple: {'4', '5'},
298 Cyan: {'4', '6'},
299 LightGray: {'4', '7'},
300
301
302 DarkGray: {'1', '0', '0'},
303 Red: {'1', '0', '1'},
304 Green: {'1', '0', '2'},
305 Yellow: {'1', '0', '3'},
306 Blue: {'1', '0', '4'},
307 Fuchsia: {'1', '0', '5'},
308 Turquoise: {'1', '0', '6'},
309 White: {'1', '0', '7'},
310 }
311
View as plain text