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 | ||
