From eda215133072bfd135dae7c9001711358221e4b1 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 8 Jul 2026 13:01:09 +0200 Subject: [PATCH] Handle a command task's end-of-input on the UI thread When a command task reaches EOF it runs onEndOfInput, which reads the view's line height (and thus its dimensions) to decide whether to scroll, sets the view's origin, and flushes stale cells. Reading the dimensions and setting the origin are UI-thread-only, but this ran on the task's own goroutine, racing the UI thread. Bounce onEndOfInput onto the UI thread, as we already do for the new-task origin reset. It's once per render, so it doesn't add the per-line UI-thread churn that streaming the content would. Co-Authored-By: Claude Opus 4.8 (1M context) --- pkg/tasks/tasks.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pkg/tasks/tasks.go b/pkg/tasks/tasks.go index d58be3a92..3a964c838 100644 --- a/pkg/tasks/tasks.go +++ b/pkg/tasks/tasks.go @@ -353,8 +353,14 @@ func (self *ViewBufferManager) NewCmdTask(start func() (Cmd, io.Reader), prefix if !ok { // if we're here then there's nothing left to scan from the source - // so we're at the EOF and can flush the stale content - self.onEndOfInput() + // so we're at the EOF and can flush the stale content. + // onEndOfInput reads the view's dimensions (to decide + // whether to scroll) and sets the origin, both of which + // are UI-thread-only, so run it there. + _ = self.onUIThread(func() error { + self.onEndOfInput() + return nil + }) callThen() break outer }