Skip to content

Commit af72874

Browse files
committed
Auto merge of #17073 - roife:better-inline-preview, r=Veykril
Better inline preview for postfix completion Better inline preview for postfix completion, a proper implementation of c5686c8. Here editors may filter completion item with the text within `delete_range`, so we need to include the `receiver text` in the `lookup` (aka `FilterText` in LSP spec) for editors to find the completion item. (See rust-lang/rust-analyzer#17036 (comment), Thanks to [pascalkuthe](https://github.com/pascalkuthe))
2 parents c037130 + 8db1c64 commit af72874

3 files changed

Lines changed: 70 additions & 47 deletions

File tree

‎crates/ide-completion/src/completions/dot.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1035,7 +1035,7 @@ fn main() {
10351035
fnpostfix_drop_completion(){
10361036
cov_mark::check!(postfix_drop_completion);
10371037
check_edit(
1038-
"drop",
1038+
"x.drop",
10391039
r#"
10401040
//- minicore: drop
10411041
struct Vec<T>(T);

‎crates/ide-completion/src/completions/postfix.rs‎

Lines changed: 64 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use ide_db::{
1212
use stdx::never;
1313
use 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 = matchbuild_postfix_snippet_builder(ctx, cap, dot_receiver){
59-
Some(it) => it,
60-
None => return,
61-
};
59+
let postfix_snippet =
60+
matchbuild_postfix_snippet_builder(ctx, cap, dot_receiver,&receiver_text){
61+
Some(it) => it,
62+
None => return,
63+
};
6264

6365
ifletSome(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 = matchbuild_postfix_snippet_builder(ctx, cap,&dot_receiver){
177-
Some(it) => it,
178-
None => return,
179-
};
178+
let postfix_snippet =
179+
matchbuild_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:&'ctxCompletionContext<'_>,
318321
cap:SnippetCap,
319322
receiver:&'ctx ast::Expr,
323+
receiver_text:&'ctxstr,
320324
) -> Option<implFn(&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
fnbuild<'ctx>(
333337
ctx:&'ctxCompletionContext<'_>,
334338
cap:SnippetCap,
339+
receiver_text:&'ctxstr,
335340
delete_range:TextRange,
336341
) -> implFn(&str,&str,&str) -> Builder + 'ctx{
337342
move |label, detail, snippet| {
338343
let edit = TextEdit::replace(delete_range, snippet.to_owned());
339-
letmut item =
340-
CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label);
344+
letmut 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

357364
fnadd_custom_postfix_completions(
@@ -512,7 +519,7 @@ fn main() {
512519
#[test]
513520
fnoption_iflet(){
514521
check_edit(
515-
"ifl",
522+
"bar.ifl",
516523
r#"
517524
//- minicore: option
518525
fn main() {
@@ -534,7 +541,7 @@ fn main() {
534541
#[test]
535542
fnoption_letelse(){
536543
check_edit(
537-
"lete",
544+
"bar.lete",
538545
r#"
539546
//- minicore: option
540547
fn main() {
@@ -557,7 +564,7 @@ $0
557564
#[test]
558565
fnresult_match(){
559566
check_edit(
560-
"match",
567+
"bar.match",
561568
r#"
562569
//- minicore: result
563570
fn main() {
@@ -579,13 +586,13 @@ fn main() {
579586

580587
#[test]
581588
fnpostfix_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
fnworks_in_simple_macro(){
587594
check_edit(
588-
"dbg",
595+
"bar.dbg",
589596
r#"
590597
macro_rules! m { ($e:expr) => { $e } }
591598
fn main() {
@@ -605,10 +612,10 @@ fn main() {
605612

606613
#[test]
607614
fnpostfix_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
614621
fn main() {
@@ -629,35 +636,39 @@ fn main() {
629636

630637
#[test]
631638
fnpostfix_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
693704
fn 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
712723
fn 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
726740
fn main() {
@@ -746,39 +760,47 @@ fn main() {
746760
#[test]
747761
fnpostfix_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#"
819841
struct A {
820842
a: i32,

‎crates/ide-completion/src/completions/postfix/format_like.rs‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,11 @@ pub(crate) fn add_format_like_completions(
4848
cap:SnippetCap,
4949
receiver_text:&ast::String,
5050
){
51-
let postfix_snippet = matchbuild_postfix_snippet_builder(ctx, cap, dot_receiver){
52-
Some(it) => it,
53-
None => return,
54-
};
51+
let postfix_snippet =
52+
matchbuild_postfix_snippet_builder(ctx, cap, dot_receiver, receiver_text.text()){
53+
Some(it) => it,
54+
None => return,
55+
};
5556

5657
ifletOk((mut out,mut exprs)) = parse_format_exprs(receiver_text.text()){
5758
// Escape any snippet bits in the out text and any of the exprs.

0 commit comments

Comments
 (0)