/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/LanguageServer/Protocol/Handler/SemanticTokens/SemanticTokensSchema.cs
147 строк
8 KB
Joey Robichaud
Colorization for array, pointer, and function pointer type aliases followup (#81363)
20 ноя 2025, 11:04
Не верифицирован
20 ноя 2025, 11:04
eb2ec00
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.Classification; using Roslyn.LanguageServer.Protocol; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.SemanticTokens; internal readonly struct SemanticTokensSchema { // TO-DO: Expand this mapping once support for custom token types is added: // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1085998 /// <summary> /// Core VS classifications, only map a few things to LSP. The rest we keep as our own standard classification /// type names so those continue to work in VS. /// </summary> private static readonly ImmutableDictionary<string, string> s_vsDirectTypeMap = new Dictionary<string, string>() { [ClassificationTypeNames.Comment] = SemanticTokenTypes.Comment, [ClassificationTypeNames.Identifier] = SemanticTokenTypes.Variable, [ClassificationTypeNames.Keyword] = SemanticTokenTypes.Keyword, [ClassificationTypeNames.NumericLiteral] = SemanticTokenTypes.Number, [ClassificationTypeNames.Operator] = SemanticTokenTypes.Operator, [ClassificationTypeNames.StringLiteral] = SemanticTokenTypes.String, }.ToImmutableDictionary(); /// <summary> /// The 'pure' set of classification types maps exact Roslyn matches to the well defined values actually in LSP. /// For example "class name" to "class". Importantly though, if there is no exact match, we do not map things /// along. This allows the user to theme things however they want. /// </summary> private static readonly ImmutableDictionary<string, string> s_pureLspDirectTypeMap = s_vsDirectTypeMap.Concat(new Dictionary<string, string> { [ClassificationTypeNames.ClassName] = SemanticTokenTypes.Class, [ClassificationTypeNames.StructName] = SemanticTokenTypes.Struct, [ClassificationTypeNames.NamespaceName] = SemanticTokenTypes.Namespace, [ClassificationTypeNames.EnumName] = SemanticTokenTypes.Enum, [ClassificationTypeNames.InterfaceName] = SemanticTokenTypes.Interface, [ClassificationTypeNames.TypeParameterName] = SemanticTokenTypes.TypeParameter, [ClassificationTypeNames.ParameterName] = SemanticTokenTypes.Parameter, [ClassificationTypeNames.LocalName] = SemanticTokenTypes.Variable, [ClassificationTypeNames.PropertyName] = SemanticTokenTypes.Property, [ClassificationTypeNames.MethodName] = SemanticTokenTypes.Method, [ClassificationTypeNames.EnumMemberName] = SemanticTokenTypes.EnumMember, [ClassificationTypeNames.EventName] = SemanticTokenTypes.Event, [ClassificationTypeNames.PreprocessorKeyword] = SemanticTokenTypes.Macro, // in https://code.visualstudio.com/api/language-extensions/semantic-highlight-guide#standard-token-types-and-modifiers [ClassificationTypeNames.LabelName] = "label", }).ToImmutableDictionary(); /// <summary> /// A schema for mapping classification type names to VS LSP token names. This maps a few classification type names /// directly to LSP semantic token types, but otherwise generally returns the classification type name as a custom token type. /// </summary> private static readonly SemanticTokensSchema s_vsTokenSchema = new(ClassificationTypeNames.AllTypeNames .Where(classificationTypeName => !ClassificationTypeNames.AdditiveTypeNames.Contains(classificationTypeName)) .ToImmutableDictionary( classificationTypeName => classificationTypeName, classificationTypeName => IDictionaryExtensions.GetValueOrDefault(s_vsDirectTypeMap, classificationTypeName) ?? classificationTypeName)); /// <summary> /// A schema for mapping classification type names to 'pure' LSP token names. This includes classification type names /// that are directly mapped to LSP semantic token types as well as mappings from roslyn classification type names to /// LSP compatible custom token type names. /// </summary> private static readonly SemanticTokensSchema s_pureLspTokenSchema = new(ClassificationTypeNames.AllTypeNames .Where(classificationTypeName => !ClassificationTypeNames.AdditiveTypeNames.Contains(classificationTypeName)) .ToImmutableDictionary( classificationTypeName => classificationTypeName, classificationTypeName => IDictionaryExtensions.GetValueOrDefault(s_pureLspDirectTypeMap, classificationTypeName) ?? CustomLspSemanticTokenNames.ClassificationTypeNameToCustomTokenName[classificationTypeName])); /// <summary> /// Mapping from additive classification type names to LSP token modifiers. /// </summary> public static readonly ImmutableDictionary<string, TokenModifiers> AdditiveClassificationTypeToTokenModifier = new Dictionary<string, TokenModifiers>() { [ClassificationTypeNames.StaticSymbol] = SemanticTokens.TokenModifiers.Static, [ClassificationTypeNames.ReassignedVariable] = SemanticTokens.TokenModifiers.ReassignedVariable, [ClassificationTypeNames.ObsoleteSymbol] = SemanticTokens.TokenModifiers.Deprecated, [ClassificationTypeNames.TestCode] = SemanticTokens.TokenModifiers.None, }.ToImmutableDictionary(); /// <summary> /// Mapping from roslyn <see cref="ClassificationTypeNames"/> to the LSP token name. This is either a standard /// <see cref="SemanticTokenTypes"/> or a custom token name. /// </summary> public readonly IReadOnlyDictionary<string, string> TokenTypeMap; /// <summary> /// Mapping from the semantic token type name to the index in <see cref="AllTokenTypes"/>. Required since we report /// tokens back to LSP as a series of ints, and LSP needs a way to decipher them. /// </summary> public readonly IReadOnlyDictionary<string, int> TokenTypeToIndex; /// <summary> /// Equivalent to see <see cref="SemanticTokenTypes.AllTypes"/> combined with the remaining custom token names from <see cref="TokenTypeMap"/> /// </summary> public readonly ImmutableArray<string> AllTokenTypes; public SemanticTokensSchema(IReadOnlyDictionary<string, string> tokenTypeMap) { TokenTypeMap = tokenTypeMap; // Get all custom token type names that don't directly map to an built-in LSP semantic token type. var customTokenTypes = TokenTypeMap.Values .Where(tokenType => !SemanticTokenTypes.AllTypes.Contains(tokenType)) .Order() .ToImmutableArray(); AllTokenTypes = [.. SemanticTokenTypes.AllTypes, .. customTokenTypes]; var tokenTypeToIndex = new Dictionary<string, int>(); foreach (var lspTokenType in SemanticTokenTypes.AllTypes) tokenTypeToIndex.Add(lspTokenType, tokenTypeToIndex.Count); foreach (var roslynTokenType in customTokenTypes) tokenTypeToIndex.Add(roslynTokenType, tokenTypeToIndex.Count); TokenTypeToIndex = tokenTypeToIndex; } public static SemanticTokensSchema GetSchema(bool clientSupportsVisualStudioExtensions) => clientSupportsVisualStudioExtensions ? s_vsTokenSchema : s_pureLspTokenSchema; public static SemanticTokensSchema LegacyTokenSchemaForRazor => s_vsTokenSchema; public static SemanticTokensSchema LegacyTokensSchemaForLSIF => s_vsTokenSchema; public static string[] TokenModifiers = [ // This must be in the same order as SemanticTokens.TokenModifiers, but skip the "None" item SemanticTokenModifiers.Static, nameof(SemanticTokens.TokenModifiers.ReassignedVariable), SemanticTokenModifiers.Deprecated, ]; }