Skip to content

Commit 6749049

Browse files
authored
LSP add workspace symbol queries (#4070)
1 parent d109ce2 commit 6749049

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

private/buf/buflsp/server.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"errors"
2323
"fmt"
2424
"runtime/debug"
25+
"slices"
2526
"strings"
2627

2728
"github.com/bufbuild/buf/private/buf/bufformat"
@@ -137,6 +138,7 @@ func (s *server) Initialize(
137138
},
138139
Full: true,
139140
},
141+
WorkspaceSymbolProvider: true,
140142
},
141143
ServerInfo: info,
142144
}, nil
@@ -505,3 +507,48 @@ func (s *server) SemanticTokensFull(
505507
}
506508
return &protocol.SemanticTokens{Data: encoded}, nil
507509
}
510+
511+
// Symbols is the entry point for workspace-wide symbol search.
512+
func (s *server) Symbols(
513+
ctx context.Context,
514+
params *protocol.WorkspaceSymbolParams,
515+
) ([]protocol.SymbolInformation, error) {
516+
const maxResults = 1000 // Limit results to avoid overwhelming clients
517+
query := strings.ToLower(params.Query)
518+
519+
var results []protocol.SymbolInformation
520+
for uri, file := range s.fileManager.uriToFile.Range {
521+
if file.ir.IsZero() {
522+
s.lsp.logger.DebugContext(ctx, fmt.Sprintf("workspace symbol: skipping file without IR: %s", uri))
523+
continue
524+
}
525+
526+
// Search through all symbols in this file.
527+
for _, sym := range file.symbols {
528+
if sym.ir.IsZero() {
529+
continue
530+
}
531+
symbolInfo := sym.GetSymbolInformation()
532+
if symbolInfo.Name == "" {
533+
continue // Symbol information not supported for this symbol.
534+
}
535+
536+
// Filter by query (case-insensitive substring match)
537+
if query != "" && !strings.Contains(strings.ToLower(symbolInfo.Name), query) {
538+
continue
539+
}
540+
results = append(results, symbolInfo)
541+
if len(results) >= maxResults {
542+
break
543+
}
544+
}
545+
}
546+
547+
slices.SortFunc(results, func(a, b protocol.SymbolInformation) int {
548+
if a.Name != b.Name {
549+
return strings.Compare(a.Name, b.Name)
550+
}
551+
return strings.Compare(a.ContainerName, b.ContainerName)
552+
})
553+
return results, nil
554+
}

private/buf/buflsp/symbol.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,55 @@ func (s *symbol) FormatDocs(ctx context.Context) string {
257257
return tooltip.String()
258258
}
259259

260+
// GetSymbolInformat returns the protocol symbol information for the symbol.
261+
func (s *symbol) GetSymbolInformation() protocol.SymbolInformation {
262+
if s.ir.IsZero() {
263+
return protocol.SymbolInformation{}
264+
}
265+
266+
fullName := s.ir.FullName()
267+
name := fullName.Name()
268+
if name == "" {
269+
return protocol.SymbolInformation{}
270+
}
271+
parentFullName := fullName.Parent()
272+
containerName := string(parentFullName)
273+
274+
location := protocol.Location{
275+
URI: s.file.uri,
276+
Range: s.Range(),
277+
}
278+
279+
// Determine the symbol kind for LSP.
280+
var kind protocol.SymbolKind
281+
switch s.ir.Kind() {
282+
case ir.SymbolKindMessage:
283+
kind = protocol.SymbolKindClass // Messages are like classes
284+
case ir.SymbolKindEnum:
285+
kind = protocol.SymbolKindEnum
286+
case ir.SymbolKindEnumValue:
287+
kind = protocol.SymbolKindEnumMember
288+
case ir.SymbolKindField:
289+
kind = protocol.SymbolKindField
290+
case ir.SymbolKindExtension:
291+
kind = protocol.SymbolKindField
292+
case ir.SymbolKindOneof:
293+
kind = protocol.SymbolKindClass // Oneof are like classes
294+
case ir.SymbolKindService:
295+
kind = protocol.SymbolKindInterface // Services are like interfaces
296+
case ir.SymbolKindMethod:
297+
kind = protocol.SymbolKindMethod
298+
default:
299+
kind = protocol.SymbolKindVariable
300+
}
301+
return protocol.SymbolInformation{
302+
Name: name,
303+
Kind: kind,
304+
Location: location,
305+
ContainerName: containerName,
306+
}
307+
}
308+
260309
func protowireTypeForPredeclared(name predeclared.Name) protowire.Type {
261310
switch name {
262311
case predeclared.Bool, predeclared.Int32, predeclared.Int64, predeclared.UInt32,

0 commit comments

Comments
 (0)