Skip to content

Commit 45912a9

Browse files
committed
Add more expression to 'in_value'
When completing some expressions, it is almost always expected to have a non unit value - ArrayExpr - ParenExpr - BreakExpr - ReturnExpr - PrefixExpr - FormatArgsArg - RecordExprField - BinExpr (rhs only) - IndexExpr (inside index only) Example --- ```rust fn main() { return $0; } ``` **Before this PR** ```rust fn main() { return if $1 { $0 }; } ``` **After this PR** ```rust fn main() { return if $1 { $2 } else { $0 }; } ```
1 parent 00b627d commit 45912a9

File tree

2 files changed

+160
-1
lines changed

2 files changed

+160
-1
lines changed

crates/ide-completion/src/completions/keyword.rs

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,146 @@ fn main() {
531531
);
532532
}
533533

534+
#[test]
535+
fn if_completion_in_format() {
536+
check_edit(
537+
"if",
538+
r#"
539+
//- minicore: fmt
540+
fn main() {
541+
format_args!("{}", $0);
542+
}
543+
"#,
544+
r#"
545+
fn main() {
546+
format_args!("{}", if $1 {
547+
$2
548+
} else {
549+
$0
550+
});
551+
}
552+
"#,
553+
);
554+
555+
check_edit(
556+
"if",
557+
r#"
558+
//- minicore: fmt
559+
fn main() {
560+
format_args!("{}", if$0);
561+
}
562+
"#,
563+
r#"
564+
fn main() {
565+
format_args!("{}", if $1 {
566+
$2
567+
} else {
568+
$0
569+
});
570+
}
571+
"#,
572+
);
573+
}
574+
575+
#[test]
576+
fn if_completion_in_value_expected_expressions() {
577+
check_edit(
578+
"if",
579+
r#"
580+
fn main() {
581+
2 + $0;
582+
}
583+
"#,
584+
r#"
585+
fn main() {
586+
2 + if $1 {
587+
$2
588+
} else {
589+
$0
590+
};
591+
}
592+
"#,
593+
);
594+
595+
check_edit(
596+
"if",
597+
r#"
598+
fn main() {
599+
-$0;
600+
}
601+
"#,
602+
r#"
603+
fn main() {
604+
-if $1 {
605+
$2
606+
} else {
607+
$0
608+
};
609+
}
610+
"#,
611+
);
612+
613+
check_edit(
614+
"if",
615+
r#"
616+
fn main() {
617+
return $0;
618+
}
619+
"#,
620+
r#"
621+
fn main() {
622+
return if $1 {
623+
$2
624+
} else {
625+
$0
626+
};
627+
}
628+
"#,
629+
);
630+
631+
check_edit(
632+
"if",
633+
r#"
634+
fn main() {
635+
loop {
636+
break $0;
637+
}
638+
}
639+
"#,
640+
r#"
641+
fn main() {
642+
loop {
643+
break if $1 {
644+
$2
645+
} else {
646+
$0
647+
};
648+
}
649+
}
650+
"#,
651+
);
652+
653+
check_edit(
654+
"if",
655+
r#"
656+
struct Foo { x: i32 }
657+
fn main() {
658+
Foo { x: $0 }
659+
}
660+
"#,
661+
r#"
662+
struct Foo { x: i32 }
663+
fn main() {
664+
Foo { x: if $1 {
665+
$2
666+
} else {
667+
$0
668+
} }
669+
}
670+
"#,
671+
);
672+
}
673+
534674
#[test]
535675
fn completes_let_in_block() {
536676
check_edit(

crates/ide-completion/src/context/analysis.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,25 @@ fn classify_name_ref<'db>(
10121012
.and_then(|next| next.first_token())
10131013
.is_some_and(|token| token.kind() == SyntaxKind::ELSE_KW)
10141014
};
1015+
let is_in_value = |it: &SyntaxNode| {
1016+
let Some(node) = it.parent() else { return false };
1017+
let kind = node.kind();
1018+
ast::LetStmt::can_cast(kind)
1019+
|| ast::ArgList::can_cast(kind)
1020+
|| ast::ArrayExpr::can_cast(kind)
1021+
|| ast::ParenExpr::can_cast(kind)
1022+
|| ast::BreakExpr::can_cast(kind)
1023+
|| ast::ReturnExpr::can_cast(kind)
1024+
|| ast::PrefixExpr::can_cast(kind)
1025+
|| ast::FormatArgsArg::can_cast(kind)
1026+
|| ast::RecordExprField::can_cast(kind)
1027+
|| ast::BinExpr::cast(node.clone())
1028+
.and_then(|expr| expr.rhs())
1029+
.is_some_and(|expr| expr.syntax() == it)
1030+
|| ast::IndexExpr::cast(node)
1031+
.and_then(|expr| expr.index())
1032+
.is_some_and(|expr| expr.syntax() == it)
1033+
};
10151034

10161035
// We do not want to generate path completions when we are sandwiched between an item decl signature and its body.
10171036
// ex. trait Foo $0 {}
@@ -1307,7 +1326,7 @@ fn classify_name_ref<'db>(
13071326
.and_then(ast::LetStmt::cast)
13081327
.is_some_and(|it| it.semicolon_token().is_none())
13091328
|| after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw;
1310-
let in_value = it.parent().and_then(Either::<ast::LetStmt, ast::ArgList>::cast).is_some();
1329+
let in_value = is_in_value(it);
13111330
let impl_ = fetch_immediate_impl_or_trait(sema, original_file, expr.syntax())
13121331
.and_then(Either::left);
13131332

0 commit comments

Comments
 (0)