Skip to content

Commit 6f5aa39

Browse files
Support modifiers in LSP semantic tokens (#4130)
Ref: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#semanticTokenModifiers We may as well populate these if we can while we're at it. Starting with deprecated and "defaultLibrary", aka builtin symbols, seems useful to report to clients, which can colorize these differently in the editor to call out their difference.
1 parent 601ce2a commit 6f5aa39

File tree

1 file changed

+35
-5
lines changed

1 file changed

+35
-5
lines changed

private/buf/buflsp/server.go

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ const (
3636
maxSymbolResults = 1000
3737
)
3838

39+
// The subset of SemanticTokenTypes that we support.
40+
// Must match the order of [semanticTypeLegend].
41+
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_semanticTokens
3942
const (
4043
semanticTypeType = iota
4144
semanticTypeStruct
@@ -45,15 +48,35 @@ const (
4548
semanticTypeInterface
4649
semanticTypeMethod
4750
semanticTypeDecorator
51+
semanticTypeNamespace
52+
)
53+
54+
// The subset of SemanticTokenModifiers that we support.
55+
// Must match the order of [semanticModifierLegend].
56+
// Semantic modifiers are encoded as a bitset, hence the shifted iota.
57+
// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_semanticTokens
58+
const (
59+
semanticModifierDeprecated = 1 << iota
60+
semanticModifierDefaultLibrary
4861
)
4962

5063
var (
51-
// These slices must match the order of the indices in the above const block.
64+
// These slices must match the order of the indices in the above const blocks.
5265
semanticTypeLegend = []string{
53-
"type", "struct", "variable", "enum",
54-
"enumMember", "interface", "method", "decorator",
66+
"type",
67+
"struct",
68+
"variable",
69+
"enum",
70+
"enumMember",
71+
"interface",
72+
"method",
73+
"decorator",
74+
"namespace",
75+
}
76+
semanticModifierLegend = []string{
77+
"deprecated",
78+
"defaultLibrary", // maps to builtin values
5579
}
56-
semanticModifierLegend = []string{}
5780
)
5881

5982
// server is an implementation of [protocol.Server].
@@ -442,10 +465,13 @@ func (s *server) SemanticTokensFull(
442465
)
443466
for _, symbol := range file.symbols {
444467
var semanticType uint32
468+
var semanticModifier uint32
445469
if symbol.isOption {
446470
semanticType = semanticTypeDecorator
447471
} else {
448472
switch symbol.ir.Kind() {
473+
case ir.SymbolKindPackage:
474+
semanticType = semanticTypeNamespace
449475
case ir.SymbolKindMessage:
450476
semanticType = semanticTypeStruct
451477
case ir.SymbolKindEnum:
@@ -454,6 +480,7 @@ func (s *server) SemanticTokensFull(
454480
// For predeclared types, we set semanticType to semanticTypeType
455481
if symbol.IsBuiltIn() {
456482
semanticType = semanticTypeType
483+
semanticModifier += semanticModifierDefaultLibrary
457484
} else {
458485
semanticType = semanticTypeVariable
459486
}
@@ -469,6 +496,9 @@ func (s *server) SemanticTokensFull(
469496
continue
470497
}
471498
}
499+
if _, ok := symbol.ir.Deprecated().AsBool(); ok {
500+
semanticModifier += semanticModifierDeprecated
501+
}
472502

473503
startLocation := symbol.span.Location(symbol.span.Start, positionalEncoding)
474504
endLocation := symbol.span.Location(symbol.span.End, positionalEncoding)
@@ -486,7 +516,7 @@ func (s *server) SemanticTokensFull(
486516
if i == startLocation.Line {
487517
symbolLen -= uint32(startLocation.Column - 1)
488518
}
489-
encoded = append(encoded, newLine-prevLine, newCol, symbolLen, semanticType, 0)
519+
encoded = append(encoded, newLine-prevLine, newCol, symbolLen, semanticType, semanticModifier)
490520
prevLine = newLine
491521
if i == startLocation.Line {
492522
prevCol = uint32(startLocation.Column - 1)

0 commit comments

Comments
 (0)