progress toward vim support

This commit is contained in:
Liam Galvin 2018-10-23 14:22:27 +01:00
parent 0b8f2ed44d
commit 2cf4b36910
7 changed files with 131 additions and 22 deletions

View File

@ -199,6 +199,44 @@ func (buffer *Buffer) ViewHeight() uint16 {
return buffer.viewHeight
}
func (buffer *Buffer) insertLine() {
if !buffer.InScrollableRegion() {
pos := buffer.RawLine()
out := make([]Line, len(buffer.lines)+1)
copy(out[:pos], buffer.lines[:pos])
out[pos] = newLine()
copy(out[pos+1:], buffer.lines[pos:])
buffer.lines = out
} else {
topIndex := buffer.convertViewLineToRawLine(uint16(buffer.topMargin))
bottomIndex := buffer.convertViewLineToRawLine(uint16(buffer.bottomMargin))
before := buffer.lines[:topIndex]
after := buffer.lines[bottomIndex+1:]
scrollable := buffer.lines[topIndex : bottomIndex+1]
out := make([]Line, len(buffer.lines))
copy(out[0:], before)
copy(out[topIndex+1:], scrollable[0:len(scrollable)-1])
copy(out[bottomIndex:], after)
out[topIndex] = newLine()
buffer.lines = out
}
}
func (buffer *Buffer) InsertLines(count int) {
if buffer.HasScrollableRegion() && !buffer.InScrollableRegion() {
// should have no effect outside of scrollable region
return
}
buffer.cursorX = 0
for i := 0; i < count; i++ {
buffer.insertLine()
}
}
func (buffer *Buffer) Index() {
// This sequence causes the active position to move downward one line without changing the column position.
@ -208,12 +246,12 @@ func (buffer *Buffer) Index() {
if uint(buffer.cursorY) < buffer.bottomMargin {
buffer.cursorY++
return
}
for i := buffer.topMargin; i < uint(buffer.cursorY); i++ {
for i := buffer.topMargin; i < uint(buffer.bottomMargin); i++ {
buffer.lines[i] = buffer.lines[i+1]
}
buffer.lines[buffer.cursorY] = newLine()
return
@ -231,19 +269,18 @@ func (buffer *Buffer) ReverseIndex() {
if uint(buffer.cursorY) > buffer.topMargin {
buffer.cursorY--
return
}
for i := buffer.bottomMargin; i > uint(buffer.cursorY); i-- {
for i := buffer.bottomMargin; i > uint(buffer.topMargin); i-- {
buffer.lines[i] = buffer.lines[i-1]
}
buffer.lines[buffer.cursorY] = newLine()
return
}
if buffer.cursorY > 0 {
buffer.cursorY--
}
}
@ -325,7 +362,7 @@ func (buffer *Buffer) incrementCursorPosition() {
buffer.cursorX++
} else {
panic("cursor position invalid")
fmt.Println("cursor position invalid")
}
}
@ -352,7 +389,6 @@ func (buffer *Buffer) NewLine() {
defer buffer.emitDisplayChange()
buffer.cursorX = 0
buffer.Index()
}
@ -459,7 +495,9 @@ func (buffer *Buffer) EraseLineFromCursor() {
defer buffer.emitDisplayChange()
line := buffer.getCurrentLine()
line.cells = line.cells[:buffer.cursorX]
if len(line.cells) > 0 {
line.cells = line.cells[:buffer.cursorX]
}
max := int(buffer.ViewWidth()) - len(line.cells)

18
demo/CSI-L.sh Executable file
View File

@ -0,0 +1,18 @@
#!/bin/bash
echo "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
echo "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
echo "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
echo "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"
echo "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE"
echo -ne "\x1b[A" # up
echo -ne "\x1b[A" # up
echo -ne "\x1b[C" # right
echo -ne "\x1b[C" # rightt
sleep 2
echo -ne "\x1b[2L" # insert 2 lines
sleep 2
echo -ne "\x1b[B" # down
echo -ne "\x1b[B" # down
sleep 2

View File

@ -12,7 +12,7 @@ var ansiSequenceMap = map[rune]escapeSequenceHandler{
'8': restoreCursorHandler,
'D': indexHandler,
'M': reverseIndexHandler,
'c': swallowHandler(0), //RIS
'c': risHandler, //RIS
'(': swallowHandler(1), // character set bullshit
')': swallowHandler(1), // character set bullshit
'*': swallowHandler(1), // character set bullshit
@ -30,6 +30,11 @@ func swallowHandler(n int) func(pty chan rune, terminal *Terminal) error {
}
}
func risHandler(pty chan rune, terminal *Terminal) error {
terminal.ActiveBuffer().Clear()
return nil
}
func indexHandler(pty chan rune, terminal *Terminal) error {
terminal.ActiveBuffer().Index()
return nil

View File

@ -21,19 +21,15 @@ type expectedParams struct {
}
var csiSequences = []csiMapping{
csiMapping{id: 'c', handler: csiSendDeviceAttributesHandler, description: " Send Device Attributes (Primary/Secondary/Tertiary DA)"},
csiMapping{id: 'd', handler: csiLinePositionAbsolute, expectedParams: &expectedParams{min: 0, max: 1}, description: "Line Position Absolute [row] (default = [1,column]) (VPA)"},
csiMapping{id: 'f', handler: csiCursorPositionHandler, description: "Horizontal and Vertical Position [row;column] (default = [1,1]) (HVP)"},
csiMapping{id: 'h', handler: csiSetModeHandler, expectedParams: &expectedParams{min: 1, max: 1}, description: "Set Mode (SM)"},
csiMapping{id: 'l', handler: csiResetModeHandler, expectedParams: &expectedParams{min: 1, max: 1}, description: "Reset Mode (RM)"},
csiMapping{id: 'm', handler: sgrSequenceHandler, description: "Character Attributes (SGR)"},
csiMapping{id: 'n', handler: csiDeviceStatusReportHandler, description: "Device Status Report (DSR)"},
csiMapping{id: 'r', handler: csiSetMarginsHandler, expectedParams: &expectedParams{min: 2, max: 2}, description: "Set Scrolling Region [top;bottom] (default = full size of window) (DECSTBM), VT100"},
csiMapping{id: 't', handler: csiWindowManipulation, description: "Window manipulation"},
csiMapping{id: 'J', handler: csiEraseInDisplayHandler, description: "Erase in Display (ED), VT100"},
csiMapping{id: 'K', handler: csiEraseInLineHandler, description: "Erase in Line (EL), VT100"},
csiMapping{id: 'L', handler: csiInsertLinesHandler, description: "Insert Ps Line(s) (default = 1) (IL)"},
csiMapping{id: 'P', handler: csiDeleteHandler, description: " Delete Ps Character(s) (default = 1) (DCH)"},
csiMapping{id: 'S', handler: csiScrollUpHandler, description: "Scroll up Ps lines (default = 1) (SU), VT420, ECMA-48"},
csiMapping{id: 'T', handler: csiScrollDownHandler, description: "Scroll down Ps lines (default = 1) (SD), VT420"},
csiMapping{id: 'X', handler: csiEraseCharactersHandler, description: "Erase Ps Character(s) (default = 1) (ECH"},
csiMapping{id: 'A', handler: csiCursorUpHandler, description: "Cursor Up Ps Times (default = 1) (CUU)"},
csiMapping{id: 'B', handler: csiCursorDownHandler, description: "Cursor Down Ps Times (default = 1) (CUD)"},
csiMapping{id: 'C', handler: csiCursorForwardHandler, description: "Cursor Forward Ps Times (default = 1) (CUF)"},
@ -42,7 +38,13 @@ var csiSequences = []csiMapping{
csiMapping{id: 'F', handler: csiCursorPrecedingLineHandler, description: "Cursor Preceding Line Ps Times (default = 1) (CPL)"},
csiMapping{id: 'G', handler: csiCursorCharacterAbsoluteHandler, description: "Cursor Character Absolute [column] (default = [row,1]) (CHA)"},
csiMapping{id: 'H', handler: csiCursorPositionHandler, description: "Cursor Position [row;column] (default = [1,1]) (CUP)"},
csiMapping{id: 'f', handler: csiCursorPositionHandler, description: "Horizontal and Vertical Position [row;column] (default = [1,1]) (HVP)"},
csiMapping{id: 'J', handler: csiEraseInDisplayHandler, description: "Erase in Display (ED), VT100"},
csiMapping{id: 'K', handler: csiEraseInLineHandler, description: "Erase in Line (EL), VT100"},
csiMapping{id: 'L', handler: csiInsertLinesHandler, description: "Insert Ps Line(s) (default = 1) (IL)"},
csiMapping{id: 'P', handler: csiDeleteHandler, description: " Delete Ps Character(s) (default = 1) (DCH)"},
csiMapping{id: 'S', handler: csiScrollUpHandler, description: "Scroll up Ps lines (default = 1) (SU), VT420, ECMA-48"},
csiMapping{id: 'T', handler: csiScrollDownHandler, description: "Scroll down Ps lines (default = 1) (SD), VT420"},
csiMapping{id: 'X', handler: csiEraseCharactersHandler, description: "Erase Ps Character(s) (default = 1) (ECH"},
}
func csiHandler(pty chan rune, terminal *Terminal) error {
@ -77,13 +79,43 @@ CSI:
}
terminal.logger.Debugf("CSI 0x%02X (ESC[%s%s%s) %s", final, param, intermediate, string(final), sequence.description)
err := sequence.handler(params, intermediate, terminal)
terminal.logger.Debugf("After CSI, state: Col %d, Line %d, Top: %d, Bottom %d", terminal.ActiveBuffer().CursorColumn(), terminal.ActiveBuffer().CursorLine(), terminal.ActiveBuffer().TopMargin(), terminal.ActiveBuffer().BottomMargin())
return err
}
}
return fmt.Errorf("Unknown CSI control sequence: 0x%02X (ESC[%s%s%s)", final, param, intermediate, string(final))
}
func csiSendDeviceAttributesHandler(params []string, intermediate string, terminal *Terminal) error {
if len(params) > 0 && len(params[0]) > 0 && params[0][0] == '>' { // secondary
_ = terminal.Write([]byte("\x1b[0;0;0c")) // report VT100
return nil
}
return fmt.Errorf("Unsupported SDA identifier")
}
func csiDeviceStatusReportHandler(params []string, intermediate string, terminal *Terminal) error {
if len(params) == 0 {
return fmt.Errorf("Missing Device Status Report identifier")
}
switch params[0] {
case "5":
_ = terminal.Write([]byte("\x1b[0n")) // everything is cool
case "6": // report cursor position
_ = terminal.Write([]byte(fmt.Sprintf(
"\x1b[%d;%dR",
terminal.ActiveBuffer().CursorLine()+1,
terminal.ActiveBuffer().CursorColumn()+1,
)))
default:
return fmt.Errorf("Unknown Device Status Report identifier: %s", params[0])
}
return nil
}
func csiCursorUpHandler(params []string, intermediate string, terminal *Terminal) error {
@ -237,10 +269,9 @@ func csiInsertLinesHandler(params []string, intermediate string, terminal *Termi
count = 1
}
}
terminal.logger.Debugf("Inserting %d lines", count)
for i := 0; i < count; i++ {
terminal.ActiveBuffer().Index()
}
terminal.ActiveBuffer().InsertLines(count)
return nil
}

View File

@ -75,6 +75,10 @@ func csiSetMode(modeStr string, enabled bool, terminal *Terminal) error {
} else {
terminal.UseMainBuffer()
}
case "?2004":
if enabled {
return fmt.Errorf("Bracketed paste mode is not yet supported")
}
default:
return fmt.Errorf("Unsupported CSI %sl code", modeStr)
}

View File

@ -39,6 +39,18 @@ func oscHandler(pty chan rune, terminal *Terminal) error {
switch pS[0] {
case "0", "2":
terminal.SetTitle(pT)
case "10": // get/set foreground colour
if len(pS) > 1 {
if pS[1] == "?" {
terminal.Write([]byte("\x1b]10;15"))
}
}
case "11": // get/set background colour
if len(pS) > 1 {
if pS[1] == "?" {
terminal.Write([]byte("\x1b]10;0"))
}
}
default:
return fmt.Errorf("Unknown OSC control sequence: %s", strings.Join(params, ";"))
}

View File

@ -98,6 +98,7 @@ func (terminal *Terminal) processInput(ctx context.Context, pty chan rune) {
} else {
//terminal.logger.Debugf("Received character 0x%X: %q", b, string(b))
if b >= 0x20 {
terminal.logger.Debugf("%c", b)
terminal.ActiveBuffer().Write(b)
} else {
terminal.logger.Error("Non-readable rune received: 0x%X", b)