aboutsummaryrefslogtreecommitdiff
path: root/crates/completion/src/completions
diff options
context:
space:
mode:
Diffstat (limited to 'crates/completion/src/completions')
-rw-r--r--crates/completion/src/completions/pattern.rs57
-rw-r--r--crates/completion/src/completions/unqualified_path.rs134
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.
6pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { 6pub(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#"
100enum E { X }
101use self::E::X;
102const Z: E = E::X;
103mod m {}
104
105static FOO: E = E::X;
106struct Bar { f: u32 }
107
108fn 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
3use assists::utils::ImportScope;
4use either::Either;
3use hir::{Adt, ModuleDef, ScopeDef, Type}; 5use hir::{Adt, ModuleDef, ScopeDef, Type};
6use ide_db::imports_locator;
4use syntax::AstNode; 7use syntax::AstNode;
5use test_utils::mark; 8use test_utils::mark;
6 9
7use crate::{CompletionContext, Completions}; 10use crate::{
11 render::{render_resolution_with_import, RenderContext},
12 CompletionContext, Completions,
13};
8 14
9pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 15pub(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
42fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { 52fn 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
76fn 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)]
67mod tests { 118mod 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
737pub mod io {
738 pub fn stdin() {}
739};
740
741//- /main.rs crate:main deps:dep
742fn main() {
743 stdi<|>
744}
745"#,
746 r#"
747use dep::io::stdin;
748
749fn 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]
764macro_rules! macro_with_curlies {
765 () => {}
766}
767
768//- /main.rs crate:main deps:dep
769fn main() {
770 curli<|>
771}
772"#,
773 r#"
774use dep::macro_with_curlies;
775
776fn 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
789pub struct FirstStruct;
790pub mod some_module {
791 pub struct SecondStruct;
792 pub struct ThirdStruct;
793}
794
795//- /main.rs crate:main deps:dep
796use dep::{FirstStruct, some_module::SecondStruct};
797
798fn main() {
799 this<|>
800}
801"#,
802 r#"
803use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
804
805fn main() {
806 ThirdStruct
807}
808"#,
809 );
810 }
679} 811}