diff --git a/go.mod b/go.mod index ff4eab1623e5a73e91d403ad89dc7b40150112eb..7c29af04b932c44304bb76ec932c476ea1f89fe0 100644 --- a/go.mod +++ b/go.mod @@ -112,8 +112,8 @@ require ( github.com/ncruces/julianday v1.0.0 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/raphamorim/notify v0.9.3 github.com/rivo/uniseg v0.4.7 - github.com/rjeczalik/notify v0.9.3 github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/sethvargo/go-retry v0.3.0 // indirect github.com/spf13/cast v1.7.1 // indirect diff --git a/go.sum b/go.sum index 74a8425c0431ce926f07e0bb3c3bd7ac540367c7..1a7f1fa4c6ab97f37f459cb9be75c281d65f61cc 100644 --- a/go.sum +++ b/go.sum @@ -86,7 +86,7 @@ github.com/charmbracelet/colorprofile v0.3.2 h1:9J27WdztfJQVAQKX2WOlSSRB+5gaKqqI github.com/charmbracelet/colorprofile v0.3.2/go.mod h1:mTD5XzNeWHj8oqHb+S1bssQb7vIHbepiebQ2kPKVKbI= github.com/charmbracelet/fang v0.3.1-0.20250711140230-d5ebb8c1d674 h1:+Cz+VfxD5DO+JT1LlswXWhre0HYLj6l2HW8HVGfMuC0= github.com/charmbracelet/fang v0.3.1-0.20250711140230-d5ebb8c1d674/go.mod h1:9gCUAHmVx5BwSafeyNr3GI0GgvlB1WYjL21SkPp1jyU= -github.com/charmbracelet/glamour/v2 v2.0.0-20250811143442-a27abb32f018 h1:PU4Zvpagsk5sgaDxn5W4sxHuLp9QRMBZB3bFSk40A4w= +github.com/charmbracelet/glamour/v2 v2.0.0-20250811143442-a27abb32f018 h1:5KgReOUbYf1O8+dIiGF0JVirb5NJNjE0gLQMwxDJap4= github.com/charmbracelet/glamour/v2 v2.0.0-20250811143442-a27abb32f018/go.mod h1:Z/GLmp9fzaqX4ze3nXG7StgWez5uBM5XtlLHK8V/qSk= github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.3.0.20250721205738-ea66aa652ee0 h1:sWRGoSw/JsO2S4t2+fmmEkRbkOxphI0AxZkQPQVKWbs= github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.3.0.20250721205738-ea66aa652ee0/go.mod h1:XIuqKpZTUXtVyeyiN1k9Tc/U7EzfaDnVc34feFHfBws= @@ -94,7 +94,7 @@ github.com/charmbracelet/log/v2 v2.0.0-20250226163916-c379e29ff706 h1:WkwO6Ks3mS github.com/charmbracelet/log/v2 v2.0.0-20250226163916-c379e29ff706/go.mod h1:mjJGp00cxcfvD5xdCa+bso251Jt4owrQvuimJtVmEmM= github.com/charmbracelet/ultraviolet v0.0.0-20250912143111-9785ff826cbf h1:2fs3BT8BFjpJ4134Tq4VoBm/fE9FB2f2P/FhmzsWelQ= github.com/charmbracelet/ultraviolet v0.0.0-20250912143111-9785ff826cbf/go.mod h1:V21rZtvULxJyG8tUsRC8caTBvKNHOuRJVxH+G6ghH0Y= -github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ= +github.com/charmbracelet/x/ansi v0.10.1 h1:LT77A3bpevRD0yZ5NDR5nonS7N83mxzzGwuZcTGezLE= github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE= github.com/charmbracelet/x/cellbuf v0.0.14-0.20250811133356-e0c5dbe5ea4a h1:zYSNtEJM9jwHbJts2k+Hroj+xQwsW1yxc4Wopdv7KaI= github.com/charmbracelet/x/cellbuf v0.0.14-0.20250811133356-e0c5dbe5ea4a/go.mod h1:rc2bsPC6MWae3LdOxNO1mOb443NlMrrDL0xEya48NNc= @@ -232,13 +232,13 @@ github.com/pressly/goose/v3 v3.25.0 h1:6WeYhMWGRCzpyd89SpODFnCBCKz41KrVbRT58nVjG github.com/pressly/goose/v3 v3.25.0/go.mod h1:4hC1KrritdCxtuFsqgs1R4AU5bWtTAf+cnWvfhf2DNY= github.com/qjebbs/go-jsons v0.0.0-20221222033332-a534c5fc1c4c h1:kmzxiX+OB0knCo1V0dkEkdPelzCdAzCURCfmFArn2/A= github.com/qjebbs/go-jsons v0.0.0-20221222033332-a534c5fc1c4c/go.mod h1:wNJrtinHyC3YSf6giEh4FJN8+yZV7nXBjvmfjhBIcw4= +github.com/raphamorim/notify v0.9.3 h1:sOUIE8U6wtt93QA3/2HOXsGsrsVvT7US5Ye01+Hzl9E= +github.com/raphamorim/notify v0.9.3/go.mod h1:3FXSIPyrunV10GCnLGPrpSxoY/Dxi+saeQb9hf+TDSo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZeY= -github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= diff --git a/internal/lsp/watcher/global_watcher.go b/internal/lsp/watcher/global_watcher.go index 5a546a7db45ffa006a97d9ba98d8816665a6efa1..c9aa4b3a26e42fe9a9e2c86834147828534c70fc 100644 --- a/internal/lsp/watcher/global_watcher.go +++ b/internal/lsp/watcher/global_watcher.go @@ -16,12 +16,12 @@ import ( "github.com/charmbracelet/crush/internal/csync" "github.com/charmbracelet/crush/internal/fsext" "github.com/charmbracelet/crush/internal/lsp/protocol" - "github.com/rjeczalik/notify" + "github.com/raphamorim/notify" ) // global manages file watching shared across all LSP clients. // -// IMPORTANT: This implementation uses github.com/rjeczalik/notify which provides +// IMPORTANT: This implementation uses github.com/raphamorim/notify which provides // recursive watching on all platforms. On macOS it uses FSEvents, on Linux it // uses inotify (with recursion handled by the library), and on Windows it uses // ReadDirectoryChangesW. @@ -30,6 +30,7 @@ import ( // - Single watch point for entire directory tree // - Automatic recursive watching without manually adding subdirectories // - No file descriptor exhaustion issues +// - Built-in ignore system for filtering file events type global struct { // Channel for receiving file system events events chan notify.EventInfo @@ -83,7 +84,7 @@ func (gw *global) unregister(name string) { // Start sets up recursive watching on the workspace root. // -// Note: We use github.com/rjeczalik/notify which provides recursive watching +// Note: We use github.com/raphamorim/notify which provides recursive watching // with a single watch point. The "..." suffix means watch recursively. // This is much more efficient than manually walking and watching each directory. func Start() error { @@ -103,6 +104,12 @@ func Start() error { gw.root = root gw.started.Store(true) + // Set up ignore system + if err := setupIgnoreSystem(root); err != nil { + slog.Warn("lsp watcher: Failed to set up ignore system", "error", err) + // Continue anyway, but without ignore functionality + } + // Start the event processing goroutine gw.wg.Add(1) go gw.processEvents() @@ -162,11 +169,6 @@ func (gw *global) processEvents() { path := event.Path() - // Skip ignored files - if fsext.ShouldExcludeFile(gw.root, path) { - continue - } - if cfg != nil && cfg.Options.DebugLSP { slog.Debug("lsp watcher: Global watcher received event", "path", path, "event", event.Event().String()) } @@ -362,3 +364,31 @@ func isFileLimitError(err error) bool { // Check for common file limit errors return errors.Is(err, syscall.EMFILE) || errors.Is(err, syscall.ENFILE) } + +// setupIgnoreSystem configures the notify library's ignore system +// to use .crushignore and .gitignore files for filtering file events +func setupIgnoreSystem(root string) error { + // Create a new ignore matcher for the workspace root + im := notify.NewIgnoreMatcher(root) + + // Load .crushignore file if it exists + crushignorePath := filepath.Join(root, ".crushignore") + if _, err := os.Stat(crushignorePath); err == nil { + if err := im.LoadIgnoreFile(crushignorePath); err != nil { + slog.Warn("lsp watcher: Failed to load .crushignore file", "error", err) + } + } + + // Load .gitignore file if it exists + gitignorePath := filepath.Join(root, ".gitignore") + if _, err := os.Stat(gitignorePath); err == nil { + if err := im.LoadIgnoreFile(gitignorePath); err != nil { + slog.Warn("lsp watcher: Failed to load .gitignore file", "error", err) + } + } + + // Set as the global ignore matcher + notify.SetIgnoreMatcher(im) + + return nil +} diff --git a/internal/lsp/watcher/global_watcher_test.go b/internal/lsp/watcher/global_watcher_test.go index cfbe8a51fb9be09fdfdc9f37be830c92d6b6eab8..f33244dea3b3b95bb65c8a570d366d4b887f6b34 100644 --- a/internal/lsp/watcher/global_watcher_test.go +++ b/internal/lsp/watcher/global_watcher_test.go @@ -8,7 +8,7 @@ import ( "time" "github.com/charmbracelet/crush/internal/csync" - "github.com/rjeczalik/notify" + "github.com/raphamorim/notify" ) func TestGlobalWatcher(t *testing.T) {