internal: Compute inlay hint tooltips lazily

This commit is contained in:
Lukas Wirth 2025-01-12 14:28:24 +01:00
parent 0f595b07bd
commit f66bbbf27d
5 changed files with 47 additions and 16 deletions

View file

@ -307,6 +307,25 @@ impl InlayHintsConfig {
Lazy::Computed(edit) Lazy::Computed(edit)
} }
} }
fn lazy_tooltip(&self, finish: impl FnOnce() -> InlayTooltip) -> Lazy<InlayTooltip> {
if self.fields_to_resolve.resolve_hint_tooltip
&& self.fields_to_resolve.resolve_label_tooltip
{
Lazy::Lazy
} else {
let tooltip = finish();
never!(
match &tooltip {
InlayTooltip::String(s) => s,
InlayTooltip::Markdown(s) => s,
}
.is_empty(),
"inlay hint produced an empty tooltip"
);
Lazy::Computed(tooltip)
}
}
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@ -486,7 +505,7 @@ pub struct InlayHintLabel {
impl InlayHintLabel { impl InlayHintLabel {
pub fn simple( pub fn simple(
s: impl Into<String>, s: impl Into<String>,
tooltip: Option<InlayTooltip>, tooltip: Option<Lazy<InlayTooltip>>,
linked_location: Option<FileRange>, linked_location: Option<FileRange>,
) -> InlayHintLabel { ) -> InlayHintLabel {
InlayHintLabel { InlayHintLabel {
@ -564,7 +583,6 @@ impl fmt::Debug for InlayHintLabel {
} }
} }
#[derive(Hash)]
pub struct InlayHintLabelPart { pub struct InlayHintLabelPart {
pub text: String, pub text: String,
/// Source location represented by this label part. The client will use this to fetch the part's /// Source location represented by this label part. The client will use this to fetch the part's
@ -575,13 +593,21 @@ pub struct InlayHintLabelPart {
pub linked_location: Option<FileRange>, pub linked_location: Option<FileRange>,
/// The tooltip to show when hovering over the inlay hint, this may invoke other actions like /// The tooltip to show when hovering over the inlay hint, this may invoke other actions like
/// hover requests to show. /// hover requests to show.
pub tooltip: Option<InlayTooltip>, pub tooltip: Option<Lazy<InlayTooltip>>,
}
impl std::hash::Hash for InlayHintLabelPart {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.text.hash(state);
self.linked_location.hash(state);
self.tooltip.is_some().hash(state);
}
} }
impl fmt::Debug for InlayHintLabelPart { impl fmt::Debug for InlayHintLabelPart {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Self { text, linked_location: None, tooltip: None } => text.fmt(f), Self { text, linked_location: None, tooltip: None | Some(Lazy::Lazy) } => text.fmt(f),
Self { text, linked_location, tooltip } => f Self { text, linked_location, tooltip } => f
.debug_struct("InlayHintLabelPart") .debug_struct("InlayHintLabelPart")
.field("text", text) .field("text", text)
@ -589,7 +615,8 @@ impl fmt::Debug for InlayHintLabelPart {
.field( .field(
"tooltip", "tooltip",
&tooltip.as_ref().map_or("", |it| match it { &tooltip.as_ref().map_or("", |it| match it {
InlayTooltip::String(it) | InlayTooltip::Markdown(it) => it, Lazy::Computed(InlayTooltip::String(it) | InlayTooltip::Markdown(it)) => it,
Lazy::Lazy => "",
}), }),
) )
.finish(), .finish(),

View file

@ -162,11 +162,13 @@ pub(super) fn hints(
let label = InlayHintLabelPart { let label = InlayHintLabelPart {
text: if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() }, text: if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() },
linked_location: None, linked_location: None,
tooltip: Some(InlayTooltip::Markdown(format!( tooltip: Some(config.lazy_tooltip(|| {
InlayTooltip::Markdown(format!(
"`{}` → `{}` ({coercion} coercion)", "`{}` → `{}` ({coercion} coercion)",
source.display(sema.db, file_id.edition()), source.display(sema.db, file_id.edition()),
target.display(sema.db, file_id.edition()), target.display(sema.db, file_id.edition()),
))), ))
})),
}; };
if postfix { &mut post } else { &mut pre }.label.append_part(label); if postfix { &mut post } else { &mut pre }.label.append_part(label);
} }

View file

@ -76,9 +76,11 @@ fn variant_hints(
} }
Err(_) => format!("{eq_} ?"), Err(_) => format!("{eq_} ?"),
}, },
Some(InlayTooltip::String(match &d { Some(config.lazy_tooltip(|| {
InlayTooltip::String(match &d {
Ok(_) => "enum variant discriminant".into(), Ok(_) => "enum variant discriminant".into(),
Err(e) => format!("{e:?}"), Err(e) => format!("{e:?}"),
})
})), })),
None, None,
); );

View file

@ -108,7 +108,7 @@ pub(super) fn hints(
} }
let mut label = InlayHintLabel::simple( let mut label = InlayHintLabel::simple(
name, name,
Some(crate::InlayTooltip::String("moz".into())), Some(config.lazy_tooltip(|| crate::InlayTooltip::String("moz".into()))),
binding_source, binding_source,
); );
label.prepend_str("drop("); label.prepend_str("drop(");

View file

@ -641,7 +641,7 @@ fn inlay_hint_label(
*something_to_resolve |= tooltip.is_some(); *something_to_resolve |= tooltip.is_some();
None None
} else { } else {
match tooltip { match tooltip.and_then(|it| it.computed()) {
Some(ide::InlayTooltip::String(s)) => { Some(ide::InlayTooltip::String(s)) => {
Some(lsp_types::InlayHintTooltip::String(s)) Some(lsp_types::InlayHintTooltip::String(s))
} }
@ -665,7 +665,7 @@ fn inlay_hint_label(
*something_to_resolve |= part.tooltip.is_some(); *something_to_resolve |= part.tooltip.is_some();
None None
} else { } else {
match part.tooltip { match part.tooltip.and_then(|it| it.computed()) {
Some(ide::InlayTooltip::String(s)) => { Some(ide::InlayTooltip::String(s)) => {
Some(lsp_types::InlayHintLabelPartTooltip::String(s)) Some(lsp_types::InlayHintLabelPartTooltip::String(s))
} }