From 88528fc6b08898da75c4ae7ac7fa346f5e67e4e3 Mon Sep 17 00:00:00 2001 From: Liam Galvin Date: Fri, 24 Aug 2018 17:32:08 +0100 Subject: [PATCH] efficiency, introduced resize bug though :/ --- README.md | 2 +- buffer/cell.go | 14 ++- buffer/cell_test.go | 18 --- gui/gui.go | 150 +++++++++++++++++-------- gui/renderer.go | 103 ++++++++--------- gui/renderstate.go | 58 ++++++++++ terminal/ansi.go | 102 +++++------------ terminal/csi.go | 10 +- terminal/output.go | 75 +++++++++---- terminal/terminal.go | 7 ++ vendor/github.com/liamg/glfont/font.go | 4 +- 11 files changed, 313 insertions(+), 230 deletions(-) delete mode 100644 buffer/cell_test.go create mode 100644 gui/renderstate.go diff --git a/README.md b/README.md index 7387788..c7fae97 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Ensure you have your latest graphics card drivers installed before use. ## What isn't supported? -- Suspend/Continue (^S, ^Q). This is archaic bullshit that annoys more people than it helps. Basically: +- Suspend/Continue (\^S, \^Q). This is archaic bullshit that annoys more people than it helps. Basically:q ![Overheating](https://imgs.xkcd.com/comics/workflow.png) diff --git a/buffer/cell.go b/buffer/cell.go index f736691..b3a0867 100644 --- a/buffer/cell.go +++ b/buffer/cell.go @@ -1,9 +1,8 @@ package buffer type Cell struct { - r rune - attr CellAttributes - hasContent bool + r rune + attr CellAttributes } type CellAttributes struct { @@ -43,5 +42,12 @@ func (cell *Cell) erase() { func (cell *Cell) setRune(r rune) { cell.r = r - cell.hasContent = r > 0 +} + +func NewBackgroundCell(colour [3]float32) Cell { + return Cell{ + attr: CellAttributes{ + BgColour: colour, + }, + } } diff --git a/buffer/cell_test.go b/buffer/cell_test.go deleted file mode 100644 index 607a659..0000000 --- a/buffer/cell_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package buffer - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestSetRune(t *testing.T) { - cell := newCell() - assert.False(t, cell.hasContent) - cell.setRune('X') - assert.True(t, cell.hasContent) - assert.Equal(t, 'X', cell.r) - cell.setRune('Y') - assert.True(t, cell.hasContent) - assert.Equal(t, 'Y', cell.r) -} diff --git a/gui/gui.go b/gui/gui.go index 080caab..a99e288 100644 --- a/gui/gui.go +++ b/gui/gui.go @@ -9,34 +9,37 @@ import ( "github.com/go-gl/gl/all-core/gl" "github.com/go-gl/glfw/v3.2/glfw" + "gitlab.com/liamg/raft/buffer" "gitlab.com/liamg/raft/config" "gitlab.com/liamg/raft/terminal" "go.uber.org/zap" ) type GUI struct { - window *glfw.Window - logger *zap.SugaredLogger - config *config.Config - terminal *terminal.Terminal - width int //window width in pixels - height int //window height in pixels - font *glfont.Font - fontScale int32 - renderer Renderer - colourAttr uint32 + window *glfw.Window + logger *zap.SugaredLogger + config *config.Config + terminal *terminal.Terminal + width int //window width in pixels + height int //window height in pixels + font *glfont.Font + fontScale int32 + renderer Renderer + colourAttr uint32 + renderState *RenderState } func New(config *config.Config, terminal *terminal.Terminal, logger *zap.SugaredLogger) *GUI { //logger. return &GUI{ - config: config, - logger: logger, - width: 600, - height: 300, - terminal: terminal, - fontScale: 15.0, + config: config, + logger: logger, + width: 600, + height: 300, + terminal: terminal, + fontScale: 15.0, + renderState: NewRenderState(), } } @@ -45,25 +48,39 @@ func New(config *config.Config, terminal *terminal.Terminal, logger *zap.Sugared // can only be called on OS thread func (gui *GUI) resize(w *glfw.Window, width int, height int) { - gui.logger.Debugf("GUI resize to %dx%d", width, height) + if width == gui.width && height == gui.height { + //return + } + + gui.logger.Debugf("Initiating GUI resize to %dx%d", width, height) gui.width = width gui.height = height + gui.logger.Debugf("Updating font resolution...") if gui.font != nil { gui.font.UpdateResolution((width), (height)) } - gl.Viewport(0, 0, int32(gui.width), int32(gui.height)) - + gui.logger.Debugf("Setting renderer area...") gui.renderer.SetArea(0, 0, gui.width, gui.height) + gui.logger.Debugf("Calculating size in cols/rows...") cols, rows := gui.renderer.GetTermSize() + gui.logger.Debugf("Resizing internal terminal...") if err := gui.terminal.SetSize(cols, rows); err != nil { gui.logger.Errorf("Failed to resize terminal to %d cols, %d rows: %s", cols, rows, err) } + gui.logger.Debugf("Resetting render state...") + gui.renderState.Reset() + + gui.logger.Debugf("Setting viewport size...") + gl.Viewport(0, 0, int32(gui.width), int32(gui.height)) + + gui.logger.Debugf("Resize complete!") + } func (gui *GUI) glfwScrollCallback(w *glfw.Window, xoff float64, yoff float64) { @@ -93,7 +110,7 @@ func (gui *GUI) Render() error { gui.logger.Debugf("Creating window...") var err error - gui.window, err = gui.createWindow(gui.width, gui.height) + gui.window, err = gui.createWindow(500, 300) if err != nil { return fmt.Errorf("Failed to create window: %s", err) } @@ -172,37 +189,79 @@ func (gui *GUI) Render() error { gui.terminal.AttachTitleChangeHandler(titleChan) gui.terminal.AttachDisplayChangeHandler(changeChan) - frames := 0 - frameCount := 0 - fps := 0 + gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) + ticker := time.NewTicker(time.Second) defer ticker.Stop() + dirty := true + defaultCell := buffer.NewBackgroundCell(gui.config.ColourScheme.Background) + + var lastCursorX uint + var lastCursorY uint + for !gui.window.ShouldClose() { select { - case <-changeChan: - frames = 2 + case <-ticker.C: gui.logger.Sync() + case <-changeChan: + dirty = true case <-titleChan: gui.window.SetTitle(gui.terminal.GetTitle()) - case <-ticker.C: - fps = frameCount - frameCount = 0 default: } gl.UseProgram(program) - if gui.config.Rendering.AlwaysRepaint || frames > 0 { + if dirty { + gui.window.SwapBuffers() + dirty = false + } - gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) + if gui.terminal.CheckDirty() { + + if gui.terminal.Modes().ShowCursor { + cx := uint(gui.terminal.GetLogicalCursorX()) + cy := uint(gui.terminal.GetLogicalCursorY()) + cy = cy + uint(gui.terminal.GetScrollOffset()) + + if lastCursorX != cx || lastCursorY != cy { + gui.renderState.SetDirty(lastCursorX, lastCursorY) + dirty = true + } + } else { + gui.renderState.SetDirty(lastCursorX, lastCursorY) + dirty = true + } lines := gui.terminal.GetVisibleLines() - for y := 0; y < len(lines); y++ { - for x, cell := range lines[y].Cells() { - gui.renderer.DrawCell(cell, uint(x), uint(y)) + lineCount := gui.terminal.ActiveBuffer().ViewHeight() + colCount := gui.terminal.ActiveBuffer().ViewWidth() + for y := 0; y < int(lineCount); y++ { + + for x := 0; x < int(colCount); x++ { + + cell := defaultCell + empty := true + + if y < len(lines) { + cells := lines[y].Cells() + if x < len(cells) { + cell = cells[x] + if cell.Rune() == 0 { + cell = defaultCell + } + empty = false + } + } + + if gui.renderState.RequiresRender(uint(x), uint(y), cell.Bg(), cell.Fg(), cell.Rune(), empty) { + gui.renderer.DrawCell(cell, uint(x), uint(y)) + dirty = true + } + } } @@ -210,26 +269,19 @@ func (gui *GUI) Render() error { cx := uint(gui.terminal.GetLogicalCursorX()) cy := uint(gui.terminal.GetLogicalCursorY()) cy = cy + uint(gui.terminal.GetScrollOffset()) - gui.renderer.DrawCursor(cx, cy, gui.config.ColourScheme.Cursor) + + if lastCursorX != cx || lastCursorY != cy { + gui.renderer.DrawCursor(cx, cy, gui.config.ColourScheme.Cursor) + gui.renderState.SetDirty(lastCursorX, lastCursorY) + lastCursorX = cx + lastCursorY = cy + dirty = true + } } - _ = fps - /* - gui.font.SetColor(1, 0.5, 0.5, 0.5) - fpsData := "" - if gui.config.Rendering.AlwaysRepaint { - fpsData = fmt.Sprintf("%d FPS | %d,%d", fps, gui.terminal.GetLogicalCursorX(), gui.terminal.GetLogicalCursorY()) - } - gui.font.Print(10, float32(gui.height-20), 1.5, fmt.Sprintf("%s", fpsData)) - */ - } - - if gui.config.Rendering.AlwaysRepaint || frames > 0 { - gui.window.SwapBuffers() - frameCount++ - frames-- } + //glfw.PollEvents() glfw.WaitEventsTimeout(0.02) // up to 50fps on no input, otherwise higher } diff --git a/gui/renderer.go b/gui/renderer.go index 4410eec..29da7d1 100644 --- a/gui/renderer.go +++ b/gui/renderer.go @@ -43,6 +43,7 @@ type rectangle struct { colourAttr uint32 colour [3]float32 points []float32 + prog uint32 } func (r *OpenGLRenderer) newRectangle(x float32, y float32, colourAttr uint32) *rectangle { @@ -53,7 +54,6 @@ func (r *OpenGLRenderer) newRectangle(x float32, y float32, colourAttr uint32) * h := r.cellHeight / float32(r.areaHeight/2) rect := &rectangle{ - colour: [3]float32{0, 0, 1}, points: []float32{ x, y, 0, x, y + h, 0, @@ -64,24 +64,8 @@ func (r *OpenGLRenderer) newRectangle(x float32, y float32, colourAttr uint32) * x + w, y + h, 0, }, colourAttr: colourAttr, + prog: r.program, } - - rect.gen() - - return rect -} - -func (rect *rectangle) gen() { - - colour := []float32{ - rect.colour[0], rect.colour[1], rect.colour[2], - rect.colour[0], rect.colour[1], rect.colour[2], - rect.colour[0], rect.colour[1], rect.colour[2], - rect.colour[0], rect.colour[1], rect.colour[2], - rect.colour[0], rect.colour[1], rect.colour[2], - rect.colour[0], rect.colour[1], rect.colour[2], - } - // SHAPE gl.GenBuffers(1, &rect.vbo) gl.BindBuffer(gl.ARRAY_BUFFER, rect.vbo) @@ -96,22 +80,37 @@ func (rect *rectangle) gen() { // colour gl.GenBuffers(1, &rect.cv) - gl.BindBuffer(gl.ARRAY_BUFFER, rect.cv) - gl.BufferData(gl.ARRAY_BUFFER, len(colour)*4, gl.Ptr(colour), gl.STATIC_DRAW) - gl.EnableVertexAttribArray(rect.colourAttr) - gl.VertexAttribPointer(rect.colourAttr, 3, gl.FLOAT, false, 0, gl.PtrOffset(0)) + + rect.setColour([3]float32{0, 1, 0}) + + return rect } func (rect *rectangle) setColour(colour [3]float32) { if rect.colour == colour { return } - rect.Free() + + c := []float32{ + colour[0], colour[1], colour[2], + colour[0], colour[1], colour[2], + colour[0], colour[1], colour[2], + colour[0], colour[1], colour[2], + colour[0], colour[1], colour[2], + colour[0], colour[1], colour[2], + } + + gl.UseProgram(rect.prog) + gl.BindBuffer(gl.ARRAY_BUFFER, rect.cv) + gl.BufferData(gl.ARRAY_BUFFER, len(c)*4, gl.Ptr(c), gl.STATIC_DRAW) + gl.EnableVertexAttribArray(rect.colourAttr) + gl.VertexAttribPointer(rect.colourAttr, 3, gl.FLOAT, false, 0, gl.PtrOffset(0)) + rect.colour = colour - rect.gen() } func (rect *rectangle) Free() { + gl.UseProgram(rect.prog) gl.DeleteVertexArrays(1, &rect.vao) gl.DeleteBuffers(1, &rect.vbo) gl.DeleteBuffers(1, &rect.cv) @@ -159,7 +158,6 @@ func (r *OpenGLRenderer) SetFont(font *glfont.Font) { // @todo check for monospa r.termCols = uint(math.Floor(float64(float32(r.areaWidth) / r.cellWidth))) r.termRows = uint(math.Floor(float64(float32(r.areaHeight) / r.cellHeight))) r.calculatePositions() - r.generateRectangles() } func (r *OpenGLRenderer) calculatePositions() { @@ -175,22 +173,27 @@ func (r *OpenGLRenderer) calculatePositions() { } } -func (r *OpenGLRenderer) generateRectangles() { - gl.UseProgram(r.program) - for line := uint(0); line < r.termRows; line++ { - for col := uint(0); col < r.termCols; col++ { - - rect, ok := r.rectangles[[2]uint{col, line}] - if ok { - rect.Free() - } - - // rounding to whole pixels makes everything nice - x := float32(float64((float32(col) * r.cellWidth))) - y := float32(float64((float32(line) * r.cellHeight) + (r.cellHeight))) - r.rectangles[[2]uint{col, line}] = r.newRectangle(x, y, r.colourAttr) - } +func (r *OpenGLRenderer) getRectangle(col uint, row uint) *rectangle { + if rect, ok := r.rectangles[[2]uint{col, row}]; ok { + return rect } + return r.generateRectangle(col, row) +} + +func (r *OpenGLRenderer) generateRectangle(col uint, line uint) *rectangle { + + gl.UseProgram(r.program) + + rect, ok := r.rectangles[[2]uint{col, line}] + if ok { + rect.Free() + } + + // rounding to whole pixels makes everything nice + x := float32(float32(col) * r.cellWidth) + y := float32((float32(line) * r.cellHeight) + (r.cellHeight)) + r.rectangles[[2]uint{col, line}] = r.newRectangle(x, y, r.colourAttr) + return r.rectangles[[2]uint{col, line}] } func (r *OpenGLRenderer) DrawCursor(col uint, row uint, colour config.Colour) { @@ -220,10 +223,6 @@ func (r *OpenGLRenderer) DrawCursor(col uint, row uint, colour config.Colour) { func (r *OpenGLRenderer) DrawCell(cell buffer.Cell, col uint, row uint) { - if cell.Attr().Hidden || (cell.Rune() == 0x00) { - return - } - var fg [3]float32 var bg [3]float32 @@ -241,18 +240,10 @@ func (r *OpenGLRenderer) DrawCell(cell buffer.Cell, col uint, row uint) { } gl.UseProgram(r.program) - - // don't bother rendering rectangles that are the same colour as the background - if bg != r.config.ColourScheme.Background { - - rect, ok := r.rectangles[[2]uint{col, row}] - if !ok { - panic(fmt.Sprintf("Missing rectangle data for cell at %d,%d", col, row)) - } - rect.setColour(bg) - gl.BindVertexArray(rect.vao) - gl.DrawArrays(gl.TRIANGLE_STRIP, 0, 6) - } + rect := r.getRectangle(col, row) + rect.setColour(bg) + gl.BindVertexArray(rect.vao) + gl.DrawArrays(gl.TRIANGLES, 0, 6) var alpha float32 = 1 if cell.Attr().Dim { diff --git a/gui/renderstate.go b/gui/renderstate.go new file mode 100644 index 0000000..2412633 --- /dev/null +++ b/gui/renderstate.go @@ -0,0 +1,58 @@ +package gui + +type RenderState struct { + cells map[[2]uint]RenderedCell +} + +func NewRenderState() *RenderState { + return &RenderState{ + cells: map[[2]uint]RenderedCell{}, + } +} + +type RenderedCell struct { + bg [3]float32 + fg [3]float32 + contents rune + dirty bool +} + +func (rs *RenderState) Reset() { + rs.cells = map[[2]uint]RenderedCell{} +} + +func (rs *RenderState) SetDirty(x uint, y uint) { + rs.cells[[2]uint{x, y}] = RenderedCell{ + bg: [3]float32{0, 0, 0}, + fg: [3]float32{0, 0, 0}, + contents: 0, + dirty: true, + } +} + +func (rs *RenderState) RequiresRender(x uint, y uint, bg [3]float32, fg [3]float32, contents rune, empty bool) bool { + + state, found := rs.cells[[2]uint{x, y}] + if !found { + if empty { + //return false + } + rs.cells[[2]uint{x, y}] = RenderedCell{ + bg: bg, + fg: fg, + contents: contents, + } + return true + } + + if state.bg != bg || state.fg != fg || state.contents != contents || state.dirty { + rs.cells[[2]uint{x, y}] = RenderedCell{ + bg: bg, + fg: fg, + contents: contents, + } + return true + } + + return false +} diff --git a/terminal/ansi.go b/terminal/ansi.go index e043fe0..089f314 100644 --- a/terminal/ansi.go +++ b/terminal/ansi.go @@ -1,18 +1,36 @@ package terminal +import "fmt" + // 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, + '[': csiHandler, + ']': oscHandler, + '7': saveCursorHandler, + '8': restoreCursorHandler, + 'D': indexHandler, + 'M': reverseIndexHandler, + 'c': swallowHandler(0), //RIS + '(': swallowHandler(1), // character set bullshit + ')': swallowHandler(1), // character set bullshit + '*': swallowHandler(1), // character set bullshit + '+': swallowHandler(1), // character set bullshit + '>': swallowHandler(0), // numeric char selection //@todo + '=': swallowHandler(0), // alt char selection //@todo } -func indexHandler(buffer chan rune, terminal *Terminal) error { +func swallowHandler(n int) func(pty chan rune, terminal *Terminal) error { + return func(pty chan rune, terminal *Terminal) error { + for i := 0; i < n; i++ { + <-pty + } + return nil + } +} + +func indexHandler(pty 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.ActiveBuffer().CursorLine() == terminal.ActiveBuffer().ViewHeight()-1 { @@ -23,17 +41,17 @@ func indexHandler(buffer chan rune, terminal *Terminal) error { return nil } -func reverseIndexHandler(buffer chan rune, terminal *Terminal) error { +func reverseIndexHandler(pty chan rune, terminal *Terminal) error { terminal.ActiveBuffer().MovePosition(0, -1) return nil } -func saveCursorHandler(buffer chan rune, terminal *Terminal) error { +func saveCursorHandler(pty chan rune, terminal *Terminal) error { terminal.ActiveBuffer().SaveCursor() return nil } -func restoreCursorHandler(buffer chan rune, terminal *Terminal) error { +func restoreCursorHandler(pty chan rune, terminal *Terminal) error { terminal.ActiveBuffer().RestoreCursor() return nil } @@ -47,67 +65,5 @@ func ansiHandler(pty chan rune, terminal *Terminal) error { return handler(pty, terminal) } - switch b { - - case 'c': - terminal.logger.Errorf("RIS not yet supported") - case '(': - b = <-pty - switch b { - case 'A': //uk @todo handle these? - //terminal.charSet = C0 - case 'B': //us - //terminal.charSet = C0 - } - case ')': - b = <-pty - switch b { - case 'A': //uk @todo handle these? - //terminal.charSet = C1 - case 'B': //us - //terminal.charSet = C1 - } - case '*': - b = <-pty - switch b { - case 'A': //uk @todo handle these? - //terminal.charSet = C2 - case 'B': //us - //terminal.charSet = C2 - } - case '+': - b = <-pty - switch b { - case 'A': //uk @todo handle these? - //terminal.charSet = C3 - case 'B': //us - //terminal.charSet = C3 - } - case '>': - // numeric char selection @todo - case '=': - //alternate char selection @todo - case '?': - pm := "" - for { - b = <-pty - switch b { - case 'h': - switch pm { - default: - terminal.logger.Errorf("Unknown private code ESC?%sh", pm) - } - case 'l': - switch pm { - default: - terminal.logger.Errorf("Unknown private code ESC?%sl", pm) - } - default: - pm += string(b) - } - } - default: - terminal.logger.Errorf("Unknown control sequence: 0x%02X [%s]", b, string(b)) - } - return nil + return fmt.Errorf("Unknown ANSI control sequence byte: 0x%02X [%v]", b, string(b)) } diff --git a/terminal/csi.go b/terminal/csi.go index 72d1db7..8178d3e 100644 --- a/terminal/csi.go +++ b/terminal/csi.go @@ -98,7 +98,7 @@ func csiSetMode(modeStr string, enabled bool, terminal *Terminal) error { } else { terminal.UseMainBuffer() } - case "?1000", "?10061000": // ?10061000 seen from htop + case "?1000", "?1006;1000", "?10061000": // ?10061000 seen from htop // enable mouse tracking if enabled { terminal.SetMouseMode(MouseModeVT200) @@ -153,16 +153,16 @@ func csiWindowManipulation(params []string, intermediate string, terminal *Termi } func csiLinePositionAbsolute(params []string, intermediate string, terminal *Terminal) error { - col := 1 + row := 1 if len(params) > 0 { var err error - col, err = strconv.Atoi(params[0]) + row, err = strconv.Atoi(params[0]) if err != nil { - col = 1 + row = 1 } } - terminal.ActiveBuffer().SetPosition(uint16(col), terminal.ActiveBuffer().CursorLine()) + terminal.ActiveBuffer().SetPosition(terminal.ActiveBuffer().CursorColumn(), uint16(row-1)) return nil } diff --git a/terminal/output.go b/terminal/output.go index ba79ec6..318823c 100644 --- a/terminal/output.go +++ b/terminal/output.go @@ -12,9 +12,59 @@ type TerminalCharSet int type escapeSequenceHandler func(pty chan rune, terminal *Terminal) error var escapeSequenceMap = map[rune]escapeSequenceHandler{ + 0x05: enqSequenceHandler, + 0x07: bellSequenceHandler, + 0x08: backspaceSequenceHandler, + 0x09: tabSequenceHandler, + 0x0a: newLineSequenceHandler, + 0x0b: newLineSequenceHandler, + 0x0c: newLineSequenceHandler, + 0x0d: carriageReturnSequenceHandler, + 0x0e: shiftOutSequenceHandler, + 0x0f: shiftInSequenceHandler, 0x1b: ansiHandler, } +func newLineSequenceHandler(pty chan rune, terminal *Terminal) error { + terminal.ActiveBuffer().NewLine() + return nil +} + +func carriageReturnSequenceHandler(pty chan rune, terminal *Terminal) error { + terminal.ActiveBuffer().CarriageReturn() + return nil +} + +func backspaceSequenceHandler(pty chan rune, terminal *Terminal) error { + terminal.ActiveBuffer().Backspace() + return nil +} + +func bellSequenceHandler(pty chan rune, terminal *Terminal) error { + // @todo ring bell - flash red or some shit? + return nil +} + +func enqSequenceHandler(pty chan rune, terminal *Terminal) error { + terminal.logger.Errorf("Received ENQ!") + return nil +} + +func shiftOutSequenceHandler(pty chan rune, terminal *Terminal) error { + terminal.logger.Errorf("Received shift out") + return nil +} + +func shiftInSequenceHandler(pty chan rune, terminal *Terminal) error { + terminal.logger.Errorf("Received shift in") + return nil +} + +func tabSequenceHandler(pty chan rune, terminal *Terminal) error { + terminal.logger.Errorf("Received tab") + return nil +} + func (terminal *Terminal) processInput(ctx context.Context, pty chan rune) { // https://en.wikipedia.org/wiki/ANSI_escape_code @@ -43,28 +93,8 @@ func (terminal *Terminal) processInput(ctx context.Context, pty chan rune) { if err := handler(pty, terminal); err != nil { terminal.logger.Errorf("Error handling escape sequence: %s", err) } - continue - } - - terminal.logger.Debugf("Received character 0x%X: %q", b, string(b)) - - switch b { - case 0x0a, 0x0c, 0x0b: // LF, FF, VT - terminal.ActiveBuffer().NewLine() - case 0x0d: // CR - terminal.ActiveBuffer().CarriageReturn() - case 0x08: // BS - // backspace - terminal.ActiveBuffer().Backspace() - case 0x07: // BEL - // @todo ring bell - flash red or some shit? - case 0x05: // ENQ - terminal.logger.Errorf("Received ENQ!") - case 0xe, 0xf: - terminal.logger.Errorf("Received SI/SO") - case 0x09: - terminal.logger.Errorf("Received TAB") - default: + } else { + terminal.logger.Debugf("Received character 0x%X: %q", b, string(b)) if b >= 0x20 { terminal.ActiveBuffer().Write(b) } else { @@ -72,5 +102,6 @@ func (terminal *Terminal) processInput(ctx context.Context, pty chan rune) { } } + terminal.isDirty = true } } diff --git a/terminal/terminal.go b/terminal/terminal.go index a5f5fca..6846153 100644 --- a/terminal/terminal.go +++ b/terminal/terminal.go @@ -45,6 +45,7 @@ type Terminal struct { resumeChan chan bool modes Modes mouseMode MouseMode + isDirty bool } type Modes struct { @@ -90,6 +91,12 @@ func New(pty *os.File, logger *zap.SugaredLogger, config *config.Config) *Termin } } +func (terminal *Terminal) CheckDirty() bool { + d := terminal.isDirty + terminal.isDirty = false + return d +} + func (terminal *Terminal) IsApplicationCursorKeysModeEnabled() bool { return terminal.modes.ApplicationCursorKeys } diff --git a/vendor/github.com/liamg/glfont/font.go b/vendor/github.com/liamg/glfont/font.go index 20617a6..802e097 100644 --- a/vendor/github.com/liamg/glfont/font.go +++ b/vendor/github.com/liamg/glfont/font.go @@ -219,7 +219,7 @@ func (f *Font) Height(scale float32, text string) float32 { baseHeight = height height = 0 } - + //skip runes that are not in font chacter range if int(runeIndex)-int(lowChar) > len(f.fontChar) || runeIndex < lowChar { continue @@ -229,7 +229,7 @@ func (f *Font) Height(scale float32, text string) float32 { ch := f.fontChar[runeIndex-lowChar] // Now advance cursors for next glyph (note that advance is number of 1/64 pixels) - if float32(ch.height) * scale > height { + if float32(ch.height)*scale > height { height = float32(ch.height) * scale }