]> git.lizzy.rs Git - rust.git/commitdiff
Working resolve completion imports prototype
authorKirill Bulatov <mail4score@gmail.com>
Mon, 30 Nov 2020 20:28:19 +0000 (22:28 +0200)
committerKirill Bulatov <mail4score@gmail.com>
Mon, 7 Dec 2020 21:41:08 +0000 (23:41 +0200)
crates/completion/src/item.rs
crates/completion/src/lib.rs
crates/ide/src/lib.rs
crates/rust-analyzer/src/completions.rs [new file with mode: 0644]
crates/rust-analyzer/src/global_state.rs
crates/rust-analyzer/src/handlers.rs
crates/rust-analyzer/src/lib.rs
crates/rust-analyzer/src/main_loop.rs
crates/rust-analyzer/src/to_proto.rs

index ce6a44e57dbffac4bdf0a8b3fc2914606136f21e..0e59f73cb4beb09b26ba0f0e89e3fd9692658d6a 100644 (file)
@@ -257,14 +257,18 @@ pub fn trigger_call_info(&self) -> bool {
     pub fn ref_match(&self) -> Option<(Mutability, CompletionScore)> {
         self.ref_match
     }
+
+    pub fn import_to_add(&self) -> Option<&ImportToAdd> {
+        self.import_to_add.as_ref()
+    }
 }
 
 /// An extra import to add after the completion is applied.
