1 //! Completes keywords.
3 use syntax::{ast, SyntaxKind};
6 use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
8 pub(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();
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::")
19 CompletionItem::new(CompletionKind::Keyword, source_range, "self")
20 .kind(CompletionItemKind::Keyword)
22 CompletionItem::new(CompletionKind::Keyword, source_range, "super::")
23 .kind(CompletionItemKind::Keyword)
24 .insert_text("super::")
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)
42 pub(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);
47 if ctx.record_lit_syntax.is_some() {
48 mark::hit!(no_keyword_completion_in_record_lit);
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 ");
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() {}")
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 {}");
69 if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent
71 add_keyword(ctx, acc, "fn", "fn $0() {}");
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 {}");
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 {}");
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 {}");
93 if ctx.if_is_prev || ctx.block_expr_parent {
94 add_keyword(ctx, acc, "let", "let ");
98 add_keyword(ctx, acc, "else", "else {$0}");
99 add_keyword(ctx, acc, "else if", "else if $0 {}");
101 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
102 add_keyword(ctx, acc, "mod", "mod $0 {}");
104 if ctx.bind_pat_parent || ctx.ref_pat_parent {
105 add_keyword(ctx, acc, "mut", "mut ");
107 if ctx.has_item_list_or_source_file_parent || has_trait_or_impl_parent || ctx.block_expr_parent
109 add_keyword(ctx, acc, "const", "const ");
110 add_keyword(ctx, acc, "type", "type ");
112 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
113 add_keyword(ctx, acc, "static", "static ");
115 if (ctx.has_item_list_or_source_file_parent) || ctx.block_expr_parent {
116 add_keyword(ctx, acc, "extern", "extern ");
118 if ctx.has_item_list_or_source_file_parent
119 || has_trait_or_impl_parent
120 || ctx.block_expr_parent
123 add_keyword(ctx, acc, "unsafe", "unsafe ");
125 if ctx.in_loop_body {
127 add_keyword(ctx, acc, "continue", "continue;");
128 add_keyword(ctx, acc, "break", "break;");
130 add_keyword(ctx, acc, "continue", "continue");
131 add_keyword(ctx, acc, "break", "break");
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 ");
139 if !ctx.is_trivial_path {
142 let fn_def = match &ctx.function_syntax {
146 acc.add_all(complete_return(ctx, &fn_def, ctx.can_be_stmt));
149 fn keyword(ctx: &CompletionContext, kw: &str, snippet: &str) -> CompletionItem {
150 let res = CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), kw)
151 .kind(CompletionItemKind::Keyword);
153 match ctx.config.snippet_cap {
154 Some(cap) => res.insert_snippet(cap, snippet),
155 _ => res.insert_text(if snippet.contains('$') { kw } else { snippet }),
160 fn add_keyword(ctx: &CompletionContext, acc: &mut Completions, kw: &str, snippet: &str) {
161 acc.add(keyword(ctx, kw, snippet));
165 ctx: &CompletionContext,
168 ) -> Option<CompletionItem> {
169 let snip = match (can_be_stmt, fn_def.ret_type().is_some()) {
170 (true, true) => "return $0;",
171 (true, false) => "return;",
172 (false, true) => "return $0",
173 (false, false) => "return",
175 Some(keyword(ctx, "return", snip))
180 use expect_test::{expect, Expect};
183 test_utils::{check_edit, completion_list},
186 use test_utils::mark;
188 fn check(ra_fixture: &str, expect: Expect) {
189 let actual = completion_list(ra_fixture, CompletionKind::Keyword);
190 expect.assert_eq(&actual)
194 fn test_keywords_in_use_stmt() {
222 fn test_keywords_at_source_file_level() {
246 fn test_keywords_in_function() {
272 fn test_keywords_inside_block() {
274 r"fn quux() { if true { $0 } }",
298 fn test_keywords_after_if() {
300 r#"fn quux() { if true { () } $0 }"#,
325 r#"fn quux() { if true { () } $0 }"#,
326 r#"fn quux() { if true { () } else {$0} }"#,
331 fn test_keywords_in_match_arm() {
335 match () { () => $0 }
351 fn test_keywords_in_trait_def() {
364 fn test_keywords_in_impl_def() {
379 fn test_keywords_in_loop() {
381 r"fn my() { loop { $0 } }",
407 fn test_keywords_after_unsafe_in_item_list() {
419 fn test_keywords_after_unsafe_in_block_expr() {
421 r"fn my_fn() { unsafe $0 }",
431 fn test_mut_in_ref_and_in_fn_parameters_list() {
445 r"fn my_fn() { let &$0 }",
453 fn test_where_keyword() {
469 fn no_keyword_completion_in_comments() {
470 mark::check!(no_keyword_completion_in_comments);
474 let x = 2; // A comment$0
482 Some multi-line comment$0
497 fn test_completion_await_impls_future() {
500 //- /main.rs crate:main deps:std
504 fn foo(a: A) { a.$0 }
506 //- /std/lib.rs crate:std
508 #[lang = "future_trait"]
519 //- /main.rs crate:main deps:std
526 //- /std/lib.rs crate:std
528 #[lang = "future_trait"]
543 r#"fn main() { let _ = $0 }"#,
572 fn skip_struct_initializer() {
573 mark::check!(no_keyword_completion_in_record_lit);
590 fn struct_initializer_field_expr() {