aboutsummaryrefslogtreecommitdiff
path: root/crates/completion/src/completions/unqualified_path.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/completion/src/completions/unqualified_path.rs')
-rw-r--r--crates/completion/src/completions/unqualified_path.rs132
1 files changed, 131 insertions, 1 deletions
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index 7df58e1da..4f1c9faa0 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,45 @@ 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 =
85 imports_locator::find_similar_imports(&ctx.sema, ctx.krate?, &potential_import_name, 400)
86 .filter_map(|import_candidate| match import_candidate {
87 // when completing outside the use declaration, modules are pretty useless
88 // and tend to bloat the completion suggestions a lot
89 Either::Left(ModuleDef::Module(_)) => None,
90 Either::Left(module_def) => Some((
91 current_module.find_use_path(ctx.db, module_def)?,
92 ScopeDef::ModuleDef(module_def),
93 )),
94 Either::Right(macro_def) => Some((
95 current_module.find_use_path(ctx.db, macro_def)?,
96 ScopeDef::MacroDef(macro_def),
97 )),
98 })
99 .filter(|(mod_path, _)| mod_path.len() > 1)
100 .filter_map(|(import_path, definition)| {
101 render_resolution_with_import(
102 RenderContext::new(ctx),
103 import_path.clone(),
104 import_scope.clone(),
105 ctx.config.merge,
106 &definition,
107 )
108 })
109 .take(20);
110
111 acc.add_all(possible_imports);
112 Some(())
113}
114
66#[cfg(test)] 115#[cfg(test)]
67mod tests { 116mod tests {
68 use expect_test::{expect, Expect}; 117 use expect_test::{expect, Expect};
@@ -676,4 +725,85 @@ impl My<|>
676 "#]], 725 "#]],
677 ) 726 )
678 } 727 }
728
729 #[test]
730 fn function_fuzzy_completion() {
731 check_edit(
732 "stdin",
733 r#"
734//- /lib.rs crate:dep
735pub mod io {
736 pub fn stdin() {}
737};
738
739//- /main.rs crate:main deps:dep
740fn main() {
741 stdi<|>
742}
743"#,
744 r#"
745use dep::io::stdin;
746
747fn main() {
748 stdin()$0
749}
750"#,
751 );
752 }
753
754 #[test]
755 fn macro_fuzzy_completion() {
756 check_edit(
757 "macro_with_curlies!",
758 r#"
759//- /lib.rs crate:dep
760/// Please call me as macro_with_curlies! {}
761#[macro_export]
762macro_rules! macro_with_curlies {
763 () => {}
764}
765
766//- /main.rs crate:main deps:dep
767fn main() {
768 curli<|>
769}
770"#,
771 r#"
772use dep::macro_with_curlies;
773
774fn main() {
775 macro_with_curlies! {$0}
776}
777"#,
778 );
779 }
780
781 #[test]
782 fn struct_fuzzy_completion() {
783 check_edit(
784 "ThirdStruct",
785 r#"
786//- /lib.rs crate:dep
787pub struct FirstStruct;
788pub mod some_module {
789 pub struct SecondStruct;
790 pub struct ThirdStruct;
791}
792
793//- /main.rs crate:main deps:dep
794use dep::{FirstStruct, some_module::SecondStruct};
795
796fn main() {
797 this<|>
798}
799"#,
800 r#"
801use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
802
803fn main() {
804 ThirdStruct
805}
806"#,
807 );
808 }
679} 809}