From 008d5130b7dce96693cd9c39cd5e71d9dc73bd5b Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sun, 22 Sep 2024 20:10:15 +0300 Subject: [PATCH 1/6] Prepare for omittiong parts of completion data that need to be resolved --- .../crates/ide-completion/src/config.rs | 3 +- .../crates/ide-completion/src/lib.rs | 29 ++++++++++++++++++ .../crates/ide-completion/src/tests.rs | 5 ++-- src/tools/rust-analyzer/crates/ide/src/lib.rs | 4 +-- .../crates/rust-analyzer/src/config.rs | 19 +++++++++--- .../rust-analyzer/src/handlers/request.rs | 2 ++ .../src/integrated_benchmarks.rs | 6 +++- .../rust-analyzer/src/lsp/capabilities.rs | 16 +++++++++- .../crates/rust-analyzer/src/lsp/ext.rs | 1 + .../crates/rust-analyzer/src/lsp/to_proto.rs | 30 +++++++++++++++---- 10 files changed, 99 insertions(+), 16 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs index 0d403f49b7a87..1d05419c96dea 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs @@ -7,7 +7,7 @@ use hir::ImportPathConfig; use ide_db::{imports::insert_use::InsertUseConfig, SnippetCap}; -use crate::snippet::Snippet; +use crate::{snippet::Snippet, CompletionFieldsToResolve}; #[derive(Clone, Debug, PartialEq, Eq)] pub struct CompletionConfig { @@ -27,6 +27,7 @@ pub struct CompletionConfig { pub prefer_absolute: bool, pub snippets: Vec, pub limit: Option, + pub fields_to_resolve: CompletionFieldsToResolve, } #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index 58d1fad09504f..1e022cf244b98 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -37,6 +37,35 @@ pub use crate::{ 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_sort_text: bool, + pub resolve_filter_text: bool, + pub resolve_text_edit: bool, + // FIXME: those are always resolved + // pub resolve_additional_text_edits: 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_sort_text: false, + resolve_filter_text: false, + resolve_text_edit: false, + resolve_command: false, + } + } +} + //FIXME: split the following feature into fine-grained features. // Feature: Magic Completions diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs index 9d77d9700718c..f371012de3f58 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs @@ -37,8 +37,8 @@ use test_fixture::ChangeFixture; use test_utils::assert_eq_text; use crate::{ - resolve_completion_edits, CallableSnippets, CompletionConfig, CompletionItem, - CompletionItemKind, + resolve_completion_edits, CallableSnippets, CompletionConfig, CompletionFieldsToResolve, + CompletionItem, CompletionItemKind, }; /// Lots of basic item definitions @@ -84,6 +84,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { prefer_absolute: false, snippets: Vec::new(), limit: None, + fields_to_resolve: CompletionFieldsToResolve::empty(), }; pub(crate) fn completion_list(ra_fixture: &str) -> String { diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 547286c3f4d64..c46c4c8ce94bb 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -119,8 +119,8 @@ pub use ide_assists::{ Assist, AssistConfig, AssistId, AssistKind, AssistResolveStrategy, SingleResolve, }; pub use ide_completion::{ - CallableSnippets, CompletionConfig, CompletionItem, CompletionItemKind, CompletionRelevance, - Snippet, SnippetScope, + CallableSnippets, CompletionConfig, CompletionFieldsToResolve, CompletionItem, + CompletionItemKind, CompletionRelevance, Snippet, SnippetScope, }; pub use ide_db::{ base_db::{Cancelled, CrateGraph, CrateId, FileChange, SourceRoot, SourceRootId}, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 4cc60695fe668..a8a7e02ac38ec 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -12,10 +12,10 @@ use std::{ use cfg::{CfgAtom, CfgDiff}; use hir::Symbol; use ide::{ - AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode, - GenericParameterHints, HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, - InlayFieldsToResolve, InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, - MemoryLayoutHoverRenderKind, Snippet, SnippetScope, SourceRootId, + AssistConfig, CallableSnippets, CompletionConfig, CompletionFieldsToResolve, DiagnosticsConfig, + ExprFillDefaultMode, GenericParameterHints, HighlightConfig, HighlightRelatedConfig, + HoverConfig, HoverDocFormat, InlayFieldsToResolve, InlayHintsConfig, JoinLinesConfig, + MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope, SourceRootId, }; use ide_db::{ imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind}, @@ -1391,6 +1391,7 @@ impl Config { } pub fn completion(&self, source_root: Option) -> CompletionConfig { + let client_capability_fields = self.completion_resolve_support_properties(); CompletionConfig { enable_postfix_completions: self.completion_postfix_enable(source_root).to_owned(), enable_imports_on_the_fly: self.completion_autoimport_enable(source_root).to_owned() @@ -1415,6 +1416,16 @@ impl Config { limit: self.completion_limit(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, + 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_sort_text: client_capability_fields.contains("sortText"), + resolve_filter_text: client_capability_fields.contains("filterText"), + resolve_text_edit: client_capability_fields.contains("textEdit"), + resolve_command: client_capability_fields.contains("command"), + }, } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index bcbd970a0d214..9e3226fe79834 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -1019,9 +1019,11 @@ pub(crate) fn handle_completion( let items = to_proto::completion_items( &snap.config, + &completion_config.fields_to_resolve, &line_index, snap.file_version(position.file_id), text_document_position, + completion_trigger_character, items, ); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs index 118469df730ce..be0509a19aa78 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -12,7 +12,8 @@ use hir::ChangeWithProcMacros; use ide::{ - AnalysisHost, CallableSnippets, CompletionConfig, DiagnosticsConfig, FilePosition, TextSize, + AnalysisHost, CallableSnippets, CompletionConfig, CompletionFieldsToResolve, DiagnosticsConfig, + FilePosition, TextSize, }; use ide_db::{ imports::insert_use::{ImportGranularity, InsertUseConfig}, @@ -168,6 +169,7 @@ fn integrated_completion_benchmark() { snippets: Vec::new(), limit: None, add_semicolon_to_unit: true, + fields_to_resolve: CompletionFieldsToResolve::empty(), }; let position = FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() }; @@ -215,6 +217,7 @@ fn integrated_completion_benchmark() { snippets: Vec::new(), limit: None, add_semicolon_to_unit: true, + fields_to_resolve: CompletionFieldsToResolve::empty(), }; let position = FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() }; @@ -260,6 +263,7 @@ fn integrated_completion_benchmark() { snippets: Vec::new(), limit: None, add_semicolon_to_unit: true, + fields_to_resolve: CompletionFieldsToResolve::empty(), }; let position = FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() }; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs index 9610808c27e18..e5df7947f2d72 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs @@ -458,7 +458,21 @@ impl ClientCapabilities { .into_iter() .flatten() .cloned() - .collect::>() + .collect() + } + + pub fn completion_resolve_support_properties(&self) -> FxHashSet { + 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() + .cloned() + .collect() } pub fn hover_markdown_support(&self) -> bool { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs index 618481bbc66b6..990fadc6719ca 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs @@ -825,6 +825,7 @@ pub struct CompletionResolveData { pub position: lsp_types::TextDocumentPositionParams, pub imports: Vec, pub version: Option, + pub completion_trigger_character: Option, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index 4902c9f88c143..6e6a70bb3bcaa 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -6,9 +6,9 @@ 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, + Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionFieldsToResolve, + CompletionItem, CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, + FileSystemEdit, 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, @@ -227,9 +227,11 @@ pub(crate) fn snippet_text_edit_vec( pub(crate) fn completion_items( config: &Config, + fields_to_resolve: &CompletionFieldsToResolve, line_index: &LineIndex, version: Option, tdpp: lsp_types::TextDocumentPositionParams, + completion_trigger_character: Option, mut items: Vec, ) -> Vec { 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 mut res = Vec::with_capacity(items.len()); 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 { @@ -253,10 +265,12 @@ pub(crate) fn completion_items( fn completion_item( acc: &mut Vec, config: &Config, + fields_to_resolve: &CompletionFieldsToResolve, line_index: &LineIndex, version: Option, tdpp: &lsp_types::TextDocumentPositionParams, max_relevance: u32, + completion_trigger_character: Option, item: CompletionItem, ) { let insert_replace_support = config.insert_replace_support().then_some(tdpp.position); @@ -264,6 +278,7 @@ fn completion_item( let lookup = item.lookup().to_owned(); let mut additional_text_edits = Vec::new(); + let mut something_to_resolve = false; // LSP does not allow arbitrary edits in completion, so we have to do a // non-trivial mapping here. @@ -337,7 +352,12 @@ fn completion_item( }) .collect::>(); if !imports.is_empty() { - let data = lsp_ext::CompletionResolveData { position: tdpp.clone(), imports, version }; + let data = lsp_ext::CompletionResolveData { + position: tdpp.clone(), + imports, + version, + completion_trigger_character, + }; lsp_item.data = Some(to_value(data).unwrap()); } } From cc2686c1a9cf9a9e089f669d9d179812618008a7 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 23 Sep 2024 05:03:54 +0300 Subject: [PATCH 2/6] Omit completion fields to be resolved later --- .../crates/ide-completion/src/lib.rs | 4 - .../crates/rust-analyzer/src/config.rs | 1 - .../rust-analyzer/src/handlers/request.rs | 55 +++++----- .../crates/rust-analyzer/src/lsp/to_proto.rs | 101 ++++++++++++------ 4 files changed, 99 insertions(+), 62 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index 1e022cf244b98..a78976d3fd8b8 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -43,11 +43,8 @@ pub struct CompletionFieldsToResolve { pub resolve_tags: bool, pub resolve_detail: bool, pub resolve_documentation: bool, - pub resolve_sort_text: bool, pub resolve_filter_text: bool, pub resolve_text_edit: bool, - // FIXME: those are always resolved - // pub resolve_additional_text_edits: bool, pub resolve_command: bool, } @@ -58,7 +55,6 @@ impl CompletionFieldsToResolve { resolve_tags: false, resolve_detail: false, resolve_documentation: false, - resolve_sort_text: false, resolve_filter_text: false, resolve_text_edit: false, resolve_command: false, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index a8a7e02ac38ec..69dd8aff4284b 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -1421,7 +1421,6 @@ impl Config { resolve_tags: client_capability_fields.contains("tags"), resolve_detail: client_capability_fields.contains("detail"), resolve_documentation: client_capability_fields.contains("documentation"), - resolve_sort_text: client_capability_fields.contains("sortText"), resolve_filter_text: client_capability_fields.contains("filterText"), resolve_text_edit: client_capability_fields.contains("textEdit"), resolve_command: client_capability_fields.contains("command"), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 9e3226fe79834..7d5a3946db161 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -1056,33 +1056,36 @@ pub(crate) fn handle_completion_resolve( }; let source_root = snap.analysis.source_root_id(file_id)?; - let additional_edits = snap - .analysis - .resolve_completion_edits( - &snap.config.completion(Some(source_root)), - FilePosition { file_id, offset }, - resolve_data - .imports - .into_iter() - .map(|import| (import.full_import_path, import.imported_name)), - )? - .into_iter() - .flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel))) - .collect::>(); - - if !all_edits_are_disjoint(&original_completion, &additional_edits) { - return Err(LspError::new( - ErrorCode::InternalError as i32, - "Import edit overlaps with the original completion edits, this is not LSP-compliant" - .into(), - ) - .into()); - } + if !resolve_data.imports.is_empty() { + let additional_edits = snap + .analysis + .resolve_completion_edits( + &snap.config.completion(Some(source_root)), + FilePosition { file_id, offset }, + resolve_data + .imports + .into_iter() + .map(|import| (import.full_import_path, import.imported_name)), + )? + .into_iter() + .flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel))) + .collect::>(); + + if !all_edits_are_disjoint(&original_completion, &additional_edits) { + return Err(LspError::new( + ErrorCode::InternalError as i32, + "Import edit overlaps with the original completion edits, this is not LSP-compliant" + .into(), + ) + .into()); + } - if let Some(original_additional_edits) = original_completion.additional_text_edits.as_mut() { - original_additional_edits.extend(additional_edits) - } else { - original_completion.additional_text_edits = Some(additional_edits); + if let Some(original_additional_edits) = original_completion.additional_text_edits.as_mut() + { + original_additional_edits.extend(additional_edits) + } else { + original_completion.additional_text_edits = Some(additional_edits); + } } Ok(original_completion) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index 6e6a70bb3bcaa..c7f4b22a77195 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -275,14 +275,23 @@ fn completion_item( ) { let insert_replace_support = config.insert_replace_support().then_some(tdpp.position); let ref_match = item.ref_match(); - let lookup = item.lookup().to_owned(); 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()) + }; + // LSP does not allow arbitrary edits in completion, so we have to do a // non-trivial mapping here. - let text_edit = { + let text_edit = if fields_to_resolve.resolve_text_edit { + something_to_resolve = true; + None + } else { let mut text_edit = None; let source_range = item.source_range; for indel in item.text_edit { @@ -305,25 +314,49 @@ fn completion_item( 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 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 { - Some(command::trigger_parameter_hints()) + if fields_to_resolve.resolve_command { + something_to_resolve = true; + Some(command::trigger_parameter_hints()) + } else { + None + } } else { 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 { label: item.label.to_string(), - detail: item.detail, - filter_text: Some(lookup), + detail, + filter_text, kind: Some(completion_item_kind(item.kind)), - text_edit: Some(text_edit), + text_edit, additional_text_edits: Some(additional_text_edits), - documentation: item.documentation.map(documentation), + documentation, deprecated: Some(item.deprecated), tags, command, @@ -332,34 +365,40 @@ fn completion_item( }; if config.completion_label_details_support() { - lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails { - detail: item.label_detail.as_ref().map(ToString::to_string), - description: lsp_item.detail.clone(), - }); + if fields_to_resolve.resolve_label_details { + something_to_resolve = true; + } else { + lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails { + detail: item.label_detail.as_ref().map(ToString::to_string), + description: lsp_item.detail.clone(), + }); + } } else if let Some(label_detail) = item.label_detail { lsp_item.label.push_str(label_detail.as_str()); } set_score(&mut lsp_item, max_relevance, item.relevance); - if config.completion(None).enable_imports_on_the_fly && !item.import_to_add.is_empty() { - let imports = item - .import_to_add - .into_iter() - .map(|(import_path, import_name)| lsp_ext::CompletionImport { - full_import_path: import_path, - imported_name: import_name, - }) - .collect::>(); - if !imports.is_empty() { - let data = lsp_ext::CompletionResolveData { - position: tdpp.clone(), - imports, - version, - completion_trigger_character, - }; - lsp_item.data = Some(to_value(data).unwrap()); - } + let imports = + if config.completion(None).enable_imports_on_the_fly && !item.import_to_add.is_empty() { + item.import_to_add + .into_iter() + .map(|(import_path, import_name)| lsp_ext::CompletionImport { + full_import_path: import_path, + imported_name: import_name, + }) + .collect() + } else { + Vec::new() + }; + if something_to_resolve || !imports.is_empty() { + let data = lsp_ext::CompletionResolveData { + position: tdpp.clone(), + imports, + version, + completion_trigger_character, + }; + lsp_item.data = Some(to_value(data).unwrap()); } if let Some((label, indel, relevance)) = ref_match { From ecae5a8b33abfa7b084aa0bd29d47f5b98ea2527 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 23 Sep 2024 05:29:30 +0300 Subject: [PATCH 3/6] Resolve completion items --- .../rust-analyzer/src/handlers/request.rs | 49 +++++++++++++++---- .../crates/rust-analyzer/src/lsp/ext.rs | 2 +- .../crates/rust-analyzer/src/lsp/to_proto.rs | 2 +- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 7d5a3946db161..80d8c53801f19 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -10,9 +10,9 @@ use std::{ use anyhow::Context; use ide::{ - AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, FilePosition, FileRange, - HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query, RangeInfo, ReferenceCategory, - Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit, + AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve, + FilePosition, FileRange, HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query, + RangeInfo, ReferenceCategory, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit, }; use ide_db::SymbolKind; use itertools::Itertools; @@ -1056,12 +1056,43 @@ pub(crate) fn handle_completion_resolve( }; 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(unresolved_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, + unresolved_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 .analysis .resolve_completion_edits( - &snap.config.completion(Some(source_root)), - FilePosition { file_id, offset }, + &forced_resolve_completions_config, + position, resolve_data .imports .into_iter() @@ -1071,7 +1102,7 @@ pub(crate) fn handle_completion_resolve( .flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel))) .collect::>(); - if !all_edits_are_disjoint(&original_completion, &additional_edits) { + if !all_edits_are_disjoint(&resolved_completion, &additional_edits) { return Err(LspError::new( ErrorCode::InternalError as i32, "Import edit overlaps with the original completion edits, this is not LSP-compliant" @@ -1080,15 +1111,15 @@ pub(crate) fn handle_completion_resolve( .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) } 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( diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs index 990fadc6719ca..8039f0644eecf 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs @@ -825,7 +825,7 @@ pub struct CompletionResolveData { pub position: lsp_types::TextDocumentPositionParams, pub imports: Vec, pub version: Option, - pub completion_trigger_character: Option, + pub trigger_character: Option, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index c7f4b22a77195..c6a57c6114ca8 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -396,7 +396,7 @@ fn completion_item( position: tdpp.clone(), imports, version, - completion_trigger_character, + trigger_character: completion_trigger_character, }; lsp_item.data = Some(to_value(data).unwrap()); } From b82c5ceba8cfb595f3556593fb3eb9cd03b1fb5c Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 23 Sep 2024 05:47:50 +0300 Subject: [PATCH 4/6] Less clones --- .../crates/rust-analyzer/src/handlers/request.rs | 2 +- .../crates/rust-analyzer/src/lsp/capabilities.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 80d8c53801f19..5eab96e245176 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -1061,7 +1061,7 @@ pub(crate) fn handle_completion_resolve( let position = FilePosition { file_id, offset }; let Some(unresolved_completions) = snap.analysis.completions( - &&forced_resolve_completions_config, + &forced_resolve_completions_config, position, resolve_data.trigger_character, )? diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs index e5df7947f2d72..3b19284f24119 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs @@ -448,7 +448,7 @@ impl ClientCapabilities { .unwrap_or_default() } - pub fn inlay_hint_resolve_support_properties(&self) -> FxHashSet { + pub fn inlay_hint_resolve_support_properties(&self) -> FxHashSet<&str> { self.0 .text_document .as_ref() @@ -457,11 +457,11 @@ impl ClientCapabilities { .map(|inlay_resolve| inlay_resolve.properties.iter()) .into_iter() .flatten() - .cloned() + .map(|s| s.as_str()) .collect() } - pub fn completion_resolve_support_properties(&self) -> FxHashSet { + pub fn completion_resolve_support_properties(&self) -> FxHashSet<&str> { self.0 .text_document .as_ref() @@ -471,7 +471,7 @@ impl ClientCapabilities { .map(|resolve_support| resolve_support.properties.iter()) .into_iter() .flatten() - .cloned() + .map(|s| s.as_str()) .collect() } From b24723a5c74ab4881539bb97c7608c147f07c25e Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Mon, 23 Sep 2024 05:51:38 +0300 Subject: [PATCH 5/6] Fix the test --- src/tools/rust-analyzer/docs/dev/lsp-extensions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md index b7bac4d29fad9..7764f7843a00b 100644 --- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md +++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@