mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Resolve inlay hint data
Skip every propery set in inlay hint client resolve capabilities, reducing overall json footprint.
This commit is contained in:
parent
0e002fe5c6
commit
e07fbabcfe
9 changed files with 200 additions and 51 deletions
|
@ -52,6 +52,42 @@ pub struct InlayHintsConfig {
|
|||
pub closure_style: ClosureStyle,
|
||||
pub max_length: Option<usize>,
|
||||
pub closing_brace_hints_min_lines: Option<usize>,
|
||||
pub fields_to_resolve: InlayFieldsToResolve,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct InlayFieldsToResolve {
|
||||
pub client_capability_fields: Vec<String>,
|
||||
}
|
||||
|
||||
impl InlayFieldsToResolve {
|
||||
pub const fn empty() -> Self {
|
||||
Self { client_capability_fields: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.client_capability_fields.is_empty()
|
||||
}
|
||||
|
||||
pub fn resolve_text_edits(&self) -> bool {
|
||||
self.client_capability_fields.iter().find(|s| s.as_str() == "textEdits").is_some()
|
||||
}
|
||||
|
||||
pub fn resolve_hint_tooltip(&self) -> bool {
|
||||
self.client_capability_fields.iter().find(|s| s.as_str() == "tooltip").is_some()
|
||||
}
|
||||
|
||||
pub fn resolve_label_tooltip(&self) -> bool {
|
||||
self.client_capability_fields.iter().find(|s| s.as_str() == "label.tooltip").is_some()
|
||||
}
|
||||
|
||||
pub fn resolve_label_location(&self) -> bool {
|
||||
self.client_capability_fields.iter().find(|s| s.as_str() == "label.location").is_some()
|
||||
}
|
||||
|
||||
pub fn resolve_label_command(&self) -> bool {
|
||||
self.client_capability_fields.iter().find(|s| s.as_str() == "label.command").is_some()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -529,6 +565,7 @@ fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use expect_test::Expect;
|
||||
use hir::ClosureStyle;
|
||||
use itertools::Itertools;
|
||||
|
@ -538,7 +575,7 @@ mod tests {
|
|||
use crate::DiscriminantHints;
|
||||
use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints};
|
||||
|
||||
use super::ClosureReturnTypeHints;
|
||||
use super::{ClosureReturnTypeHints, InlayFieldsToResolve};
|
||||
|
||||
pub(super) const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig {
|
||||
discriminant_hints: DiscriminantHints::Never,
|
||||
|
@ -559,6 +596,7 @@ mod tests {
|
|||
param_names_for_lifetime_elision_hints: false,
|
||||
max_length: None,
|
||||
closing_brace_hints_min_lines: None,
|
||||
fields_to_resolve: InlayFieldsToResolve::empty(),
|
||||
};
|
||||
pub(super) const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
|
||||
type_hints: true,
|
||||
|
@ -567,7 +605,19 @@ mod tests {
|
|||
closure_return_type_hints: ClosureReturnTypeHints::WithBlock,
|
||||
binding_mode_hints: true,
|
||||
lifetime_elision_hints: LifetimeElisionHints::Always,
|
||||
..DISABLED_CONFIG
|
||||
discriminant_hints: DiscriminantHints::Never,
|
||||
render_colons: false,
|
||||
closure_capture_hints: false,
|
||||
adjustment_hints: AdjustmentHints::Never,
|
||||
adjustment_hints_mode: AdjustmentHintsMode::Prefix,
|
||||
adjustment_hints_hide_outside_unsafe: false,
|
||||
hide_named_constructor_hints: false,
|
||||
hide_closure_initialization_hints: false,
|
||||
closure_style: ClosureStyle::ImplFn,
|
||||
param_names_for_lifetime_elision_hints: false,
|
||||
max_length: None,
|
||||
closing_brace_hints_min_lines: None,
|
||||
fields_to_resolve: InlayFieldsToResolve::empty(),
|
||||
};
|
||||
|
||||
#[track_caller]
|
||||
|
|
|
@ -91,9 +91,9 @@ pub use crate::{
|
|||
MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
|
||||
},
|
||||
inlay_hints::{
|
||||
AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints, InlayHint,
|
||||
InlayHintLabel, InlayHintLabelPart, InlayHintPosition, InlayHintsConfig, InlayKind,
|
||||
InlayTooltip, LifetimeElisionHints,
|
||||
AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints,
|
||||
InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintPosition,
|
||||
InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
|
||||
},
|
||||
join_lines::JoinLinesConfig,
|
||||
markup::Markup,
|
||||
|
|
|
@ -12,6 +12,7 @@ use ide_db::{
|
|||
};
|
||||
use syntax::{AstNode, SyntaxKind::*, TextRange, T};
|
||||
|
||||
use crate::inlay_hints::InlayFieldsToResolve;
|
||||
use crate::{
|
||||
hover::hover_for_definition,
|
||||
inlay_hints::AdjustmentHintsMode,
|
||||
|
@ -125,6 +126,7 @@ impl StaticIndex<'_> {
|
|||
max_length: Some(25),
|
||||
closure_capture_hints: false,
|
||||
closing_brace_hints_min_lines: Some(25),
|
||||
fields_to_resolve: InlayFieldsToResolve::empty(),
|
||||
},
|
||||
file_id,
|
||||
None,
|
||||
|
|
|
@ -15,7 +15,10 @@ use hir_def::{
|
|||
hir::{ExprId, PatId},
|
||||
};
|
||||
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::{
|
||||
base_db::{
|
||||
salsa::{self, debug::DebugQueryTable, ParallelDatabase},
|
||||
|
@ -782,6 +785,7 @@ impl flags::AnalysisStats {
|
|||
closure_style: hir::ClosureStyle::ImplFn,
|
||||
max_length: Some(25),
|
||||
closing_brace_hints_min_lines: Some(20),
|
||||
fields_to_resolve: InlayFieldsToResolve::empty(),
|
||||
},
|
||||
file_id,
|
||||
None,
|
||||
|
|
|
@ -13,8 +13,9 @@ use cfg::{CfgAtom, CfgDiff};
|
|||
use flycheck::FlycheckConfig;
|
||||
use ide::{
|
||||
AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
|
||||
HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayHintsConfig,
|
||||
JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope,
|
||||
HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve,
|
||||
InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
|
||||
Snippet, SnippetScope,
|
||||
};
|
||||
use ide_db::{
|
||||
imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
|
||||
|
@ -1335,6 +1336,18 @@ impl Config {
|
|||
}
|
||||
|
||||
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::<Vec<_>>();
|
||||
|
||||
InlayHintsConfig {
|
||||
render_colons: self.data.inlayHints_renderColons,
|
||||
type_hints: self.data.inlayHints_typeHints_enable,
|
||||
|
@ -1395,6 +1408,7 @@ impl Config {
|
|||
} else {
|
||||
None
|
||||
},
|
||||
fields_to_resolve: InlayFieldsToResolve { client_capability_fields },
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ use anyhow::Context;
|
|||
|
||||
use ide::{
|
||||
AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, FilePosition, FileRange,
|
||||
HoverAction, HoverGotoTypeData, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind,
|
||||
SingleResolve, SourceChange, TextEdit,
|
||||
HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory,
|
||||
Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit,
|
||||
};
|
||||
use ide_db::SymbolKind;
|
||||
use lsp_server::ErrorCode;
|
||||
|
@ -30,7 +30,7 @@ use serde_json::json;
|
|||
use stdx::{format_to, never};
|
||||
use syntax::{algo, ast, AstNode, TextRange, TextSize};
|
||||
use triomphe::Arc;
|
||||
use vfs::{AbsPath, AbsPathBuf, VfsPath};
|
||||
use vfs::{AbsPath, AbsPathBuf, FileId, VfsPath};
|
||||
|
||||
use crate::{
|
||||
cargo_target_spec::CargoTargetSpec,
|
||||
|
@ -1412,17 +1412,71 @@ pub(crate) fn handle_inlay_hints(
|
|||
snap.analysis
|
||||
.inlay_hints(&inlay_hints_config, file_id, Some(range))?
|
||||
.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<_>>>()?,
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn handle_inlay_hints_resolve(
|
||||
_snap: GlobalStateSnapshot,
|
||||
hint: InlayHint,
|
||||
snap: GlobalStateSnapshot,
|
||||
mut original_hint: InlayHint,
|
||||
) -> anyhow::Result<InlayHint> {
|
||||
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);
|
||||
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(
|
||||
|
|
|
@ -682,7 +682,9 @@ pub struct CompletionResolveData {
|
|||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct InlayHintResolveData {}
|
||||
pub struct InlayHintResolveData {
|
||||
pub file_id: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct CompletionImport {
|
||||
|
|
|
@ -8,10 +8,10 @@ use std::{
|
|||
use ide::{
|
||||
Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem,
|
||||
CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit,
|
||||
Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint,
|
||||
InlayHintLabel, InlayHintLabelPart, InlayKind, Markup, NavigationTarget, ReferenceCategory,
|
||||
RenameError, Runnable, Severity, SignatureHelp, SnippetEdit, SourceChange, StructureNodeKind,
|
||||
SymbolKind, TextEdit, TextRange, TextSize,
|
||||
Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel,
|
||||
InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayKind, Markup,
|
||||
NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp,
|
||||
SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use serde_json::to_value;
|
||||
|
@ -437,10 +437,22 @@ pub(crate) fn signature_help(
|
|||
|
||||
pub(crate) fn inlay_hint(
|
||||
snap: &GlobalStateSnapshot,
|
||||
fields_to_resolve: &InlayFieldsToResolve,
|
||||
line_index: &LineIndex,
|
||||
file_id: FileId,
|
||||
inlay_hint: InlayHint,
|
||||
) -> Cancellable<lsp_types::InlayHint> {
|
||||
let (label, tooltip) = inlay_hint_label(snap, inlay_hint.label)?;
|
||||
let (label, tooltip) = inlay_hint_label(snap, fields_to_resolve, inlay_hint.label)?;
|
||||
let data = if fields_to_resolve.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(to_value(lsp_ext::InlayHintResolveData { file_id: file_id.0 }).unwrap())
|
||||
};
|
||||
let text_edits = if fields_to_resolve.resolve_text_edits() {
|
||||
None
|
||||
} else {
|
||||
inlay_hint.text_edit.map(|it| text_edit_vec(line_index, it))
|
||||
};
|
||||
|
||||
Ok(lsp_types::InlayHint {
|
||||
position: match inlay_hint.position {
|
||||
|
@ -454,8 +466,8 @@ pub(crate) fn inlay_hint(
|
|||
InlayKind::Type | InlayKind::Chaining => Some(lsp_types::InlayHintKind::TYPE),
|
||||
_ => None,
|
||||
},
|
||||
text_edits: inlay_hint.text_edit.map(|it| text_edit_vec(line_index, it)),
|
||||
data: None,
|
||||
text_edits,
|
||||
data,
|
||||
tooltip,
|
||||
label,
|
||||
})
|
||||
|
@ -463,13 +475,15 @@ pub(crate) fn inlay_hint(
|
|||
|
||||
fn inlay_hint_label(
|
||||
snap: &GlobalStateSnapshot,
|
||||
fields_to_resolve: &InlayFieldsToResolve,
|
||||
mut label: InlayHintLabel,
|
||||
) -> Cancellable<(lsp_types::InlayHintLabel, Option<lsp_types::InlayHintTooltip>)> {
|
||||
let res = match &*label.parts {
|
||||
[InlayHintLabelPart { linked_location: None, .. }] => {
|
||||
let InlayHintLabelPart { text, tooltip, .. } = label.parts.pop().unwrap();
|
||||
(
|
||||
lsp_types::InlayHintLabel::String(text),
|
||||
let hint_tooltip = if fields_to_resolve.resolve_hint_tooltip() {
|
||||
None
|
||||
} else {
|
||||
match tooltip {
|
||||
Some(ide::InlayTooltip::String(s)) => {
|
||||
Some(lsp_types::InlayHintTooltip::String(s))
|
||||
|
@ -481,35 +495,44 @@ fn inlay_hint_label(
|
|||
}))
|
||||
}
|
||||
None => None,
|
||||
},
|
||||
)
|
||||
}
|
||||
};
|
||||
(lsp_types::InlayHintLabel::String(text), hint_tooltip)
|
||||
}
|
||||
_ => {
|
||||
let parts = label
|
||||
.parts
|
||||
.into_iter()
|
||||
.map(|part| {
|
||||
part.linked_location.map(|range| location(snap, range)).transpose().map(
|
||||
|location| lsp_types::InlayHintLabelPart {
|
||||
value: part.text,
|
||||
tooltip: match part.tooltip {
|
||||
Some(ide::InlayTooltip::String(s)) => {
|
||||
Some(lsp_types::InlayHintLabelPartTooltip::String(s))
|
||||
}
|
||||
Some(ide::InlayTooltip::Markdown(s)) => {
|
||||
Some(lsp_types::InlayHintLabelPartTooltip::MarkupContent(
|
||||
lsp_types::MarkupContent {
|
||||
kind: lsp_types::MarkupKind::Markdown,
|
||||
value: s,
|
||||
},
|
||||
))
|
||||
}
|
||||
None => None,
|
||||
},
|
||||
location,
|
||||
command: None,
|
||||
},
|
||||
)
|
||||
let tooltip = if fields_to_resolve.resolve_label_tooltip() {
|
||||
None
|
||||
} else {
|
||||
match part.tooltip {
|
||||
Some(ide::InlayTooltip::String(s)) => {
|
||||
Some(lsp_types::InlayHintLabelPartTooltip::String(s))
|
||||
}
|
||||
Some(ide::InlayTooltip::Markdown(s)) => {
|
||||
Some(lsp_types::InlayHintLabelPartTooltip::MarkupContent(
|
||||
lsp_types::MarkupContent {
|
||||
kind: lsp_types::MarkupKind::Markdown,
|
||||
value: s,
|
||||
},
|
||||
))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
};
|
||||
let location = if fields_to_resolve.resolve_label_location() {
|
||||
None
|
||||
} else {
|
||||
part.linked_location.map(|range| location(snap, range)).transpose()?
|
||||
};
|
||||
Ok(lsp_types::InlayHintLabelPart {
|
||||
value: part.text,
|
||||
tooltip,
|
||||
location,
|
||||
command: None,
|
||||
})
|
||||
})
|
||||
.collect::<Cancellable<_>>()?;
|
||||
(lsp_types::InlayHintLabel::LabelParts(parts), None)
|
||||
|
|
|
@ -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
|
||||
need to adjust this doc as well and ping this issue:
|
||||
|
@ -322,7 +322,7 @@ Position[]
|
|||
|
||||
```rust
|
||||
fn main() {
|
||||
let x: Vec<()>/*cursor here*/ = vec![]
|
||||
let x: Vec<()>/*cursor here*/ = vec![];
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -362,7 +362,7 @@ interface RunnablesParams {
|
|||
```typescript
|
||||
interface Runnable {
|
||||
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;
|
||||
/// 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.
|
||||
|
|
Loading…
Reference in a new issue