@@ -12,6 +12,7 @@ use ide_db::{
12
12
use stdx:: never;
13
13
use syntax:: {
14
14
ast:: { self , make, AstNode , AstToken } ,
15
+ format_smolstr,
15
16
SyntaxKind :: { BLOCK_EXPR , EXPR_STMT , FOR_EXPR , IF_EXPR , LOOP_EXPR , STMT_LIST , WHILE_EXPR } ,
16
17
TextRange , TextSize ,
17
18
} ;
@@ -55,10 +56,11 @@ pub(crate) fn complete_postfix(
55
56
None => return ,
56
57
} ;
57
58
58
- let postfix_snippet = match build_postfix_snippet_builder ( ctx, cap, dot_receiver) {
59
- Some ( it) => it,
60
- None => return ,
61
- } ;
59
+ let postfix_snippet =
60
+ match build_postfix_snippet_builder ( ctx, cap, dot_receiver, & receiver_text) {
61
+ Some ( it) => it,
62
+ None => return ,
63
+ } ;
62
64
63
65
if let Some ( drop_trait) = ctx. famous_defs ( ) . core_ops_Drop ( ) {
64
66
if receiver_ty. impls_trait ( ctx. db , drop_trait, & [ ] ) {
@@ -173,10 +175,11 @@ pub(crate) fn complete_postfix(
173
175
let ( dot_receiver, node_to_replace_with) = include_references ( dot_receiver) ;
174
176
let receiver_text =
175
177
get_receiver_text ( & node_to_replace_with, receiver_is_ambiguous_float_literal) ;
176
- let postfix_snippet = match build_postfix_snippet_builder ( ctx, cap, & dot_receiver) {
177
- Some ( it) => it,
178
- None => return ,
179
- } ;
178
+ let postfix_snippet =
179
+ match build_postfix_snippet_builder ( ctx, cap, & dot_receiver, & receiver_text) {
180
+ Some ( it) => it,
181
+ None => return ,
182
+ } ;
180
183
181
184
if !ctx. config . snippets . is_empty ( ) {
182
185
add_custom_postfix_completions ( acc, ctx, & postfix_snippet, & receiver_text) ;
@@ -317,6 +320,7 @@ fn build_postfix_snippet_builder<'ctx>(
317
320
ctx : & ' ctx CompletionContext < ' _ > ,
318
321
cap : SnippetCap ,
319
322
receiver : & ' ctx ast:: Expr ,
323
+ receiver_text : & ' ctx str ,
320
324
) -> Option < impl Fn ( & str , & str , & str ) -> Builder + ' ctx > {
321
325
let receiver_range = ctx. sema . original_range_opt ( receiver. syntax ( ) ) ?. range ;
322
326
if ctx. source_range ( ) . end ( ) < receiver_range. start ( ) {
@@ -332,13 +336,16 @@ fn build_postfix_snippet_builder<'ctx>(
332
336
fn build < ' ctx > (
333
337
ctx : & ' ctx CompletionContext < ' _ > ,
334
338
cap : SnippetCap ,
339
+ receiver_text : & ' ctx str ,
335
340
delete_range : TextRange ,
336
341
) -> impl Fn ( & str , & str , & str ) -> Builder + ' ctx {
337
342
move |label, detail, snippet| {
338
343
let edit = TextEdit :: replace ( delete_range, snippet. to_owned ( ) ) ;
339
- let mut item =
340
- CompletionItem :: new ( CompletionItemKind :: Snippet , ctx. source_range ( ) , label) ;
344
+ let mut item = CompletionItem :: new ( CompletionItemKind :: Snippet , delete_range, label) ;
341
345
item. detail ( detail) . snippet_edit ( cap, edit) ;
346
+ // Editors may filter completion item with the text within delete_range, so we need to
347
+ // include the receiver text in the lookup for editors to find the completion item.
348
+ item. lookup_by ( format_smolstr ! ( "{}.{}" , receiver_text, label) ) ;
342
349
let postfix_match = if ctx. original_token . text ( ) == label {
343
350
cov_mark:: hit!( postfix_exact_match_is_high_priority) ;
344
351
Some ( CompletionRelevancePostfixMatch :: Exact )
@@ -351,7 +358,7 @@ fn build_postfix_snippet_builder<'ctx>(
351
358
item
352
359
}
353
360
}
354
- Some ( build ( ctx, cap, delete_range) )
361
+ Some ( build ( ctx, cap, receiver_text , delete_range) )
355
362
}
356
363
357
364
fn add_custom_postfix_completions (
@@ -512,7 +519,7 @@ fn main() {
512
519
#[ test]
513
520
fn option_iflet ( ) {
514
521
check_edit (
515
- "ifl" ,
522
+ "bar. ifl" ,
516
523
r#"
517
524
//- minicore: option
518
525
fn main() {
@@ -534,7 +541,7 @@ fn main() {
534
541
#[ test]
535
542
fn option_letelse ( ) {
536
543
check_edit (
537
- "lete" ,
544
+ "bar. lete" ,
538
545
r#"
539
546
//- minicore: option
540
547
fn main() {
557
564
#[ test]
558
565
fn result_match ( ) {
559
566
check_edit (
560
- "match" ,
567
+ "bar. match" ,
561
568
r#"
562
569
//- minicore: result
563
570
fn main() {
@@ -579,13 +586,13 @@ fn main() {
579
586
580
587
#[ test]
581
588
fn postfix_completion_works_for_ambiguous_float_literal ( ) {
582
- check_edit ( "refm" , r#"fn main() { 42.$0 }"# , r#"fn main() { &mut 42 }"# )
589
+ check_edit ( "42. refm" , r#"fn main() { 42.$0 }"# , r#"fn main() { &mut 42 }"# )
583
590
}
584
591
585
592
#[ test]
586
593
fn works_in_simple_macro ( ) {
587
594
check_edit (
588
- "dbg" ,
595
+ "bar. dbg" ,
589
596
r#"
590
597
macro_rules! m { ($e:expr) => { $e } }
591
598
fn main() {
@@ -605,10 +612,10 @@ fn main() {
605
612
606
613
#[ test]
607
614
fn postfix_completion_for_references ( ) {
608
- check_edit ( "dbg" , r#"fn main() { &&42.$0 }"# , r#"fn main() { dbg!(&&42) }"# ) ;
609
- check_edit ( "refm" , r#"fn main() { &&42.$0 }"# , r#"fn main() { &&&mut 42 }"# ) ;
615
+ check_edit ( "&&42. dbg" , r#"fn main() { &&42.$0 }"# , r#"fn main() { dbg!(&&42) }"# ) ;
616
+ check_edit ( "42. refm" , r#"fn main() { &&42.$0 }"# , r#"fn main() { &&&mut 42 }"# ) ;
610
617
check_edit (
611
- "ifl" ,
618
+ "bar. ifl" ,
612
619
r#"
613
620
//- minicore: option
614
621
fn main() {
@@ -629,35 +636,39 @@ fn main() {
629
636
630
637
#[ test]
631
638
fn postfix_completion_for_unsafe ( ) {
632
- check_edit ( "unsafe" , r#"fn main() { foo.$0 }"# , r#"fn main() { unsafe { foo } }"# ) ;
633
- check_edit ( "unsafe" , r#"fn main() { { foo }.$0 }"# , r#"fn main() { unsafe { foo } }"# ) ;
639
+ check_edit ( "foo.unsafe" , r#"fn main() { foo.$0 }"# , r#"fn main() { unsafe { foo } }"# ) ;
634
640
check_edit (
635
- "unsafe" ,
641
+ "{ foo }.unsafe" ,
642
+ r#"fn main() { { foo }.$0 }"# ,
643
+ r#"fn main() { unsafe { foo } }"# ,
644
+ ) ;
645
+ check_edit (
646
+ "if x { foo }.unsafe" ,
636
647
r#"fn main() { if x { foo }.$0 }"# ,
637
648
r#"fn main() { unsafe { if x { foo } } }"# ,
638
649
) ;
639
650
check_edit (
640
- "unsafe" ,
651
+ "loop { foo }. unsafe" ,
641
652
r#"fn main() { loop { foo }.$0 }"# ,
642
653
r#"fn main() { unsafe { loop { foo } } }"# ,
643
654
) ;
644
655
check_edit (
645
- "unsafe" ,
656
+ "if true {}. unsafe" ,
646
657
r#"fn main() { if true {}.$0 }"# ,
647
658
r#"fn main() { unsafe { if true {} } }"# ,
648
659
) ;
649
660
check_edit (
650
- "unsafe" ,
661
+ "while true {}. unsafe" ,
651
662
r#"fn main() { while true {}.$0 }"# ,
652
663
r#"fn main() { unsafe { while true {} } }"# ,
653
664
) ;
654
665
check_edit (
655
- "unsafe" ,
666
+ "for i in 0..10 {}. unsafe" ,
656
667
r#"fn main() { for i in 0..10 {}.$0 }"# ,
657
668
r#"fn main() { unsafe { for i in 0..10 {} } }"# ,
658
669
) ;
659
670
check_edit (
660
- "unsafe" ,
671
+ "if true {1} else {2}. unsafe" ,
661
672
r#"fn main() { let x = if true {1} else {2}.$0 }"# ,
662
673
r#"fn main() { let x = unsafe { if true {1} else {2} } }"# ,
663
674
) ;
@@ -687,7 +698,7 @@ fn main() {
687
698
688
699
check_edit_with_config (
689
700
config. clone ( ) ,
690
- "break" ,
701
+ "42. break" ,
691
702
r#"
692
703
//- minicore: try
693
704
fn main() { 42.$0 }
@@ -706,7 +717,7 @@ fn main() { ControlFlow::Break(42) }
706
717
// what users would see. Unescaping happens thereafter.
707
718
check_edit_with_config (
708
719
config. clone ( ) ,
709
- " break",
720
+ r#"'\\\\'. break"# ,
710
721
r#"
711
722
//- minicore: try
712
723
fn main() { '\\'.$0 }
@@ -720,7 +731,10 @@ fn main() { ControlFlow::Break('\\\\') }
720
731
721
732
check_edit_with_config (
722
733
config,
723
- "break" ,
734
+ r#"match true {
735
+ true => "\${1:placeholder}",
736
+ false => "\\\$",
737
+ }.break"# ,
724
738
r#"
725
739
//- minicore: try
726
740
fn main() {
@@ -746,39 +760,47 @@ fn main() {
746
760
#[ test]
747
761
fn postfix_completion_for_format_like_strings ( ) {
748
762
check_edit (
749
- " format",
763
+ r#""{some_var:?}". format"# ,
750
764
r#"fn main() { "{some_var:?}".$0 }"# ,
751
765
r#"fn main() { format!("{some_var:?}") }"# ,
752
766
) ;
753
767
check_edit (
754
- " panic",
768
+ r#""Panic with {a}". panic"# ,
755
769
r#"fn main() { "Panic with {a}".$0 }"# ,
756
770
r#"fn main() { panic!("Panic with {a}") }"# ,
757
771
) ;
758
772
check_edit (
759
- " println",
773
+ r#""{ 2+2 } { SomeStruct { val: 1, other: 32 } :?}". println"# ,
760
774
r#"fn main() { "{ 2+2 } { SomeStruct { val: 1, other: 32 } :?}".$0 }"# ,
761
775
r#"fn main() { println!("{} {:?}", 2+2, SomeStruct { val: 1, other: 32 }) }"# ,
762
776
) ;
763
777
check_edit (
764
- " loge",
778
+ r#""{2+2}". loge"# ,
765
779
r#"fn main() { "{2+2}".$0 }"# ,
766
780
r#"fn main() { log::error!("{}", 2+2) }"# ,
767
781
) ;
768
782
check_edit (
769
- " logt",
783
+ r#""{2+2}". logt"# ,
770
784
r#"fn main() { "{2+2}".$0 }"# ,
771
785
r#"fn main() { log::trace!("{}", 2+2) }"# ,
772
786
) ;
773
787
check_edit (
774
- " logd",
788
+ r#""{2+2}". logd"# ,
775
789
r#"fn main() { "{2+2}".$0 }"# ,
776
790
r#"fn main() { log::debug!("{}", 2+2) }"# ,
777
791
) ;
778
- check_edit ( "logi" , r#"fn main() { "{2+2}".$0 }"# , r#"fn main() { log::info!("{}", 2+2) }"# ) ;
779
- check_edit ( "logw" , r#"fn main() { "{2+2}".$0 }"# , r#"fn main() { log::warn!("{}", 2+2) }"# ) ;
780
792
check_edit (
781
- "loge" ,
793
+ r#""{2+2}".logi"# ,
794
+ r#"fn main() { "{2+2}".$0 }"# ,
795
+ r#"fn main() { log::info!("{}", 2+2) }"# ,
796
+ ) ;
797
+ check_edit (
798
+ r#""{2+2}".logw"# ,
799
+ r#"fn main() { "{2+2}".$0 }"# ,
800
+ r#"fn main() { log::warn!("{}", 2+2) }"# ,
801
+ ) ;
802
+ check_edit (
803
+ r#""{2+2}".loge"# ,
782
804
r#"fn main() { "{2+2}".$0 }"# ,
783
805
r#"fn main() { log::error!("{}", 2+2) }"# ,
784
806
) ;
@@ -800,21 +822,21 @@ fn main() {
800
822
801
823
check_edit_with_config (
802
824
CompletionConfig { snippets : vec ! [ snippet. clone( ) ] , ..TEST_CONFIG } ,
803
- "ok" ,
825
+ "&&42. ok" ,
804
826
r#"fn main() { &&42.o$0 }"# ,
805
827
r#"fn main() { Ok(&&42) }"# ,
806
828
) ;
807
829
808
830
check_edit_with_config (
809
831
CompletionConfig { snippets : vec ! [ snippet. clone( ) ] , ..TEST_CONFIG } ,
810
- "ok" ,
832
+ "&&42. ok" ,
811
833
r#"fn main() { &&42.$0 }"# ,
812
834
r#"fn main() { Ok(&&42) }"# ,
813
835
) ;
814
836
815
837
check_edit_with_config (
816
838
CompletionConfig { snippets : vec ! [ snippet] , ..TEST_CONFIG } ,
817
- "ok" ,
839
+ "&a.a. ok" ,
818
840
r#"
819
841
struct A {
820
842
a: i32,
0 commit comments