@@ -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))
@@ -23,7 +23,7 @@ use gpui::{
use menu::Confirm;
use project::{
search::{SearchInputs, SearchQuery},
- Entry, Project,
+ Project,
};
use semantic_index::{SemanticIndex, SemanticIndexStatus};
@@ -34,7 +34,7 @@ use std::{
any::{Any, TypeId},
mem,
ops::{Not, Range},
- path::PathBuf,
+ path::{Path, PathBuf},
time::{Duration, Instant},
};
use theme::ThemeSettings;
@@ -990,13 +990,10 @@ impl ProjectSearchView {
pub fn new_search_in_directory(
workspace: &mut Workspace,
- dir_entry: &Entry,
+ dir_path: &Path,
cx: &mut ViewContext<Workspace>,
) {
- if !dir_entry.is_dir() {
- return;
- }
- let Some(filter_str) = dir_entry.path.to_str() else {
+ let Some(filter_str) = dir_path.to_str() else {
return;
};
@@ -2806,33 +2803,6 @@ pub mod tests {
})
.unwrap();
- let one_file_entry = cx.update(|cx| {
- workspace
- .read(cx)
- .project()
- .read(cx)
- .entry_for_path(&(worktree_id, "a/one.rs").into(), cx)
- .expect("no entry for /a/one.rs file")
- });
- assert!(one_file_entry.is_file());
- window
- .update(cx, |workspace, cx| {
- ProjectSearchView::new_search_in_directory(workspace, &one_file_entry, cx)
- })
- .unwrap();
- let active_search_entry = cx.read(|cx| {
- workspace
- .read(cx)
- .active_pane()
- .read(cx)
- .active_item()
- .and_then(|item| item.downcast::<ProjectSearchView>())
- });
- assert!(
- active_search_entry.is_none(),
- "Expected no search panel to be active for file entry"
- );
-
let a_dir_entry = cx.update(|cx| {
workspace
.read(cx)
@@ -2844,7 +2814,7 @@ pub mod tests {
assert!(a_dir_entry.is_dir());
window
.update(cx, |workspace, cx| {
- ProjectSearchView::new_search_in_directory(workspace, &a_dir_entry, cx)
+ ProjectSearchView::new_search_in_directory(workspace, &a_dir_entry.path, cx)
})
.unwrap();