Files
odo/vendor/github.com/hinshun/vt10x/csi.go
Anand Kumar Singh 3eb92b6a47 POC for odo interactive testing (#5466)
* POC for odo interactive testing

Signed-off-by: anandrkskd <anandrkskd@gmail.com>

* add interactive tests to make target test-integration

Signed-off-by: anandrkskd <anandrkskd@gmail.com>

* [WIP] use func to pass test instructions

Signed-off-by: anandrkskd <anandrkskd@gmail.com>

* cleanup comments/test

Signed-off-by: anandrkskd <anandrkskd@gmail.com>

* cleanup minor changes

Signed-off-by: anandrkskd <anandrkskd@gmail.com>

* fix unit test failure

Signed-off-by: anandrkskd <anandrkskd@gmail.com>

* skip for windows

Signed-off-by: anandrkskd <anandrkskd@gmail.com>

* skip for windows by not compiling, cleanup

Signed-off-by: anandrkskd <anandrkskd@gmail.com>

* cleanup, and add the make target to test files

Signed-off-by: anandrkskd <anandrkskd@gmail.com>

* incorporate review, adding comments, cleanup

Signed-off-by: anandrkskd <anandrkskd@gmail.com>

* fix failing make validate

Signed-off-by: anandrkskd <anandrkskd@gmail.com>

* update test dependency, and possible fix for windows

Signed-off-by: anandrkskd <anandrkskd@gmail.com>

* Revert "update test dependency, and possible fix for windows"

This reverts commit 55580b7dc5.

* Final cleanup

Signed-off-by: anandrkskd <anandrkskd@gmail.com>
2022-03-02 13:50:26 -05:00

190 lines
4.4 KiB
Go

package vt10x
import (
"fmt"
"strconv"
"strings"
)
// CSI (Control Sequence Introducer)
// ESC+[
type csiEscape struct {
buf []byte
args []int
mode byte
priv bool
}
func (c *csiEscape) reset() {
c.buf = c.buf[:0]
c.args = c.args[:0]
c.mode = 0
c.priv = false
}
func (c *csiEscape) put(b byte) bool {
c.buf = append(c.buf, b)
if b >= 0x40 && b <= 0x7E || len(c.buf) >= 256 {
c.parse()
return true
}
return false
}
func (c *csiEscape) parse() {
c.mode = c.buf[len(c.buf)-1]
if len(c.buf) == 1 {
return
}
s := string(c.buf)
c.args = c.args[:0]
if s[0] == '?' {
c.priv = true
s = s[1:]
}
s = s[:len(s)-1]
ss := strings.Split(s, ";")
for _, p := range ss {
i, err := strconv.Atoi(p)
if err != nil {
//t.logf("invalid CSI arg '%s'\n", p)
break
}
c.args = append(c.args, i)
}
}
func (c *csiEscape) arg(i, def int) int {
if i >= len(c.args) || i < 0 {
return def
}
return c.args[i]
}
// maxarg takes the maximum of arg(i, def) and def
func (c *csiEscape) maxarg(i, def int) int {
return max(c.arg(i, def), def)
}
func (t *State) handleCSI() {
c := &t.csi
switch c.mode {
default:
goto unknown
case '@': // ICH - insert <n> blank char
t.insertBlanks(c.arg(0, 1))
case 'A': // CUU - cursor <n> up
t.moveTo(t.cur.X, t.cur.Y-c.maxarg(0, 1))
case 'B', 'e': // CUD, VPR - cursor <n> down
t.moveTo(t.cur.X, t.cur.Y+c.maxarg(0, 1))
case 'c': // DA - device attributes
if c.arg(0, 0) == 0 {
// TODO: write vt102 id
}
case 'C', 'a': // CUF, HPR - cursor <n> forward
t.moveTo(t.cur.X+c.maxarg(0, 1), t.cur.Y)
case 'D': // CUB - cursor <n> backward
t.moveTo(t.cur.X-c.maxarg(0, 1), t.cur.Y)
case 'E': // CNL - cursor <n> down and first col
t.moveTo(0, t.cur.Y+c.arg(0, 1))
case 'F': // CPL - cursor <n> up and first col
t.moveTo(0, t.cur.Y-c.arg(0, 1))
case 'g': // TBC - tabulation clear
switch c.arg(0, 0) {
// clear current tab stop
case 0:
t.tabs[t.cur.X] = false
// clear all tabs
case 3:
for i := range t.tabs {
t.tabs[i] = false
}
default:
goto unknown
}
case 'G', '`': // CHA, HPA - Move to <col>
t.moveTo(c.arg(0, 1)-1, t.cur.Y)
case 'H', 'f': // CUP, HVP - move to <row> <col>
t.moveAbsTo(c.arg(1, 1)-1, c.arg(0, 1)-1)
case 'I': // CHT - cursor forward tabulation <n> tab stops
n := c.arg(0, 1)
for i := 0; i < n; i++ {
t.putTab(true)
}
case 'J': // ED - clear screen
// TODO: sel.ob.x = -1
switch c.arg(0, 0) {
case 0: // below
t.clear(t.cur.X, t.cur.Y, t.cols-1, t.cur.Y)
if t.cur.Y < t.rows-1 {
t.clear(0, t.cur.Y+1, t.cols-1, t.rows-1)
}
case 1: // above
if t.cur.Y > 1 {
t.clear(0, 0, t.cols-1, t.cur.Y-1)
}
t.clear(0, t.cur.Y, t.cur.X, t.cur.Y)
case 2: // all
t.clear(0, 0, t.cols-1, t.rows-1)
default:
goto unknown
}
case 'K': // EL - clear line
switch c.arg(0, 0) {
case 0: // right
t.clear(t.cur.X, t.cur.Y, t.cols-1, t.cur.Y)
case 1: // left
t.clear(0, t.cur.Y, t.cur.X, t.cur.Y)
case 2: // all
t.clear(0, t.cur.Y, t.cols-1, t.cur.Y)
}
case 'S': // SU - scroll <n> lines up
t.scrollUp(t.top, c.arg(0, 1))
case 'T': // SD - scroll <n> lines down
t.scrollDown(t.top, c.arg(0, 1))
case 'L': // IL - insert <n> blank lines
t.insertBlankLines(c.arg(0, 1))
case 'l': // RM - reset mode
t.setMode(c.priv, false, c.args)
case 'M': // DL - delete <n> lines
t.deleteLines(c.arg(0, 1))
case 'X': // ECH - erase <n> chars
t.clear(t.cur.X, t.cur.Y, t.cur.X+c.arg(0, 1)-1, t.cur.Y)
case 'P': // DCH - delete <n> chars
t.deleteChars(c.arg(0, 1))
case 'Z': // CBT - cursor backward tabulation <n> tab stops
n := c.arg(0, 1)
for i := 0; i < n; i++ {
t.putTab(false)
}
case 'd': // VPA - move to <row>
t.moveAbsTo(t.cur.X, c.arg(0, 1)-1)
case 'h': // SM - set terminal mode
t.setMode(c.priv, true, c.args)
case 'm': // SGR - terminal attribute (color)
t.setAttr(c.args)
case 'n':
switch c.arg(0, 0) {
case 5: // DSR - device status report
t.w.Write([]byte("\033[0n"))
case 6: // CPR - cursor position report
t.w.Write([]byte(fmt.Sprintf("\033[%d;%dR", t.cur.Y+1, t.cur.X+1)))
}
case 'r': // DECSTBM - set scrolling region
if c.priv {
goto unknown
} else {
t.setScroll(c.arg(0, 1)-1, c.arg(1, t.rows)-1)
t.moveAbsTo(0, 0)
}
case 's': // DECSC - save cursor position (ANSI.SYS)
t.saveCursor()
case 'u': // DECRC - restore cursor position (ANSI.SYS)
t.restoreCursor()
}
return
unknown: // TODO: get rid of this goto
t.logf("unknown CSI sequence '%c'\n", c.mode)
// TODO: c.dump()
}