Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,35 @@ private static async Task GetClassifiedSpansForDocumentAsync(
var spans = await ClassifierHelper.GetClassifiedSpansAsync(
document, textSpans, options, includeAdditiveSpans: true, cancellationToken).ConfigureAwait(false);

// The spans returned to us may include some empty spans, which we don't care about. We also don't care
// about the 'text' classification. It's added for everything between real classifications (including
// Some classified spans may not be relevant and should be filtered out before we convert to tokens.
var filteredSpans = spans.Where(s => !ShouldFilterClassification(s));

classifiedSpans.AddRange(filteredSpans);
}

private static bool ShouldFilterClassification(ClassifiedSpan s)
{
// The spans returned to us may include some empty spans, which we don't care about.
if (s.TextSpan.IsEmpty)
{
return true;
}

// We also don't care about the 'text' classification. It's added for everything between real classifications (including
// whitespace), and just means 'don't classify this'. No need for us to actually include that in
// semantic tokens as it just wastes space in the result.
var nonEmptySpans = spans.Where(s => !s.TextSpan.IsEmpty && s.ClassificationType != ClassificationTypeNames.Text);
classifiedSpans.AddRange(nonEmptySpans);
if (s.ClassificationType == ClassificationTypeNames.Text)
{
return true;
}

// Additive classification types that are mapped to TokenModifiers.None are not rendered by the client and do not need to be included.
if (SemanticTokensSchema.AdditiveClassificationTypeToTokenModifier.TryGetValue(s.ClassificationType, out var modifier) && modifier == TokenModifiers.None)
{
return true;
}

return false;
}

private static void ConvertMultiLineToSingleLineSpans(SourceText text, SegmentedList<ClassifiedSpan> classifiedSpans, SegmentedList<ClassifiedSpan> updatedClassifiedSpans)
Expand Down Expand Up @@ -288,37 +311,21 @@ private static int ComputeNextToken(
var tokenLength = originalTextSpan.Length;
Contract.ThrowIfFalse(tokenLength > 0);

// We currently only have one modifier (static). The logic below will need to change in the future if other
// modifiers are added in the future.
var modifierBits = TokenModifiers.None;
var tokenTypeIndex = 0;

// Classified spans with the same text span should be combined into one token.
while (classifiedSpans[currentClassifiedSpanIndex].TextSpan == originalTextSpan)
{
var classificationType = classifiedSpans[currentClassifiedSpanIndex].ClassificationType;
if (classificationType == ClassificationTypeNames.StaticSymbol)
{
// 4. Token modifiers - each set bit will be looked up in SemanticTokensLegend.tokenModifiers
modifierBits |= TokenModifiers.Static;
}
else if (classificationType == ClassificationTypeNames.ReassignedVariable)
{
// 5. Token modifiers - each set bit will be looked up in SemanticTokensLegend.tokenModifiers
modifierBits |= TokenModifiers.ReassignedVariable;
}
else if (classificationType == ClassificationTypeNames.ObsoleteSymbol)
{
// 6. Token modifiers - each set bit will be looked up in SemanticTokensLegend.tokenModifiers
modifierBits |= TokenModifiers.Deprecated;
}
else if (classificationType == ClassificationTypeNames.TestCode)

if (SemanticTokensSchema.AdditiveClassificationTypeToTokenModifier.TryGetValue(classificationType, out var modifier))
{
// Skip additive types that are not being converted to token modifiers.
modifierBits |= modifier;
}
else
{
// 7. Token type - looked up in SemanticTokensLegend.tokenTypes (language server defined mapping
// 5. Token type - looked up in SemanticTokensLegend.tokenTypes (language server defined mapping
// from integer to LSP token types).
tokenTypeIndex = GetTokenTypeIndex(classificationType);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ internal readonly struct SemanticTokensSchema
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 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.
Expand Down
Loading
Loading