go-prompt/posix_output.go

333 lines
7.6 KiB
Go
Raw Normal View History

2017-08-16 03:22:38 +00:00
// +build !windows
2017-07-06 16:00:35 +00:00
package prompt
import (
2018-02-15 06:51:02 +00:00
"bytes"
2017-07-06 16:00:35 +00:00
"strconv"
"syscall"
)
// PosixWriter is a ConsoleWriter implementation for POSIX environment.
// To control terminal emulator, this outputs VT100 escape sequences.
2018-02-12 10:12:31 +00:00
type PosixWriter struct {
2017-07-06 16:00:35 +00:00
fd int
buffer []byte
}
// WriteRaw to write raw byte array
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) WriteRaw(data []byte) {
2017-07-18 10:06:38 +00:00
w.buffer = append(w.buffer, data...)
2017-08-11 09:24:44 +00:00
// Flush because sometimes the render is broken when a large amount data in buffer.
w.Flush()
2017-07-18 10:06:38 +00:00
return
}
2018-02-15 06:51:02 +00:00
// Write to write safety byte array by removing control sequences.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) Write(data []byte) {
2018-02-15 06:51:02 +00:00
w.WriteRaw(bytes.Replace(data, []byte{0x1b}, []byte{'?'}, -1))
2017-07-06 16:00:35 +00:00
return
}
// WriteRawStr to write raw string
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) WriteRawStr(data string) {
2017-07-18 10:06:38 +00:00
w.WriteRaw([]byte(data))
2017-07-06 16:00:35 +00:00
return
}
2018-02-15 06:51:02 +00:00
// WriteStr to write safety string by removing control sequences.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) WriteStr(data string) {
2017-07-18 10:06:38 +00:00
w.Write([]byte(data))
2017-07-06 16:00:35 +00:00
return
}
// Flush to flush buffer
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) Flush() error {
2017-07-06 16:00:35 +00:00
_, err := syscall.Write(w.fd, w.buffer)
if err != nil {
return err
}
w.buffer = []byte{}
return nil
}
2017-07-07 00:27:21 +00:00
/* Erase */
// EraseScreen erases the screen with the background colour and moves the cursor to home.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) EraseScreen() {
2017-07-08 03:25:47 +00:00
w.WriteRaw([]byte{0x1b, 0x5b, 0x32, 0x4a})
2017-07-07 00:27:21 +00:00
return
}
// EraseUp erases the screen from the current line up to the top of the screen.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) EraseUp() {
2017-07-08 03:25:47 +00:00
w.WriteRaw([]byte{0x1b, 0x5b, 0x31, 0x4a})
2017-07-07 00:27:21 +00:00
return
}
// EraseDown erases the screen from the current line down to the bottom of the screen.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) EraseDown() {
2017-07-07 00:27:21 +00:00
w.WriteRaw([]byte{0x1b, 0x5b, 0x4a})
return
}
// EraseStartOfLine erases from the current cursor position to the start of the current line.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) EraseStartOfLine() {
2017-07-08 03:25:47 +00:00
w.WriteRaw([]byte{0x1b, 0x5b, 0x31, 0x4b})
return
}
// EraseEndOfLine erases from the current cursor position to the end of the current line.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) EraseEndOfLine() {
2017-07-07 00:27:21 +00:00
w.WriteRaw([]byte{0x1b, 0x5b, 0x4b})
2017-07-06 16:00:35 +00:00
return
}
// EraseLine erases the entire current line.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) EraseLine() {
2017-07-08 03:25:47 +00:00
w.WriteRaw([]byte{0x1b, 0x5b, 0x32, 0x4b})
return
}
2017-07-06 16:00:35 +00:00
/* Cursor */
// ShowCursor stops blinking cursor and show.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) ShowCursor() {
2017-07-07 00:27:21 +00:00
w.WriteRaw([]byte{0x1b, 0x5b, 0x3f, 0x31, 0x32, 0x6c, 0x1b, 0x5b, 0x3f, 0x32, 0x35, 0x68})
}
// HideCursor hides cursor.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) HideCursor() {
2017-07-07 00:27:21 +00:00
w.WriteRaw([]byte{0x1b, 0x5b, 0x3f, 0x32, 0x35, 0x6c})
return
}
// CursorGoTo sets the cursor position where subsequent text will begin.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) CursorGoTo(row, col int) {
if row == 0 && col == 0 {
// If no row/column parameters are provided (ie. <ESC>[H), the cursor will move to the home position.
w.WriteRaw([]byte{0x1b, 0x5b, 0x3b, 0x48})
return
}
2017-07-07 00:27:21 +00:00
r := strconv.Itoa(row)
c := strconv.Itoa(col)
w.WriteRaw([]byte{0x1b, 0x5b})
w.WriteRaw([]byte(r))
w.WriteRaw([]byte{0x3b})
w.WriteRaw([]byte(c))
w.WriteRaw([]byte{0x48})
return
}
// CursorUp moves the cursor up by 'n' rows; the default count is 1.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) CursorUp(n int) {
2018-02-12 09:36:39 +00:00
if n == 0 {
return
} else if n < 0 {
w.CursorDown(-n)
2017-07-06 16:00:35 +00:00
return
}
s := strconv.Itoa(n)
w.WriteRaw([]byte{0x1b, 0x5b})
w.WriteRaw([]byte(s))
w.WriteRaw([]byte{0x41})
return
}
// CursorDown moves the cursor down by 'n' rows; the default count is 1.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) CursorDown(n int) {
2018-02-12 09:36:39 +00:00
if n == 0 {
return
} else if n < 0 {
w.CursorUp(-n)
2017-07-06 16:00:35 +00:00
return
}
s := strconv.Itoa(n)
w.WriteRaw([]byte{0x1b, 0x5b})
w.WriteRaw([]byte(s))
w.WriteRaw([]byte{0x42})
return
}
// CursorForward moves the cursor forward by 'n' columns; the default count is 1.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) CursorForward(n int) {
if n == 0 {
return
} else if n < 0 {
2017-07-09 14:16:08 +00:00
w.CursorBackward(-n)
2017-07-06 16:00:35 +00:00
return
}
s := strconv.Itoa(n)
w.WriteRaw([]byte{0x1b, 0x5b})
w.WriteRaw([]byte(s))
w.WriteRaw([]byte{0x43})
return
}
// CursorBackward moves the cursor backward by 'n' columns; the default count is 1.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) CursorBackward(n int) {
if n == 0 {
return
} else if n < 0 {
2017-07-09 14:16:08 +00:00
w.CursorForward(-n)
2017-07-06 16:00:35 +00:00
return
}
s := strconv.Itoa(n)
w.WriteRaw([]byte{0x1b, 0x5b})
w.WriteRaw([]byte(s))
w.WriteRaw([]byte{0x44})
return
}
// AskForCPR asks for a cursor position report (CPR).
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) AskForCPR() {
2017-07-08 03:25:47 +00:00
// CPR: Cursor Position Request.
w.WriteRaw([]byte{0x1b, 0x5b, 0x36, 0x6e})
w.Flush()
return
}
// SaveCursor saves current cursor position.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) SaveCursor() {
2017-07-08 03:25:47 +00:00
w.WriteRaw([]byte{0x1b, 0x5b, 0x73})
return
}
// UnSaveCursor restores cursor position after a Save Cursor.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) UnSaveCursor() {
2017-07-08 03:25:47 +00:00
w.WriteRaw([]byte{0x1b, 0x5b, 0x75})
return
}
/* Scrolling */
// ScrollDown scrolls display down one line.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) ScrollDown() {
2017-07-08 03:25:47 +00:00
w.WriteRaw([]byte{0x1b, 0x44})
return
}
// ScrollUp scroll display up one line.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) ScrollUp() {
2017-07-08 03:25:47 +00:00
w.WriteRaw([]byte{0x1b, 0x4d})
return
}
2017-07-06 16:00:35 +00:00
/* Title */
// SetTitle sets a title of terminal window.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) SetTitle(title string) {
2018-02-15 06:51:02 +00:00
titleBytes := []byte(title)
patterns := []struct {
from []byte
to []byte
}{
{
from: []byte{0x13},
to: []byte{},
},
{
from: []byte{0x07},
to: []byte{},
},
}
for i := range patterns {
titleBytes = bytes.Replace(titleBytes, patterns[i].from, patterns[i].to, -1)
}
2017-07-06 16:00:35 +00:00
w.WriteRaw([]byte{0x1b, 0x5d, 0x32, 0x3b})
2018-02-15 06:51:02 +00:00
w.WriteRaw(titleBytes)
2017-07-06 16:00:35 +00:00
w.WriteRaw([]byte{0x07})
return
}
// ClearTitle clears a title of terminal window.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) ClearTitle() {
2017-07-06 16:00:35 +00:00
w.WriteRaw([]byte{0x1b, 0x5d, 0x32, 0x3b, 0x07})
return
}
2017-07-18 16:16:51 +00:00
/* Font */
2017-07-09 13:44:28 +00:00
// SetColor sets text and background colors. and specify whether text is bold.
2018-02-12 10:12:31 +00:00
func (w *PosixWriter) SetColor(fg, bg Color, bold bool) {
2017-07-16 08:39:26 +00:00
f, ok := foregroundANSIColors[fg]
2017-07-09 13:44:28 +00:00
if !ok {
2017-08-16 04:39:59 +00:00
f = foregroundANSIColors[DefaultColor]
2017-07-09 13:44:28 +00:00
}
2017-07-16 08:39:26 +00:00
b, ok := backgroundANSIColors[bg]
2017-07-09 13:44:28 +00:00
if !ok {
2017-08-16 04:39:59 +00:00
b = backgroundANSIColors[DefaultColor]
2017-07-09 13:44:28 +00:00
}
syscall.Write(syscall.Stdout, []byte{0x1b, 0x5b, 0x33, 0x39, 0x3b, 0x34, 0x39, 0x6d})
w.WriteRaw([]byte{0x1b, 0x5b})
2017-07-18 16:16:51 +00:00
if !bold {
w.WriteRaw([]byte{0x30, 0x3b})
}
2017-07-09 13:44:28 +00:00
w.WriteRaw(f)
w.WriteRaw([]byte{0x3b})
w.WriteRaw(b)
2017-07-18 16:16:51 +00:00
if bold {
w.WriteRaw([]byte{0x3b, 0x31})
}
2017-07-09 13:44:28 +00:00
w.WriteRaw([]byte{0x6d})
return
}
2017-07-16 19:32:42 +00:00
var foregroundANSIColors = map[Color][]byte{
DefaultColor: {0x33, 0x39}, // 39
2017-07-09 13:44:28 +00:00
// Low intensity.
2017-07-16 19:32:42 +00:00
Black: {0x33, 0x30}, // 30
DarkRed: {0x33, 0x31}, // 31
DarkGreen: {0x33, 0x32}, // 32
Brown: {0x33, 0x33}, // 33
DarkBlue: {0x33, 0x34}, // 34
Purple: {0x33, 0x35}, // 35
Cyan: {0x33, 0x36}, //36
LightGray: {0x33, 0x37}, //37
2017-07-09 13:44:28 +00:00
// High intensity.
2017-07-16 19:32:42 +00:00
DarkGray: {0x39, 0x30}, // 90
Red: {0x39, 0x31}, // 91
Green: {0x39, 0x32}, // 92
Yellow: {0x39, 0x33}, // 93
Blue: {0x39, 0x34}, // 94
Fuchsia: {0x39, 0x35}, // 95
Turquoise: {0x39, 0x36}, // 96
White: {0x39, 0x37}, // 97
2017-07-09 13:44:28 +00:00
}
2017-07-16 19:32:42 +00:00
var backgroundANSIColors = map[Color][]byte{
DefaultColor: {0x34, 0x39}, // 49
2017-07-09 13:44:28 +00:00
// Low intensity.
2017-07-16 19:32:42 +00:00
Black: {0x34, 0x30}, // 40
DarkRed: {0x34, 0x31}, // 41
DarkGreen: {0x34, 0x32}, // 42
Brown: {0x34, 0x33}, // 43
DarkBlue: {0x34, 0x34}, // 44
Purple: {0x34, 0x35}, // 45
Cyan: {0x34, 0x36}, // 46
LightGray: {0x34, 0x37}, // 47
2017-07-09 13:44:28 +00:00
// High intensity
2017-07-16 19:32:42 +00:00
DarkGray: {0x31, 0x30, 0x30}, // 100
Red: {0x31, 0x30, 0x31}, // 101
Green: {0x31, 0x30, 0x32}, // 102
Yellow: {0x31, 0x30, 0x33}, // 103
Blue: {0x31, 0x30, 0x34}, // 104
Fuchsia: {0x31, 0x30, 0x35}, // 105
Turquoise: {0x31, 0x30, 0x36}, // 106
White: {0x31, 0x30, 0x37}, // 107
2017-07-09 13:44:28 +00:00
}
2017-07-16 08:39:26 +00:00
2018-02-12 10:12:31 +00:00
var _ ConsoleWriter = &PosixWriter{}
2017-07-16 18:53:23 +00:00
// NewStandardOutputWriter returns ConsoleWriter object to write to stdout.
2018-02-12 10:12:31 +00:00
func NewStandardOutputWriter() *PosixWriter {
return &PosixWriter{
2017-07-16 18:53:23 +00:00
fd: syscall.Stdout,
}
}