diff options
Diffstat (limited to 'crates/ide_completion/src')
-rw-r--r-- | crates/ide_completion/src/completions/keyword.rs | 6 | ||||
-rw-r--r-- | crates/ide_completion/src/context.rs | 63 | ||||
-rw-r--r-- | crates/ide_completion/src/patterns.rs | 37 |
3 files changed, 39 insertions, 67 deletions
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 2c4ed1b00..fa6bcc955 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | use std::iter; | 3 | use std::iter; |
4 | 4 | ||
5 | use syntax::SyntaxKind; | 5 | use syntax::{SyntaxKind, T}; |
6 | 6 | ||
7 | use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; | 7 | use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; |
8 | 8 | ||
@@ -54,7 +54,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
54 | add_keyword(ctx, acc, "where", "where "); | 54 | add_keyword(ctx, acc, "where", "where "); |
55 | return; | 55 | return; |
56 | } | 56 | } |
57 | if ctx.unsafe_is_prev { | 57 | if ctx.previous_token_is(T![unsafe]) { |
58 | if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent { | 58 | if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent { |
59 | add_keyword(ctx, acc, "fn", "fn $1($2) {\n $0\n}") | 59 | add_keyword(ctx, acc, "fn", "fn $1($2) {\n $0\n}") |
60 | } | 60 | } |
@@ -92,7 +92,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
92 | add_keyword(ctx, acc, "for", "for $1 in $2 {\n $0\n}"); | 92 | add_keyword(ctx, acc, "for", "for $1 in $2 {\n $0\n}"); |
93 | } | 93 | } |
94 | 94 | ||
95 | if ctx.if_is_prev || ctx.block_expr_parent { | 95 | if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || ctx.block_expr_parent { |
96 | add_keyword(ctx, acc, "let", "let "); | 96 | add_keyword(ctx, acc, "let", "let "); |
97 | } | 97 | } |
98 | 98 | ||
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 2f3fb1710..85c7edabb 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -1,25 +1,26 @@ | |||
1 | //! See `CompletionContext` structure. | 1 | //! See `CompletionContext` structure. |
2 | 2 | ||
3 | use hir::{Local, ScopeDef, Semantics, SemanticsScope, Type}; | 3 | use hir::{Local, ScopeDef, Semantics, SemanticsScope, Type}; |
4 | use ide_db::base_db::{FilePosition, SourceDatabase}; | 4 | use ide_db::{ |
5 | use ide_db::{call_info::ActiveParameter, RootDatabase}; | 5 | base_db::{FilePosition, SourceDatabase}, |
6 | call_info::ActiveParameter, | ||
7 | RootDatabase, | ||
8 | }; | ||
6 | use syntax::{ | 9 | use syntax::{ |
7 | algo::find_node_at_offset, | 10 | algo::find_node_at_offset, |
8 | ast::{self, NameOrNameRef, NameOwner}, | 11 | ast::{self, NameOrNameRef, NameOwner}, |
9 | match_ast, AstNode, NodeOrToken, | 12 | match_ast, AstNode, NodeOrToken, |
10 | SyntaxKind::*, | 13 | SyntaxKind::{self, *}, |
11 | SyntaxNode, SyntaxToken, TextRange, TextSize, | 14 | SyntaxNode, SyntaxToken, TextRange, TextSize, T, |
12 | }; | 15 | }; |
13 | |||
14 | use text_edit::Indel; | 16 | use text_edit::Indel; |
15 | 17 | ||
16 | use crate::{ | 18 | use crate::{ |
17 | patterns::{ | 19 | patterns::{ |
18 | fn_is_prev, for_is_prev2, has_bind_pat_parent, has_block_expr_parent, | 20 | for_is_prev2, has_bind_pat_parent, has_block_expr_parent, has_field_list_parent, |
19 | has_field_list_parent, has_impl_as_prev_sibling, has_impl_parent, | 21 | has_impl_as_prev_sibling, has_impl_parent, has_item_list_or_source_file_parent, |
20 | has_item_list_or_source_file_parent, has_ref_parent, has_trait_as_prev_sibling, | 22 | has_ref_parent, has_trait_as_prev_sibling, has_trait_parent, inside_impl_trait_block, |
21 | has_trait_parent, if_is_prev, inside_impl_trait_block, is_in_loop_body, is_match_arm, | 23 | is_in_loop_body, is_match_arm, previous_token, |
22 | unsafe_is_prev, | ||
23 | }, | 24 | }, |
24 | CompletionConfig, | 25 | CompletionConfig, |
25 | }; | 26 | }; |
@@ -81,25 +82,26 @@ pub(crate) struct CompletionContext<'a> { | |||
81 | pub(super) is_path_type: bool, | 82 | pub(super) is_path_type: bool, |
82 | pub(super) has_type_args: bool, | 83 | pub(super) has_type_args: bool, |
83 | pub(super) attribute_under_caret: Option<ast::Attr>, | 84 | pub(super) attribute_under_caret: Option<ast::Attr>, |
85 | pub(super) locals: Vec<(String, Local)>, | ||
86 | |||
84 | pub(super) mod_declaration_under_caret: Option<ast::Module>, | 87 | pub(super) mod_declaration_under_caret: Option<ast::Module>, |
85 | pub(super) unsafe_is_prev: bool, | 88 | pub(super) has_trait_parent: bool, |
86 | pub(super) if_is_prev: bool, | 89 | pub(super) has_impl_parent: bool, |
90 | |||
91 | // keyword patterns | ||
92 | pub(super) previous_token: Option<SyntaxToken>, | ||
87 | pub(super) block_expr_parent: bool, | 93 | pub(super) block_expr_parent: bool, |
88 | pub(super) bind_pat_parent: bool, | 94 | pub(super) bind_pat_parent: bool, |
89 | pub(super) ref_pat_parent: bool, | 95 | pub(super) ref_pat_parent: bool, |
90 | pub(super) in_loop_body: bool, | 96 | pub(super) in_loop_body: bool, |
91 | pub(super) has_trait_parent: bool, | ||
92 | pub(super) has_impl_parent: bool, | ||
93 | pub(super) inside_impl_trait_block: bool, | ||
94 | pub(super) has_field_list_parent: bool, | 97 | pub(super) has_field_list_parent: bool, |
95 | pub(super) trait_as_prev_sibling: bool, | 98 | pub(super) trait_as_prev_sibling: bool, |
96 | pub(super) impl_as_prev_sibling: bool, | 99 | pub(super) impl_as_prev_sibling: bool, |
97 | pub(super) is_match_arm: bool, | 100 | pub(super) is_match_arm: bool, |
98 | pub(super) has_item_list_or_source_file_parent: bool, | 101 | pub(super) has_item_list_or_source_file_parent: bool, |
99 | pub(super) for_is_prev2: bool, | ||
100 | pub(super) fn_is_prev: bool, | ||
101 | pub(super) incomplete_let: bool, | 102 | pub(super) incomplete_let: bool, |
102 | pub(super) locals: Vec<(String, Local)>, | 103 | |
104 | no_completion_required: bool, | ||
103 | } | 105 | } |
104 | 106 | ||
105 | impl<'a> CompletionContext<'a> { | 107 | impl<'a> CompletionContext<'a> { |
@@ -175,22 +177,19 @@ impl<'a> CompletionContext<'a> { | |||
175 | has_type_args: false, | 177 | has_type_args: false, |
176 | attribute_under_caret: None, | 178 | attribute_under_caret: None, |
177 | mod_declaration_under_caret: None, | 179 | mod_declaration_under_caret: None, |
178 | unsafe_is_prev: false, | 180 | previous_token: None, |
179 | if_is_prev: false, | ||
180 | block_expr_parent: false, | 181 | block_expr_parent: false, |
181 | bind_pat_parent: false, | 182 | bind_pat_parent: false, |
182 | ref_pat_parent: false, | 183 | ref_pat_parent: false, |
183 | in_loop_body: false, | 184 | in_loop_body: false, |
184 | has_trait_parent: false, | 185 | has_trait_parent: false, |
185 | has_impl_parent: false, | 186 | has_impl_parent: false, |
186 | inside_impl_trait_block: false, | ||
187 | has_field_list_parent: false, | 187 | has_field_list_parent: false, |
188 | trait_as_prev_sibling: false, | 188 | trait_as_prev_sibling: false, |
189 | impl_as_prev_sibling: false, | 189 | impl_as_prev_sibling: false, |
190 | is_match_arm: false, | 190 | is_match_arm: false, |
191 | has_item_list_or_source_file_parent: false, | 191 | has_item_list_or_source_file_parent: false, |
192 | for_is_prev2: false, | 192 | no_completion_required: false, |
193 | fn_is_prev: false, | ||
194 | incomplete_let: false, | 193 | incomplete_let: false, |
195 | locals, | 194 | locals, |
196 | }; | 195 | }; |
@@ -245,7 +244,7 @@ impl<'a> CompletionContext<'a> { | |||
245 | /// Exception for this case is `impl Trait for Foo`, where we would like to hint trait method names. | 244 | /// Exception for this case is `impl Trait for Foo`, where we would like to hint trait method names. |
246 | /// - `for _ i$0` -- obviously, it'll be "in" keyword. | 245 | /// - `for _ i$0` -- obviously, it'll be "in" keyword. |
247 | pub(crate) fn no_completion_required(&self) -> bool { | 246 | pub(crate) fn no_completion_required(&self) -> bool { |
248 | (self.fn_is_prev && !self.inside_impl_trait_block) || self.for_is_prev2 | 247 | self.no_completion_required |
249 | } | 248 | } |
250 | 249 | ||
251 | /// The range of the identifier that is being completed. | 250 | /// The range of the identifier that is being completed. |
@@ -264,33 +263,39 @@ impl<'a> CompletionContext<'a> { | |||
264 | } | 263 | } |
265 | } | 264 | } |
266 | 265 | ||
266 | pub(crate) fn previous_token_is(&self, kind: SyntaxKind) -> bool { | ||
267 | self.previous_token.as_ref().map_or(false, |tok| tok.kind() == kind) | ||
268 | } | ||
269 | |||
267 | fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { | 270 | fn fill_keyword_patterns(&mut self, file_with_fake_ident: &SyntaxNode, offset: TextSize) { |
268 | let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap(); | 271 | let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap(); |
269 | let syntax_element = NodeOrToken::Token(fake_ident_token); | 272 | let syntax_element = NodeOrToken::Token(fake_ident_token); |
273 | self.previous_token = previous_token(syntax_element.clone()); | ||
270 | self.block_expr_parent = has_block_expr_parent(syntax_element.clone()); | 274 | self.block_expr_parent = has_block_expr_parent(syntax_element.clone()); |
271 | self.unsafe_is_prev = unsafe_is_prev(syntax_element.clone()); | ||
272 | self.if_is_prev = if_is_prev(syntax_element.clone()); | ||
273 | self.bind_pat_parent = has_bind_pat_parent(syntax_element.clone()); | 275 | self.bind_pat_parent = has_bind_pat_parent(syntax_element.clone()); |
274 | self.ref_pat_parent = has_ref_parent(syntax_element.clone()); | 276 | self.ref_pat_parent = has_ref_parent(syntax_element.clone()); |
275 | self.in_loop_body = is_in_loop_body(syntax_element.clone()); | 277 | self.in_loop_body = is_in_loop_body(syntax_element.clone()); |
276 | self.has_trait_parent = has_trait_parent(syntax_element.clone()); | 278 | self.has_trait_parent = has_trait_parent(syntax_element.clone()); |
277 | self.has_impl_parent = has_impl_parent(syntax_element.clone()); | 279 | self.has_impl_parent = has_impl_parent(syntax_element.clone()); |
278 | self.inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone()); | ||
279 | self.has_field_list_parent = has_field_list_parent(syntax_element.clone()); | 280 | self.has_field_list_parent = has_field_list_parent(syntax_element.clone()); |
280 | self.impl_as_prev_sibling = has_impl_as_prev_sibling(syntax_element.clone()); | 281 | self.impl_as_prev_sibling = has_impl_as_prev_sibling(syntax_element.clone()); |
281 | self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone()); | 282 | self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone()); |
282 | self.is_match_arm = is_match_arm(syntax_element.clone()); | 283 | self.is_match_arm = is_match_arm(syntax_element.clone()); |
284 | |||
283 | self.has_item_list_or_source_file_parent = | 285 | self.has_item_list_or_source_file_parent = |
284 | has_item_list_or_source_file_parent(syntax_element.clone()); | 286 | has_item_list_or_source_file_parent(syntax_element.clone()); |
285 | self.mod_declaration_under_caret = | 287 | self.mod_declaration_under_caret = |
286 | find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset) | 288 | find_node_at_offset::<ast::Module>(&file_with_fake_ident, offset) |
287 | .filter(|module| module.item_list().is_none()); | 289 | .filter(|module| module.item_list().is_none()); |
288 | self.for_is_prev2 = for_is_prev2(syntax_element.clone()); | ||
289 | self.fn_is_prev = fn_is_prev(syntax_element.clone()); | ||
290 | self.incomplete_let = | 290 | self.incomplete_let = |
291 | syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| { | 291 | syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| { |
292 | it.syntax().text_range().end() == syntax_element.text_range().end() | 292 | it.syntax().text_range().end() == syntax_element.text_range().end() |
293 | }); | 293 | }); |
294 | |||
295 | let inside_impl_trait_block = inside_impl_trait_block(syntax_element.clone()); | ||
296 | let fn_is_prev = self.previous_token_is(T![fn]); | ||
297 | let for_is_prev2 = for_is_prev2(syntax_element.clone()); | ||
298 | self.no_completion_required = (fn_is_prev && !inside_impl_trait_block) || for_is_prev2; | ||
294 | } | 299 | } |
295 | 300 | ||
296 | fn fill_impl_def(&mut self) { | 301 | fn fill_impl_def(&mut self) { |
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index d82564381..3d8a83ed8 100644 --- a/crates/ide_completion/src/patterns.rs +++ b/crates/ide_completion/src/patterns.rs | |||
@@ -115,36 +115,8 @@ fn test_is_match_arm() { | |||
115 | check_pattern_is_applicable(r"fn my_fn() { match () { () => m$0 } }", is_match_arm); | 115 | check_pattern_is_applicable(r"fn my_fn() { match () { () => m$0 } }", is_match_arm); |
116 | } | 116 | } |
117 | 117 | ||
118 | pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool { | 118 | pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> { |
119 | element | 119 | element.into_token().and_then(|it| previous_non_trivia_token(it)) |
120 | .into_token() | ||
121 | .and_then(|it| previous_non_trivia_token(it)) | ||
122 | .filter(|it| it.kind() == T![unsafe]) | ||
123 | .is_some() | ||
124 | } | ||
125 | #[test] | ||
126 | fn test_unsafe_is_prev() { | ||
127 | check_pattern_is_applicable(r"unsafe i$0", unsafe_is_prev); | ||
128 | } | ||
129 | |||
130 | pub(crate) fn if_is_prev(element: SyntaxElement) -> bool { | ||
131 | element | ||
132 | .into_token() | ||
133 | .and_then(|it| previous_non_trivia_token(it)) | ||
134 | .filter(|it| it.kind() == T![if]) | ||
135 | .is_some() | ||
136 | } | ||
137 | |||
138 | pub(crate) fn fn_is_prev(element: SyntaxElement) -> bool { | ||
139 | element | ||
140 | .into_token() | ||
141 | .and_then(|it| previous_non_trivia_token(it)) | ||
142 | .filter(|it| it.kind() == T![fn]) | ||
143 | .is_some() | ||
144 | } | ||
145 | #[test] | ||
146 | fn test_fn_is_prev() { | ||
147 | check_pattern_is_applicable(r"fn l$0", fn_is_prev); | ||
148 | } | 120 | } |
149 | 121 | ||
150 | /// Check if the token previous to the previous one is `for`. | 122 | /// Check if the token previous to the previous one is `for`. |
@@ -162,11 +134,6 @@ fn test_for_is_prev2() { | |||
162 | check_pattern_is_applicable(r"for i i$0", for_is_prev2); | 134 | check_pattern_is_applicable(r"for i i$0", for_is_prev2); |
163 | } | 135 | } |
164 | 136 | ||
165 | #[test] | ||
166 | fn test_if_is_prev() { | ||
167 | check_pattern_is_applicable(r"if l$0", if_is_prev); | ||
168 | } | ||
169 | |||
170 | pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool { | 137 | pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool { |
171 | previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT).is_some() | 138 | previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT).is_some() |
172 | } | 139 | } |