-#[derive(Clone)]
-pub(crate) struct ImportToAdd {
-    pub(crate) import_path: ModPath,
-    pub(crate) import_scope: ImportScope,
-    pub(crate) merge_behaviour: Option<MergeBehaviour>,
+#[derive(Debug, Clone)]
+pub struct ImportToAdd {
+    pub import_path: ModPath,
+    pub import_scope: ImportScope,
+    pub merge_behaviour: Option<MergeBehaviour>,
 }
 
 /// A helper to make `CompletionItem`s.
index 1ec2e9be72de5433a46669198c2b95a671d3d229..28209d4e0a9e479eb61719b300327da5dd56b36a 100644 (file)
@@ -18,7 +18,7 @@
 
 pub use crate::{
     config::CompletionConfig,
-    item::{CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat},
+    item::{CompletionItem, CompletionItemKind, CompletionScore, ImportToAdd, InsertTextFormat},
 };
 
 //FIXME: split the following feature into fine-grained features.
index 5244bdd610e086fcc0be5255c2058f43bcbd3932..7015a512680b6fdb5709b3d08cd18a80797975d2 100644 (file)
@@ -80,7 +80,8 @@ macro_rules! eprintln {
     },
 };
 pub use completion::{
-    CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat,
+    CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, ImportToAdd,
+    InsertTextFormat,
 };
 pub use ide_db::{
     call_info::CallInfo,
diff --git a/crates/rust-analyzer/src/completions.rs b/crates/rust-analyzer/src/completions.rs
new file mode 100644 (file)
index 0000000..d4971f0
--- /dev/null
@@ -0,0 +1,2 @@
+#[derive(Debug, Default)]
+pub struct CompletionResolveActions {}
index a27495d0d80a3ba7fc5a6b185e4e615e5f379543..dc9e7113be24d5baebda14a2a28c9fb4fd844a51 100644 (file)
@@ -7,7 +7,7 @@
 
 use crossbeam_channel::{unbounded, Receiver, Sender};
 use flycheck::FlycheckHandle;
-use ide::{Analysis, AnalysisHost, Change, FileId};
+use ide::{Analysis, AnalysisHost, Change, FileId, ImportToAdd};
 use ide_db::base_db::{CrateId, VfsPath};
 use lsp_types::{SemanticTokens, Url};
 use parking_lot::{Mutex, RwLock};
@@ -69,6 +69,7 @@ pub(crate) struct GlobalState {
     pub(crate) config: Config,
     pub(crate) analysis_host: AnalysisHost,
     pub(crate) diagnostics: DiagnosticCollection,
+    pub(crate) additional_imports: FxHashMap<String, ImportToAdd>,
     pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>,
     pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
     pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
@@ -121,6 +122,7 @@ pub(crate) fn new(sender: Sender<lsp_server::Message>, config: Config) -> Global
             config,
             analysis_host,
             diagnostics: Default::default(),
+            additional_imports: FxHashMap::default(),
             mem_docs: FxHashMap::default(),
             semantic_tokens_cache: Arc::new(Default::default()),
             vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
index 255a6e489c0461f9e39bc0216c82cbaea3c52124..853f7fa84441c783068d2de80549dadc4062611b 100644 (file)
@@ -11,6 +11,7 @@
     FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, NavigationTarget, Query,
     RangeInfo, Runnable, RunnableKind, SearchScope, TextEdit,
 };
+use ide_db::helpers::{insert_use, mod_path_to_ast};
 use itertools::Itertools;
 use lsp_server::ErrorCode;
 use lsp_types::{
@@ -24,6 +25,7 @@
     SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
 };
 use project_model::TargetKind;
+use rustc_hash::FxHashMap;
 use serde::{Deserialize, Serialize};
 use serde_json::to_value;
 use stdx::{format_to, split_once};
@@ -535,10 +537,11 @@ pub(crate) fn handle_runnables(
 }
 
 pub(crate) fn handle_completion(
-    snap: GlobalStateSnapshot,
+    global_state: &mut GlobalState,
     params: lsp_types::CompletionParams,
 ) -> Result<Option<lsp_types::CompletionResponse>> {
     let _p = profile::span("handle_completion");
+    let snap = global_state.snapshot();
     let position = from_proto::file_position(&snap, params.text_document_position)?;
     let completion_triggered_after_single_colon = {
         let mut res = false;
@@ -568,22 +571,68 @@ pub(crate) fn handle_completion(
     };
     let line_index = snap.analysis.file_line_index(position.file_id)?;
     let line_endings = snap.file_line_endings(position.file_id);
+    let mut additional_imports = FxHashMap::default();
+
     let items: Vec<CompletionItem> = items
         .into_iter()
-        .flat_map(|item| to_proto::completion_item(&line_index, line_endings, item))
+        .flat_map(|item| {
+            let import_to_add = item.import_to_add().cloned();
+            let new_completion_items = to_proto::completion_item(&line_index, line_endings, item);
+            if let Some(import_to_add) = import_to_add {
+                for new_item in &new_completion_items {
+                    additional_imports.insert(new_item.label.clone(), import_to_add.clone());
+                }
+            }
+            new_completion_items
+        })
+        .map(|mut item| {
+            item.data = Some(position.file_id.0.into());
+            item
+        })
         .collect();
 
+    global_state.additional_imports = additional_imports;
+
     let completion_list = lsp_types::CompletionList { is_incomplete: true, items };
     Ok(Some(completion_list.into()))
 }
 
 pub(crate) fn handle_resolve_completion(
-    snap: GlobalStateSnapshot,
-    original_completion: CompletionItem,
-) -> Result<CompletionItem> {
+    global_state: &mut GlobalState,
+    mut original_completion: lsp_types::CompletionItem,
+) -> Result<lsp_types::CompletionItem> {
+    // TODO kb slow, takes over 130ms
     let _p = profile::span("handle_resolve_completion");
-    // TODO kb use the field to detect it's for autocompletion and do the insert logic
-    let _data = dbg!(original_completion).data;
+
+    if let Some(import_data) =
+        global_state.additional_imports.get(dbg!(original_completion.label.as_str()))
+    {
+        let rewriter = insert_use::insert_use(
+            &import_data.import_scope,
+            mod_path_to_ast(&import_data.import_path),
+            import_data.merge_behaviour,
+        );
+        if let Some((old_ast, file_id)) =
+            // TODO kb for file_id, better use &str and then cast to u32?
+            rewriter
+            .rewrite_root()
+            .zip(original_completion.data.as_ref().and_then(|value| Some(value.as_u64()? as u32)))
+        {
+            let snap = global_state.snapshot();
+            let mut import_insert = TextEdit::builder();
+            algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert);
+            let line_index = snap.analysis.file_line_index(FileId(file_id))?;
+            let line_endings = snap.file_line_endings(FileId(file_id));
+            let text_edit = import_insert.finish();
+
+            let mut new_edits = original_completion.additional_text_edits.unwrap_or_default();
+            for indel in text_edit {
+                new_edits.push(to_proto::text_edit(&line_index, line_endings, indel));
+            }
+            original_completion.additional_text_edits = Some(new_edits);
+        }
+    }
+
     Ok(original_completion)
 }
 
index ad08f1afb5abb1e79b35a6b8f613b998f410ef1d..13f14398f26547bdd50a8266793a1715d737c5fc 100644 (file)
@@ -36,6 +36,7 @@ macro_rules! eprintln {
 mod document;
 pub mod lsp_ext;
 pub mod config;
+mod completions;
 
 use ide::AnalysisHost;
 use serde::de::DeserializeOwned;
index 12b0946ac6d16ecdaf83e88ff9a6b9f23f7952ec..21c58d959e4e6e0a62f6e0f6edb6cf5cc0a5a244 100644 (file)
@@ -436,6 +436,10 @@ fn on_request(&mut self, request_received: Instant, req: Request) -> Result<()>
                 handlers::handle_matching_brace(s.snapshot(), p)
             })?
             .on_sync::<lsp_ext::MemoryUsage>(|s, p| handlers::handle_memory_usage(s, p))?
