@@ -2,12 +2,14 @@ package watcher
8 "path/filepath"
9 "path/filepath"
10 "sync/atomic"
11 "sync/atomic"
13 "github.com/charmbracelet/crush/internal/config"
15 "github.com/charmbracelet/crush/internal/config"
@@ -113,8 +115,24 @@ func Start() error {
113 events := notify.Create | notify.Write | notify.Remove | notify.Rename
115 events := notify.Create | notify.Write | notify.Remove | notify.Rename
115 if err := notify.Watch(watchPath, gw.events, events); err != nil {
117 if err := notify.Watch(watchPath, gw.events, events); err != nil {
118+ // Check if the error might be due to file descriptor limits
119+ if isFileLimitError(err) {
120+ slog.Warn("lsp watcher: Hit file descriptor limit, attempting to increase", "error", err)
121+ if newLimit, rlimitErr := MaximizeOpenFileLimit(); rlimitErr == nil {
122+ slog.Info("lsp watcher: Increased file descriptor limit", "limit", newLimit)
123+ // Retry the watch operation
124+ if err = notify.Watch(watchPath, gw.events, events); err == nil {
125+ slog.Info("lsp watcher: Successfully set up watch after increasing limit")
128+ err = fmt.Errorf("still failed after increasing limit: %w", err)
130+ slog.Warn("lsp watcher: Failed to increase file descriptor limit", "error", rlimitErr)
116 return fmt.Errorf("lsp watcher: error setting up recursive watch on %s: %w", root, err)
133 return fmt.Errorf("lsp watcher: error setting up recursive watch on %s: %w", root, err)
119 slog.Info("lsp watcher: Started recursive watching", "root", root)
137 slog.Info("lsp watcher: Started recursive watching", "root", root)
120 return nil
138 return nil
@@ -335,3 +353,12 @@ func (gw *global) shutdown() {
335func Shutdown() {
353func Shutdown() {
336 instance().shutdown()
354 instance().shutdown()
357+// isFileLimitError checks if an error is related to file descriptor limits
358+func isFileLimitError(err error) bool {
362+ // Check for common file limit errors
363+ return errors.Is(err, syscall.EMFILE) || errors.Is(err, syscall.ENFILE)