Auto merge of #15522 - SomeoneToIgnore:resolve-inlay-hints, r=Veykril

Resolve inlay hint data

Part of https://github.com/rust-lang/rust-analyzer/issues/13962

Support https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#inlayHint_resolve better, by omitting all inlay hint fields specified in the client hint resolve capabilities.

Current list of all capabilities possible to resolve later:
```
"textEdits"
"tooltip"
"label.tooltip"
"label.location"
"label.command"
```

and every one specified in the client capabilities is now resolved by r-a, being omitted in the initial response.

--------------

When editing `inlay_hints.rs` file around line `457` with no resolve capabilities, I get
<details>
  <summary>resolved json, 10803 characters</summary>

```json
{"jsonrpc":"2.0","id":55,"result":[{"position":{"line":477,"character":1},"label":[{"value":"fn inlay_hints","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/ide/src/inlay_hints.rs","range":{"start":{"line":445,"character":14},"end":{"line":445,"character":25}}}}],"paddingLeft":true,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":451,"character":10},"label":[{"value":": "},{"value":"ProfileSpan","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/profile/src/hprof.rs","range":{"start":{"line":85,"character":11},"end":{"line":85,"character":22}}}},{"value":""}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":451,"character":27},"label":[{"value":"label:","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/profile/src/hprof.rs","range":{"start":{"line":60,"character":12},"end":{"line":60,"character":17}}}}],"kind":2,"paddingLeft":false,"paddingRight":true,"data":{"file_id":0}},{"position":{"line":452,"character":12},"label":[{"value":": "},{"value":"Semantics","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/hir/src/semantics.rs","range":{"start":{"line":108,"character":11},"end":{"line":108,"character":20}}}},{"value":"<'_, "},{"value":"RootDatabase","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/ide-db/src/lib.rs","range":{"start":{"line":75,"character":11},"end":{"line":75,"character":23}}}},{"value":">"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":453,"character":12},"label":[{"value":": "},{"value":"SourceFile","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs","range":{"start":{"line":223,"character":11},"end":{"line":223,"character":21}}}},{"value":""}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":454,"character":12},"label":[{"value":": &"},{"value":"SyntaxNode","location":{"uri":"file:///Users/someonetoignore/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rowan-0.15.11/src/api.rs","range":{"start":{"line":15,"character":11},"end":{"line":15,"character":21}}}},{"value":"<"},{"value":"RustLanguage","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/syntax/src/syntax_node.rs","range":{"start":{"line":15,"character":9},"end":{"line":15,"character":21}}}},{"value":">"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":456,"character":12},"label":": i32","kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":458,"character":15},"label":[{"value":": "},{"value":"Vec","location":{"uri":"file:///Users/someonetoignore/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/vec/mod.rs","range":{"start":{"line":395,"character":11},"end":{"line":395,"character":14}}}},{"value":"<"},{"value":"InlayHint","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/ide/src/inlay_hints.rs","range":{"start":{"line":149,"character":11},"end":{"line":149,"character":20}}}},{"value":">"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":460,"character":21},"label":[{"value":": "},{"value":"SemanticsScope","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/hir/src/semantics.rs","range":{"start":{"line":1651,"character":11},"end":{"line":1651,"character":25}}}},{"value":"<'_>"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":460,"character":36},"label":[{"value":"node:","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/hir/src/semantics.rs","range":{"start":{"line":482,"character":24},"end":{"line":482,"character":28}}}}],"kind":2,"paddingLeft":false,"paddingRight":true,"data":{"file_id":0}},{"position":{"line":461,"character":23},"label":[{"value":": "},{"value":"FamousDefs","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/ide-db/src/famous_defs.rs","range":{"start":{"line":20,"character":11},"end":{"line":20,"character":21}}}},{"value":"<'_, '_>"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":463,"character":17},"label":[{"value":": impl FnMut("},{"value":"SyntaxNode","location":{"uri":"file:///Users/someonetoignore/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rowan-0.15.11/src/api.rs","range":{"start":{"line":15,"character":11},"end":{"line":15,"character":21}}}},{"value":"<"},{"value":"RustLanguage","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/syntax/src/syntax_node.rs","range":{"start":{"line":15,"character":9},"end":{"line":15,"character":21}}}},{"value":">)"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":463,"character":25},"label":[{"value":": "},{"value":"SyntaxNode","location":{"uri":"file:///Users/someonetoignore/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rowan-0.15.11/src/api.rs","range":{"start":{"line":15,"character":11},"end":{"line":15,"character":21}}}},{"value":"<"},{"value":"RustLanguage","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/syntax/src/syntax_node.rs","range":{"start":{"line":15,"character":9},"end":{"line":15,"character":21}}}},{"value":">"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":463,"character":33},"label":[{"value":"hints:","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/ide/src/inlay_hints.rs","range":{"start":{"line":480,"character":4},"end":{"line":480,"character":9}}}}],"kind":2,"paddingLeft":false,"paddingRight":true,"data":{"file_id":0}},{"position":{"line":465,"character":22},"label":[{"value":": "},{"value":"TextRange","location":{"uri":"file:///Users/someonetoignore/.cargo/registry/src/index.crates.io-6f17d22bba15001f/text-size-1.1.0/src/range.rs","range":{"start":{"line":14,"character":11},"end":{"line":14,"character":20}}}},{"value":""}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":467,"character":35},"label":[{"value":": "},{"value":"SyntaxNode","location":{"uri":"file:///Users/someonetoignore/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rowan-0.15.11/src/api.rs","range":{"start":{"line":15,"character":11},"end":{"line":15,"character":21}}}},{"value":"<"},{"value":"RustLanguage","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/syntax/src/syntax_node.rs","range":{"start":{"line":15,"character":9},"end":{"line":15,"character":21}}}},{"value":">"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":469,"character":92},"label":[{"value":"impl "},{"value":"Iterator","location":{"uri":"file:///Users/someonetoignore/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs","range":{"start":{"line":72,"character":10},"end":{"line":72,"character":18}}}},{"value":"<"},{"value":"Item","location":{"uri":"file:///Users/someonetoignore/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs","range":{"start":{"line":76,"character":9},"end":{"line":76,"character":13}}}},{"value":" = "},{"value":"SyntaxNode","location":{"uri":"file:///Users/someonetoignore/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rowan-0.15.11/src/api.rs","range":{"start":{"line":15,"character":11},"end":{"line":15,"character":21}}}},{"value":"<"},{"value":"RustLanguage","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/syntax/src/syntax_node.rs","range":{"start":{"line":15,"character":9},"end":{"line":15,"character":21}}}},{"value":">>"}],"kind":1,"paddingLeft":true,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":468,"character":34},"label":[{"value":"impl "},{"value":"Iterator","location":{"uri":"file:///Users/someonetoignore/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs","range":{"start":{"line":72,"character":10},"end":{"line":72,"character":18}}}},{"value":"<"},{"value":"Item","location":{"uri":"file:///Users/someonetoignore/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs","range":{"start":{"line":76,"character":9},"end":{"line":76,"character":13}}}},{"value":" = "},{"value":"SyntaxNode","location":{"uri":"file:///Users/someonetoignore/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rowan-0.15.11/src/api.rs","range":{"start":{"line":15,"character":11},"end":{"line":15,"character":21}}}},{"value":"<"},{"value":"RustLanguage","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/syntax/src/syntax_node.rs","range":{"start":{"line":15,"character":9},"end":{"line":15,"character":21}}}},{"value":">>"},{"value":""}],"kind":1,"paddingLeft":true,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":467,"character":41},"label":[{"value":""},{"value":"SyntaxNode","location":{"uri":"file:///Users/someonetoignore/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rowan-0.15.11/src/api.rs","range":{"start":{"line":15,"character":11},"end":{"line":15,"character":21}}}},{"value":"<"},{"value":"RustLanguage","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/syntax/src/syntax_node.rs","range":{"start":{"line":15,"character":9},"end":{"line":15,"character":21}}}},{"value":">"}],"kind":1,"paddingLeft":true,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":469,"character":40},"label":" -> bool","kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":469,"character":39},"label":[{"value":": &"},{"value":"SyntaxNode","location":{"uri":"file:///Users/someonetoignore/.cargo/registry/src/index.crates.io-6f17d22bba15001f/rowan-0.15.11/src/api.rs","range":{"start":{"line":15,"character":11},"end":{"line":15,"character":21}}}},{"value":"<"},{"value":"RustLanguage","location":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/syntax/src/syntax_node.rs","range":{"start":{"line":15,"character":9},"end":{"line":15,"character":21}}}},{"value":">"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}}]}
```

