aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/completion')
-rw-r--r--crates/ra_ide/src/completion/complete_postfix.rs635
1 files changed, 123 insertions, 512 deletions
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs
index 3bd64804f..14013dc2f 100644
--- a/crates/ra_ide/src/completion/complete_postfix.rs
+++ b/crates/ra_ide/src/completion/complete_postfix.rs
@@ -8,14 +8,13 @@ use ra_text_edit::TextEdit;
8 8
9use crate::{ 9use crate::{
10 completion::{ 10 completion::{
11 completion_config::SnippetCap,
11 completion_context::CompletionContext, 12 completion_context::CompletionContext,
12 completion_item::{Builder, CompletionKind, Completions}, 13 completion_item::{Builder, CompletionKind, Completions},
13 }, 14 },
14 CompletionItem, 15 CompletionItem, CompletionItemKind,
15}; 16};
16 17
17use super::completion_config::SnippetCap;
18
19pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { 18pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
20 if !ctx.config.enable_postfix_completions { 19 if !ctx.config.enable_postfix_completions {
21 return; 20 return;
@@ -103,10 +102,9 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
103 &format!("while {} {{\n $0\n}}", receiver_text), 102 &format!("while {} {{\n $0\n}}", receiver_text),
104 ) 103 )
105 .add_to(acc); 104 .add_to(acc);
105 postfix_snippet(ctx, cap, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text))
106 .add_to(acc);
106 } 107 }
107 // !&&&42 is a compiler error, ergo process it before considering the references
108 postfix_snippet(ctx, cap, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text))
109 .add_to(acc);
110 108
111 postfix_snippet(ctx, cap, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text)) 109 postfix_snippet(ctx, cap, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text))
112 .add_to(acc); 110 .add_to(acc);
@@ -125,33 +123,35 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
125 let dot_receiver = include_references(dot_receiver); 123 let dot_receiver = include_references(dot_receiver);
126 let receiver_text = 124 let receiver_text =
127 get_receiver_text(&dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal); 125 get_receiver_text(&dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal);
126
128 match try_enum { 127 match try_enum {
129 Some(try_enum) => { 128 Some(try_enum) => match try_enum {
130 match try_enum { 129 TryEnum::Result => {
131 TryEnum::Result => { 130 postfix_snippet(
132 postfix_snippet(
133 ctx, 131 ctx,
134 cap, 132 cap,
135 &dot_receiver, 133 &dot_receiver,
136 "match", 134 "match",
137 "match expr {}", 135 "match expr {}",
138 &format!("match {} {{\n Ok(${{1:_}}) => {{$2\\}},\n Err(${{3:_}}) => {{$0\\}},\n}}", receiver_text), 136 &format!("match {} {{\n Ok(${{1:_}}) => {{$2}},\n Err(${{3:_}}) => {{$0}},\n}}", receiver_text),
139 ) 137 )
140 .add_to(acc); 138 .add_to(acc);
141 } 139 }
142 TryEnum::Option => { 140 TryEnum::Option => {
143 postfix_snippet( 141 postfix_snippet(
144 ctx, 142 ctx,
145 cap, 143 cap,
146 &dot_receiver, 144 &dot_receiver,
147 "match", 145 "match",
148 "match expr {}", 146 "match expr {}",
149 &format!("match {} {{\n Some(${{1:_}}) => {{$2\\}},\n None => {{$0\\}},\n}}", receiver_text), 147 &format!(
148 "match {} {{\n Some(${{1:_}}) => {{$2}},\n None => {{$0}},\n}}",
149 receiver_text
150 ),
150 ) 151 )
151 .add_to(acc); 152 .add_to(acc);
152 }
153 } 153 }
154 } 154 },
155 None => { 155 None => {
156 postfix_snippet( 156 postfix_snippet(
157 ctx, 157 ctx,
@@ -159,7 +159,7 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
159 &dot_receiver, 159 &dot_receiver,
160 "match", 160 "match",
161 "match expr {}", 161 "match expr {}",
162 &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text), 162 &format!("match {} {{\n ${{1:_}} => {{$0}},\n}}", receiver_text),
163 ) 163 )
164 .add_to(acc); 164 .add_to(acc);
165 } 165 }
@@ -232,536 +232,147 @@ fn postfix_snippet(
232 }; 232 };
233 CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label) 233 CompletionItem::new(CompletionKind::Postfix, ctx.source_range(), label)
234 .detail(detail) 234 .detail(detail)
235 .kind(CompletionItemKind::Snippet)
235 .snippet_edit(cap, edit) 236 .snippet_edit(cap, edit)
236} 237}
237 238
238#[cfg(test)] 239#[cfg(test)]
239mod tests { 240mod tests {
240 use insta::assert_debug_snapshot; 241 use expect::{expect, Expect};
241 242
242 use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; 243 use crate::completion::{
244 test_utils::{check_edit, completion_list},
245 CompletionKind,
246 };
243 247
244 fn do_postfix_completion(code: &str) -> Vec<CompletionItem> { 248 fn check(ra_fixture: &str, expect: Expect) {
245 do_completion(code, CompletionKind::Postfix) 249 let actual = completion_list(ra_fixture, CompletionKind::Postfix);
250 expect.assert_eq(&actual)
246 } 251 }
247 252
248 #[test] 253 #[test]
249 fn postfix_completion_works_for_trivial_path_expression() { 254 fn postfix_completion_works_for_trivial_path_expression() {
250 assert_debug_snapshot!( 255 check(
251 do_postfix_completion( 256 r#"
252 r#" 257fn main() {
253 fn main() { 258 let bar = true;
254 let bar = true; 259 bar.<|>
255 bar.<|> 260}
256 } 261"#,
257 "#, 262 expect![[r#"
258 ), 263 sn box Box::new(expr)
259 @r###" 264 sn call function(expr)
260 [ 265 sn dbg dbg!(expr)
261 CompletionItem { 266 sn if if expr {}
262 label: "box", 267 sn match match expr {}
263 source_range: 40..40, 268 sn not !expr
264 delete: 36..40, 269 sn ref &expr
265 insert: "Box::new(bar)", 270 sn refm &mut expr
266 detail: "Box::new(expr)", 271 sn while while expr {}
267 }, 272 "#]],
268 CompletionItem {
269 label: "call",
270 source_range: 40..40,
271 delete: 36..40,
272 insert: "${1}(bar)",
273 detail: "function(expr)",
274 },
275 CompletionItem {
276 label: "dbg",
277 source_range: 40..40,
278 delete: 36..40,
279 insert: "dbg!(bar)",
280 detail: "dbg!(expr)",
281 },
282 CompletionItem {
283 label: "if",
284 source_range: 40..40,
285 delete: 36..40,
286 insert: "if bar {\n $0\n}",
287 detail: "if expr {}",
288 },
289 CompletionItem {
290 label: "match",
291 source_range: 40..40,
292 delete: 36..40,
293 insert: "match bar {\n ${1:_} => {$0\\},\n}",
294 detail: "match expr {}",
295 },
296 CompletionItem {
297 label: "not",
298 source_range: 40..40,
299 delete: 36..40,
300 insert: "!bar",
301 detail: "!expr",
302 },
303 CompletionItem {
304 label: "ref",
305 source_range: 40..40,
306 delete: 36..40,
307 insert: "&bar",
308 detail: "&expr",
309 },
310 CompletionItem {
311 label: "refm",
312 source_range: 40..40,
313 delete: 36..40,
314 insert: "&mut bar",
315 detail: "&mut expr",
316 },
317 CompletionItem {
318 label: "while",
319 source_range: 40..40,
320 delete: 36..40,
321 insert: "while bar {\n $0\n}",
322 detail: "while expr {}",
323 },
324 ]
325 "###
326 ); 273 );
327 } 274 }
328 275
329 #[test] 276 #[test]
330 fn postfix_completion_works_for_option() { 277 fn postfix_type_filtering() {
331 assert_debug_snapshot!( 278 check(
332 do_postfix_completion( 279 r#"
333 r#" 280fn main() {
334 enum Option<T> { 281 let bar: u8 = 12;
335 Some(T), 282 bar.<|>
336 None, 283}
337 } 284"#,
338 285 expect![[r#"
339 fn main() { 286 sn box Box::new(expr)
340 let bar = Option::Some(true); 287 sn call function(expr)
341 bar.<|> 288 sn dbg dbg!(expr)
342 } 289 sn match match expr {}
343 "#, 290 sn ref &expr
344 ), 291 sn refm &mut expr
345 @r###" 292 "#]],
346 [ 293 )
347 CompletionItem {
348 label: "box",
349 source_range: 97..97,
350 delete: 93..97,
351 insert: "Box::new(bar)",
352 detail: "Box::new(expr)",
353 },
354 CompletionItem {
355 label: "call",
356 source_range: 97..97,
357 delete: 93..97,
358 insert: "${1}(bar)",
359 detail: "function(expr)",
360 },
361 CompletionItem {
362 label: "dbg",
363 source_range: 97..97,
364 delete: 93..97,
365 insert: "dbg!(bar)",
366 detail: "dbg!(expr)",
367 },
368 CompletionItem {
369 label: "ifl",
370 source_range: 97..97,
371 delete: 93..97,
372 insert: "if let Some($1) = bar {\n $0\n}",
373 detail: "if let Some {}",
374 },
375 CompletionItem {
376 label: "match",
377 source_range: 97..97,
378 delete: 93..97,
379 insert: "match bar {\n Some(${1:_}) => {$2\\},\n None => {$0\\},\n}",
380 detail: "match expr {}",
381 },
382 CompletionItem {
383 label: "not",
384 source_range: 97..97,
385 delete: 93..97,
386 insert: "!bar",
387 detail: "!expr",
388 },
389 CompletionItem {
390 label: "ref",
391 source_range: 97..97,
392 delete: 93..97,
393 insert: "&bar",
394 detail: "&expr",
395 },
396 CompletionItem {
397 label: "refm",
398 source_range: 97..97,
399 delete: 93..97,
400 insert: "&mut bar",
401 detail: "&mut expr",
402 },
403 CompletionItem {
404 label: "while",
405 source_range: 97..97,
406 delete: 93..97,
407 insert: "while let Some($1) = bar {\n $0\n}",
408 detail: "while let Some {}",
409 },
410 ]
411 "###
412 );
413 } 294 }
414 295
415 #[test] 296 #[test]
416 fn postfix_completion_works_for_result() { 297 fn option_iflet() {
417 assert_debug_snapshot!( 298 check_edit(
418 do_postfix_completion( 299 "ifl",
419 r#" 300 r#"
420 enum Result<T, E> { 301enum Option<T> { Some(T), None }
421 Ok(T), 302
422 Err(E), 303fn main() {
423 } 304 let bar = Option::Some(true);
305 bar.<|>
306}
307"#,
308 r#"
309enum Option<T> { Some(T), None }
424 310
425 fn main() { 311fn main() {
426 let bar = Result::Ok(true); 312 let bar = Option::Some(true);
427 bar.<|> 313 if let Some($1) = bar {
428 } 314 $0
429 "#, 315}
430 ), 316}
431 @r###" 317"#,
432 [
433 CompletionItem {
434 label: "box",
435 source_range: 98..98,
436 delete: 94..98,
437 insert: "Box::new(bar)",
438 detail: "Box::new(expr)",
439 },
440 CompletionItem {
441 label: "call",
442 source_range: 98..98,
443 delete: 94..98,
444 insert: "${1}(bar)",
445 detail: "function(expr)",
446 },
447 CompletionItem {
448 label: "dbg",
449 source_range: 98..98,
450 delete: 94..98,
451 insert: "dbg!(bar)",
452 detail: "dbg!(expr)",
453 },
454 CompletionItem {
455 label: "ifl",
456 source_range: 98..98,
457 delete: 94..98,
458 insert: "if let Ok($1) = bar {\n $0\n}",
459 detail: "if let Ok {}",
460 },
461 CompletionItem {
462 label: "match",
463 source_range: 98..98,
464 delete: 94..98,
465 insert: "match bar {\n Ok(${1:_}) => {$2\\},\n Err(${3:_}) => {$0\\},\n}",
466 detail: "match expr {}",
467 },
468 CompletionItem {
469 label: "not",
470 source_range: 98..98,
471 delete: 94..98,
472 insert: "!bar",
473 detail: "!expr",
474 },
475 CompletionItem {
476 label: "ref",
477 source_range: 98..98,
478 delete: 94..98,
479 insert: "&bar",
480 detail: "&expr",
481 },
482 CompletionItem {
483 label: "refm",
484 source_range: 98..98,
485 delete: 94..98,
486 insert: "&mut bar",
487 detail: "&mut expr",
488 },
489 CompletionItem {
490 label: "while",
491 source_range: 98..98,
492 delete: 94..98,
493 insert: "while let Ok($1) = bar {\n $0\n}",
494 detail: "while let Ok {}",
495 },
496 ]
497 "###
498 ); 318 );
499 } 319 }
500 320
501 #[test] 321 #[test]
502 fn some_postfix_completions_ignored() { 322 fn result_match() {
503 assert_debug_snapshot!( 323 check_edit(
504 do_postfix_completion( 324 "match",
505 r#" 325 r#"
506 fn main() { 326enum Result<T, E> { Ok(T), Err(E) }
507 let bar: u8 = 12; 327
508 bar.<|> 328fn main() {
509 } 329 let bar = Result::Ok(true);
510 "#, 330 bar.<|>
511 ), 331}
512 @r###" 332"#,
513 [ 333 r#"
514 CompletionItem { 334enum Result<T, E> { Ok(T), Err(E) }
515 label: "box", 335
516 source_range: 42..42, 336fn main() {
517 delete: 38..42, 337 let bar = Result::Ok(true);
518 insert: "Box::new(bar)", 338 match bar {
519 detail: "Box::new(expr)", 339 Ok(${1:_}) => {$2},
520 }, 340 Err(${3:_}) => {$0},
521 CompletionItem { 341}
522 label: "call", 342}
523 source_range: 42..42, 343"#,
524 delete: 38..42,
525 insert: "${1}(bar)",
526 detail: "function(expr)",
527 },
528 CompletionItem {
529 label: "dbg",
530 source_range: 42..42,
531 delete: 38..42,
532 insert: "dbg!(bar)",
533 detail: "dbg!(expr)",
534 },
535 CompletionItem {
536 label: "match",
537 source_range: 42..42,
538 delete: 38..42,
539 insert: "match bar {\n ${1:_} => {$0\\},\n}",
540 detail: "match expr {}",
541 },
542 CompletionItem {
543 label: "not",
544 source_range: 42..42,
545 delete: 38..42,
546 insert: "!bar",
547 detail: "!expr",
548 },
549 CompletionItem {
550 label: "ref",
551 source_range: 42..42,
552 delete: 38..42,
553 insert: "&bar",
554 detail: "&expr",
555 },
556 CompletionItem {
557 label: "refm",
558 source_range: 42..42,
559 delete: 38..42,
560 insert: "&mut bar",
561 detail: "&mut expr",
562 },
563 ]
564 "###
565 ); 344 );
566 } 345 }
567 346
568 #[test] 347 #[test]
569 fn postfix_completion_works_for_ambiguous_float_literal() { 348 fn postfix_completion_works_for_ambiguous_float_literal() {
570 assert_debug_snapshot!( 349 check_edit("refm", r#"fn main() { 42.<|> }"#, r#"fn main() { &mut 42 }"#)
571 do_postfix_completion(
572 r#"
573 fn main() {
574 42.<|>
575 }
576 "#,
577 ),
578 @r###"
579 [
580 CompletionItem {
581 label: "box",
582 source_range: 19..19,
583 delete: 16..19,
584 insert: "Box::new(42)",
585 detail: "Box::new(expr)",
586 },
587 CompletionItem {
588 label: "call",
589 source_range: 19..19,
590 delete: 16..19,
591 insert: "${1}(42)",
592 detail: "function(expr)",
593 },
594 CompletionItem {
595 label: "dbg",
596 source_range: 19..19,
597 delete: 16..19,
598 insert: "dbg!(42)",
599 detail: "dbg!(expr)",
600 },
601 CompletionItem {
602 label: "match",
603 source_range: 19..19,
604 delete: 16..19,
605 insert: "match 42 {\n ${1:_} => {$0\\},\n}",
606 detail: "match expr {}",
607 },
608 CompletionItem {
609 label: "not",
610 source_range: 19..19,
611 delete: 16..19,
612 insert: "!42",
613 detail: "!expr",
614 },
615 CompletionItem {
616 label: "ref",
617 source_range: 19..19,
618 delete: 16..19,
619 insert: "&42",
620 detail: "&expr",
621 },
622 CompletionItem {
623 label: "refm",
624 source_range: 19..19,
625 delete: 16..19,
626 insert: "&mut 42",
627 detail: "&mut expr",
628 },
629 ]
630 "###
631 );
632 } 350 }
633 351
634 #[test] 352 #[test]
635 fn works_in_simple_macro() { 353 fn works_in_simple_macro() {
636 assert_debug_snapshot!( 354 check_edit(
637 do_postfix_completion( 355 "dbg",
638 r#" 356 r#"
639 macro_rules! m { ($e:expr) => { $e } } 357macro_rules! m { ($e:expr) => { $e } }
640 fn main() { 358fn main() {
641 let bar: u8 = 12; 359 let bar: u8 = 12;
642 m!(bar.b<|>) 360 m!(bar.d<|>)
643 } 361}
644 "#, 362"#,
645 ), 363 r#"
646 @r###" 364macro_rules! m { ($e:expr) => { $e } }
647 [ 365fn main() {
648 CompletionItem { 366 let bar: u8 = 12;
649 label: "box", 367 m!(dbg!(bar))
650 source_range: 84..85, 368}
651 delete: 80..85, 369"#,
652 insert: "Box::new(bar)",
653 detail: "Box::new(expr)",
654 },
655 CompletionItem {
656 label: "call",
657 source_range: 84..85,
658 delete: 80..85,
659 insert: "${1}(bar)",
660 detail: "function(expr)",
661 },
662 CompletionItem {
663 label: "dbg",
664 source_range: 84..85,
665 delete: 80..85,
666 insert: "dbg!(bar)",
667 detail: "dbg!(expr)",
668 },
669 CompletionItem {
670 label: "match",
671 source_range: 84..85,
672 delete: 80..85,
673 insert: "match bar {\n ${1:_} => {$0\\},\n}",
674 detail: "match expr {}",
675 },
676 CompletionItem {
677 label: "not",
678 source_range: 84..85,
679 delete: 80..85,
680 insert: "!bar",
681 detail: "!expr",
682 },
683 CompletionItem {
684 label: "ref",
685 source_range: 84..85,
686 delete: 80..85,
687 insert: "&bar",
688 detail: "&expr",
689 },
690 CompletionItem {
691 label: "refm",
692 source_range: 84..85,
693 delete: 80..85,
694 insert: "&mut bar",
695 detail: "&mut expr",
696 },
697 ]
698 "###
699 ); 370 );
700 } 371 }
701 372
702 #[test] 373 #[test]
703 fn postfix_completion_for_references() { 374 fn postfix_completion_for_references() {
704 assert_debug_snapshot!( 375 check_edit("dbg", r#"fn main() { &&42.<|> }"#, r#"fn main() { dbg!(&&42) }"#);
705 do_postfix_completion( 376 check_edit("refm", r#"fn main() { &&42.<|> }"#, r#"fn main() { &&&mut 42 }"#);
706 r#"
707 fn main() {
708 &&&&42.<|>
709 }
710 "#,
711 ),
712 @r###"
713 [
714 CompletionItem {
715 label: "box",
716 source_range: 23..23,
717 delete: 16..23,
718 insert: "Box::new(&&&&42)",
719 detail: "Box::new(expr)",
720 },
721 CompletionItem {
722 label: "call",
723 source_range: 23..23,
724 delete: 16..23,
725 insert: "${1}(&&&&42)",
726 detail: "function(expr)",
727 },
728 CompletionItem {
729 label: "dbg",
730 source_range: 23..23,
731 delete: 16..23,
732 insert: "dbg!(&&&&42)",
733 detail: "dbg!(expr)",
734 },
735 CompletionItem {
736 label: "match",
737 source_range: 23..23,
738 delete: 16..23,
739 insert: "match &&&&42 {\n ${1:_} => {$0\\},\n}",
740 detail: "match expr {}",
741 },
742 CompletionItem {
743 label: "not",
744 source_range: 23..23,
745 delete: 20..23,
746 insert: "!42",
747 detail: "!expr",
748 },
749 CompletionItem {
750 label: "ref",
751 source_range: 23..23,
752 delete: 20..23,
753 insert: "&42",
754 detail: "&expr",
755 },
756 CompletionItem {
757 label: "refm",
758 source_range: 23..23,
759 delete: 20..23,
760 insert: "&mut 42",
761 detail: "&mut expr",
762 },
763 ]
764 "###
765 );
766 } 377 }
767} 378}