Skip to content

Commit 60c19c7

Browse files
committed
minor fixups
Signed-off-by: Pranav Gaikwad <pgaikwad@redhat.com>
1 parent 7f3be0c commit 60c19c7

5 files changed

Lines changed: 144 additions & 56 deletions

File tree

external-providers/generic-external-provider/pkg/server_configurations/nodejs/symbol_cache_helper.go

Lines changed: 64 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package nodejs
22

33
import (
4+
"fmt"
45
"path/filepath"
56
"regexp"
67
"strings"
@@ -26,10 +27,28 @@ type nodejsSymbolSearchHelper struct {
2627
// The referenced condition pattern is parsed as "@<package>/<scope>#<type>.<child_type>...". If <package> & <scope>
2728
// is present, the node_modules/ folder for that package is added to search. If not, only source is searched.
2829
func (h *nodejsSymbolSearchHelper) GetDocumentUris(conditionsByCap ...provider.ConditionsByCap) []uri.URI {
30+
primaryPath := h.config.Location
31+
if after, ok := strings.CutPrefix(primaryPath, fmt.Sprintf("%s://", uri.FileScheme)); ok {
32+
primaryPath = after
33+
}
34+
additionalPaths := []string{}
35+
if val, ok := h.config.ProviderSpecificConfig["workspaceFolders"].([]string); ok {
36+
for _, path := range val {
37+
if after, prefixOk := strings.CutPrefix(path, fmt.Sprintf("%s://", uri.FileScheme)); prefixOk {
38+
path = after
39+
}
40+
if primaryPath == "" {
41+
primaryPath = path
42+
continue
43+
}
44+
additionalPaths = append(additionalPaths, path)
45+
}
46+
}
47+
2948
// find all files in the source first
3049
searcher := provider.FileSearcher{
31-
BasePath: h.config.Location,
32-
AdditionalPaths: h.config.ProviderSpecificConfig["workspaceFolders"].([]string),
50+
BasePath: primaryPath,
51+
AdditionalPaths: additionalPaths,
3352
ProviderConfigConstraints: provider.IncludeExcludeConstraints{
3453
IncludePathsOrPatterns: []string{".*\\.(ts|js)(x?)$"}, // only search js files
3554
ExcludePathsOrPatterns: []string{
@@ -80,34 +99,56 @@ func (h *nodejsSymbolSearchHelper) MatchFileContentByConditions(content string,
8099
}
81100

82101
func (h *nodejsSymbolSearchHelper) MatchSymbolByPatterns(symbol base.WorkspaceSymbolDefinitionsPair, patterns ...string) bool {
83-
filteredPatterns := map[string]bool{}
102+
simpleQueries := []parsedQuery{}
103+
scopedQueries := []parsedQuery{}
84104
for _, q := range patterns {
85105
parsedQuery := parseQuery(q)
86-
if parsedQuery != nil && parsedQuery.Query != nil {
87-
filteredPatterns[*parsedQuery.Query] = true
88-
// if there is a definition stored with this symbol
89-
// make sure the definition comes from the same package scope
90-
if symbol.Definitions != nil {
91-
for _, definition := range symbol.Definitions {
92-
if parsedQuery.Package != nil && parsedQuery.Scope != nil {
93-
definitionLoc, ok := definition.Location.Value.(protocol.Location)
94-
if !ok || strings.Contains(string(definitionLoc.URI), filepath.Join(*parsedQuery.Package, *parsedQuery.Scope)) {
95-
if h.SymbolSearchHelper.MatchSymbolByPatterns(base.WorkspaceSymbolDefinitionsPair{
96-
WorkspaceSymbol: definition,
97-
}, *parsedQuery.Query) {
98-
return true
99-
}
100-
}
101-
}
106+
if parsedQuery != nil && parsedQuery.Query != nil && parsedQuery.Package != nil && parsedQuery.Scope != nil {
107+
scopedQueries = append(scopedQueries, *parsedQuery)
108+
} else if parsedQuery != nil && parsedQuery.Query != nil {
109+
simpleQueries = append(simpleQueries, *parsedQuery)
110+
}
111+
}
112+
113+
for _, query := range scopedQueries {
114+
// when evaluating a scoped query, use the associated definitions of the symbol to check its origin
115+
if symbol.Definitions != nil {
116+
for _, definition := range symbol.Definitions {
117+
definitionLoc, ok := definition.Location.Value.(protocol.Location)
118+
if !ok {
119+
continue
102120
}
121+
// if the definition is under @<package>/<scope> && symbol name matches pattern, we have found right symbol
122+
if strings.Contains(string(definitionLoc.URI), filepath.Join(*query.Package, *query.Scope)) &&
123+
h.SymbolSearchHelper.MatchSymbolByPatterns(base.WorkspaceSymbolDefinitionsPair{WorkspaceSymbol: definition}, *query.Query) {
124+
return true
125+
}
126+
}
127+
} else {
128+
symbolLoc, ok := symbol.WorkspaceSymbol.Location.Value.(protocol.Location)
129+
if !ok {
130+
continue
131+
}
132+
if strings.Contains(string(symbolLoc.URI), filepath.Join(*query.Package, *query.Scope)) &&
133+
h.SymbolSearchHelper.MatchSymbolByPatterns(symbol, *query.Query) {
134+
return true
103135
}
104136
}
105137
}
106-
filteredPatternsList := []string{}
107-
for pattern := range filteredPatterns {
108-
filteredPatternsList = append(filteredPatternsList, pattern)
138+
for _, query := range simpleQueries {
139+
if symbol.Definitions != nil {
140+
for _, definition := range symbol.Definitions {
141+
if h.SymbolSearchHelper.MatchSymbolByPatterns(base.WorkspaceSymbolDefinitionsPair{WorkspaceSymbol: definition}, *query.Query) {
142+
return true
143+
}
144+
}
145+
} else {
146+
if h.SymbolSearchHelper.MatchSymbolByPatterns(symbol, *query.Query) {
147+
return true
148+
}
149+
}
109150
}
110-
return h.SymbolSearchHelper.MatchSymbolByPatterns(symbol, filteredPatternsList...)
151+
return false
111152
}
112153

113154
func (h *nodejsSymbolSearchHelper) MatchSymbolByConditions(symbol base.WorkspaceSymbolDefinitionsPair, conditions ...provider.ConditionsByCap) bool {

jsonrpc2_v2/conn.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"errors"
1111
"fmt"
1212
"io"
13+
"os"
1314
"sync"
1415
"sync/atomic"
1516
"time"
@@ -429,6 +430,8 @@ func (ac *AsyncCall) Await(ctx context.Context, result interface{}) error {
429430
return nil
430431
}
431432

433+
os.WriteFile("/tmp/response.json", ac.response.Result, 0644)
434+
432435
err := json.Unmarshal(ac.response.Result, result)
433436
if err != nil {
434437
return fmt.Errorf("json.Unmarshal error: %w", err)

lsp/base_service_client/base_service_client.go

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -488,50 +488,38 @@ func (sc *LSPServiceClientBase) populateDocumentSymbolCache(ctx context.Context,
488488
return
489489
}
490490

491-
didOpen := func(uri string, langID string, text []byte) error {
492-
params := protocol.DidOpenTextDocumentParams{
493-
TextDocument: protocol.TextDocumentItem{
494-
URI: uri,
495-
LanguageID: langID,
496-
Version: 0,
497-
Text: string(text),
498-
},
499-
}
500-
// typescript server seems to throw "No project" error without notification
501-
// perhaps there's a better way to do this
502-
return sc.Conn.Notify(ctx, "textDocument/didOpen", params)
503-
}
504-
505-
didClose := func(uri string) error {
506-
params := protocol.DidCloseTextDocumentParams{
507-
TextDocument: protocol.TextDocumentIdentifier{
508-
URI: uri,
509-
},
510-
}
511-
return sc.Conn.Notify(ctx, "textDocument/didClose", params)
512-
}
513-
514491
queryDocumentSymbol := func(ctx context.Context, uri uri.URI, content []byte) ([]protocol.DocumentSymbol, error) {
515492
if symbols, exists := sc.symbolCache.GetDocumentSymbols(uri); exists {
516493
return symbols, nil
517494
}
518-
var symbols []protocol.DocumentSymbol
495+
496+
var symbols []struct {
497+
protocol.DocumentSymbol
498+
Location *protocol.Location `json:"location,omitempty"`
499+
}
519500
params := protocol.DocumentSymbolParams{
520501
TextDocument: protocol.TextDocumentIdentifier{
521502
URI: string(uri),
522503
},
523504
}
524-
if err := didOpen(string(uri), sc.symbolSearchHelper.GetLanguageID(string(uri)), content); err != nil {
505+
if err := sc.didOpen(ctx, string(uri), sc.symbolSearchHelper.GetLanguageID(string(uri)), content); err != nil {
525506
sc.Log.Error(err, "didOpen request failed", "uri", uri)
526507
}
527508
if err := sc.Conn.Call(ctx, "textDocument/documentSymbol", params).Await(ctx, &symbols); err != nil {
528509
return nil, err
529510
}
530-
if err := didClose(string(uri)); err != nil {
511+
if err := sc.didClose(ctx, string(uri)); err != nil {
531512
sc.Log.Error(err, "didClose request failed", "uri", uri)
532513
}
533-
sc.symbolCache.SetDocumentSymbols(uri, symbols)
534-
return symbols, nil
514+
documentSymbols := []protocol.DocumentSymbol{}
515+
for _, symbol := range symbols {
516+
if symbol.Location != nil {
517+
symbol.DocumentSymbol.Range = symbol.Location.Range
518+
}
519+
documentSymbols = append(documentSymbols, symbol.DocumentSymbol)
520+
}
521+
sc.symbolCache.SetDocumentSymbols(uri, documentSymbols)
522+
return documentSymbols, nil
535523
}
536524

537525
workspaceSymbolKey := func(symbol protocol.WorkspaceSymbol) string {
@@ -558,7 +546,7 @@ func (sc *LSPServiceClientBase) populateDocumentSymbolCache(ctx context.Context,
558546
// definition is found, the symbol will be used as a reference symbol.
559547
positions := sc.getMatchingPositions(string(content), fileURI.Filename())
560548
for _, position := range positions {
561-
definitions := sc.getDefinitionForPosition(ctx, position)
549+
definitions := sc.getDefinitionForPosition(ctx, fileURI, position)
562550
wsSymbolsForDefinitions := map[string]protocol.WorkspaceSymbol{}
563551
for _, definition := range definitions {
564552
uri, err := toURI(definition.URI)
@@ -657,6 +645,29 @@ func (sc *LSPServiceClientBase) drainPendingSymbolCacheUpdates() {
657645
}
658646
}
659647

648+
func (sc *LSPServiceClientBase) didOpen(ctx context.Context, uri string, langID string, text []byte) error {
649+
params := protocol.DidOpenTextDocumentParams{
650+
TextDocument: protocol.TextDocumentItem{
651+
URI: uri,
652+
LanguageID: langID,
653+
Version: 0,
654+
Text: string(text),
655+
},
656+
}
657+
// typescript server seems to throw "No project" error without notification
658+
// perhaps there's a better way to do this
659+
return sc.Conn.Notify(ctx, "textDocument/didOpen", params)
660+
}
661+
662+
func (sc *LSPServiceClientBase) didClose(ctx context.Context, uri string) error {
663+
params := protocol.DidCloseTextDocumentParams{
664+
TextDocument: protocol.TextDocumentIdentifier{
665+
URI: uri,
666+
},
667+
}
668+
return sc.Conn.Notify(ctx, "textDocument/didClose", params)
669+
}
670+
660671
func toURI(path string) (uri.URI, error) {
661672
if strings.HasPrefix(path, "file://") {
662673
return uri.Parse(path)
@@ -702,12 +713,23 @@ func (sc *LSPServiceClientBase) getMatchingPositions(content string, path string
702713
return positions
703714
}
704715

705-
func (sc *LSPServiceClientBase) getDefinitionForPosition(ctx context.Context, position protocol.TextDocumentPositionParams) []protocol.Location {
716+
func (sc *LSPServiceClientBase) getDefinitionForPosition(ctx context.Context, uri uri.URI, position protocol.TextDocumentPositionParams) []protocol.Location {
706717
res := []protocol.Location{}
707718
if sc.ServerCapabilities.Supports("textDocument/definition") {
719+
content, err := os.ReadFile(uri.Filename())
720+
if err != nil {
721+
sc.Log.Error(err, "unable to read file", "uri", uri)
722+
return res
723+
}
724+
if err := sc.didOpen(ctx, string(position.TextDocument.URI), sc.symbolSearchHelper.GetLanguageID(string(position.TextDocument.URI)), content); err != nil {
725+
sc.Log.Error(err, "didOpen request failed", "uri", position.TextDocument.URI)
726+
}
708727
if err := sc.Conn.Call(ctx, "textDocument/definition", position).Await(ctx, &res); err != nil {
709728
sc.Log.Error(err, "textDocument/definition request failed", "position", position)
710729
}
730+
if err := sc.didClose(ctx, string(position.TextDocument.URI)); err != nil {
731+
sc.Log.Error(err, "didClose request failed", "uri", position.TextDocument.URI)
732+
}
711733
}
712734
return res
713735
}

lsp/base_service_client/symbol_cache.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"path/filepath"
66
"regexp"
7+
"strings"
78
"sync"
89

910
"github.com/go-logr/logr"
@@ -139,9 +140,26 @@ func (h *defaultSymbolSearchHelper) GetDocumentUris(conditionsByCap ...provider.
139140
}
140141
}
141142
}
143+
primaryPath := h.config.Location
144+
if after, ok := strings.CutPrefix(primaryPath, fmt.Sprintf("%s://", uri.FileScheme)); ok {
145+
primaryPath = after
146+
}
147+
additionalPaths := []string{}
148+
if val, ok := h.config.ProviderSpecificConfig["workspaceFolders"].([]string); ok {
149+
for _, path := range val {
150+
if after, prefixOk := strings.CutPrefix(path, fmt.Sprintf("%s://", uri.FileScheme)); prefixOk {
151+
path = after
152+
}
153+
if primaryPath == "" {
154+
primaryPath = path
155+
continue
156+
}
157+
additionalPaths = append(additionalPaths, path)
158+
}
159+
}
142160
searcher := provider.FileSearcher{
143-
BasePath: h.config.Location,
144-
AdditionalPaths: h.config.ProviderSpecificConfig["workspaceFolders"].([]string),
161+
BasePath: primaryPath,
162+
AdditionalPaths: additionalPaths,
145163
ProviderConfigConstraints: provider.IncludeExcludeConstraints{
146164
ExcludePathsOrPatterns: []string{
147165
filepath.Join(h.config.Location, "node_modules"),

provider/lib.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,11 +303,15 @@ func newCachedWalkDir() cachedWalkDir {
303303
}
304304
// do not recurse into excluded dirs
305305
for _, excludedDir := range excludedDirs {
306-
if path == excludedDir || strings.HasPrefix(path, excludedDir) {
306+
relPath, err := filepath.Rel(basePath, path)
307+
if err == nil && (relPath == excludedDir || strings.HasPrefix(relPath, excludedDir)) {
307308
return fs.SkipDir
308309
}
309310
}
310311
for _, excludedPattern := range excludedPatterns {
312+
if !strings.Contains(excludedPattern, "*") {
313+
continue
314+
}
311315
regex, err := regexp.Compile(excludedPattern)
312316
if err != nil {
313317
continue

0 commit comments

Comments
 (0)