aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirill Bulatov <[email protected]>2020-11-30 20:28:19 +0000
committerKirill Bulatov <[email protected]>2020-12-07 21:41:08 +0000
commit6d2d27938985e210d5b5e561df8a48be20343be7 (patch)
tree511e624608a4b79c8020d41425ecdaa30186891f
parent48acd7d455be43960d67632adc9eb176a10a8afe (diff)
Working resolve completion imports prototype
-rw-r--r--crates/completion/src/item.rs14
-rw-r--r--crates/completion/src/lib.rs2
-rw-r--r--crates/ide/src/lib.rs3
-rw-r--r--crates/rust-analyzer/src/completions.rs2
-rw-r--r--crates/rust-analyzer/src/global_state.rs4
-rw-r--r--crates/rust-analyzer/src/handlers.rs63
-rw-r--r--crates/rust-analyzer/src/lib.rs1
-rw-r--r--crates/rust-analyzer/src/main_loop.rs6
-rw-r--r--crates/rust-analyzer/src/to_proto.rs29
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)]
264pub(crate) struct ImportToAdd { 268pub 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
19pub use crate::{ 19pub 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};
82pub use completion::{ 82pub use completion::{
83 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat, 83 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportToAdd,
84 InsertTextFormat,
84}; 85};
85pub use ide_db::{ 86pub 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)]
2pub 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
8use crossbeam_channel::{unbounded, Receiver, Sender}; 8use crossbeam_channel::{unbounded, Receiver, Sender};
9use flycheck::FlycheckHandle; 9use flycheck::FlycheckHandle;
10use ide::{Analysis, AnalysisHost, Change, FileId}; 10use ide::{Analysis, AnalysisHost, Change, FileId, ImportToAdd};
11use ide_db::base_db::{CrateId, VfsPath}; 11use ide_db::base_db::{CrateId, VfsPath};
12use lsp_types::{SemanticTokens, Url}; 12use lsp_types::{SemanticTokens, Url};
13use parking_lot::{Mutex, RwLock}; 13use 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};
14use ide_db::helpers::{insert_use, mod_path_to_ast};
14use itertools::Itertools; 15use itertools::Itertools;
15use lsp_server::ErrorCode; 16use lsp_server::ErrorCode;
16use lsp_types::{ 17use lsp_types::{
@@ -24,6 +25,7 @@ use lsp_types::{
24 SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit, 25 SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
25}; 26};
26use project_model::TargetKind; 27use project_model::TargetKind;
28use rustc_hash::FxHashMap;
27use serde::{Deserialize, Serialize}; 29use serde::{Deserialize, Serialize};
28use serde_json::to_value; 30use serde_json::to_value;
29use stdx::{format_to, split_once}; 31use stdx::{format_to, split_once};
@@ -535,10 +537,11 @@ pub(crate) fn handle_runnables(
535} 537}
536 538
537pub(crate) fn handle_completion( 539pub(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
580pub(crate) fn handle_resolve_completion( 600pub(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;
36mod document; 36mod document;
37pub mod lsp_ext; 37pub mod lsp_ext;
38pub mod config; 38pub mod config;
39mod completions;
39 40
40use ide::AnalysisHost; 41use ide::AnalysisHost;
41use serde::de::DeserializeOwned; 42use 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 }