diff --git a/assets/settings/default_semantic_token_rules.json b/assets/settings/default_semantic_token_rules.json index c070a253d3065f..b5b44d5fbb5db0 100644 --- a/assets/settings/default_semantic_token_rules.json +++ b/assets/settings/default_semantic_token_rules.json @@ -253,4 +253,75 @@ "token_modifiers": [], "style": ["type.event", "type"], }, + // C# (Roslyn) extended classification types + { + "token_type": "field", + "token_modifiers": [], + "style": ["property", "variable.member", "variable"], + }, + { + "token_type": "constant", + "token_modifiers": [], + "style": ["constant"], + }, + { + "token_type": "controlKeyword", + "token_modifiers": [], + "style": ["keyword.control", "keyword"], + }, + { + "token_type": "delegate", + "token_modifiers": [], + "style": ["type.delegate", "type"], + }, + { + "token_type": "extensionMethod", + "token_modifiers": [], + "style": ["function.method", "function"], + }, + { + "token_type": "operatorOverloaded", + "token_modifiers": [], + "style": ["operator"], + }, + { + "token_type": "recordClass", + "token_modifiers": [], + "style": ["type.class", "class", "type"], + }, + { + "token_type": "recordStruct", + "token_modifiers": [], + "style": ["type.struct", "struct", "type"], + }, + { + "token_type": "module", + "token_modifiers": [], + "style": ["namespace", "module"], + }, + { + "token_type": "functionPointer", + "token_modifiers": [], + "style": ["function", "type"], + }, + { + "token_type": "pointer", + "token_modifiers": [], + "style": ["type"], + }, + { + "token_type": "excludedCode", + "token_modifiers": [], + "style": ["comment"], + }, + { + "token_type": "stringVerbatim", + "token_modifiers": [], + "style": ["string"], + }, + { + "token_type": "stringEscapeCharacter", + "token_modifiers": [], + "style": ["string.escape", "string.special", "string"], + }, ] diff --git a/crates/settings/src/settings_store.rs b/crates/settings/src/settings_store.rs index 29d9f91dc6b56a..f9c8be0c7dad49 100644 --- a/crates/settings/src/settings_store.rs +++ b/crates/settings/src/settings_store.rs @@ -1796,6 +1796,36 @@ mod tests { ); } + #[test] + fn test_default_semantic_token_rules_cover_roslyn_token_types() { + let rules: SemanticTokenRules = + crate::parse_json_with_comments(&crate::default_semantic_token_rules()) + .expect("default_semantic_token_rules.json must parse"); + + // C# (Roslyn) reports its own extended token-type legend instead of the + // standard LSP types. Each of these needs a rule with a non-empty style, + // otherwise the tokens are dropped and C# falls back to tree-sitter-only + // highlighting. + for token_type in [ + "field", + "constant", + "controlKeyword", + "delegate", + "extensionMethod", + "operatorOverloaded", + "recordClass", + "recordStruct", + "module", + ] { + assert!( + rules.rules.iter().any(|rule| { + rule.token_type.as_deref() == Some(token_type) && !rule.style.is_empty() + }), + "default semantic token rules must map the C# (Roslyn) token type {token_type:?}" + ); + } + } + #[gpui::test] fn test_default_settings_release_channel_overrides(cx: &mut App) { // The test deals with overrides and should ignore the other set-ups (Preview and Stable runs)