Auto merge of #16822 - Veykril:inlays, r=Veykril

fix: Make inlay hint resolving work better for inlays targetting the same position
This commit is contained in:
bors 2024-03-18 09:00:59 +00:00
commit f40c7d8a9c
19 changed files with 113 additions and 90 deletions

View file

@ -1,5 +1,6 @@
use std::{ use std::{
fmt::{self, Write}, fmt::{self, Write},
hash::{BuildHasher, BuildHasherDefault},
mem::take, mem::take,
}; };
@ -8,7 +9,7 @@ use hir::{
known, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef, known, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef,
ModuleDefId, Semantics, ModuleDefId, Semantics,
}; };
use ide_db::{base_db::FileRange, famous_defs::FamousDefs, RootDatabase}; use ide_db::{base_db::FileRange, famous_defs::FamousDefs, FxHasher, RootDatabase};
use itertools::Itertools; use itertools::Itertools;
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use stdx::never; use stdx::never;
@ -116,7 +117,7 @@ pub enum AdjustmentHintsMode {
PreferPostfix, PreferPostfix,
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum InlayKind { pub enum InlayKind {
Adjustment, Adjustment,
BindingMode, BindingMode,
@ -132,7 +133,7 @@ pub enum InlayKind {
RangeExclusive, RangeExclusive,
} }
#[derive(Debug)] #[derive(Debug, Hash)]
pub enum InlayHintPosition { pub enum InlayHintPosition {
Before, Before,
After, After,
@ -151,13 +152,23 @@ pub struct InlayHint {
pub label: InlayHintLabel, pub label: InlayHintLabel,
/// Text edit to apply when "accepting" this inlay hint. /// Text edit to apply when "accepting" this inlay hint.
pub text_edit: Option<TextEdit>, pub text_edit: Option<TextEdit>,
pub needs_resolve: bool, }
impl std::hash::Hash for InlayHint {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.range.hash(state);
self.position.hash(state);
self.pad_left.hash(state);
self.pad_right.hash(state);
self.kind.hash(state);
self.label.hash(state);
self.text_edit.is_some().hash(state);
}
} }
impl InlayHint { impl InlayHint {
fn closing_paren_after(kind: InlayKind, range: TextRange) -> InlayHint { fn closing_paren_after(kind: InlayKind, range: TextRange) -> InlayHint {
InlayHint { InlayHint {
needs_resolve: false,
range, range,
kind, kind,
label: InlayHintLabel::from(")"), label: InlayHintLabel::from(")"),
@ -167,9 +178,9 @@ impl InlayHint {
pad_right: false, pad_right: false,
} }
} }
fn opening_paren_before(kind: InlayKind, range: TextRange) -> InlayHint { fn opening_paren_before(kind: InlayKind, range: TextRange) -> InlayHint {
InlayHint { InlayHint {
needs_resolve: false,
range, range,
kind, kind,
label: InlayHintLabel::from("("), label: InlayHintLabel::from("("),
@ -179,15 +190,19 @@ impl InlayHint {
pad_right: false, pad_right: false,
} }
} }
pub fn needs_resolve(&self) -> bool {
self.text_edit.is_some() || self.label.needs_resolve()
}
} }
#[derive(Debug)] #[derive(Debug, Hash)]
pub enum InlayTooltip { pub enum InlayTooltip {
String(String), String(String),
Markdown(String), Markdown(String),
} }
#[derive(Default)] #[derive(Default, Hash)]
pub struct InlayHintLabel { pub struct InlayHintLabel {
pub parts: SmallVec<[InlayHintLabelPart; 1]>, pub parts: SmallVec<[InlayHintLabelPart; 1]>,
} }
@ -265,6 +280,7 @@ 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
@ -313,9 +329,7 @@ impl fmt::Write for InlayHintLabelBuilder<'_> {
impl HirWrite for InlayHintLabelBuilder<'_> { impl HirWrite for InlayHintLabelBuilder<'_> {
fn start_location_link(&mut self, def: ModuleDefId) { fn start_location_link(&mut self, def: ModuleDefId) {
if self.location.is_some() { never!(self.location.is_some(), "location link is already started");
never!("location link is already started");
}
self.make_new_part(); self.make_new_part();
let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return }; let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return };
let location = location.call_site(); let location = location.call_site();
@ -425,11 +439,6 @@ fn ty_to_text_edit(
Some(builder.finish()) Some(builder.finish())
} }
pub enum RangeLimit {
Fixed(TextRange),
NearestParent(TextSize),
}
// Feature: Inlay Hints // Feature: Inlay Hints
// //
// rust-analyzer shows additional information inline with the source code. // rust-analyzer shows additional information inline with the source code.
@ -451,7 +460,7 @@ pub enum RangeLimit {
pub(crate) fn inlay_hints( pub(crate) fn inlay_hints(
db: &RootDatabase, db: &RootDatabase,
file_id: FileId, file_id: FileId,
range_limit: Option<RangeLimit>, range_limit: Option<TextRange>,
config: &InlayHintsConfig, config: &InlayHintsConfig,
) -> Vec<InlayHint> { ) -> Vec<InlayHint> {
let _p = tracing::span!(tracing::Level::INFO, "inlay_hints").entered(); let _p = tracing::span!(tracing::Level::INFO, "inlay_hints").entered();
@ -466,31 +475,13 @@ pub(crate) fn inlay_hints(
let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node); let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node);
match range_limit { match range_limit {
Some(RangeLimit::Fixed(range)) => match file.covering_element(range) { Some(range) => match file.covering_element(range) {
NodeOrToken::Token(_) => return acc, NodeOrToken::Token(_) => return acc,
NodeOrToken::Node(n) => n NodeOrToken::Node(n) => n
.descendants() .descendants()
.filter(|descendant| range.intersect(descendant.text_range()).is_some()) .filter(|descendant| range.intersect(descendant.text_range()).is_some())
.for_each(hints), .for_each(hints),
}, },
Some(RangeLimit::NearestParent(position)) => {
match file.token_at_offset(position).left_biased() {
Some(token) => {
if let Some(parent_block) =
token.parent_ancestors().find_map(ast::BlockExpr::cast)
{
parent_block.syntax().descendants().for_each(hints)
} else if let Some(parent_item) =
token.parent_ancestors().find_map(ast::Item::cast)
{
parent_item.syntax().descendants().for_each(hints)
} else {
return acc;
}
}
None => return acc,
}
}
None => file.descendants().for_each(hints), None => file.descendants().for_each(hints),
}; };
} }
@ -498,6 +489,39 @@ pub(crate) fn inlay_hints(
acc acc
} }
pub(crate) fn inlay_hints_resolve(
db: &RootDatabase,
file_id: FileId,
position: TextSize,
hash: u64,
config: &InlayHintsConfig,
) -> Option<InlayHint> {
let _p = tracing::span!(tracing::Level::INFO, "inlay_hints").entered();
let sema = Semantics::new(db);
let file = sema.parse(file_id);
let file = file.syntax();
let scope = sema.scope(file)?;
let famous_defs = FamousDefs(&sema, scope.krate());
let mut acc = Vec::new();
let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node);
match file.token_at_offset(position).left_biased() {
Some(token) => {
if let Some(parent_block) = token.parent_ancestors().find_map(ast::BlockExpr::cast) {
parent_block.syntax().descendants().for_each(hints)
} else if let Some(parent_item) = token.parent_ancestors().find_map(ast::Item::cast) {
parent_item.syntax().descendants().for_each(hints)
} else {
return None;
}
}
None => return None,
}
acc.into_iter().find(|hint| BuildHasherDefault::<FxHasher>::default().hash_one(hint) == hash)
}
fn hints( fn hints(
hints: &mut Vec<InlayHint>, hints: &mut Vec<InlayHint>,
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,

View file

@ -147,7 +147,6 @@ pub(super) fn hints(
None, None,
); );
acc.push(InlayHint { acc.push(InlayHint {
needs_resolve: label.needs_resolve(),
range: expr.syntax().text_range(), range: expr.syntax().text_range(),
pad_left: false, pad_left: false,
pad_right: false, pad_right: false,

View file

@ -99,7 +99,6 @@ pub(super) fn hints(
None => pat.syntax().text_range(), None => pat.syntax().text_range(),
}; };
acc.push(InlayHint { acc.push(InlayHint {
needs_resolve: label.needs_resolve() || text_edit.is_some(),
range: match type_ascriptable { range: match type_ascriptable {
Some(Some(t)) => text_range.cover(t.text_range()), Some(Some(t)) => text_range.cover(t.text_range()),
_ => text_range, _ => text_range,
@ -177,11 +176,7 @@ mod tests {
use syntax::{TextRange, TextSize}; use syntax::{TextRange, TextSize};
use test_utils::extract_annotations; use test_utils::extract_annotations;
use crate::{ use crate::{fixture, inlay_hints::InlayHintsConfig, ClosureReturnTypeHints};
fixture,
inlay_hints::{InlayHintsConfig, RangeLimit},
ClosureReturnTypeHints,
};
use crate::inlay_hints::tests::{ use crate::inlay_hints::tests::{
check, check_edit, check_no_edit, check_with_config, DISABLED_CONFIG, TEST_CONFIG, check, check_edit, check_no_edit, check_with_config, DISABLED_CONFIG, TEST_CONFIG,
@ -404,7 +399,7 @@ fn main() {
.inlay_hints( .inlay_hints(
&InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, &InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
file_id, file_id,
Some(RangeLimit::Fixed(TextRange::new(TextSize::from(500), TextSize::from(600)))), Some(TextRange::new(TextSize::from(500), TextSize::from(600))),
) )
.unwrap(); .unwrap();
let actual = let actual =

View file

@ -50,7 +50,6 @@ pub(super) fn hints(
_ => return, _ => return,
}; };
acc.push(InlayHint { acc.push(InlayHint {
needs_resolve: false,
range, range,
kind: InlayKind::BindingMode, kind: InlayKind::BindingMode,
label: r.into(), label: r.into(),
@ -69,7 +68,6 @@ pub(super) fn hints(
hir::BindingMode::Ref(Mutability::Shared) => "ref", hir::BindingMode::Ref(Mutability::Shared) => "ref",
}; };
acc.push(InlayHint { acc.push(InlayHint {
needs_resolve: false,
range: pat.syntax().text_range(), range: pat.syntax().text_range(),
kind: InlayKind::BindingMode, kind: InlayKind::BindingMode,
label: bm.into(), label: bm.into(),

View file

@ -59,7 +59,6 @@ pub(super) fn hints(
} }
let label = label_of_ty(famous_defs, config, &ty)?; let label = label_of_ty(famous_defs, config, &ty)?;
acc.push(InlayHint { acc.push(InlayHint {
needs_resolve: label.needs_resolve(),
range: expr.syntax().text_range(), range: expr.syntax().text_range(),
kind: InlayKind::Chaining, kind: InlayKind::Chaining,
label, label,

View file

@ -109,7 +109,6 @@ pub(super) fn hints(
let linked_location = name_range.map(|range| FileRange { file_id, range }); let linked_location = name_range.map(|range| FileRange { file_id, range });
acc.push(InlayHint { acc.push(InlayHint {
needs_resolve: linked_location.is_some(),
range: closing_token.text_range(), range: closing_token.text_range(),
kind: InlayKind::ClosingBrace, kind: InlayKind::ClosingBrace,
label: InlayHintLabel::simple(label, None, linked_location), label: InlayHintLabel::simple(label, None, linked_location),

View file

@ -32,7 +32,6 @@ pub(super) fn hints(
let range = closure.syntax().first_token()?.prev_token()?.text_range(); let range = closure.syntax().first_token()?.prev_token()?.text_range();
let range = TextRange::new(range.end() - TextSize::from(1), range.end()); let range = TextRange::new(range.end() - TextSize::from(1), range.end());
acc.push(InlayHint { acc.push(InlayHint {
needs_resolve: false,
range, range,
kind: InlayKind::ClosureCapture, kind: InlayKind::ClosureCapture,
label: InlayHintLabel::from("move"), label: InlayHintLabel::from("move"),
@ -45,7 +44,6 @@ pub(super) fn hints(
} }
}; };
acc.push(InlayHint { acc.push(InlayHint {
needs_resolve: false,
range: move_kw_range, range: move_kw_range,
kind: InlayKind::ClosureCapture, kind: InlayKind::ClosureCapture,
label: InlayHintLabel::from("("), label: InlayHintLabel::from("("),
@ -79,7 +77,6 @@ pub(super) fn hints(
}), }),
); );
acc.push(InlayHint { acc.push(InlayHint {
needs_resolve: label.needs_resolve(),
range: move_kw_range, range: move_kw_range,
kind: InlayKind::ClosureCapture, kind: InlayKind::ClosureCapture,
label, label,
@ -91,7 +88,6 @@ pub(super) fn hints(
if idx != last { if idx != last {
acc.push(InlayHint { acc.push(InlayHint {
needs_resolve: false,
range: move_kw_range, range: move_kw_range,
kind: InlayKind::ClosureCapture, kind: InlayKind::ClosureCapture,
label: InlayHintLabel::from(", "), label: InlayHintLabel::from(", "),
@ -103,7 +99,6 @@ pub(super) fn hints(
} }
} }
acc.push(InlayHint { acc.push(InlayHint {
needs_resolve: false,
range: move_kw_range, range: move_kw_range,
kind: InlayKind::ClosureCapture, kind: InlayKind::ClosureCapture,
label: InlayHintLabel::from(")"), label: InlayHintLabel::from(")"),

View file

@ -64,7 +64,6 @@ pub(super) fn hints(
}; };
acc.push(InlayHint { acc.push(InlayHint {
needs_resolve: label.needs_resolve() || text_edit.is_some(),
range: param_list.syntax().text_range(), range: param_list.syntax().text_range(),
kind: InlayKind::Type, kind: InlayKind::Type,
label, label,

View file

@ -79,7 +79,6 @@ fn variant_hints(
None, None,
); );
acc.push(InlayHint { acc.push(InlayHint {
needs_resolve: label.needs_resolve(),
range: match eq_token { range: match eq_token {
Some(t) => range.cover(t.text_range()), Some(t) => range.cover(t.text_range()),
_ => range, _ => range,

View file

@ -22,7 +22,6 @@ pub(super) fn hints(
} }
let mk_lt_hint = |t: SyntaxToken, label: String| InlayHint { let mk_lt_hint = |t: SyntaxToken, label: String| InlayHint {
needs_resolve: false,
range: t.text_range(), range: t.text_range(),
kind: InlayKind::Lifetime, kind: InlayKind::Lifetime,
label: label.into(), label: label.into(),
@ -184,7 +183,6 @@ pub(super) fn hints(
let angle_tok = gpl.l_angle_token()?; let angle_tok = gpl.l_angle_token()?;
let is_empty = gpl.generic_params().next().is_none(); let is_empty = gpl.generic_params().next().is_none();
acc.push(InlayHint { acc.push(InlayHint {
needs_resolve: false,
range: angle_tok.text_range(), range: angle_tok.text_range(),
kind: InlayKind::Lifetime, kind: InlayKind::Lifetime,
label: format!( label: format!(
@ -200,7 +198,6 @@ pub(super) fn hints(
}); });
} }
(None, allocated_lifetimes) => acc.push(InlayHint { (None, allocated_lifetimes) => acc.push(InlayHint {
needs_resolve: false,
range: func.name()?.syntax().text_range(), range: func.name()?.syntax().text_range(),
kind: InlayKind::GenericParamList, kind: InlayKind::GenericParamList,
label: format!("<{}>", allocated_lifetimes.iter().format(", "),).into(), label: format!("<{}>", allocated_lifetimes.iter().format(", "),).into(),

View file

@ -105,7 +105,6 @@ pub(super) fn hints(
pad_left: true, pad_left: true,
pad_right: true, pad_right: true,
kind: InlayKind::Drop, kind: InlayKind::Drop,
needs_resolve: label.needs_resolve(),
label, label,
text_edit: None, text_edit: None,
}) })

View file

@ -31,7 +31,6 @@ pub(super) fn hints(
if ty.lifetime().is_none() { if ty.lifetime().is_none() {
let t = ty.amp_token()?; let t = ty.amp_token()?;
acc.push(InlayHint { acc.push(InlayHint {
needs_resolve: false,
range: t.text_range(), range: t.text_range(),
kind: InlayKind::Lifetime, kind: InlayKind::Lifetime,
label: "'static".into(), label: "'static".into(),

View file

@ -57,7 +57,6 @@ pub(super) fn hints(
let label = let label =
InlayHintLabel::simple(format!("{param_name}{colon}"), None, linked_location); InlayHintLabel::simple(format!("{param_name}{colon}"), None, linked_location);
InlayHint { InlayHint {
needs_resolve: label.needs_resolve(),
range, range,
kind: InlayKind::Parameter, kind: InlayKind::Parameter,
label, label,

View file

@ -30,7 +30,6 @@ fn inlay_hint(token: SyntaxToken) -> InlayHint {
kind: crate::InlayKind::RangeExclusive, kind: crate::InlayKind::RangeExclusive,
label: crate::InlayHintLabel::from("<"), label: crate::InlayHintLabel::from("<"),
text_edit: None, text_edit: None,
needs_resolve: false,
} }
} }

View file

@ -90,7 +90,7 @@ pub use crate::{
inlay_hints::{ inlay_hints::{
AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints, AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints,
InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintPosition, InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintPosition,
InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints, RangeLimit, InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
}, },
join_lines::JoinLinesConfig, join_lines::JoinLinesConfig,
markup::Markup, markup::Markup,
@ -415,10 +415,19 @@ impl Analysis {
&self, &self,
config: &InlayHintsConfig, config: &InlayHintsConfig,
file_id: FileId, file_id: FileId,
range: Option<RangeLimit>, range: Option<TextRange>,
) -> Cancellable<Vec<InlayHint>> { ) -> Cancellable<Vec<InlayHint>> {
self.with_db(|db| inlay_hints::inlay_hints(db, file_id, range, config)) self.with_db(|db| inlay_hints::inlay_hints(db, file_id, range, config))
} }
pub fn inlay_hints_resolve(
&self,
config: &InlayHintsConfig,
file_id: FileId,
position: TextSize,
hash: u64,
) -> Cancellable<Option<InlayHint>> {
self.with_db(|db| inlay_hints::inlay_hints_resolve(db, file_id, position, hash, config))
}
/// Returns the set of folding ranges. /// Returns the set of folding ranges.
pub fn folding_ranges(&self, file_id: FileId) -> Cancellable<Vec<Fold>> { pub fn folding_ranges(&self, file_id: FileId) -> Cancellable<Vec<Fold>> {

View file

@ -12,8 +12,8 @@ use anyhow::Context;
use ide::{ use ide::{
AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, FilePosition, FileRange, AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, FilePosition, FileRange,
HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query, RangeInfo, RangeLimit, HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory,
ReferenceCategory, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit,
}; };
use ide_db::SymbolKind; use ide_db::SymbolKind;
use itertools::Itertools; use itertools::Itertools;
@ -1465,7 +1465,7 @@ pub(crate) fn handle_inlay_hints(
let inlay_hints_config = snap.config.inlay_hints(); let inlay_hints_config = snap.config.inlay_hints();
Ok(Some( Ok(Some(
snap.analysis snap.analysis
.inlay_hints(&inlay_hints_config, file_id, Some(RangeLimit::Fixed(range)))? .inlay_hints(&inlay_hints_config, file_id, Some(range))?
.into_iter() .into_iter()
.map(|it| { .map(|it| {
to_proto::inlay_hint( to_proto::inlay_hint(
@ -1499,10 +1499,11 @@ pub(crate) fn handle_inlay_hints_resolve(
let hint_position = from_proto::offset(&line_index, original_hint.position)?; let hint_position = from_proto::offset(&line_index, original_hint.position)?;
let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints(); let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints();
forced_resolve_inlay_hints_config.fields_to_resolve = InlayFieldsToResolve::empty(); forced_resolve_inlay_hints_config.fields_to_resolve = InlayFieldsToResolve::empty();
let resolve_hints = snap.analysis.inlay_hints( let resolve_hints = snap.analysis.inlay_hints_resolve(
&forced_resolve_inlay_hints_config, &forced_resolve_inlay_hints_config,
file_id, file_id,
Some(RangeLimit::NearestParent(hint_position)), hint_position,
resolve_data.hash,
)?; )?;
let mut resolved_hints = resolve_hints let mut resolved_hints = resolve_hints

View file

@ -800,6 +800,7 @@ pub struct CompletionResolveData {
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct InlayHintResolveData { pub struct InlayHintResolveData {
pub file_id: u32, pub file_id: u32,
pub hash: u64,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]

View file

@ -13,7 +13,7 @@ use ide::{
NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp, NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp,
SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize, SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
}; };
use ide_db::rust_doc::format_docs; use ide_db::{rust_doc::format_docs, FxHasher};
use itertools::Itertools; use itertools::Itertools;
use semver::VersionReq; use semver::VersionReq;
use serde_json::to_value; use serde_json::to_value;
@ -444,30 +444,42 @@ pub(crate) fn inlay_hint(
fields_to_resolve: &InlayFieldsToResolve, fields_to_resolve: &InlayFieldsToResolve,
line_index: &LineIndex, line_index: &LineIndex,
file_id: FileId, file_id: FileId,
inlay_hint: InlayHint, mut inlay_hint: InlayHint,
) -> Cancellable<lsp_types::InlayHint> { ) -> Cancellable<lsp_types::InlayHint> {
let needs_resolve = inlay_hint.needs_resolve; let resolve_hash = inlay_hint.needs_resolve().then(|| {
let (label, tooltip, mut something_to_resolve) = std::hash::BuildHasher::hash_one(
inlay_hint_label(snap, fields_to_resolve, needs_resolve, inlay_hint.label)?; &std::hash::BuildHasherDefault::<FxHasher>::default(),
&inlay_hint,
)
});
let mut something_to_resolve = false;
let text_edits = if snap let text_edits = if snap
.config .config
.visual_studio_code_version() .visual_studio_code_version()
// https://github.com/microsoft/vscode/issues/193124 // https://github.com/microsoft/vscode/issues/193124
.map_or(true, |version| VersionReq::parse(">=1.86.0").unwrap().matches(version)) .map_or(true, |version| VersionReq::parse(">=1.86.0").unwrap().matches(version))
&& needs_resolve && resolve_hash.is_some()
&& fields_to_resolve.resolve_text_edits && fields_to_resolve.resolve_text_edits
{ {
something_to_resolve |= inlay_hint.text_edit.is_some(); something_to_resolve |= inlay_hint.text_edit.is_some();
None None
} else { } else {
inlay_hint.text_edit.map(|it| text_edit_vec(line_index, it)) inlay_hint.text_edit.take().map(|it| text_edit_vec(line_index, it))
}; };
let (label, tooltip) = inlay_hint_label(
snap,
fields_to_resolve,
&mut something_to_resolve,
resolve_hash.is_some(),
inlay_hint.label,
)?;
let data = if needs_resolve && something_to_resolve { let data = match resolve_hash {
Some(to_value(lsp_ext::InlayHintResolveData { file_id: file_id.index() }).unwrap()) Some(hash) if something_to_resolve => Some(
} else { to_value(lsp_ext::InlayHintResolveData { file_id: file_id.index(), hash }).unwrap(),
None ),
_ => None,
}; };
Ok(lsp_types::InlayHint { Ok(lsp_types::InlayHint {
@ -492,15 +504,15 @@ pub(crate) fn inlay_hint(
fn inlay_hint_label( fn inlay_hint_label(
snap: &GlobalStateSnapshot, snap: &GlobalStateSnapshot,
fields_to_resolve: &InlayFieldsToResolve, fields_to_resolve: &InlayFieldsToResolve,
something_to_resolve: &mut bool,
needs_resolve: bool, needs_resolve: bool,
mut label: InlayHintLabel, mut label: InlayHintLabel,
) -> Cancellable<(lsp_types::InlayHintLabel, Option<lsp_types::InlayHintTooltip>, bool)> { ) -> Cancellable<(lsp_types::InlayHintLabel, Option<lsp_types::InlayHintTooltip>)> {
let mut something_to_resolve = false;
let (label, tooltip) = match &*label.parts { let (label, tooltip) = match &*label.parts {
[InlayHintLabelPart { linked_location: None, .. }] => { [InlayHintLabelPart { linked_location: None, .. }] => {
let InlayHintLabelPart { text, tooltip, .. } = label.parts.pop().unwrap(); let InlayHintLabelPart { text, tooltip, .. } = label.parts.pop().unwrap();
let hint_tooltip = if needs_resolve && fields_to_resolve.resolve_hint_tooltip { let hint_tooltip = if needs_resolve && fields_to_resolve.resolve_hint_tooltip {
something_to_resolve |= tooltip.is_some(); *something_to_resolve |= tooltip.is_some();
None None
} else { } else {
match tooltip { match tooltip {
@ -524,7 +536,7 @@ fn inlay_hint_label(
.into_iter() .into_iter()
.map(|part| { .map(|part| {
let tooltip = if needs_resolve && fields_to_resolve.resolve_label_tooltip { let tooltip = if needs_resolve && fields_to_resolve.resolve_label_tooltip {
something_to_resolve |= part.tooltip.is_some(); *something_to_resolve |= part.tooltip.is_some();
None None
} else { } else {
match part.tooltip { match part.tooltip {
@ -543,7 +555,7 @@ fn inlay_hint_label(
} }
}; };
let location = if needs_resolve && fields_to_resolve.resolve_label_location { let location = if needs_resolve && fields_to_resolve.resolve_label_location {
something_to_resolve |= part.linked_location.is_some(); *something_to_resolve |= part.linked_location.is_some();
None None
} else { } else {
part.linked_location.map(|range| location(snap, range)).transpose()? part.linked_location.map(|range| location(snap, range)).transpose()?
@ -559,7 +571,7 @@ fn inlay_hint_label(
(lsp_types::InlayHintLabel::LabelParts(parts), None) (lsp_types::InlayHintLabel::LabelParts(parts), None)
} }
}; };
Ok((label, tooltip, something_to_resolve)) Ok((label, tooltip))
} }
static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1); static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1);

View file

@ -1,5 +1,5 @@
<!--- <!---
lsp/ext.rs hash: 61f485497d6e8e88 lsp/ext.rs hash: d5febcbf63650753
If you need to change the above hash to make the test pass, please check if you If you need to change the above hash to make the test pass, please check if you
need to adjust this doc as well and ping this issue: need to adjust this doc as well and ping this issue:
@ -417,7 +417,7 @@ interface TestItem {
// A human readable name for this test // A human readable name for this test
label: string; label: string;
// The kind of this test item. Based on the kind, // The kind of this test item. Based on the kind,
// an icon is chosen by the editor. // an icon is chosen by the editor.
kind: "package" | "module" | "test"; kind: "package" | "module" | "test";
// True if this test may have children not available eagerly // True if this test may have children not available eagerly
canResolveChildren: boolean; canResolveChildren: boolean;
@ -492,9 +492,9 @@ a `experimental/endRunTest` when is done.
**Notification:** `ChangeTestStateParams` **Notification:** `ChangeTestStateParams`
```typescript ```typescript
type TestState = { tag: "passed" } type TestState = { tag: "passed" }
| { | {
tag: "failed"; tag: "failed";
// The standard error of the test, containing the panic message. Clients should // The standard error of the test, containing the panic message. Clients should
// render it similar to a terminal, and e.g. handle ansi colors. // render it similar to a terminal, and e.g. handle ansi colors.
message: string; message: string;