@@ -13,6 +13,7 @@ use crate::{
},
link_go_to_definition::{
go_to_fetched_definition, go_to_fetched_type_definition, update_go_to_definition_link,
+ GoToDefinitionTrigger,
},
mouse_context_menu, EditorSettings, EditorStyle, GutterHover, UnfoldAt,
};
@@ -42,7 +43,7 @@ use language::{
};
use project::{
project_settings::{GitGutterSetting, ProjectSettings},
- InlayHintLabelPart, ProjectPath, ResolveState,
+ InlayHintLabelPart, Location, LocationLink, ProjectPath, ResolveState,
};
use smallvec::SmallVec;
use std::{
@@ -395,7 +396,15 @@ impl EditorElement {
None
};
- update_go_to_definition_link(editor, point, cmd, shift, cx);
+ update_go_to_definition_link(
+ editor,
+ point
+ .map(GoToDefinitionTrigger::Text)
+ .unwrap_or(GoToDefinitionTrigger::None),
+ cmd,
+ shift,
+ cx,
+ );
if editor.has_pending_selection() {
let mut scroll_delta = Vector2F::zero();
@@ -460,7 +469,13 @@ impl EditorElement {
let point_for_position = position_map.point_for_position(text_bounds, position);
match point_for_position.as_valid() {
Some(point) => {
- update_go_to_definition_link(editor, Some(point), cmd, shift, cx);
+ update_go_to_definition_link(
+ editor,
+ GoToDefinitionTrigger::Text(point),
+ cmd,
+ shift,
+ cx,
+ );
hover_at(editor, Some(point), cx);
}
None => {
@@ -468,12 +483,13 @@ impl EditorElement {
position_map,
point_for_position,
editor,
+ (cmd, shift),
cx,
);
}
}
} else {
- update_go_to_definition_link(editor, None, cmd, shift, cx);
+ update_go_to_definition_link(editor, GoToDefinitionTrigger::None, cmd, shift, cx);
hover_at(editor, None, cx);
}
@@ -1821,11 +1837,11 @@ impl EditorElement {
}
}
-// TODO kb implement
fn update_inlay_link_and_hover_points(
position_map: &PositionMap,
point_for_position: PointForPosition,
editor: &mut Editor,
+ (cmd_held, shift_held): (bool, bool),
cx: &mut ViewContext<'_, '_, Editor>,
) {
let hint_start_offset = position_map
@@ -1861,6 +1877,9 @@ fn update_inlay_link_and_hover_points(
.to_point(&position_map.snapshot.display_snapshot),
Bias::Right,
);
+
+ let mut go_to_definition_updated = false;
+ let mut hover_updated = false;
if let Some(hovered_hint) = editor
.visible_inlay_hints(cx)
.into_iter()
@@ -1872,7 +1891,7 @@ fn update_inlay_link_and_hover_points(
if let Some(cached_hint) =
inlay_hint_cache.hint_by_id(previous_valid_anchor.excerpt_id, hovered_hint.id)
{
- match &cached_hint.resolve_state {
+ match cached_hint.resolve_state {
ResolveState::CanResolve(_, _) => {
if let Some(buffer_id) = previous_valid_anchor.buffer_id {
inlay_hint_cache.spawn_hint_resolve(
@@ -1884,7 +1903,7 @@ fn update_inlay_link_and_hover_points(
}
}
ResolveState::Resolved => {
- match &cached_hint.label {
+ match cached_hint.label {
project::InlayHintLabel::String(_) => {
if cached_hint.tooltip.is_some() {
dbg!(&cached_hint.tooltip); // TODO kb
@@ -1893,7 +1912,7 @@ fn update_inlay_link_and_hover_points(
}
project::InlayHintLabel::LabelParts(label_parts) => {
if let Some(hovered_hint_part) = find_hovered_hint_part(
- &label_parts,
+ label_parts,
hint_start_offset..hint_end_offset,
hovered_offset,
) {
@@ -1901,9 +1920,31 @@ fn update_inlay_link_and_hover_points(
dbg!(&hovered_hint_part.tooltip); // TODO kb
// hover_at_point = Some(hovered_offset);
}
- if let Some(location) = &hovered_hint_part.location {
- dbg!(location); // TODO kb
- // go_to_definition_point = Some(location);
+ if let Some(location) = hovered_hint_part.location {
+ if let Some(buffer) = cached_hint
+ .position
+ .buffer_id
+ .and_then(|buffer_id| buffer.buffer(buffer_id))
+ {
+ go_to_definition_updated = true;
+ update_go_to_definition_link(
+ editor,
+ GoToDefinitionTrigger::InlayHint(
+ hovered_hint.position,
+ LocationLink {
+ origin: Some(Location {
+ buffer,
+ range: cached_hint.position
+ ..cached_hint.position,
+ }),
+ target: location,
+ },
+ ),
+ cmd_held,
+ shift_held,
+ cx,
+ );
+ }
}
}
}
@@ -1913,14 +1954,27 @@ fn update_inlay_link_and_hover_points(
}
}
}
+
+ if !go_to_definition_updated {
+ update_go_to_definition_link(
+ editor,
+ GoToDefinitionTrigger::None,
+ cmd_held,
+ shift_held,
+ cx,
+ );
+ }
+ if !hover_updated {
+ hover_at(editor, None, cx);
+ }
}
}
-fn find_hovered_hint_part<'a>(
- label_parts: &'a [InlayHintLabelPart],
+fn find_hovered_hint_part(
+ label_parts: Vec<InlayHintLabelPart>,
hint_range: Range<InlayOffset>,
hovered_offset: InlayOffset,
-) -> Option<&'a InlayHintLabelPart> {
+) -> Option<InlayHintLabelPart> {
if hovered_offset >= hint_range.start && hovered_offset <= hint_range.end {
let mut hovered_character = (hovered_offset - hint_range.start).0;
for part in label_parts {
@@ -7,16 +7,50 @@ use util::TryFutureExt;
#[derive(Debug, Default)]
pub struct LinkGoToDefinitionState {
- pub last_mouse_location: Option<Anchor>,
+ pub last_trigger_point: Option<TriggerPoint>,
pub symbol_range: Option<Range<Anchor>>,
pub kind: Option<LinkDefinitionKind>,
pub definitions: Vec<LocationLink>,
pub task: Option<Task<Option<()>>>,
}
+pub enum GoToDefinitionTrigger {
+ Text(DisplayPoint),
+ InlayHint(Anchor, LocationLink),
+ None,
+}
+
+#[derive(Debug, Clone)]
+pub enum TriggerPoint {
+ Text(Anchor),
+ InlayHint(Anchor, LocationLink),
+}
+
+impl TriggerPoint {
+ fn anchor(&self) -> &Anchor {
+ match self {
+ TriggerPoint::Text(anchor) => anchor,
+ TriggerPoint::InlayHint(anchor, _) => anchor,
+ }
+ }
+
+ pub fn definition_kind(&self, shift: bool) -> LinkDefinitionKind {
+ match self {
+ TriggerPoint::Text(_) => {
+ if shift {
+ LinkDefinitionKind::Type
+ } else {
+ LinkDefinitionKind::Symbol
+ }
+ }
+ TriggerPoint::InlayHint(_, link) => LinkDefinitionKind::Type,
+ }
+ }
+}
+
pub fn update_go_to_definition_link(
editor: &mut Editor,
- point: Option<DisplayPoint>,
+ origin: GoToDefinitionTrigger,
cmd_held: bool,
shift_held: bool,
cx: &mut ViewContext<Editor>,
@@ -25,23 +59,30 @@ pub fn update_go_to_definition_link(
// Store new mouse point as an anchor
let snapshot = editor.snapshot(cx);
- let point = point.map(|point| {
- snapshot
- .buffer_snapshot
- .anchor_before(point.to_offset(&snapshot.display_snapshot, Bias::Left))
- });
+ let trigger_point = match origin {
+ GoToDefinitionTrigger::Text(p) => {
+ Some(TriggerPoint::Text(snapshot.buffer_snapshot.anchor_before(
+ p.to_offset(&snapshot.display_snapshot, Bias::Left),
+ )))
+ }
+ GoToDefinitionTrigger::InlayHint(p, target) => Some(TriggerPoint::InlayHint(p, target)),
+ GoToDefinitionTrigger::None => None,
+ };
// If the new point is the same as the previously stored one, return early
if let (Some(a), Some(b)) = (
- &point,
- &editor.link_go_to_definition_state.last_mouse_location,
+ &trigger_point,
+ &editor.link_go_to_definition_state.last_trigger_point,
) {
- if a.cmp(b, &snapshot.buffer_snapshot).is_eq() {
+ if a.anchor()
+ .cmp(b.anchor(), &snapshot.buffer_snapshot)
+ .is_eq()
+ {
return;
}
}
- editor.link_go_to_definition_state.last_mouse_location = point.clone();
+ editor.link_go_to_definition_state.last_trigger_point = trigger_point.clone();
if pending_nonempty_selection {
hide_link_definition(editor, cx);
@@ -49,14 +90,9 @@ pub fn update_go_to_definition_link(
}
if cmd_held {
- if let Some(point) = point {
- let kind = if shift_held {
- LinkDefinitionKind::Type
- } else {
- LinkDefinitionKind::Symbol
- };
-
- show_link_definition(kind, editor, point, snapshot, cx);
+ if let Some(trigger_point) = trigger_point {
+ let kind = trigger_point.definition_kind(shift_held);
+ show_link_definition(kind, editor, trigger_point, snapshot, cx);
return;
}
}
@@ -73,7 +109,7 @@ pub enum LinkDefinitionKind {
pub fn show_link_definition(
definition_kind: LinkDefinitionKind,
editor: &mut Editor,
- trigger_point: Anchor,
+ trigger_point: TriggerPoint,
snapshot: EditorSnapshot,
cx: &mut ViewContext<Editor>,
) {
@@ -86,10 +122,11 @@ pub fn show_link_definition(
return;
}
+ let trigger_anchor = trigger_point.anchor().clone();
let (buffer, buffer_position) = if let Some(output) = editor
.buffer
.read(cx)
- .text_anchor_for_position(trigger_point.clone(), cx)
+ .text_anchor_for_position(trigger_anchor.clone(), cx)
{
output
} else {
@@ -99,7 +136,7 @@ pub fn show_link_definition(
let excerpt_id = if let Some((excerpt_id, _, _)) = editor
.buffer()
.read(cx)
- .excerpt_containing(trigger_point.clone(), cx)
+ .excerpt_containing(trigger_anchor.clone(), cx)
{
excerpt_id
} else {
@@ -116,12 +153,12 @@ pub fn show_link_definition(
if let Some(symbol_range) = &editor.link_go_to_definition_state.symbol_range {
let point_after_start = symbol_range
.start
- .cmp(&trigger_point, &snapshot.buffer_snapshot)
+ .cmp(&trigger_anchor, &snapshot.buffer_snapshot)
.is_le();
let point_before_end = symbol_range
.end
- .cmp(&trigger_point, &snapshot.buffer_snapshot)
+ .cmp(&trigger_anchor, &snapshot.buffer_snapshot)
.is_ge();
let point_within_range = point_after_start && point_before_end;
@@ -132,34 +169,45 @@ pub fn show_link_definition(
let task = cx.spawn(|this, mut cx| {
async move {
- // query the LSP for definition info
- let definition_request = cx.update(|cx| {
- project.update(cx, |project, cx| match definition_kind {
- LinkDefinitionKind::Symbol => project.definition(&buffer, buffer_position, cx),
-
- LinkDefinitionKind::Type => {
- project.type_definition(&buffer, buffer_position, cx)
- }
- })
- });
+ let result = match trigger_point {
+ TriggerPoint::Text(_) => {
+ // query the LSP for definition info
+ cx.update(|cx| {
+ project.update(cx, |project, cx| match definition_kind {
+ LinkDefinitionKind::Symbol => {
+ project.definition(&buffer, buffer_position, cx)
+ }
- let result = definition_request.await.ok().map(|definition_result| {
- (
- definition_result.iter().find_map(|link| {
- link.origin.as_ref().map(|origin| {
- let start = snapshot
- .buffer_snapshot
- .anchor_in_excerpt(excerpt_id.clone(), origin.range.start);
- let end = snapshot
- .buffer_snapshot
- .anchor_in_excerpt(excerpt_id.clone(), origin.range.end);
-
- start..end
+ LinkDefinitionKind::Type => {
+ project.type_definition(&buffer, buffer_position, cx)
+ }
})
- }),
- definition_result,
- )
- });
+ })
+ .await
+ .ok()
+ .map(|definition_result| {
+ (
+ definition_result.iter().find_map(|link| {
+ link.origin.as_ref().map(|origin| {
+ let start = snapshot
+ .buffer_snapshot
+ .anchor_in_excerpt(excerpt_id.clone(), origin.range.start);
+ let end = snapshot
+ .buffer_snapshot
+ .anchor_in_excerpt(excerpt_id.clone(), origin.range.end);
+
+ start..end
+ })
+ }),
+ definition_result,
+ )
+ })
+ }
+ TriggerPoint::InlayHint(trigger_source, trigger_target) => {
+ // TODO kb range is wrong, should be in inlay coordinates
+ Some((Some(trigger_source..trigger_source), vec![trigger_target]))
+ }
+ };
this.update(&mut cx, |this, cx| {
// Clear any existing highlights
@@ -202,7 +250,7 @@ pub fn show_link_definition(
// If no symbol range returned from language server, use the surrounding word.
let highlight_range = symbol_range.unwrap_or_else(|| {
let snapshot = &snapshot.buffer_snapshot;
- let (offset_range, _) = snapshot.surrounding_word(trigger_point);
+ let (offset_range, _) = snapshot.surrounding_word(trigger_anchor);
snapshot.anchor_before(offset_range.start)
..snapshot.anchor_after(offset_range.end)
@@ -355,7 +403,13 @@ mod tests {
// Press cmd+shift to trigger highlight
cx.update_editor(|editor, cx| {
- update_go_to_definition_link(editor, Some(hover_point), true, true, cx);
+ update_go_to_definition_link(
+ editor,
+ GoToDefinitionTrigger::Text(hover_point),
+ true,
+ true,
+ cx,
+ );
});
requests.next().await;
cx.foreground().run_until_parked();
@@ -461,7 +515,13 @@ mod tests {
});
cx.update_editor(|editor, cx| {
- update_go_to_definition_link(editor, Some(hover_point), true, false, cx);
+ update_go_to_definition_link(
+ editor,
+ GoToDefinitionTrigger::Text(hover_point),
+ true,
+ false,
+ cx,
+ );
});
requests.next().await;
cx.foreground().run_until_parked();
@@ -482,7 +542,7 @@ mod tests {
"});
// Response without source range still highlights word
- cx.update_editor(|editor, _| editor.link_go_to_definition_state.last_mouse_location = None);
+ cx.update_editor(|editor, _| editor.link_go_to_definition_state.last_trigger_point = None);
let mut requests = cx.handle_request::<GotoDefinition, _, _>(move |url, _, _| async move {
Ok(Some(lsp::GotoDefinitionResponse::Link(vec![
lsp::LocationLink {
@@ -495,7 +555,13 @@ mod tests {
])))
});
cx.update_editor(|editor, cx| {
- update_go_to_definition_link(editor, Some(hover_point), true, false, cx);
+ update_go_to_definition_link(
+ editor,
+ GoToDefinitionTrigger::Text(hover_point),
+ true,
+ false,
+ cx,
+ );
});
requests.next().await;
cx.foreground().run_until_parked();
@@ -517,7 +583,13 @@ mod tests {
Ok(Some(lsp::GotoDefinitionResponse::Link(vec![])))
});
cx.update_editor(|editor, cx| {
- update_go_to_definition_link(editor, Some(hover_point), true, false, cx);
+ update_go_to_definition_link(
+ editor,
+ GoToDefinitionTrigger::Text(hover_point),
+ true,
+ false,
+ cx,
+ );
});
requests.next().await;
cx.foreground().run_until_parked();
@@ -534,7 +606,13 @@ mod tests {
fn do_work() { teΛst(); }
"});
cx.update_editor(|editor, cx| {
- update_go_to_definition_link(editor, Some(hover_point), false, false, cx);
+ update_go_to_definition_link(
+ editor,
+ GoToDefinitionTrigger::Text(hover_point),
+ false,
+ false,
+ cx,
+ );
});
cx.foreground().run_until_parked();
@@ -593,7 +671,13 @@ mod tests {
// Moving the mouse restores the highlights.
cx.update_editor(|editor, cx| {
- update_go_to_definition_link(editor, Some(hover_point), true, false, cx);
+ update_go_to_definition_link(
+ editor,
+ GoToDefinitionTrigger::Text(hover_point),
+ true,
+ false,
+ cx,
+ );
});
cx.foreground().run_until_parked();
cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
@@ -607,7 +691,13 @@ mod tests {
fn do_work() { tesΛt(); }
"});
cx.update_editor(|editor, cx| {
- update_go_to_definition_link(editor, Some(hover_point), true, false, cx);
+ update_go_to_definition_link(
+ editor,
+ GoToDefinitionTrigger::Text(hover_point),
+ true,
+ false,
+ cx,
+ );
});
cx.foreground().run_until_parked();
cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
@@ -703,7 +793,13 @@ mod tests {
});
});
cx.update_editor(|editor, cx| {
- update_go_to_definition_link(editor, Some(hover_point), true, false, cx);
+ update_go_to_definition_link(
+ editor,
+ GoToDefinitionTrigger::Text(hover_point),
+ true,
+ false,
+ cx,
+ );
});
cx.foreground().run_until_parked();
assert!(requests.try_next().is_err());