From 85cff19a2a216339b7424932bca1fd6685126bba Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 8 Aug 2026 19:08:12 +0200 Subject: [PATCH] Fire queued ReadToEnd callbacks when the initial read reaches EOF A task's read loop processes one LinesToRead request at a time. The initial request has a large line count and no Then callback; if the content is shorter than that, the loop hits EOF on the initial request and breaks out, abandoning any further requests still sitting in the readLines channel. So a ReadToEnd call that races a still-loading-but-shorter-than-its-initial-read view has its Then silently dropped: it isn't fired immediately (the channel was non-nil at call time) and it's never dequeued. On EOF, drain the queued requests and fire their Then callbacks before breaking out, since reaching EOF trivially satisfies any "read more" request. Co-Authored-By: Claude Opus 5 (1M context) --- pkg/tasks/tasks.go | 15 +++++++++++++++ pkg/tasks/tasks_test.go | 3 --- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/pkg/tasks/tasks.go b/pkg/tasks/tasks.go index c9b5aaa5a..dec232189 100644 --- a/pkg/tasks/tasks.go +++ b/pkg/tasks/tasks.go @@ -380,6 +380,21 @@ func (self *ViewBufferManager) NewCmdTask(start func() (Cmd, io.Reader), prefix // are UI-thread-only, so run it there. _ = self.onUIThread(self.onEndOfInput) callThen() + // Any read requests that were queued while we were reading are + // now trivially satisfied, since we've read everything. Fire + // their callbacks instead of dropping them when we break out of + // the loop below (and nil out readLines). + drain: + for { + select { + case queued := <-readLines: + if queued.Then != nil { + queued.Then() + } + default: + break drain + } + } break outer } writeToView(append(line, '\n')) diff --git a/pkg/tasks/tasks_test.go b/pkg/tasks/tasks_test.go index 4211dcb08..d9ec7e4d4 100644 --- a/pkg/tasks/tasks_test.go +++ b/pkg/tasks/tasks_test.go @@ -248,10 +248,7 @@ func TestNewCmdTaskQueuedReadAtEndOfInput(t *testing.T) { wg.Wait() - /* EXPECTED: assert.True(t, thenCalled) - ACTUAL: */ - assert.False(t, thenCalled) } func TestNewCmdTaskRefresh(t *testing.T) {