Skip to content

Fix CSS highlighting desync when a nested rule precedes a custom property - #327821

Closed
srikanthananthula63053 wants to merge 2 commits into
microsoft:mainfrom
srikanthananthula63053:fix-327799-css-nesting-highlight
Closed

Fix CSS highlighting desync when a nested rule precedes a custom property#327821
srikanthananthula63053 wants to merge 2 commits into
microsoft:mainfrom
srikanthananthula63053:fix-327799-css-nesting-highlight

Conversation

@srikanthananthula63053

@srikanthananthula63053 srikanthananthula63053 commented Jul 28, 2026

Copy link
Copy Markdown

Summary

  • Fixes CSS highlighting breaks when a nested rule comes before a custom property in the same block vscode-css#54 — CSS syntax highlighting desyncs when a nested rule inside a block is followed by a custom property, e.g. #a { .b { gap: 1px; } --c: 1px; }.
  • Root cause: rule-list-innards had no pattern for a nested rule block, so the enclosing block's own end pattern (}) matched the first } encountered — even one belonging to a nested rule — closing the outer meta.property-list.css scope prematurely. Everything after the nested rule then fell back to raw, uncolored meta.selector.css text.
  • rule-list-innards now recognizes nested selectors via #selector, and rule-list re-enters the grammar ($self) so a nested { ... } opens its own properly balanced scope. selector's begin pattern is tightened (with negative lookaheads) so it only matches when a selector is actually followed by {, not an ordinary property: value; declaration, since it now also runs inside a property list where it competes with declaration parsing.

Test plan

  • Tokenized the exact repro from the issue with vscode-textmate + vscode-oniguruma directly against the grammar file — confirmed the nested rule and the trailing custom property both highlight correctly, with no scope leaking past the nested block's own closing brace.
  • Tokenized the previously-"working" reverse order (--c before .b { ... }) — still correct, and no longer relies on incidental brace-position luck.
  • Diffed full-file tokenization (old grammar vs. patched grammar) across large, untouched real CSS files in the repo — zero differences.
  • Diffed tokenization of src/vs/workbench/contrib/chat/browser/widget/media/chat.css (4600+ lines) — the only differences were at genuine nested-rule sites, including an already-shipping nested rule (.codicon { font-size: inherit; }) that this same bug was silently mis-highlighting; it now renders correctly, and the file continues to tokenize cleanly through EOF afterward.
  • Additional manual cases verified: pseudo-class nesting (&:hover), tag-name nesting, attribute-selector nesting, deeply nested rules, nested @media, and var() values — all unaffected/correct.
  • Added an automated regression test: extensions/vscode-colorize-tests/test/colorize-fixtures/test-css-nesting.css, covering the exact issue repro plus custom-property-before-nested-rule, pseudo-class nesting with a trailing custom property, and a nested rule inside @media. Ran via npm run test-extension -- -l vscode-colorize-tests --grep test-css-nesting — passing, with the checked-in colorize-results/colorize-tree-sitter-results snapshots locking in the corrected tokenization (e.g. --c after the nested rule now scopes as variable.css instead of falling back to unstyled selector text). Any future regression in this grammar will now fail this test.

Files Changed

  • extensions/css/syntaxes/css.tmLanguage.json — grammar fix (see Root Cause above).
  • extensions/vscode-colorize-tests/test/colorize-fixtures/test-css-nesting.css — new regression fixture.
  • extensions/vscode-colorize-tests/test/colorize-results/test-css-nesting_css.json and .../colorize-tree-sitter-results/test-css-nesting_css.json — checked-in expected tokenization snapshots for the new fixture.

…erty

The CSS TextMate grammar had no pattern for nested rule blocks inside a
property list, so a bare `}` belonging to a nested rule (e.g. `.b { ... }`)
would be matched by the enclosing block's own `end` pattern and close it
prematurely. Anything after the nested rule then fell back to raw
`meta.selector.css` text with no property/value coloring.

Teach `rule-list-innards` to recognize nested selectors and re-enter the
grammar (`$self`) to open a properly balanced nested scope, and tighten
`selector`'s begin pattern so it only matches an actual nested rule
(something followed by `{`) rather than an ordinary declaration.

Verified by tokenizing the grammar directly with vscode-textmate/
vscode-oniguruma, and by diffing full-file tokenization of existing CSS
in the repo before/after: no unintended differences, and one real,
previously mis-highlighted nested rule in chat.css is now fixed.

Fixes #327799
@srikanthananthula63053
srikanthananthula63053 force-pushed the fix-327799-css-nesting-highlight branch from b0129e3 to 0b57f16 Compare July 29, 2026 07:35
Adds test-css-nesting.css to the vscode-colorize-tests fixtures,
covering the exact scenario from microsoft#327799 (a nested rule followed by
a custom property) plus related nesting forms: custom property
before a nested rule, pseudo-class nesting with a trailing custom
property, and a nested rule inside @media.

The checked-in colorize-results snapshot locks in the fixed
tokenization (e.g. `--c` after a nested rule now scopes as
variable.css instead of falling back to unstyled selector text), so
a future regression in the grammar will fail this test.
@alexr00

alexr00 commented Jul 29, 2026

Copy link
Copy Markdown
Member

Thank you for the PR, but we pull our css grammar from https://github.com/microsoft/vscode-css, so all PRs should go there.

@alexr00 alexr00 closed this Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CSS highlighting breaks when a nested rule comes before a custom property in the same block

2 participants