@@ -96,19 +96,19 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
96
96
// Determine server type for specialized handling
97
97
serverName := getServerNameFromContext (ctx )
98
98
logging .Debug ("Server type detected" , "serverName" , serverName )
99
-
99
+
100
100
// Check if this server has sent file watchers
101
101
hasFileWatchers := len (watchers ) > 0
102
-
102
+
103
103
// For servers that need file preloading, we'll use a smart approach
104
104
if shouldPreloadFiles (serverName ) || ! hasFileWatchers {
105
105
go func () {
106
106
startTime := time .Now ()
107
107
filesOpened := 0
108
-
108
+
109
109
// Determine max files to open based on server type
110
110
maxFilesToOpen := 50 // Default conservative limit
111
-
111
+
112
112
switch serverName {
113
113
case "typescript" , "typescript-language-server" , "tsserver" , "vtsls" :
114
114
// TypeScript servers benefit from seeing more files
@@ -117,17 +117,17 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
117
117
// Java servers need to see many files for project model
118
118
maxFilesToOpen = 200
119
119
}
120
-
120
+
121
121
// First, open high-priority files
122
122
highPriorityFilesOpened := w .openHighPriorityFiles (ctx , serverName )
123
123
filesOpened += highPriorityFilesOpened
124
-
124
+
125
125
if cnf .DebugLSP {
126
- logging .Debug ("Opened high-priority files" ,
126
+ logging .Debug ("Opened high-priority files" ,
127
127
"count" , highPriorityFilesOpened ,
128
128
"serverName" , serverName )
129
129
}
130
-
130
+
131
131
// If we've already opened enough high-priority files, we might not need more
132
132
if filesOpened >= maxFilesToOpen {
133
133
if cnf .DebugLSP {
@@ -137,9 +137,9 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
137
137
}
138
138
return
139
139
}
140
-
140
+
141
141
// For the remaining slots, walk the directory and open matching files
142
-
142
+
143
143
err := filepath .WalkDir (w .workspacePath , func (path string , d os.DirEntry , err error ) error {
144
144
if err != nil {
145
145
return err
@@ -199,10 +199,10 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
199
199
func (w * WorkspaceWatcher ) openHighPriorityFiles (ctx context.Context , serverName string ) int {
200
200
cnf := config .Get ()
201
201
filesOpened := 0
202
-
202
+
203
203
// Define patterns for high-priority files based on server type
204
204
var patterns []string
205
-
205
+
206
206
switch serverName {
207
207
case "typescript" , "typescript-language-server" , "tsserver" , "vtsls" :
208
208
patterns = []string {
@@ -256,7 +256,7 @@ func (w *WorkspaceWatcher) openHighPriorityFiles(ctx context.Context, serverName
256
256
"**/.editorconfig" ,
257
257
}
258
258
}
259
-
259
+
260
260
// For each pattern, find and open matching files
261
261
for _ , pattern := range patterns {
262
262
// Use doublestar.Glob to find files matching the pattern (supports ** patterns)
@@ -267,17 +267,17 @@ func (w *WorkspaceWatcher) openHighPriorityFiles(ctx context.Context, serverName
267
267
}
268
268
continue
269
269
}
270
-
270
+
271
271
for _ , match := range matches {
272
272
// Convert relative path to absolute
273
273
fullPath := filepath .Join (w .workspacePath , match )
274
-
274
+
275
275
// Skip directories and excluded files
276
276
info , err := os .Stat (fullPath )
277
277
if err != nil || info .IsDir () || shouldExcludeFile (fullPath ) {
278
278
continue
279
279
}
280
-
280
+
281
281
// Open the file
282
282
if err := w .client .OpenFile (ctx , fullPath ); err != nil {
283
283
if cnf .DebugLSP {
@@ -289,17 +289,17 @@ func (w *WorkspaceWatcher) openHighPriorityFiles(ctx context.Context, serverName
289
289
logging .Debug ("Opened high-priority file" , "path" , fullPath )
290
290
}
291
291
}
292
-
292
+
293
293
// Add a small delay to prevent overwhelming the server
294
294
time .Sleep (20 * time .Millisecond )
295
-
295
+
296
296
// Limit the number of files opened per pattern
297
297
if filesOpened >= 5 && (serverName != "java" && serverName != "jdtls" ) {
298
298
break
299
299
}
300
300
}
301
301
}
302
-
302
+
303
303
return filesOpened
304
304
}
305
305
@@ -310,16 +310,16 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
310
310
311
311
// Store the watcher in the context for later use
312
312
ctx = context .WithValue (ctx , "workspaceWatcher" , w )
313
-
313
+
314
314
// If the server name isn't already in the context, try to detect it
315
315
if _ , ok := ctx .Value ("serverName" ).(string ); ! ok {
316
316
serverName := getServerNameFromContext (ctx )
317
317
ctx = context .WithValue (ctx , "serverName" , serverName )
318
318
}
319
-
319
+
320
320
serverName := getServerNameFromContext (ctx )
321
321
logging .Debug ("Starting workspace watcher" , "workspacePath" , workspacePath , "serverName" , serverName )
322
-
322
+
323
323
// Register handler for file watcher registrations from the server
324
324
lsp .RegisterFileWatchHandler (func (id string , watchers []protocol.FileSystemWatcher ) {
325
325
w .AddRegistrations (ctx , id , watchers )
@@ -414,7 +414,11 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
414
414
case event .Op & fsnotify .Create != 0 :
415
415
// Already handled earlier in the event loop
416
416
// Just send the notification if needed
417
- info , _ := os .Stat (event .Name )
417
+ info , err := os .Stat (event .Name )
418
+ if err != nil {
419
+ logging .Error ("Error getting file info" , "path" , event .Name , "error" , err )
420
+ return
421
+ }
418
422
if ! info .IsDir () && watchKind & protocol .WatchCreate != 0 {
419
423
w .debounceHandleFileEvent (ctx , uri , protocol .FileChangeType (protocol .Created ))
420
424
}
@@ -682,7 +686,7 @@ func getServerNameFromContext(ctx context.Context) string {
682
686
if serverName , ok := ctx .Value ("serverName" ).(string ); ok && serverName != "" {
683
687
return strings .ToLower (serverName )
684
688
}
685
-
689
+
686
690
// Otherwise, try to extract server name from the client command path
687
691
if w , ok := ctx .Value ("workspaceWatcher" ).(* WorkspaceWatcher ); ok && w != nil && w .client != nil && w .client .Cmd != nil {
688
692
path := strings .ToLower (w .client .Cmd .Path )
@@ -865,7 +869,7 @@ func (w *WorkspaceWatcher) openMatchingFile(ctx context.Context, path string) {
865
869
if watched , _ := w .isPathWatched (path ); watched {
866
870
// Get server name for specialized handling
867
871
serverName := getServerNameFromContext (ctx )
868
-
872
+
869
873
// Check if the file is a high-priority file that should be opened immediately
870
874
// This helps with project initialization for certain language servers
871
875
if isHighPriorityFile (path , serverName ) {
@@ -881,21 +885,21 @@ func (w *WorkspaceWatcher) openMatchingFile(ctx context.Context, path string) {
881
885
// For non-high-priority files, we'll use different strategies based on server type
882
886
if shouldPreloadFiles (serverName ) {
883
887
// For servers that benefit from preloading, open files but with limits
884
-
888
+
885
889
// Check file size - for preloading we're more conservative
886
890
if info .Size () > (1 * 1024 * 1024 ) { // 1MB limit for preloaded files
887
891
if cnf .DebugLSP {
888
892
logging .Debug ("Skipping large file for preloading" , "path" , path , "size" , info .Size ())
889
893
}
890
894
return
891
895
}
892
-
896
+
893
897
// Check file extension for common source files
894
898
ext := strings .ToLower (filepath .Ext (path ))
895
-
899
+
896
900
// Only preload source files for the specific language
897
901
shouldOpen := false
898
-
902
+
899
903
switch serverName {
900
904
case "typescript" , "typescript-language-server" , "tsserver" , "vtsls" :
901
905
shouldOpen = ext == ".ts" || ext == ".js" || ext == ".tsx" || ext == ".jsx"
@@ -913,7 +917,7 @@ func (w *WorkspaceWatcher) openMatchingFile(ctx context.Context, path string) {
913
917
// For unknown servers, be conservative
914
918
shouldOpen = false
915
919
}
916
-
920
+
917
921
if shouldOpen {
918
922
// Don't need to check if it's already open - the client.OpenFile handles that
919
923
if err := w .client .OpenFile (ctx , path ); err != nil && cnf .DebugLSP {
@@ -943,13 +947,13 @@ func isHighPriorityFile(path string, serverName string) bool {
943
947
fileName == "main.js"
944
948
case "gopls" :
945
949
// For Go, we want to open go.mod files immediately
946
- return fileName == "go.mod" ||
950
+ return fileName == "go.mod" ||
947
951
fileName == "go.sum" ||
948
952
// Also open main.go files
949
953
fileName == "main.go"
950
954
case "rust-analyzer" :
951
955
// For Rust, we want to open Cargo.toml files immediately
952
- return fileName == "Cargo.toml" ||
956
+ return fileName == "Cargo.toml" ||
953
957
fileName == "Cargo.lock" ||
954
958
// Also open lib.rs and main.rs
955
959
fileName == "lib.rs" ||
0 commit comments