</details>

for the visible editor range alone, pretty much repeated on every consequent edit.

With this patch and all inlay hint resolve capabilities enabled, for the same example I observe quite a footprint reduction:

<details>
  <summary>unresolved json, 4142 characters</summary>

```json
{"jsonrpc":"2.0","id":49,"result":[{"position":{"line":477,"character":1},"label":[{"value":"fn inlay_hints"}],"paddingLeft":true,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":451,"character":10},"label":[{"value":": "},{"value":"ProfileSpan"},{"value":""}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":451,"character":27},"label":[{"value":"label:"}],"kind":2,"paddingLeft":false,"paddingRight":true,"data":{"file_id":0}},{"position":{"line":452,"character":12},"label":[{"value":": "},{"value":"Semantics"},{"value":"<'_, "},{"value":"RootDatabase"},{"value":">"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":453,"character":12},"label":[{"value":": "},{"value":"SourceFile"},{"value":""}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":454,"character":12},"label":[{"value":": &"},{"value":"SyntaxNode"},{"value":"<"},{"value":"RustLanguage"},{"value":">"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":456,"character":12},"label":": i32","kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":458,"character":15},"label":[{"value":": "},{"value":"Vec"},{"value":"<"},{"value":"InlayHint"},{"value":">"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":460,"character":21},"label":[{"value":": "},{"value":"SemanticsScope"},{"value":"<'_>"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":460,"character":36},"label":[{"value":"node:"}],"kind":2,"paddingLeft":false,"paddingRight":true,"data":{"file_id":0}},{"position":{"line":461,"character":23},"label":[{"value":": "},{"value":"FamousDefs"},{"value":"<'_, '_>"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":463,"character":17},"label":[{"value":": impl FnMut("},{"value":"SyntaxNode"},{"value":"<"},{"value":"RustLanguage"},{"value":">)"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":463,"character":25},"label":[{"value":": "},{"value":"SyntaxNode"},{"value":"<"},{"value":"RustLanguage"},{"value":">"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":463,"character":33},"label":[{"value":"hints:"}],"kind":2,"paddingLeft":false,"paddingRight":true,"data":{"file_id":0}},{"position":{"line":465,"character":22},"label":[{"value":": "},{"value":"TextRange"},{"value":""}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":467,"character":35},"label":[{"value":": "},{"value":"SyntaxNode"},{"value":"<"},{"value":"RustLanguage"},{"value":">"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":469,"character":92},"label":[{"value":"impl "},{"value":"Iterator"},{"value":"<"},{"value":"Item"},{"value":" = "},{"value":"SyntaxNode"},{"value":"<"},{"value":"RustLanguage"},{"value":">>"}],"kind":1,"paddingLeft":true,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":468,"character":34},"label":[{"value":"impl "},{"value":"Iterator"},{"value":"<"},{"value":"Item"},{"value":" = "},{"value":"SyntaxNode"},{"value":"<"},{"value":"RustLanguage"},{"value":">>"},{"value":""}],"kind":1,"paddingLeft":true,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":467,"character":41},"label":[{"value":""},{"value":"SyntaxNode"},{"value":"<"},{"value":"RustLanguage"},{"value":">"}],"kind":1,"paddingLeft":true,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":469,"character":40},"label":" -> bool","kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}},{"position":{"line":469,"character":39},"label":[{"value":": &"},{"value":"SyntaxNode"},{"value":"<"},{"value":"RustLanguage"},{"value":">"}],"kind":1,"paddingLeft":false,"paddingRight":false,"data":{"file_id":0}}]}
```

