mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-29 06:23:25 +00:00
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:
commit
f40c7d8a9c
19 changed files with 113 additions and 90 deletions
|
@ -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<'_, '_>,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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(")"),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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,
|
||||||
})
|
})
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>> {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue