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