Repository navigation
perf(web): long composer code blocks no longer re-highlight on every keystroke - #19439
Conversation
…keystroke Every edit changes a code block's signature, so the whole fence was re-tokenized with Shiki, synchronously, before the next paint. In an 18,000-character TSX fence the median keystroke took 200-248 ms to paint. A fence over 2,000 characters now keeps the colors it had, mapped through the edit and limited to its block, and is re-tokenized once typing pauses for 300 ms. Shorter fences still repaint on every keystroke. A highlighter that fails to load clears the old colors instead of keeping them.
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a localized performance fix that debounces highlighting only for long composer code blocks while preserving existing behavior for short blocks and final syntax coloring. Focused tests cover the new timing and decoration-preservation paths, with no schema, deployment, security, billing, or static-analysis configuration impact. You can add or adjust custom eligibility rules. Learn more. |
|
Warning Review limit reachedOnly developers with an assigned seat can use this organization's usage-based review budget, and seats here are assigned manually. Ask an admin to assign a seat, or change the review continuation mode in Billing. Next included review available in 3 minutes. View limit details
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
|
Taking over this one as maintainer for the composer-chat-14 batch. I will preserve the long-fence typing fix, refresh it against main, simplify the tests and implementation, and verify it with independent reviews. Thanks @MohibShaikh for the reproduction and measurements. |
Typing in a long composer code fence synchronously re-tokenizes the entire fence on each edit, stalling the web renderer. Fences above 2,000 characters now keep their mapped colors and refresh after a 300 ms pause. Short fences remain immediate; the existing 20,000-character cap remains.
Retains @MohibShaikh's original work and measurements in #19439, with main merged and the tests and implementation simplified. The takeover also prevents stale async loads from bypassing the delay and refreshes immediately when the theme changes. Split token decorations stay inside their fences; failed grammar loads clear retained colors.
Tradeoff: retained colors can be briefly incorrect until a pause. Edits elsewhere also restart that pause, and changing a long fence's language can retain its old colors for 300 ms. During a first grammar load, editing elsewhere can defer initial colors until the pause.
Validation at 8e9f96ee72:
composerCodeBlockHighlight.test.tsandcomposer-code-block.test.ts), plus changed-file lint/formatting and web typecheck.Before — main, same composer fixture:
After — current head, matching fixture and viewport:
Recordings: before: per-edit tokenization, after: deferred tokenization. A local DejaVu font fixture made captures legible; no provider turn was started.
The change applies to the web composer and the renderer used by desktop. Native mobile uses a separate composer. No provider adapters, wire contracts, permissions, or connection routing change. Not verified: macOS, Windows, iOS, Android, Electron desktop, Safari, Firefox, remote relay/tunnel, or a separate physical client.
Implementation: Codex GPT-6.1 Sol through T3 Code; tests: Codex GPT-6 Astra; independent reviews: Claude Opus 5.5 and Codex GPT-6 Sol.