Uncomment a bunch of tests in the editor

Piotr Osiewicz created

Change summary

crates/editor2/src/editor_tests.rs          |    1 
crates/editor2/src/element.rs               |    2 
crates/editor2/src/git.rs                   |  364 +++---
crates/editor2/src/link_go_to_definition.rs | 1337 +++++++++++-----------
4 files changed, 852 insertions(+), 852 deletions(-)

Detailed changes

crates/editor2/src/editor_tests.rs 🔗

@@ -6325,7 +6325,6 @@ async fn test_extra_newline_insertion(cx: &mut gpui::TestAppContext) {
     });
 }
 
-//todo!(finish editor tests)
 // #[gpui::test]
 // fn test_highlighted_ranges(cx: &mut TestAppContext) {
 //     init_test(cx, |_| {});

crates/editor2/src/element.rs 🔗

@@ -328,7 +328,7 @@ impl EditorElement {
         });
     }
 
-    fn modifiers_changed(
+    pub(crate) fn modifiers_changed(
         editor: &mut Editor,
         event: &ModifiersChangedEvent,
         cx: &mut ViewContext<Editor>,

crates/editor2/src/git.rs 🔗

@@ -88,195 +88,195 @@ pub fn diff_hunk_to_display(hunk: DiffHunk<u32>, snapshot: &DisplaySnapshot) ->
     }
 }
 
