diff --git a/buffer/buffer.go b/buffer/buffer.go index 57a09c0..3a53a3b 100644 --- a/buffer/buffer.go +++ b/buffer/buffer.go @@ -182,6 +182,26 @@ func (buffer *Buffer) incrementCursorPosition() { } } +func (buffer *Buffer) Backspace() { + if buffer.cursorX == 0 { + line := buffer.getCurrentLine() + if line.wrapped { + buffer.MovePosition(int16(buffer.Width()-1), -1) + if int(buffer.cursorX) < len(line.cells) { + line.cells[buffer.cursorX].erase() + } + } else { + //@todo ring bell or whatever + } + } else { + buffer.MovePosition(-1, 0) + line := buffer.getCurrentLine() + if int(buffer.cursorX) < len(line.cells) { + line.cells[buffer.cursorX].erase() + } + } +} + func (buffer *Buffer) CarriageReturn() { defer buffer.emitDisplayChange() buffer.cursorX = 0 diff --git a/config/config.go b/config/config.go index 87e5b41..d7c7941 100644 --- a/config/config.go +++ b/config/config.go @@ -9,6 +9,7 @@ type Config struct { DebugMode bool `yaml:"debug"` ColourScheme terminal.ColourScheme Rendering RenderingConfig `yaml:"rendering"` + Slomo bool `yaml:"slomo"` } type RenderingConfig struct { diff --git a/gui/input.go b/gui/input.go index cc473c7..b356e78 100644 --- a/gui/input.go +++ b/gui/input.go @@ -30,6 +30,10 @@ func (gui *GUI) key(w *glfw.Window, key glfw.Key, scancode int, action glfw.Acti case glfw.KeyC: // ctrl^c gui.logger.Debugf("Sending CTRL^C") gui.terminal.Write([]byte{0x3}) // send EOT + case glfw.KeyS: + gui.terminal.Suspend() + case glfw.KeyQ: + gui.terminal.Resume() } } } diff --git a/main.go b/main.go index 05efcab..3e12563 100644 --- a/main.go +++ b/main.go @@ -22,6 +22,7 @@ func getConfig() config.Config { conf := loadConfigFile() flag.BoolVar(&conf.DebugMode, "debug", conf.DebugMode, "Enable debug logging") + flag.BoolVar(&conf.Slomo, "slomo", conf.Slomo, "Render in slow motion (useful for debugging)") flag.BoolVar(&conf.Rendering.AlwaysRepaint, "always-repaint", conf.Rendering.AlwaysRepaint, "Always repaint the window, even when no changes have occurred") flag.Parse() diff --git a/terminal/escapes.go b/terminal/escapes.go index 1f1a4e0..c7470e5 100644 --- a/terminal/escapes.go +++ b/terminal/escapes.go @@ -2,7 +2,6 @@ package terminal import ( "context" - "fmt" ) // Wish list here: http://invisible-island.net/xterm/ctlseqs/ctlseqs.html @@ -15,6 +14,20 @@ var escapeSequenceMap = map[rune]escapeSequenceHandler{ 0x1b: ansiHandler, } +func (terminal *Terminal) Suspend() { + select { + case terminal.pauseChan <- true: + default: + } +} + +func (terminal *Terminal) Resume() { + select { + case terminal.resumeChan <- true: + default: + } +} + func (terminal *Terminal) processInput(ctx context.Context, buffer chan rune) { // https://en.wikipedia.org/wiki/ANSI_escape_code @@ -22,18 +35,25 @@ func (terminal *Terminal) processInput(ctx context.Context, buffer chan rune) { for { select { + case <-terminal.pauseChan: + // @todo alert user when terminal is suspended + terminal.logger.Debugf("Terminal suspended") + <-terminal.resumeChan case <-ctx.Done(): break default: } + //if terminal.config.slomo + //time.Sleep(time.Millisecond * 100) + b := <-buffer handler, ok := escapeSequenceMap[b] if ok { if err := handler(buffer, terminal); err != nil { - fmt.Errorf("Error handling escape sequence 0x%X: %s", b, err) + terminal.logger.Errorf("Error handling escape sequence 0x%X: %s", b, err) } continue } @@ -47,7 +67,7 @@ func (terminal *Terminal) processInput(ctx context.Context, buffer chan rune) { terminal.buffer.CarriageReturn() case 0x08: // backspace - terminal.buffer.MovePosition(-1, 0) + terminal.buffer.Backspace() case 0x07: // @todo ring bell - flash red or some shit? default: diff --git a/terminal/terminal.go b/terminal/terminal.go index baace09..2b9d92c 100644 --- a/terminal/terminal.go +++ b/terminal/terminal.go @@ -11,6 +11,7 @@ import ( "unsafe" "gitlab.com/liamg/raft/buffer" + "gitlab.com/liamg/raft/config" "go.uber.org/zap" ) @@ -21,8 +22,10 @@ type Terminal struct { logger *zap.SugaredLogger title string size Winsize - colourScheme ColourScheme + config config.Config titleHandlers []chan bool + pauseChan chan bool + resumeChan chan bool } type Line struct { @@ -42,7 +45,7 @@ type Position struct { Col int } -func New(pty *os.File, logger *zap.SugaredLogger, colourScheme ColourScheme) *Terminal { +func New(pty *os.File, logger *zap.SugaredLogger, config config.Config) *Terminal { return &Terminal{ buffer: buffer.NewBuffer(0, 0, buffer.CellAttributes{ @@ -51,8 +54,10 @@ func New(pty *os.File, logger *zap.SugaredLogger, colourScheme ColourScheme) *Te }), pty: pty, logger: logger, - colourScheme: colourScheme, + config: config, titleHandlers: []chan bool{}, + pauseChan: make(chan bool, 1), + resumeChan: make(chan bool, 1), } }