Make "go to definition" work in project diagnostics

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2022-01-20 17:30:30 +01:00
parent d92b40474f
commit b6685a532c
9 changed files with 79 additions and 37 deletions

View file

@ -9,13 +9,13 @@ use editor::{
Autoscroll, BuildSettings, Editor, ExcerptId, ExcerptProperties, MultiBuffer, ToOffset, Autoscroll, BuildSettings, Editor, ExcerptId, ExcerptProperties, MultiBuffer, ToOffset,
}; };
use gpui::{ use gpui::{
action, elements::*, keymap::Binding, AppContext, Entity, ModelHandle, MutableAppContext, action, elements::*, keymap::Binding, AnyViewHandle, AppContext, Entity, ModelHandle,
RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle, MutableAppContext, RenderContext, Task, View, ViewContext, ViewHandle, WeakViewHandle,
}; };
use language::{Bias, Buffer, Diagnostic, DiagnosticEntry, Point, Selection, SelectionGoal}; use language::{Bias, Buffer, Diagnostic, DiagnosticEntry, Point, Selection, SelectionGoal};
use postage::watch; use postage::watch;
use project::{Project, ProjectPath}; 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 util::TryFutureExt;
use workspace::{NavHistory, Workspace}; use workspace::{NavHistory, Workspace};
@ -194,7 +194,6 @@ impl ProjectDiagnosticsEditor {
} }
let editor = workspace let editor = workspace
.open_item(buffer, cx) .open_item(buffer, cx)
.to_any()
.downcast::<Editor>() .downcast::<Editor>()
.unwrap(); .unwrap();
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
@ -595,6 +594,21 @@ impl workspace::ItemView for ProjectDiagnosticsEditor {
cx, cx,
)) ))
} }
fn act_as_type(
&self,
type_id: TypeId,
self_handle: &ViewHandle<Self>,
_: &AppContext,
) -> Option<AnyViewHandle> {
if type_id == TypeId::of::<Self>() {
Some(self_handle.into())
} else if type_id == TypeId::of::<Editor>() {
Some((&self.editor).into())
} else {
None
}
}
} }
fn path_header_renderer(buffer: ModelHandle<Buffer>, build_settings: BuildSettings) -> RenderBlock { fn path_header_renderer(buffer: ModelHandle<Buffer>, build_settings: BuildSettings) -> RenderBlock {

View file

@ -2992,11 +2992,17 @@ impl Editor {
_: &GoToDefinition, _: &GoToDefinition,
cx: &mut ViewContext<Workspace>, cx: &mut ViewContext<Workspace>,
) { ) {
let editor = workspace let active_item = workspace.active_item(cx);
.active_item(cx) let editor = if let Some(editor) = active_item
.and_then(|item| item.to_any().downcast::<Self>()) .as_ref()
.unwrap() .and_then(|item| item.act_as::<Self>(cx))
.read(cx); {
editor
} else {
return;
};
let editor = editor.read(cx);
let buffer = editor.buffer.read(cx); let buffer = editor.buffer.read(cx);
let head = editor.newest_selection::<usize>(&buffer.read(cx)).head(); let head = editor.newest_selection::<usize>(&buffer.read(cx)).head();
let (buffer, head) = editor.buffer.read(cx).text_anchor_for_position(head, cx); 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)); .to_offset(definition.target_buffer.read(cx));
let target_editor = workspace let target_editor = workspace
.open_item(BufferItemHandle(definition.target_buffer), cx) .open_item(BufferItemHandle(definition.target_buffer), cx)
.to_any()
.downcast::<Self>() .downcast::<Self>()
.unwrap(); .unwrap();
target_editor.update(cx, |target_editor, cx| { target_editor.update(cx, |target_editor, cx| {

View file

@ -279,7 +279,7 @@ impl StatusItemView for CursorPosition {
active_pane_item: Option<&dyn ItemViewHandle>, active_pane_item: Option<&dyn ItemViewHandle>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) { ) {
if let Some(editor) = active_pane_item.and_then(|item| item.to_any().downcast::<Editor>()) { if let Some(editor) = active_pane_item.and_then(|item| item.downcast::<Editor>()) {
self._observe_active_editor = Some(cx.observe(&editor, Self::update_position)); self._observe_active_editor = Some(cx.observe(&editor, Self::update_position));
self.update_position(editor, cx); self.update_position(editor, cx);
} else { } else {
@ -365,7 +365,7 @@ impl StatusItemView for DiagnosticMessage {
active_pane_item: Option<&dyn ItemViewHandle>, active_pane_item: Option<&dyn ItemViewHandle>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) { ) {
if let Some(editor) = active_pane_item.and_then(|item| item.to_any().downcast::<Editor>()) { if let Some(editor) = active_pane_item.and_then(|item| item.downcast::<Editor>()) {
self._observe_active_editor = Some(cx.observe(&editor, Self::update)); self._observe_active_editor = Some(cx.observe(&editor, Self::update));
self.update(editor, cx); self.update(editor, cx);
} else { } else {

View file

@ -80,17 +80,13 @@ impl GoToLine {
} }
fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) { fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) {
workspace.toggle_modal(cx, |cx, workspace| { if let Some(editor) = workspace.active_item(cx).unwrap().downcast::<Editor>() {
let editor = workspace workspace.toggle_modal(cx, |cx, workspace| {
.active_item(cx) let view = cx.add_view(|cx| GoToLine::new(editor, workspace.settings.clone(), cx));
.unwrap() cx.subscribe(&view, Self::on_event).detach();
.to_any() view
.downcast::<Editor>() });
.unwrap(); }
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<Self>) { fn confirm(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {

View file

@ -55,7 +55,7 @@ pub fn new_journal_entry(app_state: Arc<AppState>, cx: &mut MutableAppContext) {
.await; .await;
if let Some(Some(Ok(item))) = opened.first() { if let Some(Some(Ok(item))) = opened.first() {
if let Some(editor) = item.to_any().downcast::<Editor>() { if let Some(editor) = item.downcast::<Editor>() {
editor.update(&mut cx, |editor, cx| { editor.update(&mut cx, |editor, cx| {
let len = editor.buffer().read(cx).read(cx).len(); let len = editor.buffer().read(cx).read(cx).len();
editor.select_ranges([len..len], Some(Autoscroll::Center), cx); editor.select_ranges([len..len], Some(Autoscroll::Center), cx);

View file

@ -144,7 +144,7 @@ impl OutlineView {
fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) { fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) {
if let Some(editor) = workspace if let Some(editor) = workspace
.active_item(cx) .active_item(cx)
.and_then(|item| item.to_any().downcast::<Editor>()) .and_then(|item| item.downcast::<Editor>())
{ {
let settings = workspace.settings(); let settings = workspace.settings();
let buffer = editor let buffer = editor

View file

@ -351,7 +351,7 @@ impl Pane {
fn focus_active_item(&mut self, cx: &mut ViewContext<Self>) { fn focus_active_item(&mut self, cx: &mut ViewContext<Self>) {
if let Some(active_item) = self.active_item() { if let Some(active_item) = self.active_item() {
cx.focus(active_item.to_any()); cx.focus(active_item);
} }
} }

View file

@ -33,7 +33,7 @@ use sidebar::{Side, Sidebar, SidebarItemId, ToggleSidebarItem, ToggleSidebarItem
use status_bar::StatusBar; use status_bar::StatusBar;
pub use status_bar::StatusItemView; pub use status_bar::StatusItemView;
use std::{ use std::{
any::Any, any::{Any, TypeId},
future::Future, future::Future,
hash::{Hash, Hasher}, hash::{Hash, Hasher},
path::{Path, PathBuf}, path::{Path, PathBuf},
@ -185,6 +185,18 @@ pub trait ItemView: View {
fn should_update_tab_on_event(_: &Self::Event) -> bool { fn should_update_tab_on_event(_: &Self::Event) -> bool {
false false
} }
fn act_as_type(
&self,
type_id: TypeId,
self_handle: &ViewHandle<Self>,
_: &AppContext,
) -> Option<AnyViewHandle> {
if TypeId::of::<Self>() == type_id {
Some(self_handle.into())
} else {
None
}
}
} }
pub trait ItemHandle: Send + Sync { pub trait ItemHandle: Send + Sync {
@ -207,7 +219,7 @@ pub trait WeakItemHandle {
fn upgrade(&self, cx: &AppContext) -> Option<Box<dyn ItemHandle>>; fn upgrade(&self, cx: &AppContext) -> Option<Box<dyn ItemHandle>>;
} }
pub trait ItemViewHandle { pub trait ItemViewHandle: 'static {
fn item_handle(&self, cx: &AppContext) -> Box<dyn ItemHandle>; fn item_handle(&self, cx: &AppContext) -> Box<dyn ItemHandle>;
fn title(&self, cx: &AppContext) -> String; fn title(&self, cx: &AppContext) -> String;
fn project_entry(&self, cx: &AppContext) -> Option<ProjectEntry>; fn project_entry(&self, cx: &AppContext) -> Option<ProjectEntry>;
@ -229,6 +241,7 @@ pub trait ItemViewHandle {
abs_path: PathBuf, abs_path: PathBuf,
cx: &mut MutableAppContext, cx: &mut MutableAppContext,
) -> Task<Result<()>>; ) -> Task<Result<()>>;
fn act_as_type(&self, type_id: TypeId, cx: &AppContext) -> Option<AnyViewHandle>;
} }
pub trait WeakItemViewHandle { pub trait WeakItemViewHandle {
@ -326,6 +339,17 @@ impl PartialEq for Box<dyn WeakItemHandle> {
impl Eq for Box<dyn WeakItemHandle> {} impl Eq for Box<dyn WeakItemHandle> {}
impl dyn ItemViewHandle {
pub fn downcast<T: View>(&self) -> Option<ViewHandle<T>> {
self.to_any().downcast()
}
pub fn act_as<T: View>(&self, cx: &AppContext) -> Option<ViewHandle<T>> {
self.act_as_type(TypeId::of::<T>(), cx)
.and_then(|t| t.downcast())
}
}
impl<T: ItemView> ItemViewHandle for ViewHandle<T> { impl<T: ItemView> ItemViewHandle for ViewHandle<T> {
fn item_handle(&self, cx: &AppContext) -> Box<dyn ItemHandle> { fn item_handle(&self, cx: &AppContext) -> Box<dyn ItemHandle> {
Box::new(self.read(cx).item_handle(cx)) Box::new(self.read(cx).item_handle(cx))
@ -413,6 +437,16 @@ impl<T: ItemView> ItemViewHandle for ViewHandle<T> {
fn can_save_as(&self, cx: &AppContext) -> bool { fn can_save_as(&self, cx: &AppContext) -> bool {
self.read(cx).can_save_as(cx) self.read(cx).can_save_as(cx)
} }
fn act_as_type(&self, type_id: TypeId, cx: &AppContext) -> Option<AnyViewHandle> {
self.read(cx).act_as_type(type_id, self, cx)
}
}
impl Into<AnyViewHandle> for Box<dyn ItemViewHandle> {
fn into(self) -> AnyViewHandle {
self.to_any()
}
} }
impl Clone for Box<dyn ItemViewHandle> { impl Clone for Box<dyn ItemViewHandle> {

View file

@ -205,7 +205,6 @@ mod tests {
workspace workspace
.active_item(cx) .active_item(cx)
.unwrap() .unwrap()
.to_any()
.downcast::<editor::Editor>() .downcast::<editor::Editor>()
.unwrap() .unwrap()
}); });
@ -451,7 +450,7 @@ mod tests {
let editor = cx.read(|cx| { let editor = cx.read(|cx| {
let pane = workspace.read(cx).active_pane().read(cx); let pane = workspace.read(cx).active_pane().read(cx);
let item = pane.active_item().unwrap(); let item = pane.active_item().unwrap();
item.to_any().downcast::<Editor>().unwrap() item.downcast::<Editor>().unwrap()
}); });
cx.update(|cx| { cx.update(|cx| {
@ -504,7 +503,6 @@ mod tests {
workspace workspace
.active_item(cx) .active_item(cx)
.unwrap() .unwrap()
.to_any()
.downcast::<Editor>() .downcast::<Editor>()
.unwrap() .unwrap()
}); });
@ -573,7 +571,6 @@ mod tests {
workspace workspace
.active_item(cx) .active_item(cx)
.unwrap() .unwrap()
.to_any()
.downcast::<Editor>() .downcast::<Editor>()
.unwrap() .unwrap()
}); });
@ -598,7 +595,6 @@ mod tests {
workspace workspace
.active_item(cx) .active_item(cx)
.unwrap() .unwrap()
.to_any()
.downcast::<Editor>() .downcast::<Editor>()
.unwrap() .unwrap()
}); });
@ -738,7 +734,6 @@ mod tests {
.update(&mut cx, |w, cx| w.open_path(file1.clone(), cx)) .update(&mut cx, |w, cx| w.open_path(file1.clone(), cx))
.await .await
.unwrap() .unwrap()
.to_any()
.downcast::<Editor>() .downcast::<Editor>()
.unwrap(); .unwrap();
editor1.update(&mut cx, |editor, cx| { editor1.update(&mut cx, |editor, cx| {
@ -748,14 +743,12 @@ mod tests {
.update(&mut cx, |w, cx| w.open_path(file2.clone(), cx)) .update(&mut cx, |w, cx| w.open_path(file2.clone(), cx))
.await .await
.unwrap() .unwrap()
.to_any()
.downcast::<Editor>() .downcast::<Editor>()
.unwrap(); .unwrap();
let editor3 = workspace let editor3 = workspace
.update(&mut cx, |w, cx| w.open_path(file3.clone(), cx)) .update(&mut cx, |w, cx| w.open_path(file3.clone(), cx))
.await .await
.unwrap() .unwrap()
.to_any()
.downcast::<Editor>() .downcast::<Editor>()
.unwrap(); .unwrap();
editor3.update(&mut cx, |editor, cx| { editor3.update(&mut cx, |editor, cx| {
@ -871,7 +864,7 @@ mod tests {
) -> (ProjectPath, DisplayPoint) { ) -> (ProjectPath, DisplayPoint) {
workspace.update(cx, |workspace, cx| { workspace.update(cx, |workspace, cx| {
let item = workspace.active_item(cx).unwrap(); let item = workspace.active_item(cx).unwrap();
let editor = item.to_any().downcast::<Editor>().unwrap(); let editor = item.downcast::<Editor>().unwrap();
let selections = editor.update(cx, |editor, cx| editor.selected_display_ranges(cx)); let selections = editor.update(cx, |editor, cx| editor.selected_display_ranges(cx));
let path = workspace let path = workspace
.project() .project()