diff options
Diffstat (limited to 'crates/completion/src/completions')
-rw-r--r-- | crates/completion/src/completions/pattern.rs | 57 | ||||
-rw-r--r-- | crates/completion/src/completions/unqualified_path.rs | 134 |
2 files changed, 176 insertions, 15 deletions
diff --git a/crates/completion/src/completions/pattern.rs b/crates/completion/src/completions/pattern.rs index 7ab7f09fe..4f63ff0ef 100644 --- a/crates/completion/src/completions/pattern.rs +++ b/crates/completion/src/completions/pattern.rs | |||
@@ -4,7 +4,7 @@ use crate::{CompletionContext, Completions}; | |||
4 | 4 | ||
5 | /// Completes constats and paths in patterns. | 5 | /// Completes constats and paths in patterns. |
6 | pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | 6 | pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { |
7 | if !ctx.is_pat_binding_or_const { | 7 | if !(ctx.is_pat_binding_or_const || ctx.is_irrefutable_let_pat_binding) { |
8 | return; | 8 | return; |
9 | } | 9 | } |
10 | if ctx.record_pat_syntax.is_some() { | 10 | if ctx.record_pat_syntax.is_some() { |
@@ -14,20 +14,27 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
14 | // FIXME: ideally, we should look at the type we are matching against and | 14 | // FIXME: ideally, we should look at the type we are matching against and |
15 | // suggest variants + auto-imports | 15 | // suggest variants + auto-imports |
16 | ctx.scope.process_all_names(&mut |name, res| { | 16 | ctx.scope.process_all_names(&mut |name, res| { |
17 | match &res { | 17 | let add_resolution = match &res { |
18 | hir::ScopeDef::ModuleDef(def) => match def { | 18 | hir::ScopeDef::ModuleDef(def) => { |
19 | hir::ModuleDef::Adt(hir::Adt::Enum(..)) | 19 | if ctx.is_irrefutable_let_pat_binding { |
20 | | hir::ModuleDef::Adt(hir::Adt::Struct(..)) | 20 | matches!(def, hir::ModuleDef::Adt(hir::Adt::Struct(_))) |
21 | | hir::ModuleDef::EnumVariant(..) | 21 | } else { |
22 | | hir::ModuleDef::Const(..) | 22 | matches!( |
23 | | hir::ModuleDef::Module(..) => (), | 23 | def, |
24 | _ => return, | 24 | hir::ModuleDef::Adt(hir::Adt::Enum(..)) |
25 | }, | 25 | | hir::ModuleDef::Adt(hir::Adt::Struct(..)) |
26 | hir::ScopeDef::MacroDef(_) => (), | 26 | | hir::ModuleDef::EnumVariant(..) |
27 | _ => return, | 27 | | hir::ModuleDef::Const(..) |
28 | | hir::ModuleDef::Module(..) | ||
29 | ) | ||
30 | } | ||
31 | } | ||
32 | hir::ScopeDef::MacroDef(_) => true, | ||
33 | _ => false, | ||
28 | }; | 34 | }; |
29 | 35 | if add_resolution { | |
30 | acc.add_resolution(ctx, name.to_string(), &res) | 36 | acc.add_resolution(ctx, name.to_string(), &res); |
37 | } | ||
31 | }); | 38 | }); |
32 | } | 39 | } |
33 | 40 | ||
@@ -85,4 +92,26 @@ fn foo() { | |||
85 | "#]], | 92 | "#]], |
86 | ); | 93 | ); |
87 | } | 94 | } |
95 | |||
96 | #[test] | ||
97 | fn completes_in_irrefutable_let() { | ||
98 | check( | ||
99 | r#" | ||
100 | enum E { X } | ||
101 | use self::E::X; | ||
102 | const Z: E = E::X; | ||
103 | mod m {} | ||
104 | |||
105 | static FOO: E = E::X; | ||
106 | struct Bar { f: u32 } | ||
107 | |||
108 | fn foo() { | ||
109 | let <|> | ||
110 | } | ||
111 | "#, | ||
112 | expect![[r#" | ||
113 | st Bar | ||
114 | "#]], | ||
115 | ); | ||
116 | } | ||
88 | } | 117 | } |
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs index 7df58e1da..3bd776905 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,10 @@ 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 | if ctx.config.enable_experimental_completions { | ||
48 | fuzzy_completion(acc, ctx).unwrap_or_default() | ||
49 | } | ||
40 | } | 50 | } |
41 | 51 | ||
42 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { | 52 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { |
@@ -63,6 +73,47 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T | |||
63 | } | 73 | } |
64 | } | 74 | } |
65 | 75 | ||
76 | fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | ||
77 | let _p = profile::span("fuzzy_completion"); | ||
78 | let current_module = ctx.scope.module()?; | ||
79 | let anchor = ctx.name_ref_syntax.as_ref()?; | ||
80 | let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; | ||
81 | |||
82 | let potential_import_name = ctx.token.to_string(); | ||
83 | |||
84 | let possible_imports = imports_locator::find_similar_imports( | ||
85 | &ctx.sema, | ||
86 | ctx.krate?, | ||
87 | &potential_import_name, | ||
88 | 50, | ||
89 | true, | ||
90 | ) | ||
91 | .filter_map(|import_candidate| { | ||
92 | Some(match import_candidate { | ||
93 | Either::Left(module_def) => { | ||
94 | (current_module.find_use_path(ctx.db, module_def)?, ScopeDef::ModuleDef(module_def)) | ||
95 | } | ||
96 | Either::Right(macro_def) => { | ||
97 | (current_module.find_use_path(ctx.db, macro_def)?, ScopeDef::MacroDef(macro_def)) | ||
98 | } | ||
99 | }) | ||
100 | }) | ||
101 | .filter(|(mod_path, _)| mod_path.len() > 1) | ||
102 | .take(20) | ||
103 | .filter_map(|(import_path, definition)| { | ||
104 | render_resolution_with_import( | ||
105 | RenderContext::new(ctx), | ||
106 | import_path.clone(), | ||
107 | import_scope.clone(), | ||
108 | ctx.config.merge, | ||
109 | &definition, | ||
110 | ) | ||
111 | }); | ||
112 | |||
113 | acc.add_all(possible_imports); | ||
114 | Some(()) | ||
115 | } | ||
116 | |||
66 | #[cfg(test)] | 117 | #[cfg(test)] |
67 | mod tests { | 118 | mod tests { |
68 | use expect_test::{expect, Expect}; | 119 | use expect_test::{expect, Expect}; |
@@ -676,4 +727,85 @@ impl My<|> | |||
676 | "#]], | 727 | "#]], |
677 | ) | 728 | ) |
678 | } | 729 | } |
730 | |||
731 | #[test] | ||
732 | fn function_fuzzy_completion() { | ||
733 | check_edit( | ||
734 | "stdin", | ||
735 | r#" | ||
736 | //- /lib.rs crate:dep | ||
737 | pub mod io { | ||
738 | pub fn stdin() {} | ||
739 | }; | ||
740 | |||
741 | //- /main.rs crate:main deps:dep | ||
742 | fn main() { | ||
743 | stdi<|> | ||
744 | } | ||
745 | "#, | ||
746 | r#" | ||
747 | use dep::io::stdin; | ||
748 | |||
749 | fn main() { | ||
750 | stdin()$0 | ||
751 | } | ||
752 | "#, | ||
753 | ); | ||
754 | } | ||
755 | |||
756 | #[test] | ||
757 | fn macro_fuzzy_completion() { | ||
758 | check_edit( | ||
759 | "macro_with_curlies!", | ||
760 | r#" | ||
761 | //- /lib.rs crate:dep | ||
762 | /// Please call me as macro_with_curlies! {} | ||
763 | #[macro_export] | ||
764 | macro_rules! macro_with_curlies { | ||
765 | () => {} | ||
766 | } | ||
767 | |||
768 | //- /main.rs crate:main deps:dep | ||
769 | fn main() { | ||
770 | curli<|> | ||
771 | } | ||
772 | "#, | ||
773 | r#" | ||
774 | use dep::macro_with_curlies; | ||
775 | |||
776 | fn main() { | ||
777 | macro_with_curlies! {$0} | ||
778 | } | ||
779 | "#, | ||
780 | ); | ||
781 | } | ||
782 | |||
783 | #[test] | ||
784 | fn struct_fuzzy_completion() { | ||
785 | check_edit( | ||
786 | "ThirdStruct", | ||
787 | r#" | ||
788 | //- /lib.rs crate:dep | ||
789 | pub struct FirstStruct; | ||
790 | pub mod some_module { | ||
791 | pub struct SecondStruct; | ||
792 | pub struct ThirdStruct; | ||
793 | } | ||
794 | |||
795 | //- /main.rs crate:main deps:dep | ||
796 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
797 | |||
798 | fn main() { | ||
799 | this<|> | ||
800 | } | ||
801 | "#, | ||
802 | r#" | ||
803 | use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}}; | ||
804 | |||
805 | fn main() { | ||
806 | ThirdStruct | ||
807 | } | ||
808 | "#, | ||
809 | ); | ||
810 | } | ||
679 | } | 811 | } |