From 80a4746a46a7874975acedfda6157bfbaa44bd9c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Mon, 8 Sep 2025 13:22:36 +0200 Subject: [PATCH] project: Be explicit about project-searchability for buffers (#37773) Closes https://github.com/zed-industries/zed/issues/28830 Release Notes: - Fixed builtin buffers and log views showing up in project search --- .../src/activity_indicator.rs | 3 +- crates/agent_ui/src/acp/thread_view.rs | 2 +- crates/agent_ui/src/active_thread.rs | 2 +- crates/auto_update_ui/src/auto_update_ui.rs | 5 +-- crates/collab/src/tests/following_tests.rs | 2 +- crates/collab/src/tests/integration_tests.rs | 2 +- crates/editor/src/editor.rs | 4 +- crates/editor/src/editor_tests.rs | 6 +-- crates/editor/src/items.rs | 4 +- crates/editor/src/rust_analyzer_ext.rs | 2 +- crates/git_ui/src/git_panel.rs | 3 -- crates/language_tools/src/lsp_button.rs | 2 +- crates/project/src/buffer_store.rs | 44 ++++++++++++++----- crates/project/src/git_store.rs | 2 +- crates/project/src/project.rs | 22 +++++----- crates/project/src/project_tests.rs | 10 ++--- crates/remote_server/src/headless_project.rs | 2 +- crates/zed/src/zed.rs | 7 +-- 18 files changed, 71 insertions(+), 53 deletions(-) diff --git a/crates/activity_indicator/src/activity_indicator.rs b/crates/activity_indicator/src/activity_indicator.rs index 1f4c10b060..1870ab74db 100644 --- a/crates/activity_indicator/src/activity_indicator.rs +++ b/crates/activity_indicator/src/activity_indicator.rs @@ -212,7 +212,8 @@ impl ActivityIndicator { server_name, status, } => { - let create_buffer = project.update(cx, |project, cx| project.create_buffer(cx)); + let create_buffer = + project.update(cx, |project, cx| project.create_buffer(false, cx)); let status = status.clone(); let server_name = server_name.clone(); cx.spawn_in(window, async move |workspace, cx| { diff --git a/crates/agent_ui/src/acp/thread_view.rs b/crates/agent_ui/src/acp/thread_view.rs index 441b4aa06f..d635918c19 100644 --- a/crates/agent_ui/src/acp/thread_view.rs +++ b/crates/agent_ui/src/acp/thread_view.rs @@ -4255,7 +4255,7 @@ impl AcpThreadView { } let buffer = project.update(cx, |project, cx| { - project.create_local_buffer(&markdown, Some(markdown_language), cx) + project.create_local_buffer(&markdown, Some(markdown_language), true, cx) }); let buffer = cx.new(|cx| { MultiBuffer::singleton(buffer, cx).with_title(thread_summary.clone()) diff --git a/crates/agent_ui/src/active_thread.rs b/crates/agent_ui/src/active_thread.rs index fbba3eaffd..dad2e282a5 100644 --- a/crates/agent_ui/src/active_thread.rs +++ b/crates/agent_ui/src/active_thread.rs @@ -3585,7 +3585,7 @@ pub(crate) fn open_active_thread_as_markdown( } let buffer = project.update(cx, |project, cx| { - project.create_local_buffer(&markdown, Some(markdown_language), cx) + project.create_local_buffer(&markdown, Some(markdown_language), true, cx) }); let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx).with_title(thread_summary.clone())); diff --git a/crates/auto_update_ui/src/auto_update_ui.rs b/crates/auto_update_ui/src/auto_update_ui.rs index 7063dffd6d..729ab425d0 100644 --- a/crates/auto_update_ui/src/auto_update_ui.rs +++ b/crates/auto_update_ui/src/auto_update_ui.rs @@ -88,10 +88,7 @@ fn view_release_notes_locally( .update_in(cx, |workspace, window, cx| { let project = workspace.project().clone(); let buffer = project.update(cx, |project, cx| { - let buffer = project.create_local_buffer("", markdown, cx); - project - .mark_buffer_as_non_searchable(buffer.read(cx).remote_id(), cx); - buffer + project.create_local_buffer("", markdown, false, cx) }); buffer.update(cx, |buffer, cx| { buffer.edit([(0..0, body.release_notes)], None, cx) diff --git a/crates/collab/src/tests/following_tests.rs b/crates/collab/src/tests/following_tests.rs index 1e0c915bcb..0a9a69bfca 100644 --- a/crates/collab/src/tests/following_tests.rs +++ b/crates/collab/src/tests/following_tests.rs @@ -2098,7 +2098,7 @@ async fn test_following_after_replacement(cx_a: &mut TestAppContext, cx_b: &mut share_workspace(&workspace, cx_a).await.unwrap(); let buffer = workspace.update(cx_a, |workspace, cx| { workspace.project().update(cx, |project, cx| { - project.create_local_buffer(&sample_text(26, 5, 'a'), None, cx) + project.create_local_buffer(&sample_text(26, 5, 'a'), None, false, cx) }) }); let multibuffer = cx_a.new(|cx| { diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 07bd162e66..646dbfbd15 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -2506,7 +2506,7 @@ async fn test_propagate_saves_and_fs_changes( }); let new_buffer_a = project_a - .update(cx_a, |p, cx| p.create_buffer(cx)) + .update(cx_a, |p, cx| p.create_buffer(false, cx)) .await .unwrap(); diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index b1f9bde6dd..2fc885e3fd 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -2619,7 +2619,7 @@ impl Editor { cx: &mut Context, ) -> Task>> { let project = workspace.project().clone(); - let create = project.update(cx, |project, cx| project.create_buffer(cx)); + let create = project.update(cx, |project, cx| project.create_buffer(true, cx)); cx.spawn_in(window, async move |workspace, cx| { let buffer = create.await?; @@ -2657,7 +2657,7 @@ impl Editor { cx: &mut Context, ) { let project = workspace.project().clone(); - let create = project.update(cx, |project, cx| project.create_buffer(cx)); + let create = project.update(cx, |project, cx| project.create_buffer(true, cx)); cx.spawn_in(window, async move |workspace, cx| { let buffer = create.await?; diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 36405079b8..5be6f685d1 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -15913,7 +15913,7 @@ async fn test_following(cx: &mut TestAppContext) { let project = Project::test(fs, ["/file.rs".as_ref()], cx).await; let buffer = project.update(cx, |project, cx| { - let buffer = project.create_local_buffer(&sample_text(16, 8, 'a'), None, cx); + let buffer = project.create_local_buffer(&sample_text(16, 8, 'a'), None, false, cx); cx.new(|cx| MultiBuffer::singleton(buffer, cx)) }); let leader = cx.add_window(|window, cx| build_editor(buffer.clone(), window, cx)); @@ -16165,8 +16165,8 @@ async fn test_following_with_multiple_excerpts(cx: &mut TestAppContext) { let (buffer_1, buffer_2) = project.update(cx, |project, cx| { ( - project.create_local_buffer("abc\ndef\nghi\njkl\n", None, cx), - project.create_local_buffer("mno\npqr\nstu\nvwx\n", None, cx), + project.create_local_buffer("abc\ndef\nghi\njkl\n", None, false, cx), + project.create_local_buffer("mno\npqr\nstu\nvwx\n", None, false, cx), ) }); diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 48c3a8a41a..253d0c2751 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -1130,7 +1130,7 @@ impl SerializableItem for Editor { // First create the empty buffer let buffer = project - .update(cx, |project, cx| project.create_buffer(cx))? + .update(cx, |project, cx| project.create_buffer(true, cx))? .await?; // Then set the text so that the dirty bit is set correctly @@ -1238,7 +1238,7 @@ impl SerializableItem for Editor { .. } => window.spawn(cx, async move |cx| { let buffer = project - .update(cx, |project, cx| project.create_buffer(cx))? + .update(cx, |project, cx| project.create_buffer(true, cx))? .await?; cx.update(|window, cx| { diff --git a/crates/editor/src/rust_analyzer_ext.rs b/crates/editor/src/rust_analyzer_ext.rs index cf74ee0a9e..f4059ca03d 100644 --- a/crates/editor/src/rust_analyzer_ext.rs +++ b/crates/editor/src/rust_analyzer_ext.rs @@ -200,7 +200,7 @@ pub fn expand_macro_recursively( } let buffer = project - .update(cx, |project, cx| project.create_buffer(cx))? + .update(cx, |project, cx| project.create_buffer(false, cx))? .await?; workspace.update_in(cx, |workspace, window, cx| { buffer.update(cx, |buffer, cx| { diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 64163b0ebc..02a60d8fe3 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -388,9 +388,6 @@ pub(crate) fn commit_message_editor( window: &mut Window, cx: &mut Context, ) -> Editor { - project.update(cx, |this, cx| { - this.mark_buffer_as_non_searchable(commit_message_buffer.read(cx).remote_id(), cx); - }); let buffer = cx.new(|cx| MultiBuffer::singleton(commit_message_buffer, cx)); let max_lines = if in_panel { MAX_PANEL_EDITOR_LINES } else { 18 }; let mut commit_editor = Editor::new( diff --git a/crates/language_tools/src/lsp_button.rs b/crates/language_tools/src/lsp_button.rs index f91c4cc61c..59beceff98 100644 --- a/crates/language_tools/src/lsp_button.rs +++ b/crates/language_tools/src/lsp_button.rs @@ -296,7 +296,7 @@ impl LanguageServerState { .update(cx, |workspace, cx| { workspace .project() - .update(cx, |project, cx| project.create_buffer(cx)) + .update(cx, |project, cx| project.create_buffer(false, cx)) }) .ok() else { diff --git a/crates/project/src/buffer_store.rs b/crates/project/src/buffer_store.rs index 89bd4b27c9..c2b6145b36 100644 --- a/crates/project/src/buffer_store.rs +++ b/crates/project/src/buffer_store.rs @@ -319,7 +319,11 @@ impl RemoteBufferStore { }) } - fn create_buffer(&self, cx: &mut Context) -> Task>> { + fn create_buffer( + &self, + project_searchable: bool, + cx: &mut Context, + ) -> Task>> { let create = self.upstream_client.request(proto::OpenNewBuffer { project_id: self.project_id, }); @@ -327,8 +331,13 @@ impl RemoteBufferStore { let response = create.await?; let buffer_id = BufferId::new(response.buffer_id)?; - this.update(cx, |this, cx| this.wait_for_remote_buffer(buffer_id, cx))? - .await + this.update(cx, |this, cx| { + if !project_searchable { + this.non_searchable_buffers.insert(buffer_id); + } + this.wait_for_remote_buffer(buffer_id, cx) + })? + .await }) } @@ -670,12 +679,21 @@ impl LocalBufferStore { }) } - fn create_buffer(&self, cx: &mut Context) -> Task>> { + fn create_buffer( + &self, + project_searchable: bool, + cx: &mut Context, + ) -> Task>> { cx.spawn(async move |buffer_store, cx| { let buffer = cx.new(|cx| Buffer::local("", cx).with_language(language::PLAIN_TEXT.clone(), cx))?; buffer_store.update(cx, |buffer_store, cx| { buffer_store.add_buffer(buffer.clone(), cx).log_err(); + if !project_searchable { + buffer_store + .non_searchable_buffers + .insert(buffer.read(cx).remote_id()); + } })?; Ok(buffer) }) @@ -848,10 +866,14 @@ impl BufferStore { }) } - pub fn create_buffer(&mut self, cx: &mut Context) -> Task>> { + pub fn create_buffer( + &mut self, + project_searchable: bool, + cx: &mut Context, + ) -> Task>> { match &self.state { - BufferStoreState::Local(this) => this.create_buffer(cx), - BufferStoreState::Remote(this) => this.create_buffer(cx), + BufferStoreState::Local(this) => this.create_buffer(project_searchable, cx), + BufferStoreState::Remote(this) => this.create_buffer(project_searchable, cx), } } @@ -1610,6 +1632,7 @@ impl BufferStore { &mut self, text: &str, language: Option>, + project_searchable: bool, cx: &mut Context, ) -> Entity { let buffer = cx.new(|cx| { @@ -1619,6 +1642,9 @@ impl BufferStore { self.add_buffer(buffer.clone(), cx).log_err(); let buffer_id = buffer.read(cx).remote_id(); + if !project_searchable { + self.non_searchable_buffers.insert(buffer_id); + } if let Some(file) = File::from_dyn(buffer.read(cx).file()) { self.path_to_buffer_id.insert( @@ -1688,10 +1714,6 @@ impl BufferStore { } serialized_transaction } - - pub(crate) fn mark_buffer_as_non_searchable(&mut self, buffer_id: BufferId) { - self.non_searchable_buffers.insert(buffer_id); - } } impl OpenBuffer { diff --git a/crates/project/src/git_store.rs b/crates/project/src/git_store.rs index b7ff3e7fef..92c68f6646 100644 --- a/crates/project/src/git_store.rs +++ b/crates/project/src/git_store.rs @@ -3317,7 +3317,7 @@ impl Repository { ) -> Task>> { cx.spawn(async move |repository, cx| { let buffer = buffer_store - .update(cx, |buffer_store, cx| buffer_store.create_buffer(cx))? + .update(cx, |buffer_store, cx| buffer_store.create_buffer(false, cx))? .await?; if let Some(language_registry) = language_registry { diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 0ebfd83f4e..04001e9e3b 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -2540,22 +2540,28 @@ impl Project { } } - pub fn create_buffer(&mut self, cx: &mut Context) -> Task>> { - self.buffer_store - .update(cx, |buffer_store, cx| buffer_store.create_buffer(cx)) + pub fn create_buffer( + &mut self, + searchable: bool, + cx: &mut Context, + ) -> Task>> { + self.buffer_store.update(cx, |buffer_store, cx| { + buffer_store.create_buffer(searchable, cx) + }) } pub fn create_local_buffer( &mut self, text: &str, language: Option>, + project_searchable: bool, cx: &mut Context, ) -> Entity { if self.is_via_collab() || self.is_via_remote_server() { panic!("called create_local_buffer on a remote project") } self.buffer_store.update(cx, |buffer_store, cx| { - buffer_store.create_local_buffer(text, language, cx) + buffer_store.create_local_buffer(text, language, project_searchable, cx) }) } @@ -4913,7 +4919,7 @@ impl Project { mut cx: AsyncApp, ) -> Result { let buffer = this - .update(&mut cx, |this, cx| this.create_buffer(cx))? + .update(&mut cx, |this, cx| this.create_buffer(true, cx))? .await?; let peer_id = envelope.original_sender_id()?; @@ -5244,12 +5250,6 @@ impl Project { pub fn agent_location(&self) -> Option { self.agent_location.clone() } - - pub fn mark_buffer_as_non_searchable(&self, buffer_id: BufferId, cx: &mut Context) { - self.buffer_store.update(cx, |buffer_store, _| { - buffer_store.mark_buffer_as_non_searchable(buffer_id) - }); - } } pub struct PathMatchCandidateSet { diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index e65da3acd4..c72f35833b 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -3876,7 +3876,7 @@ async fn test_save_file_spawns_language_server(cx: &mut gpui::TestAppContext) { ); let buffer = project - .update(cx, |this, cx| this.create_buffer(cx)) + .update(cx, |this, cx| this.create_buffer(false, cx)) .unwrap() .await; project.update(cx, |this, cx| { @@ -4088,7 +4088,9 @@ async fn test_save_as(cx: &mut gpui::TestAppContext) { let languages = project.update(cx, |project, _| project.languages().clone()); languages.add(rust_lang()); - let buffer = project.update(cx, |project, cx| project.create_local_buffer("", None, cx)); + let buffer = project.update(cx, |project, cx| { + project.create_local_buffer("", None, false, cx) + }); buffer.update(cx, |buffer, cx| { buffer.edit([(0..0, "abc")], None, cx); assert!(buffer.is_dirty()); @@ -5585,9 +5587,7 @@ async fn test_search_with_buffer_exclusions(cx: &mut gpui::TestAppContext) { let project = Project::test(fs.clone(), [path!("/dir").as_ref()], cx).await; let _buffer = project.update(cx, |project, cx| { - let buffer = project.create_local_buffer("file", None, cx); - project.mark_buffer_as_non_searchable(buffer.read(cx).remote_id(), cx); - buffer + project.create_local_buffer("file", None, false, cx) }); assert_eq!( diff --git a/crates/remote_server/src/headless_project.rs b/crates/remote_server/src/headless_project.rs index 7fb5ac8498..2714e9ff79 100644 --- a/crates/remote_server/src/headless_project.rs +++ b/crates/remote_server/src/headless_project.rs @@ -517,7 +517,7 @@ impl HeadlessProject { let buffer_store = this.buffer_store.clone(); let buffer = this .buffer_store - .update(cx, |buffer_store, cx| buffer_store.create_buffer(cx)); + .update(cx, |buffer_store, cx| buffer_store.create_buffer(true, cx)); anyhow::Ok((buffer_store, buffer)) })??; diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index fda43a10ba..cb5cfea81a 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -1167,7 +1167,7 @@ fn open_log_file(workspace: &mut Workspace, window: &mut Window, cx: &mut Contex }; let project = workspace.project().clone(); let buffer = project.update(cx, |project, cx| { - project.create_local_buffer(&log, None, cx) + project.create_local_buffer(&log, None, false, cx) }); let buffer = cx @@ -1733,7 +1733,7 @@ fn open_telemetry_log_file( workspace.update_in( cx, |workspace, window, cx| { let project = workspace.project().clone(); - let buffer = project.update(cx, |project, cx| project.create_local_buffer(&content, json, cx)); + let buffer = project.update(cx, |project, cx| project.create_local_buffer(&content, json,false, cx)); let buffer = cx.new(|cx| { MultiBuffer::singleton(buffer, cx).with_title("Telemetry Log".into()) }); @@ -1772,7 +1772,8 @@ fn open_bundled_file( workspace.with_local_workspace(window, cx, |workspace, window, cx| { let project = workspace.project(); let buffer = project.update(cx, move |project, cx| { - let buffer = project.create_local_buffer(text.as_ref(), language, cx); + let buffer = + project.create_local_buffer(text.as_ref(), language, false, cx); buffer.update(cx, |buffer, cx| { buffer.set_capability(Capability::ReadOnly, cx); });