Resolve inlay hint data

Skip every propery set in inlay hint client resolve capabilities,
reducing overall json footprint.
This commit is contained in:
Kirill Bulatov 2023-08-28 00:11:26 +03:00
parent 0e002fe5c6
commit e07fbabcfe
9 changed files with 200 additions and 51 deletions

View file

@ -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,

View file

@ -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 },
}
}

View file

@ -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(

View file

@ -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 {

View file

@ -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)