diff options
author | Kirill Bulatov <[email protected]> | 2020-12-04 14:03:22 +0000 |
---|---|---|
committer | Kirill Bulatov <[email protected]> | 2020-12-07 21:41:08 +0000 |
commit | deda74edd89affb3f77d274776d2a672bc11db90 (patch) | |
tree | e9c7dac6df4fd06012ca6b6e628223e925998f1e | |
parent | 93bc009a5968c964693299263689b50b2efe9abc (diff) |
Use stateless completion resolve
-rw-r--r-- | crates/completion/src/completions/unqualified_path.rs | 10 | ||||
-rw-r--r-- | crates/completion/src/item.rs | 1 | ||||
-rw-r--r-- | crates/completion/src/lib.rs | 32 | ||||
-rw-r--r-- | crates/completion/src/render.rs | 12 | ||||
-rw-r--r-- | crates/ide/src/lib.rs | 22 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 118 |
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 | ||
10 | use crate::{ | 10 | use 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 | ||
15 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 15 | pub(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 | ||
278 | impl ImportEdit { | 278 | impl 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 | ||
12 | mod completions; | 12 | mod completions; |
13 | 13 | ||
14 | use ide_db::base_db::FilePosition; | 14 | use ide_db::{ |
15 | use ide_db::RootDatabase; | 15 | base_db::FilePosition, helpers::insert_use::ImportScope, imports_locator, RootDatabase, |
16 | }; | ||
17 | use syntax::AstNode; | ||
18 | use text_edit::TextEdit; | ||
16 | 19 | ||
17 | use crate::{completions::Completions, context::CompletionContext, item::CompletionKind}; | 20 | use 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. | ||
138 | pub 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)] |
135 | mod tests { | 163 | mod 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 | ||
10 | mod builder_ext; | 10 | mod builder_ext; |
11 | 11 | ||
12 | use hir::{Documentation, HasAttrs, HirDisplay, ModPath, Mutability, ScopeDef, Type}; | 12 | use hir::{Documentation, HasAttrs, HirDisplay, Mutability, ScopeDef, Type}; |
13 | use ide_db::helpers::insert_use::{ImportScope, MergeBehaviour}; | ||
14 | use ide_db::RootDatabase; | 13 | use ide_db::RootDatabase; |
15 | use syntax::TextRange; | 14 | use syntax::TextRange; |
16 | use test_utils::mark; | 15 | use test_utils::mark; |
@@ -48,15 +47,12 @@ pub(crate) fn render_resolution<'a>( | |||
48 | 47 | ||
49 | pub(crate) fn render_resolution_with_import<'a>( | 48 | pub(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 | ||
10 | use ide::{ | 10 | use 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 | }; |
15 | use itertools::Itertools; | 15 | use 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 | }; |
27 | use project_model::TargetKind; | 27 | use project_model::TargetKind; |
28 | use serde::{Deserialize, Serialize}; | 28 | use 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 | ||
604 | pub(crate) fn handle_completion_resolve( | 598 | pub(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)] |
1608 | struct CompletionResolveData { | 1611 | struct 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 | ||
1613 | fn append_import_edits( | 1617 | fn 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 | } |