Add default semantic token rules for C# (Roslyn) token types - #60027
Closed
tatsudo wants to merge 1 commit into
Closed
Add default semantic token rules for C# (Roslyn) token types#60027tatsudo wants to merge 1 commit into
tatsudo wants to merge 1 commit into
Conversation
Roslyn reports an extended token-type legend (field, controlKeyword, recordClass, extensionMethod, ...) that the default rules did not cover, so those tokens were silently dropped and C# fell back to tree-sitter-only highlighting. Map them to existing theme styles. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4 tasks
xfight-eleven
pushed a commit
to xfight-eleven/zed
that referenced
this pull request
Jun 28, 2026
…ries#60015) In C# files nothing gets semantic highlighting — class fields and other identifiers are colored by tree-sitter only, so a private field looks the same as a plain local variable. The reason: Roslyn (the C# language server) doesn't declare `semanticTokensProvider` statically in its `initialize` response. It registers it **dynamically** (`client/registerCapability`), and only when the client advertises `textDocument.semanticTokens.dynamicRegistration = true`. Zed advertised `false` and didn't handle such a registration, so Roslyn never offered semantic tokens at all. (rust-analyzer/gopls are unaffected — they declare the capability statically.) This is the first of two PRs. This one makes Roslyn actually **send** semantic tokens. The companion PR (zed-industries#60027) maps Roslyn's C#-specific token types to theme styles — without it the tokens arrive but most are dropped, since their types aren't in Zed's default rules. ## Solution - Advertise `textDocument.semanticTokens.dynamicRegistration = true`. - Handle the `textDocument/semanticTokens` registration and unregistration so the capability is stored, following the existing arms for `documentLink`, diagnostics, etc. ## Testing - Added a test that dynamically registers and unregisters `textDocument/semanticTokens` and checks the stored capability appears and is cleared. - Verified manually against Roslyn on a C# project: Zed now sends `textDocument/semanticTokens/full` and gets tokens back; before this change there was no semantic-token traffic at all. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - Support dynamic registration of the `textDocument/semanticTokens` capability. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Member
|
Thanks for this! I see no reason to not just ship this with the C# extension, hence am gonna close this at this time. Feel free to inform me here should I be missing something. Thanks! |
MrSubidubi
pushed a commit
to zed-extensions/csharp
that referenced
this pull request
Jul 17, 2026
Roslyn reports an extended semantic-token legend (`field`, `controlKeyword`, `recordClass`, `extensionMethod`, ...) beyond the standard LSP types. Without rules for them, those tokens are dropped and C# falls back to tree-sitter-only highlighting (e.g. a private field looks like a local variable). This adds `languages/csharp/semantic_token_rules.json` mapping the C#-specific types to theme styles. Standard types stay covered by Zed's built-in defaults, so only the Roslyn-specific ones are listed here (same approach the built-in rust/cpp/go/python rules use). Fixes #85. Moved here from zed-industries/zed#60027 per @MrSubidubi's suggestion. Needs zed-industries/zed#60015 (dynamic registration of `textDocument/semanticTokens`) to actually deliver the tokens — together they resolve #85. ## Showcase <details> <summary>Click to view showcase</summary> **Before** — Roslyn's C# token types aren't mapped, so fields/keywords fall back to tree-sitter (a field looks like a plain variable): <img width="979" height="1089" alt="Screenshot 2026-06-28 at 10 06 41" src="https://github.com/user-attachments/assets/26a79bc9-f7c6-4700-8b39-0505af75180c" /> **After** — fields, constants, control-flow keywords and records get semantic colors: <img width="934" height="1032" alt="Screenshot 2026-06-28 at 09 58 15" src="https://github.com/user-attachments/assets/def44b05-85fa-4b39-9ea7-74ceb667bf6d" /> </details> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jolutz
pushed a commit
to jolutz/zed
that referenced
this pull request
Aug 8, 2026
…ries#60015) In C# files nothing gets semantic highlighting — class fields and other identifiers are colored by tree-sitter only, so a private field looks the same as a plain local variable. The reason: Roslyn (the C# language server) doesn't declare `semanticTokensProvider` statically in its `initialize` response. It registers it **dynamically** (`client/registerCapability`), and only when the client advertises `textDocument.semanticTokens.dynamicRegistration = true`. Zed advertised `false` and didn't handle such a registration, so Roslyn never offered semantic tokens at all. (rust-analyzer/gopls are unaffected — they declare the capability statically.) This is the first of two PRs. This one makes Roslyn actually **send** semantic tokens. The companion PR (zed-industries#60027) maps Roslyn's C#-specific token types to theme styles — without it the tokens arrive but most are dropped, since their types aren't in Zed's default rules. ## Solution - Advertise `textDocument.semanticTokens.dynamicRegistration = true`. - Handle the `textDocument/semanticTokens` registration and unregistration so the capability is stored, following the existing arms for `documentLink`, diagnostics, etc. ## Testing - Added a test that dynamically registers and unregisters `textDocument/semanticTokens` and checks the stored capability appears and is cleared. - Verified manually against Roslyn on a C# project: Zed now sends `textDocument/semanticTokens/full` and gets tokens back; before this change there was no semantic-token traffic at all. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - Support dynamic registration of the `textDocument/semanticTokens` capability. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Roslyn reports an extended token-type legend (field, controlKeyword, recordClass, extensionMethod, ...) that the default rules did not cover, so those tokens were silently dropped and C# fell back to tree-sitter-only highlighting. Map them to existing theme styles.
Objective
Companion to #60015. This PR adds highlighting support for Roslyn's (C#) semantic token types, so C# code can be colored correctly instead of being limited to the standard LSP token set.
Zed's default semantic token rules only cover the ~24 standard LSP token types, and there's no catch-all rule. Roslyn reports a much larger, C#-specific legend (
field,controlKeyword,recordClass,extensionMethod, ...), so any token whose type isn't one of those 24 is silently dropped — leaving C# fields, constants, control-flow keywords, records, etc. without semantic highlighting (a private field stays indistinguishable from a local variable).Solution
Add default rules in
default_semantic_token_rules.jsonmapping Roslyn's C# token types to existing theme styles (with fallback chains, in the existing// C#section).Testing
Self-Review Checklist:
Showcase
Click to view showcase
Before — Roslyn's C# token types aren't mapped, so fields/keywords fall back to tree-sitter (a field looks like a plain variable):
After — fields, constants, control-flow keywords and records get semantic colors:
Release Notes:
Improved C# semantic highlighting by mapping Roslyn's token types (fields, constants, records, control-flow keywords, and more) to theme styles.