diff options
22 files changed, 369 insertions, 96 deletions
diff --git a/Cargo.lock b/Cargo.lock index 09215a37a..b236d69cc 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -255,6 +255,7 @@ version = "0.0.0" | |||
255 | dependencies = [ | 255 | dependencies = [ |
256 | "assists", | 256 | "assists", |
257 | "base_db", | 257 | "base_db", |
258 | "either", | ||
258 | "expect-test", | 259 | "expect-test", |
259 | "hir", | 260 | "hir", |
260 | "ide_db", | 261 | "ide_db", |
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>, |
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(); |
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index 30a5e4580..37ed092ad 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -110,15 +110,9 @@ impl Crate { | |||
110 | pub fn query_external_importables( | 110 | pub fn query_external_importables( |
111 | self, | 111 | self, |
112 | db: &dyn DefDatabase, | 112 | db: &dyn DefDatabase, |
113 | query: &str, | 113 | query: import_map::Query, |
114 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | 114 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { |
115 | import_map::search_dependencies( | 115 | import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| match item { |
116 | db, | ||
117 | self.into(), | ||
118 | import_map::Query::new(query).anchor_end().case_sensitive().limit(40), | ||
119 | ) | ||
120 | .into_iter() | ||
121 | .map(|item| match item { | ||
122 | ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), | 116 | ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), |
123 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), | 117 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), |
124 | }) | 118 | }) |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 0d184379f..5fea25ef1 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -49,6 +49,7 @@ pub use hir_def::{ | |||
49 | builtin_type::BuiltinType, | 49 | builtin_type::BuiltinType, |
50 | docs::Documentation, | 50 | docs::Documentation, |
51 | find_path::PrefixKind, | 51 | find_path::PrefixKind, |
52 | import_map, | ||
52 | item_scope::ItemInNs, | 53 | item_scope::ItemInNs, |
53 | nameres::ModuleSource, | 54 | nameres::ModuleSource, |
54 | path::{ModPath, PathKind}, | 55 | path::{ModPath, PathKind}, |
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs index df74be00b..9d8ea7368 100644 --- a/crates/ide_db/src/imports_locator.rs +++ b/crates/ide_db/src/imports_locator.rs | |||
@@ -1,36 +1,70 @@ | |||
1 | //! This module contains an import search funcionality that is provided to the assists module. | 1 | //! This module contains an import search funcionality that is provided to the assists module. |
2 | //! Later, this should be moved away to a separate crate that is accessible from the assists module. | 2 | //! Later, this should be moved away to a separate crate that is accessible from the assists module. |
3 | 3 | ||
4 | use hir::{Crate, MacroDef, ModuleDef, Semantics}; | 4 | use hir::{import_map, Crate, MacroDef, ModuleDef, Semantics}; |
5 | use syntax::{ast, AstNode, SyntaxKind::NAME}; | 5 | use syntax::{ast, AstNode, SyntaxKind::NAME}; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
8 | defs::{Definition, NameClass}, | 8 | defs::{Definition, NameClass}, |
9 | symbol_index::{self, FileSymbol, Query}, | 9 | symbol_index::{self, FileSymbol}, |
10 | RootDatabase, | 10 | RootDatabase, |
11 | }; | 11 | }; |
12 | use either::Either; | 12 | use either::Either; |
13 | use rustc_hash::FxHashSet; | 13 | use rustc_hash::FxHashSet; |
14 | 14 | ||
15 | pub fn find_imports<'a>( | 15 | pub fn find_exact_imports<'a>( |
16 | sema: &Semantics<'a, RootDatabase>, | 16 | sema: &Semantics<'a, RootDatabase>, |
17 | krate: Crate, | 17 | krate: Crate, |
18 | name_to_import: &str, | 18 | name_to_import: &str, |
19 | ) -> Vec<Either<ModuleDef, MacroDef>> { | 19 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { |
20 | let _p = profile::span("search_for_imports"); | 20 | let _p = profile::span("find_exact_imports"); |
21 | find_imports( | ||
22 | sema, | ||
23 | krate, | ||
24 | { | ||
25 | let mut local_query = symbol_index::Query::new(name_to_import.to_string()); | ||
26 | local_query.exact(); | ||
27 | local_query.limit(40); | ||
28 | local_query | ||
29 | }, | ||
30 | import_map::Query::new(name_to_import).anchor_end().case_sensitive().limit(40), | ||
31 | ) | ||
32 | } | ||
33 | |||
34 | pub fn find_similar_imports<'a>( | ||
35 | sema: &Semantics<'a, RootDatabase>, | ||
36 | krate: Crate, | ||
37 | name_to_import: &str, | ||
38 | limit: usize, | ||
39 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | ||
40 | let _p = profile::span("find_similar_imports"); | ||
41 | find_imports( | ||
42 | sema, | ||
43 | krate, | ||
44 | { | ||
45 | let mut local_query = symbol_index::Query::new(name_to_import.to_string()); | ||
46 | local_query.limit(limit); | ||
47 | local_query | ||
48 | }, | ||
49 | import_map::Query::new(name_to_import).limit(limit), | ||
50 | ) | ||
51 | } | ||
52 | |||
53 | fn find_imports<'a>( | ||
54 | sema: &Semantics<'a, RootDatabase>, | ||
55 | krate: Crate, | ||
56 | local_query: symbol_index::Query, | ||
57 | external_query: import_map::Query, | ||
58 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | ||
59 | let _p = profile::span("find_similar_imports"); | ||
21 | let db = sema.db; | 60 | let db = sema.db; |
22 | 61 | ||
23 | // Query dependencies first. | 62 | // Query dependencies first. |
24 | let mut candidates: FxHashSet<_> = | 63 | let mut candidates: FxHashSet<_> = |
25 | krate.query_external_importables(db, name_to_import).collect(); | 64 | krate.query_external_importables(db, external_query).collect(); |
26 | 65 | ||
27 | // Query the local crate using the symbol index. | 66 | // Query the local crate using the symbol index. |
28 | let local_results = { | 67 | let local_results = symbol_index::crate_symbols(db, krate.into(), local_query); |
29 | let mut query = Query::new(name_to_import.to_string()); | ||
30 | query.exact(); | ||
31 | query.limit(40); | ||
32 | symbol_index::crate_symbols(db, krate.into(), query) | ||
33 | }; | ||
34 | 68 | ||
35 | candidates.extend( | 69 | candidates.extend( |
36 | local_results | 70 | local_results |
@@ -43,7 +77,7 @@ pub fn find_imports<'a>( | |||
43 | }), | 77 | }), |
44 | ); | 78 | ); |
45 | 79 | ||
46 | candidates.into_iter().collect() | 80 | candidates.into_iter() |
47 | } | 81 | } |
48 | 82 | ||
49 | fn get_name_definition<'a>( | 83 | fn get_name_definition<'a>( |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index d16796590..5fc6800cf 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -294,10 +294,6 @@ impl Config { | |||
294 | max_length: data.inlayHints_maxLength, | 294 | max_length: data.inlayHints_maxLength, |
295 | }; | 295 | }; |
296 | 296 | ||
297 | self.completion.enable_postfix_completions = data.completion_postfix_enable; | ||
298 | self.completion.add_call_parenthesis = data.completion_addCallParenthesis; | ||
299 | self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets; | ||
300 | |||
301 | self.assist.insert_use.merge = match data.assist_importMergeBehaviour { | 297 | self.assist.insert_use.merge = match data.assist_importMergeBehaviour { |
302 | MergeBehaviourDef::None => None, | 298 | MergeBehaviourDef::None => None, |
303 | MergeBehaviourDef::Full => Some(MergeBehaviour::Full), | 299 | MergeBehaviourDef::Full => Some(MergeBehaviour::Full), |
@@ -309,6 +305,11 @@ impl Config { | |||
309 | ImportPrefixDef::BySelf => PrefixKind::BySelf, | 305 | ImportPrefixDef::BySelf => PrefixKind::BySelf, |
310 | }; | 306 | }; |
311 | 307 | ||
308 | self.completion.enable_postfix_completions = data.completion_postfix_enable; | ||
309 | self.completion.add_call_parenthesis = data.completion_addCallParenthesis; | ||
310 | self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets; | ||
311 | self.completion.merge = self.assist.insert_use.merge; | ||
312 | |||
312 | self.call_info_full = data.callInfo_full; | 313 | self.call_info_full = data.callInfo_full; |
313 | 314 | ||
314 | self.lens = LensConfig { | 315 | self.lens = LensConfig { |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 8d2d86f0e..118e7276f 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -573,7 +573,7 @@ pub(crate) fn handle_completion( | |||
573 | .flat_map(|item| to_proto::completion_item(&line_index, line_endings, item)) | 573 | .flat_map(|item| to_proto::completion_item(&line_index, line_endings, item)) |
574 | .collect(); | 574 | .collect(); |
575 | 575 | ||
576 | let completion_list = lsp_types::CompletionList { is_incomplete: false, items }; | 576 | let completion_list = lsp_types::CompletionList { is_incomplete: true, items }; |
577 | Ok(Some(completion_list.into())) | 577 | Ok(Some(completion_list.into())) |
578 | } | 578 | } |
579 | 579 | ||