Render local input responses immediately#553
Conversation
When output arrives within 150ms of a keystroke and the terminal isn't inside a DEC 2026 sync block, paint synchronously on the main runloop instead of going through queuePendingDisplay's 16.67ms frame throttle. Without this, input echo waits one 60Hz tick. When output bursts coincide with typing, pendingDisplay stays armed and subsequent keystrokes are coalesced into the next tick, producing a perceptible "skipped characters appear together" feel. Complementary to the recent sync-output simplification on main.
The SyncDebug type is not defined in the tree, so main currently fails to compile. Stripping the call sites in Terminal.swift and AppleTerminalView.swift unblocks CI on this PR. Easy to revert if SyncDebug is reintroduced later.
|
Added a second commit dropping the |
|
Apologies for the delay, question about this. displayImmediately() can schedule a separate main-thread redraw for every feed chunk. It looks like feedFinish() calls displayImmediately() without using pendingDisplay to coalesce redraws. Then when we run the feed on the main thread we post a new call to the main queue every time. Seems like the immediate path should still bypass the 16.67 ms timer, but it needs to coalesce duplicate redraw requests. For example, set pendingDisplay before posting the immediate main-queue block, then clear it once the redraw runs. |
|
Let me merge and add the suggestion |
Reopened version of #542 on top of the recent sync-output rework.
Problem
After
9446f60, the remaining typing-lag source is the 16.67ms throttle inqueuePendingDisplay. When output bursts coincide with keystrokes,pendingDisplaystays armed and subsequent keystrokes get coalesced into the next 60Hz tick. Perceptible as occasional "skipped" characters that appear together a frame later.In practice this surfaces most when the host is under load — we see it consistently when many terminals are running concurrently in Maestri.
Fix
Input-immediate bypass only, no settle-window machinery. If output arrives within 150ms of a keystroke and we're not in a sync block, paint synchronously instead of via
asyncAfter(+16.67ms). Complementary to the sync-output simplification on main.Tests
Confirmed in Maestri against the same workloads that motivated the first PR.