Fix the regex matcher

Kirill Bulatov created

Change summary

crates/project/src/project.rs  | 11 ++++++-----
crates/project/src/search.rs   | 32 +++++++++++++++++++++++---------
crates/project/src/worktree.rs |  3 +--
crates/util/src/paths.rs       | 12 +++++++++++-
4 files changed, 41 insertions(+), 17 deletions(-)

Detailed changes

crates/project/src/project.rs 🔗

@@ -5784,11 +5784,6 @@ impl Project {
                                 while let Some(ignored_abs_path) =
                                     ignored_paths_to_process.pop_front()
                                 {
-                                    if !query.file_matches(Some(&ignored_abs_path))
-                                        || snapshot.is_path_excluded(ignored_abs_path.clone())
-                                    {
-                                        continue;
-                                    }
                                     if let Some(fs_metadata) = fs
                                         .metadata(&ignored_abs_path)
                                         .await
@@ -5816,6 +5811,12 @@ impl Project {
                                                 }
                                             }
                                         } else if !fs_metadata.is_symlink {
+                                            if !query.file_matches(Some(&ignored_abs_path))
+                                                || snapshot
+                                                    .is_path_excluded(ignored_abs_path.clone())
+                                            {
+                                                continue;
+                                            }
                                             let matches = if let Some(file) = fs
                                                 .open_sync(&ignored_abs_path)
                                                 .await

crates/project/src/search.rs 🔗

@@ -371,15 +371,29 @@ impl SearchQuery {
     pub fn file_matches(&self, file_path: Option<&Path>) -> bool {
         match file_path {
             Some(file_path) => {
-                !self
-                    .files_to_exclude()
-                    .iter()
-                    .any(|exclude_glob| exclude_glob.is_match(file_path))
-                    && (self.files_to_include().is_empty()
-                        || self
-                            .files_to_include()
-                            .iter()
-                            .any(|include_glob| include_glob.is_match(file_path)))
+                let mut path = file_path.to_path_buf();
+                let mut matches = false;
+                loop {
+                    matches = !self
+                        .files_to_exclude()
+                        .iter()
+                        .any(|exclude_glob| exclude_glob.is_match(&path))
+                        && (self.files_to_include().is_empty()
+                            || self
+                                .files_to_include()
+                                .iter()
+                                .any(|include_glob| include_glob.is_match(&path)));
+                    if matches || !path.pop() {
+                        break;
+                    }
+                }
+
+                let path_str = file_path.to_string_lossy();
+                if path_str.contains("node_modules") && path_str.contains("prettier") {
+                    dbg!(path_str, path, matches);
+                }
+
+                matches
             }
             None => self.files_to_include().is_empty(),
         }

crates/util/src/paths.rs 🔗

@@ -223,7 +223,7 @@ impl PathMatcher {
     pub fn is_match<P: AsRef<Path>>(&self, other: P) -> bool {
         let other_path = other.as_ref();
         other_path.starts_with(&self.maybe_path)
-            || other_path.file_name() == Some(self.maybe_path.as_os_str())
+            || other_path.ends_with(&self.maybe_path)
             || self.glob.is_match(other_path)
             || self.check_with_end_separator(other_path)
     }
@@ -422,4 +422,14 @@ mod tests {
             "Path matcher {path_matcher} should match {path:?}"
         );
     }
+
+    #[test]
+    fn project_search() {
+        let path = Path::new("/Users/someonetoignore/work/zed/zed.dev/node_modules");
+        let path_matcher = PathMatcher::new("**/node_modules/**").unwrap();
+        assert!(
+            path_matcher.is_match(&path),
+            "Path matcher {path_matcher} should match {path:?}"
+        );
+    }
 }