</details>

with all unresolved parts needing only for navigation, hover or applying the hint edit — dynamic parts that are made after mouse hover or similar events, that resolve the hint data.
This commit is contained in:
bors 2023-09-08 11:12:27 +00:00
commit 70a6cf0ef7
22 changed files with 274 additions and 82 deletions

View File

@ -52,6 +52,28 @@ pub struct InlayHintsConfig {
pub closure_style: ClosureStyle, pub closure_style: ClosureStyle,
pub max_length: Option<usize>, pub max_length: Option<usize>,
pub closing_brace_hints_min_lines: Option<usize>, pub closing_brace_hints_min_lines: Option<usize>,
pub fields_to_resolve: InlayFieldsToResolve,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct InlayFieldsToResolve {
pub resolve_text_edits: bool,
pub resolve_hint_tooltip: bool,
pub resolve_label_tooltip: bool,
pub resolve_label_location: bool,
pub resolve_label_command: bool,
}
impl InlayFieldsToResolve {
pub const fn empty() -> Self {
Self {
resolve_text_edits: false,
resolve_hint_tooltip: false,
resolve_label_tooltip: false,
resolve_label_location: false,
resolve_label_command: false,
}
}
} }
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
@ -123,11 +145,13 @@ 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 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(")"),
@ -139,6 +163,7 @@ impl InlayHint {
} }
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("("),
@ -196,6 +221,10 @@ impl InlayHintLabel {
}), }),
} }
} }
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 {
@ -529,6 +558,7 @@ fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use expect_test::Expect; use expect_test::Expect;
use hir::ClosureStyle; use hir::ClosureStyle;
use itertools::Itertools; use itertools::Itertools;
@ -538,7 +568,7 @@ mod tests {
use crate::DiscriminantHints; use crate::DiscriminantHints;
use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints}; use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints};
use super::ClosureReturnTypeHints; use super::{ClosureReturnTypeHints, InlayFieldsToResolve};
pub(super) const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig { pub(super) const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig {
discriminant_hints: DiscriminantHints::Never, discriminant_hints: DiscriminantHints::Never,
@ -559,6 +589,7 @@ mod tests {
param_names_for_lifetime_elision_hints: false, param_names_for_lifetime_elision_hints: false,
max_length: None, max_length: None,
closing_brace_hints_min_lines: None, closing_brace_hints_min_lines: None,
fields_to_resolve: InlayFieldsToResolve::empty(),
}; };
pub(super) const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig { pub(super) const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
type_hints: true, type_hints: true,

View File

@ -137,13 +137,7 @@ pub(super) fn hints(
} }
_ => continue, _ => continue,
}; };
acc.push(InlayHint { let label = InlayHintLabel::simple(
range: expr.syntax().text_range(),
pad_left: false,
pad_right: false,
position: if postfix { InlayHintPosition::After } else { InlayHintPosition::Before },
kind: InlayKind::Adjustment,
label: InlayHintLabel::simple(
if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() }, if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() },
Some(InlayTooltip::Markdown(format!( Some(InlayTooltip::Markdown(format!(
"`{}` → `{}` ({coercion} coercion)", "`{}` → `{}` ({coercion} coercion)",
@ -151,7 +145,15 @@ pub(super) fn hints(
target.display(sema.db), target.display(sema.db),
))), ))),
None, None,
), );
acc.push(InlayHint {
needs_resolve: label.needs_resolve(),
range: expr.syntax().text_range(),
pad_left: false,
pad_right: false,
position: if postfix { InlayHintPosition::After } else { InlayHintPosition::Before },
kind: InlayKind::Adjustment,
label,
text_edit: None, text_edit: None,
}); });
} }

