@@ -96,19 +96,19 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
9696// Determine server type for specialized handling
9797serverName := getServerNameFromContext (ctx )
9898logging .Debug ("Server type detected" , "serverName" , serverName )
99-
99+
100100// Check if this server has sent file watchers
101101hasFileWatchers := len (watchers ) > 0
102-
102+
103103// For servers that need file preloading, we'll use a smart approach
104104if shouldPreloadFiles (serverName ) || ! hasFileWatchers {
105105go func () {
106106startTime := time .Now ()
107107filesOpened := 0
108-
108+
109109// Determine max files to open based on server type
110110maxFilesToOpen := 50 // Default conservative limit
111-
111+
112112switch serverName {
113113case "typescript" , "typescript-language-server" , "tsserver" , "vtsls" :
114114// TypeScript servers benefit from seeing more files
@@ -117,17 +117,17 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
117117// Java servers need to see many files for project model
118118maxFilesToOpen = 200
119119}
120-
120+
121121// First, open high-priority files
122122highPriorityFilesOpened := w .openHighPriorityFiles (ctx , serverName )
123123filesOpened += highPriorityFilesOpened
124-
124+
125125if cnf .DebugLSP {
126- logging .Debug ("Opened high-priority files" ,
126+ logging .Debug ("Opened high-priority files" ,
127127"count" , highPriorityFilesOpened ,
128128"serverName" , serverName )
129129}
130-
130+
131131// If we've already opened enough high-priority files, we might not need more
132132if filesOpened >= maxFilesToOpen {
133133if cnf .DebugLSP {
@@ -137,9 +137,9 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
137137}
138138return
139139}
140-
140+
141141// For the remaining slots, walk the directory and open matching files
142-
142+
143143err := filepath .WalkDir (w .workspacePath , func (path string , d os.DirEntry , err error ) error {
144144if err != nil {
145145return err
@@ -199,10 +199,10 @@ func (w *WorkspaceWatcher) AddRegistrations(ctx context.Context, id string, watc
199199func (w * WorkspaceWatcher ) openHighPriorityFiles (ctx context.Context , serverName string ) int {
200200cnf := config .Get ()
201201filesOpened := 0
202-
202+
203203// Define patterns for high-priority files based on server type
204204var patterns []string
205-
205+
206206switch serverName {
207207case "typescript" , "typescript-language-server" , "tsserver" , "vtsls" :
208208patterns = []string {
@@ -256,7 +256,7 @@ func (w *WorkspaceWatcher) openHighPriorityFiles(ctx context.Context, serverName
256256"**/.editorconfig" ,
257257}
258258}
259-
259+
260260// For each pattern, find and open matching files
261261for _ , pattern := range patterns {
262262// Use doublestar.Glob to find files matching the pattern (supports ** patterns)
@@ -267,17 +267,17 @@ func (w *WorkspaceWatcher) openHighPriorityFiles(ctx context.Context, serverName
267267}
268268continue
269269}
270-
270+
271271for _ , match := range matches {
272272// Convert relative path to absolute
273273fullPath := filepath .Join (w .workspacePath , match )
274-
274+
275275// Skip directories and excluded files
276276info , err := os .Stat (fullPath )
277277if err != nil || info .IsDir () || shouldExcludeFile (fullPath ) {
278278continue
279279}
280-
280+
281281// Open the file
282282if err := w .client .OpenFile (ctx , fullPath ); err != nil {
283283if cnf .DebugLSP {
@@ -289,17 +289,17 @@ func (w *WorkspaceWatcher) openHighPriorityFiles(ctx context.Context, serverName
289289logging .Debug ("Opened high-priority file" , "path" , fullPath )
290290}
291291}
292-
292+
293293// Add a small delay to prevent overwhelming the server
294294time .Sleep (20 * time .Millisecond )
295-
295+
296296// Limit the number of files opened per pattern
297297if filesOpened >= 5 && (serverName != "java" && serverName != "jdtls" ) {
298298break
299299}
300300}
301301}
302-
302+
303303return filesOpened
304304}
305305
@@ -310,16 +310,16 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
310310
311311// Store the watcher in the context for later use
312312ctx = context .WithValue (ctx , "workspaceWatcher" , w )
313-
313+
314314// If the server name isn't already in the context, try to detect it
315315if _ , ok := ctx .Value ("serverName" ).(string ); ! ok {
316316serverName := getServerNameFromContext (ctx )
317317ctx = context .WithValue (ctx , "serverName" , serverName )
318318}
319-
319+
320320serverName := getServerNameFromContext (ctx )
321321logging .Debug ("Starting workspace watcher" , "workspacePath" , workspacePath , "serverName" , serverName )
322-
322+
323323// Register handler for file watcher registrations from the server
324324lsp .RegisterFileWatchHandler (func (id string , watchers []protocol.FileSystemWatcher ) {
325325w .AddRegistrations (ctx , id , watchers )
@@ -414,7 +414,11 @@ func (w *WorkspaceWatcher) WatchWorkspace(ctx context.Context, workspacePath str
414414case event .Op & fsnotify .Create != 0 :
415415// Already handled earlier in the event loop
416416// 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+ }
418422if ! info .IsDir () && watchKind & protocol .WatchCreate != 0 {
419423w .debounceHandleFileEvent (ctx , uri , protocol .FileChangeType (protocol .Created ))
420424}
@@ -682,7 +686,7 @@ func getServerNameFromContext(ctx context.Context) string {
682686if serverName , ok := ctx .Value ("serverName" ).(string ); ok && serverName != "" {
683687return strings .ToLower (serverName )
684688}
685-
689+
686690// Otherwise, try to extract server name from the client command path
687691if w , ok := ctx .Value ("workspaceWatcher" ).(* WorkspaceWatcher ); ok && w != nil && w .client != nil && w .client .Cmd != nil {
688692path := strings .ToLower (w .client .Cmd .Path )
@@ -865,7 +869,7 @@ func (w *WorkspaceWatcher) openMatchingFile(ctx context.Context, path string) {
865869if watched , _ := w .isPathWatched (path ); watched {
866870// Get server name for specialized handling
867871serverName := getServerNameFromContext (ctx )
868-
872+
869873// Check if the file is a high-priority file that should be opened immediately
870874// This helps with project initialization for certain language servers
871875if isHighPriorityFile (path , serverName ) {
@@ -881,21 +885,21 @@ func (w *WorkspaceWatcher) openMatchingFile(ctx context.Context, path string) {
881885// For non-high-priority files, we'll use different strategies based on server type
882886if shouldPreloadFiles (serverName ) {
883887// For servers that benefit from preloading, open files but with limits
884-
888+
885889// Check file size - for preloading we're more conservative
886890if info .Size () > (1 * 1024 * 1024 ) { // 1MB limit for preloaded files
887891if cnf .DebugLSP {
888892logging .Debug ("Skipping large file for preloading" , "path" , path , "size" , info .Size ())
889893}
890894return
891895}
892-
896+
893897// Check file extension for common source files
894898ext := strings .ToLower (filepath .Ext (path ))
895-
899+
896900// Only preload source files for the specific language
897901shouldOpen := false
898-
902+
899903switch serverName {
900904case "typescript" , "typescript-language-server" , "tsserver" , "vtsls" :
901905shouldOpen = ext == ".ts" || ext == ".js" || ext == ".tsx" || ext == ".jsx"
@@ -913,7 +917,7 @@ func (w *WorkspaceWatcher) openMatchingFile(ctx context.Context, path string) {
913917// For unknown servers, be conservative
914918shouldOpen = false
915919}
916-
920+
917921if shouldOpen {
918922// Don't need to check if it's already open - the client.OpenFile handles that
919923if err := w .client .OpenFile (ctx , path ); err != nil && cnf .DebugLSP {
@@ -943,13 +947,13 @@ func isHighPriorityFile(path string, serverName string) bool {
943947fileName == "main.js"
944948case "gopls" :
945949// For Go, we want to open go.mod files immediately
946- return fileName == "go.mod" ||
950+ return fileName == "go.mod" ||
947951fileName == "go.sum" ||
948952// Also open main.go files
949953fileName == "main.go"
950954case "rust-analyzer" :
951955// For Rust, we want to open Cargo.toml files immediately
952- return fileName == "Cargo.toml" ||
956+ return fileName == "Cargo.toml" ||
953957fileName == "Cargo.lock" ||
954958// Also open lib.rs and main.rs
955959fileName == "lib.rs" ||
0 commit comments