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.rs141
1 files changed, 139 insertions, 2 deletions
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index 7df58e1da..ecda37862 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::{insert_use, mod_path_to_ast, ImportScope};
4use either::Either;
3use hir::{Adt, ModuleDef, ScopeDef, Type}; 5use hir::{Adt, ModuleDef, ScopeDef, Type};
4use syntax::AstNode; 6use ide_db::imports_locator;
7use syntax::{algo, AstNode};
5use test_utils::mark; 8use test_utils::mark;
6 9
7use crate::{CompletionContext, Completions}; 10use crate::{
11 render::{render_resolution, 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,56 @@ 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()
48}
49
50// TODO kb add a setting toggle for this feature?
51fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
52 let _p = profile::span("fuzzy_completion®");
53 let current_module = ctx.scope.module()?;
54 let anchor = ctx.name_ref_syntax.as_ref()?;
55 let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
56
57 let potential_import_name = ctx.token.to_string();
58
59 let possible_imports =
60 imports_locator::find_similar_imports(&ctx.sema, ctx.krate?, &potential_import_name, 400)
61 .filter_map(|import_candidate| match import_candidate {
62 // when completing outside the use declaration, modules are pretty useless
63 // and tend to bloat the completion suggestions a lot
64 Either::Left(ModuleDef::Module(_)) => None,
65 Either::Left(module_def) => Some((
66 current_module.find_use_path(ctx.db, module_def)?,
67 ScopeDef::ModuleDef(module_def),
68 )),
69 Either::Right(macro_def) => Some((
70 current_module.find_use_path(ctx.db, macro_def)?,
71 ScopeDef::MacroDef(macro_def),
72 )),
73 })
74 .filter_map(|(mod_path, definition)| {
75 let mut resolution_with_missing_import = render_resolution(
76 RenderContext::new(ctx),
77 mod_path.segments.last()?.to_string(),
78 &definition,
79 )?;
80
81 let mut text_edits =
82 resolution_with_missing_import.text_edit().to_owned().into_builder();
83
84 let rewriter =
85 insert_use(&import_scope, mod_path_to_ast(&mod_path), ctx.config.merge);
86 let old_ast = rewriter.rewrite_root()?;
87 algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut text_edits);
88
89 resolution_with_missing_import.update_text_edit(text_edits.finish());
90
91 Some(resolution_with_missing_import)
92 });
93
94 acc.add_all(possible_imports);
95 Some(())
40} 96}
41 97
42fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { 98fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) {
@@ -676,4 +732,85 @@ impl My<|>
676 "#]], 732 "#]],
677 ) 733 )
678 } 734 }
735
736 #[test]
737 fn function_magic_completion() {
738 check_edit(
739 "stdin",
740 r#"
741//- /lib.rs crate:dep
742pub mod io {
743 pub fn stdin() {}
744};
745
746//- /main.rs crate:main deps:dep
747fn main() {
748 stdi<|>
749}
750"#,
751 r#"
752use dep::io::stdin;
753
754fn main() {
755 stdin()$0
756}
757"#,
758 );
759 }
760
761 #[test]
762 fn macro_magic_completion() {
763 check_edit(
764 "macro_with_curlies!",
765 r#"
766//- /lib.rs crate:dep
767/// Please call me as macro_with_curlies! {}
768#[macro_export]
769macro_rules! macro_with_curlies {
770 () => {}
771}
772
773//- /main.rs crate:main deps:dep
774fn main() {
775 curli<|>
776}
777"#,
778 r#"
779use dep::macro_with_curlies;
780
781fn main() {
782 macro_with_curlies! {$0}
783}
784"#,
785 );
786 }
787
788 #[test]
789 fn case_insensitive_magic_completion_works() {
790 check_edit(
791 "ThirdStruct",
792 r#"
793//- /lib.rs crate:dep
794pub struct FirstStruct;
795pub mod some_module {
796 pub struct SecondStruct;
797 pub struct ThirdStruct;
798}
799
800//- /main.rs crate:main deps:dep
801use dep::{FirstStruct, some_module::SecondStruct};
802
803fn main() {
804 this<|>
805}
806"#,
807 r#"
808use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
809
810fn main() {
811 ThirdStruct
812}
813"#,
814 );
815 }
679} 816}