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/assists | |
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/assists')
-rw-r--r-- | crates/assists/src/handlers/auto_import.rs | 3 | ||||
-rw-r--r-- | crates/assists/src/handlers/extract_struct_from_enum_variant.rs | 3 | ||||
-rw-r--r-- | crates/assists/src/handlers/replace_derive_with_manual_impl.rs | 28 | ||||
-rw-r--r-- | crates/assists/src/handlers/replace_qualified_name_with_use.rs | 2 | ||||
-rw-r--r-- | crates/assists/src/utils.rs | 3 | ||||
-rw-r--r-- | crates/assists/src/utils/import_assets.rs | 34 | ||||
-rw-r--r-- | crates/assists/src/utils/insert_use.rs | 16 |
7 files changed, 48 insertions, 41 deletions
diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs index 37dd61266..d665837a2 100644 --- a/crates/assists/src/handlers/auto_import.rs +++ b/crates/assists/src/handlers/auto_import.rs | |||
@@ -98,7 +98,8 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
98 | 98 | ||
99 | let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range; | 99 | let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range; |
100 | let group = import_group_message(import_assets.import_candidate()); | 100 | let group = import_group_message(import_assets.import_candidate()); |
101 | let scope = ImportScope::find_insert_use_container(import_assets.syntax_under_caret(), ctx)?; | 101 | let scope = |
102 | ImportScope::find_insert_use_container(import_assets.syntax_under_caret(), &ctx.sema)?; | ||
102 | for (import, _) in proposed_imports { | 103 | for (import, _) in proposed_imports { |
103 | acc.add_group( | 104 | acc.add_group( |
104 | &group, | 105 | &group, |
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs index 067afabf2..cac77c49b 100644 --- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -143,8 +143,7 @@ fn insert_import( | |||
143 | if let Some(mut mod_path) = mod_path { | 143 | if let Some(mut mod_path) = mod_path { |
144 | mod_path.segments.pop(); | 144 | mod_path.segments.pop(); |
145 | mod_path.segments.push(variant_hir_name.clone()); | 145 | mod_path.segments.push(variant_hir_name.clone()); |
146 | let scope = ImportScope::find_insert_use_container(scope_node, ctx)?; | 146 | let scope = ImportScope::find_insert_use_container(scope_node, &ctx.sema)?; |
147 | |||
148 | *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use.merge); | 147 | *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use.merge); |
149 | } | 148 | } |
150 | Some(()) | 149 | Some(()) |
diff --git a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs index 82625516c..453a6cebf 100644 --- a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs | |||
@@ -62,19 +62,21 @@ pub(crate) fn replace_derive_with_manual_impl( | |||
62 | let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; | 62 | let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; |
63 | let current_crate = current_module.krate(); | 63 | let current_crate = current_module.krate(); |
64 | 64 | ||
65 | let found_traits = imports_locator::find_imports(&ctx.sema, current_crate, trait_token.text()) | 65 | let found_traits = |
66 | .into_iter() | 66 | imports_locator::find_exact_imports(&ctx.sema, current_crate, trait_token.text()) |
67 | .filter_map(|candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate { | 67 | .filter_map( |
68 | either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_), | 68 | |candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate { |
69 | _ => None, | 69 | either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_), |
70 | }) | 70 | _ => None, |
71 | .flat_map(|trait_| { | 71 | }, |
72 | current_module | 72 | ) |
73 | .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_)) | 73 | .flat_map(|trait_| { |
74 | .as_ref() | 74 | current_module |
75 | .map(mod_path_to_ast) | 75 | .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_)) |
76 | .zip(Some(trait_)) | 76 | .as_ref() |
77 | }); | 77 | .map(mod_path_to_ast) |
78 | .zip(Some(trait_)) | ||
79 | }); | ||
78 | 80 | ||
79 | let mut no_traits_found = true; | 81 | let mut no_traits_found = true; |
80 | for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { | 82 | for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { |
diff --git a/crates/assists/src/handlers/replace_qualified_name_with_use.rs b/crates/assists/src/handlers/replace_qualified_name_with_use.rs index d7e1d9580..a66db9ae3 100644 --- a/crates/assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -34,7 +34,7 @@ pub(crate) fn replace_qualified_name_with_use( | |||
34 | } | 34 | } |
35 | 35 | ||
36 | let target = path.syntax().text_range(); | 36 | let target = path.syntax().text_range(); |
37 | let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?; | 37 | let scope = ImportScope::find_insert_use_container(path.syntax(), &ctx.sema)?; |
38 | let syntax = scope.as_syntax_node(); | 38 | let syntax = scope.as_syntax_node(); |
39 | acc.add( | 39 | acc.add( |
40 | AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite), | 40 | AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite), |
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index d1a0a99b1..66c0cdd5f 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -22,8 +22,7 @@ use crate::{ | |||
22 | ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, | 22 | ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | pub use insert_use::MergeBehaviour; | 25 | pub use insert_use::{insert_use, ImportScope, MergeBehaviour}; |
26 | pub(crate) use insert_use::{insert_use, ImportScope}; | ||
27 | 26 | ||
28 | pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path { | 27 | pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path { |
29 | let mut segments = Vec::new(); | 28 | let mut segments = Vec::new(); |
diff --git a/crates/assists/src/utils/import_assets.rs b/crates/assists/src/utils/import_assets.rs index f47edbb76..ff5c0e78e 100644 --- a/crates/assists/src/utils/import_assets.rs +++ b/crates/assists/src/utils/import_assets.rs | |||
@@ -179,21 +179,25 @@ impl ImportAssets { | |||
179 | } | 179 | } |
180 | }; | 180 | }; |
181 | 181 | ||
182 | let mut res = imports_locator::find_imports(sema, current_crate, &self.get_search_query()) | 182 | let mut res = |
183 | .into_iter() | 183 | imports_locator::find_exact_imports(sema, current_crate, &self.get_search_query()) |
184 | .filter_map(filter) | 184 | .filter_map(filter) |
185 | .filter_map(|candidate| { | 185 | .filter_map(|candidate| { |
186 | let item: hir::ItemInNs = candidate.either(Into::into, Into::into); | 186 | let item: hir::ItemInNs = candidate.either(Into::into, Into::into); |
187 | if let Some(prefix_kind) = prefixed { | 187 | if let Some(prefix_kind) = prefixed { |
188 | self.module_with_name_to_import.find_use_path_prefixed(db, item, prefix_kind) | 188 | self.module_with_name_to_import.find_use_path_prefixed( |
189 | } else { | 189 | db, |
190 | self.module_with_name_to_import.find_use_path(db, item) | 190 | item, |
191 | } | 191 | prefix_kind, |
192 | .map(|path| (path, item)) | 192 | ) |
193 | }) | 193 | } else { |
194 | .filter(|(use_path, _)| !use_path.segments.is_empty()) | 194 | self.module_with_name_to_import.find_use_path(db, item) |
195 | .take(20) | 195 | } |
196 | .collect::<Vec<_>>(); | 196 | .map(|path| (path, item)) |
197 | }) | ||
198 | .filter(|(use_path, _)| use_path.len() > 1) | ||
199 | .take(20) | ||
200 | .collect::<Vec<_>>(); | ||
197 | res.sort_by_key(|(path, _)| path.clone()); | 201 | res.sort_by_key(|(path, _)| path.clone()); |
198 | res | 202 | res |
199 | } | 203 | } |
diff --git a/crates/assists/src/utils/insert_use.rs b/crates/assists/src/utils/insert_use.rs index af3fc96b6..423782a0e 100644 --- a/crates/assists/src/utils/insert_use.rs +++ b/crates/assists/src/utils/insert_use.rs | |||
@@ -1,6 +1,8 @@ | |||
1 | //! Handle syntactic aspects of inserting a new `use`. | 1 | //! Handle syntactic aspects of inserting a new `use`. |
2 | use std::{cmp::Ordering, iter::successors}; | 2 | use std::{cmp::Ordering, iter::successors}; |
3 | 3 | ||
4 | use hir::Semantics; | ||
5 | use ide_db::RootDatabase; | ||
4 | use itertools::{EitherOrBoth, Itertools}; | 6 | use itertools::{EitherOrBoth, Itertools}; |
5 | use syntax::{ | 7 | use syntax::{ |
6 | algo::SyntaxRewriter, | 8 | algo::SyntaxRewriter, |
@@ -13,8 +15,8 @@ use syntax::{ | |||
13 | }; | 15 | }; |
14 | use test_utils::mark; | 16 | use test_utils::mark; |
15 | 17 | ||
16 | #[derive(Debug)] | 18 | #[derive(Debug, Clone)] |
17 | pub(crate) enum ImportScope { | 19 | pub enum ImportScope { |
18 | File(ast::SourceFile), | 20 | File(ast::SourceFile), |
19 | Module(ast::ItemList), | 21 | Module(ast::ItemList), |
20 | } | 22 | } |
@@ -31,14 +33,14 @@ impl ImportScope { | |||
31 | } | 33 | } |
32 | 34 | ||
33 | /// Determines the containing syntax node in which to insert a `use` statement affecting `position`. | 35 | /// Determines the containing syntax node in which to insert a `use` statement affecting `position`. |
34 | pub(crate) fn find_insert_use_container( | 36 | pub fn find_insert_use_container( |
35 | position: &SyntaxNode, | 37 | position: &SyntaxNode, |
36 | ctx: &crate::assist_context::AssistContext, | 38 | sema: &Semantics<'_, RootDatabase>, |
37 | ) -> Option<Self> { | 39 | ) -> Option<Self> { |
38 | ctx.sema.ancestors_with_macros(position.clone()).find_map(Self::from) | 40 | sema.ancestors_with_macros(position.clone()).find_map(Self::from) |
39 | } | 41 | } |
40 | 42 | ||
41 | pub(crate) fn as_syntax_node(&self) -> &SyntaxNode { | 43 | pub fn as_syntax_node(&self) -> &SyntaxNode { |
42 | match self { | 44 | match self { |
43 | ImportScope::File(file) => file.syntax(), | 45 | ImportScope::File(file) => file.syntax(), |
44 | ImportScope::Module(item_list) => item_list.syntax(), | 46 | ImportScope::Module(item_list) => item_list.syntax(), |
@@ -88,7 +90,7 @@ fn is_inner_comment(token: SyntaxToken) -> bool { | |||
88 | } | 90 | } |
89 | 91 | ||
90 | /// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. | 92 | /// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. |
91 | pub(crate) fn insert_use<'a>( | 93 | pub fn insert_use<'a>( |
92 | scope: &ImportScope, | 94 | scope: &ImportScope, |
93 | path: ast::Path, | 95 | path: ast::Path, |
94 | merge: Option<MergeBehaviour>, | 96 | merge: Option<MergeBehaviour>, |