Add cmd+shift+click action for triggering go to type definition

This commit is contained in:
ForLoveOfCats 2022-07-29 00:11:55 -04:00
parent 5149c15329
commit 2c70583ef0
3 changed files with 159 additions and 41 deletions

View file

@ -6,7 +6,9 @@ use super::{
use crate::{ use crate::{
display_map::{BlockStyle, DisplaySnapshot, TransformBlock}, display_map::{BlockStyle, DisplaySnapshot, TransformBlock},
hover_popover::HoverAt, hover_popover::HoverAt,
link_go_to_definition::{CmdChanged, GoToFetchedDefinition, UpdateGoToDefinitionLink}, link_go_to_definition::{
CmdShiftChanged, GoToFetchedDefinition, GoToFetchedTypeDefinition, UpdateGoToDefinitionLink,
},
mouse_context_menu::DeployMouseContextMenu, mouse_context_menu::DeployMouseContextMenu,
EditorStyle, EditorStyle,
}; };
@ -122,7 +124,12 @@ impl EditorElement {
if cmd && paint.text_bounds.contains_point(position) { if cmd && paint.text_bounds.contains_point(position) {
let (point, overshoot) = paint.point_for_position(&self.snapshot(cx), layout, position); let (point, overshoot) = paint.point_for_position(&self.snapshot(cx), layout, position);
if overshoot.is_zero() { if overshoot.is_zero() {
cx.dispatch_action(GoToFetchedDefinition { point }); if shift {
cx.dispatch_action(GoToFetchedTypeDefinition { point });
} else {
cx.dispatch_action(GoToFetchedDefinition { point });
}
return true; return true;
} }
} }
@ -238,8 +245,12 @@ impl EditorElement {
fn mouse_moved( fn mouse_moved(
&self, &self,
position: Vector2F, MouseMovedEvent {
cmd: bool, cmd,
shift,
position,
..
}: MouseMovedEvent,
layout: &LayoutState, layout: &LayoutState,
paint: &PaintState, paint: &PaintState,
cx: &mut EventContext, cx: &mut EventContext,
@ -260,6 +271,7 @@ impl EditorElement {
cx.dispatch_action(UpdateGoToDefinitionLink { cx.dispatch_action(UpdateGoToDefinitionLink {
point, point,
cmd_held: cmd, cmd_held: cmd,
shift_held: shift,
}); });
if paint if paint
@ -283,8 +295,11 @@ impl EditorElement {
true true
} }
fn modifiers_changed(&self, cmd: bool, cx: &mut EventContext) -> bool { fn modifiers_changed(&self, event: ModifiersChangedEvent, cx: &mut EventContext) -> bool {
cx.dispatch_action(CmdChanged { cmd_down: cmd }); cx.dispatch_action(CmdShiftChanged {
cmd_down: event.cmd,
shift_down: event.shift,
});
false false
} }
@ -1534,32 +1549,34 @@ impl Element for EditorElement {
paint, paint,
cx, cx,
), ),
Event::MouseDown(MouseButtonEvent { Event::MouseDown(MouseButtonEvent {
button: MouseButton::Right, button: MouseButton::Right,
position, position,
.. ..
}) => self.mouse_right_down(*position, layout, paint, cx), }) => self.mouse_right_down(*position, layout, paint, cx),
Event::MouseUp(MouseButtonEvent { Event::MouseUp(MouseButtonEvent {
button: MouseButton::Left, button: MouseButton::Left,
position, position,
.. ..
}) => self.mouse_up(*position, cx), }) => self.mouse_up(*position, cx),
Event::MouseMoved(MouseMovedEvent { Event::MouseMoved(MouseMovedEvent {
pressed_button: Some(MouseButton::Left), pressed_button: Some(MouseButton::Left),
position, position,
.. ..
}) => self.mouse_dragged(*position, layout, paint, cx), }) => self.mouse_dragged(*position, layout, paint, cx),
Event::ScrollWheel(ScrollWheelEvent { Event::ScrollWheel(ScrollWheelEvent {
position, position,
delta, delta,
precise, precise,
}) => self.scroll(*position, *delta, *precise, layout, paint, cx), }) => self.scroll(*position, *delta, *precise, layout, paint, cx),
Event::ModifiersChanged(ModifiersChangedEvent { cmd, .. }) => {
self.modifiers_changed(*cmd, cx) &Event::ModifiersChanged(event) => self.modifiers_changed(event, cx),
}
Event::MouseMoved(MouseMovedEvent { position, cmd, .. }) => { &Event::MouseMoved(event) => self.mouse_moved(event, layout, paint, cx),
self.mouse_moved(*position, *cmd, layout, paint, cx)
}
_ => false, _ => false,
} }

View file

@ -8,18 +8,21 @@ use util::TryFutureExt;
use workspace::Workspace; use workspace::Workspace;
use crate::{ use crate::{
Anchor, DisplayPoint, Editor, EditorSnapshot, Event, GoToDefinition, Select, SelectPhase, Anchor, DisplayPoint, Editor, EditorSnapshot, Event, GoToDefinition, GoToTypeDefinition,
Select, SelectPhase,
}; };
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub struct UpdateGoToDefinitionLink { pub struct UpdateGoToDefinitionLink {
pub point: Option<DisplayPoint>, pub point: Option<DisplayPoint>,
pub cmd_held: bool, pub cmd_held: bool,
pub shift_held: bool,
} }
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub struct CmdChanged { pub struct CmdShiftChanged {
pub cmd_down: bool, pub cmd_down: bool,
pub shift_down: bool,
} }
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
@ -27,28 +30,44 @@ pub struct GoToFetchedDefinition {
pub point: DisplayPoint, pub point: DisplayPoint,
} }
#[derive(Clone, PartialEq)]
pub struct GoToFetchedTypeDefinition {
pub point: DisplayPoint,
}
impl_internal_actions!( impl_internal_actions!(
editor, editor,
[UpdateGoToDefinitionLink, CmdChanged, GoToFetchedDefinition] [
UpdateGoToDefinitionLink,
CmdShiftChanged,
GoToFetchedDefinition,
GoToFetchedTypeDefinition
]
); );
pub fn init(cx: &mut MutableAppContext) { pub fn init(cx: &mut MutableAppContext) {
cx.add_action(update_go_to_definition_link); cx.add_action(update_go_to_definition_link);
cx.add_action(cmd_changed); cx.add_action(cmd_shift_changed);
cx.add_action(go_to_fetched_definition); cx.add_action(go_to_fetched_definition);
cx.add_action(go_to_fetched_type_definition);
} }
#[derive(Default)] #[derive(Default)]
pub struct LinkGoToDefinitionState { pub struct LinkGoToDefinitionState {
pub last_mouse_location: Option<Anchor>, pub last_mouse_location: Option<Anchor>,
pub symbol_range: Option<Range<Anchor>>, pub symbol_range: Option<Range<Anchor>>,
pub kind: Option<LinkDefinitionKind>,
pub definitions: Vec<LocationLink>, pub definitions: Vec<LocationLink>,
pub task: Option<Task<Option<()>>>, pub task: Option<Task<Option<()>>>,
} }
pub fn update_go_to_definition_link( pub fn update_go_to_definition_link(
editor: &mut Editor, editor: &mut Editor,
&UpdateGoToDefinitionLink { point, cmd_held }: &UpdateGoToDefinitionLink, &UpdateGoToDefinitionLink {
point,
cmd_held,
shift_held,
}: &UpdateGoToDefinitionLink,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) { ) {
// Store new mouse point as an anchor // Store new mouse point as an anchor
@ -72,7 +91,13 @@ pub fn update_go_to_definition_link(
editor.link_go_to_definition_state.last_mouse_location = point.clone(); editor.link_go_to_definition_state.last_mouse_location = point.clone();
if cmd_held { if cmd_held {
if let Some(point) = point { if let Some(point) = point {
show_link_definition(editor, point, snapshot, cx); let kind = if shift_held {
LinkDefinitionKind::Type
} else {
LinkDefinitionKind::Symbol
};
show_link_definition(kind, editor, point, snapshot, cx);
return; return;
} }
} }
@ -80,9 +105,12 @@ pub fn update_go_to_definition_link(
hide_link_definition(editor, cx); hide_link_definition(editor, cx);
} }
pub fn cmd_changed( pub fn cmd_shift_changed(
editor: &mut Editor, editor: &mut Editor,
&CmdChanged { cmd_down }: &CmdChanged, &CmdShiftChanged {
cmd_down,
shift_down,
}: &CmdShiftChanged,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) { ) {
if let Some(point) = editor if let Some(point) = editor
@ -92,19 +120,37 @@ pub fn cmd_changed(
{ {
if cmd_down { if cmd_down {
let snapshot = editor.snapshot(cx); let snapshot = editor.snapshot(cx);
show_link_definition(editor, point.clone(), snapshot, cx); let kind = if shift_down {
LinkDefinitionKind::Type
} else {
LinkDefinitionKind::Symbol
};
show_link_definition(kind, editor, point.clone(), snapshot, cx);
} else { } else {
hide_link_definition(editor, cx) hide_link_definition(editor, cx)
} }
} }
} }
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LinkDefinitionKind {
Symbol,
Type,
}
pub fn show_link_definition( pub fn show_link_definition(
definition_kind: LinkDefinitionKind,
editor: &mut Editor, editor: &mut Editor,
trigger_point: Anchor, trigger_point: Anchor,
snapshot: EditorSnapshot, snapshot: EditorSnapshot,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) { ) {
let same_kind = editor.link_go_to_definition_state.kind == Some(definition_kind);
if !same_kind {
hide_link_definition(editor, cx);
}
if editor.pending_rename.is_some() { if editor.pending_rename.is_some() {
return; return;
} }
@ -135,17 +181,22 @@ pub fn show_link_definition(
return; return;
}; };
// Don't request again if the location is within the symbol region of a previous request // Don't request again if the location is within the symbol region of a previous request with the same kind
if let Some(symbol_range) = &editor.link_go_to_definition_state.symbol_range { if let Some(symbol_range) = &editor.link_go_to_definition_state.symbol_range {
if symbol_range let point_after_start = symbol_range
.start .start
.cmp(&trigger_point, &snapshot.buffer_snapshot) .cmp(&trigger_point, &snapshot.buffer_snapshot)
.is_le() .is_le();
&& symbol_range
.end let point_before_end = symbol_range
.cmp(&trigger_point, &snapshot.buffer_snapshot) .end
.is_ge() .cmp(&trigger_point, &snapshot.buffer_snapshot)
{ .is_ge();
let point_within_range = point_after_start && point_before_end;
let same_kind = editor.link_go_to_definition_state.kind == Some(definition_kind);
if point_within_range && same_kind {
return; return;
} }
} }
@ -154,8 +205,14 @@ pub fn show_link_definition(
async move { async move {
// query the LSP for definition info // query the LSP for definition info
let definition_request = cx.update(|cx| { let definition_request = cx.update(|cx| {
project.update(cx, |project, cx| { project.update(cx, |project, cx| match definition_kind {
project.definition(&buffer, buffer_position.clone(), cx) LinkDefinitionKind::Symbol => {
project.definition(&buffer, buffer_position.clone(), cx)
}
LinkDefinitionKind::Type => {
project.type_definition(&buffer, buffer_position.clone(), cx)
}
}) })
}); });
@ -181,6 +238,7 @@ pub fn show_link_definition(
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
// Clear any existing highlights // Clear any existing highlights
this.clear_text_highlights::<LinkGoToDefinitionState>(cx); this.clear_text_highlights::<LinkGoToDefinitionState>(cx);
this.link_go_to_definition_state.kind = Some(definition_kind);
this.link_go_to_definition_state.symbol_range = result this.link_go_to_definition_state.symbol_range = result
.as_ref() .as_ref()
.and_then(|(symbol_range, _)| symbol_range.clone()); .and_then(|(symbol_range, _)| symbol_range.clone());
@ -258,7 +316,24 @@ pub fn hide_link_definition(editor: &mut Editor, cx: &mut ViewContext<Editor>) {
pub fn go_to_fetched_definition( pub fn go_to_fetched_definition(
workspace: &mut Workspace, workspace: &mut Workspace,
GoToFetchedDefinition { point }: &GoToFetchedDefinition, &GoToFetchedDefinition { point }: &GoToFetchedDefinition,
cx: &mut ViewContext<Workspace>,
) {
go_to_fetched_definition_of_kind(LinkDefinitionKind::Symbol, workspace, point, cx);
}
pub fn go_to_fetched_type_definition(
workspace: &mut Workspace,
&GoToFetchedTypeDefinition { point }: &GoToFetchedTypeDefinition,
cx: &mut ViewContext<Workspace>,
) {
go_to_fetched_definition_of_kind(LinkDefinitionKind::Type, workspace, point, cx);
}
fn go_to_fetched_definition_of_kind(
kind: LinkDefinitionKind,
workspace: &mut Workspace,
point: DisplayPoint,
cx: &mut ViewContext<Workspace>, cx: &mut ViewContext<Workspace>,
) { ) {
let active_item = workspace.active_item(cx); let active_item = workspace.active_item(cx);
@ -271,13 +346,14 @@ pub fn go_to_fetched_definition(
return; return;
}; };
let definitions = editor_handle.update(cx, |editor, cx| { let (cached_definitions, cached_definitions_kind) = editor_handle.update(cx, |editor, cx| {
let definitions = editor.link_go_to_definition_state.definitions.clone(); let definitions = editor.link_go_to_definition_state.definitions.clone();
hide_link_definition(editor, cx); hide_link_definition(editor, cx);
definitions (definitions, editor.link_go_to_definition_state.kind)
}); });
if !definitions.is_empty() { let is_correct_kind = cached_definitions_kind == Some(kind);
if !cached_definitions.is_empty() && is_correct_kind {
editor_handle.update(cx, |editor, cx| { editor_handle.update(cx, |editor, cx| {
if !editor.focused { if !editor.focused {
cx.focus_self(); cx.focus_self();
@ -285,7 +361,7 @@ pub fn go_to_fetched_definition(
} }
}); });
Editor::navigate_to_definitions(workspace, editor_handle, definitions, cx); Editor::navigate_to_definitions(workspace, editor_handle, cached_definitions, cx);
} else { } else {
editor_handle.update(cx, |editor, cx| { editor_handle.update(cx, |editor, cx| {
editor.select( editor.select(
@ -298,7 +374,13 @@ pub fn go_to_fetched_definition(
); );
}); });
Editor::go_to_definition(workspace, &GoToDefinition, cx); match kind {
LinkDefinitionKind::Symbol => Editor::go_to_definition(workspace, &GoToDefinition, cx),
LinkDefinitionKind::Type => {
Editor::go_to_type_definition(workspace, &GoToTypeDefinition, cx)
}
}
} }
} }
@ -367,6 +449,7 @@ mod tests {
&UpdateGoToDefinitionLink { &UpdateGoToDefinitionLink {
point: Some(hover_point), point: Some(hover_point),
cmd_held: true, cmd_held: true,
shift_held: false,
}, },
cx, cx,
); );
@ -382,7 +465,14 @@ mod tests {
// Unpress cmd causes highlight to go away // Unpress cmd causes highlight to go away
cx.update_editor(|editor, cx| { cx.update_editor(|editor, cx| {
cmd_changed(editor, &CmdChanged { cmd_down: false }, cx); cmd_shift_changed(
editor,
&CmdShiftChanged {
cmd_down: false,
shift_down: false,
},
cx,
);
}); });
// Assert no link highlights // Assert no link highlights
cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {" cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
@ -412,6 +502,7 @@ mod tests {
&UpdateGoToDefinitionLink { &UpdateGoToDefinitionLink {
point: Some(hover_point), point: Some(hover_point),
cmd_held: true, cmd_held: true,
shift_held: false,
}, },
cx, cx,
); );
@ -445,6 +536,7 @@ mod tests {
&UpdateGoToDefinitionLink { &UpdateGoToDefinitionLink {
point: Some(hover_point), point: Some(hover_point),
cmd_held: true, cmd_held: true,
shift_held: false,
}, },
cx, cx,
); );
@ -473,6 +565,7 @@ mod tests {
&UpdateGoToDefinitionLink { &UpdateGoToDefinitionLink {
point: Some(hover_point), point: Some(hover_point),
cmd_held: false, cmd_held: false,
shift_held: false,
}, },
cx, cx,
); );
@ -512,7 +605,14 @@ mod tests {
]))) ])))
}); });
cx.update_editor(|editor, cx| { cx.update_editor(|editor, cx| {
cmd_changed(editor, &CmdChanged { cmd_down: true }, cx); cmd_shift_changed(
editor,
&CmdShiftChanged {
cmd_down: true,
shift_down: false,
},
cx,
);
}); });
requests.next().await; requests.next().await;
cx.foreground().run_until_parked(); cx.foreground().run_until_parked();
@ -537,6 +637,7 @@ mod tests {
&UpdateGoToDefinitionLink { &UpdateGoToDefinitionLink {
point: Some(hover_point), point: Some(hover_point),
cmd_held: true, cmd_held: true,
shift_held: false,
}, },
cx, cx,
); );

View file

@ -11,7 +11,7 @@ pub struct KeyUpEvent {
pub keystroke: Keystroke, pub keystroke: Keystroke,
} }
#[derive(Clone, Debug)] #[derive(Clone, Copy, Debug)]
pub struct ModifiersChangedEvent { pub struct ModifiersChangedEvent {
pub ctrl: bool, pub ctrl: bool,
pub alt: bool, pub alt: bool,
@ -19,7 +19,7 @@ pub struct ModifiersChangedEvent {
pub cmd: bool, pub cmd: bool,
} }
#[derive(Clone, Debug, Default)] #[derive(Clone, Copy, Debug, Default)]
pub struct ScrollWheelEvent { pub struct ScrollWheelEvent {
pub position: Vector2F, pub position: Vector2F,
pub delta: Vector2F, pub delta: Vector2F,