From 6042e1c28b961597dfda999bb6737bb73151f2b3 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 13 Oct 2026 09:48:20 +0200 Subject: [PATCH] Restore the terminal if one of gocui's goroutines panics A panic in the goroutine that polls the terminal for events leaves the terminal in raw mode and on the alternate screen. The panic is then hard to read, and the terminal needs a reset afterwards. Guard this goroutine the same way as the worker goroutines. Guard the goroutines that send a resize event too; they are unlikely to panic, but this way all of gocui's goroutines are guarded, and a check for unguarded goroutines doesn't need any exceptions. Co-Authored-By: Claude Opus 5.5 (1M context) --- pkg/gocui/gui.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/gocui/gui.go b/pkg/gocui/gui.go index decae19b7..afc71a2ed 100644 --- a/pkg/gocui/gui.go +++ b/pkg/gocui/gui.go @@ -1106,7 +1106,7 @@ func (g *Gui) SetManager(managers ...Manager) { g.keybindings = nil g.tabClickBindings = nil - go func() { g.gEvents <- GocuiEvent{Type: eventResize} }() + go safe(func() { g.gEvents <- GocuiEvent{Type: eventResize} }) } // SetManagerFunc sets the given manager function. It deletes all views and @@ -1120,7 +1120,7 @@ func (g *Gui) SetManagerFunc(manager func(*Gui) error) { func (g *Gui) MainLoop() error { defer close(g.loopExited) - go func() { + go safe(func() { for { select { case <-g.stop: @@ -1129,7 +1129,7 @@ func (g *Gui) MainLoop() error { g.gEvents <- g.pollEvent() } } - }() + }) Screen.EnableFocus() Screen.EnablePaste() @@ -2187,7 +2187,7 @@ func (g *Gui) Resume() error { // Schedule a redraw of the whole screen. Nothing else guarantees one: // flushes are skipped while suspended, and after re-engaging the screen // the terminal shows nothing until we draw again. - go func() { g.gEvents <- GocuiEvent{Type: eventResize} }() + go safe(func() { g.gEvents <- GocuiEvent{Type: eventResize} }) return nil }