diff options
Diffstat (limited to 'crates/ide_completion/src/completions/keyword.rs')
-rw-r--r-- | crates/ide_completion/src/completions/keyword.rs | 220 |
1 files changed, 117 insertions, 103 deletions
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index 58e35bad9..0d035c611 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs | |||
@@ -4,7 +4,10 @@ use std::iter; | |||
4 | 4 | ||
5 | use syntax::{SyntaxKind, T}; | 5 | use syntax::{SyntaxKind, T}; |
6 | 6 | ||
7 | use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; | 7 | use crate::{ |
8 | patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind, | ||
9 | CompletionKind, Completions, | ||
10 | }; | ||
8 | 11 | ||
9 | pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) { | 12 | pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) { |
10 | // complete keyword "crate" in use stmt | 13 | // complete keyword "crate" in use stmt |
@@ -44,96 +47,95 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
44 | cov_mark::hit!(no_keyword_completion_in_comments); | 47 | cov_mark::hit!(no_keyword_completion_in_comments); |
45 | return; | 48 | return; |
46 | } | 49 | } |
47 | if ctx.record_lit_syntax.is_some() { | 50 | if matches!(ctx.completion_location, Some(ImmediateLocation::RecordExpr(_))) { |
48 | cov_mark::hit!(no_keyword_completion_in_record_lit); | 51 | cov_mark::hit!(no_keyword_completion_in_record_lit); |
49 | return; | 52 | return; |
50 | } | 53 | } |
54 | let mut add_keyword = |kw, snippet| add_keyword(ctx, acc, kw, snippet); | ||
51 | 55 | ||
52 | let has_trait_or_impl_parent = ctx.has_impl_or_trait_parent(); | 56 | let expects_assoc_item = ctx.expects_assoc_item(); |
53 | let has_block_expr_parent = ctx.has_block_expr_parent(); | 57 | let has_block_expr_parent = ctx.has_block_expr_parent(); |
54 | let has_item_list_parent = ctx.has_item_list_parent(); | 58 | let expects_item = ctx.expects_item(); |
59 | |||
55 | if ctx.has_impl_or_trait_prev_sibling() { | 60 | if ctx.has_impl_or_trait_prev_sibling() { |
56 | add_keyword(ctx, acc, "where", "where "); | 61 | add_keyword("where", "where "); |
57 | return; | 62 | return; |
58 | } | 63 | } |
59 | if ctx.previous_token_is(T![unsafe]) { | 64 | if ctx.previous_token_is(T![unsafe]) { |
60 | if has_item_list_parent || has_block_expr_parent { | 65 | if expects_item || expects_assoc_item || has_block_expr_parent { |
61 | add_keyword(ctx, acc, "fn", "fn $1($2) {\n $0\n}") | 66 | add_keyword("fn", "fn $1($2) {\n $0\n}") |
62 | } | 67 | } |
63 | 68 | ||
64 | if has_item_list_parent || has_block_expr_parent { | 69 | if expects_item || has_block_expr_parent { |
65 | add_keyword(ctx, acc, "trait", "trait $1 {\n $0\n}"); | 70 | add_keyword("trait", "trait $1 {\n $0\n}"); |
66 | add_keyword(ctx, acc, "impl", "impl $1 {\n $0\n}"); | 71 | add_keyword("impl", "impl $1 {\n $0\n}"); |
67 | } | 72 | } |
68 | 73 | ||
69 | return; | 74 | return; |
70 | } | 75 | } |
71 | if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent { | ||
72 | add_keyword(ctx, acc, "fn", "fn $1($2) {\n $0\n}"); | ||
73 | } | ||
74 | if has_item_list_parent || has_block_expr_parent { | ||
75 | add_keyword(ctx, acc, "use", "use "); | ||
76 | add_keyword(ctx, acc, "impl", "impl $1 {\n $0\n}"); | ||
77 | add_keyword(ctx, acc, "trait", "trait $1 {\n $0\n}"); | ||
78 | } | ||
79 | 76 | ||
80 | if has_item_list_parent { | 77 | if expects_item || ctx.expects_non_trait_assoc_item() || ctx.expect_record_field() { |
81 | add_keyword(ctx, acc, "enum", "enum $1 {\n $0\n}"); | 78 | add_keyword("pub(crate)", "pub(crate) "); |
82 | add_keyword(ctx, acc, "struct", "struct $0"); | 79 | add_keyword("pub", "pub "); |
83 | add_keyword(ctx, acc, "union", "union $1 {\n $0\n}"); | ||
84 | } | 80 | } |
85 | 81 | ||
86 | if ctx.is_expr { | 82 | if expects_item || expects_assoc_item || has_block_expr_parent { |
87 | add_keyword(ctx, acc, "match", "match $1 {\n $0\n}"); | 83 | add_keyword("unsafe", "unsafe "); |
88 | add_keyword(ctx, acc, "while", "while $1 {\n $0\n}"); | 84 | add_keyword("fn", "fn $1($2) {\n $0\n}"); |
89 | add_keyword(ctx, acc, "while let", "while let $1 = $2 {\n $0\n}"); | 85 | add_keyword("const", "const $0"); |
90 | add_keyword(ctx, acc, "loop", "loop {\n $0\n}"); | 86 | add_keyword("type", "type $0"); |
91 | add_keyword(ctx, acc, "if", "if $1 {\n $0\n}"); | ||
92 | add_keyword(ctx, acc, "if let", "if let $1 = $2 {\n $0\n}"); | ||
93 | add_keyword(ctx, acc, "for", "for $1 in $2 {\n $0\n}"); | ||
94 | } | 87 | } |
95 | 88 | ||
96 | if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || has_block_expr_parent { | 89 | if expects_item || has_block_expr_parent { |
97 | add_keyword(ctx, acc, "let", "let "); | 90 | add_keyword("use", "use $0"); |
91 | add_keyword("impl", "impl $1 {\n $0\n}"); | ||
92 | add_keyword("trait", "trait $1 {\n $0\n}"); | ||
93 | add_keyword("static", "static $0"); | ||
94 | add_keyword("extern", "extern $0"); | ||
95 | add_keyword("mod", "mod $0"); | ||
98 | } | 96 | } |
99 | 97 | ||
100 | if ctx.after_if { | 98 | if expects_item { |
101 | add_keyword(ctx, acc, "else", "else {\n $0\n}"); | 99 | add_keyword("enum", "enum $1 {\n $0\n}"); |
102 | add_keyword(ctx, acc, "else if", "else if $1 {\n $0\n}"); | 100 | add_keyword("struct", "struct $0"); |
103 | } | 101 | add_keyword("union", "union $1 {\n $0\n}"); |
104 | if has_item_list_parent || has_block_expr_parent { | ||
105 | add_keyword(ctx, acc, "mod", "mod $0"); | ||
106 | } | 102 | } |
107 | if ctx.has_ident_or_ref_pat_parent() { | 103 | |
108 | add_keyword(ctx, acc, "mut", "mut "); | 104 | if ctx.expects_expression() { |
105 | if !has_block_expr_parent { | ||
106 | add_keyword("unsafe", "unsafe {\n $0\n}"); | ||
107 | } | ||
108 | add_keyword("match", "match $1 {\n $0\n}"); | ||
109 | add_keyword("while", "while $1 {\n $0\n}"); | ||
110 | add_keyword("while let", "while let $1 = $2 {\n $0\n}"); | ||
111 | add_keyword("loop", "loop {\n $0\n}"); | ||
112 | add_keyword("if", "if $1 {\n $0\n}"); | ||
113 | add_keyword("if let", "if let $1 = $2 {\n $0\n}"); | ||
114 | add_keyword("for", "for $1 in $2 {\n $0\n}"); | ||
109 | } | 115 | } |
110 | if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent { | 116 | |
111 | add_keyword(ctx, acc, "const", "const "); | 117 | if ctx.previous_token_is(T![if]) || ctx.previous_token_is(T![while]) || has_block_expr_parent { |
112 | add_keyword(ctx, acc, "type", "type "); | 118 | add_keyword("let", "let "); |
113 | } | 119 | } |
114 | if has_item_list_parent || has_block_expr_parent { | 120 | |
115 | add_keyword(ctx, acc, "static", "static "); | 121 | if ctx.after_if() { |
116 | }; | 122 | add_keyword("else", "else {\n $0\n}"); |
117 | if has_item_list_parent || has_block_expr_parent { | 123 | add_keyword("else if", "else if $1 {\n $0\n}"); |
118 | add_keyword(ctx, acc, "extern", "extern "); | ||
119 | } | 124 | } |
120 | if has_item_list_parent || has_trait_or_impl_parent || has_block_expr_parent || ctx.is_match_arm | 125 | |
121 | { | 126 | if ctx.expects_ident_pat_or_ref_expr() { |
122 | add_keyword(ctx, acc, "unsafe", "unsafe "); | 127 | add_keyword("mut", "mut "); |
123 | } | 128 | } |
129 | |||
124 | if ctx.in_loop_body { | 130 | if ctx.in_loop_body { |
125 | if ctx.can_be_stmt { | 131 | if ctx.can_be_stmt { |
126 | add_keyword(ctx, acc, "continue", "continue;"); | 132 | add_keyword("continue", "continue;"); |
127 | add_keyword(ctx, acc, "break", "break;"); | 133 | add_keyword("break", "break;"); |
128 | } else { | 134 | } else { |
129 | add_keyword(ctx, acc, "continue", "continue"); | 135 | add_keyword("continue", "continue"); |
130 | add_keyword(ctx, acc, "break", "break"); | 136 | add_keyword("break", "break"); |
131 | } | 137 | } |
132 | } | 138 | } |
133 | if has_item_list_parent || ctx.has_impl_parent() || ctx.has_field_list_parent() { | ||
134 | add_keyword(ctx, acc, "pub(crate)", "pub(crate) "); | ||
135 | add_keyword(ctx, acc, "pub", "pub "); | ||
136 | } | ||
137 | 139 | ||
138 | if !ctx.is_trivial_path { | 140 | if !ctx.is_trivial_path { |
139 | return; | 141 | return; |
@@ -144,8 +146,6 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
144 | }; | 146 | }; |
145 | 147 | ||
146 | add_keyword( | 148 | add_keyword( |
147 | ctx, | ||
148 | acc, | ||
149 | "return", | 149 | "return", |
150 | match (ctx.can_be_stmt, fn_def.ret_type().is_some()) { | 150 | match (ctx.can_be_stmt, fn_def.ret_type().is_some()) { |
151 | (true, true) => "return $0;", | 151 | (true, true) => "return $0;", |
@@ -162,15 +162,12 @@ fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet | |||
162 | 162 | ||
163 | match ctx.config.snippet_cap { | 163 | match ctx.config.snippet_cap { |
164 | Some(cap) => { | 164 | Some(cap) => { |
165 | let tmp; | 165 | if snippet.ends_with('}') && ctx.incomplete_let { |
166 | let snippet = if snippet.ends_with('}') && ctx.incomplete_let { | ||
167 | cov_mark::hit!(let_semi); | 166 | cov_mark::hit!(let_semi); |
168 | tmp = format!("{};", snippet); | 167 | item.insert_snippet(cap, format!("{};", snippet)); |
169 | &tmp | ||
170 | } else { | 168 | } else { |
171 | snippet | 169 | item.insert_snippet(cap, snippet); |
172 | }; | 170 | } |
173 | item.insert_snippet(cap, snippet); | ||
174 | } | 171 | } |
175 | None => { | 172 | None => { |
176 | item.insert_text(if snippet.contains('$') { kw } else { snippet }); | 173 | item.insert_text(if snippet.contains('$') { kw } else { snippet }); |
@@ -233,21 +230,21 @@ mod tests { | |||
233 | check( | 230 | check( |
234 | r"m$0", | 231 | r"m$0", |
235 | expect![[r#" | 232 | expect![[r#" |
233 | kw pub(crate) | ||
234 | kw pub | ||
235 | kw unsafe | ||
236 | kw fn | 236 | kw fn |
237 | kw const | ||
238 | kw type | ||
237 | kw use | 239 | kw use |
238 | kw impl | 240 | kw impl |
239 | kw trait | 241 | kw trait |
242 | kw static | ||
243 | kw extern | ||
244 | kw mod | ||
240 | kw enum | 245 | kw enum |
241 | kw struct | 246 | kw struct |
242 | kw union | 247 | kw union |
243 | kw mod | ||
244 | kw const | ||
245 | kw type | ||
246 | kw static | ||
247 | kw extern | ||
248 | kw unsafe | ||
249 | kw pub(crate) | ||
250 | kw pub | ||
251 | "#]], | 248 | "#]], |
252 | ); | 249 | ); |
253 | } | 250 | } |
@@ -257,10 +254,16 @@ mod tests { | |||
257 | check( | 254 | check( |
258 | r"fn quux() { $0 }", | 255 | r"fn quux() { $0 }", |
259 | expect![[r#" | 256 | expect![[r#" |
257 | kw unsafe | ||
260 | kw fn | 258 | kw fn |
259 | kw const | ||
260 | kw type | ||
261 | kw use | 261 | kw use |
262 | kw impl | 262 | kw impl |
263 | kw trait | 263 | kw trait |
264 | kw static | ||
265 | kw extern | ||
266 | kw mod | ||
264 | kw match | 267 | kw match |
265 | kw while | 268 | kw while |
266 | kw while let | 269 | kw while let |
@@ -269,12 +272,6 @@ mod tests { | |||
269 | kw if let | 272 | kw if let |
270 | kw for | 273 | kw for |
271 | kw let | 274 | kw let |
272 | kw mod | ||
273 | kw const | ||
274 | kw type | ||
275 | kw static | ||
276 | kw extern | ||
277 | kw unsafe | ||
278 | kw return | 275 | kw return |
279 | "#]], | 276 | "#]], |
280 | ); | 277 | ); |
@@ -285,10 +282,16 @@ mod tests { | |||
285 | check( | 282 | check( |
286 | r"fn quux() { if true { $0 } }", | 283 | r"fn quux() { if true { $0 } }", |
287 | expect![[r#" | 284 | expect![[r#" |
285 | kw unsafe | ||
288 | kw fn | 286 | kw fn |
287 | kw const | ||
288 | kw type | ||
289 | kw use | 289 | kw use |
290 | kw impl | 290 | kw impl |
291 | kw trait | 291 | kw trait |
292 | kw static | ||
293 | kw extern | ||
294 | kw mod | ||
292 | kw match | 295 | kw match |
293 | kw while | 296 | kw while |
294 | kw while let | 297 | kw while let |
@@ -297,12 +300,6 @@ mod tests { | |||
297 | kw if let | 300 | kw if let |
298 | kw for | 301 | kw for |
299 | kw let | 302 | kw let |
300 | kw mod | ||
301 | kw const | ||
302 | kw type | ||
303 | kw static | ||
304 | kw extern | ||
305 | kw unsafe | ||
306 | kw return | 303 | kw return |
307 | "#]], | 304 | "#]], |
308 | ); | 305 | ); |
@@ -313,10 +310,16 @@ mod tests { | |||
313 | check( | 310 | check( |
314 | r#"fn quux() { if true { () } $0 }"#, | 311 | r#"fn quux() { if true { () } $0 }"#, |
315 | expect![[r#" | 312 | expect![[r#" |
313 | kw unsafe | ||
316 | kw fn | 314 | kw fn |
315 | kw const | ||
316 | kw type | ||
317 | kw use | 317 | kw use |
318 | kw impl | 318 | kw impl |
319 | kw trait | 319 | kw trait |
320 | kw static | ||
321 | kw extern | ||
322 | kw mod | ||
320 | kw match | 323 | kw match |
321 | kw while | 324 | kw while |
322 | kw while let | 325 | kw while let |
@@ -327,12 +330,6 @@ mod tests { | |||
327 | kw let | 330 | kw let |
328 | kw else | 331 | kw else |
329 | kw else if | 332 | kw else if |
330 | kw mod | ||
331 | kw const | ||
332 | kw type | ||
333 | kw static | ||
334 | kw extern | ||
335 | kw unsafe | ||
336 | kw return | 333 | kw return |
337 | "#]], | 334 | "#]], |
338 | ); | 335 | ); |
@@ -354,6 +351,7 @@ fn quux() -> i32 { | |||
354 | } | 351 | } |
355 | "#, | 352 | "#, |
356 | expect![[r#" | 353 | expect![[r#" |
354 | kw unsafe | ||
357 | kw match | 355 | kw match |
358 | kw while | 356 | kw while |
359 | kw while let | 357 | kw while let |
@@ -361,7 +359,6 @@ fn quux() -> i32 { | |||
361 | kw if | 359 | kw if |
362 | kw if let | 360 | kw if let |
363 | kw for | 361 | kw for |
364 | kw unsafe | ||
365 | kw return | 362 | kw return |
366 | "#]], | 363 | "#]], |
367 | ); | 364 | ); |
@@ -372,10 +369,10 @@ fn quux() -> i32 { | |||
372 | check( | 369 | check( |
373 | r"trait My { $0 }", | 370 | r"trait My { $0 }", |
374 | expect![[r#" | 371 | expect![[r#" |
372 | kw unsafe | ||
375 | kw fn | 373 | kw fn |
376 | kw const | 374 | kw const |
377 | kw type | 375 | kw type |
378 | kw unsafe | ||
379 | "#]], | 376 | "#]], |
380 | ); | 377 | ); |
381 | } | 378 | } |
@@ -385,12 +382,27 @@ fn quux() -> i32 { | |||
385 | check( | 382 | check( |
386 | r"impl My { $0 }", | 383 | r"impl My { $0 }", |
387 | expect![[r#" | 384 | expect![[r#" |
385 | kw pub(crate) | ||
386 | kw pub | ||
387 | kw unsafe | ||
388 | kw fn | 388 | kw fn |
389 | kw const | 389 | kw const |
390 | kw type | 390 | kw type |
391 | kw unsafe | 391 | "#]], |
392 | ); | ||
393 | } | ||
394 | |||
395 | #[test] | ||
396 | fn test_keywords_in_impl_def_with_attr() { | ||
397 | check( | ||
398 | r"impl My { #[foo] $0 }", | ||
399 | expect![[r#" | ||
392 | kw pub(crate) | 400 | kw pub(crate) |
393 | kw pub | 401 | kw pub |
402 | kw unsafe | ||
403 | kw fn | ||
404 | kw const | ||
405 | kw type | ||
394 | "#]], | 406 | "#]], |
395 | ); | 407 | ); |
396 | } | 408 | } |
@@ -400,10 +412,16 @@ fn quux() -> i32 { | |||
400 | check( | 412 | check( |
401 | r"fn my() { loop { $0 } }", | 413 | r"fn my() { loop { $0 } }", |
402 | expect![[r#" | 414 | expect![[r#" |
415 | kw unsafe | ||
403 | kw fn | 416 | kw fn |
417 | kw const | ||
418 | kw type | ||
404 | kw use | 419 | kw use |
405 | kw impl | 420 | kw impl |
406 | kw trait | 421 | kw trait |
422 | kw static | ||
423 | kw extern | ||
424 | kw mod | ||
407 | kw match | 425 | kw match |
408 | kw while | 426 | kw while |
409 | kw while let | 427 | kw while let |
@@ -412,12 +430,6 @@ fn quux() -> i32 { | |||
412 | kw if let | 430 | kw if let |
413 | kw for | 431 | kw for |
414 | kw let | 432 | kw let |
415 | kw mod | ||
416 | kw const | ||
417 | kw type | ||
418 | kw static | ||
419 | kw extern | ||
420 | kw unsafe | ||
421 | kw continue | 433 | kw continue |
422 | kw break | 434 | kw break |
423 | kw return | 435 | kw return |
@@ -564,6 +576,7 @@ pub mod future { | |||
564 | check( | 576 | check( |
565 | r#"fn main() { let _ = $0 }"#, | 577 | r#"fn main() { let _ = $0 }"#, |
566 | expect![[r#" | 578 | expect![[r#" |
579 | kw unsafe | ||
567 | kw match | 580 | kw match |
568 | kw while | 581 | kw while |
569 | kw while let | 582 | kw while let |
@@ -624,6 +637,7 @@ fn foo() { | |||
624 | } | 637 | } |
625 | "#, | 638 | "#, |
626 | expect![[r#" | 639 | expect![[r#" |
640 | kw unsafe | ||
627 | kw match | 641 | kw match |
628 | kw while | 642 | kw while |
629 | kw while let | 643 | kw while let |