diff --git a/internal/lsp/watcher/global_watcher.go b/internal/lsp/watcher/global_watcher.go index 29b19f316ba0f654ae779526b5926b1fe9785819..4d49e05b2626397a963383a4f95cecb0f3529727 100644 --- a/internal/lsp/watcher/global_watcher.go +++ b/internal/lsp/watcher/global_watcher.go @@ -12,6 +12,7 @@ import ( "github.com/charmbracelet/crush/internal/config" "github.com/charmbracelet/crush/internal/csync" "github.com/charmbracelet/crush/internal/fsext" + "github.com/charmbracelet/crush/internal/home" "github.com/charmbracelet/crush/internal/lsp/protocol" "github.com/fsnotify/fsnotify" ) @@ -91,16 +92,31 @@ func (gw *global) unregister(name string) { // events for all files within watched directories. Multiple calls with the same workspace // are safe since fsnotify handles directory deduplication internally. func Start() error { + cfg := config.Get() + root := cfg.WorkingDir() + + // Skip file watching entirely when running in home directory + // Home directories typically contain too many files and directories + // which can overwhelm the file watcher and cause "too many open files" errors + if root == home.Dir() { + slog.Info("lsp watcher: Skipping file watcher in home directory to prevent resource exhaustion", "path", root) + return nil + } + gw := instance() + // If watcher creation failed, skip file watching entirely + if gw.watcher == nil { + slog.Warn("lsp watcher: File watcher not available, file watching disabled") + return nil + } + // technically workspace root is always the same... if gw.started.Load() { slog.Debug("lsp watcher: watcher already set up, skipping") return nil } - cfg := config.Get() - root := cfg.WorkingDir() slog.Debug("lsp watcher: set workspace directory to global watcher", "path", root) // Store the workspace root for hierarchical ignore checking @@ -116,7 +132,9 @@ func Start() error { // Multiple calls with the same directories are safe (fsnotify deduplicates) err := fsext.WalkDirectories(root, func(path string, d os.DirEntry, err error) error { if err != nil { - return err + // Skip directories we don't have permission to access + slog.Debug("lsp watcher: Skipping directory due to error", "path", path, "error", err) + return nil } // Add directory to watcher (fsnotify handles deduplication automatically) @@ -137,7 +155,8 @@ func Start() error { // fsnotify handles deduplication internally, so we don't need to track watched directories. func (gw *global) addDirectoryToWatcher(dirPath string) error { if gw.watcher == nil { - return fmt.Errorf("lsp watcher: global watcher not initialized") + // File watching is disabled, skip silently + return nil } // Add directory to fsnotify watcher - fsnotify handles deduplication @@ -160,7 +179,7 @@ func (gw *global) processEvents() { cfg := config.Get() if gw.watcher == nil || !gw.started.Load() { - slog.Error("lsp watcher: Global watcher not initialized") + slog.Debug("lsp watcher: Global watcher not available or not started") return }