Add link_go_to_definition test for inlays

Kirill Bulatov created

Change summary

crates/editor/src/element.rs               | 232 ------------
crates/editor/src/hover_popover.rs         |  23 +
crates/editor/src/inlay_hint_cache.rs      |  14 
crates/editor/src/link_go_to_definition.rs | 413 +++++++++++++++++++++++
4 files changed, 447 insertions(+), 235 deletions(-)

Detailed changes

crates/editor/src/element.rs 🔗

@@ -4,16 +4,16 @@ use super::{
     MAX_LINE_LEN,
 };
 use crate::{
-    display_map::{BlockStyle, DisplaySnapshot, FoldStatus, InlayOffset, TransformBlock},
+    display_map::{BlockStyle, DisplaySnapshot, FoldStatus, TransformBlock},
     editor_settings::ShowScrollbar,
     git::{diff_hunk_to_display, DisplayDiffHunk},
     hover_popover::{
-        hide_hover, hover_at, hover_at_inlay, InlayHover, HOVER_POPOVER_GAP,
-        MIN_POPOVER_CHARACTER_WIDTH, MIN_POPOVER_LINE_HEIGHT,
+        hide_hover, hover_at, HOVER_POPOVER_GAP, MIN_POPOVER_CHARACTER_WIDTH,
+        MIN_POPOVER_LINE_HEIGHT,
     },
     link_go_to_definition::{
         go_to_fetched_definition, go_to_fetched_type_definition, update_go_to_definition_link,
-        GoToDefinitionTrigger, InlayRange,
+        update_inlay_link_and_hover_points, GoToDefinitionTrigger,
     },
     mouse_context_menu, EditorSettings, EditorStyle, GutterHover, UnfoldAt,
 };
@@ -43,8 +43,7 @@ use language::{
 };
 use project::{
     project_settings::{GitGutterSetting, ProjectSettings},
-    HoverBlock, HoverBlockKind, InlayHintLabelPart, InlayHintLabelPartTooltip, InlayHintTooltip,
-    Location, LocationLink, ProjectPath, ResolveState,
+    ProjectPath,
 };
 use smallvec::SmallVec;
 use std::{
@@ -478,10 +477,11 @@ impl EditorElement {
                 }
                 None => {
                     update_inlay_link_and_hover_points(
-                        position_map,
+                        &position_map.snapshot,
                         point_for_position,
                         editor,
-                        (cmd, shift),
+                        cmd,
+                        shift,
                         cx,
                     );
                 }
@@ -1835,214 +1835,6 @@ impl EditorElement {
     }
 }
 