-// #[cfg(any(test, feature = "test_support"))]
-// mod tests {
-//     // use crate::editor_tests::init_test;
-//     use crate::Point;
-//     use gpui::TestAppContext;
-//     use multi_buffer::{ExcerptRange, MultiBuffer};
-//     use project::{FakeFs, Project};
-//     use unindent::Unindent;
-//     #[gpui::test]
-//     async fn test_diff_hunks_in_range(cx: &mut TestAppContext) {
-//         use git::diff::DiffHunkStatus;
-//         init_test(cx, |_| {});
+#[cfg(any(test, feature = "test_support"))]
+mod tests {
+    use crate::editor_tests::init_test;
+    use crate::Point;
+    use gpui::{Context, TestAppContext};
+    use multi_buffer::{ExcerptRange, MultiBuffer};
+    use project::{FakeFs, Project};
+    use unindent::Unindent;
+    #[gpui::test]
+    async fn test_diff_hunks_in_range(cx: &mut TestAppContext) {
+        use git::diff::DiffHunkStatus;
+        init_test(cx, |_| {});
 
-//         let fs = FakeFs::new(cx.background());
-//         let project = Project::test(fs, [], cx).await;
+        let fs = FakeFs::new(cx.background_executor.clone());
+        let project = Project::test(fs, [], cx).await;
 
-//         // buffer has two modified hunks with two rows each
-//         let buffer_1 = project
-//             .update(cx, |project, cx| {
-//                 project.create_buffer(
-//                     "
-//                         1.zero
-//                         1.ONE
-//                         1.TWO
-//                         1.three
-//                         1.FOUR
-//                         1.FIVE
-//                         1.six
-//                     "
-//                     .unindent()
-//                     .as_str(),
-//                     None,
-//                     cx,
-//                 )
-//             })
-//             .unwrap();
-//         buffer_1.update(cx, |buffer, cx| {
-//             buffer.set_diff_base(
-//                 Some(
-//                     "
-//                         1.zero
-//                         1.one
-//                         1.two
-//                         1.three
-//                         1.four
-//                         1.five
-//                         1.six
-//                     "
-//                     .unindent(),
-//                 ),
-//                 cx,
-//             );
-//         });
+        // buffer has two modified hunks with two rows each
+        let buffer_1 = project
+            .update(cx, |project, cx| {
+                project.create_buffer(
+                    "
+                        1.zero
+                        1.ONE
+                        1.TWO
+                        1.three
+                        1.FOUR
+                        1.FIVE
+                        1.six
+                    "
+                    .unindent()
+                    .as_str(),
+                    None,
+                    cx,
+                )
+            })
+            .unwrap();
+        buffer_1.update(cx, |buffer, cx| {
+            buffer.set_diff_base(
+                Some(
+                    "
+                        1.zero
+                        1.one
+                        1.two
+                        1.three
+                        1.four
+                        1.five
+                        1.six
+                    "
+                    .unindent(),
+                ),
+                cx,
+            );
+        });
 
-//         // buffer has a deletion hunk and an insertion hunk
-//         let buffer_2 = project
-//             .update(cx, |project, cx| {
-//                 project.create_buffer(
-//                     "
-//                         2.zero
-//                         2.one
-//                         2.two
-//                         2.three
-//                         2.four
-//                         2.five
-//                         2.six
-//                     "
-//                     .unindent()
-//                     .as_str(),
-//                     None,
-//                     cx,
-//                 )
-//             })
-//             .unwrap();
-//         buffer_2.update(cx, |buffer, cx| {
-//             buffer.set_diff_base(
-//                 Some(
-//                     "
-//                         2.zero
-//                         2.one
-//                         2.one-and-a-half
-//                         2.two
-//                         2.three
-//                         2.four
-//                         2.six
-//                     "
-//                     .unindent(),
-//                 ),
-//                 cx,
-//             );
-//         });
+        // buffer has a deletion hunk and an insertion hunk
+        let buffer_2 = project
+            .update(cx, |project, cx| {
+                project.create_buffer(
+                    "
+                        2.zero
+                        2.one
+                        2.two
+                        2.three
+                        2.four
+                        2.five
+                        2.six
+                    "
+                    .unindent()
+                    .as_str(),
+                    None,
+                    cx,
+                )
+            })
+            .unwrap();
+        buffer_2.update(cx, |buffer, cx| {
+            buffer.set_diff_base(
+                Some(
+                    "
+                        2.zero
+                        2.one
+                        2.one-and-a-half
+                        2.two
+                        2.three
+                        2.four
+                        2.six
+                    "
+                    .unindent(),
+                ),
+                cx,
+            );
+        });
 
-//         cx.foreground().run_until_parked();
+        cx.background_executor.run_until_parked();
 
-//         let multibuffer = cx.add_model(|cx| {
-//             let mut multibuffer = MultiBuffer::new(0);
-//             multibuffer.push_excerpts(
-//                 buffer_1.clone(),
-//                 [
-//                     // excerpt ends in the middle of a modified hunk
-//                     ExcerptRange {
-//                         context: Point::new(0, 0)..Point::new(1, 5),
-//                         primary: Default::default(),
-//                     },
-//                     // excerpt begins in the middle of a modified hunk
-//                     ExcerptRange {
-//                         context: Point::new(5, 0)..Point::new(6, 5),
-//                         primary: Default::default(),
-//                     },
-//                 ],
-//                 cx,
-//             );
-//             multibuffer.push_excerpts(
-//                 buffer_2.clone(),
-//                 [
-//                     // excerpt ends at a deletion
-//                     ExcerptRange {
-//                         context: Point::new(0, 0)..Point::new(1, 5),
-//                         primary: Default::default(),
-//                     },
-//                     // excerpt starts at a deletion
-//                     ExcerptRange {
-//                         context: Point::new(2, 0)..Point::new(2, 5),
-//                         primary: Default::default(),
-//                     },
-//                     // excerpt fully contains a deletion hunk
-//                     ExcerptRange {
-//                         context: Point::new(1, 0)..Point::new(2, 5),
-//                         primary: Default::default(),
-//                     },
-//                     // excerpt fully contains an insertion hunk
-//                     ExcerptRange {
-//                         context: Point::new(4, 0)..Point::new(6, 5),
-//                         primary: Default::default(),
-//                     },
-//                 ],
-//                 cx,
-//             );
-//             multibuffer
-//         });
+        let multibuffer = cx.build_model(|cx| {
+            let mut multibuffer = MultiBuffer::new(0);
+            multibuffer.push_excerpts(
+                buffer_1.clone(),
+                [
+                    // excerpt ends in the middle of a modified hunk
+                    ExcerptRange {
+                        context: Point::new(0, 0)..Point::new(1, 5),
+                        primary: Default::default(),
+                    },
+                    // excerpt begins in the middle of a modified hunk
+                    ExcerptRange {
+                        context: Point::new(5, 0)..Point::new(6, 5),
+                        primary: Default::default(),
+                    },
+                ],
+                cx,
+            );
+            multibuffer.push_excerpts(
+                buffer_2.clone(),
+                [
+                    // excerpt ends at a deletion
+                    ExcerptRange {
+                        context: Point::new(0, 0)..Point::new(1, 5),
+                        primary: Default::default(),
+                    },
+                    // excerpt starts at a deletion
+                    ExcerptRange {
+                        context: Point::new(2, 0)..Point::new(2, 5),
+                        primary: Default::default(),
+                    },
+                    // excerpt fully contains a deletion hunk
+                    ExcerptRange {
+                        context: Point::new(1, 0)..Point::new(2, 5),
+                        primary: Default::default(),
+                    },
+                    // excerpt fully contains an insertion hunk
+                    ExcerptRange {
+                        context: Point::new(4, 0)..Point::new(6, 5),
+                        primary: Default::default(),
+                    },
+                ],
+                cx,
+            );
+            multibuffer
+        });
 
-//         let snapshot = multibuffer.read_with(cx, |b, cx| b.snapshot(cx));
+        let snapshot = multibuffer.read_with(cx, |b, cx| b.snapshot(cx));
 
-//         assert_eq!(
-//             snapshot.text(),
-//             "
-//                 1.zero
-//                 1.ONE
-//                 1.FIVE
-//                 1.six
-//                 2.zero
-//                 2.one
-//                 2.two
-//                 2.one
-//                 2.two
-//                 2.four
-//                 2.five
-//                 2.six"
-//                 .unindent()
-//         );
+        assert_eq!(
+            snapshot.text(),
+            "
+                1.zero
+                1.ONE
+                1.FIVE
+                1.six
+                2.zero
+                2.one
+                2.two
+                2.one
+                2.two
+                2.four
+                2.five
+                2.six"
+                .unindent()
+        );
 
-//         let expected = [
-//             (DiffHunkStatus::Modified, 1..2),
-//             (DiffHunkStatus::Modified, 2..3),
-//             //TODO: Define better when and where removed hunks show up at range extremities
-//             (DiffHunkStatus::Removed, 6..6),
-//             (DiffHunkStatus::Removed, 8..8),
-//             (DiffHunkStatus::Added, 10..11),
-//         ];
+        let expected = [
+            (DiffHunkStatus::Modified, 1..2),
+            (DiffHunkStatus::Modified, 2..3),
+            //TODO: Define better when and where removed hunks show up at range extremities
+            (DiffHunkStatus::Removed, 6..6),
+            (DiffHunkStatus::Removed, 8..8),
+            (DiffHunkStatus::Added, 10..11),
+        ];
 
-//         assert_eq!(
-//             snapshot
-//                 .git_diff_hunks_in_range(0..12)
-//                 .map(|hunk| (hunk.status(), hunk.buffer_range))
-//                 .collect::<Vec<_>>(),
-//             &expected,
-//         );
+        assert_eq!(
+            snapshot
+                .git_diff_hunks_in_range(0..12)
+                .map(|hunk| (hunk.status(), hunk.buffer_range))
+                .collect::<Vec<_>>(),
+            &expected,
+        );
 
-//         assert_eq!(
-//             snapshot
-//                 .git_diff_hunks_in_range_rev(0..12)
-//                 .map(|hunk| (hunk.status(), hunk.buffer_range))
-//                 .collect::<Vec<_>>(),
-//             expected
-//                 .iter()
-//                 .rev()
-//                 .cloned()
-//                 .collect::<Vec<_>>()
-//                 .as_slice(),
-//         );
-//     }
-// }
+        assert_eq!(
+            snapshot
+                .git_diff_hunks_in_range_rev(0..12)
+                .map(|hunk| (hunk.status(), hunk.buffer_range))
+                .collect::<Vec<_>>(),
+            expected
+                .iter()
+                .rev()
+                .cloned()
+                .collect::<Vec<_>>()
+                .as_slice(),
+        );
+    }
+}
@@ -608,671 +608,672 @@ fn go_to_fetched_definition_of_kind(
     }
 }
 