View File

@ -99,6 +99,7 @@ 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,

View File

@ -50,9 +50,10 @@ 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.to_string().into(), label: r.into(),
text_edit: None, text_edit: None,
position: InlayHintPosition::Before, position: InlayHintPosition::Before,
pad_left: false, pad_left: false,
@ -68,9 +69,10 @@ 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.to_string().into(), label: bm.into(),
text_edit: None, text_edit: None,
position: InlayHintPosition::Before, position: InlayHintPosition::Before,
pad_left: false, pad_left: false,

View File

@ -57,10 +57,12 @@ pub(super) fn hints(
} }
} }
} }
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_of_ty(famous_defs, config, &ty)?, label,
text_edit: None, text_edit: None,
position: InlayHintPosition::After, position: InlayHintPosition::After,
pad_left: true, pad_left: true,
@ -128,6 +130,7 @@ fn main() {
"", "",
], ],
text_edit: None, text_edit: None,
needs_resolve: true,
}, },
InlayHint { InlayHint {
range: 147..154, range: 147..154,
@ -152,6 +155,7 @@ fn main() {
"", "",
], ],
text_edit: None, text_edit: None,
needs_resolve: true,
}, },
] ]
"#]], "#]],
@ -221,6 +225,7 @@ fn main() {
"", "",
], ],
text_edit: None, text_edit: None,
needs_resolve: true,
}, },
InlayHint { InlayHint {
range: 143..179, range: 143..179,
@ -245,6 +250,7 @@ fn main() {
"", "",
], ],
text_edit: None, text_edit: None,
needs_resolve: true,
}, },
] ]
"#]], "#]],
@ -298,6 +304,7 @@ fn main() {
"", "",
], ],
text_edit: None, text_edit: None,
needs_resolve: true,
}, },
InlayHint { InlayHint {
range: 143..179, range: 143..179,
@ -322,6 +329,7 @@ fn main() {
"", "",
], ],
text_edit: None, text_edit: None,
needs_resolve: true,
}, },
] ]
"#]], "#]],
@ -389,6 +397,7 @@ fn main() {
"<i32, bool>>", "<i32, bool>>",
], ],
text_edit: None, text_edit: None,
needs_resolve: true,
}, },
InlayHint { InlayHint {
range: 246..265, range: 246..265,
@ -426,6 +435,7 @@ fn main() {
"<i32, bool>>", "<i32, bool>>",
], ],
text_edit: None, text_edit: None,
needs_resolve: true,
}, },
] ]
"#]], "#]],
@ -495,6 +505,7 @@ fn main() {
" = ()>", " = ()>",
], ],
text_edit: None, text_edit: None,
needs_resolve: true,
}, },
InlayHint { InlayHint {
range: 174..224, range: 174..224,
@ -532,6 +543,7 @@ fn main() {
" = ()>", " = ()>",
], ],
text_edit: None, text_edit: None,
needs_resolve: true,
}, },
InlayHint { InlayHint {
range: 174..206, range: 174..206,
@ -569,6 +581,7 @@ fn main() {
" = ()>", " = ()>",
], ],
text_edit: None, text_edit: None,
needs_resolve: true,
}, },
InlayHint { InlayHint {
range: 174..189, range: 174..189,
@ -593,6 +606,7 @@ fn main() {
"", "",
], ],
text_edit: None, text_edit: None,
needs_resolve: true,
}, },
] ]
"#]], "#]],
@ -655,6 +669,7 @@ fn main() {
], ],
}, },
), ),
needs_resolve: true,
}, },
InlayHint { InlayHint {
range: 145..185, range: 145..185,
@ -679,6 +694,7 @@ fn main() {
"", "",
], ],
text_edit: None, text_edit: None,
needs_resolve: true,
}, },
InlayHint { InlayHint {
range: 145..168, range: 145..168,
@ -703,6 +719,7 @@ fn main() {
"", "",
], ],
text_edit: None, text_edit: None,
needs_resolve: true,
}, },
InlayHint { InlayHint {
range: 222..228, range: 222..228,
@ -725,6 +742,7 @@ fn main() {
}, },
], ],
text_edit: None, text_edit: None,
needs_resolve: true,
}, },
] ]
"#]], "#]],

