diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-11-17 17:50:08 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-11-17 17:50:08 +0000 |
commit | 156f7d6963fb6b47570bfa457fdf51733a182054 (patch) | |
tree | 1070543fd0be92d3ab720bc297962a5dad5e64e8 /crates/completion | |
parent | f4b4f17662a7a1c80743b3108bb0da28b0fe47e5 (diff) | |
parent | 16f0b2fdde2fba8f45cc18a8de11b45751c0f923 (diff) |
Merge #6553
6553: Auto imports in completion r=matklad a=SomeoneToIgnore
![completion](https://user-images.githubusercontent.com/2690773/99155339-ae4fb380-26bf-11eb-805a-655b1706ce70.gif)
Closes https://github.com/rust-analyzer/rust-analyzer/issues/1062 but does not handle the completion order, since it's a separate task for https://github.com/rust-analyzer/rust-analyzer/issues/4922 , https://github.com/rust-analyzer/rust-analyzer/issues/4922 and maybe something else.
2 quirks in the current implementation:
* traits are not auto imported during method completion
If I understand the current situation right, we cannot search for traits by a **part** of a method name, we need a full name with correct case to get a trait for it.
* VSCode (?) autocompletion is not as rigid as in Intellij Rust as you can notice on the animation.
Intellij is able to refresh the completions on every new symbol added, yet VS Code does not query the completions on every symbol for me.
With a few debug prints placed in RA, I've observed the following behaviour: after the first set of completion suggestions is received, next symbol input does not trigger a server request, if the completions contain this symbol.
When more symbols added, the existing completion suggestions are filtered out until none are left and only then, on the next symbol it queries for completions.
It seems like the only alternative to get an updated set of results is to manually retrigger it with Esc and Ctrl + Space.
Despite the eerie latter bullet, the completion seems to work pretty fine and fast nontheless, but if you have any ideas on how to make it more smooth, I'll gladly try it out.
Co-authored-by: Kirill Bulatov <[email protected]>
Diffstat (limited to 'crates/completion')
-rw-r--r-- | crates/completion/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/completion/src/completions.rs | 8 | ||||
-rw-r--r-- | crates/completion/src/completions/unqualified_path.rs | 130 | ||||
-rw-r--r-- | crates/completion/src/config.rs | 4 | ||||
-rw-r--r-- | crates/completion/src/item.rs | 59 | ||||
-rw-r--r-- | crates/completion/src/render.rs | 57 | ||||
-rw-r--r-- | crates/completion/src/render/enum_variant.rs | 10 | ||||
-rw-r--r-- | crates/completion/src/render/function.rs | 12 | ||||
-rw-r--r-- | crates/completion/src/render/macro_.rs | 12 |
9 files changed, 264 insertions, 29 deletions
diff --git a/crates/completion/Cargo.toml b/crates/completion/Cargo.toml index 3015ec9e0..e7df9d955 100644 --- a/crates/completion/Cargo.toml +++ b/crates/completion/Cargo.toml | |||
@@ -13,6 +13,7 @@ doctest = false | |||
13 | itertools = "0.9.0" | 13 | itertools = "0.9.0" |
14 | log = "0.4.8" | 14 | log = "0.4.8" |
15 | rustc-hash = "1.1.0" | 15 | rustc-hash = "1.1.0" |
16 | either = "1.6.1" | ||
16 | 17 | ||
17 | assists = { path = "../assists", version = "0.0.0" } | 18 | assists = { path = "../assists", version = "0.0.0" } |
18 | stdx = { path = "../stdx", version = "0.0.0" } | 19 | stdx = { path = "../stdx", version = "0.0.0" } |
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index 75dbb1a23..9b7d6c580 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs | |||
@@ -90,7 +90,7 @@ impl Completions { | |||
90 | Some(it) => it, | 90 | Some(it) => it, |
91 | None => return, | 91 | None => return, |
92 | }; | 92 | }; |
93 | if let Some(item) = render_macro(RenderContext::new(ctx), name, macro_) { | 93 | if let Some(item) = render_macro(RenderContext::new(ctx), None, name, macro_) { |
94 | self.add(item); | 94 | self.add(item); |
95 | } | 95 | } |
96 | } | 96 | } |
@@ -101,7 +101,7 @@ impl Completions { | |||
101 | func: hir::Function, | 101 | func: hir::Function, |
102 | local_name: Option<String>, | 102 | local_name: Option<String>, |
103 | ) { | 103 | ) { |
104 | let item = render_fn(RenderContext::new(ctx), local_name, func); | 104 | let item = render_fn(RenderContext::new(ctx), None, local_name, func); |
105 | self.add(item) | 105 | self.add(item) |
106 | } | 106 | } |
107 | 107 | ||
@@ -123,7 +123,7 @@ impl Completions { | |||
123 | variant: hir::EnumVariant, | 123 | variant: hir::EnumVariant, |
124 | path: ModPath, | 124 | path: ModPath, |
125 | ) { | 125 | ) { |
126 | let item = render_enum_variant(RenderContext::new(ctx), None, variant, Some(path)); | 126 | let item = render_enum_variant(RenderContext::new(ctx), None, None, variant, Some(path)); |
127 | self.add(item); | 127 | self.add(item); |
128 | } | 128 | } |
129 | 129 | ||
@@ -133,7 +133,7 @@ impl Completions { | |||
133 | variant: hir::EnumVariant, | 133 | variant: hir::EnumVariant, |
134 | local_name: Option<String>, | 134 | local_name: Option<String>, |
135 | ) { | 135 | ) { |
136 | let item = render_enum_variant(RenderContext::new(ctx), local_name, variant, None); | 136 | let item = render_enum_variant(RenderContext::new(ctx), None, local_name, variant, None); |
137 | self.add(item); | 137 | self.add(item); |
138 | } | 138 | } |
139 | } | 139 | } |
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs index 7df58e1da..86c143b63 100644 --- a/crates/completion/src/completions/unqualified_path.rs +++ b/crates/completion/src/completions/unqualified_path.rs | |||
@@ -1,10 +1,16 @@ | |||
1 | //! Completion of names from the current scope, e.g. locals and imported items. | 1 | //! Completion of names from the current scope, e.g. locals and imported items. |
2 | 2 | ||
3 | use assists::utils::ImportScope; | ||
4 | use either::Either; | ||
3 | use hir::{Adt, ModuleDef, ScopeDef, Type}; | 5 | use hir::{Adt, ModuleDef, ScopeDef, Type}; |
6 | use ide_db::imports_locator; | ||
4 | use syntax::AstNode; | 7 | use syntax::AstNode; |
5 | use test_utils::mark; | 8 | use test_utils::mark; |
6 | 9 | ||
7 | use crate::{CompletionContext, Completions}; | 10 | use crate::{ |
11 | render::{render_resolution_with_import, RenderContext}, | ||
12 | CompletionContext, Completions, | ||
13 | }; | ||
8 | 14 | ||
9 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 15 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
10 | if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { | 16 | if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { |
@@ -37,6 +43,8 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
37 | } | 43 | } |
38 | acc.add_resolution(ctx, name.to_string(), &res) | 44 | acc.add_resolution(ctx, name.to_string(), &res) |
39 | }); | 45 | }); |
46 | |||
47 | fuzzy_completion(acc, ctx).unwrap_or_default() | ||
40 | } | 48 | } |
41 | 49 | ||
42 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { | 50 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { |
@@ -63,6 +71,45 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T | |||
63 | } | 71 | } |
64 | } | 72 | } |
65 | 73 | ||
74 | fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | ||
75 | let _p = profile::span("fuzzy_completion"); | ||
76 | let current_module = ctx.scope.module()?; | ||
77 | let anchor = ctx.name_ref_syntax.as_ref()?; | ||
78 | let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; | ||
79 | |||
80 | let potential_import_name = ctx.token.to_string(); | ||
81 | |||
82 | let possible_imports = | ||
83 | imports_locator::find_similar_imports(&ctx.sema, ctx.krate?, &potential_import_name, 400) | ||
84 | .filter_map(|import_candidate| match import_candidate { | ||
85 | // when completing outside the use declaration, modules are pretty useless | ||
86 | // and tend to bloat the completion suggestions a lot | ||
87 | Either::Left(ModuleDef::Module(_)) => None, | ||
88 | Either::Left(module_def) => Some(( | ||
89 | current_module.find_use_path(ctx.db, module_def)?, | ||
90 | ScopeDef::ModuleDef(module_def), | ||
91 | )), | ||
92 | Either::Right(macro_def) => Some(( | ||
93 | current_module.find_use_path(ctx.db, macro_def)?, | ||
94 | ScopeDef::MacroDef(macro_def), | ||
95 | )), | ||
96 | }) | ||
97 | .filter(|(mod_path, _)| mod_path.len() > 1) | ||
98 | .filter_map(|(import_path, definition)| { | ||
99 | render_resolution_with_import( | ||
100 | RenderContext::new(ctx), | ||
101 | import_path.clone(), | ||
102 | import_scope.clone(), | ||
103 | ctx.config.merge, | ||
104 | &definition, | ||
105 | ) | ||
106 | }) | ||
107 | .take(20); | ||
108 | |||
109 | acc.add_all(possible_imports); | ||
110 | Some(()) | ||
111 | } | ||
112 | |||
66 | #[cfg(test)] | 113 | #[cfg(test)] |
67 | mod tests { | 114 | mod tests { |
68 | use expect_test::{expect, Expect}; | 115 | use expect_test::{expect, Expect}; |
@@ -676,4 +723,85 @@ impl My<|> | |||
676 | "#]], | 723 | "#]], |
677 | ) | 724 | ) |
678 | } | 725 | } |
726 | |||
727 | #[test] | ||
728 | fn function_fuzzy_completion() { | ||
729 | check_edit( | ||
730 | "stdin", | ||
731 | r#" | ||
732 | //- /lib.rs crate:dep | ||
733 | pub mod io { | ||
734 | pub fn stdin() {} | ||
735 | }; | ||
736 | |||
737 | //- /main.rs crate:main deps:dep | ||
738 | fn main() { | ||
739 | stdi<|> | ||
740 | } | ||
741 | "#, | ||
742 | r#" | ||
743 | use dep::io::stdin; | ||
744 | |||
745 | fn main() { | ||
746 | stdin()$0 | ||
747 | } | ||
748 | "#, | ||
749 | ); | ||
750 | } | ||
751 | |||
752 | #[test] | ||
753 | fn macro_fuzzy_completion() { | ||
754 | check_edit( | ||
755 | "macro_with_curlies!", | ||
756 | r#" | ||
757 | //- /lib.rs crate:dep | ||
758 | /// Please call me as macro_with_curlies! {} | ||
759 | #[macro_export] | ||
760 | macro_rules! macro_with_curlies { | ||
761 | () => {} | ||
762 | } | ||
763 | |||
764 | //- /main.rs crate:main deps:dep | ||
765 | fn main() { | ||
766 | curli<|> | ||
767 | } | ||
768 | "#, | ||
769 | r#" | ||
770 | use dep::macro_with_curlies; | ||
771 | |||
772 | fn main() { | ||
773 | macro_with_curlies! {$0} | ||
774 | } | ||
775 | "#, | ||
776 | ); | ||
777 | } | ||
778 | |||
779 | #[test] | ||
780 | fn struct_fuzzy_completion() { | ||
781 | check_edit( | ||
782 | "ThirdStruct", | ||
783 | r#" | ||
784 | //- /lib.rs crate:dep | ||
785 | pub struct FirstStruct; | ||
786 | pub mod some_module { | ||
787 | pub struct SecondStruct; | ||
788 | pub struct ThirdStruct; | ||
789 | } | ||
790 | |||
791 | //- /main.rs crate:main deps:dep | ||
792 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
793 | |||
794 | fn main() { | ||
795 | this<|> | ||
796 | } | ||
797 | "#, | ||
798 | r#" | ||
799 | use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}}; | ||
800 | |||
801 | fn main() { | ||
802 | ThirdStruct | ||
803 | } | ||
804 | "#, | ||
805 | ); | ||
806 | } | ||
679 | } | 807 | } |
diff --git a/crates/completion/src/config.rs b/crates/completion/src/config.rs index 71b49ace8..82874ff25 100644 --- a/crates/completion/src/config.rs +++ b/crates/completion/src/config.rs | |||
@@ -4,12 +4,15 @@ | |||
4 | //! module, and we use to statically check that we only produce snippet | 4 | //! module, and we use to statically check that we only produce snippet |
5 | //! completions if we are allowed to. | 5 | //! completions if we are allowed to. |
6 | 6 | ||
7 | use assists::utils::MergeBehaviour; | ||
8 | |||
7 | #[derive(Clone, Debug, PartialEq, Eq)] | 9 | #[derive(Clone, Debug, PartialEq, Eq)] |
8 | pub struct CompletionConfig { | 10 | pub struct CompletionConfig { |
9 | pub enable_postfix_completions: bool, | 11 | pub enable_postfix_completions: bool, |
10 | pub add_call_parenthesis: bool, | 12 | pub add_call_parenthesis: bool, |
11 | pub add_call_argument_snippets: bool, | 13 | pub add_call_argument_snippets: bool, |
12 | pub snippet_cap: Option<SnippetCap>, | 14 | pub snippet_cap: Option<SnippetCap>, |
15 | pub merge: Option<MergeBehaviour>, | ||
13 | } | 16 | } |
14 | 17 | ||
15 | impl CompletionConfig { | 18 | impl CompletionConfig { |
@@ -30,6 +33,7 @@ impl Default for CompletionConfig { | |||
30 | add_call_parenthesis: true, | 33 | add_call_parenthesis: true, |
31 | add_call_argument_snippets: true, | 34 | add_call_argument_snippets: true, |
32 | snippet_cap: Some(SnippetCap { _private: () }), | 35 | snippet_cap: Some(SnippetCap { _private: () }), |
36 | merge: Some(MergeBehaviour::Full), | ||
33 | } | 37 | } |
34 | } | 38 | } |
35 | } | 39 | } |
diff --git a/crates/completion/src/item.rs b/crates/completion/src/item.rs index 6d1d085f4..b13c3f376 100644 --- a/crates/completion/src/item.rs +++ b/crates/completion/src/item.rs | |||
@@ -2,8 +2,9 @@ | |||
2 | 2 | ||
3 | use std::fmt; | 3 | use std::fmt; |
4 | 4 | ||
5 | use hir::{Documentation, Mutability}; | 5 | use assists::utils::{insert_use, mod_path_to_ast, ImportScope, MergeBehaviour}; |
6 | use syntax::TextRange; | 6 | use hir::{Documentation, ModPath, Mutability}; |
7 | use syntax::{algo, TextRange}; | ||
7 | use text_edit::TextEdit; | 8 | use text_edit::TextEdit; |
8 | 9 | ||
9 | use crate::config::SnippetCap; | 10 | use crate::config::SnippetCap; |
@@ -31,6 +32,7 @@ pub struct CompletionItem { | |||
31 | /// | 32 | /// |
32 | /// Typically, replaces `source_range` with new identifier. | 33 | /// Typically, replaces `source_range` with new identifier. |
33 | text_edit: TextEdit, | 34 | text_edit: TextEdit, |
35 | |||
34 | insert_text_format: InsertTextFormat, | 36 | insert_text_format: InsertTextFormat, |
35 | 37 | ||
36 | /// What item (struct, function, etc) are we completing. | 38 | /// What item (struct, function, etc) are we completing. |
@@ -199,8 +201,10 @@ impl CompletionItem { | |||
199 | trigger_call_info: None, | 201 | trigger_call_info: None, |
200 | score: None, | 202 | score: None, |
201 | ref_match: None, | 203 | ref_match: None, |
204 | import_data: None, | ||
202 | } | 205 | } |
203 | } | 206 | } |
207 | |||
204 | /// What user sees in pop-up in the UI. | 208 | /// What user sees in pop-up in the UI. |
205 | pub fn label(&self) -> &str { | 209 | pub fn label(&self) -> &str { |
206 | &self.label | 210 | &self.label |
@@ -257,6 +261,7 @@ impl CompletionItem { | |||
257 | pub(crate) struct Builder { | 261 | pub(crate) struct Builder { |
258 | source_range: TextRange, | 262 | source_range: TextRange, |
259 | completion_kind: CompletionKind, | 263 | completion_kind: CompletionKind, |
264 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
260 | label: String, | 265 | label: String, |
261 | insert_text: Option<String>, | 266 | insert_text: Option<String>, |
262 | insert_text_format: InsertTextFormat, | 267 | insert_text_format: InsertTextFormat, |
@@ -273,23 +278,50 @@ pub(crate) struct Builder { | |||
273 | 278 | ||
274 | impl Builder { | 279 | impl Builder { |
275 | pub(crate) fn build(self) -> CompletionItem { | 280 | pub(crate) fn build(self) -> CompletionItem { |
276 | let label = self.label; | 281 | let mut label = self.label; |
277 | let text_edit = match self.text_edit { | 282 | let mut lookup = self.lookup; |
283 | let mut insert_text = self.insert_text; | ||
284 | let mut text_edits = TextEdit::builder(); | ||
285 | |||
286 | if let Some((import_path, import_scope, merge_behaviour)) = self.import_data { | ||
287 | let import = mod_path_to_ast(&import_path); | ||
288 | let mut import_path_without_last_segment = import_path; | ||
289 | let _ = import_path_without_last_segment.segments.pop(); | ||
290 | |||
291 | if !import_path_without_last_segment.segments.is_empty() { | ||
292 | if lookup.is_none() { | ||
293 | lookup = Some(label.clone()); | ||
294 | } | ||
295 | if insert_text.is_none() { | ||
296 | insert_text = Some(label.clone()); | ||
297 | } | ||
298 | label = format!("{}::{}", import_path_without_last_segment, label); | ||
299 | } | ||
300 | |||
301 | let rewriter = insert_use(&import_scope, import, merge_behaviour); | ||
302 | if let Some(old_ast) = rewriter.rewrite_root() { | ||
303 | algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut text_edits); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | let original_edit = match self.text_edit { | ||
278 | Some(it) => it, | 308 | Some(it) => it, |
279 | None => TextEdit::replace( | 309 | None => { |
280 | self.source_range, | 310 | TextEdit::replace(self.source_range, insert_text.unwrap_or_else(|| label.clone())) |
281 | self.insert_text.unwrap_or_else(|| label.clone()), | 311 | } |
282 | ), | ||
283 | }; | 312 | }; |
284 | 313 | ||
314 | let mut resulting_edit = text_edits.finish(); | ||
315 | resulting_edit.union(original_edit).expect("Failed to unite text edits"); | ||
316 | |||
285 | CompletionItem { | 317 | CompletionItem { |
286 | source_range: self.source_range, | 318 | source_range: self.source_range, |
287 | label, | 319 | label, |
288 | insert_text_format: self.insert_text_format, | 320 | insert_text_format: self.insert_text_format, |
289 | text_edit, | 321 | text_edit: resulting_edit, |
290 | detail: self.detail, | 322 | detail: self.detail, |
291 | documentation: self.documentation, | 323 | documentation: self.documentation, |
292 | lookup: self.lookup, | 324 | lookup, |
293 | kind: self.kind, | 325 | kind: self.kind, |
294 | completion_kind: self.completion_kind, | 326 | completion_kind: self.completion_kind, |
295 | deprecated: self.deprecated.unwrap_or(false), | 327 | deprecated: self.deprecated.unwrap_or(false), |
@@ -358,6 +390,13 @@ impl Builder { | |||
358 | self.trigger_call_info = Some(true); | 390 | self.trigger_call_info = Some(true); |
359 | self | 391 | self |
360 | } | 392 | } |
393 | pub(crate) fn import_data( | ||
394 | mut self, | ||
395 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
396 | ) -> Builder { | ||
397 | self.import_data = import_data; | ||
398 | self | ||
399 | } | ||
361 | pub(crate) fn set_ref_match( | 400 | pub(crate) fn set_ref_match( |
362 | mut self, | 401 | mut self, |
363 | ref_match: Option<(Mutability, CompletionScore)>, | 402 | ref_match: Option<(Mutability, CompletionScore)>, |
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs index 1fa02c375..e892d4de8 100644 --- a/crates/completion/src/render.rs +++ b/crates/completion/src/render.rs | |||
@@ -9,7 +9,8 @@ pub(crate) mod type_alias; | |||
9 | 9 | ||
10 | mod builder_ext; | 10 | mod builder_ext; |
11 | 11 | ||
12 | use hir::{Documentation, HasAttrs, HirDisplay, Mutability, ScopeDef, Type}; | 12 | use assists::utils::{ImportScope, MergeBehaviour}; |
13 | use hir::{Documentation, HasAttrs, HirDisplay, ModPath, Mutability, ScopeDef, Type}; | ||
13 | use ide_db::RootDatabase; | 14 | use ide_db::RootDatabase; |
14 | use syntax::TextRange; | 15 | use syntax::TextRange; |
15 | use test_utils::mark; | 16 | use test_utils::mark; |
@@ -42,7 +43,22 @@ pub(crate) fn render_resolution<'a>( | |||
42 | local_name: String, | 43 | local_name: String, |
43 | resolution: &ScopeDef, | 44 | resolution: &ScopeDef, |
44 | ) -> Option<CompletionItem> { | 45 | ) -> Option<CompletionItem> { |
45 | Render::new(ctx).render_resolution(local_name, resolution) | 46 | Render::new(ctx).render_resolution(local_name, None, resolution) |
47 | } | ||
48 | |||
49 | pub(crate) fn render_resolution_with_import<'a>( | ||
50 | ctx: RenderContext<'a>, | ||
51 | import: ModPath, | ||
52 | import_scope: ImportScope, | ||
53 | merge_behaviour: Option<MergeBehaviour>, | ||
54 | resolution: &ScopeDef, | ||
55 | ) -> Option<CompletionItem> { | ||
56 | let local_name = import.segments.last()?.to_string(); | ||
57 | Render::new(ctx).render_resolution( | ||
58 | local_name, | ||
59 | Some((import, import_scope, merge_behaviour)), | ||
60 | resolution, | ||
61 | ) | ||
46 | } | 62 | } |
47 | 63 | ||
48 | /// Interface for data and methods required for items rendering. | 64 | /// Interface for data and methods required for items rendering. |
@@ -131,6 +147,7 @@ impl<'a> Render<'a> { | |||
131 | fn render_resolution( | 147 | fn render_resolution( |
132 | self, | 148 | self, |
133 | local_name: String, | 149 | local_name: String, |
150 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
134 | resolution: &ScopeDef, | 151 | resolution: &ScopeDef, |
135 | ) -> Option<CompletionItem> { | 152 | ) -> Option<CompletionItem> { |
136 | use hir::ModuleDef::*; | 153 | use hir::ModuleDef::*; |
@@ -142,15 +159,15 @@ impl<'a> Render<'a> { | |||
142 | 159 | ||
143 | let kind = match resolution { | 160 | let kind = match resolution { |
144 | ScopeDef::ModuleDef(Function(func)) => { | 161 | ScopeDef::ModuleDef(Function(func)) => { |
145 | let item = render_fn(self.ctx, Some(local_name), *func); | 162 | let item = render_fn(self.ctx, import_data, Some(local_name), *func); |
146 | return Some(item); | 163 | return Some(item); |
147 | } | 164 | } |
148 | ScopeDef::ModuleDef(EnumVariant(var)) => { | 165 | ScopeDef::ModuleDef(EnumVariant(var)) => { |
149 | let item = render_enum_variant(self.ctx, Some(local_name), *var, None); | 166 | let item = render_enum_variant(self.ctx, import_data, Some(local_name), *var, None); |
150 | return Some(item); | 167 | return Some(item); |
151 | } | 168 | } |
152 | ScopeDef::MacroDef(mac) => { | 169 | ScopeDef::MacroDef(mac) => { |
153 | let item = render_macro(self.ctx, local_name, *mac); | 170 | let item = render_macro(self.ctx, import_data, local_name, *mac); |
154 | return item; | 171 | return item; |
155 | } | 172 | } |
156 | 173 | ||
@@ -175,6 +192,7 @@ impl<'a> Render<'a> { | |||
175 | local_name, | 192 | local_name, |
176 | ) | 193 | ) |
177 | .kind(CompletionItemKind::UnresolvedReference) | 194 | .kind(CompletionItemKind::UnresolvedReference) |
195 | .import_data(import_data) | ||
178 | .build(); | 196 | .build(); |
179 | return Some(item); | 197 | return Some(item); |
180 | } | 198 | } |
@@ -227,7 +245,12 @@ impl<'a> Render<'a> { | |||
227 | } | 245 | } |
228 | } | 246 | } |
229 | 247 | ||
230 | let item = item.kind(kind).set_documentation(docs).set_ref_match(ref_match).build(); | 248 | let item = item |
249 | .kind(kind) | ||
250 | .import_data(import_data) | ||
251 | .set_documentation(docs) | ||
252 | .set_ref_match(ref_match) | ||
253 | .build(); | ||
231 | Some(item) | 254 | Some(item) |
232 | } | 255 | } |
233 | 256 | ||
@@ -426,6 +449,28 @@ fn main() { let _: m::Spam = S<|> } | |||
426 | kind: Module, | 449 | kind: Module, |
427 | }, | 450 | }, |
428 | CompletionItem { | 451 | CompletionItem { |
452 | label: "m::Spam", | ||
453 | source_range: 75..76, | ||
454 | text_edit: TextEdit { | ||
455 | indels: [ | ||
456 | Indel { | ||
457 | insert: "use m::Spam;", | ||
458 | delete: 0..0, | ||
459 | }, | ||
460 | Indel { | ||
461 | insert: "\n\n", | ||
462 | delete: 0..0, | ||
463 | }, | ||
464 | Indel { | ||
465 | insert: "Spam", | ||
466 | delete: 75..76, | ||
467 | }, | ||
468 | ], | ||
469 | }, | ||
470 | kind: Enum, | ||
471 | lookup: "Spam", | ||
472 | }, | ||
473 | CompletionItem { | ||
429 | label: "m::Spam::Foo", | 474 | label: "m::Spam::Foo", |
430 | source_range: 75..76, | 475 | source_range: 75..76, |
431 | delete: 75..76, | 476 | delete: 75..76, |
diff --git a/crates/completion/src/render/enum_variant.rs b/crates/completion/src/render/enum_variant.rs index fd412ed0e..6070e9b1d 100644 --- a/crates/completion/src/render/enum_variant.rs +++ b/crates/completion/src/render/enum_variant.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | //! Renderer for `enum` variants. | 1 | //! Renderer for `enum` variants. |
2 | 2 | ||
3 | use assists::utils::{ImportScope, MergeBehaviour}; | ||
3 | use hir::{HasAttrs, HirDisplay, ModPath, StructKind}; | 4 | use hir::{HasAttrs, HirDisplay, ModPath, StructKind}; |
4 | use itertools::Itertools; | 5 | use itertools::Itertools; |
5 | use test_utils::mark; | 6 | use test_utils::mark; |
@@ -11,11 +12,12 @@ use crate::{ | |||
11 | 12 | ||
12 | pub(crate) fn render_enum_variant<'a>( | 13 | pub(crate) fn render_enum_variant<'a>( |
13 | ctx: RenderContext<'a>, | 14 | ctx: RenderContext<'a>, |
15 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
14 | local_name: Option<String>, | 16 | local_name: Option<String>, |
15 | variant: hir::EnumVariant, | 17 | variant: hir::EnumVariant, |
16 | path: Option<ModPath>, | 18 | path: Option<ModPath>, |
17 | ) -> CompletionItem { | 19 | ) -> CompletionItem { |
18 | EnumVariantRender::new(ctx, local_name, variant, path).render() | 20 | EnumVariantRender::new(ctx, local_name, variant, path).render(import_data) |
19 | } | 21 | } |
20 | 22 | ||
21 | #[derive(Debug)] | 23 | #[derive(Debug)] |
@@ -60,7 +62,10 @@ impl<'a> EnumVariantRender<'a> { | |||
60 | } | 62 | } |
61 | } | 63 | } |
62 | 64 | ||
63 | fn render(self) -> CompletionItem { | 65 | fn render( |
66 | self, | ||
67 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
68 | ) -> CompletionItem { | ||
64 | let mut builder = CompletionItem::new( | 69 | let mut builder = CompletionItem::new( |
65 | CompletionKind::Reference, | 70 | CompletionKind::Reference, |
66 | self.ctx.source_range(), | 71 | self.ctx.source_range(), |
@@ -69,6 +74,7 @@ impl<'a> EnumVariantRender<'a> { | |||
69 | .kind(CompletionItemKind::EnumVariant) | 74 | .kind(CompletionItemKind::EnumVariant) |
70 | .set_documentation(self.variant.docs(self.ctx.db())) | 75 | .set_documentation(self.variant.docs(self.ctx.db())) |
71 | .set_deprecated(self.ctx.is_deprecated(self.variant)) | 76 | .set_deprecated(self.ctx.is_deprecated(self.variant)) |
77 | .import_data(import_data) | ||
72 | .detail(self.detail()); | 78 | .detail(self.detail()); |
73 | 79 | ||
74 | if self.variant_kind == StructKind::Tuple { | 80 | if self.variant_kind == StructKind::Tuple { |
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs index 4fa6eafd7..9dd5cd18c 100644 --- a/crates/completion/src/render/function.rs +++ b/crates/completion/src/render/function.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! Renderer for function calls. | 1 | //! Renderer for function calls. |
2 | 2 | ||
3 | use hir::{HasSource, Type}; | 3 | use assists::utils::{ImportScope, MergeBehaviour}; |
4 | use hir::{HasSource, ModPath, Type}; | ||
4 | use syntax::{ast::Fn, display::function_declaration}; | 5 | use syntax::{ast::Fn, display::function_declaration}; |
5 | 6 | ||
6 | use crate::{ | 7 | use crate::{ |
@@ -10,10 +11,11 @@ use crate::{ | |||
10 | 11 | ||
11 | pub(crate) fn render_fn<'a>( | 12 | pub(crate) fn render_fn<'a>( |
12 | ctx: RenderContext<'a>, | 13 | ctx: RenderContext<'a>, |
14 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
13 | local_name: Option<String>, | 15 | local_name: Option<String>, |
14 | fn_: hir::Function, | 16 | fn_: hir::Function, |
15 | ) -> CompletionItem { | 17 | ) -> CompletionItem { |
16 | FunctionRender::new(ctx, local_name, fn_).render() | 18 | FunctionRender::new(ctx, local_name, fn_).render(import_data) |
17 | } | 19 | } |
18 | 20 | ||
19 | #[derive(Debug)] | 21 | #[derive(Debug)] |
@@ -36,7 +38,10 @@ impl<'a> FunctionRender<'a> { | |||
36 | FunctionRender { ctx, name, fn_, ast_node } | 38 | FunctionRender { ctx, name, fn_, ast_node } |
37 | } | 39 | } |
38 | 40 | ||
39 | fn render(self) -> CompletionItem { | 41 | fn render( |
42 | self, | ||
43 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
44 | ) -> CompletionItem { | ||
40 | let params = self.params(); | 45 | let params = self.params(); |
41 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) | 46 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) |
42 | .kind(self.kind()) | 47 | .kind(self.kind()) |
@@ -44,6 +49,7 @@ impl<'a> FunctionRender<'a> { | |||
44 | .set_deprecated(self.ctx.is_deprecated(self.fn_)) | 49 | .set_deprecated(self.ctx.is_deprecated(self.fn_)) |
45 | .detail(self.detail()) | 50 | .detail(self.detail()) |
46 | .add_call_parens(self.ctx.completion, self.name, params) | 51 | .add_call_parens(self.ctx.completion, self.name, params) |
52 | .import_data(import_data) | ||
47 | .build() | 53 | .build() |
48 | } | 54 | } |
49 | 55 | ||
diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs index 96be59cc3..fead59e41 100644 --- a/crates/completion/src/render/macro_.rs +++ b/crates/completion/src/render/macro_.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! Renderer for macro invocations. | 1 | //! Renderer for macro invocations. |
2 | 2 | ||
3 | use hir::{Documentation, HasSource}; | 3 | use assists::utils::{ImportScope, MergeBehaviour}; |
4 | use hir::{Documentation, HasSource, ModPath}; | ||
4 | use syntax::display::macro_label; | 5 | use syntax::display::macro_label; |
5 | use test_utils::mark; | 6 | use test_utils::mark; |
6 | 7 | ||
@@ -11,10 +12,11 @@ use crate::{ | |||
11 | 12 | ||
12 | pub(crate) fn render_macro<'a>( | 13 | pub(crate) fn render_macro<'a>( |
13 | ctx: RenderContext<'a>, | 14 | ctx: RenderContext<'a>, |
15 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
14 | name: String, | 16 | name: String, |
15 | macro_: hir::MacroDef, | 17 | macro_: hir::MacroDef, |
16 | ) -> Option<CompletionItem> { | 18 | ) -> Option<CompletionItem> { |
17 | MacroRender::new(ctx, name, macro_).render() | 19 | MacroRender::new(ctx, name, macro_).render(import_data) |
18 | } | 20 | } |
19 | 21 | ||
20 | #[derive(Debug)] | 22 | #[derive(Debug)] |
@@ -36,7 +38,10 @@ impl<'a> MacroRender<'a> { | |||
36 | MacroRender { ctx, name, macro_, docs, bra, ket } | 38 | MacroRender { ctx, name, macro_, docs, bra, ket } |
37 | } | 39 | } |
38 | 40 | ||
39 | fn render(&self) -> Option<CompletionItem> { | 41 | fn render( |
42 | &self, | ||
43 | import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>, | ||
44 | ) -> Option<CompletionItem> { | ||
40 | // FIXME: Currently proc-macro do not have ast-node, | 45 | // FIXME: Currently proc-macro do not have ast-node, |
41 | // such that it does not have source | 46 | // such that it does not have source |
42 | if self.macro_.is_proc_macro() { | 47 | if self.macro_.is_proc_macro() { |
@@ -48,6 +53,7 @@ impl<'a> MacroRender<'a> { | |||
48 | .kind(CompletionItemKind::Macro) | 53 | .kind(CompletionItemKind::Macro) |
49 | .set_documentation(self.docs.clone()) | 54 | .set_documentation(self.docs.clone()) |
50 | .set_deprecated(self.ctx.is_deprecated(self.macro_)) | 55 | .set_deprecated(self.ctx.is_deprecated(self.macro_)) |
56 | .import_data(import_data) | ||
51 | .detail(self.detail()); | 57 | .detail(self.detail()); |
52 | 58 | ||
53 | let needs_bang = self.needs_bang(); | 59 | let needs_bang = self.needs_bang(); |