diff options
Diffstat (limited to 'crates/completion/src/completions')
-rw-r--r-- | crates/completion/src/completions/magic.rs | 151 | ||||
-rw-r--r-- | crates/completion/src/completions/unqualified_path.rs | 141 |
2 files changed, 139 insertions, 153 deletions
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 | |||
3 | use assists::utils::{insert_use, mod_path_to_ast, ImportScope}; | ||
4 | use either::Either; | ||
5 | use hir::{ModuleDef, ScopeDef}; | ||
6 | use ide_db::imports_locator; | ||
7 | use syntax::{algo, AstNode}; | ||
8 | |||
9 | use crate::{ | ||
10 | context::CompletionContext, | ||
11 | render::{render_resolution, RenderContext}, | ||
12 | }; | ||
13 | |||
14 | use super::Completions; | ||
15 | |||
16 | // TODO kb add a setting toggle for this feature? | ||
17 | pub(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)] | ||
68 | mod 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 | ||
77 | pub mod io { | ||
78 | pub fn stdin() {} | ||
79 | }; | ||
80 | |||
81 | //- /main.rs crate:main deps:dep | ||
82 | fn main() { | ||
83 | stdi<|> | ||
84 | } | ||
85 | "#, | ||
86 | r#" | ||
87 | use dep::io::stdin; | ||
88 | |||
89 | fn 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] | ||
104 | macro_rules! macro_with_curlies { | ||
105 | () => {} | ||
106 | } | ||
107 | |||
108 | //- /main.rs crate:main deps:dep | ||
109 | fn main() { | ||
110 | curli<|> | ||
111 | } | ||
112 | "#, | ||
113 | r#" | ||
114 | use dep::macro_with_curlies; | ||
115 | |||
116 | fn 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 | ||
129 | pub struct FirstStruct; | ||
130 | pub mod some_module { | ||
131 | pub struct SecondStruct; | ||
132 | pub struct ThirdStruct; | ||
133 | } | ||
134 | |||
135 | //- /main.rs crate:main deps:dep | ||
136 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
137 | |||
138 | fn main() { | ||
139 | this<|> | ||
140 | } | ||
141 | "#, | ||
142 | r#" | ||
143 | use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}}; | ||
144 | |||
145 | fn 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 | ||
3 | use assists::utils::{insert_use, mod_path_to_ast, ImportScope}; | ||
4 | use either::Either; | ||
3 | use hir::{Adt, ModuleDef, ScopeDef, Type}; | 5 | use hir::{Adt, ModuleDef, ScopeDef, Type}; |
4 | use syntax::AstNode; | 6 | use ide_db::imports_locator; |
7 | use syntax::{algo, 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, 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,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? | ||
51 | fn 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 | ||
42 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { | 98 | fn 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 | ||
742 | pub mod io { | ||
743 | pub fn stdin() {} | ||
744 | }; | ||
745 | |||
746 | //- /main.rs crate:main deps:dep | ||
747 | fn main() { | ||
748 | stdi<|> | ||
749 | } | ||
750 | "#, | ||
751 | r#" | ||
752 | use dep::io::stdin; | ||
753 | |||
754 | fn 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] | ||
769 | macro_rules! macro_with_curlies { | ||
770 | () => {} | ||
771 | } | ||
772 | |||
773 | //- /main.rs crate:main deps:dep | ||
774 | fn main() { | ||
775 | curli<|> | ||
776 | } | ||
777 | "#, | ||
778 | r#" | ||
779 | use dep::macro_with_curlies; | ||
780 | |||
781 | fn 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 | ||
794 | pub struct FirstStruct; | ||
795 | pub mod some_module { | ||
796 | pub struct SecondStruct; | ||
797 | pub struct ThirdStruct; | ||
798 | } | ||
799 | |||
800 | //- /main.rs crate:main deps:dep | ||
801 | use dep::{FirstStruct, some_module::SecondStruct}; | ||
802 | |||
803 | fn main() { | ||
804 | this<|> | ||
805 | } | ||
806 | "#, | ||
807 | r#" | ||
808 | use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}}; | ||
809 | |||
810 | fn main() { | ||
811 | ThirdStruct | ||
812 | } | ||
813 | "#, | ||
814 | ); | ||
815 | } | ||
679 | } | 816 | } |