aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorKirill Bulatov <[email protected]>2020-12-04 14:03:22 +0000
committerKirill Bulatov <[email protected]>2020-12-07 21:41:08 +0000
commitdeda74edd89affb3f77d274776d2a672bc11db90 (patch)
treee9c7dac6df4fd06012ca6b6e628223e925998f1e /crates
parent93bc009a5968c964693299263689b50b2efe9abc (diff)
Use stateless completion resolve
Diffstat (limited to 'crates')
-rw-r--r--crates/completion/src/completions/unqualified_path.rs10
-rw-r--r--crates/completion/src/item.rs1
-rw-r--r--crates/completion/src/lib.rs32
-rw-r--r--crates/completion/src/render.rs12
-rw-r--r--crates/ide/src/lib.rs22
-rw-r--r--crates/rust-analyzer/src/handlers.rs118
6 files changed, 124 insertions, 71 deletions
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index 81691cd7f..26a2b7a1b 100644
--- a/crates/completion/src/completions/unqualified_path.rs
+++ b/crates/completion/src/completions/unqualified_path.rs
@@ -9,7 +9,7 @@ use test_utils::mark;
9 9
10use crate::{ 10use crate::{
11 render::{render_resolution_with_import, RenderContext}, 11 render::{render_resolution_with_import, RenderContext},
12 CompletionContext, Completions, 12 CompletionContext, Completions, ImportEdit,
13}; 13};
14 14
15pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 15pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
@@ -103,9 +103,11 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()
103 .filter_map(|(import_path, definition)| { 103 .filter_map(|(import_path, definition)| {
104 render_resolution_with_import( 104 render_resolution_with_import(
105 RenderContext::new(ctx), 105 RenderContext::new(ctx),
106 import_path.clone(), 106 ImportEdit {
107 import_scope.clone(), 107 import_path: import_path.clone(),
108 ctx.config.merge, 108 import_scope: import_scope.clone(),
109 merge_behaviour: ctx.config.merge,
110 },
109 &definition, 111 &definition,
110 ) 112 )
111 }); 113 });
diff --git a/crates/completion/src/item.rs b/crates/completion/src/item.rs
index 2dadf7e5b..4e56f28f3 100644
--- a/crates/completion/src/item.rs
+++ b/crates/completion/src/item.rs
@@ -276,7 +276,6 @@ pub struct ImportEdit {
276} 276}
277 277
278impl ImportEdit { 278impl ImportEdit {
279 // TODO kb remove this at all now, since it's used only once?
280 /// Attempts to insert the import to the given scope, producing a text edit. 279 /// Attempts to insert the import to the given scope, producing a text edit.
281 /// May return no edit in edge cases, such as scope already containing the import. 280 /// May return no edit in edge cases, such as scope already containing the import.
282 pub fn to_text_edit(&self) -> Option<TextEdit> { 281 pub fn to_text_edit(&self) -> Option<TextEdit> {
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs
index c57203c80..938c92dbb 100644
--- a/crates/completion/src/lib.rs
+++ b/crates/completion/src/lib.rs
@@ -11,8 +11,11 @@ mod render;
11 11
12mod completions; 12mod completions;
13 13
14use ide_db::base_db::FilePosition; 14use ide_db::{
15use ide_db::RootDatabase; 15 base_db::FilePosition, helpers::insert_use::ImportScope, imports_locator, RootDatabase,
16};
17use syntax::AstNode;
18use text_edit::TextEdit;
16 19
17use crate::{completions::Completions, context::CompletionContext, item::CompletionKind}; 20use crate::{completions::Completions, context::CompletionContext, item::CompletionKind};
18 21
@@ -131,6 +134,31 @@ pub fn completions(
131 Some(acc) 134 Some(acc)
132} 135}
133 136
137/// Resolves additional completion data at the position given.
138pub fn resolve_completion_edits(
139 db: &RootDatabase,
140 config: &CompletionConfig,
141 position: FilePosition,
142 full_import_path: &str,
143 imported_name: &str,
144) -> Option<TextEdit> {
145 let ctx = CompletionContext::new(db, position, config)?;
146 let anchor = ctx.name_ref_syntax.as_ref()?;
147 let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
148
149 let current_module = ctx.sema.scope(anchor.syntax()).module()?;
150 let current_crate = current_module.krate();
151
152 let import_path = imports_locator::find_exact_imports(&ctx.sema, current_crate, imported_name)
153 .filter_map(|candidate| {
154 let item: hir::ItemInNs = candidate.either(Into::into, Into::into);
155 current_module.find_use_path(db, item)
156 })
157 .find(|mod_path| mod_path.to_string() == full_import_path)?;
158
159 ImportEdit { import_path, import_scope, merge_behaviour: config.merge }.to_text_edit()
160}
161
134#[cfg(test)] 162#[cfg(test)]
135mod tests { 163mod tests {
136 use crate::config::CompletionConfig; 164 use crate::config::CompletionConfig;
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs
index a6faedb18..9a43480e1 100644
--- a/crates/completion/src/render.rs
+++ b/crates/completion/src/render.rs
@@ -9,8 +9,7 @@ pub(crate) mod type_alias;
9 9
10mod builder_ext; 10mod builder_ext;
11 11
12use hir::{Documentation, HasAttrs, HirDisplay, ModPath, Mutability, ScopeDef, Type}; 12use hir::{Documentation, HasAttrs, HirDisplay, Mutability, ScopeDef, Type};
13use ide_db::helpers::insert_use::{ImportScope, MergeBehaviour};
14use ide_db::RootDatabase; 13use ide_db::RootDatabase;
15use syntax::TextRange; 14use syntax::TextRange;
16use test_utils::mark; 15use test_utils::mark;
@@ -48,15 +47,12 @@ pub(crate) fn render_resolution<'a>(
48 47
49pub(crate) fn render_resolution_with_import<'a>( 48pub(crate) fn render_resolution_with_import<'a>(
50 ctx: RenderContext<'a>, 49 ctx: RenderContext<'a>,
51 import_path: ModPath, 50 import_edit: ImportEdit,
52 import_scope: ImportScope,
53 merge_behaviour: Option<MergeBehaviour>,
54 resolution: &ScopeDef, 51 resolution: &ScopeDef,
55) -> Option<CompletionItem> { 52) -> Option<CompletionItem> {
56 let local_name = import_path.segments.last()?.to_string();
57 Render::new(ctx).render_resolution( 53 Render::new(ctx).render_resolution(
58 local_name, 54 import_edit.import_path.segments.last()?.to_string(),
59 Some(ImportEdit { import_path, import_scope, merge_behaviour }), 55 Some(import_edit),
60 resolution, 56 resolution,
61 ) 57 )
62} 58}
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 9e38d6506..4a274f5ba 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -469,6 +469,28 @@ impl Analysis {
469 self.with_db(|db| completion::completions(db, config, position).map(Into::into)) 469 self.with_db(|db| completion::completions(db, config, position).map(Into::into))
470 } 470 }
471 471
472 /// Resolves additional completion data at the position given.
473 pub fn resolve_completion_edits(
474 &self,
475 config: &CompletionConfig,
476 position: FilePosition,
477 full_import_path: &str,
478 imported_name: &str,
479 ) -> Cancelable<Vec<TextEdit>> {
480 Ok(self
481 .with_db(|db| {
482 completion::resolve_completion_edits(
483 db,
484 config,
485 position,
486 full_import_path,
487 imported_name,
488 )
489 })?
490 .map(|edit| vec![edit])
491 .unwrap_or_default())
492 }
493
472 /// Computes resolved assists with source changes for the given position. 494 /// Computes resolved assists with source changes for the given position.
473 pub fn resolved_assists( 495 pub fn resolved_assists(
474 &self, 496 &self,
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index dacd4ec50..f92280524 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -8,8 +8,8 @@ use std::{
8}; 8};
9 9
10use ide::{ 10use ide::{
11 CompletionResolveCapability, FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, 11 CompletionConfig, CompletionResolveCapability, FileId, FilePosition, FileRange, HoverAction,
12 ImportEdit, LineIndex, NavigationTarget, Query, RangeInfo, Runnable, RunnableKind, SearchScope, 12 HoverGotoTypeData, NavigationTarget, Query, RangeInfo, Runnable, RunnableKind, SearchScope,
13 TextEdit, 13 TextEdit,
14}; 14};
15use itertools::Itertools; 15use itertools::Itertools;
@@ -22,7 +22,7 @@ use lsp_types::{
22 HoverContents, Location, NumberOrString, Position, PrepareRenameResponse, Range, RenameParams, 22 HoverContents, Location, NumberOrString, Position, PrepareRenameResponse, Range, RenameParams,
23 SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams, 23 SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams,
24 SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, 24 SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation,
25 SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit, 25 SymbolTag, TextDocumentIdentifier, TextDocumentPositionParams, Url, WorkspaceEdit,
26}; 26};
27use project_model::TargetKind; 27use project_model::TargetKind;
28use serde::{Deserialize, Serialize}; 28use serde::{Deserialize, Serialize};
@@ -35,7 +35,6 @@ use crate::{
35 config::RustfmtConfig, 35 config::RustfmtConfig,
36 from_json, from_proto, 36 from_json, from_proto,
37 global_state::{GlobalState, GlobalStateSnapshot}, 37 global_state::{GlobalState, GlobalStateSnapshot},
38 line_endings::LineEndings,
39 lsp_ext::{self, InlayHint, InlayHintsParams}, 38 lsp_ext::{self, InlayHint, InlayHintsParams},
40 to_proto, LspError, Result, 39 to_proto, LspError, Result,
41}; 40};
@@ -541,7 +540,7 @@ pub(crate) fn handle_completion(
541 params: lsp_types::CompletionParams, 540 params: lsp_types::CompletionParams,
542) -> Result<Option<lsp_types::CompletionResponse>> { 541) -> Result<Option<lsp_types::CompletionResponse>> {
543 let _p = profile::span("handle_completion"); 542 let _p = profile::span("handle_completion");
544 let text_document_url = params.text_document_position.text_document.uri.clone(); 543 let text_document_position = params.text_document_position.clone();
545 let position = from_proto::file_position(&snap, params.text_document_position)?; 544 let position = from_proto::file_position(&snap, params.text_document_position)?;
546 let completion_triggered_after_single_colon = { 545 let completion_triggered_after_single_colon = {
547 let mut res = false; 546 let mut res = false;
@@ -574,23 +573,18 @@ pub(crate) fn handle_completion(
574 573
575 let items: Vec<CompletionItem> = items 574 let items: Vec<CompletionItem> = items
576 .into_iter() 575 .into_iter()
577 .enumerate() 576 .flat_map(|item| {
578 .flat_map(|(item_index, item)| {
579 let mut new_completion_items = 577 let mut new_completion_items =
580 to_proto::completion_item(&line_index, line_endings, item.clone()); 578 to_proto::completion_item(&line_index, line_endings, item.clone());
581 579
582 if snap.config.completion.resolve_additional_edits_lazily() { 580 for new_item in &mut new_completion_items {
583 // TODO kb add resolve data somehow here 581 let _ = fill_resolve_data(
584 if let Some(import_edit) = item.import_to_add() { 582 &mut new_item.data,
585 // let data = serde_json::to_value(&CompletionData { 583 &item,
586 // document_url: text_document_url.clone(), 584 &snap.config.completion,
587 // import_id: item_index, 585 &text_document_position,
588 // }) 586 )
589 // .expect(&format!("Should be able to serialize usize value {}", item_index)); 587 .take();
590 for new_item in &mut new_completion_items {
591 // new_item.data = Some(data.clone());
592 }
593 }
594 } 588 }
595 589
596 new_completion_items 590 new_completion_items
@@ -603,8 +597,8 @@ pub(crate) fn handle_completion(
603 597
604pub(crate) fn handle_completion_resolve( 598pub(crate) fn handle_completion_resolve(
605 snap: GlobalStateSnapshot, 599 snap: GlobalStateSnapshot,
606 mut original_completion: lsp_types::CompletionItem, 600 mut original_completion: CompletionItem,
607) -> Result<lsp_types::CompletionItem> { 601) -> Result<CompletionItem> {
608 let _p = profile::span("handle_resolve_completion"); 602 let _p = profile::span("handle_resolve_completion");
609 603
610 // FIXME resolve the other capabilities also? 604 // FIXME resolve the other capabilities also?
@@ -627,21 +621,30 @@ pub(crate) fn handle_completion_resolve(
627 None => return Ok(original_completion), 621 None => return Ok(original_completion),
628 }; 622 };
629 623
630 // TODO kb get the resolve data and somehow reparse the whole ast again? 624 let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?;
631 // let file_id = from_proto::file_id(&snap, &document_url)?; 625 let line_index = snap.analysis.file_line_index(file_id)?;
632 // let root = snap.analysis.parse(file_id)?; 626 let line_endings = snap.file_line_endings(file_id);
633 627 let offset = from_proto::offset(&line_index, resolve_data.position.position);
634 // if let Some(import_to_add) = 628
635 // import_edit_ptr.and_then(|import_edit| import_edit.into_import_edit(root.syntax())) 629 let mut additional_edits = snap
636 // { 630 .analysis
637 // // FIXME actually add all additional edits here? see `to_proto::completion_item` for more 631 .resolve_completion_edits(
638 // append_import_edits( 632 &snap.config.completion,
639 // &mut original_completion, 633 FilePosition { file_id, offset },
640 // &import_to_add, 634 &resolve_data.full_import_path,
641 // snap.analysis.file_line_index(file_id)?.as_ref(), 635 &resolve_data.imported_name,
642 // snap.file_line_endings(file_id), 636 )?
643 // ); 637 .into_iter()
644 // } 638 .flat_map(|edit| {
639 edit.into_iter().map(|indel| to_proto::text_edit(&line_index, line_endings, indel))
640 })
641 .collect_vec();
642
643 if let Some(original_additional_edits) = original_completion.additional_text_edits.as_mut() {
644 original_additional_edits.extend(additional_edits.drain(..))
645 } else {
646 original_completion.additional_text_edits = Some(additional_edits);
647 }
645 648
646 Ok(original_completion) 649 Ok(original_completion)
647} 650}
@@ -1606,27 +1609,30 @@ fn should_skip_target(runnable: &Runnable, cargo_spec: Option<&CargoTargetSpec>)
1606 1609
1607#[derive(Debug, Serialize, Deserialize)] 1610#[derive(Debug, Serialize, Deserialize)]
1608struct CompletionResolveData { 1611struct CompletionResolveData {
1609 document_url: Url, 1612 position: lsp_types::TextDocumentPositionParams,
1610 import_id: usize, 1613 full_import_path: String,
1614 imported_name: String,
1611} 1615}
1612 1616
1613fn append_import_edits( 1617fn fill_resolve_data(
1614 completion: &mut lsp_types::CompletionItem, 1618 resolve_data: &mut Option<serde_json::Value>,
1615 import_to_add: &ImportEdit, 1619 item: &ide::CompletionItem,
1616 line_index: &LineIndex, 1620 completion_config: &CompletionConfig,
1617 line_endings: LineEndings, 1621 position: &TextDocumentPositionParams,
1618) { 1622) -> Option<()> {
1619 let import_edits = import_to_add.to_text_edit().map(|import_edit| { 1623 if completion_config.resolve_additional_edits_lazily() {
1620 import_edit 1624 let import_edit = item.import_to_add()?;
1621 .into_iter() 1625 let full_import_path = import_edit.import_path.to_string();
1622 .map(|indel| to_proto::text_edit(line_index, line_endings, indel)) 1626 let imported_name = import_edit.import_path.segments.clone().pop()?.to_string();
1623 .collect_vec() 1627
1624 }); 1628 *resolve_data = Some(
1625 if let Some(original_additional_edits) = completion.additional_text_edits.as_mut() { 1629 serde_json::to_value(CompletionResolveData {
1626 if let Some(mut new_edits) = import_edits { 1630 position: position.to_owned(),
1627 original_additional_edits.extend(new_edits.drain(..)) 1631 full_import_path,
1628 } 1632 imported_name,
1629 } else { 1633 })
1630 completion.additional_text_edits = import_edits; 1634 .expect("Failed to serialize a regular struct with derives"),
1635 )
1631 } 1636 }
1637 Some(())
1632} 1638}