diff --git a/.gitignore b/.gitignore index cf7a9a7d..2664ab5c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea .vscode /darktile +*.swp diff --git a/internal/app/darktile/gui/gui.go b/internal/app/darktile/gui/gui.go index a2614c0f..e5012381 100644 --- a/internal/app/darktile/gui/gui.go +++ b/internal/app/darktile/gui/gui.go @@ -102,12 +102,12 @@ func (g *GUI) Run() error { func (g *GUI) watchForUpdate() { for range g.updateChan { ebiten.ScheduleFrame() - go func() { - if g.keyState.AnythingPressed() { + if g.keyState.AnythingPressed() { + go func() { time.Sleep(time.Millisecond * 10) ebiten.ScheduleFrame() - } - }() + }() + } } } diff --git a/internal/app/darktile/gui/input.go b/internal/app/darktile/gui/input.go index 7122c5a9..a974a885 100644 --- a/internal/app/darktile/gui/input.go +++ b/internal/app/darktile/gui/input.go @@ -37,6 +37,8 @@ var modifiableKeys = map[ebiten.Key]uint8{ } func (g *GUI) handleInput() error { + g.terminal.Lock() + defer g.terminal.Unlock() if err := g.handleMouse(); err != nil { return err diff --git a/internal/app/darktile/gui/key_states.go b/internal/app/darktile/gui/key_states.go index d650381a..6ea41638 100644 --- a/internal/app/darktile/gui/key_states.go +++ b/internal/app/darktile/gui/key_states.go @@ -30,6 +30,8 @@ type press struct { } func (k *keyState) AnythingPressed() bool { + k.mu.Lock() + defer k.mu.Unlock() return len(k.keys) > 0 } diff --git a/internal/app/darktile/gui/render/render.go b/internal/app/darktile/gui/render/render.go index 359e0690..5a523e80 100644 --- a/internal/app/darktile/gui/render/render.go +++ b/internal/app/darktile/gui/render/render.go @@ -62,6 +62,8 @@ func New(screen *ebiten.Image, terminal *termutil.Terminal, fontManager *font.Ma } func (r *Render) Draw() { + r.terminal.Lock() + defer r.terminal.Unlock() // 1. fill frame with default background colour r.frame.Fill(r.theme.DefaultBackground()) diff --git a/internal/app/darktile/gui/resize.go b/internal/app/darktile/gui/resize.go index 9c5b8300..1611f176 100644 --- a/internal/app/darktile/gui/resize.go +++ b/internal/app/darktile/gui/resize.go @@ -22,14 +22,17 @@ func (g *GUI) Layout(outsideWidth, outsideHeight int) (int, int) { func (g *GUI) resize(w, h int) { - if g.fontManager.CharSize().X == 0 || g.fontManager.CharSize().Y == 0 { + if g.fontManager.CharSize().X == 0 || g.fontManager.CharSize().Y == 0 || g.terminal == nil { return } cols := uint16(w / g.fontManager.CharSize().X) rows := uint16(h / g.fontManager.CharSize().Y) - if g.terminal != nil && g.terminal.IsRunning() { + g.terminal.Lock() + defer g.terminal.Unlock() + + if g.terminal.IsRunning() { _ = g.terminal.SetSize(rows, cols) } } diff --git a/internal/app/darktile/termutil/ansi.go b/internal/app/darktile/termutil/ansi.go index e7d67e88..421e4ddb 100644 --- a/internal/app/darktile/termutil/ansi.go +++ b/internal/app/darktile/termutil/ansi.go @@ -6,6 +6,9 @@ func (t *Terminal) handleANSI(readChan chan MeasuredRune) (renderRequired bool) t.log("ANSI SEQ %c 0x%X", r.Rune, r.Rune) + t.mu.Lock() + defer t.mu.Unlock() + switch r.Rune { case '[': return t.handleCSI(readChan) diff --git a/internal/app/darktile/termutil/terminal.go b/internal/app/darktile/termutil/terminal.go index b1eb669f..9d9ca1cc 100644 --- a/internal/app/darktile/termutil/terminal.go +++ b/internal/app/darktile/termutil/terminal.go @@ -7,6 +7,7 @@ import ( "io" "os" "os/exec" + "sync" "github.com/creack/pty" "golang.org/x/term" @@ -20,6 +21,7 @@ const ( // Terminal communicates with the underlying terminal type Terminal struct { + mu sync.Mutex windowManipulator WindowManipulator pty *os.File updateChan chan struct{} @@ -196,17 +198,20 @@ func (t *Terminal) requestRender() { } } +func (t *Terminal) processSequence(mr MeasuredRune) (render bool) { + if mr.Rune == 0x1b { + return t.handleANSI(t.processChan) + } + return t.processRunes(mr) +} + func (t *Terminal) process() { for { select { case <-t.closeChan: return case mr := <-t.processChan: - if mr.Rune == 0x1b { // ANSI escape char, which means this is a sequence - if t.handleANSI(t.processChan) { - t.requestRender() - } - } else if t.processRunes(mr) { // otherwise it's just an individual rune we need to process + if t.processSequence(mr) { t.requestRender() } } @@ -214,6 +219,8 @@ func (t *Terminal) process() { } func (t *Terminal) processRunes(runes ...MeasuredRune) (renderRequired bool) { + t.mu.Lock() + defer t.mu.Unlock() for _, r := range runes { @@ -226,31 +233,31 @@ func (t *Terminal) processRunes(runes ...MeasuredRune) (renderRequired bool) { //DING DING DING continue case 0x8: //backspace - t.GetActiveBuffer().backspace() + t.activeBuffer.backspace() renderRequired = true case 0x9: //tab - t.GetActiveBuffer().tab() + t.activeBuffer.tab() renderRequired = true case 0xa, 0xc: //newLine/form feed - t.GetActiveBuffer().newLine() + t.activeBuffer.newLine() renderRequired = true case 0xb: //vertical tab - t.GetActiveBuffer().verticalTab() + t.activeBuffer.verticalTab() renderRequired = true case 0xd: //carriageReturn - t.GetActiveBuffer().carriageReturn() + t.activeBuffer.carriageReturn() renderRequired = true case 0xe: //shiftOut - t.GetActiveBuffer().currentCharset = 1 + t.activeBuffer.currentCharset = 1 case 0xf: //shiftIn - t.GetActiveBuffer().currentCharset = 0 + t.activeBuffer.currentCharset = 0 default: if r.Rune < 0x20 { // handle any other control chars here? continue } - t.GetActiveBuffer().write(t.translateRune(r)) + t.activeBuffer.write(t.translateRune(r)) renderRequired = true } } @@ -259,7 +266,7 @@ func (t *Terminal) processRunes(runes ...MeasuredRune) (renderRequired bool) { } func (t *Terminal) translateRune(b MeasuredRune) MeasuredRune { - table := t.GetActiveBuffer().charsets[t.GetActiveBuffer().currentCharset] + table := t.activeBuffer.charsets[t.activeBuffer.currentCharset] if table == nil { return b } @@ -306,3 +313,11 @@ func (t *Terminal) useMainBuffer() { func (t *Terminal) useAltBuffer() { t.switchBuffer(AltBuffer) } + +func (t *Terminal) Lock() { + t.mu.Lock() +} + +func (t *Terminal) Unlock() { + t.mu.Unlock() +}