-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
-        .snapshot
-        .display_point_to_inlay_offset(point_for_position.previous_valid, Bias::Left);
-    let hint_end_offset = position_map
-        .snapshot
-        .display_point_to_inlay_offset(point_for_position.next_valid, Bias::Right);
-    let offset_overshoot = point_for_position.column_overshoot_after_line_end as usize;
-    let hovered_offset = if offset_overshoot == 0 {
-        Some(
-            position_map
-                .snapshot
-                .display_point_to_inlay_offset(point_for_position.exact_unclipped, Bias::Left),
-        )
-    } else if (hint_end_offset - hint_start_offset).0 >= offset_overshoot {
-        Some(InlayOffset(hint_start_offset.0 + offset_overshoot))
-    } else {
-        None
-    };
-    if let Some(hovered_offset) = hovered_offset {
-        let snapshot = editor.buffer().read(cx).snapshot(cx);
-        let previous_valid_anchor = snapshot.anchor_at(
-            point_for_position
-                .previous_valid
-                .to_point(&position_map.snapshot.display_snapshot),
-            Bias::Left,
-        );
-        let next_valid_anchor = snapshot.anchor_at(
-            point_for_position
-                .next_valid
-                .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()
-            .skip_while(|hint| hint.position.cmp(&previous_valid_anchor, &snapshot).is_lt())
-            .take_while(|hint| hint.position.cmp(&next_valid_anchor, &snapshot).is_le())
-            .max_by_key(|hint| hint.id)
-        {
-            let inlay_hint_cache = editor.inlay_hint_cache();
-            let excerpt_id = previous_valid_anchor.excerpt_id;
-            if let Some(cached_hint) = inlay_hint_cache.hint_by_id(excerpt_id, hovered_hint.id) {
-                match cached_hint.resolve_state {
-                    ResolveState::CanResolve(_, _) => {
-                        if let Some(buffer_id) = previous_valid_anchor.buffer_id {
-                            inlay_hint_cache.spawn_hint_resolve(
-                                buffer_id,
-                                excerpt_id,
-                                hovered_hint.id,
-                                cx,
-                            );
-                        }
-                    }
-                    ResolveState::Resolved => {
-                        match cached_hint.label {
-                            project::InlayHintLabel::String(_) => {
-                                if let Some(tooltip) = cached_hint.tooltip {
-                                    hover_at_inlay(
-                                        editor,
-                                        InlayHover {
-                                            excerpt: excerpt_id,
-                                            tooltip: match tooltip {
-                                                InlayHintTooltip::String(text) => HoverBlock {
-                                                    text,
-                                                    kind: HoverBlockKind::PlainText,
-                                                },
-                                                InlayHintTooltip::MarkupContent(content) => {
-                                                    HoverBlock {
-                                                        text: content.value,
-                                                        kind: content.kind,
-                                                    }
-                                                }
-                                            },
-                                            triggered_from: hovered_offset,
-                                            range: InlayRange {
-                                                inlay_position: hovered_hint.position,
-                                                highlight_start: hint_start_offset,
-                                                highlight_end: hint_end_offset,
-                                            },
-                                        },
-                                        cx,
-                                    );
-                                    hover_updated = true;
-                                }
-                            }
-                            project::InlayHintLabel::LabelParts(label_parts) => {
-                                if let Some((hovered_hint_part, part_range)) =
-                                    find_hovered_hint_part(
-                                        label_parts,
-                                        hint_start_offset..hint_end_offset,
-                                        hovered_offset,
-                                    )
-                                {
-                                    if let Some(tooltip) = hovered_hint_part.tooltip {
-                                        hover_at_inlay(
-                                            editor,
-                                            InlayHover {
-                                                excerpt: excerpt_id,
-                                                tooltip: match tooltip {
-                                                    InlayHintLabelPartTooltip::String(text) => {
-                                                        HoverBlock {
-                                                            text,
-                                                            kind: HoverBlockKind::PlainText,
-                                                        }
-                                                    }
-                                                    InlayHintLabelPartTooltip::MarkupContent(
-                                                        content,
-                                                    ) => HoverBlock {
-                                                        text: content.value,
-                                                        kind: content.kind,
-                                                    },
-                                                },
-                                                triggered_from: hovered_offset,
-                                                range: InlayRange {
-                                                    inlay_position: hovered_hint.position,
-                                                    highlight_start: part_range.start,
-                                                    highlight_end: part_range.end,
-                                                },
-                                            },
-                                            cx,
-                                        );
-                                        hover_updated = true;
-                                    }
-                                    if let Some(location) = hovered_hint_part.location {
-                                        if let Some(buffer) =
-                                            cached_hint.position.buffer_id.and_then(|buffer_id| {
-                                                editor.buffer().read(cx).buffer(buffer_id)
-                                            })
-                                        {
-                                            go_to_definition_updated = true;
-                                            update_go_to_definition_link(
-                                                editor,
-                                                GoToDefinitionTrigger::InlayHint(
-                                                    InlayRange {
-                                                        inlay_position: hovered_hint.position,
-                                                        highlight_start: part_range.start,
-                                                        highlight_end: part_range.end,
-                                                    },
-                                                    LocationLink {
-                                                        origin: Some(Location {
-                                                            buffer,
-                                                            range: cached_hint.position
-                                                                ..cached_hint.position,
-                                                        }),
-                                                        target: location,
-                                                    },
-                                                ),
-                                                cmd_held,
-                                                shift_held,
-                                                cx,
-                                            );
-                                        }
-                                    }
-                                }
-                            }
-                        };
-                    }
-                    ResolveState::Resolving => {}
-                }
-            }
-        }
-
-        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(
-    label_parts: Vec<InlayHintLabelPart>,
-    hint_range: Range<InlayOffset>,
-    hovered_offset: InlayOffset,
-) -> Option<(InlayHintLabelPart, Range<InlayOffset>)> {
-    if hovered_offset >= hint_range.start && hovered_offset <= hint_range.end {
-        let mut hovered_character = (hovered_offset - hint_range.start).0;
-        let mut part_start = hint_range.start;
-        for part in label_parts {
-            let part_len = part.value.chars().count();
-            if hovered_character >= part_len {
-                hovered_character -= part_len;
-                part_start.0 += part_len;
-            } else {
-                return Some((part, part_start..InlayOffset(part_start.0 + part_len)));
-            }
-        }
-    }
-    None
-}
-
 struct HighlightedChunk<'a> {
     chunk: &'a str,
     style: Option<HighlightStyle>,
@@ -2871,12 +2663,12 @@ struct PositionMap {
     snapshot: EditorSnapshot,
 }
 
-#[derive(Debug)]
+#[derive(Debug, Copy, Clone)]
 pub struct PointForPosition {
-    previous_valid: DisplayPoint,
+    pub previous_valid: DisplayPoint,
     pub next_valid: DisplayPoint,
-    exact_unclipped: DisplayPoint,
-    column_overshoot_after_line_end: u32,
+    pub exact_unclipped: DisplayPoint,
+    pub column_overshoot_after_line_end: u32,
 }
 
 impl PointForPosition {

crates/editor/src/hover_popover.rs 🔗

@@ -13,7 +13,7 @@ use gpui::{
     AnyElement, AppContext, CursorRegion, Element, ModelHandle, MouseRegion, Task, ViewContext,
 };
 use language::{Bias, DiagnosticEntry, DiagnosticSeverity, Language, LanguageRegistry};
-use project::{HoverBlock, HoverBlockKind, Project};
+use project::{HoverBlock, HoverBlockKind, InlayHintLabelPart, Project};
 use std::{ops::Range, sync::Arc, time::Duration};
 use util::TryFutureExt;
 
@@ -55,6 +55,27 @@ pub struct InlayHover {
     pub tooltip: HoverBlock,
 }
 
+pub fn find_hovered_hint_part(
+    label_parts: Vec<InlayHintLabelPart>,
+    hint_range: Range<InlayOffset>,
+    hovered_offset: InlayOffset,
+) -> Option<(InlayHintLabelPart, Range<InlayOffset>)> {
+    if hovered_offset >= hint_range.start && hovered_offset <= hint_range.end {
+        let mut hovered_character = (hovered_offset - hint_range.start).0;
+        let mut part_start = hint_range.start;
+        for part in label_parts {
+            let part_len = part.value.chars().count();
+            if hovered_character >= part_len {
+                hovered_character -= part_len;
+                part_start.0 += part_len;
+            } else {
+                return Some((part, part_start..InlayOffset(part_start.0 + part_len)));
+            }
+        }
+    }
+    None
+}
+
 pub fn hover_at_inlay(editor: &mut Editor, inlay_hover: InlayHover, cx: &mut ViewContext<Editor>) {
     if settings::get::<EditorSettings>(cx).hover_popover_enabled {
         if editor.pending_rename.is_some() {

crates/editor/src/inlay_hint_cache.rs 🔗

@@ -904,7 +904,7 @@ fn apply_hint_update(
 }
 
 #[cfg(test)]
-mod tests {
+pub mod tests {
     use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
 
     use crate::{
@@ -2989,15 +2989,11 @@ all hints should be invalidated and requeried for all of its visible excerpts"
         ("/a/main.rs", editor, fake_server)
     }
 
-    fn cached_hint_labels(editor: &Editor) -> Vec<String> {
+    pub fn cached_hint_labels(editor: &Editor) -> Vec<String> {
         let mut labels = Vec::new();
         for (_, excerpt_hints) in &editor.inlay_hint_cache().hints {
-            let excerpt_hints = excerpt_hints.read();
-            for (_, inlay) in excerpt_hints.hints.iter() {
-                match &inlay.label {
-                    project::InlayHintLabel::String(s) => labels.push(s.to_string()),
-                    _ => unreachable!(),
-                }
+            for (_, inlay) in &excerpt_hints.read().hints {
+                labels.push(inlay.text());
             }
         }
 
@@ -3005,7 +3001,7 @@ all hints should be invalidated and requeried for all of its visible excerpts"
         labels
     }
 
-    fn visible_hint_labels(editor: &Editor, cx: &ViewContext<'_, '_, Editor>) -> Vec<String> {
+    pub fn visible_hint_labels(editor: &Editor, cx: &ViewContext<'_, '_, Editor>) -> Vec<String> {
         let mut hints = editor
             .visible_inlay_hints(cx)
             .into_iter()
@@ -1,10 +1,15 @@
 use crate::{
-    display_map::InlayOffset, element::PointForPosition, Anchor, DisplayPoint, Editor,
-    EditorSnapshot, SelectPhase,
+    display_map::{DisplaySnapshot, InlayOffset},
+    element::PointForPosition,
+    hover_popover::{self, InlayHover},
+    Anchor, DisplayPoint, Editor, EditorSnapshot, SelectPhase,
 };
 use gpui::{Task, ViewContext};
 use language::{Bias, ToOffset};
-use project::LocationLink;
+use project::{
+    HoverBlock, HoverBlockKind, InlayHintLabelPartTooltip, InlayHintTooltip, Location,
+    LocationLink, ResolveState,
+};
 use std::ops::Range;
 use util::TryFutureExt;
 
@@ -23,7 +28,7 @@ pub enum GoToDefinitionTrigger {
     None,
 }
 
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub struct InlayRange {
     pub inlay_position: Anchor,
     pub highlight_start: InlayOffset,
@@ -140,6 +145,192 @@ pub fn update_go_to_definition_link(
     hide_link_definition(editor, cx);
 }
 
+pub fn update_inlay_link_and_hover_points(
+    snapshot: &DisplaySnapshot,
+    point_for_position: PointForPosition,
+    editor: &mut Editor,
+    cmd_held: bool,
+    shift_held: bool,
+    cx: &mut ViewContext<'_, '_, Editor>,
+) {
+    let hint_start_offset =
+        snapshot.display_point_to_inlay_offset(point_for_position.previous_valid, Bias::Left);
+    let hint_end_offset =
+        snapshot.display_point_to_inlay_offset(point_for_position.next_valid, Bias::Right);
+    let offset_overshoot = point_for_position.column_overshoot_after_line_end as usize;
+    let hovered_offset = if offset_overshoot == 0 {
+        Some(snapshot.display_point_to_inlay_offset(point_for_position.exact_unclipped, Bias::Left))
+    } else if (hint_end_offset - hint_start_offset).0 >= offset_overshoot {
+        Some(InlayOffset(hint_start_offset.0 + offset_overshoot))
+    } else {
+        None
+    };
+    if let Some(hovered_offset) = hovered_offset {
+        let buffer_snapshot = editor.buffer().read(cx).snapshot(cx);
+        let previous_valid_anchor = buffer_snapshot.anchor_at(
+            point_for_position.previous_valid.to_point(snapshot),
+            Bias::Left,
+        );
+        let next_valid_anchor = buffer_snapshot.anchor_at(
+            point_for_position.next_valid.to_point(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()
+            .skip_while(|hint| {
+                hint.position
+                    .cmp(&previous_valid_anchor, &buffer_snapshot)
+                    .is_lt()
+            })
+            .take_while(|hint| {
+                hint.position
+                    .cmp(&next_valid_anchor, &buffer_snapshot)
+                    .is_le()
+            })
+            .max_by_key(|hint| hint.id)
+        {
+            let inlay_hint_cache = editor.inlay_hint_cache();
+            let excerpt_id = previous_valid_anchor.excerpt_id;
+            if let Some(cached_hint) = inlay_hint_cache.hint_by_id(excerpt_id, hovered_hint.id) {
+                match cached_hint.resolve_state {
+                    ResolveState::CanResolve(_, _) => {
+                        if let Some(buffer_id) = previous_valid_anchor.buffer_id {
+                            inlay_hint_cache.spawn_hint_resolve(
+                                buffer_id,
+                                excerpt_id,
+                                hovered_hint.id,
+                                cx,
+                            );
+                        }
+                    }
+                    ResolveState::Resolved => {
+                        match cached_hint.label {
+                            project::InlayHintLabel::String(_) => {
+                                if let Some(tooltip) = cached_hint.tooltip {
+                                    hover_popover::hover_at_inlay(
+                                        editor,
+                                        InlayHover {
+                                            excerpt: excerpt_id,
+                                            tooltip: match tooltip {
+                                                InlayHintTooltip::String(text) => HoverBlock {
+                                                    text,
+                                                    kind: HoverBlockKind::PlainText,
+                                                },
+                                                InlayHintTooltip::MarkupContent(content) => {
+                                                    HoverBlock {
+                                                        text: content.value,
+                                                        kind: content.kind,
+                                                    }
+                                                }
+                                            },
+                                            triggered_from: hovered_offset,
+                                            range: InlayRange {
+                                                inlay_position: hovered_hint.position,
+                                                highlight_start: hint_start_offset,
+                                                highlight_end: hint_end_offset,
+                                            },
+                                        },
+                                        cx,
+                                    );
+                                    hover_updated = true;
+                                }
+                            }
+                            project::InlayHintLabel::LabelParts(label_parts) => {
+                                if let Some((hovered_hint_part, part_range)) =
+                                    hover_popover::find_hovered_hint_part(
+                                        label_parts,
+                                        hint_start_offset..hint_end_offset,
+                                        hovered_offset,
+                                    )
+                                {
+                                    if let Some(tooltip) = hovered_hint_part.tooltip {
+                                        hover_popover::hover_at_inlay(
+                                            editor,
+                                            InlayHover {
+                                                excerpt: excerpt_id,
+                                                tooltip: match tooltip {
+                                                    InlayHintLabelPartTooltip::String(text) => {
+                                                        HoverBlock {
+                                                            text,
+                                                            kind: HoverBlockKind::PlainText,
+                                                        }
+                                                    }
+                                                    InlayHintLabelPartTooltip::MarkupContent(
+                                                        content,
+                                                    ) => HoverBlock {
+                                                        text: content.value,
+                                                        kind: content.kind,
+                                                    },
+                                                },
+                                                triggered_from: hovered_offset,
+                                                range: InlayRange {
+                                                    inlay_position: hovered_hint.position,
+                                                    highlight_start: part_range.start,
+                                                    highlight_end: part_range.end,
+                                                },
+                                            },
+                                            cx,
+                                        );
+                                        hover_updated = true;
+                                    }
+                                    if let Some(location) = hovered_hint_part.location {
+                                        if let Some(buffer) =
+                                            cached_hint.position.buffer_id.and_then(|buffer_id| {
+                                                editor.buffer().read(cx).buffer(buffer_id)
+                                            })
+                                        {
+                                            go_to_definition_updated = true;
+                                            update_go_to_definition_link(
+                                                editor,
+                                                GoToDefinitionTrigger::InlayHint(
+                                                    InlayRange {
+                                                        inlay_position: hovered_hint.position,
+                                                        highlight_start: part_range.start,
+                                                        highlight_end: part_range.end,
+                                                    },
+                                                    LocationLink {
+                                                        origin: Some(Location {
+                                                            buffer,
+                                                            range: cached_hint.position
+                                                                ..cached_hint.position,
+                                                        }),
+                                                        target: location,
+                                                    },
+                                                ),
+                                                cmd_held,
+                                                shift_held,
+                                                cx,
+                                            );
+                                        }
+                                    }
+                                }
+                            }
+                        };
+                    }
+                    ResolveState::Resolving => {}
+                }
+            }
+        }
+
+        if !go_to_definition_updated {
+            update_go_to_definition_link(
+                editor,
+                GoToDefinitionTrigger::None,
+                cmd_held,
+                shift_held,
+                cx,
+            );
+        }
+        if !hover_updated {
+            hover_popover::hover_at(editor, None, cx);
+        }
+    }
+}
+
 #[derive(Debug, Clone, Copy, PartialEq)]
 pub enum LinkDefinitionKind {
     Symbol,
@@ -391,14 +582,21 @@ fn go_to_fetched_definition_of_kind(
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::{editor_tests::init_test, test::editor_lsp_test_context::EditorLspTestContext};
+    use crate::{
+        display_map::ToDisplayPoint,
+        editor_tests::init_test,
+        inlay_hint_cache::tests::{cached_hint_labels, visible_hint_labels},
+        test::editor_lsp_test_context::EditorLspTestContext,
+    };
     use futures::StreamExt;
     use gpui::{
         platform::{self, Modifiers, ModifiersChangedEvent},
         View,
     };
     use indoc::indoc;
+    use language::language_settings::InlayHintSettings;
     use lsp::request::{GotoDefinition, GotoTypeDefinition};
+    use util::assert_set_eq;
 
     #[gpui::test]
     async fn test_link_go_to_type_definition(cx: &mut gpui::TestAppContext) {
@@ -853,4 +1051,209 @@ mod tests {
         "});
         cx.foreground().run_until_parked();
     }
+
+    #[gpui::test]
+    async fn test_link_go_to_inlay(cx: &mut gpui::TestAppContext) {
+        init_test(cx, |settings| {
+            settings.defaults.inlay_hints = Some(InlayHintSettings {
+                enabled: true,
+                show_type_hints: true,
+                show_parameter_hints: true,
+                show_other_hints: true,
+            })
+        });
+
+        let mut cx = EditorLspTestContext::new_rust(
+            lsp::ServerCapabilities {
+                inlay_hint_provider: Some(lsp::OneOf::Left(true)),
+                ..Default::default()
+            },
+            cx,
+        )
+        .await;
+        cx.set_state(indoc! {"
+            struct TestStruct;
+
+            fn main() {
+                let variableˇ = TestStruct;
+            }
+        "});
+        let hint_start_offset = cx.ranges(indoc! {"
+            struct TestStruct;
+
+            fn main() {
+                let variableˇ = TestStruct;
+            }
+        "})[0]
+            .start;
+        let hint_position = cx.to_lsp(hint_start_offset);
+        let target_range = cx.lsp_range(indoc! {"
+            struct «TestStruct»;
+
+            fn main() {
+                let variable = TestStruct;
+            }
+        "});
+
+        let expected_uri = cx.buffer_lsp_url.clone();
+        let inlay_label = ": TestStruct";
+        cx.lsp
+            .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
+                let expected_uri = expected_uri.clone();
+                async move {
+                    assert_eq!(params.text_document.uri, expected_uri);
+                    Ok(Some(vec![lsp::InlayHint {
+                        position: hint_position,
+                        label: lsp::InlayHintLabel::LabelParts(vec![lsp::InlayHintLabelPart {
+                            value: inlay_label.to_string(),
+                            location: Some(lsp::Location {
+                                uri: params.text_document.uri,
+                                range: target_range,
+                            }),
+                            ..Default::default()
+                        }]),
+                        kind: Some(lsp::InlayHintKind::TYPE),
+                        text_edits: None,
+                        tooltip: None,
+                        padding_left: Some(false),
+                        padding_right: Some(false),
+                        data: None,
+                    }]))
+                }
+            })
+            .next()
+            .await;
+        cx.foreground().run_until_parked();
+        cx.update_editor(|editor, cx| {
+            let expected_layers = vec![inlay_label.to_string()];
+            assert_eq!(expected_layers, cached_hint_labels(editor));
+            assert_eq!(expected_layers, visible_hint_labels(editor, cx));
+        });
+
+        let inlay_range = cx
+            .ranges(indoc! {"
+            struct TestStruct;
+
+            fn main() {
+                let variable« »= TestStruct;
+            }
+        "})
+            .get(0)
+            .cloned()
+            .unwrap();
+        let hint_hover_position = cx.update_editor(|editor, cx| {
+            let snapshot = editor.snapshot(cx);
+            PointForPosition {
+                previous_valid: inlay_range.start.to_display_point(&snapshot),
+                next_valid: inlay_range.end.to_display_point(&snapshot),
+                exact_unclipped: inlay_range.end.to_display_point(&snapshot),
+                column_overshoot_after_line_end: (inlay_label.len() / 2) as u32,
+            }
+        });
+        // Press cmd to trigger highlight
+        cx.update_editor(|editor, cx| {
+            update_inlay_link_and_hover_points(
+                &editor.snapshot(cx),
+                hint_hover_position,
+                editor,
+                true,
+                false,
+                cx,
+            );
+        });
+        cx.foreground().run_until_parked();
+        cx.update_editor(|editor, cx| {
+            let snapshot = editor.snapshot(cx);
+            let actual_ranges = snapshot
+                .highlight_ranges::<LinkGoToDefinitionState>()
+                .map(|ranges| ranges.as_ref().clone().1)
+                .unwrap_or_default()
+                .into_iter()
+                .map(|range| match range {
+                    DocumentRange::Text(range) => {
+                        panic!("Unexpected regular text selection range {range:?}")
+                    }
+                    DocumentRange::Inlay(inlay_range) => inlay_range,
+                })
+                .collect::<Vec<_>>();
+
+            let buffer_snapshot = editor.buffer().update(cx, |buffer, cx| buffer.snapshot(cx));
+            let expected_highlight_start = snapshot.display_point_to_inlay_offset(
+                inlay_range.start.to_display_point(&snapshot),
+                Bias::Left,
+            );
+            let expected_ranges = vec![InlayRange {
+                inlay_position: buffer_snapshot.anchor_at(inlay_range.start, Bias::Right),
+                highlight_start: expected_highlight_start,
+                highlight_end: InlayOffset(expected_highlight_start.0 + inlay_label.len()),
+            }];
+            assert_set_eq!(actual_ranges, expected_ranges);
+        });
+
+        // Unpress cmd causes highlight to go away
+        cx.update_editor(|editor, cx| {
+            editor.modifiers_changed(
+                &platform::ModifiersChangedEvent {
+                    modifiers: Modifiers {
+                        cmd: false,
+                        ..Default::default()
+                    },
+                    ..Default::default()
+                },
+                cx,
+            );
+        });
+        // Assert no link highlights
+        cx.update_editor(|editor, cx| {
+            let snapshot = editor.snapshot(cx);
+            let actual_ranges = snapshot
+                .highlight_ranges::<LinkGoToDefinitionState>()
+                .map(|ranges| ranges.as_ref().clone().1)
+                .unwrap_or_default()
+                .into_iter()
+                .map(|range| match range {
+                    DocumentRange::Text(range) => {
+                        panic!("Unexpected regular text selection range {range:?}")
+                    }
+                    DocumentRange::Inlay(inlay_range) => inlay_range,
+                })
+                .collect::<Vec<_>>();
+
+            assert!(actual_ranges.is_empty(), "When no cmd is pressed, should have no hint label selected, but got: {actual_ranges:?}");
+        });
+
+        // Cmd+click without existing definition requests and jumps
+        cx.update_editor(|editor, cx| {
+            editor.modifiers_changed(
+                &platform::ModifiersChangedEvent {
+                    modifiers: Modifiers {
+                        cmd: true,
+                        ..Default::default()
+                    },
+                    ..Default::default()
+                },
+                cx,
+            );
+            update_inlay_link_and_hover_points(
+                &editor.snapshot(cx),
+                hint_hover_position,
+                editor,
+                true,
+                false,
+                cx,
+            );
+        });
+        cx.foreground().run_until_parked();
+        cx.update_editor(|editor, cx| {
+            go_to_fetched_type_definition(editor, hint_hover_position, false, cx);
+        });
+        cx.foreground().run_until_parked();
+        cx.assert_editor_state(indoc! {"
+            struct «TestStructˇ»;
+
+            fn main() {
+                let variable = TestStruct;
+            }
+        "});
+    }
 }