1- use itertools:: Itertools ;
1+ use itertools:: { Itertools , chain } ;
22use syntax:: {
33 SyntaxKind :: WHITESPACE ,
4+ TextRange ,
45 ast:: {
56 AstNode , BlockExpr , ElseBranch , Expr , IfExpr , MatchArm , Pat , edit:: AstNodeEdit , make,
67 prec:: ExprPrecedence , syntax_factory:: SyntaxFactory ,
@@ -44,13 +45,26 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext<'_>)
4445 cov_mark:: hit!( move_guard_inapplicable_in_arm_body) ;
4546 return None ;
4647 }
47- let space_before_guard = guard. syntax ( ) . prev_sibling_or_token ( ) ;
48+ let rest_arms = rest_arms ( & match_arm, ctx. selection_trimmed ( ) ) ?;
49+ let space_before_delete = chain (
50+ guard. syntax ( ) . prev_sibling_or_token ( ) ,
51+ rest_arms. iter ( ) . filter_map ( |it| it. syntax ( ) . prev_sibling_or_token ( ) ) ,
52+ ) ;
4853 let space_after_arrow = match_arm. fat_arrow_token ( ) ?. next_sibling_or_token ( ) ;
4954
50- let guard_condition = guard. condition ( ) ?. reset_indent ( ) ;
5155 let arm_expr = match_arm. expr ( ) ?;
52- let then_branch = crate :: utils:: wrap_block ( & arm_expr) ;
53- let if_expr = make:: expr_if ( guard_condition, then_branch, None ) . indent ( arm_expr. indent_level ( ) ) ;
56+ let if_branch = chain ( [ & match_arm] , & rest_arms)
57+ . rfold ( None , |else_branch, arm| {
58+ if let Some ( guard) = arm. guard ( ) {
59+ let then_branch = crate :: utils:: wrap_block ( & arm. expr ( ) ?) ;
60+ let guard_condition = guard. condition ( ) ?. reset_indent ( ) ;
61+ Some ( make:: expr_if ( guard_condition, then_branch, else_branch) . into ( ) )
62+ } else {
63+ arm. expr ( ) . map ( |it| crate :: utils:: wrap_block ( & it) . into ( ) )
64+ }
65+ } ) ?
66+ . indent ( arm_expr. indent_level ( ) ) ;
67+ let ElseBranch :: IfExpr ( if_expr) = if_branch else { return None } ;
5468
5569 let target = guard. syntax ( ) . text_range ( ) ;
5670 acc. add (
@@ -59,10 +73,13 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext<'_>)
5973 target,
6074 |builder| {
6175 let mut edit = builder. make_editor ( match_arm. syntax ( ) ) ;
62- if let Some ( element) = space_before_guard
63- && element. kind ( ) == WHITESPACE
64- {
65- edit. delete ( element) ;
76+ for element in space_before_delete {
77+ if element. kind ( ) == WHITESPACE {
78+ edit. delete ( element) ;
79+ }
80+ }
81+ for rest_arm in & rest_arms {
82+ edit. delete ( rest_arm. syntax ( ) ) ;
6683 }
6784 if let Some ( element) = space_after_arrow
6885 && element. kind ( ) == WHITESPACE
@@ -221,6 +238,25 @@ pub(crate) fn move_arm_cond_to_match_guard(
221238 )
222239}
223240
241+ fn rest_arms ( match_arm : & MatchArm , selection : TextRange ) -> Option < Vec < MatchArm > > {
242+ match_arm
243+ . parent_match ( )
244+ . match_arm_list ( ) ?
245+ . arms ( )
246+ . skip_while ( |it| it != match_arm)
247+ . skip ( 1 )
248+ . take_while ( move |it| {
249+ selection. is_empty ( ) || crate :: utils:: is_selected ( it, selection, false )
250+ } )
251+ . take_while ( move |it| {
252+ it. pat ( )
253+ . zip ( match_arm. pat ( ) )
254+ . is_some_and ( |( a, b) | a. syntax ( ) . text ( ) == b. syntax ( ) . text ( ) )
255+ } )
256+ . collect :: < Vec < _ > > ( )
257+ . into ( )
258+ }
259+
224260// Parses an if-else-if chain to get the conditions and the then branches until we encounter an else
225261// branch or the end.
226262fn parse_if_chain ( if_expr : IfExpr ) -> Option < ( Vec < ( Expr , BlockExpr ) > , Option < BlockExpr > ) > {
@@ -344,6 +380,115 @@ fn main() {
344380 ) ;
345381 }
346382
383+ #[ test]
384+ fn move_multiple_guard_to_arm_body_works ( ) {
385+ check_assist (
386+ move_guard_to_arm_body,
387+ r#"
388+ fn main() {
389+ match 92 {
390+ x @ 0..30 $0if x % 3 == 0 => false,
391+ x @ 0..30 if x % 2 == 0 => true,
392+ _ => false
393+ }
394+ }
395+ "# ,
396+ r#"
397+ fn main() {
398+ match 92 {
399+ x @ 0..30 => if x % 3 == 0 {
400+ false
401+ } else if x % 2 == 0 {
402+ true
403+ },
404+ _ => false
405+ }
406+ }
407+ "# ,
408+ ) ;
409+
410+ check_assist (
411+ move_guard_to_arm_body,
412+ r#"
413+ fn main() {
414+ match 92 {
415+ x @ 0..30 $0if x % 3 == 0 => false,
416+ x @ 0..30 if x % 2 == 0 => true,
417+ x @ 0..30 => false,
418+ _ => true
419+ }
420+ }
421+ "# ,
422+ r#"
423+ fn main() {
424+ match 92 {
425+ x @ 0..30 => if x % 3 == 0 {
426+ false
427+ } else if x % 2 == 0 {
428+ true
429+ } else {
430+ false
431+ },
432+ _ => true
433+ }
434+ }
435+ "# ,
436+ ) ;
437+
438+ check_assist (
439+ move_guard_to_arm_body,
440+ r#"
441+ fn main() {
442+ match 92 {
443+ x @ 0..30 if x % 3 == 0 => false,
444+ x @ 0..30 $0if x % 2 == 0$0 => true,
445+ x @ 0..30 => false,
446+ _ => true
447+ }
448+ }
449+ "# ,
450+ r#"
451+ fn main() {
452+ match 92 {
453+ x @ 0..30 if x % 3 == 0 => false,
454+ x @ 0..30 => if x % 2 == 0 {
455+ true
456+ },
457+ x @ 0..30 => false,
458+ _ => true
459+ }
460+ }
461+ "# ,
462+ ) ;
463+
464+ check_assist (
465+ move_guard_to_arm_body,
466+ r#"
467+ fn main() {
468+ match 92 {
469+ x @ 0..30 $0if x % 3 == 0 => false,
470+ x @ 0..30 $0if x % 2 == 0 => true,
471+ x @ 0..30 => false,
472+ _ => true
473+ }
474+ }
475+ "# ,
476+ r#"
477+ fn main() {
478+ match 92 {
479+ x @ 0..30 => if x % 3 == 0 {
480+ false
481+ } else if x % 2 == 0 {
482+ true
483+ },
484+ x @ 0..30 => false,
485+ _ => true
486+ }
487+ }
488+ "# ,
489+ ) ;
490+ }
491+
347492 #[ test]
348493 fn move_guard_to_block_arm_body_works ( ) {
349494 check_assist (
0 commit comments