@@ -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;
+ }
+ "});
+ }
+}