+            .on_sync::<lsp_types::request::Completion>(handlers::handle_completion)?
+            .on_sync::<lsp_types::request::ResolveCompletionItem>(
+                handlers::handle_resolve_completion,
+            )?
             .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
             .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
             .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)
@@ -453,8 +457,6 @@ fn on_request(&mut self, request_received: Instant, req: Request) -> Result<()>
             .on::<lsp_types::request::GotoDefinition>(handlers::handle_goto_definition)
             .on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation)
             .on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
-            .on::<lsp_types::request::Completion>(handlers::handle_completion)
-            .on::<lsp_types::request::ResolveCompletionItem>(handlers::handle_resolve_completion)
             .on::<lsp_types::request::CodeLensRequest>(handlers::handle_code_lens)
             .on::<lsp_types::request::CodeLensResolve>(handlers::handle_code_lens_resolve)
             .on::<lsp_types::request::FoldingRangeRequest>(handlers::handle_folding_range)
index db9ed08f6f2f88cab362271b1757a9d96b40fdc7..01eabe8526a561e279a41be34635e1c49ce46f09 100644 (file)
@@ -231,35 +231,6 @@ fn set_score(res: &mut lsp_types::CompletionItem, label: &str) {
         None => vec![res],
     };
 
-    // TODO kb need to get this logic away and store for the later resolve request
-    /*
-    let mut label = self.label;
-    let mut lookup = self.lookup;
-    let mut insert_text = self.insert_text;
-    let mut text_edits = TextEdit::builder();
-
-    if let Some((import_path, import_scope, merge_behaviour)) = completion_item.import_data.as_ref() {
-        let import = mod_path_to_ast(&import_path);
-            let mut import_path_without_last_segment = import_path;
-            let _ = import_path_without_last_segment.segments.pop();
-
-            if !import_path_without_last_segment.segments.is_empty() {
-                if lookup.is_none() {
-                    lookup = Some(label.clone());
-                }
-                if insert_text.is_none() {
-                    insert_text = Some(label.clone());
-                }
-                label = format!("{}::{}", import_path_without_last_segment, label);
-            }
-
-            let rewriter = insert_use(&import_scope, import, merge_behaviour);
-            if let Some(old_ast) = rewriter.rewrite_root() {
-                algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut text_edits);
-            }
-    }
-    */
-
     for mut r in all_results.iter_mut() {
         r.insert_text_format = Some(insert_text_format(completion_item.insert_text_format()));
     }