Skip to content

Commit 2f58d53

Browse files
committed
Separate VT100 writer
1 parent de18dfb commit 2f58d53

File tree

5 files changed

+351
-630
lines changed

5 files changed

+351
-630
lines changed

console_interface.go

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ type WinSize struct {
66
Col uint16
77
}
88

9+
// DisplayAttribute represents display attributes like Blinking, Bold, Italic and so on.
910
type DisplayAttribute int
1011

1112
const (
@@ -163,5 +164,8 @@ type ConsoleWriter interface {
163164
/* Font */
164165

165166
// SetColor sets text and background colors. and specify whether text is bold.
167+
// Deprecated. This interface is not cool, please use SetDisplayAttributes.
166168
SetColor(fg, bg Color, bold bool)
169+
// SetDisplayAttributes set display attributes (Set colors, blink, bold, italic and so on).
170+
SetDisplayAttributes(fg, bg Color, attrs ...DisplayAttribute)
167171
}

output_posix.go

+4-328
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,14 @@
33
package prompt
44

55
import (
6-
"bytes"
7-
"strconv"
86
"syscall"
97
)
108

119
// PosixWriter is a ConsoleWriter implementation for POSIX environment.
1210
// To control terminal emulator, this outputs VT100 escape sequences.
1311
type PosixWriter struct {
14-
fd int
15-
buffer []byte
16-
}
17-
18-
// WriteRaw to write raw byte array
19-
func (w *PosixWriter) WriteRaw(data []byte) {
20-
w.buffer = append(w.buffer, data...)
21-
return
22-
}
23-
24-
// Write to write safety byte array by removing control sequences.
25-
func (w *PosixWriter) Write(data []byte) {
26-
w.WriteRaw(bytes.Replace(data, []byte{0x1b}, []byte{'?'}, -1))
27-
return
28-
}
29-
30-
// WriteRawStr to write raw string
31-
func (w *PosixWriter) WriteRawStr(data string) {
32-
w.WriteRaw([]byte(data))
33-
return
34-
}
35-
36-
// WriteStr to write safety string by removing control sequences.
37-
func (w *PosixWriter) WriteStr(data string) {
38-
w.Write([]byte(data))
39-
return
12+
VT100Writer
13+
fd int
4014
}
4115

4216
// Flush to flush buffer
@@ -49,309 +23,11 @@ func (w *PosixWriter) Flush() error {
4923
return nil
5024
}
5125

52-
/* Erase */
53-
54-
// EraseScreen erases the screen with the background colour and moves the cursor to home.
55-
func (w *PosixWriter) EraseScreen() {
56-
w.WriteRaw([]byte{0x1b, '[', '2', 'J'})
57-
return
58-
}
59-
60-
// EraseUp erases the screen from the current line up to the top of the screen.
61-
func (w *PosixWriter) EraseUp() {
62-
w.WriteRaw([]byte{0x1b, '[', '2', 'J'})
63-
return
64-
}
65-
66-
// EraseDown erases the screen from the current line down to the bottom of the screen.
67-
func (w *PosixWriter) EraseDown() {
68-
w.WriteRaw([]byte{0x1b, '[', 'J'})
69-
return
70-
}
71-
72-
// EraseStartOfLine erases from the current cursor position to the start of the current line.
73-
func (w *PosixWriter) EraseStartOfLine() {
74-
w.WriteRaw([]byte{0x1b, '[', '1', 'K'})
75-
return
76-
}
77-
78-
// EraseEndOfLine erases from the current cursor position to the end of the current line.
79-
func (w *PosixWriter) EraseEndOfLine() {
80-
w.WriteRaw([]byte{0x1b, '[', 'K'})
81-
return
82-
}
83-
84-
// EraseLine erases the entire current line.
85-
func (w *PosixWriter) EraseLine() {
86-
w.WriteRaw([]byte{0x1b, '[', '2', 'K'})
87-
return
88-
}
89-
90-
/* Cursor */
91-
92-
// ShowCursor stops blinking cursor and show.
93-
func (w *PosixWriter) ShowCursor() {
94-
w.WriteRaw([]byte{0x1b, '[', '?', '1', '2', 'l', 0x1b, '[', '?', '2', '5', 'h'})
95-
}
96-
97-
// HideCursor hides cursor.
98-
func (w *PosixWriter) HideCursor() {
99-
w.WriteRaw([]byte{0x1b, '[', '?', '2', '5', 'l'})
100-
return
101-
}
102-
103-
// CursorGoTo sets the cursor position where subsequent text will begin.
104-
func (w *PosixWriter) CursorGoTo(row, col int) {
105-
if row == 0 && col == 0 {
106-
// If no row/column parameters are provided (ie. <ESC>[H), the cursor will move to the home position.
107-
w.WriteRaw([]byte{0x1b, '[', 'H'})
108-
return
109-
}
110-
r := strconv.Itoa(row)
111-
c := strconv.Itoa(col)
112-
w.WriteRaw([]byte{0x1b, '['})
113-
w.WriteRaw([]byte(r))
114-
w.WriteRaw([]byte{';'})
115-
w.WriteRaw([]byte(c))
116-
w.WriteRaw([]byte{'H'})
117-
return
118-
}
119-
120-
// CursorUp moves the cursor up by 'n' rows; the default count is 1.
121-
func (w *PosixWriter) CursorUp(n int) {
122-
if n == 0 {
123-
return
124-
} else if n < 0 {
125-
w.CursorDown(-n)
126-
return
127-
}
128-
s := strconv.Itoa(n)
129-
w.WriteRaw([]byte{0x1b, '['})
130-
w.WriteRaw([]byte(s))
131-
w.WriteRaw([]byte{'A'})
132-
return
133-
}
134-
135-
// CursorDown moves the cursor down by 'n' rows; the default count is 1.
136-
func (w *PosixWriter) CursorDown(n int) {
137-
if n == 0 {
138-
return
139-
} else if n < 0 {
140-
w.CursorUp(-n)
141-
return
142-
}
143-
s := strconv.Itoa(n)
144-
w.WriteRaw([]byte{0x1b, '['})
145-
w.WriteRaw([]byte(s))
146-
w.WriteRaw([]byte{'B'})
147-
return
148-
}
149-
150-
// CursorForward moves the cursor forward by 'n' columns; the default count is 1.
151-
func (w *PosixWriter) CursorForward(n int) {
152-
if n == 0 {
153-
return
154-
} else if n < 0 {
155-
w.CursorBackward(-n)
156-
return
157-
}
158-
s := strconv.Itoa(n)
159-
w.WriteRaw([]byte{0x1b, '['})
160-
w.WriteRaw([]byte(s))
161-
w.WriteRaw([]byte{'C'})
162-
return
163-
}
164-
165-
// CursorBackward moves the cursor backward by 'n' columns; the default count is 1.
166-
func (w *PosixWriter) CursorBackward(n int) {
167-
if n == 0 {
168-
return
169-
} else if n < 0 {
170-
w.CursorForward(-n)
171-
return
172-
}
173-
s := strconv.Itoa(n)
174-
w.WriteRaw([]byte{0x1b, '['})
175-
w.WriteRaw([]byte(s))
176-
w.WriteRaw([]byte{'D'})
177-
return
178-
}
179-
180-
// AskForCPR asks for a cursor position report (CPR).
181-
func (w *PosixWriter) AskForCPR() {
182-
// CPR: Cursor Position Request.
183-
w.WriteRaw([]byte{0x1b, '[', '6', 'n'})
184-
w.Flush()
185-
return
186-
}
187-
188-
// SaveCursor saves current cursor position.
189-
func (w *PosixWriter) SaveCursor() {
190-
w.WriteRaw([]byte{0x1b, '[', 's'})
191-
return
192-
}
193-
194-
// UnSaveCursor restores cursor position after a Save Cursor.
195-
func (w *PosixWriter) UnSaveCursor() {
196-
w.WriteRaw([]byte{0x1b, '[', 'u'})
197-
return
198-
}
199-
200-
/* Scrolling */
201-
202-
// ScrollDown scrolls display down one line.
203-
func (w *PosixWriter) ScrollDown() {
204-
w.WriteRaw([]byte{0x1b, 'D'})
205-
return
206-
}
207-
208-
// ScrollUp scroll display up one line.
209-
func (w *PosixWriter) ScrollUp() {
210-
w.WriteRaw([]byte{0x1b, 'M'})
211-
return
212-
}
213-
214-
/* Title */
215-
216-
// SetTitle sets a title of terminal window.
217-
func (w *PosixWriter) SetTitle(title string) {
218-
titleBytes := []byte(title)
219-
patterns := []struct {
220-
from []byte
221-
to []byte
222-
}{
223-
{
224-
from: []byte{0x13},
225-
to: []byte{},
226-
},
227-
{
228-
from: []byte{0x07},
229-
to: []byte{},
230-
},
231-
}
232-
for i := range patterns {
233-
titleBytes = bytes.Replace(titleBytes, patterns[i].from, patterns[i].to, -1)
234-
}
235-
236-
w.WriteRaw([]byte{0x1b, ']', '2', ';'})
237-
w.WriteRaw(titleBytes)
238-
w.WriteRaw([]byte{0x07})
239-
return
240-
}
241-
242-
// ClearTitle clears a title of terminal window.
243-
func (w *PosixWriter) ClearTitle() {
244-
w.WriteRaw([]byte{0x1b, ']', '2', ';', 0x07})
245-
return
246-
}
247-
248-
/* Font */
249-
250-
// SetColor sets text and background colors. and specify whether text is bold.
251-
// Deprecated. This interface is not cool, please use SetDisplayAttributes.
252-
func (w *PosixWriter) SetColor(fg, bg Color, bold bool) {
253-
if bold {
254-
w.SetDisplayAttributes(fg, bg, DisplayBold)
255-
} else {
256-
w.SetDisplayAttributes(fg, bg, DisplayDefaultFont)
257-
}
258-
return
259-
}
260-
261-
// SetDisplayAttributes set display attributes (Set colors, blink, bold, italic and so on).
262-
func (w *PosixWriter) SetDisplayAttributes(fg, bg Color, attrs ...DisplayAttribute) {
263-
w.WriteRaw([]byte{0x1b, '['}) // control sequence introducer
264-
defer w.WriteRaw([]byte{'m'}) // final character
265-
266-
var separator byte = ';'
267-
for i := range attrs {
268-
p, ok := displayAttributeParameters[attrs[i]]
269-
if !ok {
270-
continue
271-
}
272-
w.WriteRaw(p)
273-
w.WriteRaw([]byte{separator})
274-
}
275-
276-
f, ok := foregroundANSIColors[fg]
277-
if !ok {
278-
f = foregroundANSIColors[DefaultColor]
279-
}
280-
w.WriteRaw(f)
281-
w.WriteRaw([]byte{separator})
282-
b, ok := backgroundANSIColors[bg]
283-
if !ok {
284-
b = backgroundANSIColors[DefaultColor]
285-
}
286-
w.WriteRaw(b)
287-
return
288-
}
289-
290-
var displayAttributeParameters = map[DisplayAttribute][]byte{
291-
DisplayReset: {'0'},
292-
DisplayBold: {'1'},
293-
DisplayLowIntensity: {'2'},
294-
DisplayItalic: {'3'},
295-
DisplayUnderline: {'4'},
296-
DisplayBlink: {'5'},
297-
DisplayRapidBlink: {'6'},
298-
DisplayReverse: {'7'},
299-
DisplayInvisible: {'8'},
300-
DisplayCrossedOut: {'9'},
301-
DisplayDefaultFont: {'1', '0'},
302-
}
303-
304-
var foregroundANSIColors = map[Color][]byte{
305-
DefaultColor: {'3', '9'},
306-
307-
// Low intensity.
308-
Black: {'3', '0'},
309-
DarkRed: {'3', '1'},
310-
DarkGreen: {'3', '2'},
311-
Brown: {'3', '3'},
312-
DarkBlue: {'3', '4'},
313-
Purple: {'3', '5'},
314-
Cyan: {'3', '6'},
315-
LightGray: {'3', '7'},
316-
317-
// High intensity.
318-
DarkGray: {'9', '0'},
319-
Red: {'9', '1'},
320-
Green: {'9', '2'},
321-
Yellow: {'9', '3'},
322-
Blue: {'9', '4'},
323-
Fuchsia: {'9', '5'},
324-
Turquoise: {'9', '6'},
325-
White: {'9', '7'},
326-
}
327-
328-
var backgroundANSIColors = map[Color][]byte{
329-
DefaultColor: {'4', '9'},
330-
331-
// Low intensity.
332-
Black: {'4', '0'},
333-
DarkRed: {'4', '1'},
334-
DarkGreen: {'4', '2'},
335-
Brown: {'4', '3'},
336-
DarkBlue: {'4', '4'},
337-
Purple: {'4', '5'},
338-
Cyan: {'4', '6'},
339-
LightGray: {'4', '7'},
340-
341-
// High intensity
342-
DarkGray: {'1', '0', '0'},
343-
Red: {'1', '0', '1'},
344-
Green: {'1', '0', '2'},
345-
Yellow: {'1', '0', '3'},
346-
Blue: {'1', '0', '4'},
347-
Fuchsia: {'1', '0', '5'},
348-
Turquoise: {'1', '0', '6'},
349-
White: {'1', '0', '7'},
350-
}
351-
35226
var _ ConsoleWriter = &PosixWriter{}
35327

35428
// NewStandardOutputWriter returns ConsoleWriter object to write to stdout.
29+
// This generates VT100 escape sequences because almost terminal emulators
30+
// in POSIX OS built on top of a VT100 specification.
35531
func NewStandardOutputWriter() *PosixWriter {
35632
return &PosixWriter{
35733
fd: syscall.Stdout,

0 commit comments

Comments
 (0)