aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/completions/keyword.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion/src/completions/keyword.rs')
-rw-r--r--crates/ide_completion/src/completions/keyword.rs239
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
3use std::iter; 3use std::iter;
4 4
5use syntax::SyntaxKind; 5use syntax::{SyntaxKind, T};
6 6
7use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions}; 7use 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() {
646fn main() { let x = $0 } 655fn main() { let x = $0 }
647"#, 656"#,
648 r#" 657 r#"
649fn main() { let x = match $0 {}; } 658fn 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#"
662fn main() { 673fn 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#"
678fn main() { 691fn main() {
679 let x = loop {$0}; 692 let x = loop {
693 $0
694};
680 bar(); 695 bar();
681} 696}
682"#, 697"#,