mirror of https://github.com/liamg/aminal.git
ess
This commit is contained in:
parent
132ce51f78
commit
9ac2e9cba0
|
@ -12,6 +12,8 @@ type Buffer struct {
|
|||
viewWidth uint16
|
||||
cursorAttr CellAttributes
|
||||
displayChangeHandlers []chan bool
|
||||
savedX uint16
|
||||
savedY uint16
|
||||
}
|
||||
|
||||
// NewBuffer creates a new terminal buffer
|
||||
|
@ -26,6 +28,16 @@ func NewBuffer(viewCols uint16, viewLines uint16, attr CellAttributes) *Buffer {
|
|||
return b
|
||||
}
|
||||
|
||||
func (buffer *Buffer) SaveCursor() {
|
||||
buffer.savedX = buffer.cursorX
|
||||
buffer.savedY = buffer.cursorY
|
||||
}
|
||||
|
||||
func (buffer *Buffer) RestoreCursor() {
|
||||
buffer.cursorX = buffer.savedX
|
||||
buffer.cursorY = buffer.savedY
|
||||
}
|
||||
|
||||
func (buffer *Buffer) CursorAttr() *CellAttributes {
|
||||
return &buffer.cursorAttr
|
||||
}
|
||||
|
@ -155,13 +167,11 @@ func (buffer *Buffer) incrementCursorPosition() {
|
|||
buffer.cursorX = 0
|
||||
buffer.cursorY++
|
||||
|
||||
_, err := buffer.getCurrentLine()
|
||||
if err != nil {
|
||||
line := newLine()
|
||||
line.setWrapped(true)
|
||||
buffer.lines = append(buffer.lines, line)
|
||||
}
|
||||
rawLine := int(buffer.RawLine())
|
||||
|
||||
line := newLine()
|
||||
line.setWrapped(true)
|
||||
buffer.lines = append(append(buffer.lines[:rawLine], line), buffer.lines[rawLine:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -172,18 +182,19 @@ func (buffer *Buffer) CarriageReturn() {
|
|||
|
||||
line, err := buffer.getCurrentLine()
|
||||
if err != nil {
|
||||
buffer.ensureLinesExistToRawHeight()
|
||||
line, err = buffer.getCurrentLine()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println("Failed to get new line during carriage return")
|
||||
|
||||
buffer.cursorX = 0
|
||||
return
|
||||
}
|
||||
|
||||
if buffer.cursorX == 0 && line.wrapped {
|
||||
buffer.cursorY--
|
||||
if len(line.cells) == 0 {
|
||||
rawLine := int(buffer.RawLine())
|
||||
buffer.lines = append(buffer.lines[:rawLine], buffer.lines[rawLine+1:]...)
|
||||
}
|
||||
buffer.cursorY--
|
||||
} else {
|
||||
buffer.cursorX = 0
|
||||
}
|
||||
|
@ -196,20 +207,14 @@ func (buffer *Buffer) NewLine() {
|
|||
// if we're at the beginning of a line which wrapped from the previous one, and we need a new line, we can effectively not add a new line, and set the current one to non-wrapped
|
||||
if buffer.cursorX == 0 {
|
||||
line, err := buffer.getCurrentLine()
|
||||
if err != nil {
|
||||
buffer.ensureLinesExistToRawHeight()
|
||||
line, err = buffer.getCurrentLine()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
if line.wrapped {
|
||||
if err == nil && line != nil && line.wrapped {
|
||||
line.setWrapped(false)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if buffer.cursorY == buffer.viewHeight-1 {
|
||||
buffer.ensureLinesExistToRawHeight()
|
||||
buffer.lines = append(buffer.lines, newLine())
|
||||
} else {
|
||||
buffer.cursorY++
|
||||
|
@ -313,19 +318,28 @@ func (buffer *Buffer) EraseLineToCursor() {
|
|||
}
|
||||
}
|
||||
|
||||
func (buffer *Buffer) EraseLineAfterCursor() {
|
||||
func (buffer *Buffer) EraseLineFromCursor() {
|
||||
defer buffer.emitDisplayChange()
|
||||
line, err := buffer.getCurrentLine()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
max := int(buffer.cursorX + 1)
|
||||
if line.wrapped && buffer.cursorX == 0 {
|
||||
//panic("wtf")
|
||||
return
|
||||
}
|
||||
|
||||
max := int(buffer.cursorX)
|
||||
if max > len(line.cells) {
|
||||
max = len(line.cells)
|
||||
}
|
||||
|
||||
line.cells = line.cells[:max]
|
||||
fmt.Printf("Erase line from cursor, cursor is at %d\n", buffer.cursorX)
|
||||
|
||||
for c := int(buffer.cursorX); c < len(line.cells); c++ {
|
||||
line.cells[c].erase()
|
||||
}
|
||||
}
|
||||
|
||||
func (buffer *Buffer) EraseDisplay() {
|
||||
|
@ -338,7 +352,7 @@ func (buffer *Buffer) EraseDisplay() {
|
|||
}
|
||||
}
|
||||
|
||||
func (buffer *Buffer) EraseDisplayAfterCursor() {
|
||||
func (buffer *Buffer) EraseDisplayFromCursor() {
|
||||
defer buffer.emitDisplayChange()
|
||||
line, err := buffer.getCurrentLine()
|
||||
if err != nil {
|
||||
|
|
|
@ -10,13 +10,16 @@ import (
|
|||
)
|
||||
|
||||
func TestOffsets(t *testing.T) {
|
||||
b := NewBuffer(10, 8, CellAttributes{})
|
||||
test := "hellothere\r\nhellothere\r\nhellothere\r\nhellothere\r\nhellothere\r\nhellothere\r\nhellothere\r\nhellothere\r\nhellothere\r\nhellothere\r\nhellothere\r\nhellothere\r\n?"
|
||||
b.Write([]rune(test)...)
|
||||
b := NewBuffer(10, 3, CellAttributes{})
|
||||
b.Write([]rune("hello\r\n")...)
|
||||
b.Write([]rune("hello\r\n")...)
|
||||
b.Write([]rune("hello\r\n")...)
|
||||
b.Write([]rune("hello\r\n")...)
|
||||
b.Write([]rune("hello")...)
|
||||
assert.Equal(t, uint16(10), b.ViewWidth())
|
||||
assert.Equal(t, uint16(10), b.Width())
|
||||
assert.Equal(t, uint16(8), b.ViewHeight())
|
||||
assert.Equal(t, 13, b.Height())
|
||||
assert.Equal(t, uint16(3), b.ViewHeight())
|
||||
assert.Equal(t, 5, b.Height())
|
||||
}
|
||||
|
||||
func TestBufferCreation(t *testing.T) {
|
||||
|
@ -126,6 +129,15 @@ func TestWritingNewLineAsFirstRuneOnWrappedLine(t *testing.T) {
|
|||
|
||||
func TestWritingNewLineAsSecondRuneOnWrappedLine(t *testing.T) {
|
||||
b := NewBuffer(3, 20, CellAttributes{})
|
||||
/*
|
||||
|abc
|
||||
|d
|
||||
|_ef
|
||||
|
|
||||
|
|
||||
|z
|
||||
*/
|
||||
|
||||
b.Write('a', 'b', 'c', 'd')
|
||||
b.Write(0x0a)
|
||||
b.Write('e', 'f')
|
||||
|
@ -136,7 +148,7 @@ func TestWritingNewLineAsSecondRuneOnWrappedLine(t *testing.T) {
|
|||
|
||||
assert.Equal(t, "abc", b.lines[0].String())
|
||||
assert.Equal(t, "d", b.lines[1].String())
|
||||
assert.Equal(t, "ef", b.lines[2].String())
|
||||
assert.Equal(t, "\x00ef", b.lines[2].String())
|
||||
assert.Equal(t, "", b.lines[3].String())
|
||||
assert.Equal(t, "", b.lines[4].String())
|
||||
assert.Equal(t, "z", b.lines[5].String())
|
||||
|
@ -366,9 +378,9 @@ func TestEraseLineAfterCursor(t *testing.T) {
|
|||
b := NewBuffer(80, 5, CellAttributes{})
|
||||
b.Write([]rune("hello, this is a test\r\ndeleted")...)
|
||||
b.MovePosition(-3, 0)
|
||||
b.EraseLineAfterCursor()
|
||||
b.EraseLineFromCursor()
|
||||
assert.Equal(t, "hello, this is a test", b.lines[0].String())
|
||||
assert.Equal(t, "delet", b.lines[1].String())
|
||||
assert.Equal(t, "dele", b.lines[1].String())
|
||||
}
|
||||
func TestEraseDisplay(t *testing.T) {
|
||||
b := NewBuffer(80, 5, CellAttributes{})
|
||||
|
@ -392,11 +404,11 @@ func TestEraseDisplayToCursor(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
func TestEraseDisplayAfterCursor(t *testing.T) {
|
||||
func TestEraseDisplayFromCursor(t *testing.T) {
|
||||
b := NewBuffer(80, 5, CellAttributes{})
|
||||
b.Write([]rune("hello\r\nasdasd\r\nthings")...)
|
||||
b.MovePosition(-3, -1)
|
||||
b.EraseDisplayAfterCursor()
|
||||
b.EraseDisplayFromCursor()
|
||||
lines := b.GetVisibleLines()
|
||||
assert.Equal(t, "hello", lines[0].String())
|
||||
assert.Equal(t, "asd", lines[1].String())
|
||||
|
|
3
main.go
3
main.go
|
@ -19,8 +19,11 @@ func getConfig() config.Config {
|
|||
if ignore {
|
||||
return config.DefaultConfig
|
||||
}
|
||||
|
||||
conf := loadConfigFile()
|
||||
flag.BoolVar(&conf.DebugMode, "debug", conf.DebugMode, "Enable debug logging")
|
||||
flag.BoolVar(&conf.Rendering.AlwaysRepaint, "always-repaint", conf.Rendering.AlwaysRepaint, "Always repaint the window, even when no changes have occurred")
|
||||
|
||||
flag.Parse()
|
||||
return conf
|
||||
}
|
||||
|
|
|
@ -1,8 +1,41 @@
|
|||
package terminal
|
||||
|
||||
// https://www.xfree86.org/4.8.0/ctlseqs.html
|
||||
// https://vt100.net/docs/vt100-ug/chapter3.html
|
||||
|
||||
var ansiSequenceMap = map[rune]escapeSequenceHandler{
|
||||
'[': csiHandler,
|
||||
0x5d: oscHandler,
|
||||
'7': saveCursorHandler,
|
||||
'8': restoreCursorHandler,
|
||||
'D': indexHandler,
|
||||
'M': reverseIndexHandler,
|
||||
}
|
||||
|
||||
func indexHandler(buffer chan rune, terminal *Terminal) error {
|
||||
// @todo is thus right?
|
||||
// "This sequence causes the active position to move downward one line without changing the column position. If the active position is at the bottom margin, a scroll up is performed."
|
||||
if terminal.buffer.CursorLine() == terminal.buffer.ViewHeight()-1 {
|
||||
terminal.buffer.NewLine()
|
||||
return nil
|
||||
}
|
||||
terminal.buffer.MovePosition(0, 1)
|
||||
return nil
|
||||
}
|
||||
|
||||
func reverseIndexHandler(buffer chan rune, terminal *Terminal) error {
|
||||
terminal.buffer.MovePosition(0, -1)
|
||||
return nil
|
||||
}
|
||||
|
||||
func saveCursorHandler(buffer chan rune, terminal *Terminal) error {
|
||||
terminal.buffer.SaveCursor()
|
||||
return nil
|
||||
}
|
||||
|
||||
func restoreCursorHandler(buffer chan rune, terminal *Terminal) error {
|
||||
terminal.buffer.RestoreCursor()
|
||||
return nil
|
||||
}
|
||||
|
||||
func ansiHandler(buffer chan rune, terminal *Terminal) error {
|
||||
|
|
|
@ -195,7 +195,7 @@ func csiEraseInDisplayHandler(params []string, intermediate string, terminal *Te
|
|||
switch n {
|
||||
|
||||
case "0", "":
|
||||
terminal.buffer.EraseDisplayAfterCursor()
|
||||
terminal.buffer.EraseDisplayFromCursor()
|
||||
case "1":
|
||||
terminal.buffer.EraseDisplayToCursor()
|
||||
case "2":
|
||||
|
@ -209,6 +209,7 @@ func csiEraseInDisplayHandler(params []string, intermediate string, terminal *Te
|
|||
|
||||
// CSI Ps K
|
||||
func csiEraseInLineHandler(params []string, intermediate string, terminal *Terminal) error {
|
||||
|
||||
n := "0"
|
||||
if len(params) > 0 {
|
||||
n = params[0]
|
||||
|
@ -216,7 +217,7 @@ func csiEraseInLineHandler(params []string, intermediate string, terminal *Termi
|
|||
|
||||
switch n {
|
||||
case "0", "": //erase adter cursor
|
||||
terminal.buffer.EraseLineAfterCursor()
|
||||
terminal.buffer.EraseLineFromCursor()
|
||||
case "1": // erase to cursor inclusive
|
||||
terminal.buffer.EraseLineToCursor()
|
||||
case "2": // erase entire
|
||||
|
|
|
@ -38,7 +38,7 @@ func (terminal *Terminal) processInput(ctx context.Context, buffer chan rune) {
|
|||
continue
|
||||
}
|
||||
|
||||
terminal.logger.Debugf("Received character 0x%X: %s", b, string(b))
|
||||
terminal.logger.Debugf("Received character 0x%X: %q", b, string(b))
|
||||
|
||||
switch b {
|
||||
case 0x0a:
|
||||
|
|
Loading…
Reference in New Issue