diff options
Diffstat (limited to 'crates/completion/src/completions/unqualified_path.rs')
-rw-r--r-- | crates/completion/src/completions/unqualified_path.rs | 130 |
1 files changed, 129 insertions, 1 deletions
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 | } |