Repository navigation
Set color decorator CSS variables only when an editor shows colors - #342235
Draft
Karthik Nadig (karthiknadig) wants to merge 1 commit into
Draft
Karthik Nadig (karthiknadig) wants to merge 1 commit into
Karthik Nadig (karthiknadig) wants to merge 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
The narrow change preserves swatch sizing and cleanup, with focused regression coverage and no unresolved findings.
No open issues 🎉
What changed in this PR
Defers color-decorator CSS properties until an editor displays color swatches, avoiding unnecessary restyling and partially addressing slow Agents window session switching.
Changes:
- Initializes sizing properties once, when decorations first appear, while preserving disposal cleanup.
- Adds regression tests for colorless editors, model switching, and cleanup.
| File | Description |
|---|---|
| src/vs/editor/contrib/colorPicker/test/browser/colorDetector.test.ts | Tests deferred initialization, model switching, and disposal. |
| src/vs/editor/contrib/colorPicker/browser/colorDetector.ts | Sets sizing properties only when color decorations first appear. |
Review effort: Balanced
Contributor
|
Base:
|
ColorDetector is created for every code editor after its first render and wrote two inherited CSS custom properties on the editor container. That restyled every rendered line, even in editors without colors such as chat code blocks. Set them the first time color decorations are shown instead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Karthik Nadig (karthiknadig)
force-pushed
the
karthiknadig/bug-swarm/c2-f1-code-block-editor-layout
branch
from
October 18, 2026 05:09
2322b47 to
c539df0
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #341282
Problem
Switching between two finished sessions in the Agents window, each with one large response containing 45 code blocks, takes a median of 2,728 ms on
mainand 2,379 ms with this PR (−349 ms, −13%), measured over 12 switches in 3 runs for each build.Part of that time is spent restyling every code-block editor a second time, right after it first renders, even though none of these editors shows a color. This PR removes that second pass. Switching is still slow for other reasons, so #341282 is only partly addressed.
Root cause
ColorDetectoris an editor contribution that is created for every code editor after its first render (colorPickerContribution.ts#L30). Since #332340, its constructor writes two CSS custom properties,--vscode-colorPicker-colorDecoratorWidthand--vscode-colorPicker-colorDecoratorMargin, on the editor's container element (colorDetector.ts#L64-L70).Custom properties are inherited, so changing them invalidates the computed style of the whole editor subtree. The next layout read then recalculates style for every rendered line. The only reader of these properties is the
.colorpicker-color-decorationrule (colorPicker.css#L18-L19), which only matches when color decorations exist. Editors that never show a color still pay for the restyle.In the Agents window every rendered chat code block is its own code editor, so each session switch performs 90 of these writes (45 editors × 2 properties).
Fix
Set the two properties the first time
ColorDetectorshows at least one color decoration, just before the decorations are applied, and remove them when the contribution is disposed. This keeps the swatch size and margin unchanged for editors with colors, including when an editor switches from a model without colors to one with colors. It also skips the restyle for editors that have no colors.Nothing else reads these variables. I searched the repo, and outside this file they appear only in
colorPicker.cssand the stylelint list of known variables. The change is in the shared editor contribution, so it also applies to other embedded editors that usually show no colors, such as notebook cells and diff editors. I only measured the Agents window case.Before / after
Both recordings switch between the same two sessions four times. After the switches, the overlay shows the medians: how many code-block editors that had already rendered got their custom properties changed again, the large style recalculations (20,000 elements or more), total style recalculation, and switch time. These recordings were taken with tracing on, so their switch times are higher than the headline numbers above.
Before
After
Regular editor check with this PR: a CSS file still shows color swatches at the expected size after switching from a file without colors in the same editor.
Measurements
The setup was a Code OSS dev build from this branch and from
main@1e81fc75bb5, on Windows withVSCODE_DEV_DISABLE_DISPOSABLE_TRACKING=1. The Agents window was connected to a local scripted Agent Host, with no model traffic. It served two finished sessions. Each session holds one ~100 KB markdown response: 50 sections with a list, a 4-row table and a 20-line TypeScript code block. The transcript renders 45 code-block editors.mainMutationObserveronstyleattributes inside chat code blocks counts changes to--*properties on elements that contain.view-line. 4 switches per run, over 3 runs.UpdateLayoutTreedurations on the renderer main thread in a Chrome trace (devtools.timeline). Measured from the click to 1.5 s after the transcript appears. Same 12 switches.UpdateLayoutTreeevents withelementCount≥ 20,000How to test
a { color: #007acc; background: rgb(220, 53, 69); }. The color swatches look the same as onmain: same size and spacing before the color value.Snippet to count code-block restyles in the Agents window
Paste in Developer Tools before switching sessions.
window.__restylethen gives the number of custom-property writes on code-block editors that had already rendered lines. Onmainit shows 2 per code block for each switch. With this PR it reports none.Validation
main@1e81fc7(source change reverted, new test kept)scripts\test.bat --run src/vs/editor/contrib/colorPicker/test/browser/colorDetector.test.ts0.8em/0.2emwhile the editor shows no colors. The dispose test passes onmaintoo.scripts\test.bat --run src/vs/editor/contrib/colorPicker/test/browser/colorDetector.test.ts --run src/vs/editor/contrib/colorPicker/test/browser/defaultDocumentColorProvider.test.tsnpm run typecheck-clientnpm run eslint -- src/vs/editor/contrib/colorPicker/browser/colorDetector.ts src/vs/editor/contrib/colorPicker/test/browser/colorDetector.test.tsmainvs this PRmain, 2,379 ms with this PRmainvs this PRMutationObservercounter, 3 runs × 4 switches per buildmain: 90 property writes per switch and a 1,431 ms style-recalc median. With this PR: no such writes and a 1,104 ms median.plain.css, split it into a new editor, then opencolors.cssin that same editor.plain.css, the container has neither property. After switching tocolors.cssit has0.8em/0.2em, and the editor shows 6 swatches. Each is 11.2 px wide with 2.8 px margins at a 14 px font size, which is 0.8 em / 0.2 em as onmain.Found and fixed with automated exploratory testing. Draft until reviewed by a human.