Fix project search filtering on projects with multiple worktrees (#9337)

Fixes #9285

Release Notes:

- Fixed a bug that broke search filtering when searching a project with
multiple worktrees
([#9285](https://github.com/zed-industries/zed/issues/9285)).

---------

Co-authored-by: Thorsten <thorsten@zed.dev>
This commit is contained in:
Antonio Scandurra 2024-03-14 16:40:48 +01:00 committed by GitHub
parent 7629c16162
commit fab55486f5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 195 additions and 90 deletions

View file

@ -3758,8 +3758,8 @@ async fn test_search(cx: &mut gpui::TestAppContext) {
.await
.unwrap(),
HashMap::from_iter([
("two.rs".to_string(), vec![6..9]),
("three.rs".to_string(), vec![37..40])
("dir/two.rs".to_string(), vec![6..9]),
("dir/three.rs".to_string(), vec![37..40])
])
);
@ -3783,9 +3783,9 @@ async fn test_search(cx: &mut gpui::TestAppContext) {
.await
.unwrap(),
HashMap::from_iter([
("two.rs".to_string(), vec![6..9]),
("three.rs".to_string(), vec![37..40]),
("four.rs".to_string(), vec![25..28, 36..39])
("dir/two.rs".to_string(), vec![6..9]),
("dir/three.rs".to_string(), vec![37..40]),
("dir/four.rs".to_string(), vec![25..28, 36..39])
])
);
}
@ -3846,8 +3846,8 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
.await
.unwrap(),
HashMap::from_iter([
("one.rs".to_string(), vec![8..12]),
("two.rs".to_string(), vec![8..12]),
("dir/one.rs".to_string(), vec![8..12]),
("dir/two.rs".to_string(), vec![8..12]),
]),
"Rust only search should give only Rust files"
);
@ -3871,8 +3871,8 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
.await
.unwrap(),
HashMap::from_iter([
("one.ts".to_string(), vec![14..18]),
("two.ts".to_string(), vec![14..18]),
("dir/one.ts".to_string(), vec![14..18]),
("dir/two.ts".to_string(), vec![14..18]),
]),
"TypeScript only search should give only TypeScript files, even if other inclusions don't match anything"
);
@ -3897,10 +3897,10 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) {
.await
.unwrap(),
HashMap::from_iter([
("one.rs".to_string(), vec![8..12]),
("one.ts".to_string(), vec![14..18]),
("two.rs".to_string(), vec![8..12]),
("two.ts".to_string(), vec![14..18]),
("dir/one.rs".to_string(), vec![8..12]),
("dir/one.ts".to_string(), vec![14..18]),
("dir/two.rs".to_string(), vec![8..12]),
("dir/two.ts".to_string(), vec![14..18]),
]),
"Rust and typescript search should give both Rust and TypeScript files, even if other inclusions don't match anything"
);
@ -3942,10 +3942,10 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
.await
.unwrap(),
HashMap::from_iter([
("one.rs".to_string(), vec![8..12]),
("one.ts".to_string(), vec![14..18]),
("two.rs".to_string(), vec![8..12]),
("two.ts".to_string(), vec![14..18]),
("dir/one.rs".to_string(), vec![8..12]),
("dir/one.ts".to_string(), vec![14..18]),
("dir/two.rs".to_string(), vec![8..12]),
("dir/two.ts".to_string(), vec![14..18]),
]),
"If no exclusions match, all files should be returned"
);
@ -3967,8 +3967,8 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
.await
.unwrap(),
HashMap::from_iter([
("one.ts".to_string(), vec![14..18]),
("two.ts".to_string(), vec![14..18]),
("dir/one.ts".to_string(), vec![14..18]),
("dir/two.ts".to_string(), vec![14..18]),
]),
"Rust exclusion search should give only TypeScript files"
);
@ -3992,8 +3992,8 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) {
.await
.unwrap(),
HashMap::from_iter([
("one.rs".to_string(), vec![8..12]),
("two.rs".to_string(), vec![8..12]),
("dir/one.rs".to_string(), vec![8..12]),
("dir/two.rs".to_string(), vec![8..12]),
]),
"TypeScript exclusion search should give only Rust files, even if other exclusions don't match anything"
);
@ -4128,13 +4128,105 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex
.await
.unwrap(),
HashMap::from_iter([
("one.ts".to_string(), vec![14..18]),
("two.ts".to_string(), vec![14..18]),
("dir/one.ts".to_string(), vec![14..18]),
("dir/two.ts".to_string(), vec![14..18]),
]),
"Non-intersecting TypeScript inclusions and Rust exclusions should return TypeScript files"
);
}
#[gpui::test]
async fn test_search_multiple_worktrees_with_inclusions(cx: &mut gpui::TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.executor());
fs.insert_tree(
"/worktree-a",
json!({
"haystack.rs": r#"// NEEDLE"#,
"haystack.ts": r#"// NEEDLE"#,
}),
)
.await;
fs.insert_tree(
"/worktree-b",
json!({
"haystack.rs": r#"// NEEDLE"#,
"haystack.ts": r#"// NEEDLE"#,
}),
)
.await;
let project = Project::test(
fs.clone(),
["/worktree-a".as_ref(), "/worktree-b".as_ref()],
cx,
)
.await;
assert_eq!(
search(
&project,
SearchQuery::text(
"NEEDLE",
false,
true,
false,
vec![PathMatcher::new("worktree-a/*.rs").unwrap()],
Vec::new()
)
.unwrap(),
cx
)
.await
.unwrap(),
HashMap::from_iter([("worktree-a/haystack.rs".to_string(), vec![3..9])]),
"should only return results from included worktree"
);
assert_eq!(
search(
&project,
SearchQuery::text(
"NEEDLE",
false,
true,
false,
vec![PathMatcher::new("worktree-b/*.rs").unwrap()],
Vec::new()
)
.unwrap(),
cx
)
.await
.unwrap(),
HashMap::from_iter([("worktree-b/haystack.rs".to_string(), vec![3..9])]),
"should only return results from included worktree"
);
assert_eq!(
search(
&project,
SearchQuery::text(
"NEEDLE",
false,
true,
false,
vec![PathMatcher::new("*.ts").unwrap()],
Vec::new()
)
.unwrap(),
cx
)
.await
.unwrap(),
HashMap::from_iter([
("worktree-a/haystack.ts".to_string(), vec![3..9]),
("worktree-b/haystack.ts".to_string(), vec![3..9])
]),
"should return results from both worktrees"
);
}
#[gpui::test]
async fn test_search_in_gitignored_dirs(cx: &mut gpui::TestAppContext) {
init_test(cx);
@ -4173,7 +4265,7 @@ async fn test_search_in_gitignored_dirs(cx: &mut gpui::TestAppContext) {
)
.await
.unwrap(),
HashMap::from_iter([("package.json".to_string(), vec![8..11])]),
HashMap::from_iter([("dir/package.json".to_string(), vec![8..11])]),
"Only one non-ignored file should have the query"
);
@ -4186,15 +4278,21 @@ async fn test_search_in_gitignored_dirs(cx: &mut gpui::TestAppContext) {
.await
.unwrap(),
HashMap::from_iter([
("package.json".to_string(), vec![8..11]),
("target/index.txt".to_string(), vec![6..9]),
("dir/package.json".to_string(), vec![8..11]),
("dir/target/index.txt".to_string(), vec![6..9]),
(
"node_modules/prettier/package.json".to_string(),
"dir/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]),
(
"dir/node_modules/prettier/index.ts".to_string(),
vec![15..18]
),
("dir/node_modules/eslint/index.ts".to_string(), vec![13..16]),
(
"dir/node_modules/eslint/package.json".to_string(),
vec![8..11]
),
]),
"Unrestricted search with ignored directories should find every file with the query"
);
@ -4216,7 +4314,7 @@ async fn test_search_in_gitignored_dirs(cx: &mut gpui::TestAppContext) {
.await
.unwrap(),
HashMap::from_iter([(
"node_modules/prettier/package.json".to_string(),
"dir/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"
@ -4313,8 +4411,13 @@ async fn search(
Ok(result
.into_iter()
.map(|(buffer, ranges)| {
buffer.update(cx, |buffer, _| {
let path = buffer.file().unwrap().path().to_string_lossy().to_string();
buffer.update(cx, |buffer, cx| {
let path = buffer
.file()
.unwrap()
.full_path(cx)
.to_string_lossy()
.to_string();
let ranges = ranges
.into_iter()
.map(|range| range.to_offset(buffer))