@@ -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+ }
0 commit comments