diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index aa2c09519c..40d589bea7 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -847,27 +847,6 @@ impl Editor { Self::new(EditorMode::Full, buffer, project, None, cx) } - pub fn find_or_create( - workspace: &mut Workspace, - buffer: ModelHandle, - cx: &mut ViewContext, - ) -> ViewHandle { - let project = workspace.project().clone(); - - if let Some(item) = project::File::from_dyn(buffer.read(cx).file()) - .and_then(|file| file.project_entry_id(cx)) - .and_then(|entry_id| workspace.active_pane().read(cx).item_for_entry(entry_id)) - .and_then(|item| item.downcast()) - { - workspace.activate_item(&item, cx); - return item; - } - - let editor = cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx)); - workspace.add_item(Box::new(editor.clone()), cx); - editor - } - pub fn clone(&self, cx: &mut ViewContext) -> Self { let mut clone = Self::new( self.mode, @@ -4324,8 +4303,7 @@ impl Editor { for definition in definitions { let range = definition.range.to_offset(definition.buffer.read(cx)); - let target_editor_handle = - Self::find_or_create(workspace, definition.buffer, cx); + let target_editor_handle = workspace.open_project_item(definition.buffer, cx); target_editor_handle.update(cx, |target_editor, cx| { // When selecting a definition in a different buffer, disable the nav history // to avoid creating a history entry at the previous cursor location. @@ -5597,7 +5575,7 @@ impl Editor { workspace.activate_next_pane(cx); for (buffer, ranges) in new_selections_by_buffer.into_iter() { - let editor = Self::find_or_create(workspace, buffer, cx); + let editor = workspace.open_project_item::(buffer, cx); editor.update(cx, |editor, cx| { editor.select_ranges(ranges, Some(Autoscroll::Newest), cx); }); diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 60dd8ae303..6f083f00a9 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -4,13 +4,13 @@ use gpui::{ elements::*, AppContext, Entity, ModelHandle, RenderContext, Subscription, Task, View, ViewContext, ViewHandle, }; -use language::{Bias, Diagnostic, File as _}; +use language::{Bias, Buffer, Diagnostic, File as _}; use project::{File, Project, ProjectPath}; use std::fmt::Write; use std::path::PathBuf; use text::{Point, Selection}; use util::ResultExt; -use workspace::{Item, ItemHandle, ItemNavHistory, Settings, StatusItemView}; +use workspace::{Item, ItemHandle, ItemNavHistory, ProjectItem, Settings, StatusItemView}; impl Item for Editor { fn navigate(&mut self, data: Box, cx: &mut ViewContext) { @@ -132,6 +132,18 @@ impl Item for Editor { } } +impl ProjectItem for Editor { + type Item = Buffer; + + fn for_project_item( + project: ModelHandle, + buffer: ModelHandle, + cx: &mut ViewContext, + ) -> Self { + Self::for_buffer(buffer, Some(project), cx) + } +} + pub struct CursorPosition { position: Option, selected_count: usize, diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index ff535afafb..c999b8ce4e 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -49,6 +49,10 @@ use util::{post_inc, ResultExt, TryFutureExt as _}; pub use fs::*; pub use worktree::*; +pub trait Item: Entity { + fn entry_id(&self, cx: &AppContext) -> Option; +} + pub struct Project { worktrees: Vec, active_entry: Option, @@ -4522,6 +4526,12 @@ fn relativize_path(base: &Path, path: &Path) -> PathBuf { components.iter().map(|c| c.as_os_str()).collect() } +impl Item for Buffer { + fn entry_id(&self, cx: &AppContext) -> Option { + File::from_dyn(self.file()).and_then(|file| file.project_entry_id(cx)) + } +} + #[cfg(test)] mod tests { use super::{Event, *}; diff --git a/crates/project_symbols/src/project_symbols.rs b/crates/project_symbols/src/project_symbols.rs index d79b2dedae..27e125a592 100644 --- a/crates/project_symbols/src/project_symbols.rs +++ b/crates/project_symbols/src/project_symbols.rs @@ -354,7 +354,7 @@ impl ProjectSymbolsView { .read(cx) .clip_point_utf16(symbol.range.start, Bias::Left); - let editor = Editor::find_or_create(workspace, buffer, cx); + let editor = workspace.open_project_item::(buffer, cx); editor.update(cx, |editor, cx| { editor.select_ranges( [position..position], diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index c388a16c2d..57a74b52ef 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -280,7 +280,7 @@ impl Pane { } } - pub(crate) fn open_item( + pub fn open_item( &mut self, project_entry_id: ProjectEntryId, cx: &mut ViewContext, diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 6481e2c8ee..d220dbc0fa 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -195,6 +195,16 @@ pub trait Item: View { } } +pub trait ProjectItem: Item { + type Item: project::Item; + + fn for_project_item( + project: ModelHandle, + item: ModelHandle, + cx: &mut ViewContext, + ) -> Self; +} + pub trait ItemHandle: 'static { fn tab_content(&self, style: &theme::Tab, cx: &AppContext) -> ElementBox; fn project_path(&self, cx: &AppContext) -> Option; @@ -833,6 +843,31 @@ impl Workspace { }) } + pub fn open_project_item( + &mut self, + project_item: ModelHandle, + cx: &mut ViewContext, + ) -> ViewHandle + where + T: ProjectItem, + { + use project::Item as _; + + if let Some(item) = project_item + .read(cx) + .entry_id(cx) + .and_then(|entry_id| self.active_pane().read(cx).item_for_entry(entry_id)) + .and_then(|item| item.downcast()) + { + self.activate_item(&item, cx); + return item; + } + + let item = cx.add_view(|cx| T::for_project_item(self.project().clone(), project_item, cx)); + self.add_item(Box::new(item.clone()), cx); + item + } + pub fn activate_item(&mut self, item: &dyn ItemHandle, cx: &mut ViewContext) -> bool { let result = self.panes.iter().find_map(|pane| { if let Some(ix) = pane.read(cx).index_for_item(item) {