diff --git a/demo/clear.sh b/demo/clear.sh new file mode 100755 index 0000000..6a691da --- /dev/null +++ b/demo/clear.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +echo "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +echo "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" +echo "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" +echo "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" +echo -n "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" + +echo -ne "\x1b[A" # up +echo -ne "\x1b[D" # left +echo -ne "\x1b[A" # up +echo -ne "\x1b[D" # left +echo -ne "\x1b[A" # up +echo -ne "\x1b[D" # left +sleep 2 +echo -ne "\x1b[J0" + diff --git a/demo/colour.sh b/demo/colour.sh new file mode 100755 index 0000000..0982b35 --- /dev/null +++ b/demo/colour.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +printf " " +for b in 0 1 2 3 4 5 6 7; do printf " 4${b}m "; done +echo +for f in "" 30 31 32 33 34 35 36 37; do + for s in "" "1;"; do + printf "%4sm" "${s}${f}" + printf " \033[%sm%s\033[0m" "$s$f" "gYw " + for b in 0 1 2 3 4 5 6 7; do + printf " \033[4%s;%sm%s\033[0m" "$b" "$s$f" " gYw " + done + echo + done +done \ No newline at end of file diff --git a/demo/position.sh b/demo/position.sh new file mode 100755 index 0000000..7805666 --- /dev/null +++ b/demo/position.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +echo "ABCDEFGHIJKLM" +echo "NOPQRSTUVWXYZ" +echo "ABCDEFGHIJKLM" +echo "NOPQRSTUVWXYZ" +echo "ABCDEFGHIJKLM" +echo "NOPQRSTUVWXYZ" +echo "ABCDEFGHIJKLM" +echo "NOPQRSTUVWXYZ" +sleep 1 +echo -ne "\x1b[A" # up +sleep 1 +echo -ne "\x1b[D" # left +sleep 1 +echo -ne "\x1b[C" # right +sleep 1 +echo -ne "\x1b[C" # right +sleep 1 +echo -ne "\x1b[C" # right +sleep 1 +echo -ne "\x1b[A" # up +sleep 1 +echo -ne "\x1b[A" # up +sleep 1 +echo -ne "\x1b[B" # down +sleep 1 +echo -n "123" +sleep 1 +echo -ne "\x1b[E" # line down (col 0) +sleep 1 +echo -n "ZZZ" +sleep 1 +echo -ne "\x1b[F" # line up (col 0) +sleep 1 +echo -n "XXX" +sleep 1 +echo -ne "\x1b[E" # line down (col 0) +sleep 1 +echo \ No newline at end of file diff --git a/gui/gui.go b/gui/gui.go index 06c6074..52b96e3 100644 --- a/gui/gui.go +++ b/gui/gui.go @@ -100,7 +100,13 @@ func (gui *GUI) updateTexts() { c, err := gui.terminal.GetCellAtPos(terminal.Position{Line: row, Col: col}) - if err != nil || c == nil || c.IsHidden() { + if err != nil { + //gui.logger.Errorf("Failed to get cell: %s", err) + gui.cells[row][col].Hide() + continue + } + + if c == nil || c.IsHidden() { gui.cells[row][col].Hide() continue } @@ -176,7 +182,7 @@ func (gui *GUI) Render() error { gui.logger.Debugf("Loading font...") //if err := gui.loadFont("/usr/share/fonts/nerd-fonts-complete/ttf/Roboto Mono Nerd Font Complete.ttf", 12); err != nil { - if err := gui.loadFont("./fonts/Roboto.ttf", 12); err != nil { + if err := gui.loadFont("./fonts/Roboto.ttf", 13); err != nil { return fmt.Errorf("Failed to load font: %s", err) } diff --git a/gui/input.go b/gui/input.go index a295171..6f17671 100644 --- a/gui/input.go +++ b/gui/input.go @@ -39,6 +39,34 @@ func (gui *GUI) key(w *glfw.Window, key glfw.Key, scancode int, action glfw.Acti gui.terminal.Write([]byte{0x0a}) case glfw.KeyBackspace: gui.terminal.Write([]byte{0x08}) + case glfw.KeyUp: + gui.terminal.Write([]byte{ + 0x1b, + '[', + 'A', + }) + case glfw.KeyDown: + gui.terminal.Write([]byte{ + 0x1b, + '[', + 'B', + }) + case glfw.KeyLeft: + gui.terminal.Write([]byte{ + 0x1b, + '[', + 'D', + }) + case glfw.KeyRight: + gui.terminal.Write([]byte{ + 0x1b, + '[', + 'C', + }) + case glfw.KeyTab: + gui.terminal.Write([]byte{ + 0x09, + }) } //gui.logger.Debugf("Key pressed: 0x%X %q", key, string([]byte{byte(key)})) diff --git a/terminal/escapes.go b/terminal/escapes.go index 133d422..8a70d02 100644 --- a/terminal/escapes.go +++ b/terminal/escapes.go @@ -15,7 +15,7 @@ func (terminal *Terminal) processInput(buffer chan rune) { if b == 0x1b { // if the byte is an escape character, read the next byte to determine which one b = <-buffer switch b { - case 0x5b: // CSI: Control Sequence Introducer ] + case '[': // CSI: Control Sequence Introducer [ var final rune param := "" intermediate := "" @@ -61,7 +61,12 @@ func (terminal *Terminal) processInput(buffer chan rune) { } } - terminal.position.Line += distance + _, h := terminal.GetSize() + if terminal.position.Line+distance >= h { + terminal.position.Line = h - 1 + } else { + terminal.position.Line += distance + } case 'C': distance := 1 @@ -167,6 +172,23 @@ func (terminal *Terminal) processInput(buffer chan rune) { } switch n { + + case "1": + line := terminal.getBufferedLine(terminal.position.Line) + if line != nil { + for i := 0; i <= terminal.position.Col; i++ { + if i < len(line.Cells) { + line.Cells[i].r = ' ' + } + } + } + for i := 0; i < terminal.position.Line; i++ { + line := terminal.getBufferedLine(i) + if line != nil { + line.Cells = []Cell{} + } + } + case "0", "": line := terminal.getBufferedLine(terminal.position.Line) if line != nil { @@ -179,19 +201,7 @@ func (terminal *Terminal) processInput(buffer chan rune) { line.Cells = []Cell{} } } - case "1": - line := terminal.getBufferedLine(terminal.position.Line) - if line != nil { - for i := 0; i < terminal.position.Col; i++ { - line.Cells[i].r = 0 - } - } - for i := 0; i < terminal.position.Line; i++ { - line := terminal.getBufferedLine(i) - if line != nil { - line.Cells = []Cell{} - } - } + case "2": _, h := terminal.GetSize() for i := 0; i < h; i++ { @@ -206,6 +216,7 @@ func (terminal *Terminal) processInput(buffer chan rune) { terminal.lines = []Line{} terminal.position.Col = 0 terminal.position.Line = 0 + default: terminal.logger.Errorf("Unknown CSI ED sequence: %s", n) } @@ -217,20 +228,20 @@ func (terminal *Terminal) processInput(buffer chan rune) { } switch n { - case "0", "": - line := terminal.getBufferedLine(terminal.position.Line) - if line != nil { - if terminal.position.Col < len(line.Cells) { - line.Cells = line.Cells[:terminal.position.Col] - } - } case "1": line := terminal.getBufferedLine(terminal.position.Line) if line != nil { - for i := 0; i < terminal.position.Col; i++ { - line.Cells[i].r = 0 + for i := 0; i <= terminal.position.Col; i++ { + if i < len(line.Cells) { + line.Cells[i].r = ' ' + } } } + case "0", "": + line := terminal.getBufferedLine(terminal.position.Line) + if line != nil { + line.Cells = line.Cells[:terminal.position.Col] + } case "2": line := terminal.getBufferedLine(terminal.position.Line) if line != nil { @@ -247,17 +258,17 @@ func (terminal *Terminal) processInput(buffer chan rune) { switch param { case "0", "": terminal.cellAttr = terminal.defaultCellAttr - case "1": + case "1", "01": terminal.cellAttr.Bold = true - case "2": + case "2", "02": terminal.cellAttr.Dim = true - case "4": + case "4", "04": terminal.cellAttr.Underline = true - case "5": + case "5", "05": terminal.cellAttr.Blink = true - case "7": + case "7", "07": terminal.cellAttr.Reverse = true - case "8": + case "8", "08": terminal.cellAttr.Hidden = true case "21": terminal.cellAttr.Bold = false @@ -288,7 +299,7 @@ func (terminal *Terminal) processInput(buffer chan rune) { case "36": terminal.cellAttr.FgColour = terminal.colourScheme.CyanFg case "37": - terminal.cellAttr.FgColour = terminal.colourScheme.LightGreyFg + terminal.cellAttr.FgColour = terminal.colourScheme.WhiteFg case "90": terminal.cellAttr.FgColour = terminal.colourScheme.DarkGreyFg case "91": @@ -322,7 +333,7 @@ func (terminal *Terminal) processInput(buffer chan rune) { case "46": terminal.cellAttr.BgColour = terminal.colourScheme.CyanBg case "47": - terminal.cellAttr.BgColour = terminal.colourScheme.LightGreenBg + terminal.cellAttr.BgColour = terminal.colourScheme.WhiteBg case "100": terminal.cellAttr.BgColour = terminal.colourScheme.DarkGreyBg case "101": @@ -344,7 +355,7 @@ func (terminal *Terminal) processInput(buffer chan rune) { terminal.logger.Errorf("Unknown SGR control sequence: (ESC[%s%s%s)", param, intermediate, string(final)) } - terminal.logger.Debugf("SGR control sequence: (ESC[%s%s%s)", param, intermediate, string(final)) + //terminal.logger.Debugf("SGR control sequence: (ESC[%s%s%s)", param, intermediate, string(final)) } default: @@ -353,6 +364,10 @@ func (terminal *Terminal) processInput(buffer chan rune) { terminal.showCursor() case "?25l": terminal.hideCursor() + case "?12h": + // todo enable cursor blink + case "?12l": + // todo disable cursor blink default: terminal.logger.Errorf("Unknown CSI control sequence: 0x%02X (ESC[%s%s%s)", final, param, intermediate, string(final)) } @@ -396,12 +411,14 @@ func (terminal *Terminal) processInput(buffer chan rune) { switch b { case 0x0a: - terminal.position.Line++ + _, h := terminal.GetSize() - if terminal.position.Line >= h { - terminal.position.Line-- + if terminal.position.Line+1 >= h { + terminal.lines = append(terminal.lines, NewLine()) + } else { + terminal.position.Line++ } - terminal.lines = append(terminal.lines, NewLine()) + case 0x0d: terminal.position.Col = 0 case 0x08: diff --git a/terminal/terminal.go b/terminal/terminal.go index e00189d..1d4f195 100644 --- a/terminal/terminal.go +++ b/terminal/terminal.go @@ -105,6 +105,7 @@ func New(pty *os.File, logger *zap.SugaredLogger, colourScheme ColourScheme) *Te cellAttr: defaultCellAttr, defaultCellAttr: defaultCellAttr, colourScheme: colourScheme, + cursorVisible: true, } } @@ -246,10 +247,6 @@ func (terminal *Terminal) setRuneAtPos(pos Position, r rune) error { return fmt.Errorf("Col %d does not exist", pos.Col) } - if pos.Line == 0 && pos.Col == 0 { - fmt.Printf("\n\nSetting %d %d to %q\n\n\n", pos.Line, pos.Col, string(r)) - } - for terminal.position.Line >= len(terminal.lines) { terminal.lines = append(terminal.lines, NewLine()) } diff --git a/vendor/github.com/4ydx/gltext/v4.1/text.go b/vendor/github.com/4ydx/gltext/v4.1/text.go index b6761a1..69aa333 100644 --- a/vendor/github.com/4ydx/gltext/v4.1/text.go +++ b/vendor/github.com/4ydx/gltext/v4.1/text.go @@ -6,6 +6,7 @@ package v41 import ( "fmt" + "github.com/4ydx/gltext" "github.com/go-gl/gl/v4.1-core/gl" "github.com/go-gl/mathgl/mgl32"