mirror of https://github.com/liamg/aminal.git
progress toward vim support
This commit is contained in:
parent
0b8f2ed44d
commit
2cf4b36910
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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, ";"))
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue