@@ -12,6 +12,7 @@ use ide_db::{
1212use stdx:: never;
1313use syntax:: {
1414 ast:: { self , make, AstNode , AstToken } ,
15+ format_smolstr,
1516 SyntaxKind :: { BLOCK_EXPR , EXPR_STMT , FOR_EXPR , IF_EXPR , LOOP_EXPR , STMT_LIST , WHILE_EXPR } ,
1617 TextRange , TextSize ,
1718} ;
@@ -55,10 +56,11 @@ pub(crate) fn complete_postfix(
5556 None => return ,
5657 } ;
5758
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+ } ;
6264
6365 if let Some ( drop_trait) = ctx. famous_defs ( ) . core_ops_Drop ( ) {
6466 if receiver_ty. impls_trait ( ctx. db , drop_trait, & [ ] ) {
@@ -173,10 +175,11 @@ pub(crate) fn complete_postfix(
173175 let ( dot_receiver, node_to_replace_with) = include_references ( dot_receiver) ;
174176 let receiver_text =
175177 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+ } ;
180183
181184 if !ctx. config . snippets . is_empty ( ) {
182185 add_custom_postfix_completions ( acc, ctx, & postfix_snippet, & receiver_text) ;
@@ -317,6 +320,7 @@ fn build_postfix_snippet_builder<'ctx>(
317320 ctx : & ' ctx CompletionContext < ' _ > ,
318321 cap : SnippetCap ,
319322 receiver : & ' ctx ast:: Expr ,
323+ receiver_text : & ' ctx str ,
320324) -> Option < impl Fn ( & str , & str , & str ) -> Builder + ' ctx > {
321325 let receiver_range = ctx. sema . original_range_opt ( receiver. syntax ( ) ) ?. range ;
322326 if ctx. source_range ( ) . end ( ) < receiver_range. start ( ) {
@@ -332,13 +336,16 @@ fn build_postfix_snippet_builder<'ctx>(
332336 fn build < ' ctx > (
333337 ctx : & ' ctx CompletionContext < ' _ > ,
334338 cap : SnippetCap ,
339+ receiver_text : & ' ctx str ,
335340 delete_range : TextRange ,
336341 ) -> impl Fn ( & str , & str , & str ) -> Builder + ' ctx {
337342 move |label, detail, snippet| {
338343 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) ;
341345 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) ) ;
342349 let postfix_match = if ctx. original_token . text ( ) == label {
343350 cov_mark:: hit!( postfix_exact_match_is_high_priority) ;
344351 Some ( CompletionRelevancePostfixMatch :: Exact )
@@ -351,7 +358,7 @@ fn build_postfix_snippet_builder<'ctx>(
351358 item
352359 }
353360 }
354- Some ( build ( ctx, cap, delete_range) )
361+ Some ( build ( ctx, cap, receiver_text , delete_range) )
355362}
356363
357364fn add_custom_postfix_completions (
@@ -512,7 +519,7 @@ fn main() {
512519 #[ test]
513520 fn option_iflet ( ) {
514521 check_edit (
515- "ifl" ,
522+ "bar. ifl" ,
516523 r#"
517524//- minicore: option
518525fn main() {
@@ -534,7 +541,7 @@ fn main() {
534541 #[ test]
535542 fn option_letelse ( ) {
536543 check_edit (
537- "lete" ,
544+ "bar. lete" ,
538545 r#"
539546//- minicore: option
540547fn main() {
557564 #[ test]
558565 fn result_match ( ) {
559566 check_edit (
560- "match" ,
567+ "bar. match" ,
561568 r#"
562569//- minicore: result
563570fn main() {
@@ -579,13 +586,13 @@ fn main() {
579586
580587 #[ test]
581588 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 }"# )
583590 }
584591
585592 #[ test]
586593 fn works_in_simple_macro ( ) {
587594 check_edit (
588- "dbg" ,
595+ "bar. dbg" ,
589596 r#"
590597macro_rules! m { ($e:expr) => { $e } }
591598fn main() {
@@ -605,10 +612,10 @@ fn main() {
605612
606613 #[ test]
607614 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 }"# ) ;
610617 check_edit (
611- "ifl" ,
618+ "bar. ifl" ,
612619 r#"
613620//- minicore: option
614621fn main() {
@@ -629,35 +636,39 @@ fn main() {
629636
630637 #[ test]
631638 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 } }"# ) ;
634640 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" ,
636647 r#"fn main() { if x { foo }.$0 }"# ,
637648 r#"fn main() { unsafe { if x { foo } } }"# ,
638649 ) ;
639650 check_edit (
640- "unsafe" ,
651+ "loop { foo }. unsafe" ,
641652 r#"fn main() { loop { foo }.$0 }"# ,
642653 r#"fn main() { unsafe { loop { foo } } }"# ,
643654 ) ;
644655 check_edit (
645- "unsafe" ,
656+ "if true {}. unsafe" ,
646657 r#"fn main() { if true {}.$0 }"# ,
647658 r#"fn main() { unsafe { if true {} } }"# ,
648659 ) ;
649660 check_edit (
650- "unsafe" ,
661+ "while true {}. unsafe" ,
651662 r#"fn main() { while true {}.$0 }"# ,
652663 r#"fn main() { unsafe { while true {} } }"# ,
653664 ) ;
654665 check_edit (
655- "unsafe" ,
666+ "for i in 0..10 {}. unsafe" ,
656667 r#"fn main() { for i in 0..10 {}.$0 }"# ,
657668 r#"fn main() { unsafe { for i in 0..10 {} } }"# ,
658669 ) ;
659670 check_edit (
660- "unsafe" ,
671+ "if true {1} else {2}. unsafe" ,
661672 r#"fn main() { let x = if true {1} else {2}.$0 }"# ,
662673 r#"fn main() { let x = unsafe { if true {1} else {2} } }"# ,
663674 ) ;
@@ -687,7 +698,7 @@ fn main() {
687698
688699 check_edit_with_config (
689700 config. clone ( ) ,
690- "break" ,
701+ "42. break" ,
691702 r#"
692703//- minicore: try
693704fn main() { 42.$0 }
@@ -706,7 +717,7 @@ fn main() { ControlFlow::Break(42) }
706717 // what users would see. Unescaping happens thereafter.
707718 check_edit_with_config (
708719 config. clone ( ) ,
709- " break",
720+ r#"'\\\\'. break"# ,
710721 r#"
711722//- minicore: try
712723fn main() { '\\'.$0 }
@@ -720,7 +731,10 @@ fn main() { ControlFlow::Break('\\\\') }
720731
721732 check_edit_with_config (
722733 config,
723- "break" ,
734+ r#"match true {
735+ true => "\${1:placeholder}",
736+ false => "\\\$",
737+ }.break"# ,
724738 r#"
725739//- minicore: try
726740fn main() {
@@ -746,39 +760,47 @@ fn main() {
746760 #[ test]
747761 fn postfix_completion_for_format_like_strings ( ) {
748762 check_edit (
749- " format",
763+ r#""{some_var:?}". format"# ,
750764 r#"fn main() { "{some_var:?}".$0 }"# ,
751765 r#"fn main() { format!("{some_var:?}") }"# ,
752766 ) ;
753767 check_edit (
754- " panic",
768+ r#""Panic with {a}". panic"# ,
755769 r#"fn main() { "Panic with {a}".$0 }"# ,
756770 r#"fn main() { panic!("Panic with {a}") }"# ,
757771 ) ;
758772 check_edit (
759- " println",
773+ r#""{ 2+2 } { SomeStruct { val: 1, other: 32 } :?}". println"# ,
760774 r#"fn main() { "{ 2+2 } { SomeStruct { val: 1, other: 32 } :?}".$0 }"# ,
761775 r#"fn main() { println!("{} {:?}", 2+2, SomeStruct { val: 1, other: 32 }) }"# ,
762776 ) ;
763777 check_edit (
764- " loge",
778+ r#""{2+2}". loge"# ,
765779 r#"fn main() { "{2+2}".$0 }"# ,
766780 r#"fn main() { log::error!("{}", 2+2) }"# ,
767781 ) ;
768782 check_edit (
769- " logt",
783+ r#""{2+2}". logt"# ,
770784 r#"fn main() { "{2+2}".$0 }"# ,
771785 r#"fn main() { log::trace!("{}", 2+2) }"# ,
772786 ) ;
773787 check_edit (
774- " logd",
788+ r#""{2+2}". logd"# ,
775789 r#"fn main() { "{2+2}".$0 }"# ,
776790 r#"fn main() { log::debug!("{}", 2+2) }"# ,
777791 ) ;
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) }"# ) ;
780792 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"# ,
782804 r#"fn main() { "{2+2}".$0 }"# ,
783805 r#"fn main() { log::error!("{}", 2+2) }"# ,
784806 ) ;
@@ -800,21 +822,21 @@ fn main() {
800822
801823 check_edit_with_config (
802824 CompletionConfig { snippets : vec ! [ snippet. clone( ) ] , ..TEST_CONFIG } ,
803- "ok" ,
825+ "&&42. ok" ,
804826 r#"fn main() { &&42.o$0 }"# ,
805827 r#"fn main() { Ok(&&42) }"# ,
806828 ) ;
807829
808830 check_edit_with_config (
809831 CompletionConfig { snippets : vec ! [ snippet. clone( ) ] , ..TEST_CONFIG } ,
810- "ok" ,
832+ "&&42. ok" ,
811833 r#"fn main() { &&42.$0 }"# ,
812834 r#"fn main() { Ok(&&42) }"# ,
813835 ) ;
814836
815837 check_edit_with_config (
816838 CompletionConfig { snippets : vec ! [ snippet] , ..TEST_CONFIG } ,
817- "ok" ,
839+ "&a.a. ok" ,
818840 r#"
819841struct A {
820842 a: i32,
0 commit comments