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