View File

@ -109,6 +109,7 @@ 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

@ -31,9 +31,10 @@ 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::simple("move", None, None), label: InlayHintLabel::from("move"),
text_edit: None, text_edit: None,
position: InlayHintPosition::After, position: InlayHintPosition::After,
pad_left: false, pad_left: false,
@ -43,6 +44,7 @@ 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("("),
@ -59,10 +61,7 @@ pub(super) fn hints(
// force cache the source file, otherwise sema lookup will potentially panic // force cache the source file, otherwise sema lookup will potentially panic
_ = sema.parse_or_expand(source.file()); _ = sema.parse_or_expand(source.file());
acc.push(InlayHint { let label = InlayHintLabel::simple(
range: move_kw_range,
kind: InlayKind::ClosureCapture,
label: InlayHintLabel::simple(
format!( format!(
"{}{}", "{}{}",
match capture.kind() { match capture.kind() {
@ -75,7 +74,12 @@ pub(super) fn hints(
), ),
None, None,
source.name().and_then(|name| name.syntax().original_file_range_opt(sema.db)), source.name().and_then(|name| name.syntax().original_file_range_opt(sema.db)),
), );
acc.push(InlayHint {
needs_resolve: label.needs_resolve(),
range: move_kw_range,
kind: InlayKind::ClosureCapture,
label,
text_edit: None, text_edit: None,
position: InlayHintPosition::After, position: InlayHintPosition::After,
pad_left: false, pad_left: false,
@ -84,9 +88,10 @@ 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::simple(", ", None, None), label: InlayHintLabel::from(", "),
text_edit: None, text_edit: None,
position: InlayHintPosition::After, position: InlayHintPosition::After,
pad_left: false, pad_left: false,
@ -95,6 +100,7 @@ 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,6 +64,7 @@ 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,6 +79,7 @@ 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,6 +22,7 @@ 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(),
@ -185,6 +186,7 @@ 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,6 +202,7 @@ 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

@ -31,9 +31,10 @@ 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".to_owned().into(), label: "'static".into(),
text_edit: None, text_edit: None,
position: InlayHintPosition::After, position: InlayHintPosition::After,
pad_left: false, pad_left: false,

View File

@ -57,6 +57,7 @@ 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

@ -91,9 +91,9 @@ pub use crate::{
MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
}, },
inlay_hints::{ inlay_hints::{
AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints, InlayHint, AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints,
InlayHintLabel, InlayHintLabelPart, InlayHintPosition, InlayHintsConfig, InlayKind, InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintPosition,
InlayTooltip, LifetimeElisionHints, InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
}, },
join_lines::JoinLinesConfig, join_lines::JoinLinesConfig,
markup::Markup, markup::Markup,

View File

@ -12,6 +12,7 @@ use ide_db::{
}; };
use syntax::{AstNode, SyntaxKind::*, TextRange, T}; use syntax::{AstNode, SyntaxKind::*, TextRange, T};
use crate::inlay_hints::InlayFieldsToResolve;
use crate::{ use crate::{
hover::hover_for_definition, hover::hover_for_definition,
inlay_hints::AdjustmentHintsMode, inlay_hints::AdjustmentHintsMode,
@ -125,6 +126,7 @@ impl StaticIndex<'_> {
max_length: Some(25), max_length: Some(25),
closure_capture_hints: false, closure_capture_hints: false,
closing_brace_hints_min_lines: Some(25), closing_brace_hints_min_lines: Some(25),
fields_to_resolve: InlayFieldsToResolve::empty(),
}, },
file_id, file_id,
None, None,

View File

@ -15,7 +15,10 @@ use hir_def::{
hir::{ExprId, PatId}, hir::{ExprId, PatId},
}; };
use hir_ty::{Interner, Substitution, TyExt, TypeFlags}; use hir_ty::{Interner, Substitution, TyExt, TypeFlags};
use ide::{Analysis, AnnotationConfig, DiagnosticsConfig, InlayHintsConfig, LineCol, RootDatabase}; use ide::{
Analysis, AnnotationConfig, DiagnosticsConfig, InlayFieldsToResolve, InlayHintsConfig, LineCol,
RootDatabase,
};
use ide_db::{ use ide_db::{
base_db::{ base_db::{
salsa::{self, debug::DebugQueryTable, ParallelDatabase}, salsa::{self, debug::DebugQueryTable, ParallelDatabase},
@ -786,6 +789,7 @@ impl flags::AnalysisStats {
closure_style: hir::ClosureStyle::ImplFn, closure_style: hir::ClosureStyle::ImplFn,
max_length: Some(25), max_length: Some(25),
closing_brace_hints_min_lines: Some(20), closing_brace_hints_min_lines: Some(20),
fields_to_resolve: InlayFieldsToResolve::empty(),
}, },
file_id, file_id,
None, None,

View File

@ -13,8 +13,9 @@ use cfg::{CfgAtom, CfgDiff};
use flycheck::FlycheckConfig; use flycheck::FlycheckConfig;
use ide::{ use ide::{
AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode, AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayHintsConfig, HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve,
JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope, InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
Snippet, SnippetScope,
}; };
use ide_db::{ use ide_db::{
imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind}, imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
@ -1335,6 +1336,18 @@ impl Config {
} }
pub fn inlay_hints(&self) -> InlayHintsConfig { pub fn inlay_hints(&self) -> InlayHintsConfig {
let client_capability_fields = self
.caps
.text_document
.as_ref()
.and_then(|text| text.inlay_hint.as_ref())
.and_then(|inlay_hint_caps| inlay_hint_caps.resolve_support.as_ref())
.map(|inlay_resolve| inlay_resolve.properties.iter())
.into_iter()
.flatten()
.cloned()
.collect::<FxHashSet<_>>();
InlayHintsConfig { InlayHintsConfig {
render_colons: self.data.inlayHints_renderColons, render_colons: self.data.inlayHints_renderColons,
type_hints: self.data.inlayHints_typeHints_enable, type_hints: self.data.inlayHints_typeHints_enable,
@ -1395,6 +1408,13 @@ impl Config {
} else { } else {
None None
}, },
fields_to_resolve: InlayFieldsToResolve {
resolve_text_edits: client_capability_fields.contains("textEdits"),
resolve_hint_tooltip: client_capability_fields.contains("tooltip"),
resolve_label_tooltip: client_capability_fields.contains("label.tooltip"),
resolve_label_location: client_capability_fields.contains("label.location"),
resolve_label_command: client_capability_fields.contains("label.command"),
},
} }
} }

View File

@ -498,6 +498,10 @@ impl GlobalStateSnapshot {
pub(crate) fn vfs_memory_usage(&self) -> usize { pub(crate) fn vfs_memory_usage(&self) -> usize {
self.vfs_read().memory_usage() self.vfs_read().memory_usage()
} }
pub(crate) fn file_exists(&self, file_id: FileId) -> bool {
self.vfs.read().0.exists(file_id)
}
} }
pub(crate) fn file_id_to_url(vfs: &vfs::Vfs, id: FileId) -> Url { pub(crate) fn file_id_to_url(vfs: &vfs::Vfs, id: FileId) -> Url {

View File

@ -11,8 +11,8 @@ use anyhow::Context;
use ide::{ use ide::{
AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, FilePosition, FileRange, AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, FilePosition, FileRange,
HoverAction, HoverGotoTypeData, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind, HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory,
SingleResolve, SourceChange, TextEdit, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit,
}; };
use ide_db::SymbolKind; use ide_db::SymbolKind;
use lsp_server::ErrorCode; use lsp_server::ErrorCode;
@ -30,7 +30,7 @@ use serde_json::json;
use stdx::{format_to, never}; use stdx::{format_to, never};
use syntax::{algo, ast, AstNode, TextRange, TextSize}; use syntax::{algo, ast, AstNode, TextRange, TextSize};
use triomphe::Arc; use triomphe::Arc;
use vfs::{AbsPath, AbsPathBuf, VfsPath}; use vfs::{AbsPath, AbsPathBuf, FileId, VfsPath};
use crate::{ use crate::{
cargo_target_spec::CargoTargetSpec, cargo_target_spec::CargoTargetSpec,
@ -1412,17 +1412,73 @@ pub(crate) fn handle_inlay_hints(
snap.analysis snap.analysis
.inlay_hints(&inlay_hints_config, file_id, Some(range))? .inlay_hints(&inlay_hints_config, file_id, Some(range))?
.into_iter() .into_iter()
.map(|it| to_proto::inlay_hint(&snap, &line_index, it)) .map(|it| {
to_proto::inlay_hint(
&snap,
&inlay_hints_config.fields_to_resolve,
&line_index,
file_id,
it,
)
})
.collect::<Cancellable<Vec<_>>>()?, .collect::<Cancellable<Vec<_>>>()?,
)) ))
} }
pub(crate) fn handle_inlay_hints_resolve( pub(crate) fn handle_inlay_hints_resolve(
_snap: GlobalStateSnapshot, snap: GlobalStateSnapshot,
hint: InlayHint, mut original_hint: InlayHint,
) -> anyhow::Result<InlayHint> { ) -> anyhow::Result<InlayHint> {
let _p = profile::span("handle_inlay_hints_resolve"); let _p = profile::span("handle_inlay_hints_resolve");
Ok(hint)
let data = match original_hint.data.take() {
Some(it) => it,
None => return Ok(original_hint),
};
let resolve_data: lsp_ext::InlayHintResolveData = serde_json::from_value(data)?;
let file_id = FileId(resolve_data.file_id);
anyhow::ensure!(snap.file_exists(file_id), "Invalid LSP resolve data");
let line_index = snap.file_line_index(file_id)?;
let range = from_proto::text_range(
&line_index,
lsp_types::Range { start: original_hint.position, end: original_hint.position },
)?;
let range_start = range.start();
let range_end = range.end();
let large_range = TextRange::new(
range_start.checked_sub(1.into()).unwrap_or(range_start),
range_end.checked_add(1.into()).unwrap_or(range_end),
);
let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints();
forced_resolve_inlay_hints_config.fields_to_resolve = InlayFieldsToResolve::empty();
let resolve_hints = snap.analysis.inlay_hints(
&forced_resolve_inlay_hints_config,
file_id,
Some(large_range),
)?;
let mut resolved_hints = resolve_hints
.into_iter()
.filter_map(|it| {
to_proto::inlay_hint(
&snap,
&forced_resolve_inlay_hints_config.fields_to_resolve,
&line_index,
file_id,
it,
)
.ok()
})
.filter(|hint| hint.position == original_hint.position)
.filter(|hint| hint.kind == original_hint.kind);
if let Some(resolved_hint) = resolved_hints.next() {
if resolved_hints.next().is_none() {
return Ok(resolved_hint);
}
}
Ok(original_hint)
} }
pub(crate) fn handle_call_hierarchy_prepare( pub(crate) fn handle_call_hierarchy_prepare(

View File

@ -682,7 +682,9 @@ pub struct CompletionResolveData {
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct InlayHintResolveData {} pub struct InlayHintResolveData {
pub file_id: u32,
}
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct CompletionImport { pub struct CompletionImport {

View File

@ -8,10 +8,10 @@ use std::{
use ide::{ use ide::{
Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem, Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem,
CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit, CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit,
Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint, Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel,
InlayHintLabel, InlayHintLabelPart, InlayKind, Markup, NavigationTarget, ReferenceCategory, InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayKind, Markup,
RenameError, Runnable, Severity, SignatureHelp, SnippetEdit, SourceChange, StructureNodeKind, NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp,
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;
use itertools::Itertools; use itertools::Itertools;
@ -438,10 +438,25 @@ pub(crate) fn signature_help(
pub(crate) fn inlay_hint( pub(crate) fn inlay_hint(
snap: &GlobalStateSnapshot, snap: &GlobalStateSnapshot,
fields_to_resolve: &InlayFieldsToResolve,
line_index: &LineIndex, line_index: &LineIndex,
file_id: FileId,
inlay_hint: InlayHint, inlay_hint: InlayHint,
) -> Cancellable<lsp_types::InlayHint> { ) -> Cancellable<lsp_types::InlayHint> {
let (label, tooltip) = inlay_hint_label(snap, inlay_hint.label)?; let needs_resolve = inlay_hint.needs_resolve;
let (label, tooltip, mut something_to_resolve) =
inlay_hint_label(snap, fields_to_resolve, needs_resolve, inlay_hint.label)?;
let text_edits = if needs_resolve && fields_to_resolve.resolve_text_edits {
something_to_resolve |= inlay_hint.text_edit.is_some();
None
} else {
inlay_hint.text_edit.map(|it| text_edit_vec(line_index, it))
};
let data = if needs_resolve && something_to_resolve {
Some(to_value(lsp_ext::InlayHintResolveData { file_id: file_id.0 }).unwrap())
} else {
None
};
Ok(lsp_types::InlayHint { Ok(lsp_types::InlayHint {
position: match inlay_hint.position { position: match inlay_hint.position {
@ -455,8 +470,8 @@ pub(crate) fn inlay_hint(
InlayKind::Type | InlayKind::Chaining => Some(lsp_types::InlayHintKind::TYPE), InlayKind::Type | InlayKind::Chaining => Some(lsp_types::InlayHintKind::TYPE),
_ => None, _ => None,
}, },
text_edits: inlay_hint.text_edit.map(|it| text_edit_vec(line_index, it)), text_edits,
data: None, data,
tooltip, tooltip,
label, label,
}) })
@ -464,13 +479,18 @@ pub(crate) fn inlay_hint(
fn inlay_hint_label( fn inlay_hint_label(
snap: &GlobalStateSnapshot, snap: &GlobalStateSnapshot,
fields_to_resolve: &InlayFieldsToResolve,
needs_resolve: bool,
mut label: InlayHintLabel, mut label: InlayHintLabel,
) -> Cancellable<(lsp_types::InlayHintLabel, Option<lsp_types::InlayHintTooltip>)> { ) -> Cancellable<(lsp_types::InlayHintLabel, Option<lsp_types::InlayHintTooltip>, bool)> {
let res = match &*label.parts { let mut something_to_resolve = false;
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 {
lsp_types::InlayHintLabel::String(text), something_to_resolve |= tooltip.is_some();
None
} else {
match tooltip { match tooltip {
Some(ide::InlayTooltip::String(s)) => { Some(ide::InlayTooltip::String(s)) => {
Some(lsp_types::InlayHintTooltip::String(s)) Some(lsp_types::InlayHintTooltip::String(s))
@ -482,18 +502,20 @@ fn inlay_hint_label(
})) }))
} }
None => None, None => None,
}, }
) };
(lsp_types::InlayHintLabel::String(text), hint_tooltip)
} }
_ => { _ => {
let parts = label let parts = label
.parts .parts
.into_iter() .into_iter()
.map(|part| { .map(|part| {
part.linked_location.map(|range| location(snap, range)).transpose().map( let tooltip = if needs_resolve && fields_to_resolve.resolve_label_tooltip {
|location| lsp_types::InlayHintLabelPart { something_to_resolve |= part.tooltip.is_some();
value: part.text, None
tooltip: match part.tooltip { } else {
match part.tooltip {
Some(ide::InlayTooltip::String(s)) => { Some(ide::InlayTooltip::String(s)) => {
Some(lsp_types::InlayHintLabelPartTooltip::String(s)) Some(lsp_types::InlayHintLabelPartTooltip::String(s))
} }
@ -506,17 +528,26 @@ fn inlay_hint_label(
)) ))
} }
None => None, None => None,
}, }
};
let location = if needs_resolve && fields_to_resolve.resolve_label_location {
something_to_resolve |= part.linked_location.is_some();
None
} else {
part.linked_location.map(|range| location(snap, range)).transpose()?
};
Ok(lsp_types::InlayHintLabelPart {
value: part.text,
tooltip,
location, location,
command: None, command: None,
}, })
)
}) })
.collect::<Cancellable<_>>()?; .collect::<Cancellable<_>>()?;
(lsp_types::InlayHintLabel::LabelParts(parts), None) (lsp_types::InlayHintLabel::LabelParts(parts), None)
} }
}; };
Ok(res) Ok((label, tooltip, something_to_resolve))
} }
static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1); static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1);

View File

@ -184,6 +184,11 @@ impl Vfs {
mem::take(&mut self.changes) mem::take(&mut self.changes)
} }
/// Provides a panic-less way to verify file_id validity.
pub fn exists(&self, file_id: FileId) -> bool {
self.get(file_id).is_some()
}
/// Returns the id associated with `path` /// Returns the id associated with `path`
/// ///
/// - If `path` does not exists in the `Vfs`, allocate a new id for it, associated with a /// - If `path` does not exists in the `Vfs`, allocate a new id for it, associated with a

View File

@ -1,5 +1,5 @@
<!--- <!---
lsp/ext.rs hash: 149a5be3c5e469d1 lsp/ext.rs hash: 121482ee911854da
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:
@ -322,7 +322,7 @@ Position[]
```rust ```rust
fn main() { fn main() {
let x: Vec<()>/*cursor here*/ = vec![] let x: Vec<()>/*cursor here*/ = vec![];
} }
``` ```
@ -362,7 +362,7 @@ interface RunnablesParams {
```typescript ```typescript
interface Runnable { interface Runnable {
label: string; label: string;
/// If this Runnable is associated with a specific function/module, etc, the location of this item /// If this Runnable is associated with a specific function/module, etc., the location of this item
location?: LocationLink; location?: LocationLink;
/// Running things is necessary technology specific, `kind` needs to be advertised via server capabilities, /// Running things is necessary technology specific, `kind` needs to be advertised via server capabilities,
// the type of `args` is specific to `kind`. The actual running is handled by the client. // the type of `args` is specific to `kind`. The actual running is handled by the client.