-// #[cfg(test)]
-// mod tests {
-//     use super::*;
-//     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) {
-//         init_test(cx, |_| {});
-
-//         let mut cx = EditorLspTestContext::new_rust(
-//             lsp::ServerCapabilities {
-//                 hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
-//                 type_definition_provider: Some(lsp::TypeDefinitionProviderCapability::Simple(true)),
-//                 ..Default::default()
-//             },
-//             cx,
-//         )
-//         .await;
-
-//         cx.set_state(indoc! {"
-//             struct A;
-//             let vˇariable = A;
-//         "});
-
-//         // Basic hold cmd+shift, expect highlight in region if response contains type definition
-//         let hover_point = cx.display_point(indoc! {"
-//             struct A;
-//             let vˇariable = A;
-//         "});
-//         let symbol_range = cx.lsp_range(indoc! {"
-//             struct A;
-//             let «variable» = A;
-//         "});
-//         let target_range = cx.lsp_range(indoc! {"
-//             struct «A»;
-//             let variable = A;
-//         "});
-
-//         let mut requests =
-//             cx.handle_request::<GotoTypeDefinition, _, _>(move |url, _, _| async move {
-//                 Ok(Some(lsp::GotoTypeDefinitionResponse::Link(vec![
-//                     lsp::LocationLink {
-//                         origin_selection_range: Some(symbol_range),
-//                         target_uri: url.clone(),
-//                         target_range,
-//                         target_selection_range: target_range,
-//                     },
-//                 ])))
-//             });
-
-//         // Press cmd+shift to trigger highlight
-//         cx.update_editor(|editor, cx| {
-//             update_go_to_definition_link(
-//                 editor,
-//                 Some(GoToDefinitionTrigger::Text(hover_point)),
-//                 true,
-//                 true,
-//                 cx,
-//             );
-//         });
-//         requests.next().await;
-//         cx.foreground().run_until_parked();
-//         cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
-//             struct A;
-//             let «variable» = A;
-//         "});
-
-//         // Unpress shift causes highlight to go away (normal goto-definition is not valid here)
-//         cx.update_editor(|editor, cx| {
-//             editor.modifiers_changed(
-//                 &platform::ModifiersChangedEvent {
-//                     modifiers: Modifiers {
-//                         cmd: true,
-//                         ..Default::default()
-//                     },
-//                     ..Default::default()
-//                 },
-//                 cx,
-//             );
-//         });
-//         // Assert no link highlights
-//         cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
-//             struct A;
-//             let variable = A;
-//         "});
-
-//         // Cmd+shift click without existing definition requests and jumps
-//         let hover_point = cx.display_point(indoc! {"
-//             struct A;
-//             let vˇariable = A;
-//         "});
-//         let target_range = cx.lsp_range(indoc! {"
-//             struct «A»;
-//             let variable = A;
-//         "});
-
-//         let mut requests =
-//             cx.handle_request::<GotoTypeDefinition, _, _>(move |url, _, _| async move {
-//                 Ok(Some(lsp::GotoTypeDefinitionResponse::Link(vec![
-//                     lsp::LocationLink {
-//                         origin_selection_range: None,
-//                         target_uri: url,
-//                         target_range,
-//                         target_selection_range: target_range,
-//                     },
-//                 ])))
-//             });
-
-//         cx.update_editor(|editor, cx| {
-//             go_to_fetched_type_definition(editor, PointForPosition::valid(hover_point), false, cx);
-//         });
-//         requests.next().await;
-//         cx.foreground().run_until_parked();
-
-//         cx.assert_editor_state(indoc! {"
-//             struct «Aˇ»;
-//             let variable = A;
-//         "});
-//     }
-
-//     #[gpui::test]
-//     async fn test_link_go_to_definition(cx: &mut gpui::TestAppContext) {
-//         init_test(cx, |_| {});
-
-//         let mut cx = EditorLspTestContext::new_rust(
-//             lsp::ServerCapabilities {
-//                 hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
-//                 ..Default::default()
-//             },
-//             cx,
-//         )
-//         .await;
-
-//         cx.set_state(indoc! {"
-//             fn ˇtest() { do_work(); }
-//             fn do_work() { test(); }
-//         "});
-
-//         // Basic hold cmd, expect highlight in region if response contains definition
-//         let hover_point = cx.display_point(indoc! {"
-//             fn test() { do_wˇork(); }
-//             fn do_work() { test(); }
-//         "});
-//         let symbol_range = cx.lsp_range(indoc! {"
-//             fn test() { «do_work»(); }
-//             fn do_work() { test(); }
-//         "});
-//         let target_range = cx.lsp_range(indoc! {"
-//             fn test() { do_work(); }
-//             fn «do_work»() { test(); }
-//         "});
-
-//         let mut requests = cx.handle_request::<GotoDefinition, _, _>(move |url, _, _| async move {
-//             Ok(Some(lsp::GotoDefinitionResponse::Link(vec![
-//                 lsp::LocationLink {
-//                     origin_selection_range: Some(symbol_range),
-//                     target_uri: url.clone(),
-//                     target_range,
-//                     target_selection_range: target_range,
-//                 },
-//             ])))
-//         });
-
-//         cx.update_editor(|editor, cx| {
-//             update_go_to_definition_link(
-//                 editor,
-//                 Some(GoToDefinitionTrigger::Text(hover_point)),
-//                 true,
-//                 false,
-//                 cx,
-//             );
-//         });
-//         requests.next().await;
-//         cx.foreground().run_until_parked();
-//         cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
-//             fn test() { «do_work»(); }
-//             fn do_work() { test(); }
-//         "});
-
-//         // Unpress cmd causes highlight to go away
-//         cx.update_editor(|editor, cx| {
-//             editor.modifiers_changed(&Default::default(), cx);
-//         });
-
-//         // Assert no link highlights
-//         cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
-//             fn test() { do_work(); }
-//             fn do_work() { test(); }
-//         "});
-
-//         // Response without source range still highlights word
-//         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 {
-//                     // No origin range
-//                     origin_selection_range: None,
-//                     target_uri: url.clone(),
-//                     target_range,
-//                     target_selection_range: target_range,
-//                 },
-//             ])))
-//         });
-//         cx.update_editor(|editor, cx| {
-//             update_go_to_definition_link(
-//                 editor,
-//                 Some(GoToDefinitionTrigger::Text(hover_point)),
-//                 true,
-//                 false,
-//                 cx,
-//             );
-//         });
-//         requests.next().await;
-//         cx.foreground().run_until_parked();
-
-//         cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
-//             fn test() { «do_work»(); }
-//             fn do_work() { test(); }
-//         "});
-
-//         // Moving mouse to location with no response dismisses highlight
-//         let hover_point = cx.display_point(indoc! {"
-//             fˇn test() { do_work(); }
-//             fn do_work() { test(); }
-//         "});
-//         let mut requests = cx
-//             .lsp
-//             .handle_request::<GotoDefinition, _, _>(move |_, _| async move {
-//                 // No definitions returned
-//                 Ok(Some(lsp::GotoDefinitionResponse::Link(vec![])))
-//             });
-//         cx.update_editor(|editor, cx| {
-//             update_go_to_definition_link(
-//                 editor,
-//                 Some(GoToDefinitionTrigger::Text(hover_point)),
-//                 true,
-//                 false,
-//                 cx,
-//             );
-//         });
-//         requests.next().await;
-//         cx.foreground().run_until_parked();
-
-//         // Assert no link highlights
-//         cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
-//             fn test() { do_work(); }
-//             fn do_work() { test(); }
-//         "});
-
-//         // Move mouse without cmd and then pressing cmd triggers highlight
-//         let hover_point = cx.display_point(indoc! {"
-//             fn test() { do_work(); }
-//             fn do_work() { teˇst(); }
-//         "});
-//         cx.update_editor(|editor, cx| {
-//             update_go_to_definition_link(
-//                 editor,
-//                 Some(GoToDefinitionTrigger::Text(hover_point)),
-//                 false,
-//                 false,
-//                 cx,
-//             );
-//         });
-//         cx.foreground().run_until_parked();
-
-//         // Assert no link highlights
-//         cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
-//             fn test() { do_work(); }
-//             fn do_work() { test(); }
-//         "});
-
-//         let symbol_range = cx.lsp_range(indoc! {"
-//             fn test() { do_work(); }
-//             fn do_work() { «test»(); }
-//         "});
-//         let target_range = cx.lsp_range(indoc! {"
-//             fn «test»() { do_work(); }
-//             fn do_work() { test(); }
-//         "});
-
-//         let mut requests = cx.handle_request::<GotoDefinition, _, _>(move |url, _, _| async move {
-//             Ok(Some(lsp::GotoDefinitionResponse::Link(vec![
-//                 lsp::LocationLink {
-//                     origin_selection_range: Some(symbol_range),
-//                     target_uri: url,
-//                     target_range,
-//                     target_selection_range: target_range,
-//                 },
-//             ])))
-//         });
-//         cx.update_editor(|editor, cx| {
-//             editor.modifiers_changed(
-//                 &ModifiersChangedEvent {
-//                     modifiers: Modifiers {
-//                         cmd: true,
-//                         ..Default::default()
-//                     },
-//                 },
-//                 cx,
-//             );
-//         });
-//         requests.next().await;
-//         cx.foreground().run_until_parked();
-
-//         cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
-//             fn test() { do_work(); }
-//             fn do_work() { «test»(); }
-//         "});
-
-//         // Deactivating the window dismisses the highlight
-//         cx.update_workspace(|workspace, cx| {
-//             workspace.on_window_activation_changed(false, cx);
-//         });
-//         cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
-//             fn test() { do_work(); }
-//             fn do_work() { test(); }
-//         "});
-
-//         // Moving the mouse restores the highlights.
-//         cx.update_editor(|editor, cx| {
-//             update_go_to_definition_link(
-//                 editor,
-//                 Some(GoToDefinitionTrigger::Text(hover_point)),
-//                 true,
-//                 false,
-//                 cx,
-//             );
-//         });
-//         cx.foreground().run_until_parked();
-//         cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
-//             fn test() { do_work(); }
-//             fn do_work() { «test»(); }
-//         "});
-
-//         // Moving again within the same symbol range doesn't re-request
-//         let hover_point = cx.display_point(indoc! {"
-//             fn test() { do_work(); }
-//             fn do_work() { tesˇt(); }
-//         "});
-//         cx.update_editor(|editor, cx| {
-//             update_go_to_definition_link(
-//                 editor,
-//                 Some(GoToDefinitionTrigger::Text(hover_point)),
-//                 true,
-//                 false,
-//                 cx,
-//             );
-//         });
-//         cx.foreground().run_until_parked();
-//         cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
-//             fn test() { do_work(); }
-//             fn do_work() { «test»(); }
-//         "});
-
-//         // Cmd click with existing definition doesn't re-request and dismisses highlight
-//         cx.update_editor(|editor, cx| {
-//             go_to_fetched_definition(editor, PointForPosition::valid(hover_point), false, cx);
-//         });
-//         // Assert selection moved to to definition
-//         cx.lsp
-//             .handle_request::<GotoDefinition, _, _>(move |_, _| async move {
-//                 // Empty definition response to make sure we aren't hitting the lsp and using
-//                 // the cached location instead
-//                 Ok(Some(lsp::GotoDefinitionResponse::Link(vec![])))
-//             });
-//         cx.foreground().run_until_parked();
-//         cx.assert_editor_state(indoc! {"
-//             fn «testˇ»() { do_work(); }
-//             fn do_work() { test(); }
-//         "});
-
-//         // Assert no link highlights after jump
-//         cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
-//             fn test() { do_work(); }
-//             fn do_work() { test(); }
-//         "});
-
-//         // Cmd click without existing definition requests and jumps
-//         let hover_point = cx.display_point(indoc! {"
-//             fn test() { do_wˇork(); }
-//             fn do_work() { test(); }
-//         "});
-//         let target_range = cx.lsp_range(indoc! {"
-//             fn test() { do_work(); }
-//             fn «do_work»() { test(); }
-//         "});
-
-//         let mut requests = cx.handle_request::<GotoDefinition, _, _>(move |url, _, _| async move {
-//             Ok(Some(lsp::GotoDefinitionResponse::Link(vec![
-//                 lsp::LocationLink {
-//                     origin_selection_range: None,
-//                     target_uri: url,
-//                     target_range,
-//                     target_selection_range: target_range,
-//                 },
-//             ])))
-//         });
-//         cx.update_editor(|editor, cx| {
-//             go_to_fetched_definition(editor, PointForPosition::valid(hover_point), false, cx);
-//         });
-//         requests.next().await;
-//         cx.foreground().run_until_parked();
-//         cx.assert_editor_state(indoc! {"
-//             fn test() { do_work(); }
-//             fn «do_workˇ»() { test(); }
-//         "});
-
-//         // 1. We have a pending selection, mouse point is over a symbol that we have a response for, hitting cmd and nothing happens
-//         // 2. Selection is completed, hovering
-//         let hover_point = cx.display_point(indoc! {"
-//             fn test() { do_wˇork(); }
-//             fn do_work() { test(); }
-//         "});
-//         let target_range = cx.lsp_range(indoc! {"
-//             fn test() { do_work(); }
-//             fn «do_work»() { test(); }
-//         "});
-//         let mut requests = cx.handle_request::<GotoDefinition, _, _>(move |url, _, _| async move {
-//             Ok(Some(lsp::GotoDefinitionResponse::Link(vec![
-//                 lsp::LocationLink {
-//                     origin_selection_range: None,
-//                     target_uri: url,
-//                     target_range,
-//                     target_selection_range: target_range,
-//                 },
-//             ])))
-//         });
-
-//         // create a pending selection
-//         let selection_range = cx.ranges(indoc! {"
-//             fn «test() { do_w»ork(); }
-//             fn do_work() { test(); }
-//         "})[0]
-//             .clone();
-//         cx.update_editor(|editor, cx| {
-//             let snapshot = editor.buffer().read(cx).snapshot(cx);
-//             let anchor_range = snapshot.anchor_before(selection_range.start)
-//                 ..snapshot.anchor_after(selection_range.end);
-//             editor.change_selections(Some(crate::Autoscroll::fit()), cx, |s| {
-//                 s.set_pending_anchor_range(anchor_range, crate::SelectMode::Character)
-//             });
-//         });
-//         cx.update_editor(|editor, cx| {
-//             update_go_to_definition_link(
-//                 editor,
-//                 Some(GoToDefinitionTrigger::Text(hover_point)),
-//                 true,
-//                 false,
-//                 cx,
-//             );
-//         });
-//         cx.foreground().run_until_parked();
-//         assert!(requests.try_next().is_err());
-//         cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
-//             fn test() { do_work(); }
-//             fn do_work() { test(); }
-//         "});
-//         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 hint_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: hint_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![hint_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);
-//             let previous_valid = inlay_range.start.to_display_point(&snapshot);
-//             let next_valid = inlay_range.end.to_display_point(&snapshot);
-//             assert_eq!(previous_valid.row(), next_valid.row());
-//             assert!(previous_valid.column() < next_valid.column());
-//             let exact_unclipped = DisplayPoint::new(
-//                 previous_valid.row(),
-//                 previous_valid.column() + (hint_label.len() / 2) as u32,
-//             );
-//             PointForPosition {
-//                 previous_valid,
-//                 next_valid,
-//                 exact_unclipped,
-//                 column_overshoot_after_line_end: 0,
-//             }
-//         });
-//         // 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_highlights = snapshot
-//                 .inlay_highlights::<LinkGoToDefinitionState>()
-//                 .into_iter()
-//                 .flat_map(|highlights| highlights.values().map(|(_, highlight)| highlight))
-//                 .collect::<Vec<_>>();
-
-//             let buffer_snapshot = editor.buffer().update(cx, |buffer, cx| buffer.snapshot(cx));
-//             let expected_highlight = InlayHighlight {
-//                 inlay: InlayId::Hint(0),
-//                 inlay_position: buffer_snapshot.anchor_at(inlay_range.start, Bias::Right),
-//                 range: 0..hint_label.len(),
-//             };
-//             assert_set_eq!(actual_highlights, vec![&expected_highlight]);
-//         });
-
-//         // 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
-//                 .text_highlight_ranges::<LinkGoToDefinitionState>()
-//                 .map(|ranges| ranges.as_ref().clone().1)
-//                 .unwrap_or_default();
-
-//             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;
-//             }
-//         "});
-//     }
-// }
+#[cfg(test)]
+mod tests {
+    use super::*;
+    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::{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) {
+        init_test(cx, |_| {});
+
+        let mut cx = EditorLspTestContext::new_rust(
+            lsp::ServerCapabilities {
+                hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
+                type_definition_provider: Some(lsp::TypeDefinitionProviderCapability::Simple(true)),
+                ..Default::default()
+            },
+            cx,
+        )
+        .await;
+
+        cx.set_state(indoc! {"
+            struct A;
+            let vˇariable = A;
+        "});
+
+        // Basic hold cmd+shift, expect highlight in region if response contains type definition
+        let hover_point = cx.display_point(indoc! {"
+            struct A;
+            let vˇariable = A;
+        "});
+        let symbol_range = cx.lsp_range(indoc! {"
+            struct A;
+            let «variable» = A;
+        "});
+        let target_range = cx.lsp_range(indoc! {"
+            struct «A»;
+            let variable = A;
+        "});
+
+        let mut requests =
+            cx.handle_request::<GotoTypeDefinition, _, _>(move |url, _, _| async move {
+                Ok(Some(lsp::GotoTypeDefinitionResponse::Link(vec![
+                    lsp::LocationLink {
+                        origin_selection_range: Some(symbol_range),
+                        target_uri: url.clone(),
+                        target_range,
+                        target_selection_range: target_range,
+                    },
+                ])))
+            });
+
+        // Press cmd+shift to trigger highlight
+        cx.update_editor(|editor, cx| {
+            update_go_to_definition_link(
+                editor,
+                Some(GoToDefinitionTrigger::Text(hover_point)),
+                true,
+                true,
+                cx,
+            );
+        });
+        requests.next().await;
+        cx.background_executor.run_until_parked();
+        cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
+            struct A;
+            let «variable» = A;
+        "});
+
+        // Unpress shift causes highlight to go away (normal goto-definition is not valid here)
+        cx.update_editor(|editor, cx| {
+            crate::element::EditorElement::modifiers_changed(
+                editor,
+                &ModifiersChangedEvent {
+                    modifiers: Modifiers {
+                        command: true,
+                        ..Default::default()
+                    },
+                    ..Default::default()
+                },
+                cx,
+            );
+        });
+        // Assert no link highlights
+        cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
+            struct A;
+            let variable = A;
+        "});
+
+        // Cmd+shift click without existing definition requests and jumps
+        let hover_point = cx.display_point(indoc! {"
+            struct A;
+            let vˇariable = A;
+        "});
+        let target_range = cx.lsp_range(indoc! {"
+            struct «A»;
+            let variable = A;
+        "});
+
+        let mut requests =
+            cx.handle_request::<GotoTypeDefinition, _, _>(move |url, _, _| async move {
+                Ok(Some(lsp::GotoTypeDefinitionResponse::Link(vec![
+                    lsp::LocationLink {
+                        origin_selection_range: None,
+                        target_uri: url,
+                        target_range,
+                        target_selection_range: target_range,
+                    },
+                ])))
+            });
+
+        cx.update_editor(|editor, cx| {
+            go_to_fetched_type_definition(editor, PointForPosition::valid(hover_point), false, cx);
+        });
+        requests.next().await;
+        cx.background_executor.run_until_parked();
+
+        cx.assert_editor_state(indoc! {"
+            struct «Aˇ»;
+            let variable = A;
+        "});
+    }
+
+    #[gpui::test]
+    async fn test_link_go_to_definition(cx: &mut gpui::TestAppContext) {
+        init_test(cx, |_| {});
+
+        let mut cx = EditorLspTestContext::new_rust(
+            lsp::ServerCapabilities {
+                hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
+                ..Default::default()
+            },
+            cx,
+        )
+        .await;
+
+        cx.set_state(indoc! {"
+                fn ˇtest() { do_work(); }
+                fn do_work() { test(); }
+            "});
+
+        // Basic hold cmd, expect highlight in region if response contains definition
+        let hover_point = cx.display_point(indoc! {"
+                fn test() { do_wˇork(); }
+                fn do_work() { test(); }
+            "});
+        let symbol_range = cx.lsp_range(indoc! {"
+                fn test() { «do_work»(); }
+                fn do_work() { test(); }
+            "});
+        let target_range = cx.lsp_range(indoc! {"
+                fn test() { do_work(); }
+                fn «do_work»() { test(); }
+            "});
+
+        let mut requests = cx.handle_request::<GotoDefinition, _, _>(move |url, _, _| async move {
+            Ok(Some(lsp::GotoDefinitionResponse::Link(vec![
+                lsp::LocationLink {
+                    origin_selection_range: Some(symbol_range),
+                    target_uri: url.clone(),
+                    target_range,
+                    target_selection_range: target_range,
+                },
+            ])))
+        });
+
+        cx.update_editor(|editor, cx| {
+            update_go_to_definition_link(
+                editor,
+                Some(GoToDefinitionTrigger::Text(hover_point)),
+                true,
+                false,
+                cx,
+            );
+        });
+        requests.next().await;
+        cx.background_executor.run_until_parked();
+        cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
+                fn test() { «do_work»(); }
+                fn do_work() { test(); }
+            "});
+
+        // Unpress cmd causes highlight to go away
+        cx.update_editor(|editor, cx| {
+            crate::element::EditorElement::modifiers_changed(editor, &Default::default(), cx);
+        });
+
+        // Assert no link highlights
+        cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
+                fn test() { do_work(); }
+                fn do_work() { test(); }
+            "});
+
+        // Response without source range still highlights word
+        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 {
+                    // No origin range
+                    origin_selection_range: None,
+                    target_uri: url.clone(),
+                    target_range,
+                    target_selection_range: target_range,
+                },
+            ])))
+        });
+        cx.update_editor(|editor, cx| {
+            update_go_to_definition_link(
+                editor,
+                Some(GoToDefinitionTrigger::Text(hover_point)),
+                true,
+                false,
+                cx,
+            );
+        });
+        requests.next().await;
+        cx.background_executor.run_until_parked();
+
+        cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
+                fn test() { «do_work»(); }
+                fn do_work() { test(); }
+            "});
+
+        // Moving mouse to location with no response dismisses highlight
+        let hover_point = cx.display_point(indoc! {"
+                fˇn test() { do_work(); }
+                fn do_work() { test(); }
+            "});
+        let mut requests = cx
+            .lsp
+            .handle_request::<GotoDefinition, _, _>(move |_, _| async move {
+                // No definitions returned
+                Ok(Some(lsp::GotoDefinitionResponse::Link(vec![])))
+            });
+        cx.update_editor(|editor, cx| {
+            update_go_to_definition_link(
+                editor,
+                Some(GoToDefinitionTrigger::Text(hover_point)),
+                true,
+                false,
+                cx,
+            );
+        });
+        requests.next().await;
+        cx.background_executor.run_until_parked();
+
+        // Assert no link highlights
+        cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
+                fn test() { do_work(); }
+                fn do_work() { test(); }
+            "});
+
+        // Move mouse without cmd and then pressing cmd triggers highlight
+        let hover_point = cx.display_point(indoc! {"
+                fn test() { do_work(); }
+                fn do_work() { teˇst(); }
+            "});
+        cx.update_editor(|editor, cx| {
+            update_go_to_definition_link(
+                editor,
+                Some(GoToDefinitionTrigger::Text(hover_point)),
+                false,
+                false,
+                cx,
+            );
+        });
+        cx.background_executor.run_until_parked();
+
+        // Assert no link highlights
+        cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
+                fn test() { do_work(); }
+                fn do_work() { test(); }
+            "});
+
+        let symbol_range = cx.lsp_range(indoc! {"
+                fn test() { do_work(); }
+                fn do_work() { «test»(); }
+            "});
+        let target_range = cx.lsp_range(indoc! {"
+                fn «test»() { do_work(); }
+                fn do_work() { test(); }
+            "});
+
+        let mut requests = cx.handle_request::<GotoDefinition, _, _>(move |url, _, _| async move {
+            Ok(Some(lsp::GotoDefinitionResponse::Link(vec![
+                lsp::LocationLink {
+                    origin_selection_range: Some(symbol_range),
+                    target_uri: url,
+                    target_range,
+                    target_selection_range: target_range,
+                },
+            ])))
+        });
+        cx.update_editor(|editor, cx| {
+            crate::element::EditorElement::modifiers_changed(
+                editor,
+                &ModifiersChangedEvent {
+                    modifiers: Modifiers {
+                        command: true,
+                        ..Default::default()
+                    },
+                },
+                cx,
+            );
+        });
+        requests.next().await;
+        cx.background_executor.run_until_parked();
+
+        cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
+                fn test() { do_work(); }
+                fn do_work() { «test»(); }
+            "});
+
+        // Deactivating the window dismisses the highlight
+        cx.update_workspace(|workspace, cx| {
+            workspace.on_window_activation_changed(cx);
+        });
+        cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
+                fn test() { do_work(); }
+                fn do_work() { test(); }
+            "});
+
+        // Moving the mouse restores the highlights.
+        cx.update_editor(|editor, cx| {
+            update_go_to_definition_link(
+                editor,
+                Some(GoToDefinitionTrigger::Text(hover_point)),
+                true,
+                false,
+                cx,
+            );
+        });
+        cx.background_executor.run_until_parked();
+        cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
+                fn test() { do_work(); }
+                fn do_work() { «test»(); }
+            "});
+
+        // Moving again within the same symbol range doesn't re-request
+        let hover_point = cx.display_point(indoc! {"
+                fn test() { do_work(); }
+                fn do_work() { tesˇt(); }
+            "});
+        cx.update_editor(|editor, cx| {
+            update_go_to_definition_link(
+                editor,
+                Some(GoToDefinitionTrigger::Text(hover_point)),
+                true,
+                false,
+                cx,
+            );
+        });
+        cx.background_executor.run_until_parked();
+        cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
+                fn test() { do_work(); }
+                fn do_work() { «test»(); }
+            "});
+
+        // Cmd click with existing definition doesn't re-request and dismisses highlight
+        cx.update_editor(|editor, cx| {
+            go_to_fetched_definition(editor, PointForPosition::valid(hover_point), false, cx);
+        });
+        // Assert selection moved to to definition
+        cx.lsp
+            .handle_request::<GotoDefinition, _, _>(move |_, _| async move {
+                // Empty definition response to make sure we aren't hitting the lsp and using
+                // the cached location instead
+                Ok(Some(lsp::GotoDefinitionResponse::Link(vec![])))
+            });
+        cx.background_executor.run_until_parked();
+        cx.assert_editor_state(indoc! {"
+                fn «testˇ»() { do_work(); }
+                fn do_work() { test(); }
+            "});
+
+        // Assert no link highlights after jump
+        cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
+                fn test() { do_work(); }
+                fn do_work() { test(); }
+            "});
+
+        // Cmd click without existing definition requests and jumps
+        let hover_point = cx.display_point(indoc! {"
+                fn test() { do_wˇork(); }
+                fn do_work() { test(); }
+            "});
+        let target_range = cx.lsp_range(indoc! {"
+                fn test() { do_work(); }
+                fn «do_work»() { test(); }
+            "});
+
+        let mut requests = cx.handle_request::<GotoDefinition, _, _>(move |url, _, _| async move {
+            Ok(Some(lsp::GotoDefinitionResponse::Link(vec![
+                lsp::LocationLink {
+                    origin_selection_range: None,
+                    target_uri: url,
+                    target_range,
+                    target_selection_range: target_range,
+                },
+            ])))
+        });
+        cx.update_editor(|editor, cx| {
+            go_to_fetched_definition(editor, PointForPosition::valid(hover_point), false, cx);
+        });
+        requests.next().await;
+        cx.background_executor.run_until_parked();
+        cx.assert_editor_state(indoc! {"
+                fn test() { do_work(); }
+                fn «do_workˇ»() { test(); }
+            "});
+
+        // 1. We have a pending selection, mouse point is over a symbol that we have a response for, hitting cmd and nothing happens
+        // 2. Selection is completed, hovering
+        let hover_point = cx.display_point(indoc! {"
+                fn test() { do_wˇork(); }
+                fn do_work() { test(); }
+            "});
+        let target_range = cx.lsp_range(indoc! {"
+                fn test() { do_work(); }
+                fn «do_work»() { test(); }
+            "});
+        let mut requests = cx.handle_request::<GotoDefinition, _, _>(move |url, _, _| async move {
+            Ok(Some(lsp::GotoDefinitionResponse::Link(vec![
+                lsp::LocationLink {
+                    origin_selection_range: None,
+                    target_uri: url,
+                    target_range,
+                    target_selection_range: target_range,
+                },
+            ])))
+        });
+
+        // create a pending selection
+        let selection_range = cx.ranges(indoc! {"
+                fn «test() { do_w»ork(); }
+                fn do_work() { test(); }
+            "})[0]
+            .clone();
+        cx.update_editor(|editor, cx| {
+            let snapshot = editor.buffer().read(cx).snapshot(cx);
+            let anchor_range = snapshot.anchor_before(selection_range.start)
+                ..snapshot.anchor_after(selection_range.end);
+            editor.change_selections(Some(crate::Autoscroll::fit()), cx, |s| {
+                s.set_pending_anchor_range(anchor_range, crate::SelectMode::Character)
+            });
+        });
+        cx.update_editor(|editor, cx| {
+            update_go_to_definition_link(
+                editor,
+                Some(GoToDefinitionTrigger::Text(hover_point)),
+                true,
+                false,
+                cx,
+            );
+        });
+        cx.background_executor.run_until_parked();
+        assert!(requests.try_next().is_err());
+        cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
+                fn test() { do_work(); }
+                fn do_work() { test(); }
+            "});
+        cx.background_executor.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 hint_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: hint_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.background_executor.run_until_parked();
+        cx.update_editor(|editor, cx| {
+            let expected_layers = vec![hint_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);
+            let previous_valid = inlay_range.start.to_display_point(&snapshot);
+            let next_valid = inlay_range.end.to_display_point(&snapshot);
+            assert_eq!(previous_valid.row(), next_valid.row());
+            assert!(previous_valid.column() < next_valid.column());
+            let exact_unclipped = DisplayPoint::new(
+                previous_valid.row(),
+                previous_valid.column() + (hint_label.len() / 2) as u32,
+            );
+            PointForPosition {
+                previous_valid,
+                next_valid,
+                exact_unclipped,
+                column_overshoot_after_line_end: 0,
+            }
+        });
+        // 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.background_executor.run_until_parked();
+        cx.update_editor(|editor, cx| {
+            let snapshot = editor.snapshot(cx);
+            let actual_highlights = snapshot
+                .inlay_highlights::<LinkGoToDefinitionState>()
+                .into_iter()
+                .flat_map(|highlights| highlights.values().map(|(_, highlight)| highlight))
+                .collect::<Vec<_>>();
+
+            let buffer_snapshot = editor.buffer().update(cx, |buffer, cx| buffer.snapshot(cx));
+            let expected_highlight = InlayHighlight {
+                inlay: InlayId::Hint(0),
+                inlay_position: buffer_snapshot.anchor_at(inlay_range.start, Bias::Right),
+                range: 0..hint_label.len(),
+            };
+            assert_set_eq!(actual_highlights, vec![&expected_highlight]);
+        });
+
+        // Unpress cmd causes highlight to go away
+        cx.update_editor(|editor, cx| {
+            crate::element::EditorElement::modifiers_changed(
+                editor,
+                &ModifiersChangedEvent {
+                    modifiers: Modifiers {
+                        command: false,
+                        ..Default::default()
+                    },
+                    ..Default::default()
+                },
+                cx,
+            );
+        });
+        // Assert no link highlights
+        cx.update_editor(|editor, cx| {
+                let snapshot = editor.snapshot(cx);
+                let actual_ranges = snapshot
+                    .text_highlight_ranges::<LinkGoToDefinitionState>()
+                    .map(|ranges| ranges.as_ref().clone().1)
+                    .unwrap_or_default();
+
+                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| {
+            crate::element::EditorElement::modifiers_changed(
+                editor,
+                &ModifiersChangedEvent {
+                    modifiers: Modifiers {
+                        command: true,
+                        ..Default::default()
+                    },
+                    ..Default::default()
+                },
+                cx,
+            );
+            update_inlay_link_and_hover_points(
+                &editor.snapshot(cx),
+                hint_hover_position,
+                editor,
+                true,
+                false,
+                cx,
+            );
+        });
+        cx.background_executor.run_until_parked();
+        cx.update_editor(|editor, cx| {
+            go_to_fetched_type_definition(editor, hint_hover_position, false, cx);
+        });
+        cx.background_executor.run_until_parked();
+        cx.assert_editor_state(indoc! {"
+                struct «TestStructˇ»;
+
+                fn main() {
+                    let variable = TestStruct;
+                }
+            "});
+    }
+}