From 274aaa25c97f0bdab0439c2d80f375ca1a639fa3 Mon Sep 17 00:00:00 2001 From: wuyangfan <1102042793@qq.com> Date: Sun, 17 May 2026 04:26:18 +0800 Subject: [PATCH 1/2] fix: apply --exclude globs under each --search-path root Exclude patterns were built relative to the first search path only, so patterns like `ghi/def` did not exclude matching paths under additional `--search-path` roots. Prefix relative globs with `**/` when multiple search paths are used. Fixes #1919 Co-authored-by: Cursor --- src/walk.rs | 41 +++++++++++++++++++++++++++++++++++++++-- tests/tests.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/src/walk.rs b/src/walk.rs index 018ad2f70..a52f909f7 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -330,12 +330,18 @@ impl WorkerState { fn build_overrides(&self, paths: &[PathBuf]) -> Result { let first_path = &paths[0]; let config = &self.config; + let multi_root = paths.len() > 1; let mut builder = OverrideBuilder::new(first_path); for pattern in &config.exclude_patterns { + let pattern = if multi_root { + Cow::Owned(normalize_exclude_pattern_for_multi_root(pattern)) + } else { + Cow::Borrowed(pattern.as_str()) + }; builder - .add(pattern) + .add(pattern.as_ref()) .map_err(|e| anyhow!("Malformed exclude pattern: {}", e))?; } @@ -687,6 +693,21 @@ fn search_str_for_entry<'a>( } } +/// When multiple `--search-path` roots are used, exclude globs are matched relative to the +/// first root in the `ignore` crate. Prefix with `**/` so the pattern applies under each root. +fn normalize_exclude_pattern_for_multi_root(pattern: &str) -> String { + let (prefix, glob) = match pattern.strip_prefix('!') { + Some(rest) => ("!", rest), + None => ("", pattern), + }; + + if glob.starts_with("**/") || glob.starts_with('/') { + return pattern.to_string(); + } + + format!("{prefix}**/{glob}") +} + /// Recursively scan the given search path for files / pathnames matching the patterns. /// /// If the `--exec` argument was supplied, this will create a thread pool for executing @@ -698,9 +719,25 @@ pub fn scan(paths: &[PathBuf], patterns: Vec, config: Config) -> Result Date: Sun, 17 May 2026 04:31:08 +0800 Subject: [PATCH 2/2] test: drop unrelated full-path glob warning test from #1919 PR The warning test belongs to #1650 / #1999, not the multi search-path exclude fix. Co-authored-by: Cursor --- tests/tests.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/tests/tests.rs b/tests/tests.rs index 189e94dbe..3de52f3dd 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -590,21 +590,6 @@ fn test_full_path_glob_searches() { ); } -#[cfg(not(windows))] -#[test] -fn test_warn_when_full_path_glob_missing_leading_anchor() { - let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES); - - te.assert_output(&["--glob", "--full-path", "foo.txt"], ""); - - let output = te.assert_success_and_get_output(".", &["--glob", "--full-path", "foo.txt"]); - let stderr = String::from_utf8_lossy(&output.stderr); - assert!( - stderr.contains("[fd warning]:") && stderr.contains("**/foo.txt"), - "expected full-path glob anchor warning, got: {stderr}" - ); -} - #[test] fn test_smart_case_glob_searches() { let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);