diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 3971fabf64..cff31fc6fb 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -9,13 +9,13 @@ use editor::{ Autoscroll, BuildSettings, Editor, ExcerptId, ExcerptProperties, MultiBuffer, ToOffset, }; use gpui::{ - action, elements::*, keymap::Binding, AppContext, Entity, ModelHandle, MutableAppContext, - RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle, + action, elements::*, keymap::Binding, AnyViewHandle, AppContext, Entity, ModelHandle, + MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle, }; use language::{Bias, Buffer, Diagnostic, DiagnosticEntry, Point, Selection, SelectionGoal}; use postage::watch; use project::{Project, ProjectPath}; -use std::{cmp::Ordering, mem, ops::Range, path::PathBuf, rc::Rc, sync::Arc}; +use std::{any::TypeId, cmp::Ordering, mem, ops::Range, path::PathBuf, rc::Rc, sync::Arc}; use util::TryFutureExt; use workspace::{NavHistory, Workspace}; @@ -194,7 +194,6 @@ impl ProjectDiagnosticsEditor { } let editor = workspace .open_item(buffer, cx) - .to_any() .downcast::() .unwrap(); editor.update(cx, |editor, cx| { @@ -595,6 +594,21 @@ impl workspace::ItemView for ProjectDiagnosticsEditor { cx, )) } + + fn act_as_type( + &self, + type_id: TypeId, + self_handle: &ViewHandle, + _: &AppContext, + ) -> Option { + if type_id == TypeId::of::() { + Some(self_handle.into()) + } else if type_id == TypeId::of::() { + Some((&self.editor).into()) + } else { + None + } + } } fn path_header_renderer(buffer: ModelHandle, build_settings: BuildSettings) -> RenderBlock { diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index f2acfc23f8..d7b1e54735 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -2992,11 +2992,17 @@ impl Editor { _: &GoToDefinition, cx: &mut ViewContext, ) { - let editor = workspace - .active_item(cx) - .and_then(|item| item.to_any().downcast::()) - .unwrap() - .read(cx); + let active_item = workspace.active_item(cx); + let editor = if let Some(editor) = active_item + .as_ref() + .and_then(|item| item.act_as::(cx)) + { + editor + } else { + return; + }; + + let editor = editor.read(cx); let buffer = editor.buffer.read(cx); let head = editor.newest_selection::(&buffer.read(cx)).head(); let (buffer, head) = editor.buffer.read(cx).text_anchor_for_position(head, cx); @@ -3012,7 +3018,6 @@ impl Editor { .to_offset(definition.target_buffer.read(cx)); let target_editor = workspace .open_item(BufferItemHandle(definition.target_buffer), cx) - .to_any() .downcast::() .unwrap(); target_editor.update(cx, |target_editor, cx| { diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index e534f3b8fa..dd471a8c36 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -279,7 +279,7 @@ impl StatusItemView for CursorPosition { active_pane_item: Option<&dyn ItemViewHandle>, cx: &mut ViewContext, ) { - if let Some(editor) = active_pane_item.and_then(|item| item.to_any().downcast::()) { + if let Some(editor) = active_pane_item.and_then(|item| item.downcast::()) { self._observe_active_editor = Some(cx.observe(&editor, Self::update_position)); self.update_position(editor, cx); } else { @@ -365,7 +365,7 @@ impl StatusItemView for DiagnosticMessage { active_pane_item: Option<&dyn ItemViewHandle>, cx: &mut ViewContext, ) { - if let Some(editor) = active_pane_item.and_then(|item| item.to_any().downcast::()) { + if let Some(editor) = active_pane_item.and_then(|item| item.downcast::()) { self._observe_active_editor = Some(cx.observe(&editor, Self::update)); self.update(editor, cx); } else { diff --git a/crates/go_to_line/src/go_to_line.rs b/crates/go_to_line/src/go_to_line.rs index c282cd1c75..68d7424ae4 100644 --- a/crates/go_to_line/src/go_to_line.rs +++ b/crates/go_to_line/src/go_to_line.rs @@ -80,17 +80,13 @@ impl GoToLine { } fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext) { - workspace.toggle_modal(cx, |cx, workspace| { - let editor = workspace - .active_item(cx) - .unwrap() - .to_any() - .downcast::() - .unwrap(); - let view = cx.add_view(|cx| GoToLine::new(editor, workspace.settings.clone(), cx)); - cx.subscribe(&view, Self::on_event).detach(); - view - }); + if let Some(editor) = workspace.active_item(cx).unwrap().downcast::() { + workspace.toggle_modal(cx, |cx, workspace| { + let view = cx.add_view(|cx| GoToLine::new(editor, workspace.settings.clone(), cx)); + cx.subscribe(&view, Self::on_event).detach(); + view + }); + } } fn confirm(&mut self, _: &Confirm, cx: &mut ViewContext) { diff --git a/crates/journal/src/journal.rs b/crates/journal/src/journal.rs index 8adda8e1d3..460423f6dc 100644 --- a/crates/journal/src/journal.rs +++ b/crates/journal/src/journal.rs @@ -55,7 +55,7 @@ pub fn new_journal_entry(app_state: Arc, cx: &mut MutableAppContext) { .await; if let Some(Some(Ok(item))) = opened.first() { - if let Some(editor) = item.to_any().downcast::() { + if let Some(editor) = item.downcast::() { editor.update(&mut cx, |editor, cx| { let len = editor.buffer().read(cx).read(cx).len(); editor.select_ranges([len..len], Some(Autoscroll::Center), cx); diff --git a/crates/outline/src/outline.rs b/crates/outline/src/outline.rs index 46bf088c31..151e3ec0bb 100644 --- a/crates/outline/src/outline.rs +++ b/crates/outline/src/outline.rs @@ -144,7 +144,7 @@ impl OutlineView { fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext) { if let Some(editor) = workspace .active_item(cx) - .and_then(|item| item.to_any().downcast::()) + .and_then(|item| item.downcast::()) { let settings = workspace.settings(); let buffer = editor diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 3944a5d49d..524ccf68e2 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -351,7 +351,7 @@ impl Pane { fn focus_active_item(&mut self, cx: &mut ViewContext) { if let Some(active_item) = self.active_item() { - cx.focus(active_item.to_any()); + cx.focus(active_item); } } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index e865c7f2b1..2f661789a3 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -33,7 +33,7 @@ use sidebar::{Side, Sidebar, SidebarItemId, ToggleSidebarItem, ToggleSidebarItem use status_bar::StatusBar; pub use status_bar::StatusItemView; use std::{ - any::Any, + any::{Any, TypeId}, future::Future, hash::{Hash, Hasher}, path::{Path, PathBuf}, @@ -185,6 +185,18 @@ pub trait ItemView: View { fn should_update_tab_on_event(_: &Self::Event) -> bool { false } + fn act_as_type( + &self, + type_id: TypeId, + self_handle: &ViewHandle, + _: &AppContext, + ) -> Option { + if TypeId::of::() == type_id { + Some(self_handle.into()) + } else { + None + } + } } pub trait ItemHandle: Send + Sync { @@ -207,7 +219,7 @@ pub trait WeakItemHandle { fn upgrade(&self, cx: &AppContext) -> Option>; } -pub trait ItemViewHandle { +pub trait ItemViewHandle: 'static { fn item_handle(&self, cx: &AppContext) -> Box; fn title(&self, cx: &AppContext) -> String; fn project_entry(&self, cx: &AppContext) -> Option; @@ -229,6 +241,7 @@ pub trait ItemViewHandle { abs_path: PathBuf, cx: &mut MutableAppContext, ) -> Task>; + fn act_as_type(&self, type_id: TypeId, cx: &AppContext) -> Option; } pub trait WeakItemViewHandle { @@ -326,6 +339,17 @@ impl PartialEq for Box { impl Eq for Box {} +impl dyn ItemViewHandle { + pub fn downcast(&self) -> Option> { + self.to_any().downcast() + } + + pub fn act_as(&self, cx: &AppContext) -> Option> { + self.act_as_type(TypeId::of::(), cx) + .and_then(|t| t.downcast()) + } +} + impl ItemViewHandle for ViewHandle { fn item_handle(&self, cx: &AppContext) -> Box { Box::new(self.read(cx).item_handle(cx)) @@ -413,6 +437,16 @@ impl ItemViewHandle for ViewHandle { fn can_save_as(&self, cx: &AppContext) -> bool { self.read(cx).can_save_as(cx) } + + fn act_as_type(&self, type_id: TypeId, cx: &AppContext) -> Option { + self.read(cx).act_as_type(type_id, self, cx) + } +} + +impl Into for Box { + fn into(self) -> AnyViewHandle { + self.to_any() + } } impl Clone for Box { diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 72fd6f28d3..22eef7fe40 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -205,7 +205,6 @@ mod tests { workspace .active_item(cx) .unwrap() - .to_any() .downcast::() .unwrap() }); @@ -451,7 +450,7 @@ mod tests { let editor = cx.read(|cx| { let pane = workspace.read(cx).active_pane().read(cx); let item = pane.active_item().unwrap(); - item.to_any().downcast::().unwrap() + item.downcast::().unwrap() }); cx.update(|cx| { @@ -504,7 +503,6 @@ mod tests { workspace .active_item(cx) .unwrap() - .to_any() .downcast::() .unwrap() }); @@ -573,7 +571,6 @@ mod tests { workspace .active_item(cx) .unwrap() - .to_any() .downcast::() .unwrap() }); @@ -598,7 +595,6 @@ mod tests { workspace .active_item(cx) .unwrap() - .to_any() .downcast::() .unwrap() }); @@ -738,7 +734,6 @@ mod tests { .update(&mut cx, |w, cx| w.open_path(file1.clone(), cx)) .await .unwrap() - .to_any() .downcast::() .unwrap(); editor1.update(&mut cx, |editor, cx| { @@ -748,14 +743,12 @@ mod tests { .update(&mut cx, |w, cx| w.open_path(file2.clone(), cx)) .await .unwrap() - .to_any() .downcast::() .unwrap(); let editor3 = workspace .update(&mut cx, |w, cx| w.open_path(file3.clone(), cx)) .await .unwrap() - .to_any() .downcast::() .unwrap(); editor3.update(&mut cx, |editor, cx| { @@ -871,7 +864,7 @@ mod tests { ) -> (ProjectPath, DisplayPoint) { workspace.update(cx, |workspace, cx| { let item = workspace.active_item(cx).unwrap(); - let editor = item.to_any().downcast::().unwrap(); + let editor = item.downcast::().unwrap(); let selections = editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)); let path = workspace .project()