diff options
author | Kirill Bulatov <[email protected]> | 2020-11-30 20:28:19 +0000 |
---|---|---|
committer | Kirill Bulatov <[email protected]> | 2020-12-07 21:41:08 +0000 |
commit | 6d2d27938985e210d5b5e561df8a48be20343be7 (patch) | |
tree | 511e624608a4b79c8020d41425ecdaa30186891f | |
parent | 48acd7d455be43960d67632adc9eb176a10a8afe (diff) |
Working resolve completion imports prototype
-rw-r--r-- | crates/completion/src/item.rs | 14 | ||||
-rw-r--r-- | crates/completion/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ide/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/rust-analyzer/src/completions.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/global_state.rs | 4 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 63 | ||||
-rw-r--r-- | crates/rust-analyzer/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 6 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 29 |
9 files changed, 78 insertions, 46 deletions
diff --git a/crates/completion/src/item.rs b/crates/completion/src/item.rs index ce6a44e57..0e59f73cb 100644 --- a/crates/completion/src/item.rs +++ b/crates/completion/src/item.rs | |||
@@ -257,14 +257,18 @@ impl CompletionItem { | |||
257 | pub fn ref_match(&self) -> Option<(Mutability, CompletionScore)> { | 257 | pub fn ref_match(&self) -> Option<(Mutability, CompletionScore)> { |
258 | self.ref_match | 258 | self.ref_match |
259 | } | 259 | } |
260 | |||
261 | pub fn import_to_add(&self) -> Option<&ImportToAdd> { | ||
262 | self.import_to_add.as_ref() | ||
263 | } | ||
260 | } | 264 | } |
261 | 265 | ||
262 | /// An extra import to add after the completion is applied. | 266 | /// An extra import to add after the completion is applied. |
263 | #[derive(Clone)] | 267 | #[derive(Debug, Clone)] |
264 | pub(crate) struct ImportToAdd { | 268 | pub struct ImportToAdd { |
265 | pub(crate) import_path: ModPath, | 269 | pub import_path: ModPath, |
266 | pub(crate) import_scope: ImportScope, | 270 | pub import_scope: ImportScope, |
267 | pub(crate) merge_behaviour: Option<MergeBehaviour>, | 271 | pub merge_behaviour: Option<MergeBehaviour>, |
268 | } | 272 | } |
269 | 273 | ||
270 | /// A helper to make `CompletionItem`s. | 274 | /// A helper to make `CompletionItem`s. |
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs index 1ec2e9be7..28209d4e0 100644 --- a/crates/completion/src/lib.rs +++ b/crates/completion/src/lib.rs | |||
@@ -18,7 +18,7 @@ use crate::{completions::Completions, context::CompletionContext, item::Completi | |||
18 | 18 | ||
19 | pub use crate::{ | 19 | pub use crate::{ |
20 | config::CompletionConfig, | 20 | config::CompletionConfig, |
21 | item::{CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat}, | 21 | item::{CompletionItem, CompletionItemKind, CompletionScore, ImportToAdd, InsertTextFormat}, |
22 | }; | 22 | }; |
23 | 23 | ||
24 | //FIXME: split the following feature into fine-grained features. | 24 | //FIXME: split the following feature into fine-grained features. |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 5244bdd61..7015a5126 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -80,7 +80,8 @@ pub use crate::{ | |||
80 | }, | 80 | }, |
81 | }; | 81 | }; |
82 | pub use completion::{ | 82 | pub use completion::{ |
83 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat, | 83 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportToAdd, |
84 | InsertTextFormat, | ||
84 | }; | 85 | }; |
85 | pub use ide_db::{ | 86 | pub use ide_db::{ |
86 | call_info::CallInfo, | 87 | call_info::CallInfo, |
diff --git a/crates/rust-analyzer/src/completions.rs b/crates/rust-analyzer/src/completions.rs new file mode 100644 index 000000000..d4971f06e --- /dev/null +++ b/crates/rust-analyzer/src/completions.rs | |||
@@ -0,0 +1,2 @@ | |||
1 | #[derive(Debug, Default)] | ||
2 | pub struct CompletionResolveActions {} | ||
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index a27495d0d..dc9e7113b 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs | |||
@@ -7,7 +7,7 @@ use std::{sync::Arc, time::Instant}; | |||
7 | 7 | ||
8 | use crossbeam_channel::{unbounded, Receiver, Sender}; | 8 | use crossbeam_channel::{unbounded, Receiver, Sender}; |
9 | use flycheck::FlycheckHandle; | 9 | use flycheck::FlycheckHandle; |
10 | use ide::{Analysis, AnalysisHost, Change, FileId}; | 10 | use ide::{Analysis, AnalysisHost, Change, FileId, ImportToAdd}; |
11 | use ide_db::base_db::{CrateId, VfsPath}; | 11 | use ide_db::base_db::{CrateId, VfsPath}; |
12 | use lsp_types::{SemanticTokens, Url}; | 12 | use lsp_types::{SemanticTokens, Url}; |
13 | use parking_lot::{Mutex, RwLock}; | 13 | use parking_lot::{Mutex, RwLock}; |
@@ -69,6 +69,7 @@ pub(crate) struct GlobalState { | |||
69 | pub(crate) config: Config, | 69 | pub(crate) config: Config, |
70 | pub(crate) analysis_host: AnalysisHost, | 70 | pub(crate) analysis_host: AnalysisHost, |
71 | pub(crate) diagnostics: DiagnosticCollection, | 71 | pub(crate) diagnostics: DiagnosticCollection, |
72 | pub(crate) additional_imports: FxHashMap<String, ImportToAdd>, | ||
72 | pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>, | 73 | pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>, |
73 | pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>, | 74 | pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>, |
74 | pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>, | 75 | pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>, |
@@ -121,6 +122,7 @@ impl GlobalState { | |||
121 | config, | 122 | config, |
122 | analysis_host, | 123 | analysis_host, |
123 | diagnostics: Default::default(), | 124 | diagnostics: Default::default(), |
125 | additional_imports: FxHashMap::default(), | ||
124 | mem_docs: FxHashMap::default(), | 126 | mem_docs: FxHashMap::default(), |
125 | semantic_tokens_cache: Arc::new(Default::default()), | 127 | semantic_tokens_cache: Arc::new(Default::default()), |
126 | vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), | 128 | vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 255a6e489..853f7fa84 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -11,6 +11,7 @@ use ide::{ | |||
11 | FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, NavigationTarget, Query, | 11 | FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, NavigationTarget, Query, |
12 | RangeInfo, Runnable, RunnableKind, SearchScope, TextEdit, | 12 | RangeInfo, Runnable, RunnableKind, SearchScope, TextEdit, |
13 | }; | 13 | }; |
14 | use ide_db::helpers::{insert_use, mod_path_to_ast}; | ||
14 | use itertools::Itertools; | 15 | use itertools::Itertools; |
15 | use lsp_server::ErrorCode; | 16 | use lsp_server::ErrorCode; |
16 | use lsp_types::{ | 17 | use lsp_types::{ |
@@ -24,6 +25,7 @@ use lsp_types::{ | |||
24 | SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit, | 25 | SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit, |
25 | }; | 26 | }; |
26 | use project_model::TargetKind; | 27 | use project_model::TargetKind; |
28 | use rustc_hash::FxHashMap; | ||
27 | use serde::{Deserialize, Serialize}; | 29 | use serde::{Deserialize, Serialize}; |
28 | use serde_json::to_value; | 30 | use serde_json::to_value; |
29 | use stdx::{format_to, split_once}; | 31 | use stdx::{format_to, split_once}; |
@@ -535,10 +537,11 @@ pub(crate) fn handle_runnables( | |||
535 | } | 537 | } |
536 | 538 | ||
537 | pub(crate) fn handle_completion( | 539 | pub(crate) fn handle_completion( |
538 | snap: GlobalStateSnapshot, | 540 | global_state: &mut GlobalState, |
539 | params: lsp_types::CompletionParams, | 541 | params: lsp_types::CompletionParams, |
540 | ) -> Result<Option<lsp_types::CompletionResponse>> { | 542 | ) -> Result<Option<lsp_types::CompletionResponse>> { |
541 | let _p = profile::span("handle_completion"); | 543 | let _p = profile::span("handle_completion"); |
544 | let snap = global_state.snapshot(); | ||
542 | let position = from_proto::file_position(&snap, params.text_document_position)?; | 545 | let position = from_proto::file_position(&snap, params.text_document_position)?; |
543 | let completion_triggered_after_single_colon = { | 546 | let completion_triggered_after_single_colon = { |
544 | let mut res = false; | 547 | let mut res = false; |
@@ -568,22 +571,68 @@ pub(crate) fn handle_completion( | |||
568 | }; | 571 | }; |
569 | let line_index = snap.analysis.file_line_index(position.file_id)?; | 572 | let line_index = snap.analysis.file_line_index(position.file_id)?; |
570 | let line_endings = snap.file_line_endings(position.file_id); | 573 | let line_endings = snap.file_line_endings(position.file_id); |
574 | let mut additional_imports = FxHashMap::default(); | ||
575 | |||
571 | let items: Vec<CompletionItem> = items | 576 | let items: Vec<CompletionItem> = items |
572 | .into_iter() | 577 | .into_iter() |
573 | .flat_map(|item| to_proto::completion_item(&line_index, line_endings, item)) | 578 | .flat_map(|item| { |
579 | let import_to_add = item.import_to_add().cloned(); | ||
580 | let new_completion_items = to_proto::completion_item(&line_index, line_endings, item); | ||
581 | if let Some(import_to_add) = import_to_add { | ||
582 | for new_item in &new_completion_items { | ||
583 | additional_imports.insert(new_item.label.clone(), import_to_add.clone()); | ||
584 | } | ||
585 | } | ||
586 | new_completion_items | ||
587 | }) | ||
588 | .map(|mut item| { | ||
589 | item.data = Some(position.file_id.0.into()); | ||
590 | item | ||
591 | }) | ||
574 | .collect(); | 592 | .collect(); |
575 | 593 | ||
594 | global_state.additional_imports = additional_imports; | ||
595 | |||
576 | let completion_list = lsp_types::CompletionList { is_incomplete: true, items }; | 596 | let completion_list = lsp_types::CompletionList { is_incomplete: true, items }; |
577 | Ok(Some(completion_list.into())) | 597 | Ok(Some(completion_list.into())) |
578 | } | 598 | } |
579 | 599 | ||
580 | pub(crate) fn handle_resolve_completion( | 600 | pub(crate) fn handle_resolve_completion( |
581 | snap: GlobalStateSnapshot, | 601 | global_state: &mut GlobalState, |
582 | original_completion: CompletionItem, | 602 | mut original_completion: lsp_types::CompletionItem, |
583 | ) -> Result<CompletionItem> { | 603 | ) -> Result<lsp_types::CompletionItem> { |
604 | // TODO kb slow, takes over 130ms | ||
584 | let _p = profile::span("handle_resolve_completion"); | 605 | let _p = profile::span("handle_resolve_completion"); |
585 | // TODO kb use the field to detect it's for autocompletion and do the insert logic | 606 | |
586 | let _data = dbg!(original_completion).data; | 607 | if let Some(import_data) = |
608 | global_state.additional_imports.get(dbg!(original_completion.label.as_str())) | ||
609 | { | ||
610 | let rewriter = insert_use::insert_use( | ||
611 | &import_data.import_scope, | ||
612 | mod_path_to_ast(&import_data.import_path), | ||
613 | import_data.merge_behaviour, | ||
614 | ); | ||
615 | if let Some((old_ast, file_id)) = | ||
616 | // TODO kb for file_id, better use &str and then cast to u32? | ||
617 | rewriter | ||
618 | .rewrite_root() | ||
619 | .zip(original_completion.data.as_ref().and_then(|value| Some(value.as_u64()? as u32))) | ||
620 | { | ||
621 | let snap = global_state.snapshot(); | ||
622 | let mut import_insert = TextEdit::builder(); | ||
623 | algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert); | ||
624 | let line_index = snap.analysis.file_line_index(FileId(file_id))?; | ||
625 | let line_endings = snap.file_line_endings(FileId(file_id)); | ||
626 | let text_edit = import_insert.finish(); | ||
627 | |||
628 | let mut new_edits = original_completion.additional_text_edits.unwrap_or_default(); | ||
629 | for indel in text_edit { | ||
630 | new_edits.push(to_proto::text_edit(&line_index, line_endings, indel)); | ||
631 | } | ||
632 | original_completion.additional_text_edits = Some(new_edits); | ||
633 | } | ||
634 | } | ||
635 | |||
587 | Ok(original_completion) | 636 | Ok(original_completion) |
588 | } | 637 | } |
589 | 638 | ||
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index ad08f1afb..13f14398f 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs | |||
@@ -36,6 +36,7 @@ mod thread_pool; | |||
36 | mod document; | 36 | mod document; |
37 | pub mod lsp_ext; | 37 | pub mod lsp_ext; |
38 | pub mod config; | 38 | pub mod config; |
39 | mod completions; | ||
39 | 40 | ||
40 | use ide::AnalysisHost; | 41 | use ide::AnalysisHost; |
41 | use serde::de::DeserializeOwned; | 42 | use serde::de::DeserializeOwned; |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 12b0946ac..21c58d959 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -436,6 +436,10 @@ impl GlobalState { | |||
436 | handlers::handle_matching_brace(s.snapshot(), p) | 436 | handlers::handle_matching_brace(s.snapshot(), p) |
437 | })? | 437 | })? |
438 | .on_sync::<lsp_ext::MemoryUsage>(|s, p| handlers::handle_memory_usage(s, p))? | 438 | .on_sync::<lsp_ext::MemoryUsage>(|s, p| handlers::handle_memory_usage(s, p))? |
439 | .on_sync::<lsp_types::request::Completion>(handlers::handle_completion)? | ||
440 | .on_sync::<lsp_types::request::ResolveCompletionItem>( | ||
441 | handlers::handle_resolve_completion, | ||
442 | )? | ||
439 | .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status) | 443 | .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status) |
440 | .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree) | 444 | .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree) |
441 | .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro) | 445 | .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro) |
@@ -453,8 +457,6 @@ impl GlobalState { | |||
453 | .on::<lsp_types::request::GotoDefinition>(handlers::handle_goto_definition) | 457 | .on::<lsp_types::request::GotoDefinition>(handlers::handle_goto_definition) |
454 | .on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation) | 458 | .on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation) |
455 | .on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition) | 459 | .on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition) |
456 | .on::<lsp_types::request::Completion>(handlers::handle_completion) | ||
457 | .on::<lsp_types::request::ResolveCompletionItem>(handlers::handle_resolve_completion) | ||
458 | .on::<lsp_types::request::CodeLensRequest>(handlers::handle_code_lens) | 460 | .on::<lsp_types::request::CodeLensRequest>(handlers::handle_code_lens) |
459 | .on::<lsp_types::request::CodeLensResolve>(handlers::handle_code_lens_resolve) | 461 | .on::<lsp_types::request::CodeLensResolve>(handlers::handle_code_lens_resolve) |
460 | .on::<lsp_types::request::FoldingRangeRequest>(handlers::handle_folding_range) | 462 | .on::<lsp_types::request::FoldingRangeRequest>(handlers::handle_folding_range) |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index db9ed08f6..01eabe852 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -231,35 +231,6 @@ pub(crate) fn completion_item( | |||
231 | None => vec![res], | 231 | None => vec![res], |
232 | }; | 232 | }; |
233 | 233 | ||
234 | // TODO kb need to get this logic away and store for the later resolve request | ||
235 | /* | ||
236 | let mut label = self.label; | ||
237 | let mut lookup = self.lookup; | ||
238 | let mut insert_text = self.insert_text; | ||
239 | let mut text_edits = TextEdit::builder(); | ||
240 | |||
241 | if let Some((import_path, import_scope, merge_behaviour)) = completion_item.import_data.as_ref() { | ||
242 | let import = mod_path_to_ast(&import_path); | ||
243 | let mut import_path_without_last_segment = import_path; | ||
244 | let _ = import_path_without_last_segment.segments.pop(); | ||
245 | |||
246 | if !import_path_without_last_segment.segments.is_empty() { | ||
247 | if lookup.is_none() { | ||
248 | lookup = Some(label.clone()); | ||
249 | } | ||
250 | if insert_text.is_none() { | ||
251 | insert_text = Some(label.clone()); | ||
252 | } | ||
253 | label = format!("{}::{}", import_path_without_last_segment, label); | ||
254 | } | ||
255 | |||
256 | let rewriter = insert_use(&import_scope, import, merge_behaviour); | ||
257 | if let Some(old_ast) = rewriter.rewrite_root() { | ||
258 | algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut text_edits); | ||
259 | } | ||
260 | } | ||
261 | */ | ||
262 | |||
263 | for mut r in all_results.iter_mut() { | 234 | for mut r in all_results.iter_mut() { |
264 | r.insert_text_format = Some(insert_text_format(completion_item.insert_text_format())); | 235 | r.insert_text_format = Some(insert_text_format(completion_item.insert_text_format())); |
265 | } | 236 | } |