Add symmetric assertion for inlay-hint hover disambiguation

This commit is contained in:
Shuhei Kadowaki 2026-05-21 21:33:46 +09:00
parent b4f3ea7871
commit 5f371d806d

View file

@ -2266,71 +2266,98 @@ mod tests {
); );
}); });
// Hover in the middle of the first inlay's rendered text. async fn assert_hovered_inlay(
let hover_position = cx.update_editor(|editor, window, cx| { cx: &mut EditorLspTestContext,
let snapshot = editor.snapshot(window, cx); hint_offset: usize,
let inlay_start = MultiBufferOffset(first_hint_offset).to_display_point(&snapshot); label_len: u32,
let exact_unclipped = DisplayPoint::new( expected_tooltip: &str,
inlay_start.row(), expected_inlay_id: InlayId,
inlay_start.column() + (first_label.len() as u32 / 2), ) {
); let hover_position = cx.update_editor(|editor, window, cx| {
let previous_valid = snapshot.clip_point(exact_unclipped, Bias::Left); let snapshot = editor.snapshot(window, cx);
let next_valid = snapshot.clip_point(exact_unclipped, Bias::Right); let inlay_start = MultiBufferOffset(hint_offset).to_display_point(&snapshot);
let nearest_valid = if previous_valid == next_valid { let exact_unclipped =
previous_valid DisplayPoint::new(inlay_start.row(), inlay_start.column() + label_len / 2);
} else { let previous_valid = snapshot.clip_point(exact_unclipped, Bias::Left);
match snapshot.inlay_bias_at(exact_unclipped) { let next_valid = snapshot.clip_point(exact_unclipped, Bias::Right);
Some(Bias::Left) => next_valid, let nearest_valid = if previous_valid == next_valid {
Some(Bias::Right) => previous_valid, previous_valid
None => previous_valid, } else {
match snapshot.inlay_bias_at(exact_unclipped) {
Some(Bias::Left) => next_valid,
Some(Bias::Right) => previous_valid,
None => previous_valid,
}
};
PointForPosition {
previous_valid,
next_valid,
nearest_valid,
exact_unclipped,
column_overshoot_after_line_end: 0,
} }
}; });
PointForPosition { cx.update_editor(|editor, window, cx| {
previous_valid, editor.hover_state = HoverState::default();
next_valid, editor.update_inlay_link_and_hover_points(
nearest_valid, &editor.snapshot(window, cx),
exact_unclipped, hover_position,
column_overshoot_after_line_end: 0, None,
} true,
}); false,
cx.update_editor(|editor, window, cx| { window,
editor.update_inlay_link_and_hover_points( cx,
&editor.snapshot(window, cx), );
hover_position, });
None, cx.background_executor
true, .advance_clock(Duration::from_millis(get_hover_popover_delay(cx) + 100));
false, cx.background_executor.run_until_parked();
window,
cx,
);
});
cx.background_executor
.advance_clock(Duration::from_millis(get_hover_popover_delay(&cx) + 100));
cx.background_executor.run_until_parked();
cx.update_editor(|editor, _, cx| { cx.update_editor(|editor, _, cx| {
let hover_state = &editor.hover_state; let hover_state = &editor.hover_state;
assert_eq!( assert_eq!(
hover_state.info_popovers.len(), hover_state.info_popovers.len(),
1, 1,
"expected exactly one popover", "expected exactly one popover for inlay {expected_inlay_id:?}",
); );
let popover = hover_state.info_popovers.first().unwrap(); let popover = hover_state.info_popovers.first().unwrap();
assert_eq!( assert_eq!(
popover.get_rendered_text(cx), popover.get_rendered_text(cx),
"Foo", expected_tooltip,
"popover content should match the first inlay (the one under the cursor), \ "popover content should match the inlay under the cursor, \
not the adjacent inlay one source character past it", not the adjacent inlay one source character away",
); );
let RangeInEditor::Inlay(highlight) = &popover.symbol_range else { let RangeInEditor::Inlay(highlight) = &popover.symbol_range else {
panic!("expected an inlay popover, got {:?}", popover.symbol_range); panic!("expected an inlay popover, got {:?}", popover.symbol_range);
}; };
assert_eq!( assert_eq!(
highlight.inlay, highlight.inlay, expected_inlay_id,
InlayId::Hint(0), "popover should reference the hovered inlay",
"popover should reference the first inlay", );
); });
}); }
// Hover the first inlay (`::Foo`): the buffer-position window also covers
// the second hint past `;`, so the hovered-offset filter must pick the first.
assert_hovered_inlay(
&mut cx,
first_hint_offset,
first_label.len() as u32,
"Foo",
InlayId::Hint(0),
)
.await;
// Symmetric check: hover the second inlay (`::Bar`) and verify the filter
// picks the second hint despite the first hint also being in range.
assert_hovered_inlay(
&mut cx,
second_hint_offset,
second_label.len() as u32,
"Bar",
InlayId::Hint(1),
)
.await;
} }
#[test] #[test]