diff --git a/Cargo.lock b/Cargo.lock index 7b0063fdfe..7436afc0f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16059,6 +16059,7 @@ dependencies = [ "picker_preview", "pretty_assertions", "project", + "proto", "regex", "serde_json", "settings", diff --git a/crates/project/src/buffer_store.rs b/crates/project/src/buffer_store.rs index 283eae7523..6f97482836 100644 --- a/crates/project/src/buffer_store.rs +++ b/crates/project/src/buffer_store.rs @@ -1666,6 +1666,18 @@ impl BufferStore { self.shared_buffers.remove(peer_id); } + pub fn is_shared(&self, buffer_id: BufferId, cx: &App) -> bool { + self.shared_buffers + .values() + .any(|buffers| buffers.contains_key(&buffer_id)) + || self.as_remote().is_some_and(|remote| { + remote + .shared_with_me + .iter() + .any(|buffer| buffer.read(cx).remote_id() == buffer_id) + }) + } + pub fn update_peer_id(&mut self, old_peer_id: &proto::PeerId, new_peer_id: proto::PeerId) { if let Some(buffers) = self.shared_buffers.remove(old_peer_id) { self.shared_buffers.insert(new_peer_id, buffers); diff --git a/crates/search/Cargo.toml b/crates/search/Cargo.toml index 80ec649665..4f3628a63e 100644 --- a/crates/search/Cargo.toml +++ b/crates/search/Cargo.toml @@ -60,5 +60,6 @@ gpui = { workspace = true, features = ["test-support"] } language = { workspace = true, features = ["test-support"] } lsp.workspace = true pretty_assertions.workspace = true +proto.workspace = true unindent.workspace = true workspace = { workspace = true, features = ["test-support"] } diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 7ec8b181c2..87a5fc1fdf 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -58,7 +58,7 @@ use util::{ResultExt as _, paths::PathMatcher}; use workspace::{ DeploySearch, ItemNavHistory, NewSearch, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace, WorkspaceId, - item::{Item, ItemEvent, ItemHandle, SaveOptions}, + item::{Item, ItemBufferKind, ItemEvent, ItemHandle, SaveOptions}, searchable::{Direction, SearchEvent, SearchToken, SearchableItem, SearchableItemHandle}, }; @@ -253,6 +253,7 @@ const SEARCH_ON_TYPE_DEBOUNCE: Duration = Duration::from_millis(250); pub struct ProjectSearch { pub(crate) project: Entity, + workspace: WeakEntity, pub excerpts: Entity, pub pending_search: Option>>>, pub match_ranges: Vec>, @@ -268,6 +269,7 @@ pub struct ProjectSearch { search_excluded_history_cursor: SearchHistoryCursor, pub project_search_turning_into_text_finder: Arc, _excerpts_subscription: Subscription, + _workspace_subscription: Option, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -393,13 +395,19 @@ pub struct ProjectSearchBar { } impl ProjectSearch { - pub fn new(project: Entity, cx: &mut Context) -> Self { + pub fn new( + project: Entity, + workspace: WeakEntity, + cx: &mut Context, + ) -> Self { let capability = project.read(cx).capability(); let excerpts = cx.new(|_| MultiBuffer::new(capability)); - let subscription = Self::subscribe_to_excerpts(&excerpts, cx); + let excerpts_subscription = Self::subscribe_to_excerpts(&excerpts, cx); + let workspace_subscription = Self::subscribe_to_workspace(&workspace, cx); Self { project, + workspace, excerpts, pending_search: Default::default(), match_ranges: Default::default(), @@ -414,7 +422,8 @@ impl ProjectSearch { search_included_history_cursor: Default::default(), search_excluded_history_cursor: Default::default(), project_search_turning_into_text_finder: Arc::new(AtomicBool::new(false)), - _excerpts_subscription: subscription, + _excerpts_subscription: excerpts_subscription, + _workspace_subscription: workspace_subscription, } } @@ -423,10 +432,12 @@ impl ProjectSearch { let excerpts = self .excerpts .update(cx, |excerpts, cx| cx.new(|cx| excerpts.clone(cx))); - let subscription = Self::subscribe_to_excerpts(&excerpts, cx); + let excerpts_subscription = Self::subscribe_to_excerpts(&excerpts, cx); + let workspace_subscription = Self::subscribe_to_workspace(&self.workspace, cx); Self { project: self.project.clone(), + workspace: self.workspace.clone(), excerpts, pending_search: Default::default(), match_ranges: self.match_ranges.clone(), @@ -449,7 +460,8 @@ impl ProjectSearch { search_included_history_cursor: self.search_included_history_cursor.clone(), search_excluded_history_cursor: self.search_excluded_history_cursor.clone(), project_search_turning_into_text_finder: Arc::new(AtomicBool::new(false)), - _excerpts_subscription: subscription, + _excerpts_subscription: excerpts_subscription, + _workspace_subscription: workspace_subscription, } }) } @@ -464,26 +476,46 @@ impl ProjectSearch { }) } + fn subscribe_to_workspace( + workspace: &WeakEntity, + cx: &mut Context, + ) -> Option { + workspace.upgrade().map(|workspace| { + cx.subscribe(&workspace, |this, _, event, cx| { + if matches!(event, workspace::Event::ItemRemoved { .. }) { + this.remove_closed_untitled_buffers(cx); + } + }) + }) + } + fn remove_deleted_buffers(&mut self, cx: &mut Context) { - let deleted_buffer_ids = self + self.remove_stale_buffers(None, cx); + } + + fn remove_closed_untitled_buffers(&mut self, cx: &mut Context) { + self.remove_stale_buffers(self.workspace.upgrade().as_ref(), cx); + } + + fn remove_stale_buffers( + &mut self, + workspace: Option<&Entity>, + cx: &mut Context, + ) { + let stale_buffer_ids = self .excerpts .read(cx) .all_buffers_iter() - .filter(|buffer| { - buffer - .read(cx) - .file() - .is_some_and(|file| file.disk_state().is_deleted()) - }) + .filter(|buffer| is_buffer_stale(&self.project, workspace, buffer, cx)) .map(|buffer| buffer.read(cx).remote_id()) .collect::>(); - if deleted_buffer_ids.is_empty() { + if stale_buffer_ids.is_empty() { return; } let snapshot = self.excerpts.update(cx, |excerpts, cx| { - for buffer_id in deleted_buffer_ids { + for buffer_id in stale_buffer_ids { excerpts.remove_excerpts_for_buffer(buffer_id, cx); } excerpts.snapshot(cx) @@ -691,25 +723,39 @@ async fn consume_search_stream( buffers_with_ranges .into_iter() .map(|(buffer, ranges)| { - excerpts.set_anchored_excerpts_for_path( + let new_ranges = excerpts.set_anchored_excerpts_for_path( PathKey::for_buffer(&buffer, cx), - buffer, + buffer.clone(), ranges, multibuffer_context_lines(cx), cx, - ) + ); + async move { (buffer, new_ranges.await) } }) .collect::>() }) }) .ok()?; - while let Some(new_ranges) = new_ranges.next().await { + while let Some((buffer, new_ranges)) = new_ranges.next().await { // `new_ranges.next().await` likely never gets hit while still pending so `async_task` // will not reschedule, starving other front end tasks, insert a yield point for that here smol::future::yield_now().await; project_search .update(cx, |project_search, cx| { - project_search.match_ranges.extend(new_ranges); + let workspace = project_search.workspace.upgrade(); + if !is_buffer_stale( + &project_search.project, + workspace.as_ref(), + &buffer, + cx, + ) { + project_search.match_ranges.extend(new_ranges); + } else { + let buffer_id = buffer.read(cx).remote_id(); + project_search.excerpts.update(cx, |excerpts, cx| { + excerpts.remove_excerpts_for_buffer(buffer_id, cx) + }); + } cx.notify(); }) .ok()?; @@ -881,6 +927,7 @@ async fn apply_reused_chunk( .collect::>(); let batch_changed = project_search .update(cx, |project_search, cx| { + let workspace = project_search.workspace.upgrade(); let batch_changed = project_search.excerpts.update(cx, |excerpts, cx| { let mut batch_changed = false; let mut applied = Vec::with_capacity(batch.len()); @@ -908,6 +955,12 @@ async fn apply_reused_chunk( } else { None }; + if is_buffer_stale(&project_search.project, workspace.as_ref(), &buffer, cx) + { + excerpts.remove_excerpts_for_paths(vec![path_key], cx); + batch_changed |= previous_span.is_some(); + continue; + } excerpts.set_excerpt_ranges_for_path( path_key, buffer, @@ -1624,7 +1677,8 @@ impl ProjectSearchView { ) { let weak_workspace = cx.entity().downgrade(); - let entity = cx.new(|cx| ProjectSearch::new(workspace.project().clone(), cx)); + let entity = cx + .new(|cx| ProjectSearch::new(workspace.project().clone(), weak_workspace.clone(), cx)); let search = cx.new(|cx| ProjectSearchView::new(weak_workspace, entity, window, cx, None)); workspace.add_item_to_active_pane(Box::new(search.clone()), None, true, window, cx); search.update(cx, |search, cx| { @@ -1682,12 +1736,13 @@ impl ProjectSearchView { new_query }); if let Some(new_query) = new_query { + let weak_workspace = cx.entity().downgrade(); let entity = cx.new(|cx| { - let mut entity = ProjectSearch::new(workspace.project().clone(), cx); + let mut entity = + ProjectSearch::new(workspace.project().clone(), weak_workspace.clone(), cx); entity.search(new_query, SearchMode::Manual, false, cx); entity }); - let weak_workspace = cx.entity().downgrade(); workspace.add_item_to_active_pane( Box::new(cx.new(|cx| { ProjectSearchView::new(weak_workspace, entity, window, cx, None) @@ -1756,7 +1811,9 @@ impl ProjectSearchView { let weak_workspace = cx.entity().downgrade(); - let project_search = cx.new(|cx| ProjectSearch::new(workspace.project().clone(), cx)); + let project_search = cx.new(|cx| { + ProjectSearch::new(workspace.project().clone(), weak_workspace.clone(), cx) + }); let project_search_view = cx.new(|cx| { ProjectSearchView::new(weak_workspace, project_search, window, cx, settings) }); @@ -3380,6 +3437,30 @@ fn register_workspace_action_for_present_search( }); } +fn is_buffer_stale( + project: &Entity, + workspace: Option<&Entity>, + buffer: &Entity, + cx: &App, +) -> bool { + let buffer_entity_id = buffer.entity_id(); + let buffer = buffer.read(cx); + if let Some(file) = buffer.file() { + file.disk_state().is_deleted() + } else if let Some(workspace) = workspace { + !workspace.read(cx).items(cx).any(|item| { + item.buffer_kind(cx) == ItemBufferKind::Singleton + && item.project_item_model_ids(cx).contains(&buffer_entity_id) + }) && !project + .read(cx) + .buffer_store() + .read(cx) + .is_shared(buffer.remote_id(), cx) + } else { + false + } +} + #[cfg(any(test, feature = "test-support"))] pub fn perform_project_search( search_view: &Entity, @@ -3422,7 +3503,7 @@ pub mod tests { }; use util::{path, paths::PathStyle, rel_path::rel_path}; use util_macros::perf; - use workspace::{DeploySearch, MultiWorkspace}; + use workspace::{DeploySearch, MultiWorkspace, SaveIntent}; #[test] fn test_split_glob_patterns() { @@ -3474,7 +3555,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project, cx)); + let search = cx.new(|cx| ProjectSearch::new(project, workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search, window, cx, None) }); @@ -3544,7 +3625,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project, cx)); + let search = cx.new(|cx| ProjectSearch::new(project, workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search, window, cx, None) }); @@ -3585,7 +3666,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project, cx)); + let search = cx.new(|cx| ProjectSearch::new(project, workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search, window, cx, None) }); @@ -3735,7 +3816,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = cx.new(|cx| ProjectSearch::new(project.clone(), workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -3887,6 +3968,184 @@ pub mod tests { assert!(!results_collapsed); } + #[gpui::test] + async fn test_search_results_do_not_read_closed_untitled_buffer(cx: &mut TestAppContext) { + init_test(cx); + + let fs = FakeFs::new(cx.background_executor.clone()); + fs.insert_tree( + path!("/dir"), + json!({ + "one.rs": "const ONE: usize = 1;", + }), + ) + .await; + + let project = Project::test(fs.clone(), [path!("/dir").as_ref()], cx).await; + let window = + cx.add_window(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx)); + let workspace = window + .read_with(cx, |mw, _| mw.workspace().clone()) + .unwrap(); + + let untitled_buffer = project.update(cx, |project, cx| { + project.create_local_buffer("const TWO: usize = one::ONE;\n", None, true, cx) + }); + let editor = window + .update(cx, |_, window, cx| { + let multibuffer = MultiBuffer::build_from_buffer(untitled_buffer.clone(), cx); + let editor = cx.new(|cx| { + Editor::new( + editor::EditorMode::full(), + multibuffer, + Some(project.clone()), + window, + cx, + ) + }); + workspace.update(cx, |workspace, cx| { + workspace.add_item_to_center(Box::new(editor.clone()), window, cx); + }); + editor + }) + .unwrap(); + + let search = cx.new(|cx| ProjectSearch::new(project, workspace.downgrade(), cx)); + let search_view = cx.add_window(|window, cx| { + ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) + }); + + perform_search(search_view, "const", cx); + + search_view + .update(cx, |search_view, _window, cx| { + let results_text = search_view + .results_editor + .update(cx, |editor, cx| editor.display_text(cx)); + + assert_eq!( + "\n\nconst TWO: usize = one::ONE;\n\n\n\nconst ONE: usize = 1;", + results_text + ); + }) + .unwrap(); + + let pane = cx.read(|cx| workspace.read(cx).active_pane().clone()); + let close_task = window + .update(cx, |_, window, cx| { + pane.update(cx, |pane, cx| { + pane.close_item_by_id(editor.entity_id(), SaveIntent::Skip, window, cx) + }) + }) + .unwrap(); + close_task.await.unwrap(); + cx.run_until_parked(); + + search_view + .update(cx, |search_view, _window, cx| { + let results_text = search_view + .results_editor + .update(cx, |editor, cx| editor.display_text(cx)); + assert_eq!("\n\nconst ONE: usize = 1;", results_text); + }) + .unwrap(); + + // Re-run the search and verify the closed untitled buffer stays gone + perform_search(search_view, "const", cx); + + search_view + .update(cx, |search_view, _window, cx| { + let results_text = search_view + .results_editor + .update(cx, |editor, cx| editor.display_text(cx)); + assert_eq!("\n\nconst ONE: usize = 1;", results_text); + }) + .unwrap(); + } + + #[gpui::test] + async fn test_search_results_keep_peer_shared_untitled_buffers(cx: &mut TestAppContext) { + init_test(cx); + + let fs = FakeFs::new(cx.background_executor.clone()); + fs.insert_tree( + path!("/dir"), + json!({ + "one.rs": "const ONE: usize = 1;", + }), + ) + .await; + + let project = Project::test(fs.clone(), [path!("/dir").as_ref()], cx).await; + let window = + cx.add_window(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx)); + let workspace = window + .read_with(cx, |mw, _| mw.workspace().clone()) + .unwrap(); + + let untitled_buffer = project.update(cx, |project, cx| { + project.create_local_buffer("const TWO: usize = one::ONE;\n", None, true, cx) + }); + project.update(cx, |project, cx| { + project.buffer_store().update(cx, |buffer_store, cx| { + buffer_store + .create_buffer_for_peer( + &untitled_buffer, + proto::PeerId { owner_id: 0, id: 1 }, + cx, + ) + .detach_and_log_err(cx); + }); + }); + + let search = cx.new(|cx| ProjectSearch::new(project, workspace.downgrade(), cx)); + let search_view = cx.add_window(|window, cx| { + ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) + }); + + perform_search(search_view, "const", cx); + search_view + .update(cx, |search_view, _window, cx| { + let results_text = search_view + .results_editor + .update(cx, |editor, cx| editor.display_text(cx)); + assert_eq!( + "\n\nconst TWO: usize = one::ONE;\n\n\n\nconst ONE: usize = 1;", + results_text + ); + }) + .unwrap(); + + search.update(cx, |search, cx| search.remove_closed_untitled_buffers(cx)); + cx.run_until_parked(); + + search_view + .update(cx, |search_view, _window, cx| { + let results_text = search_view + .results_editor + .update(cx, |editor, cx| editor.display_text(cx)); + assert_eq!( + "\n\nconst TWO: usize = one::ONE;\n\n\n\nconst ONE: usize = 1;", + results_text + ); + }) + .unwrap(); + + perform_search(search_view, "const", cx); + + search_view + .update(cx, |search_view, _window, cx| { + let results_text = search_view + .results_editor + .update(cx, |editor, cx| editor.display_text(cx)); + assert_eq!( + "\n\nconst TWO: usize = one::ONE;\n\n\n\nconst ONE: usize = 1;", + results_text + ); + }) + .unwrap(); + } + #[perf] #[gpui::test] async fn test_collapse_state_syncs_after_manual_buffer_fold(cx: &mut TestAppContext) { @@ -3908,7 +4167,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = cx.new(|cx| ProjectSearch::new(project.clone(), workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -5632,7 +5891,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project, cx)); + let search = cx.new(|cx| ProjectSearch::new(project, workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -5986,7 +6245,7 @@ pub mod tests { .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); let cx = &mut VisualTestContext::from_window(window.into(), cx); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = cx.new(|cx| ProjectSearch::new(project.clone(), workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -6156,7 +6415,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = cx.new(|cx| ProjectSearch::new(project.clone(), workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -6420,7 +6679,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = cx.new(|cx| ProjectSearch::new(project.clone(), workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -6627,7 +6886,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = cx.new(|cx| ProjectSearch::new(project.clone(), workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -6699,7 +6958,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = cx.new(|cx| ProjectSearch::new(project.clone(), workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -6906,7 +7165,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = cx.new(|cx| ProjectSearch::new(project.clone(), workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -7151,7 +7410,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = cx.new(|cx| ProjectSearch::new(project.clone(), workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -7213,7 +7472,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project, cx)); + let search = cx.new(|cx| ProjectSearch::new(project, workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -7286,7 +7545,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project, cx)); + let search = cx.new(|cx| ProjectSearch::new(project, workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -7378,7 +7637,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = cx.new(|cx| ProjectSearch::new(project.clone(), workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -7458,7 +7717,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = cx.new(|cx| ProjectSearch::new(project.clone(), workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -7838,7 +8097,8 @@ pub mod tests { let buffer_untitled = project.update(cx, |project, cx| { project.create_local_buffer("fn needle_untitled() {}", None, true, cx) }); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = + cx.new(|cx| ProjectSearch::new(project.clone(), WeakEntity::new_invalid(), cx)); let build_query = || { SearchOptions::NONE .build_query( @@ -7913,7 +8173,8 @@ pub mod tests { }) .await .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = + cx.new(|cx| ProjectSearch::new(project.clone(), WeakEntity::new_invalid(), cx)); let query = SearchOptions::NONE .build_query( @@ -7964,7 +8225,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project, cx)); + let search = cx.new(|cx| ProjectSearch::new(project, workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -8025,7 +8286,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project, cx)); + let search = cx.new(|cx| ProjectSearch::new(project, workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -8493,7 +8754,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = cx.new(|cx| ProjectSearch::new(project.clone(), workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -8577,7 +8838,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = cx.new(|cx| ProjectSearch::new(project.clone(), workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -8659,7 +8920,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = cx.new(|cx| ProjectSearch::new(project.clone(), workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -8728,7 +8989,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project, cx)); + let search = cx.new(|cx| ProjectSearch::new(project, workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -8769,7 +9030,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = cx.new(|cx| ProjectSearch::new(project.clone(), workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -8835,7 +9096,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = cx.new(|cx| ProjectSearch::new(project.clone(), workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -8918,7 +9179,7 @@ pub mod tests { let workspace = window .read_with(cx, |mw, _| mw.workspace().clone()) .unwrap(); - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = cx.new(|cx| ProjectSearch::new(project.clone(), workspace.downgrade(), cx)); let search_view = cx.add_window(|window, cx| { ProjectSearchView::new(workspace.downgrade(), search.clone(), window, cx, None) }); @@ -8985,7 +9246,8 @@ pub mod tests { ) .await; let project = Project::test(fs.clone(), [path!("/dir").as_ref()], cx).await; - let search = cx.new(|cx| ProjectSearch::new(project.clone(), cx)); + let search = + cx.new(|cx| ProjectSearch::new(project.clone(), WeakEntity::new_invalid(), cx)); let query = SearchOptions::REGEX .build_query( "needle_[a-z]+", diff --git a/crates/search/src/text_finder/delegate.rs b/crates/search/src/text_finder/delegate.rs index 48ffb00570..8a739aebbd 100644 --- a/crates/search/src/text_finder/delegate.rs +++ b/crates/search/src/text_finder/delegate.rs @@ -350,7 +350,7 @@ impl Delegate { .get(&project.downgrade()) .cloned(); - let search = cx.new(|cx| ProjectSearch::new(project, cx)); + let search = cx.new(|cx| ProjectSearch::new(project, weak_workspace.clone(), cx)); let project_search = cx.new(|cx| ProjectSearchView::new(weak_workspace, search, window, cx, settings)); cx.spawn(async move |_, cx| Self::new_from_project_search(project_search, cx).await)