TerminalGridReportCoalescer: PTY grid at most once per 25 ms, the newest (Ghostty's min_ms rule)
Summary
Adds TerminalGridReportCoalescer (CmuxNextTerminal): the PTY size rule of Ghostty.app (Thread.zig min_ms 25). The first new grid opens a 25 ms window and is not sent at once. A later grid in the window replaces it. The newest grid is sent when the window ends.
viewSized(_:): opens the window, or replaces the waiting grid.flush(): sends the waiting grid now (not if it equals the last sent grid).reportNow(_:): a forced report, sent at once, even if it equals the last sent grid.cancel(): drops the waiting grid.DemandTimerwith an injectedClock. It never sleeps or blocks the main thread. A stale fire afterflush()orcancel()sends nothing.
This PR has no caller yet, so the new type is dead code for now; the RESIZE OWNER accepted that for one day. It lands alone so that key resizes (T-KEYS, #36478) and divider drags (T-DRAGS, frame-owner-s2) can both use it. Those PRs then rebase onto it.
Owner note: CmuxNextTerminal is owned by PL-ghostty. This PR adds one new file and changes no existing file.
Observed / Not run
Observed:
- Fleet step
3c009ace2df88e5202eface1at 47bbe042 (the same two commits on the older base): all 7TerminalGridReportCoalescerTestspass (ManualClock). prepush-gate.pyat this head: no new violations.
Not run (pending at the time of writing; I add the results here):
- The compile and the
TerminalGridReportCoalescerTestsrun at this head. - The app launch smoke on macOS 14 and 15. The type has no caller, so app behavior does not change.
Changelog
none
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Adds TerminalGridReportCoalescer, applying Ghostty.app's 25 ms min_ms rule so a terminal view sends at most one PTY grid report per window, always the newest. The first change opens the window; later changes replace the waiting grid; the newest is delivered when the window ends. flush() sends the waiting grid immediately, reportNow(_:) forces an immediate send even for a duplicate, and cancel() drops the waiting grid.
The new type has no caller yet, so it is dead code for now; it lands alone so the key-resize (T-KEYS) and divider-drag (T-DRAGS) changes can rebase onto it. One file is added; no existing file changes.