mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-29 10:58:02 +00:00
Merge pull request #18921 from Veykril/push-zwullmxomvsm
internal: Compute inlay hint text edits lazily
This commit is contained in:
commit
69ab0cfb48
9 changed files with 150 additions and 57 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{self, Write},
|
fmt::{self, Write},
|
||||||
mem::take,
|
mem::{self, take},
|
||||||
};
|
};
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
|
|
@ -297,6 +297,17 @@ pub struct InlayHintsConfig {
|
||||||
pub closing_brace_hints_min_lines: Option<usize>,
|
pub closing_brace_hints_min_lines: Option<usize>,
|
||||||
pub fields_to_resolve: InlayFieldsToResolve,
|
pub fields_to_resolve: InlayFieldsToResolve,
|
||||||
}
|
}
|
||||||
|
impl InlayHintsConfig {
|
||||||
|
fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> Lazy<TextEdit> {
|
||||||
|
if self.fields_to_resolve.resolve_text_edits {
|
||||||
|
Lazy::Lazy
|
||||||
|
} else {
|
||||||
|
let edit = finish();
|
||||||
|
never!(edit.is_empty(), "inlay hint produced an empty text edit");
|
||||||
|
Lazy::Computed(edit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct InlayFieldsToResolve {
|
pub struct InlayFieldsToResolve {
|
||||||
|
|
@ -408,12 +419,32 @@ pub struct InlayHint {
|
||||||
/// The actual label to show in the inlay hint.
|
/// The actual label to show in the inlay hint.
|
||||||
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<Lazy<TextEdit>>,
|
||||||
/// Range to recompute inlay hints when trying to resolve for this hint. If this is none, the
|
/// Range to recompute inlay hints when trying to resolve for this hint. If this is none, the
|
||||||
/// hint does not support resolving.
|
/// hint does not support resolving.
|
||||||
pub resolve_parent: Option<TextRange>,
|
pub resolve_parent: Option<TextRange>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A type signaling that a value is either computed, or is available for computation.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Lazy<T> {
|
||||||
|
Computed(T),
|
||||||
|
Lazy,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Lazy<T> {
|
||||||
|
pub fn computed(self) -> Option<T> {
|
||||||
|
match self {
|
||||||
|
Lazy::Computed(it) => Some(it),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_lazy(&self) -> bool {
|
||||||
|
matches!(self, Self::Lazy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl std::hash::Hash for InlayHint {
|
impl std::hash::Hash for InlayHint {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
self.range.hash(state);
|
self.range.hash(state);
|
||||||
|
|
@ -422,7 +453,7 @@ impl std::hash::Hash for InlayHint {
|
||||||
self.pad_right.hash(state);
|
self.pad_right.hash(state);
|
||||||
self.kind.hash(state);
|
self.kind.hash(state);
|
||||||
self.label.hash(state);
|
self.label.hash(state);
|
||||||
self.text_edit.is_some().hash(state);
|
mem::discriminant(&self.text_edit).hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -439,10 +470,6 @@ impl InlayHint {
|
||||||
resolve_parent: None,
|
resolve_parent: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn needs_resolve(&self) -> Option<TextRange> {
|
|
||||||
self.resolve_parent.filter(|_| self.text_edit.is_some() || self.label.needs_resolve())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
|
|
@ -503,10 +530,6 @@ impl InlayHintLabel {
|
||||||
}
|
}
|
||||||
self.parts.push(part);
|
self.parts.push(part);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn needs_resolve(&self) -> bool {
|
|
||||||
self.parts.iter().any(|part| part.linked_location.is_some() || part.tooltip.is_some())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for InlayHintLabel {
|
impl From<String> for InlayHintLabel {
|
||||||
|
|
@ -725,19 +748,22 @@ fn hint_iterator(
|
||||||
|
|
||||||
fn ty_to_text_edit(
|
fn ty_to_text_edit(
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
sema: &Semantics<'_, RootDatabase>,
|
||||||
|
config: &InlayHintsConfig,
|
||||||
node_for_hint: &SyntaxNode,
|
node_for_hint: &SyntaxNode,
|
||||||
ty: &hir::Type,
|
ty: &hir::Type,
|
||||||
offset_to_insert: TextSize,
|
offset_to_insert: TextSize,
|
||||||
prefix: String,
|
prefix: impl Into<String>,
|
||||||
) -> Option<TextEdit> {
|
) -> Option<Lazy<TextEdit>> {
|
||||||
let scope = sema.scope(node_for_hint)?;
|
|
||||||
// FIXME: Limit the length and bail out on excess somehow?
|
// FIXME: Limit the length and bail out on excess somehow?
|
||||||
let rendered = ty.display_source_code(scope.db, scope.module().into(), false).ok()?;
|
let rendered = sema
|
||||||
|
.scope(node_for_hint)
|
||||||
let mut builder = TextEdit::builder();
|
.and_then(|scope| ty.display_source_code(scope.db, scope.module().into(), false).ok())?;
|
||||||
builder.insert(offset_to_insert, prefix);
|
Some(config.lazy_text_edit(|| {
|
||||||
builder.insert(offset_to_insert, rendered);
|
let mut builder = TextEdit::builder();
|
||||||
Some(builder.finish())
|
builder.insert(offset_to_insert, prefix.into());
|
||||||
|
builder.insert(offset_to_insert, rendered);
|
||||||
|
builder.finish()
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool {
|
fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool {
|
||||||
|
|
@ -847,7 +873,7 @@ mod tests {
|
||||||
|
|
||||||
let edits = inlay_hints
|
let edits = inlay_hints
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|hint| hint.text_edit)
|
.filter_map(|hint| hint.text_edit?.computed())
|
||||||
.reduce(|mut acc, next| {
|
.reduce(|mut acc, next| {
|
||||||
acc.union(next).expect("merging text edits failed");
|
acc.union(next).expect("merging text edits failed");
|
||||||
acc
|
acc
|
||||||
|
|
@ -867,7 +893,8 @@ mod tests {
|
||||||
let (analysis, file_id) = fixture::file(ra_fixture);
|
let (analysis, file_id) = fixture::file(ra_fixture);
|
||||||
let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
|
let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
|
||||||
|
|
||||||
let edits: Vec<_> = inlay_hints.into_iter().filter_map(|hint| hint.text_edit).collect();
|
let edits: Vec<_> =
|
||||||
|
inlay_hints.into_iter().filter_map(|hint| hint.text_edit?.computed()).collect();
|
||||||
|
|
||||||
assert!(edits.is_empty(), "unexpected edits: {edits:?}");
|
assert!(edits.is_empty(), "unexpected edits: {edits:?}");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ pub(super) fn hints(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if allow_edit {
|
if allow_edit {
|
||||||
let edit = {
|
let edit = Some(config.lazy_text_edit(|| {
|
||||||
let mut b = TextEditBuilder::default();
|
let mut b = TextEditBuilder::default();
|
||||||
if let Some(pre) = &pre {
|
if let Some(pre) = &pre {
|
||||||
b.insert(
|
b.insert(
|
||||||
|
|
@ -198,14 +198,14 @@ pub(super) fn hints(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
b.finish()
|
b.finish()
|
||||||
};
|
}));
|
||||||
match (&mut pre, &mut post) {
|
match (&mut pre, &mut post) {
|
||||||
(Some(pre), Some(post)) => {
|
(Some(pre), Some(post)) => {
|
||||||
pre.text_edit = Some(edit.clone());
|
pre.text_edit = edit.clone();
|
||||||
post.text_edit = Some(edit);
|
post.text_edit = edit;
|
||||||
}
|
}
|
||||||
(Some(pre), None) => pre.text_edit = Some(edit),
|
(Some(pre), None) => pre.text_edit = edit,
|
||||||
(None, Some(post)) => post.text_edit = Some(edit),
|
(None, Some(post)) => post.text_edit = edit,
|
||||||
(None, None) => (),
|
(None, None) => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,13 +78,14 @@ pub(super) fn hints(
|
||||||
let text_edit = if let Some(colon_token) = &type_ascriptable {
|
let text_edit = if let Some(colon_token) = &type_ascriptable {
|
||||||
ty_to_text_edit(
|
ty_to_text_edit(
|
||||||
sema,
|
sema,
|
||||||
|
config,
|
||||||
desc_pat.syntax(),
|
desc_pat.syntax(),
|
||||||
&ty,
|
&ty,
|
||||||
colon_token
|
colon_token
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or_else(|| pat.syntax().text_range(), |t| t.text_range())
|
.map_or_else(|| pat.syntax().text_range(), |t| t.text_range())
|
||||||
.end(),
|
.end(),
|
||||||
if colon_token.is_some() { String::new() } else { String::from(": ") },
|
if colon_token.is_some() { "" } else { ": " },
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
||||||
|
|
@ -99,17 +99,24 @@ pub(super) fn hints(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let hints @ [_, ..] = &mut acc[acc_base..] {
|
if let hints @ [_, ..] = &mut acc[acc_base..] {
|
||||||
let mut edit = TextEditBuilder::default();
|
let edit = config.lazy_text_edit(|| {
|
||||||
for h in &mut *hints {
|
let mut edit = TextEditBuilder::default();
|
||||||
edit.insert(
|
for h in &mut *hints {
|
||||||
match h.position {
|
edit.insert(
|
||||||
InlayHintPosition::Before => h.range.start(),
|
match h.position {
|
||||||
InlayHintPosition::After => h.range.end(),
|
InlayHintPosition::Before => h.range.start(),
|
||||||
},
|
InlayHintPosition::After => h.range.end(),
|
||||||
h.label.parts.iter().map(|p| &*p.text).chain(h.pad_right.then_some(" ")).collect(),
|
},
|
||||||
);
|
h.label
|
||||||
}
|
.parts
|
||||||
let edit = edit.finish();
|
.iter()
|
||||||
|
.map(|p| &*p.text)
|
||||||
|
.chain(h.pad_right.then_some(" "))
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
edit.finish()
|
||||||
|
});
|
||||||
hints.iter_mut().for_each(|h| h.text_edit = Some(edit.clone()));
|
hints.iter_mut().for_each(|h| h.text_edit = Some(edit.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,13 +52,14 @@ pub(super) fn hints(
|
||||||
let text_edit = if has_block_body {
|
let text_edit = if has_block_body {
|
||||||
ty_to_text_edit(
|
ty_to_text_edit(
|
||||||
sema,
|
sema,
|
||||||
|
config,
|
||||||
closure.syntax(),
|
closure.syntax(),
|
||||||
&ty,
|
&ty,
|
||||||
arrow
|
arrow
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or_else(|| param_list.syntax().text_range(), |t| t.text_range())
|
.map_or_else(|| param_list.syntax().text_range(), |t| t.text_range())
|
||||||
.end(),
|
.end(),
|
||||||
if arrow.is_none() { String::from(" -> ") } else { String::new() },
|
if arrow.is_none() { " -> " } else { "" },
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
||||||
|
|
@ -36,13 +36,14 @@ pub(super) fn enum_hints(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
for variant in enum_.variant_list()?.variants() {
|
for variant in enum_.variant_list()?.variants() {
|
||||||
variant_hints(acc, sema, &enum_, &variant);
|
variant_hints(acc, config, sema, &enum_, &variant);
|
||||||
}
|
}
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn variant_hints(
|
fn variant_hints(
|
||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
|
config: &InlayHintsConfig,
|
||||||
sema: &Semantics<'_, RootDatabase>,
|
sema: &Semantics<'_, RootDatabase>,
|
||||||
enum_: &ast::Enum,
|
enum_: &ast::Enum,
|
||||||
variant: &ast::Variant,
|
variant: &ast::Variant,
|
||||||
|
|
@ -88,7 +89,9 @@ fn variant_hints(
|
||||||
},
|
},
|
||||||
kind: InlayKind::Discriminant,
|
kind: InlayKind::Discriminant,
|
||||||
label,
|
label,
|
||||||
text_edit: d.ok().map(|val| TextEdit::insert(range.start(), format!("{eq_} {val}"))),
|
text_edit: d.ok().map(|val| {
|
||||||
|
config.lazy_text_edit(|| TextEdit::insert(range.end(), format!("{eq_} {val}")))
|
||||||
|
}),
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: false,
|
pad_right: false,
|
||||||
|
|
@ -99,8 +102,10 @@ fn variant_hints(
|
||||||
}
|
}
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use expect_test::expect;
|
||||||
|
|
||||||
use crate::inlay_hints::{
|
use crate::inlay_hints::{
|
||||||
tests::{check_with_config, DISABLED_CONFIG},
|
tests::{check_edit, check_with_config, DISABLED_CONFIG},
|
||||||
DiscriminantHints, InlayHintsConfig,
|
DiscriminantHints, InlayHintsConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -207,4 +212,33 @@ enum Enum {
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn edit() {
|
||||||
|
check_edit(
|
||||||
|
InlayHintsConfig { discriminant_hints: DiscriminantHints::Always, ..DISABLED_CONFIG },
|
||||||
|
r#"
|
||||||
|
#[repr(u8)]
|
||||||
|
enum Enum {
|
||||||
|
Variant(),
|
||||||
|
Variant1,
|
||||||
|
Variant2 {},
|
||||||
|
Variant3,
|
||||||
|
Variant5,
|
||||||
|
Variant6,
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
#[repr(u8)]
|
||||||
|
enum Enum {
|
||||||
|
Variant() = 0,
|
||||||
|
Variant1 = 1,
|
||||||
|
Variant2 {} = 2,
|
||||||
|
Variant3 = 3,
|
||||||
|
Variant5 = 4,
|
||||||
|
Variant6 = 5,
|
||||||
|
}
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use crate::{InlayHint, InlayHintsConfig};
|
||||||
pub(super) fn extern_block_hints(
|
pub(super) fn extern_block_hints(
|
||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
FamousDefs(_sema, _): &FamousDefs<'_, '_>,
|
FamousDefs(_sema, _): &FamousDefs<'_, '_>,
|
||||||
_config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
_file_id: EditionedFileId,
|
_file_id: EditionedFileId,
|
||||||
extern_block: ast::ExternBlock,
|
extern_block: ast::ExternBlock,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
|
|
@ -23,7 +23,9 @@ pub(super) fn extern_block_hints(
|
||||||
pad_right: true,
|
pad_right: true,
|
||||||
kind: crate::InlayKind::ExternUnsafety,
|
kind: crate::InlayKind::ExternUnsafety,
|
||||||
label: crate::InlayHintLabel::from("unsafe"),
|
label: crate::InlayHintLabel::from("unsafe"),
|
||||||
text_edit: Some(TextEdit::insert(abi.syntax().text_range().start(), "unsafe ".to_owned())),
|
text_edit: Some(config.lazy_text_edit(|| {
|
||||||
|
TextEdit::insert(abi.syntax().text_range().start(), "unsafe ".to_owned())
|
||||||
|
})),
|
||||||
resolve_parent: Some(extern_block.syntax().text_range()),
|
resolve_parent: Some(extern_block.syntax().text_range()),
|
||||||
});
|
});
|
||||||
Some(())
|
Some(())
|
||||||
|
|
@ -32,7 +34,7 @@ pub(super) fn extern_block_hints(
|
||||||
pub(super) fn fn_hints(
|
pub(super) fn fn_hints(
|
||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
FamousDefs(_sema, _): &FamousDefs<'_, '_>,
|
FamousDefs(_sema, _): &FamousDefs<'_, '_>,
|
||||||
_config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
_file_id: EditionedFileId,
|
_file_id: EditionedFileId,
|
||||||
fn_: &ast::Fn,
|
fn_: &ast::Fn,
|
||||||
extern_block: &ast::ExternBlock,
|
extern_block: &ast::ExternBlock,
|
||||||
|
|
@ -42,14 +44,14 @@ pub(super) fn fn_hints(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let fn_ = fn_.fn_token()?;
|
let fn_ = fn_.fn_token()?;
|
||||||
acc.push(item_hint(extern_block, fn_));
|
acc.push(item_hint(config, extern_block, fn_));
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn static_hints(
|
pub(super) fn static_hints(
|
||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
FamousDefs(_sema, _): &FamousDefs<'_, '_>,
|
FamousDefs(_sema, _): &FamousDefs<'_, '_>,
|
||||||
_config: &InlayHintsConfig,
|
config: &InlayHintsConfig,
|
||||||
_file_id: EditionedFileId,
|
_file_id: EditionedFileId,
|
||||||
static_: &ast::Static,
|
static_: &ast::Static,
|
||||||
extern_block: &ast::ExternBlock,
|
extern_block: &ast::ExternBlock,
|
||||||
|
|
@ -59,11 +61,15 @@ pub(super) fn static_hints(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let static_ = static_.static_token()?;
|
let static_ = static_.static_token()?;
|
||||||
acc.push(item_hint(extern_block, static_));
|
acc.push(item_hint(config, extern_block, static_));
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn item_hint(extern_block: &ast::ExternBlock, token: SyntaxToken) -> InlayHint {
|
fn item_hint(
|
||||||
|
config: &InlayHintsConfig,
|
||||||
|
extern_block: &ast::ExternBlock,
|
||||||
|
token: SyntaxToken,
|
||||||
|
) -> InlayHint {
|
||||||
InlayHint {
|
InlayHint {
|
||||||
range: token.text_range(),
|
range: token.text_range(),
|
||||||
position: crate::InlayHintPosition::Before,
|
position: crate::InlayHintPosition::Before,
|
||||||
|
|
@ -71,7 +77,7 @@ fn item_hint(extern_block: &ast::ExternBlock, token: SyntaxToken) -> InlayHint {
|
||||||
pad_right: true,
|
pad_right: true,
|
||||||
kind: crate::InlayKind::ExternUnsafety,
|
kind: crate::InlayKind::ExternUnsafety,
|
||||||
label: crate::InlayHintLabel::from("unsafe"),
|
label: crate::InlayHintLabel::from("unsafe"),
|
||||||
text_edit: {
|
text_edit: Some(config.lazy_text_edit(|| {
|
||||||
let mut builder = TextEdit::builder();
|
let mut builder = TextEdit::builder();
|
||||||
builder.insert(token.text_range().start(), "unsafe ".to_owned());
|
builder.insert(token.text_range().start(), "unsafe ".to_owned());
|
||||||
if extern_block.unsafe_token().is_none() {
|
if extern_block.unsafe_token().is_none() {
|
||||||
|
|
@ -79,8 +85,8 @@ fn item_hint(extern_block: &ast::ExternBlock, token: SyntaxToken) -> InlayHint {
|
||||||
builder.insert(abi.syntax().text_range().start(), "unsafe ".to_owned());
|
builder.insert(abi.syntax().text_range().start(), "unsafe ".to_owned());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(builder.finish())
|
builder.finish()
|
||||||
},
|
})),
|
||||||
resolve_parent: Some(extern_block.syntax().text_range()),
|
resolve_parent: Some(extern_block.syntax().text_range()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,9 @@ pub(super) fn hints(
|
||||||
range: t.text_range(),
|
range: t.text_range(),
|
||||||
kind: InlayKind::Lifetime,
|
kind: InlayKind::Lifetime,
|
||||||
label: "'static".into(),
|
label: "'static".into(),
|
||||||
text_edit: Some(TextEdit::insert(t.text_range().start(), "'static ".into())),
|
text_edit: Some(config.lazy_text_edit(|| {
|
||||||
|
TextEdit::insert(t.text_range().start(), "'static ".into())
|
||||||
|
})),
|
||||||
position: InlayHintPosition::After,
|
position: InlayHintPosition::After,
|
||||||
pad_left: false,
|
pad_left: false,
|
||||||
pad_right: true,
|
pad_right: true,
|
||||||
|
|
|
||||||
|
|
@ -547,7 +547,18 @@ pub(crate) fn inlay_hint(
|
||||||
file_id: FileId,
|
file_id: FileId,
|
||||||
mut inlay_hint: InlayHint,
|
mut inlay_hint: InlayHint,
|
||||||
) -> Cancellable<lsp_types::InlayHint> {
|
) -> Cancellable<lsp_types::InlayHint> {
|
||||||
let resolve_range_and_hash = inlay_hint.needs_resolve().map(|range| {
|
let hint_needs_resolve = |hint: &InlayHint| -> Option<TextRange> {
|
||||||
|
hint.resolve_parent.filter(|_| {
|
||||||
|
hint.text_edit.is_some()
|
||||||
|
|| hint
|
||||||
|
.label
|
||||||
|
.parts
|
||||||
|
.iter()
|
||||||
|
.any(|part| part.linked_location.is_some() || part.tooltip.is_some())
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let resolve_range_and_hash = hint_needs_resolve(&inlay_hint).map(|range| {
|
||||||
(
|
(
|
||||||
range,
|
range,
|
||||||
std::hash::BuildHasher::hash_one(
|
std::hash::BuildHasher::hash_one(
|
||||||
|
|
@ -568,7 +579,11 @@ pub(crate) fn inlay_hint(
|
||||||
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.take().map(|it| text_edit_vec(line_index, it))
|
inlay_hint
|
||||||
|
.text_edit
|
||||||
|
.take()
|
||||||
|
.and_then(|it| it.computed())
|
||||||
|
.map(|it| text_edit_vec(line_index, it))
|
||||||
};
|
};
|
||||||
let (label, tooltip) = inlay_hint_label(
|
let (label, tooltip) = inlay_hint_label(
|
||||||
snap,
|
snap,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue