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