277 lines
5.3 KiB
Go
277 lines
5.3 KiB
Go
package prompt
|
|
|
|
import (
|
|
"strconv"
|
|
"syscall"
|
|
)
|
|
|
|
type VT100Writer struct {
|
|
fd int
|
|
buffer []byte
|
|
}
|
|
|
|
func (w *VT100Writer) Write(data []byte) {
|
|
w.WriteRaw(byteFilter(data, writeFilter))
|
|
return
|
|
}
|
|
|
|
func (w *VT100Writer) WriteStr(data string) {
|
|
w.Write([]byte(data))
|
|
return
|
|
}
|
|
|
|
func (w *VT100Writer) WriteRaw(data []byte) {
|
|
w.buffer = append(w.buffer, data...)
|
|
return
|
|
}
|
|
|
|
func (w *VT100Writer) Flush() error {
|
|
_, err := syscall.Write(w.fd, w.buffer)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
w.buffer = []byte{}
|
|
return nil
|
|
}
|
|
|
|
/* Erase */
|
|
|
|
func (w *VT100Writer) EraseScreen() {
|
|
w.WriteRaw([]byte{0x1b, 0x5b, 0x32, 0x4a})
|
|
return
|
|
}
|
|
|
|
func (w *VT100Writer) EraseUp() {
|
|
w.WriteRaw([]byte{0x1b, 0x5b, 0x31, 0x4a})
|
|
return
|
|
}
|
|
|
|
func (w *VT100Writer) EraseDown() {
|
|
w.WriteRaw([]byte{0x1b, 0x5b, 0x4a})
|
|
return
|
|
}
|
|
|
|
func (w *VT100Writer) EraseStartOfLine() {
|
|
w.WriteRaw([]byte{0x1b, 0x5b, 0x31, 0x4b})
|
|
return
|
|
}
|
|
|
|
func (w *VT100Writer) EraseEndOfLine() {
|
|
w.WriteRaw([]byte{0x1b, 0x5b, 0x4b})
|
|
return
|
|
}
|
|
|
|
func (w *VT100Writer) EraseLine() {
|
|
w.WriteRaw([]byte{0x1b, 0x5b, 0x32, 0x4b})
|
|
return
|
|
}
|
|
|
|
/* Cursor */
|
|
|
|
func (w *VT100Writer) ShowCursor() {
|
|
w.WriteRaw([]byte{0x1b, 0x5b, 0x3f, 0x31, 0x32, 0x6c, 0x1b, 0x5b, 0x3f, 0x32, 0x35, 0x68})
|
|
}
|
|
|
|
func (w *VT100Writer) HideCursor() {
|
|
w.WriteRaw([]byte{0x1b, 0x5b, 0x3f, 0x32, 0x35, 0x6c})
|
|
return
|
|
}
|
|
|
|
func (w *VT100Writer) CursorGoTo(row, col int) {
|
|
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
|
|
}
|
|
|
|
func (w *VT100Writer) CursorUp(n int) {
|
|
if n < 0 {
|
|
w.CursorDown(n)
|
|
return
|
|
}
|
|
s := strconv.Itoa(n)
|
|
w.WriteRaw([]byte{0x1b, 0x5b})
|
|
w.WriteRaw([]byte(s))
|
|
w.WriteRaw([]byte{0x41})
|
|
return
|
|
}
|
|
|
|
func (w *VT100Writer) CursorDown(n int) {
|
|
if n < 0 {
|
|
w.CursorUp(n)
|
|
return
|
|
}
|
|
s := strconv.Itoa(n)
|
|
w.WriteRaw([]byte{0x1b, 0x5b})
|
|
w.WriteRaw([]byte(s))
|
|
w.WriteRaw([]byte{0x42})
|
|
return
|
|
}
|
|
|
|
func (w *VT100Writer) CursorForward(n int) {
|
|
if n == 0 {
|
|
return
|
|
} else if n < 0 {
|
|
w.CursorBackward(-n)
|
|
return
|
|
}
|
|
s := strconv.Itoa(n)
|
|
w.WriteRaw([]byte{0x1b, 0x5b})
|
|
w.WriteRaw([]byte(s))
|
|
w.WriteRaw([]byte{0x43})
|
|
return
|
|
}
|
|
|
|
func (w *VT100Writer) CursorBackward(n int) {
|
|
if n == 0 {
|
|
return
|
|
} else if n < 0 {
|
|
w.CursorForward(-n)
|
|
return
|
|
}
|
|
s := strconv.Itoa(n)
|
|
w.WriteRaw([]byte{0x1b, 0x5b})
|
|
w.WriteRaw([]byte(s))
|
|
w.WriteRaw([]byte{0x44})
|
|
return
|
|
}
|
|
|
|
func (w *VT100Writer) AskForCPR() {
|
|
// CPR: Cursor Position Request.
|
|
w.WriteRaw([]byte{0x1b, 0x5b, 0x36, 0x6e})
|
|
w.Flush()
|
|
return
|
|
}
|
|
|
|
func (w *VT100Writer) SaveCursor() {
|
|
w.WriteRaw([]byte{0x1b, 0x5b, 0x73})
|
|
return
|
|
}
|
|
|
|
func (w *VT100Writer) UnSaveCursor() {
|
|
w.WriteRaw([]byte{0x1b, 0x5b, 0x75})
|
|
return
|
|
}
|
|
|
|
/* Scrolling */
|
|
|
|
func (w *VT100Writer) ScrollDown() {
|
|
w.WriteRaw([]byte{0x1b, 0x44})
|
|
return
|
|
}
|
|
|
|
func (w *VT100Writer) ScrollUp() {
|
|
w.WriteRaw([]byte{0x1b, 0x4d})
|
|
return
|
|
}
|
|
|
|
/* Title */
|
|
|
|
func (w *VT100Writer) SetTitle(title string) {
|
|
w.WriteRaw([]byte{0x1b, 0x5d, 0x32, 0x3b})
|
|
w.WriteRaw(byteFilter([]byte(title), setTextFilter))
|
|
w.WriteRaw([]byte{0x07})
|
|
return
|
|
}
|
|
|
|
func (w *VT100Writer) ClearTitle() {
|
|
w.WriteRaw([]byte{0x1b, 0x5d, 0x32, 0x3b, 0x07})
|
|
return
|
|
}
|
|
|
|
/* colors */
|
|
|
|
func (w *VT100Writer) SetColor(fg, bg string) (ok bool) {
|
|
f, ok := foregroundANSIColors[fg]
|
|
if !ok {
|
|
return
|
|
}
|
|
b, ok := backgroundANSIColors[bg]
|
|
if !ok {
|
|
return
|
|
}
|
|
syscall.Write(syscall.Stdout, []byte{0x1b, 0x5b, 0x33, 0x39, 0x3b, 0x34, 0x39, 0x6d})
|
|
w.WriteRaw([]byte{0x1b, 0x5b})
|
|
w.WriteRaw(f)
|
|
w.WriteRaw([]byte{0x3b})
|
|
w.WriteRaw(b)
|
|
w.WriteRaw([]byte{0x6d})
|
|
return
|
|
}
|
|
|
|
var foregroundANSIColors = map[string][]byte{
|
|
"default": {0x33, 0x39}, // 39
|
|
|
|
// Low intensity.
|
|
"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
|
|
|
|
// High intensity.
|
|
"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
|
|
}
|
|
|
|
var backgroundANSIColors = map[string][]byte{
|
|
"default": {0x34, 0x39}, // 49
|
|
|
|
// Low intensity.
|
|
"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
|
|
|
|
// High intensity
|
|
"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
|
|
}
|
|
|
|
func writeFilter(buf byte) bool {
|
|
return buf != 0x1b && buf != 0x3f
|
|
}
|
|
|
|
func setTextFilter(buf byte) bool {
|
|
return buf != 0x1b && buf != 0x07
|
|
}
|
|
|
|
func byteFilter(buf []byte, fn ...func(b byte) bool) []byte {
|
|
if len(fn) == 0 {
|
|
return buf
|
|
}
|
|
ret := make([]byte, 0, len(buf))
|
|
f := fn[0]
|
|
for i, n := range buf {
|
|
if f(n) {
|
|
ret = append(ret, buf[i])
|
|
}
|
|
}
|
|
return byteFilter(ret, fn[1:]...)
|
|
}
|
|
|
|
var _ ConsoleWriter = &VT100Writer{}
|