mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Auto merge of #18167 - SomeoneToIgnore:fat-completions, r=Veykril
internal: Send less data during `textDocument/completion` if possible Similar to https://github.com/rust-lang/rust-analyzer/pull/15522, stops sending extra data during `textDocument/completion` if that data was set in the client completions resolve capabilities, and sends those only during `completionItem/resolve` requests. Currently, rust-analyzer sends back all fields (including potentially huge docs) for every completion item which might get large. Same as the other one, this PR aims to keep the changes minimal and does not remove extra computations for such fields — instead, it just filters them out before sending to the client. The PR omits primitive, boolean and integer, types such as `deprecated`, `preselect`, `insertTextFormat`, `insertTextMode`, etc. AND `additionalTextEdits` — this one looks very dangerous to compute for each completion item (as the spec says we ought to if there's no corresponding resolve capabilities provided) due to the diff computations and the fact that this code had been in the resolution for some time. It would be good to resolve this lazily too, please let me know if it's ok to do. When tested with Zed which only defines `documentation` and `additionalTextEdits` in its client completion resolve capabilities, rust-analyzer starts to send almost 3 times less characters: Request: ```json {"jsonrpc":"2.0","id":104,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/ide/src/inlay_hints.rs"},"position":{"line":90,"character":14},"context":{"triggerKind":1}}} ``` <img width="1338" alt="image" src="https://github.com/user-attachments/assets/104f19b5-7095-4fc1-b008-5d829623b2e2"> Before: 381944 characters [before.json](https://github.com/user-attachments/files/17092385/before.json) After: 140503 characters [after.json](https://github.com/user-attachments/files/17092386/after.json) After Zed's [patch](https://github.com/zed-industries/zed/pull/18212) to enable all resolving possible: 84452 characters [after-after.json](https://github.com/user-attachments/files/17092755/after-after.json)
This commit is contained in:
commit
dfe6d503b8
11 changed files with 227 additions and 76 deletions
|
@ -7,7 +7,7 @@
|
||||||
use hir::ImportPathConfig;
|
use hir::ImportPathConfig;
|
||||||
use ide_db::{imports::insert_use::InsertUseConfig, SnippetCap};
|
use ide_db::{imports::insert_use::InsertUseConfig, SnippetCap};
|
||||||
|
|
||||||
use crate::snippet::Snippet;
|
use crate::{snippet::Snippet, CompletionFieldsToResolve};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct CompletionConfig {
|
pub struct CompletionConfig {
|
||||||
|
@ -27,6 +27,7 @@ pub struct CompletionConfig {
|
||||||
pub prefer_absolute: bool,
|
pub prefer_absolute: bool,
|
||||||
pub snippets: Vec<Snippet>,
|
pub snippets: Vec<Snippet>,
|
||||||
pub limit: Option<usize>,
|
pub limit: Option<usize>,
|
||||||
|
pub fields_to_resolve: CompletionFieldsToResolve,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
|
|
@ -37,6 +37,31 @@ pub use crate::{
|
||||||
snippet::{Snippet, SnippetScope},
|
snippet::{Snippet, SnippetScope},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct CompletionFieldsToResolve {
|
||||||
|
pub resolve_label_details: bool,
|
||||||
|
pub resolve_tags: bool,
|
||||||
|
pub resolve_detail: bool,
|
||||||
|
pub resolve_documentation: bool,
|
||||||
|
pub resolve_filter_text: bool,
|
||||||
|
pub resolve_text_edit: bool,
|
||||||
|
pub resolve_command: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompletionFieldsToResolve {
|
||||||
|
pub const fn empty() -> Self {
|
||||||
|
Self {
|
||||||
|
resolve_label_details: false,
|
||||||
|
resolve_tags: false,
|
||||||
|
resolve_detail: false,
|
||||||
|
resolve_documentation: false,
|
||||||
|
resolve_filter_text: false,
|
||||||
|
resolve_text_edit: false,
|
||||||
|
resolve_command: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//FIXME: split the following feature into fine-grained features.
|
//FIXME: split the following feature into fine-grained features.
|
||||||
|
|
||||||
// Feature: Magic Completions
|
// Feature: Magic Completions
|
||||||
|
|
|
@ -37,8 +37,8 @@ use test_fixture::ChangeFixture;
|
||||||
use test_utils::assert_eq_text;
|
use test_utils::assert_eq_text;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
resolve_completion_edits, CallableSnippets, CompletionConfig, CompletionItem,
|
resolve_completion_edits, CallableSnippets, CompletionConfig, CompletionFieldsToResolve,
|
||||||
CompletionItemKind,
|
CompletionItem, CompletionItemKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Lots of basic item definitions
|
/// Lots of basic item definitions
|
||||||
|
@ -84,6 +84,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
|
||||||
prefer_absolute: false,
|
prefer_absolute: false,
|
||||||
snippets: Vec::new(),
|
snippets: Vec::new(),
|
||||||
limit: None,
|
limit: None,
|
||||||
|
fields_to_resolve: CompletionFieldsToResolve::empty(),
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn completion_list(ra_fixture: &str) -> String {
|
pub(crate) fn completion_list(ra_fixture: &str) -> String {
|
||||||
|
|
|
@ -119,8 +119,8 @@ pub use ide_assists::{
|
||||||
Assist, AssistConfig, AssistId, AssistKind, AssistResolveStrategy, SingleResolve,
|
Assist, AssistConfig, AssistId, AssistKind, AssistResolveStrategy, SingleResolve,
|
||||||
};
|
};
|
||||||
pub use ide_completion::{
|
pub use ide_completion::{
|
||||||
CallableSnippets, CompletionConfig, CompletionItem, CompletionItemKind, CompletionRelevance,
|
CallableSnippets, CompletionConfig, CompletionFieldsToResolve, CompletionItem,
|
||||||
Snippet, SnippetScope,
|
CompletionItemKind, CompletionRelevance, Snippet, SnippetScope,
|
||||||
};
|
};
|
||||||
pub use ide_db::{
|
pub use ide_db::{
|
||||||
base_db::{Cancelled, CrateGraph, CrateId, FileChange, SourceRoot, SourceRootId},
|
base_db::{Cancelled, CrateGraph, CrateId, FileChange, SourceRoot, SourceRootId},
|
||||||
|
|
|
@ -12,10 +12,10 @@ use std::{
|
||||||
use cfg::{CfgAtom, CfgDiff};
|
use cfg::{CfgAtom, CfgDiff};
|
||||||
use hir::Symbol;
|
use hir::Symbol;
|
||||||
use ide::{
|
use ide::{
|
||||||
AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
|
AssistConfig, CallableSnippets, CompletionConfig, CompletionFieldsToResolve, DiagnosticsConfig,
|
||||||
GenericParameterHints, HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat,
|
ExprFillDefaultMode, GenericParameterHints, HighlightConfig, HighlightRelatedConfig,
|
||||||
InlayFieldsToResolve, InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig,
|
HoverConfig, HoverDocFormat, InlayFieldsToResolve, InlayHintsConfig, JoinLinesConfig,
|
||||||
MemoryLayoutHoverRenderKind, Snippet, SnippetScope, SourceRootId,
|
MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope, SourceRootId,
|
||||||
};
|
};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
|
imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
|
||||||
|
@ -1393,6 +1393,7 @@ impl Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn completion(&self, source_root: Option<SourceRootId>) -> CompletionConfig {
|
pub fn completion(&self, source_root: Option<SourceRootId>) -> CompletionConfig {
|
||||||
|
let client_capability_fields = self.completion_resolve_support_properties();
|
||||||
CompletionConfig {
|
CompletionConfig {
|
||||||
enable_postfix_completions: self.completion_postfix_enable(source_root).to_owned(),
|
enable_postfix_completions: self.completion_postfix_enable(source_root).to_owned(),
|
||||||
enable_imports_on_the_fly: self.completion_autoimport_enable(source_root).to_owned()
|
enable_imports_on_the_fly: self.completion_autoimport_enable(source_root).to_owned()
|
||||||
|
@ -1417,6 +1418,15 @@ impl Config {
|
||||||
limit: self.completion_limit(source_root).to_owned(),
|
limit: self.completion_limit(source_root).to_owned(),
|
||||||
enable_term_search: self.completion_termSearch_enable(source_root).to_owned(),
|
enable_term_search: self.completion_termSearch_enable(source_root).to_owned(),
|
||||||
term_search_fuel: self.completion_termSearch_fuel(source_root).to_owned() as u64,
|
term_search_fuel: self.completion_termSearch_fuel(source_root).to_owned() as u64,
|
||||||
|
fields_to_resolve: CompletionFieldsToResolve {
|
||||||
|
resolve_label_details: client_capability_fields.contains("labelDetails"),
|
||||||
|
resolve_tags: client_capability_fields.contains("tags"),
|
||||||
|
resolve_detail: client_capability_fields.contains("detail"),
|
||||||
|
resolve_documentation: client_capability_fields.contains("documentation"),
|
||||||
|
resolve_filter_text: client_capability_fields.contains("filterText"),
|
||||||
|
resolve_text_edit: client_capability_fields.contains("textEdit"),
|
||||||
|
resolve_command: client_capability_fields.contains("command"),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,9 @@ use std::{
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
|
||||||
use ide::{
|
use ide::{
|
||||||
AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, FilePosition, FileRange,
|
AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve,
|
||||||
HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory,
|
FilePosition, FileRange, HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query,
|
||||||
Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit,
|
RangeInfo, ReferenceCategory, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit,
|
||||||
};
|
};
|
||||||
use ide_db::SymbolKind;
|
use ide_db::SymbolKind;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
@ -1019,9 +1019,11 @@ pub(crate) fn handle_completion(
|
||||||
|
|
||||||
let items = to_proto::completion_items(
|
let items = to_proto::completion_items(
|
||||||
&snap.config,
|
&snap.config,
|
||||||
|
&completion_config.fields_to_resolve,
|
||||||
&line_index,
|
&line_index,
|
||||||
snap.file_version(position.file_id),
|
snap.file_version(position.file_id),
|
||||||
text_document_position,
|
text_document_position,
|
||||||
|
completion_trigger_character,
|
||||||
items,
|
items,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1054,11 +1056,43 @@ pub(crate) fn handle_completion_resolve(
|
||||||
};
|
};
|
||||||
let source_root = snap.analysis.source_root_id(file_id)?;
|
let source_root = snap.analysis.source_root_id(file_id)?;
|
||||||
|
|
||||||
|
let mut forced_resolve_completions_config = snap.config.completion(Some(source_root));
|
||||||
|
forced_resolve_completions_config.fields_to_resolve = CompletionFieldsToResolve::empty();
|
||||||
|
|
||||||
|
let position = FilePosition { file_id, offset };
|
||||||
|
let Some(resolved_completions) = snap.analysis.completions(
|
||||||
|
&forced_resolve_completions_config,
|
||||||
|
position,
|
||||||
|
resolve_data.trigger_character,
|
||||||
|
)?
|
||||||
|
else {
|
||||||
|
return Ok(original_completion);
|
||||||
|
};
|
||||||
|
let resolved_completions = to_proto::completion_items(
|
||||||
|
&snap.config,
|
||||||
|
&forced_resolve_completions_config.fields_to_resolve,
|
||||||
|
&line_index,
|
||||||
|
snap.file_version(position.file_id),
|
||||||
|
resolve_data.position,
|
||||||
|
resolve_data.trigger_character,
|
||||||
|
resolved_completions,
|
||||||
|
);
|
||||||
|
let Some(mut resolved_completion) = resolved_completions.into_iter().find(|completion| {
|
||||||
|
completion.label == original_completion.label
|
||||||
|
&& completion.kind == original_completion.kind
|
||||||
|
&& completion.deprecated == original_completion.deprecated
|
||||||
|
&& completion.preselect == original_completion.preselect
|
||||||
|
&& completion.sort_text == original_completion.sort_text
|
||||||
|
}) else {
|
||||||
|
return Ok(original_completion);
|
||||||
|
};
|
||||||
|
|
||||||
|
if !resolve_data.imports.is_empty() {
|
||||||
let additional_edits = snap
|
let additional_edits = snap
|
||||||
.analysis
|
.analysis
|
||||||
.resolve_completion_edits(
|
.resolve_completion_edits(
|
||||||
&snap.config.completion(Some(source_root)),
|
&forced_resolve_completions_config,
|
||||||
FilePosition { file_id, offset },
|
position,
|
||||||
resolve_data
|
resolve_data
|
||||||
.imports
|
.imports
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -1068,7 +1102,7 @@ pub(crate) fn handle_completion_resolve(
|
||||||
.flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel)))
|
.flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel)))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if !all_edits_are_disjoint(&original_completion, &additional_edits) {
|
if !all_edits_are_disjoint(&resolved_completion, &additional_edits) {
|
||||||
return Err(LspError::new(
|
return Err(LspError::new(
|
||||||
ErrorCode::InternalError as i32,
|
ErrorCode::InternalError as i32,
|
||||||
"Import edit overlaps with the original completion edits, this is not LSP-compliant"
|
"Import edit overlaps with the original completion edits, this is not LSP-compliant"
|
||||||
|
@ -1077,13 +1111,15 @@ pub(crate) fn handle_completion_resolve(
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(original_additional_edits) = original_completion.additional_text_edits.as_mut() {
|
if let Some(original_additional_edits) = resolved_completion.additional_text_edits.as_mut()
|
||||||
|
{
|
||||||
original_additional_edits.extend(additional_edits)
|
original_additional_edits.extend(additional_edits)
|
||||||
} else {
|
} else {
|
||||||
original_completion.additional_text_edits = Some(additional_edits);
|
resolved_completion.additional_text_edits = Some(additional_edits);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(original_completion)
|
Ok(resolved_completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn handle_folding_range(
|
pub(crate) fn handle_folding_range(
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
|
|
||||||
use hir::ChangeWithProcMacros;
|
use hir::ChangeWithProcMacros;
|
||||||
use ide::{
|
use ide::{
|
||||||
AnalysisHost, CallableSnippets, CompletionConfig, DiagnosticsConfig, FilePosition, TextSize,
|
AnalysisHost, CallableSnippets, CompletionConfig, CompletionFieldsToResolve, DiagnosticsConfig,
|
||||||
|
FilePosition, TextSize,
|
||||||
};
|
};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
imports::insert_use::{ImportGranularity, InsertUseConfig},
|
imports::insert_use::{ImportGranularity, InsertUseConfig},
|
||||||
|
@ -172,6 +173,7 @@ fn integrated_completion_benchmark() {
|
||||||
snippets: Vec::new(),
|
snippets: Vec::new(),
|
||||||
limit: None,
|
limit: None,
|
||||||
add_semicolon_to_unit: true,
|
add_semicolon_to_unit: true,
|
||||||
|
fields_to_resolve: CompletionFieldsToResolve::empty(),
|
||||||
};
|
};
|
||||||
let position =
|
let position =
|
||||||
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
|
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
|
||||||
|
@ -219,6 +221,7 @@ fn integrated_completion_benchmark() {
|
||||||
snippets: Vec::new(),
|
snippets: Vec::new(),
|
||||||
limit: None,
|
limit: None,
|
||||||
add_semicolon_to_unit: true,
|
add_semicolon_to_unit: true,
|
||||||
|
fields_to_resolve: CompletionFieldsToResolve::empty(),
|
||||||
};
|
};
|
||||||
let position =
|
let position =
|
||||||
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
|
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
|
||||||
|
@ -264,6 +267,7 @@ fn integrated_completion_benchmark() {
|
||||||
snippets: Vec::new(),
|
snippets: Vec::new(),
|
||||||
limit: None,
|
limit: None,
|
||||||
add_semicolon_to_unit: true,
|
add_semicolon_to_unit: true,
|
||||||
|
fields_to_resolve: CompletionFieldsToResolve::empty(),
|
||||||
};
|
};
|
||||||
let position =
|
let position =
|
||||||
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
|
FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
|
||||||
|
|
|
@ -448,7 +448,7 @@ impl ClientCapabilities {
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inlay_hint_resolve_support_properties(&self) -> FxHashSet<String> {
|
pub fn inlay_hint_resolve_support_properties(&self) -> FxHashSet<&str> {
|
||||||
self.0
|
self.0
|
||||||
.text_document
|
.text_document
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -457,8 +457,22 @@ impl ClientCapabilities {
|
||||||
.map(|inlay_resolve| inlay_resolve.properties.iter())
|
.map(|inlay_resolve| inlay_resolve.properties.iter())
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
.cloned()
|
.map(|s| s.as_str())
|
||||||
.collect::<FxHashSet<_>>()
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn completion_resolve_support_properties(&self) -> FxHashSet<&str> {
|
||||||
|
self.0
|
||||||
|
.text_document
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|text| text.completion.as_ref())
|
||||||
|
.and_then(|completion_caps| completion_caps.completion_item.as_ref())
|
||||||
|
.and_then(|completion_item_caps| completion_item_caps.resolve_support.as_ref())
|
||||||
|
.map(|resolve_support| resolve_support.properties.iter())
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.map(|s| s.as_str())
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hover_markdown_support(&self) -> bool {
|
pub fn hover_markdown_support(&self) -> bool {
|
||||||
|
|
|
@ -825,6 +825,7 @@ pub struct CompletionResolveData {
|
||||||
pub position: lsp_types::TextDocumentPositionParams,
|
pub position: lsp_types::TextDocumentPositionParams,
|
||||||
pub imports: Vec<CompletionImport>,
|
pub imports: Vec<CompletionImport>,
|
||||||
pub version: Option<i32>,
|
pub version: Option<i32>,
|
||||||
|
pub trigger_character: Option<char>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
|
|
@ -6,9 +6,9 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use ide::{
|
use ide::{
|
||||||
Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem,
|
Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionFieldsToResolve,
|
||||||
CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit,
|
CompletionItem, CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange,
|
||||||
Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel,
|
FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel,
|
||||||
InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayKind, Markup,
|
InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayKind, Markup,
|
||||||
NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp,
|
NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp,
|
||||||
SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
|
SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
|
||||||
|
@ -227,9 +227,11 @@ pub(crate) fn snippet_text_edit_vec(
|
||||||
|
|
||||||
pub(crate) fn completion_items(
|
pub(crate) fn completion_items(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
|
fields_to_resolve: &CompletionFieldsToResolve,
|
||||||
line_index: &LineIndex,
|
line_index: &LineIndex,
|
||||||
version: Option<i32>,
|
version: Option<i32>,
|
||||||
tdpp: lsp_types::TextDocumentPositionParams,
|
tdpp: lsp_types::TextDocumentPositionParams,
|
||||||
|
completion_trigger_character: Option<char>,
|
||||||
mut items: Vec<CompletionItem>,
|
mut items: Vec<CompletionItem>,
|
||||||
) -> Vec<lsp_types::CompletionItem> {
|
) -> Vec<lsp_types::CompletionItem> {
|
||||||
if config.completion_hide_deprecated() {
|
if config.completion_hide_deprecated() {
|
||||||
|
@ -239,7 +241,17 @@ pub(crate) fn completion_items(
|
||||||
let max_relevance = items.iter().map(|it| it.relevance.score()).max().unwrap_or_default();
|
let max_relevance = items.iter().map(|it| it.relevance.score()).max().unwrap_or_default();
|
||||||
let mut res = Vec::with_capacity(items.len());
|
let mut res = Vec::with_capacity(items.len());
|
||||||
for item in items {
|
for item in items {
|
||||||
completion_item(&mut res, config, line_index, version, &tdpp, max_relevance, item);
|
completion_item(
|
||||||
|
&mut res,
|
||||||
|
config,
|
||||||
|
fields_to_resolve,
|
||||||
|
line_index,
|
||||||
|
version,
|
||||||
|
&tdpp,
|
||||||
|
max_relevance,
|
||||||
|
completion_trigger_character,
|
||||||
|
item,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(limit) = config.completion(None).limit {
|
if let Some(limit) = config.completion(None).limit {
|
||||||
|
@ -253,21 +265,33 @@ pub(crate) fn completion_items(
|
||||||
fn completion_item(
|
fn completion_item(
|
||||||
acc: &mut Vec<lsp_types::CompletionItem>,
|
acc: &mut Vec<lsp_types::CompletionItem>,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
|
fields_to_resolve: &CompletionFieldsToResolve,
|
||||||
line_index: &LineIndex,
|
line_index: &LineIndex,
|
||||||
version: Option<i32>,
|
version: Option<i32>,
|
||||||
tdpp: &lsp_types::TextDocumentPositionParams,
|
tdpp: &lsp_types::TextDocumentPositionParams,
|
||||||
max_relevance: u32,
|
max_relevance: u32,
|
||||||
|
completion_trigger_character: Option<char>,
|
||||||
item: CompletionItem,
|
item: CompletionItem,
|
||||||
) {
|
) {
|
||||||
let insert_replace_support = config.insert_replace_support().then_some(tdpp.position);
|
let insert_replace_support = config.insert_replace_support().then_some(tdpp.position);
|
||||||
let ref_match = item.ref_match();
|
let ref_match = item.ref_match();
|
||||||
let lookup = item.lookup().to_owned();
|
|
||||||
|
|
||||||
let mut additional_text_edits = Vec::new();
|
let mut additional_text_edits = Vec::new();
|
||||||
|
let mut something_to_resolve = false;
|
||||||
|
|
||||||
|
let filter_text = if fields_to_resolve.resolve_filter_text {
|
||||||
|
something_to_resolve = !item.lookup().is_empty();
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(item.lookup().to_owned())
|
||||||
|
};
|
||||||
|
|
||||||
|
let text_edit = if fields_to_resolve.resolve_text_edit {
|
||||||
|
something_to_resolve = true;
|
||||||
|
None
|
||||||
|
} else {
|
||||||
// LSP does not allow arbitrary edits in completion, so we have to do a
|
// LSP does not allow arbitrary edits in completion, so we have to do a
|
||||||
// non-trivial mapping here.
|
// non-trivial mapping here.
|
||||||
let text_edit = {
|
|
||||||
let mut text_edit = None;
|
let mut text_edit = None;
|
||||||
let source_range = item.source_range;
|
let source_range = item.source_range;
|
||||||
for indel in item.text_edit {
|
for indel in item.text_edit {
|
||||||
|
@ -290,25 +314,49 @@ fn completion_item(
|
||||||
additional_text_edits.push(text_edit);
|
additional_text_edits.push(text_edit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
text_edit.unwrap()
|
Some(text_edit.unwrap())
|
||||||
};
|
};
|
||||||
|
|
||||||
let insert_text_format = item.is_snippet.then_some(lsp_types::InsertTextFormat::SNIPPET);
|
let insert_text_format = item.is_snippet.then_some(lsp_types::InsertTextFormat::SNIPPET);
|
||||||
let tags = item.deprecated.then(|| vec![lsp_types::CompletionItemTag::DEPRECATED]);
|
let tags = if fields_to_resolve.resolve_tags {
|
||||||
|
something_to_resolve = item.deprecated;
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
item.deprecated.then(|| vec![lsp_types::CompletionItemTag::DEPRECATED])
|
||||||
|
};
|
||||||
let command = if item.trigger_call_info && config.client_commands().trigger_parameter_hints {
|
let command = if item.trigger_call_info && config.client_commands().trigger_parameter_hints {
|
||||||
|
if fields_to_resolve.resolve_command {
|
||||||
|
something_to_resolve = true;
|
||||||
|
None
|
||||||
|
} else {
|
||||||
Some(command::trigger_parameter_hints())
|
Some(command::trigger_parameter_hints())
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let detail = if fields_to_resolve.resolve_detail {
|
||||||
|
something_to_resolve = item.detail.is_some();
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
item.detail
|
||||||
|
};
|
||||||
|
|
||||||
|
let documentation = if fields_to_resolve.resolve_documentation {
|
||||||
|
something_to_resolve = item.documentation.is_some();
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
item.documentation.map(documentation)
|
||||||
|
};
|
||||||
|
|
||||||
let mut lsp_item = lsp_types::CompletionItem {
|
let mut lsp_item = lsp_types::CompletionItem {
|
||||||
label: item.label.to_string(),
|
label: item.label.to_string(),
|
||||||
detail: item.detail,
|
detail,
|
||||||
filter_text: Some(lookup),
|
filter_text,
|
||||||
kind: Some(completion_item_kind(item.kind)),
|
kind: Some(completion_item_kind(item.kind)),
|
||||||
text_edit: Some(text_edit),
|
text_edit,
|
||||||
additional_text_edits: Some(additional_text_edits),
|
additional_text_edits: Some(additional_text_edits),
|
||||||
documentation: item.documentation.map(documentation),
|
documentation,
|
||||||
deprecated: Some(item.deprecated),
|
deprecated: Some(item.deprecated),
|
||||||
tags,
|
tags,
|
||||||
command,
|
command,
|
||||||
|
@ -317,30 +365,41 @@ fn completion_item(
|
||||||
};
|
};
|
||||||
|
|
||||||
if config.completion_label_details_support() {
|
if config.completion_label_details_support() {
|
||||||
|
if fields_to_resolve.resolve_label_details {
|
||||||
|
something_to_resolve = true;
|
||||||
|
} else {
|
||||||
lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails {
|
lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails {
|
||||||
detail: item.label_detail.as_ref().map(ToString::to_string),
|
detail: item.label_detail.as_ref().map(ToString::to_string),
|
||||||
description: lsp_item.detail.clone(),
|
description: lsp_item.detail.clone(),
|
||||||
});
|
});
|
||||||
|
}
|
||||||
} else if let Some(label_detail) = item.label_detail {
|
} else if let Some(label_detail) = item.label_detail {
|
||||||
lsp_item.label.push_str(label_detail.as_str());
|
lsp_item.label.push_str(label_detail.as_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
set_score(&mut lsp_item, max_relevance, item.relevance);
|
set_score(&mut lsp_item, max_relevance, item.relevance);
|
||||||
|
|
||||||
|
let imports =
|
||||||
if config.completion(None).enable_imports_on_the_fly && !item.import_to_add.is_empty() {
|
if config.completion(None).enable_imports_on_the_fly && !item.import_to_add.is_empty() {
|
||||||
let imports = item
|
item.import_to_add
|
||||||
.import_to_add
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(import_path, import_name)| lsp_ext::CompletionImport {
|
.map(|(import_path, import_name)| lsp_ext::CompletionImport {
|
||||||
full_import_path: import_path,
|
full_import_path: import_path,
|
||||||
imported_name: import_name,
|
imported_name: import_name,
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect()
|
||||||
if !imports.is_empty() {
|
} else {
|
||||||
let data = lsp_ext::CompletionResolveData { position: tdpp.clone(), imports, version };
|
Vec::new()
|
||||||
|
};
|
||||||
|
if something_to_resolve || !imports.is_empty() {
|
||||||
|
let data = lsp_ext::CompletionResolveData {
|
||||||
|
position: tdpp.clone(),
|
||||||
|
imports,
|
||||||
|
version,
|
||||||
|
trigger_character: completion_trigger_character,
|
||||||
|
};
|
||||||
lsp_item.data = Some(to_value(data).unwrap());
|
lsp_item.data = Some(to_value(data).unwrap());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let Some((label, indel, relevance)) = ref_match {
|
if let Some((label, indel, relevance)) = ref_match {
|
||||||
let mut lsp_item_with_ref = lsp_types::CompletionItem { label, ..lsp_item.clone() };
|
let mut lsp_item_with_ref = lsp_types::CompletionItem { label, ..lsp_item.clone() };
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<!---
|
<!---
|
||||||
lsp/ext.rs hash: 6292ee8d88d4c9ec
|
lsp/ext.rs hash: 90cf7718d54fe3c2
|
||||||
|
|
||||||
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:
|
||||||
|
|
Loading…
Reference in a new issue