diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index 5d061b868f..4fe6e1699b 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -4050,6 +4050,94 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex ); } +#[gpui::test] +async fn test_search_in_gitignored_dirs(cx: &mut gpui::TestAppContext) { + init_test(cx); + + let fs = FakeFs::new(cx.background()); + fs.insert_tree( + "/dir", + json!({ + ".git": {}, + ".gitignore": "**/target\n/node_modules\n", + "target": { + "index.txt": "index_key:index_value" + }, + "node_modules": { + "eslint": { + "index.ts": "const eslint_key = 'eslint value'", + "package.json": r#"{ "some_key": "some value" }"#, + }, + "prettier": { + "index.ts": "const prettier_key = 'prettier value'", + "package.json": r#"{ "other_key": "other value" }"#, + }, + }, + "package.json": r#"{ "main_key": "main value" }"#, + }), + ) + .await; + let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await; + + let query = "key"; + assert_eq!( + search( + &project, + SearchQuery::text(query, false, false, false, Vec::new(), Vec::new()).unwrap(), + cx + ) + .await + .unwrap(), + HashMap::from_iter([("package.json".to_string(), vec![8..11])]), + "Only one non-ignored file should have the query" + ); + + assert_eq!( + search( + &project, + SearchQuery::text(query, false, false, true, Vec::new(), Vec::new()).unwrap(), + cx + ) + .await + .unwrap(), + HashMap::from_iter([ + ("package.json".to_string(), vec![8..11]), + ("target/index.txt".to_string(), vec![6..9]), + ( + "node_modules/prettier/package.json".to_string(), + vec![9..12] + ), + ("node_modules/prettier/index.ts".to_string(), vec![15..18]), + ("node_modules/eslint/index.ts".to_string(), vec![13..16]), + ("node_modules/eslint/package.json".to_string(), vec![8..11]), + ]), + "Unrestricted search with ignored directories should find every file with the query" + ); + + assert_eq!( + search( + &project, + SearchQuery::text( + query, + false, + false, + true, + vec![PathMatcher::new("node_modules/prettier/**").unwrap()], + vec![PathMatcher::new("*.ts").unwrap()], + ) + .unwrap(), + cx + ) + .await + .unwrap(), + HashMap::from_iter([( + "node_modules/prettier/package.json".to_string(), + vec![9..12] + )]), + "With search including ignored prettier directory and excluding TS files, only one file should be found" + ); +} + #[test] fn test_glob_literal_prefix() { assert_eq!(glob_literal_prefix("**/*.js"), ""); diff --git a/crates/project/src/search.rs b/crates/project/src/search.rs index fb9c9199bd..bfbc537b27 100644 --- a/crates/project/src/search.rs +++ b/crates/project/src/search.rs @@ -372,28 +372,24 @@ impl SearchQuery { match file_path { Some(file_path) => { let mut path = file_path.to_path_buf(); - let mut matches; loop { - matches = !self + if 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; + { + return false; + } else if self.files_to_include().is_empty() + || self + .files_to_include() + .iter() + .any(|include_glob| include_glob.is_match(&path)) + { + return true; + } else if !path.pop() { + return false; } } - - 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(), } diff --git a/crates/util/src/paths.rs b/crates/util/src/paths.rs index 44e78b9376..19b244383f 100644 --- a/crates/util/src/paths.rs +++ b/crates/util/src/paths.rs @@ -218,8 +218,6 @@ impl PathMatcher { }) } - // TODO kb tests for matching - // TODO kb add an integration test on excluded file opening pub fn is_match>(&self, other: P) -> bool { let other_path = other.as_ref(); other_path.starts_with(&self.maybe_path)