diff options
Diffstat (limited to 'crates/ide_completion/src/completions/keyword.rs')
-rw-r--r-- | crates/ide_completion/src/completions/keyword.rs | 239 |
1 files changed, 127 insertions, 112 deletions
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 61b667104..e71a04b6e 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 | ||
@@ -48,107 +48,102 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
48 | cov_mark::hit!(no_keyword_completion_in_record_lit); | 48 | cov_mark::hit!(no_keyword_completion_in_record_lit); |
49 | return; | 49 | return; |
50 | } | 50 | } |
51 | let mut add_keyword = |kw, snippet| add_keyword(ctx, acc, kw, snippet); | ||
51 | 52 | ||
52 | let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent; | 53 | let expects_assoc_item = ctx.expects_assoc_item(); |
53 | if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling { | 54 | let has_block_expr_parent = ctx.has_block_expr_parent(); |
54 | add_keyword(ctx, acc, "where", "where "); | 55 | let expects_item = ctx.expects_item(); |
56 | |||
57 | if ctx.has_impl_or_trait_prev_sibling() { | ||
58 | // FIXME this also incorrectly shows up after a complete trait/impl | ||
59 | add_keyword("where", "where "); | ||
55 | return; | 60 | return; |
56 | } | 61 | } |
57 | if ctx.unsafe_is_prev { | 62 | if ctx.previous_token_is(T![unsafe]) { |
58 | if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent { | 63 | if expects_item || expects_assoc_item || has_block_expr_parent { |
59 | add_keyword(ctx, acc, "fn", "fn $0() {}") | 64 | add_keyword("fn", "fn $1($2) {\n $0\n}") |
60 | } | 65 | } |
61 | 66 | ||
62 | if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { | 67 | if expects_item || has_block_expr_parent { |
63 | add_keyword(ctx, acc, "trait", "trait $0 {}"); | 68 | add_keyword("trait", "trait $1 {\n $0\n}"); |
64 | add_keyword(ctx, acc, "impl", "impl $0 {}"); | 69 | add_keyword("impl", "impl $1 {\n $0\n}"); |
65 | } | 70 | } |
66 | 71 | ||
67 | return; | 72 | return; |
68 | } | 73 | } |
69 | if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent | ||
70 | { | ||
71 | add_keyword(ctx, acc, "fn", "fn $0() {}"); | ||
72 | } | ||
73 | if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { | ||
74 | add_keyword(ctx, acc, "use", "use "); | ||
75 | add_keyword(ctx, acc, "impl", "impl $0 {}"); | ||
76 | add_keyword(ctx, acc, "trait", "trait $0 {}"); | ||
77 | } | ||
78 | 74 | ||
79 | if ctx.has_item_list_or_source_file_parent { | 75 | if expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_record_field() { |
80 | add_keyword(ctx, acc, "enum", "enum $0 {}"); | 76 | add_keyword("pub(crate)", "pub(crate) "); |
81 | add_keyword(ctx, acc, "struct", "struct $0"); | 77 | add_keyword("pub", "pub "); |
82 | add_keyword(ctx, acc, "union", "union $0 {}"); | ||
83 | } | 78 | } |
84 | 79 | ||
85 | if ctx.is_expr { | 80 | if expects_item || expects_assoc_item || has_block_expr_parent || ctx.is_match_arm { |
86 | add_keyword(ctx, acc, "match", "match $0 {}"); | 81 | add_keyword("unsafe", "unsafe "); |
87 | add_keyword(ctx, acc, "while", "while $0 {}"); | ||
88 | add_keyword(ctx, acc, "while let", "while let $1 = $0 {}"); | ||
89 | add_keyword(ctx, acc, "loop", "loop {$0}"); | ||
90 | add_keyword(ctx, acc, "if", "if $0 {}"); | ||
91 | add_keyword(ctx, acc, "if let", "if let $1 = $0 {}"); | ||
92 | add_keyword(ctx, acc, "for", "for $1 in $0 {}"); | ||
93 | } | 82 | } |
94 | 83 | ||
95 | if ctx.if_is_prev || ctx.block_expr_parent { | 84 | if expects_item || expects_assoc_item || has_block_expr_parent { |
96 | add_keyword(ctx, acc, "let", "let "); | 85 | add_keyword("fn", "fn $1($2) {\n $0\n}"); |
86 | add_keyword("const", "const $0"); | ||
87 | add_keyword("type", "type $0"); | ||
97 | } | 88 | } |
98 | 89 | ||
99 | if ctx.after_if { | 90 | if expects_item || has_block_expr_parent { |
100 | add_keyword(ctx, acc, "else", "else {$0}"); | 91 | add_keyword("use", "use $0"); |
101 | add_keyword(ctx, acc, "else if", "else if $0 {}"); | 92 | add_keyword("impl", "impl $1 {\n $0\n}"); |
93 | add_keyword("trait", "trait $1 {\n $0\n}"); | ||
94 | add_keyword("static", "static $0"); | ||
95 | add_keyword("extern", "extern $0"); | ||
96 | add_keyword("mod", "mod $0"); | ||
102 | } | 97 | } |
103 | if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { | 98 | |
104 | add_keyword(ctx, acc, "mod", "mod $0"); | 99 | if expects_item { |
100 | add_keyword("enum", "enum $1 {\n $0\n}"); | ||
101 | add_keyword("struct", "struct $0"); | ||
102 | add_keyword("union", "union $1 {\n $0\n}"); | ||
105 | } | 103 | } |
106 | if ctx.bind_pat_parent || ctx.ref_pat_parent { | 104 | |
107 | add_keyword(ctx, acc, "mut", "mut "); | 105 | if ctx.expects_expression() { |
106 | add_keyword("match", "match $1 {\n $0\n}"); | ||
107 | add_keyword("while", "while $1 {\n $0\n}"); | ||
108 | add_keyword("while let", "while let $1 = $2 {\n $0\n}"); | ||
109 | add_keyword("loop", "loop {\n $0\n}"); | ||
110 | add_keyword("if", "if $1 {\n $0\n}"); | ||
111 | add_keyword("if let", "if let $1 = $2 {\n $0\n}"); | ||
112 | add_keyword("for", "for $1 in $2 {\n $0\n}"); | ||
108 | } | 113 | } |
109 | if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent | 114 | |
110 | { | 115 | if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || has_block_expr_parent { |
111 | add_keyword(ctx, acc, "const", "const "); | 116 | add_keyword("let", "let "); |
112 | add_keyword(ctx, acc, "type", "type "); | ||
113 | } | 117 | } |
114 | if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { | 118 | |
115 | add_keyword(ctx, acc, "static", "static "); | 119 | if ctx.after_if() { |
116 | }; | 120 | add_keyword("else", "else {\n $0\n}"); |
117 | if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent { | 121 | add_keyword("else if", "else if $1 {\n $0\n}"); |
118 | add_keyword(ctx, acc, "extern", "extern "); | ||
119 | } | 122 | } |
120 | if ctx.has_item_list_or_source_file_parent | 123 | |
121 | || has_trait_or_impl_parent | 124 | if ctx.expects_ident_pat_or_ref_expr() { |
122 | || ctx.block_expr_parent | 125 | add_keyword("mut", "mut "); |
123 | || ctx.is_match_arm | ||
124 | { | ||
125 | add_keyword(ctx, acc, "unsafe", "unsafe "); | ||
126 | } | 126 | } |
127 | |||
127 | if ctx.in_loop_body { | 128 | if ctx.in_loop_body { |
128 | if ctx.can_be_stmt { | 129 | if ctx.can_be_stmt { |
129 | add_keyword(ctx, acc, "continue", "continue;"); | 130 | add_keyword("continue", "continue;"); |
130 | add_keyword(ctx, acc, "break", "break;"); | 131 | add_keyword("break", "break;"); |
131 | } else { | 132 | } else { |
132 | add_keyword(ctx, acc, "continue", "continue"); | 133 | add_keyword("continue", "continue"); |
133 | add_keyword(ctx, acc, "break", "break"); | 134 | add_keyword("break", "break"); |
134 | } | 135 | } |
135 | } | 136 | } |
136 | if ctx.has_item_list_or_source_file_parent || ctx.has_impl_parent | ctx.has_field_list_parent { | ||
137 | add_keyword(ctx, acc, "pub(crate)", "pub(crate) "); | ||
138 | add_keyword(ctx, acc, "pub", "pub "); | ||
139 | } | ||
140 | 137 | ||
141 | if !ctx.is_trivial_path { | 138 | if !ctx.is_trivial_path { |
142 | return; | 139 | return; |
143 | } | 140 | } |
144 | let fn_def = match &ctx.function_syntax { | 141 | let fn_def = match &ctx.function_def { |
145 | Some(it) => it, | 142 | Some(it) => it, |
146 | None => return, | 143 | None => return, |
147 | }; | 144 | }; |
148 | 145 | ||
149 | add_keyword( | 146 | add_keyword( |
150 | ctx, | ||
151 | acc, | ||
152 | "return", | 147 | "return", |
153 | match (ctx.can_be_stmt, fn_def.ret_type().is_some()) { | 148 | match (ctx.can_be_stmt, fn_def.ret_type().is_some()) { |
154 | (true, true) => "return $0;", | 149 | (true, true) => "return $0;", |
@@ -165,15 +160,12 @@ fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet | |||
165 | 160 | ||
166 | match ctx.config.snippet_cap { | 161 | match ctx.config.snippet_cap { |
167 | Some(cap) => { | 162 | Some(cap) => { |
168 | let tmp; | 163 | if snippet.ends_with('}') && ctx.incomplete_let { |
169 | let snippet = if snippet.ends_with('}') && ctx.incomplete_let { | ||
170 | cov_mark::hit!(let_semi); | 164 | cov_mark::hit!(let_semi); |
171 | tmp = format!("{};", snippet); | 165 | item.insert_snippet(cap, format!("{};", snippet)); |
172 | &tmp | ||
173 | } else { | 166 | } else { |
174 | snippet | 167 | item.insert_snippet(cap, snippet); |
175 | }; | 168 | } |
176 | item.insert_snippet(cap, snippet); | ||
177 | } | 169 | } |
178 | None => { | 170 | None => { |
179 | item.insert_text(if snippet.contains('$') { kw } else { snippet }); | 171 | item.insert_text(if snippet.contains('$') { kw } else { snippet }); |
@@ -236,21 +228,21 @@ mod tests { | |||
236 | check( | 228 | check( |
237 | r"m$0", | 229 | r"m$0", |
238 | expect![[r#" | 230 | expect![[r#" |
231 | kw pub(crate) | ||
232 | kw pub | ||
233 | kw unsafe | ||
239 | kw fn | 234 | kw fn |
235 | kw const | ||
236 | kw type | ||
240 | kw use | 237 | kw use |
241 | kw impl | 238 | kw impl |
242 | kw trait | 239 | kw trait |
240 | kw static | ||
241 | kw extern | ||
242 | kw mod | ||
243 | kw enum | 243 | kw enum |
244 | kw struct | 244 | kw struct |
245 | kw union | 245 | kw union |
246 | kw mod | ||
247 | kw const | ||
248 | kw type | ||
249 | kw static | ||
250 | kw extern | ||
251 | kw unsafe | ||
252 | kw pub(crate) | ||
253 | kw pub | ||
254 | "#]], | 246 | "#]], |
255 | ); | 247 | ); |
256 | } | 248 | } |
@@ -260,10 +252,16 @@ mod tests { | |||
260 | check( | 252 | check( |
261 | r"fn quux() { $0 }", | 253 | r"fn quux() { $0 }", |
262 | expect![[r#" | 254 | expect![[r#" |
255 | kw unsafe | ||
263 | kw fn | 256 | kw fn |
257 | kw const | ||
258 | kw type | ||
264 | kw use | 259 | kw use |
265 | kw impl | 260 | kw impl |
266 | kw trait | 261 | kw trait |
262 | kw static | ||
263 | kw extern | ||
264 | kw mod | ||
267 | kw match | 265 | kw match |
268 | kw while | 266 | kw while |
269 | kw while let | 267 | kw while let |
@@ -272,12 +270,6 @@ mod tests { | |||
272 | kw if let | 270 | kw if let |
273 | kw for | 271 | kw for |
274 | kw let | 272 | kw let |
275 | kw mod | ||
276 | kw const | ||
277 | kw type | ||
278 | kw static | ||
279 | kw extern | ||
280 | kw unsafe | ||
281 | kw return | 273 | kw return |
282 | "#]], | 274 | "#]], |
283 | ); | 275 | ); |
@@ -288,10 +280,16 @@ mod tests { | |||
288 | check( | 280 | check( |
289 | r"fn quux() { if true { $0 } }", | 281 | r"fn quux() { if true { $0 } }", |
290 | expect![[r#" | 282 | expect![[r#" |
283 | kw unsafe | ||
291 | kw fn | 284 | kw fn |
285 | kw const | ||
286 | kw type | ||
292 | kw use | 287 | kw use |
293 | kw impl | 288 | kw impl |
294 | kw trait | 289 | kw trait |
290 | kw static | ||
291 | kw extern | ||
292 | kw mod | ||
295 | kw match | 293 | kw match |
296 | kw while | 294 | kw while |
297 | kw while let | 295 | kw while let |
@@ -300,12 +298,6 @@ mod tests { | |||
300 | kw if let | 298 | kw if let |
301 | kw for | 299 | kw for |
302 | kw let | 300 | kw let |
303 | kw mod | ||
304 | kw const | ||
305 | kw type | ||
306 | kw static | ||
307 | kw extern | ||
308 | kw unsafe | ||
309 | kw return | 301 | kw return |
310 | "#]], | 302 | "#]], |
311 | ); | 303 | ); |
@@ -316,10 +308,16 @@ mod tests { | |||
316 | check( | 308 | check( |
317 | r#"fn quux() { if true { () } $0 }"#, | 309 | r#"fn quux() { if true { () } $0 }"#, |
318 | expect![[r#" | 310 | expect![[r#" |
311 | kw unsafe | ||
319 | kw fn | 312 | kw fn |
313 | kw const | ||
314 | kw type | ||
320 | kw use | 315 | kw use |
321 | kw impl | 316 | kw impl |
322 | kw trait | 317 | kw trait |
318 | kw static | ||
319 | kw extern | ||
320 | kw mod | ||
323 | kw match | 321 | kw match |
324 | kw while | 322 | kw while |
325 | kw while let | 323 | kw while let |
@@ -330,19 +328,15 @@ mod tests { | |||
330 | kw let | 328 | kw let |
331 | kw else | 329 | kw else |
332 | kw else if | 330 | kw else if |
333 | kw mod | ||
334 | kw const | ||
335 | kw type | ||
336 | kw static | ||
337 | kw extern | ||
338 | kw unsafe | ||
339 | kw return | 331 | kw return |
340 | "#]], | 332 | "#]], |
341 | ); | 333 | ); |
342 | check_edit( | 334 | check_edit( |
343 | "else", | 335 | "else", |
344 | r#"fn quux() { if true { () } $0 }"#, | 336 | r#"fn quux() { if true { () } $0 }"#, |
345 | r#"fn quux() { if true { () } else {$0} }"#, | 337 | r#"fn quux() { if true { () } else { |
338 | $0 | ||
339 | } }"#, | ||
346 | ); | 340 | ); |
347 | } | 341 | } |
348 | 342 | ||
@@ -355,6 +349,7 @@ fn quux() -> i32 { | |||
355 | } | 349 | } |
356 | "#, | 350 | "#, |
357 | expect![[r#" | 351 | expect![[r#" |
352 | kw unsafe | ||
358 | kw match | 353 | kw match |
359 | kw while | 354 | kw while |
360 | kw while let | 355 | kw while let |
@@ -362,7 +357,6 @@ fn quux() -> i32 { | |||
362 | kw if | 357 | kw if |
363 | kw if let | 358 | kw if let |
364 | kw for | 359 | kw for |
365 | kw unsafe | ||
366 | kw return | 360 | kw return |
367 | "#]], | 361 | "#]], |
368 | ); | 362 | ); |
@@ -373,10 +367,10 @@ fn quux() -> i32 { | |||
373 | check( | 367 | check( |
374 | r"trait My { $0 }", | 368 | r"trait My { $0 }", |
375 | expect![[r#" | 369 | expect![[r#" |
370 | kw unsafe | ||
376 | kw fn | 371 | kw fn |
377 | kw const | 372 | kw const |
378 | kw type | 373 | kw type |
379 | kw unsafe | ||
380 | "#]], | 374 | "#]], |
381 | ); | 375 | ); |
382 | } | 376 | } |
@@ -386,12 +380,27 @@ fn quux() -> i32 { | |||
386 | check( | 380 | check( |
387 | r"impl My { $0 }", | 381 | r"impl My { $0 }", |
388 | expect![[r#" | 382 | expect![[r#" |
383 | kw pub(crate) | ||
384 | kw pub | ||
385 | kw unsafe | ||
389 | kw fn | 386 | kw fn |
390 | kw const | 387 | kw const |
391 | kw type | 388 | kw type |
392 | kw unsafe | 389 | "#]], |
390 | ); | ||
391 | } | ||
392 | |||
393 | #[test] | ||
394 | fn test_keywords_in_impl_def_with_attr() { | ||
395 | check( | ||
396 | r"impl My { #[foo] $0 }", | ||
397 | expect![[r#" | ||
393 | kw pub(crate) | 398 | kw pub(crate) |
394 | kw pub | 399 | kw pub |
400 | kw unsafe | ||
401 | kw fn | ||
402 | kw const | ||
403 | kw type | ||
395 | "#]], | 404 | "#]], |
396 | ); | 405 | ); |
397 | } | 406 | } |
@@ -401,10 +410,16 @@ fn quux() -> i32 { | |||
401 | check( | 410 | check( |
402 | r"fn my() { loop { $0 } }", | 411 | r"fn my() { loop { $0 } }", |
403 | expect![[r#" | 412 | expect![[r#" |
413 | kw unsafe | ||
404 | kw fn | 414 | kw fn |
415 | kw const | ||
416 | kw type | ||
405 | kw use | 417 | kw use |
406 | kw impl | 418 | kw impl |
407 | kw trait | 419 | kw trait |
420 | kw static | ||
421 | kw extern | ||
422 | kw mod | ||
408 | kw match | 423 | kw match |
409 | kw while | 424 | kw while |
410 | kw while let | 425 | kw while let |
@@ -413,12 +428,6 @@ fn quux() -> i32 { | |||
413 | kw if let | 428 | kw if let |
414 | kw for | 429 | kw for |
415 | kw let | 430 | kw let |
416 | kw mod | ||
417 | kw const | ||
418 | kw type | ||
419 | kw static | ||
420 | kw extern | ||
421 | kw unsafe | ||
422 | kw continue | 431 | kw continue |
423 | kw break | 432 | kw break |
424 | kw return | 433 | kw return |
@@ -646,7 +655,9 @@ fn foo() { | |||
646 | fn main() { let x = $0 } | 655 | fn main() { let x = $0 } |
647 | "#, | 656 | "#, |
648 | r#" | 657 | r#" |
649 | fn main() { let x = match $0 {}; } | 658 | fn main() { let x = match $1 { |
659 | $0 | ||
660 | }; } | ||
650 | "#, | 661 | "#, |
651 | ); | 662 | ); |
652 | 663 | ||
@@ -660,7 +671,9 @@ fn main() { | |||
660 | "#, | 671 | "#, |
661 | r#" | 672 | r#" |
662 | fn main() { | 673 | fn main() { |
663 | let x = if $0 {}; | 674 | let x = if $1 { |
675 | $0 | ||
676 | }; | ||
664 | let y = 92; | 677 | let y = 92; |
665 | } | 678 | } |
666 | "#, | 679 | "#, |
@@ -676,7 +689,9 @@ fn main() { | |||
676 | "#, | 689 | "#, |
677 | r#" | 690 | r#" |
678 | fn main() { | 691 | fn main() { |
679 | let x = loop {$0}; | 692 | let x = loop { |
693 | $0 | ||
694 | }; | ||
680 | bar(); | 695 | bar(); |
681 | } | 696 | } |
682 | "#, | 697 | "#, |