aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/completion/Cargo.toml1
-rw-r--r--crates/completion/src/completions.rs1
-rw-r--r--crates/completion/src/completions/magic.rs151
-rw-r--r--crates/completion/src/completions/unqualified_path.rs141
-rw-r--r--crates/completion/src/lib.rs1
5 files changed, 139 insertions, 156 deletions
diff --git a/crates/completion/Cargo.toml b/crates/completion/Cargo.toml
index 799b4a3d5..e7df9d955 100644
--- a/crates/completion/Cargo.toml
+++ b/crates/completion/Cargo.toml
@@ -22,7 +22,6 @@ text_edit = { path = "../text_edit", version = "0.0.0" }
22base_db = { path = "../base_db", version = "0.0.0" } 22base_db = { path = "../base_db", version = "0.0.0" }
23ide_db = { path = "../ide_db", version = "0.0.0" } 23ide_db = { path = "../ide_db", version = "0.0.0" }
24profile = { path = "../profile", version = "0.0.0" } 24profile = { path = "../profile", version = "0.0.0" }
25assists = { path = "../assists", version = "0.0.0" }
26test_utils = { path = "../test_utils", version = "0.0.0" } 25test_utils = { path = "../test_utils", version = "0.0.0" }
27 26
28# completions crate should depend only on the top-level `hir` package. if you need 27# completions crate should depend only on the top-level `hir` package. if you need
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs
index 4abb10156..75dbb1a23 100644
--- a/crates/completion/src/completions.rs
+++ b/crates/completion/src/completions.rs
@@ -13,7 +13,6 @@ pub(crate) mod postfix;
13pub(crate) mod macro_in_item_position; 13pub(crate) mod macro_in_item_position;
14pub(crate) mod trait_impl; 14pub(crate) mod trait_impl;
15pub(crate) mod mod_; 15pub(crate) mod mod_;
16pub(crate) mod magic;
17 16
18use hir::{ModPath, ScopeDef, Type}; 17use hir::{ModPath, ScopeDef, Type};
19 18
diff --git a/crates/completion/src/completions/magic.rs b/crates/completion/src/completions/magic.rs
deleted file mode 100644
index 0c4db0199..000000000
--- a/crates/completion/src/completions/magic.rs
+++ /dev/null
@@ -1,151 +0,0 @@
1//! TODO kb move this into the complete_unqualified_path when starts to work properly
2
3use assists::utils::{insert_use, mod_path_to_ast, ImportScope};
4use either::Either;
5use hir::{ModuleDef, ScopeDef};
6use ide_db::imports_locator;
7use syntax::{algo, AstNode};
8
9use crate::{
10 context::CompletionContext,
11 render::{render_resolution, RenderContext},
12};
13
14use super::Completions;
15
16// TODO kb add a setting toggle for this feature?
17pub(crate) fn complete_magic(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
18 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) {
19 return None;
20 }
21 let _p = profile::span("complete_magic");
22 let current_module = ctx.scope.module()?;
23 let anchor = ctx.name_ref_syntax.as_ref()?;
24 let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
25
26 let potential_import_name = ctx.token.to_string();
27
28 let possible_imports =
29 imports_locator::find_similar_imports(&ctx.sema, ctx.krate?, &potential_import_name, 400)
30 .filter_map(|import_candidate| match import_candidate {
31 // when completing outside the use declaration, modules are pretty useless
32 // and tend to bloat the completion suggestions a lot
33 Either::Left(ModuleDef::Module(_)) => None,
34 Either::Left(module_def) => Some((
35 current_module.find_use_path(ctx.db, module_def)?,
36 ScopeDef::ModuleDef(module_def),
37 )),
38 Either::Right(macro_def) => Some((
39 current_module.find_use_path(ctx.db, macro_def)?,
40 ScopeDef::MacroDef(macro_def),
41 )),
42 })
43 .filter_map(|(mod_path, definition)| {
44 let mut resolution_with_missing_import = render_resolution(
45 RenderContext::new(ctx),
46 mod_path.segments.last()?.to_string(),
47 &definition,
48 )?;
49
50 let mut text_edits =
51 resolution_with_missing_import.text_edit().to_owned().into_builder();
52
53 let rewriter =
54 insert_use(&import_scope, mod_path_to_ast(&mod_path), ctx.config.merge);
55 let old_ast = rewriter.rewrite_root()?;
56 algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut text_edits);
57
58 resolution_with_missing_import.update_text_edit(text_edits.finish());
59
60 Some(resolution_with_missing_import)
61 });
62
63 acc.add_all(possible_imports);
64 Some(())
65}
66
67#[cfg(test)]
68mod tests {
69 use crate::test_utils::check_edit;
70
71 #[test]
72 fn function_magic_completion() {
73 check_edit(
74 "stdin",
75 r#"
76//- /lib.rs crate:dep
77pub mod io {
78 pub fn stdin() {}
79};
80
81//- /main.rs crate:main deps:dep
82fn main() {
83 stdi<|>
84}
85"#,
86 r#"
87use dep::io::stdin;
88
89fn main() {
90 stdin()$0
91}
92"#,
93 );
94 }
95
96 #[test]
97 fn macro_magic_completion() {
98 check_edit(
99 "macro_with_curlies!",
100 r#"
101//- /lib.rs crate:dep
102/// Please call me as macro_with_curlies! {}
103#[macro_export]
104macro_rules! macro_with_curlies {
105 () => {}
106}
107
108//- /main.rs crate:main deps:dep
109fn main() {
110 curli<|>
111}
112"#,
113 r#"
114use dep::macro_with_curlies;
115
116fn main() {
117 macro_with_curlies! {$0}
118}
119"#,
120 );
121 }
122
123 #[test]
124 fn case_insensitive_magic_completion_works() {
125 check_edit(
126 "ThirdStruct",
127 r#"
128//- /lib.rs crate:dep
129pub struct FirstStruct;
130pub mod some_module {
131 pub struct SecondStruct;
132 pub struct ThirdStruct;
133}
134
135//- /main.rs crate:main deps:dep
136use dep::{FirstStruct, some_module::SecondStruct};
137
138fn main() {
139 this<|>
140}
141"#,
142 r#"
143use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
144
145fn main() {
146 ThirdStruct
147}
148"#,
149 );
150 }
151}
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}
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs
index 8323af8b2..cb6e0554e 100644
--- a/crates/completion/src/lib.rs
+++ b/crates/completion/src/lib.rs
@@ -118,7 +118,6 @@ pub fn completions(
118 completions::macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx); 118 completions::macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx);
119 completions::trait_impl::complete_trait_impl(&mut acc, &ctx); 119 completions::trait_impl::complete_trait_impl(&mut acc, &ctx);
120 completions::mod_::complete_mod(&mut acc, &ctx); 120 completions::mod_::complete_mod(&mut acc, &ctx);
121 completions::magic::complete_magic(&mut acc, &ctx);
122 121
123 Some(acc) 122 Some(acc)
124} 123}