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) <noreply@anthropic.com>
This commit is contained in:
Stefan Haller
2026-08-15 15:30:27 +02:00
co-authored by Claude Opus 5
parent 9293f03c83
commit 85cff19a2a
2 changed files with 15 additions and 3 deletions
+15
View File
@@ -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'))
-3
View File
@@ -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) {