From 44d8200e04f641b99b95a2078d884b20c61432cd Mon Sep 17 00:00:00 2001 From: Neil Date: Sat, 19 Sep 2026 15:17:46 -0700 Subject: [PATCH] revert(terminal): stop pacing latency-sensitive foreground redraws Dense-SGR pacing was also applied to foreground writes inside the post-keystroke window. There it traded an unmeasured benefit for two concrete costs: a macrotask delay before first paint, since the write became an enqueue plus a zero-delay drain, and up to eight viewport snapshot/settle cycles where there had been one, because the forced refresh flag rides every split batch. The 128 KiB parser burst this pacing exists to bound lives on the background and drain paths, which keep all of it. Restore the synchronous write on the latency-sensitive path and pin it with a test. --- .../pane-terminal-output-scheduler.test.ts | 35 +++---------------- .../pane-terminal-output-writer.ts | 23 ------------ 2 files changed, 4 insertions(+), 54 deletions(-) diff --git a/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.test.ts b/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.test.ts index cb9d732035d..de47f23df15 100644 --- a/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.test.ts +++ b/src/renderer/src/lib/pane-manager/pane-terminal-output-scheduler.test.ts @@ -613,16 +613,10 @@ describe('pane terminal output scheduler', () => { expect(terminal.write.mock.calls.map(([data]) => data).join('')).toBe(`${dense}${tail}`) }) - it('paces a latency-sensitive dense foreground redraw instead of writing it whole', async () => { + it('writes a latency-sensitive foreground redraw whole, even when it is dense', async () => { vi.useFakeTimers() const { writeTerminalOutput } = await loadScheduler() const terminal = createForegroundTerminal() - const parsed: (() => void)[] = [] - terminal.write.mockImplementation((_data: string, callback?: () => void) => { - if (callback) { - parsed.push(callback) - } - }) const dense = Array.from( { length: 1_300 }, (_, index) => `\x1b[${30 + (index % 8)}mX\x1b[0m` @@ -630,30 +624,9 @@ describe('pane terminal output scheduler', () => { writeTerminalOutput(terminal, dense, { foreground: true, latencySensitive: true }) - // The redraw is queued rather than submitted whole, then released one - // parser batch at a time. - expect(terminal.write).not.toHaveBeenCalled() - vi.advanceTimersByTime(0) - expect(terminal.write).toHaveBeenCalledTimes(1) - expect(terminal.write.mock.calls[0]?.[0]).toHaveLength(4 * 1024) - - while (parsed.length > 0) { - parsed.shift()?.() - vi.advanceTimersByTime(0) - } - expect(terminal.write.mock.calls.map(([data]) => data).join('')).toBe(dense) - expect(terminal.write.mock.calls.length).toBeGreaterThan(1) - }) - - it('writes a latency-sensitive foreground redraw whole when it is not dense', async () => { - vi.useFakeTimers() - const { writeTerminalOutput } = await loadScheduler() - const terminal = createForegroundTerminal() - const plain = 'plain redraw line\r\n'.repeat(1_000) - - writeTerminalOutput(terminal, plain, { foreground: true, latencySensitive: true }) - - expect(terminal.write.mock.calls.map(([data]) => data)).toEqual([plain]) + // Pacing this path would delay first paint by a macrotask and multiply the + // per-write viewport settle inside the post-keystroke window. + expect(terminal.write.mock.calls.map(([data]) => data)).toEqual([dense]) }) it('holds the parse probe behind terminal output the flush could not submit', async () => { diff --git a/src/renderer/src/lib/pane-manager/pane-terminal-output-writer.ts b/src/renderer/src/lib/pane-manager/pane-terminal-output-writer.ts index ba278a76843..5334b5d108d 100644 --- a/src/renderer/src/lib/pane-manager/pane-terminal-output-writer.ts +++ b/src/renderer/src/lib/pane-manager/pane-terminal-output-writer.ts @@ -34,7 +34,6 @@ import { import { ALWAYS_REFRESH_FOREGROUND_SYNCHRONOUSLY, BACKGROUND_FLUSH_DELAY_MS, - DENSE_SGR_CHUNK_CHARS, FOREGROUND_BACKLOG_WARNING, LARGE_BACKLOG_CHARS, discardTerminalOutput, @@ -43,7 +42,6 @@ import { type TerminalOutputTarget, type WriteTerminalOutputOptions } from './pane-terminal-output-queue-registry' -import { isDenseSgr } from '../../../../shared/terminal-sgr-density' export function writeTerminalOutputImpl( terminal: TerminalOutputTarget, @@ -188,27 +186,6 @@ export function writeTerminalOutputImpl( scheduleDrain(0) return } - if (data.length >= DENSE_SGR_CHUNK_CHARS && isDenseSgr(data)) { - const queued = entry ?? createQueueEntry(terminal, options) - queued.onBackgroundBacklogDropped = options.onBackgroundBacklogDropped - queued.highPriority = true - queuedByTerminal.set(terminal, queued) - enqueueChunk(queued, data, { - foreground: true, - forceForegroundRefresh: options.forceForegroundRefresh, - followupForegroundRefresh: options.followupForegroundRefresh, - shouldRefreshForegroundSynchronously: options.shouldRefreshForegroundSynchronously, - stripTransientCursorShows: options.stripTransientCursorShows, - beforeWrite: options.beforeWrite, - onParsed: options.onParsed, - ackCredit: options.ackCredit - }) - if (queueCapExceeded(queued)) { - replaceBacklogWithWarning(queued, FOREGROUND_BACKLOG_WARNING) - } - scheduleDrain(0) - return - } flushTerminalOutputImpl(terminal) const remaining = queuedByTerminal.get(terminal) if (remaining) {