aboutsummaryrefslogtreecommitdiff
path: root/crates/completion/src/completions/keyword.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/completion/src/completions/keyword.rs')
-rw-r--r--crates/completion/src/completions/keyword.rs660
1 files changed, 0 insertions, 660 deletions
diff --git a/crates/completion/src/completions/keyword.rs b/crates/completion/src/completions/keyword.rs
deleted file mode 100644
index 47e146128..000000000
--- a/crates/completion/src/completions/keyword.rs
+++ /dev/null
@@ -1,660 +0,0 @@
1//! Completes keywords.
2
3use syntax::SyntaxKind;
4use test_utils::mark;
5
6use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
7
8pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) {
9 // complete keyword "crate" in use stmt
10 let source_range = ctx.source_range();
11
12 if ctx.use_item_syntax.is_some() {
13 if ctx.path_qual.is_none() {
14 CompletionItem::new(CompletionKind::Keyword, source_range, "crate::")
15 .kind(CompletionItemKind::Keyword)
16 .insert_text("crate::")
17 .add_to(acc);
18 }
19 CompletionItem::new(CompletionKind::Keyword, source_range, "self")
20 .kind(CompletionItemKind::Keyword)
21 .add_to(acc);
22 CompletionItem::new(CompletionKind::Keyword, source_range, "super::")
23 .kind(CompletionItemKind::Keyword)
24 .insert_text("super::")
25 .add_to(acc);
26 }
27
28 // Suggest .await syntax for types that implement Future trait
29 if let Some(receiver) = &ctx.dot_receiver {
30 if let Some(ty) = ctx.sema.type_of_expr(receiver) {
31 if ty.impls_future(ctx.db) {
32 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await")
33 .kind(CompletionItemKind::Keyword)
34 .detail("expr.await")
35 .insert_text("await")
36 .add_to(acc);
37 }
38 };
39 }
40}
41
42pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) {
43 if ctx.token.kind() == SyntaxKind::COMMENT {
44 mark::hit!(no_keyword_completion_in_comments);
45 return;
46 }
47 if ctx.record_lit_syntax.is_some() {
48 mark::hit!(no_keyword_completion_in_record_lit);
49 return;
50 }
51
52 let has_trait_or_impl_parent = ctx.has_impl_parent || ctx.has_trait_parent;
53 if ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling {
54 add_keyword(ctx, acc, "where", "where ");
55 return;
56 }
57 if ctx.unsafe_is_prev {
58 if ctx.has_item_list_or_source_file_parent || ctx.block_expr_parent {
59 add_keyword(ctx, acc, "fn", "fn $0() {}")
60 }
61
62 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
63 add_keyword(ctx, acc, "trait", "trait $0 {}");
64 add_keyword(ctx, acc, "impl", "impl $0 {}");
65 }
66
67 return;
68 }
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
79 if ctx.has_item_list_or_source_file_parent {
80 add_keyword(ctx, acc, "enum", "enum $0 {}");
81 add_keyword(ctx, acc, "struct", "struct $0");
82 add_keyword(ctx, acc, "union", "union $0 {}");
83 }
84
85 if ctx.is_expr {
86 add_keyword(ctx, acc, "match", "match $0 {}");
87 add_keyword(ctx, acc, "while", "while $0 {}");
88 add_keyword(ctx, acc, "loop", "loop {$0}");
89 add_keyword(ctx, acc, "if", "if $0 {}");
90 add_keyword(ctx, acc, "if let", "if let $1 = $0 {}");
91 }
92
93 if ctx.if_is_prev || ctx.block_expr_parent {
94 add_keyword(ctx, acc, "let", "let ");
95 }
96
97 if ctx.after_if {
98 add_keyword(ctx, acc, "else", "else {$0}");
99 add_keyword(ctx, acc, "else if", "else if $0 {}");
100 }
101 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
102 add_keyword(ctx, acc, "mod", "mod $0");
103 }
104 if ctx.bind_pat_parent || ctx.ref_pat_parent {
105 add_keyword(ctx, acc, "mut", "mut ");
106 }
107 if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent
108 {
109 add_keyword(ctx, acc, "const", "const ");
110 add_keyword(ctx, acc, "type", "type ");
111 }
112 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
113 add_keyword(ctx, acc, "static", "static ");
114 };
115 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
116 add_keyword(ctx, acc, "extern", "extern ");
117 }
118 if ctx.has_item_list_or_source_file_parent
119 || has_trait_or_impl_parent
120 || ctx.block_expr_parent
121 || ctx.is_match_arm
122 {
123 add_keyword(ctx, acc, "unsafe", "unsafe ");
124 }
125 if ctx.in_loop_body {
126 if ctx.can_be_stmt {
127 add_keyword(ctx, acc, "continue", "continue;");
128 add_keyword(ctx, acc, "break", "break;");
129 } else {
130 add_keyword(ctx, acc, "continue", "continue");
131 add_keyword(ctx, acc, "break", "break");
132 }
133 }
134 if ctx.has_item_list_or_source_file_parent || ctx.has_impl_parent | ctx.has_field_list_parent {
135 add_keyword(ctx, acc, "pub(crate)", "pub(crate) ");
136 add_keyword(ctx, acc, "pub", "pub ");
137 }
138
139 if !ctx.is_trivial_path {
140 return;
141 }
142 let fn_def = match &ctx.function_syntax {
143 Some(it) => it,
144 None => return,
145 };
146
147 add_keyword(
148 ctx,
149 acc,
150 "return",
151 match (ctx.can_be_stmt, fn_def.ret_type().is_some()) {
152 (true, true) => "return $0;",
153 (true, false) => "return;",
154 (false, true) => "return $0",
155 (false, false) => "return",
156 },
157 )
158}
159
160fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
161 let builder = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
162 .kind(CompletionItemKind::Keyword);
163 let builder = match ctx.config.snippet_cap {
164 Some(cap) => {
165 let tmp;
166 let snippet = if snippet.ends_with('}') && ctx.incomplete_let {
167 mark::hit!(let_semi);
168 tmp = format!("{};", snippet);
169 &tmp
170 } else {
171 snippet
172 };
173 builder.insert_snippet(cap, snippet)
174 }
175 None => builder.insert_text(if snippet.contains('$') { kw } else { snippet }),
176 };
177 acc.add(builder.build());
178}
179
180#[cfg(test)]
181mod tests {
182 use expect_test::{expect, Expect};
183 use test_utils::mark;
184
185 use crate::{
186 test_utils::{check_edit, completion_list},
187 CompletionKind,
188 };
189
190 fn check(ra_fixture: &str, expect: Expect) {
191 let actual = completion_list(ra_fixture, CompletionKind::Keyword);
192 expect.assert_eq(&actual)
193 }
194
195 #[test]
196 fn test_keywords_in_use_stmt() {
197 check(
198 r"use $0",
199 expect![[r#"
200 kw crate::
201 kw self
202 kw super::
203 "#]],
204 );
205
206 check(
207 r"use a::$0",
208 expect![[r#"
209 kw self
210 kw super::
211 "#]],
212 );
213
214 check(
215 r"use a::{b, $0}",
216 expect![[r#"
217 kw self
218 kw super::
219 "#]],
220 );
221 }
222
223 #[test]
224 fn test_keywords_at_source_file_level() {
225 check(
226 r"m$0",
227 expect![[r#"
228 kw fn
229 kw use
230 kw impl
231 kw trait
232 kw enum
233 kw struct
234 kw union
235 kw mod
236 kw const
237 kw type
238 kw static
239 kw extern
240 kw unsafe
241 kw pub(crate)
242 kw pub
243 "#]],
244 );
245 }
246
247 #[test]
248 fn test_keywords_in_function() {
249 check(
250 r"fn quux() { $0 }",
251 expect![[r#"
252 kw fn
253 kw use
254 kw impl
255 kw trait
256 kw match
257 kw while
258 kw loop
259 kw if
260 kw if let
261 kw let
262 kw mod
263 kw const
264 kw type
265 kw static
266 kw extern
267 kw unsafe
268 kw return
269 "#]],
270 );
271 }
272
273 #[test]
274 fn test_keywords_inside_block() {
275 check(
276 r"fn quux() { if true { $0 } }",
277 expect![[r#"
278 kw fn
279 kw use
280 kw impl
281 kw trait
282 kw match
283 kw while
284 kw loop
285 kw if
286 kw if let
287 kw let
288 kw mod
289 kw const
290 kw type
291 kw static
292 kw extern
293 kw unsafe
294 kw return
295 "#]],
296 );
297 }
298
299 #[test]
300 fn test_keywords_after_if() {
301 check(
302 r#"fn quux() { if true { () } $0 }"#,
303 expect![[r#"
304 kw fn
305 kw use
306 kw impl
307 kw trait
308 kw match
309 kw while
310 kw loop
311 kw if
312 kw if let
313 kw let
314 kw else
315 kw else if
316 kw mod
317 kw const
318 kw type
319 kw static
320 kw extern
321 kw unsafe
322 kw return
323 "#]],
324 );
325 check_edit(
326 "else",
327 r#"fn quux() { if true { () } $0 }"#,
328 r#"fn quux() { if true { () } else {$0} }"#,
329 );
330 }
331
332 #[test]
333 fn test_keywords_in_match_arm() {
334 check(
335 r#"
336fn quux() -> i32 {
337 match () { () => $0 }
338}
339"#,
340 expect![[r#"
341 kw match
342 kw while
343 kw loop
344 kw if
345 kw if let
346 kw unsafe
347 kw return
348 "#]],
349 );
350 }
351
352 #[test]
353 fn test_keywords_in_trait_def() {
354 check(
355 r"trait My { $0 }",
356 expect![[r#"
357 kw fn
358 kw const
359 kw type
360 kw unsafe
361 "#]],
362 );
363 }
364
365 #[test]
366 fn test_keywords_in_impl_def() {
367 check(
368 r"impl My { $0 }",
369 expect![[r#"
370 kw fn
371 kw const
372 kw type
373 kw unsafe
374 kw pub(crate)
375 kw pub
376 "#]],
377 );
378 }
379
380 #[test]
381 fn test_keywords_in_loop() {
382 check(
383 r"fn my() { loop { $0 } }",
384 expect![[r#"
385 kw fn
386 kw use
387 kw impl
388 kw trait
389 kw match
390 kw while
391 kw loop
392 kw if
393 kw if let
394 kw let
395 kw mod
396 kw const
397 kw type
398 kw static
399 kw extern
400 kw unsafe
401 kw continue
402 kw break
403 kw return
404 "#]],
405 );
406 }
407
408 #[test]
409 fn test_keywords_after_unsafe_in_item_list() {
410 check(
411 r"unsafe $0",
412 expect![[r#"
413 kw fn
414 kw trait
415 kw impl
416 "#]],
417 );
418 }
419
420 #[test]
421 fn test_keywords_after_unsafe_in_block_expr() {
422 check(
423 r"fn my_fn() { unsafe $0 }",
424 expect![[r#"
425 kw fn
426 kw trait
427 kw impl
428 "#]],
429 );
430 }
431
432 #[test]
433 fn test_mut_in_ref_and_in_fn_parameters_list() {
434 check(
435 r"fn my_fn(&$0) {}",
436 expect![[r#"
437 kw mut
438 "#]],
439 );
440 check(
441 r"fn my_fn($0) {}",
442 expect![[r#"
443 kw mut
444 "#]],
445 );
446 check(
447 r"fn my_fn() { let &$0 }",
448 expect![[r#"
449 kw mut
450 "#]],
451 );
452 }
453
454 #[test]
455 fn test_where_keyword() {
456 check(
457 r"trait A $0",
458 expect![[r#"
459 kw where
460 "#]],
461 );
462 check(
463 r"impl A $0",
464 expect![[r#"
465 kw where
466 "#]],
467 );
468 }
469
470 #[test]
471 fn no_keyword_completion_in_comments() {
472 mark::check!(no_keyword_completion_in_comments);
473 check(
474 r#"
475fn test() {
476 let x = 2; // A comment$0
477}
478"#,
479 expect![[""]],
480 );
481 check(
482 r#"
483/*
484Some multi-line comment$0
485*/
486"#,
487 expect![[""]],
488 );
489 check(
490 r#"
491/// Some doc comment
492/// let test$0 = 1
493"#,
494 expect![[""]],
495 );
496 }
497
498 #[test]
499 fn test_completion_await_impls_future() {
500 check(
501 r#"
502//- /main.rs crate:main deps:std
503use std::future::*;
504struct A {}
505impl Future for A {}
506fn foo(a: A) { a.$0 }
507
508//- /std/lib.rs crate:std
509pub mod future {
510 #[lang = "future_trait"]
511 pub trait Future {}
512}
513"#,
514 expect![[r#"
515 kw await expr.await
516 "#]],
517 );
518
519 check(
520 r#"
521//- /main.rs crate:main deps:std
522use std::future::*;
523fn foo() {
524 let a = async {};
525 a.$0
526}
527
528//- /std/lib.rs crate:std
529pub mod future {
530 #[lang = "future_trait"]
531 pub trait Future {
532 type Output;
533 }
534}
535"#,
536 expect![[r#"
537 kw await expr.await
538 "#]],
539 )
540 }
541
542 #[test]
543 fn after_let() {
544 check(
545 r#"fn main() { let _ = $0 }"#,
546 expect![[r#"
547 kw match
548 kw while
549 kw loop
550 kw if
551 kw if let
552 kw return
553 "#]],
554 )
555 }
556
557 #[test]
558 fn before_field() {
559 check(
560 r#"
561struct Foo {
562 $0
563 pub f: i32,
564}
565"#,
566 expect![[r#"
567 kw pub(crate)
568 kw pub
569 "#]],
570 )
571 }
572
573 #[test]
574 fn skip_struct_initializer() {
575 mark::check!(no_keyword_completion_in_record_lit);
576 check(
577 r#"
578struct Foo {
579 pub f: i32,
580}
581fn foo() {
582 Foo {
583 $0
584 }
585}
586"#,
587 expect![[r#""#]],
588 );
589 }
590
591 #[test]
592 fn struct_initializer_field_expr() {
593 check(
594 r#"
595struct Foo {
596 pub f: i32,
597}
598fn foo() {
599 Foo {
600 f: $0
601 }
602}
603"#,
604 expect![[r#"
605 kw match
606 kw while
607 kw loop
608 kw if
609 kw if let
610 kw return
611 "#]],
612 );
613 }
614
615 #[test]
616 fn let_semi() {
617 mark::check!(let_semi);
618 check_edit(
619 "match",
620 r#"
621fn main() { let x = $0 }
622"#,
623 r#"
624fn main() { let x = match $0 {}; }
625"#,
626 );
627
628 check_edit(
629 "if",
630 r#"
631fn main() {
632 let x = $0
633 let y = 92;
634}
635"#,
636 r#"
637fn main() {
638 let x = if $0 {};
639 let y = 92;
640}
641"#,
642 );
643
644 check_edit(
645 "loop",
646 r#"
647fn main() {
648 let x = $0
649 bar();
650}
651"#,
652 r#"
653fn main() {
654 let x = loop {$0};
655 bar();
656}
657"#,
658 );
659 }
660}