@@ -1482,7 +1482,7 @@ class SourceVisitor extends ThrowingAstVisitor {
1482
1482
builder.endRule ();
1483
1483
builder.unnest ();
1484
1484
1485
- builder.nestExpression (indent: 2 , now: true );
1485
+ builder.nestExpression (indent: Indent .block , now: true );
1486
1486
1487
1487
if (isSpreadBody) {
1488
1488
space ();
@@ -2747,73 +2747,147 @@ class SourceVisitor extends ThrowingAstVisitor {
2747
2747
}
2748
2748
2749
2749
@override
2750
- void visitSwitchCase (SwitchCase node) {
2751
- _visitLabels (node.labels);
2752
- token (node.keyword);
2753
- space ();
2754
- visit (node.expression);
2755
- token (node.colon);
2750
+ void visitSwitchExpression (SwitchExpression node) {
2751
+ // Start the rule for splitting between the cases before the value. That
2752
+ // way, if the value expression splits, the cases do too. Avoids:
2753
+ //
2754
+ // switch ([
2755
+ // element,
2756
+ // ]) { inline => caseBody };
2757
+ builder.startRule ();
2756
2758
2757
- builder. indent ();
2758
- newline ( );
2759
+ _visitSwitchValue (node.switchKeyword, node.leftParenthesis, node.expression,
2760
+ node.rightParenthesis );
2759
2761
2760
- visitNodes (node.statements, between: oneOrTwoNewlines);
2761
- builder.unindent ();
2762
+ token (node.leftBracket);
2763
+ builder = builder.startBlock (space: true );
2764
+
2765
+ visitCommaSeparatedNodes (node.cases, between: split);
2766
+
2767
+ var hasTrailingComma = node.cases.last.commaAfter != null ;
2768
+ _endBody (node.rightBracket, forceSplit: hasTrailingComma);
2762
2769
}
2763
2770
2764
2771
@override
2765
- void visitSwitchDefault ( SwitchDefault node) {
2766
- _visitLabels (node.labels);
2767
- token (node.keyword);
2768
- token (node.colon );
2772
+ void visitSwitchExpressionCase ( SwitchExpressionCase node) {
2773
+ // Wrap the rule for splitting after "=>" around the pattern so that a
2774
+ // split in the pattern forces the expression to move to the next line too.
2775
+ builder. startLazyRule ( );
2769
2776
2770
- builder.indent ();
2771
- newline ();
2777
+ // Wrap the expression's nesting around the pattern too so that a split in
2778
+ // the pattern is indented farther then the body expression. Used +2 indent
2779
+ // because switch expressions are block-like, similar to how we split the
2780
+ // bodies of if and for elements in collections.
2781
+ builder.nestExpression (indent: Indent .block);
2772
2782
2773
- visitNodes (node.statements, between: oneOrTwoNewlines);
2774
- builder.unindent ();
2783
+ var whenClause = node.guardedPattern.whenClause;
2784
+ if (whenClause == null ) {
2785
+ visit (node.guardedPattern.pattern);
2786
+ } else {
2787
+ // Wrap the when clause rule around the pattern so that if the pattern
2788
+ // splits then we split before "when" too.
2789
+ builder.startRule ();
2790
+ builder.nestExpression (indent: Indent .block);
2791
+ visit (node.guardedPattern.pattern);
2792
+ split ();
2793
+ builder.startBlockArgumentNesting ();
2794
+ _visitWhenClause (whenClause);
2795
+ builder.endBlockArgumentNesting ();
2796
+ builder.unnest ();
2797
+ builder.endRule ();
2798
+ }
2799
+
2800
+ space ();
2801
+ token (node.arrow);
2802
+ split ();
2803
+
2804
+ builder.endRule ();
2805
+
2806
+ visit (node.expression);
2807
+ builder.unnest ();
2775
2808
}
2776
2809
2777
2810
@override
2778
- void visitSwitchPatternCase (SwitchPatternCase node) {
2779
- _visitLabels (node.labels);
2811
+ void visitSwitchStatement (SwitchStatement node) {
2812
+ _visitSwitchValue (node.switchKeyword, node.leftParenthesis, node.expression,
2813
+ node.rightParenthesis);
2814
+ _beginBody (node.leftBracket);
2780
2815
2781
- token (node.keyword);
2782
- space ();
2816
+ for (var member in node.members) {
2817
+ // If the case pattern and body don't contain any splits, then we allow
2818
+ // the entire case on one line:
2819
+ //
2820
+ // switch (obj) {
2821
+ // case 1:
2822
+ // case 2: print('one or two');
2823
+ // default: print('other');
2824
+ // }
2825
+ //
2826
+ // We wrap the rule for this around the entire case so that a split in
2827
+ // the pattern or the case statement forces splitting after the ":" too.
2828
+ builder.startLazyRule ();
2783
2829
2784
- builder.indent ();
2785
- builder.startBlockArgumentNesting ();
2786
- builder.nestExpression ();
2787
- visit (node.guardedPattern.pattern);
2788
- builder.unnest ();
2789
- builder.endBlockArgumentNesting ();
2790
- builder.unindent ();
2830
+ _visitLabels (member.labels);
2831
+ token (member.keyword);
2791
2832
2792
- visit (node.guardedPattern.whenClause);
2793
- token (node.colon);
2833
+ if (member is SwitchCase ) {
2834
+ space ();
2835
+ visit (member.expression);
2836
+ } else if (member is SwitchPatternCase ) {
2837
+ space ();
2794
2838
2795
- builder.indent ();
2796
- newline ();
2839
+ var whenClause = member.guardedPattern.whenClause;
2840
+ if (whenClause == null ) {
2841
+ builder.indent ();
2842
+ visit (member.guardedPattern.pattern);
2843
+ builder.unindent ();
2844
+ } else {
2845
+ // Wrap the when clause rule around the pattern so that if the pattern
2846
+ // splits then we split before "when" too.
2847
+ builder.startRule ();
2848
+ builder.nestExpression ();
2849
+ builder.startBlockArgumentNesting ();
2850
+ visit (member.guardedPattern.pattern);
2851
+ split ();
2852
+ _visitWhenClause (whenClause);
2853
+ builder.endBlockArgumentNesting ();
2854
+ builder.unnest ();
2855
+ builder.endRule ();
2856
+ }
2857
+ }
2797
2858
2798
- visitNodes (node.statements, between: oneOrTwoNewlines);
2799
- builder.unindent ();
2859
+ token (member.colon);
2860
+
2861
+ if (member.statements.isNotEmpty) {
2862
+ builder.indent ();
2863
+ split ();
2864
+ visitNodes (member.statements, between: oneOrTwoNewlines);
2865
+ builder.unindent ();
2866
+ oneOrTwoNewlines ();
2867
+ } else {
2868
+ // Don't preserve blank lines between empty cases.
2869
+ newline ();
2870
+ }
2871
+
2872
+ builder.endRule ();
2873
+ }
2874
+
2875
+ newline ();
2876
+ _endBody (node.rightBracket, forceSplit: true );
2800
2877
}
2801
2878
2802
- @override
2803
- void visitSwitchStatement (SwitchStatement node) {
2879
+ /// Visits the `switch (expr)` part of a switch statement or expression.
2880
+ void _visitSwitchValue (Token switchKeyword, Token leftParenthesis,
2881
+ Expression value, Token rightParenthesis) {
2804
2882
builder.nestExpression ();
2805
- token (node. switchKeyword);
2883
+ token (switchKeyword);
2806
2884
space ();
2807
- token (node. leftParenthesis);
2885
+ token (leftParenthesis);
2808
2886
soloZeroSplit ();
2809
- visit (node.expression );
2810
- token (node. rightParenthesis);
2887
+ visit (value );
2888
+ token (rightParenthesis);
2811
2889
space ();
2812
2890
builder.unnest ();
2813
-
2814
- _beginBody (node.leftBracket);
2815
- visitNodes (node.members, between: oneOrTwoNewlines, after: newline);
2816
- _endBody (node.rightBracket, forceSplit: true );
2817
2891
}
2818
2892
2819
2893
@override
@@ -2951,20 +3025,6 @@ class SourceVisitor extends ThrowingAstVisitor {
2951
3025
});
2952
3026
}
2953
3027
2954
- @override
2955
- void visitWhenClause (WhenClause node) {
2956
- builder.startRule ();
2957
- split ();
2958
- token (node.whenKeyword);
2959
- space ();
2960
- builder.startBlockArgumentNesting ();
2961
- builder.nestExpression ();
2962
- visit (node.expression);
2963
- builder.unnest ();
2964
- builder.endBlockArgumentNesting ();
2965
- builder.endRule ();
2966
- }
2967
-
2968
3028
@override
2969
3029
void visitWhileStatement (WhileStatement node) {
2970
3030
builder.nestExpression ();
@@ -3644,19 +3704,20 @@ class SourceVisitor extends ThrowingAstVisitor {
3644
3704
space ();
3645
3705
token (leftParenthesis);
3646
3706
3647
- if (caseClause != null ) {
3707
+ if (caseClause == null ) {
3708
+ // Simple if with no "case".
3709
+ visit (condition);
3710
+ } else {
3711
+ // If-case.
3712
+
3648
3713
// Wrap the rule for splitting before "case" around the value expression
3649
3714
// so that if the value splits, we split before "case" too.
3650
- builder.startRule ();
3715
+ var caseRule = Rule ();
3716
+ builder.startRule (caseRule);
3651
3717
3652
- // Nest the condition so that it indents deeper than the case clause.
3653
- builder.nestExpression ();
3654
- }
3655
-
3656
- visit (condition);
3718
+ visit (condition);
3657
3719
3658
- // If-case clause.
3659
- if (caseClause != null ) {
3720
+ // "case" and pattern.
3660
3721
split ();
3661
3722
token (caseClause.caseKeyword);
3662
3723
space ();
@@ -3665,15 +3726,34 @@ class SourceVisitor extends ThrowingAstVisitor {
3665
3726
visit (caseClause.guardedPattern.pattern);
3666
3727
builder.unnest ();
3667
3728
builder.endBlockArgumentNesting ();
3668
- builder.endRule ();
3669
- visit (caseClause.guardedPattern.whenClause);
3729
+
3730
+ builder.endRule (); // Case rule.
3731
+
3732
+ var whenClause = caseClause.guardedPattern.whenClause;
3733
+ if (whenClause != null ) {
3734
+ // Wrap the rule for "when" around the guard so that a split in the
3735
+ // guard splits at "when" too.
3736
+ builder.startRule ();
3737
+ split ();
3738
+ builder.startBlockArgumentNesting ();
3739
+ builder.nestExpression ();
3740
+ _visitWhenClause (whenClause);
3741
+ builder.unnest ();
3742
+ builder.endBlockArgumentNesting ();
3743
+ builder.endRule (); // Guard rule.
3744
+ }
3670
3745
}
3671
3746
3672
3747
token (rightParenthesis);
3673
- if (caseClause != null ) builder.unnest ();
3674
3748
builder.unnest ();
3675
3749
}
3676
3750
3751
+ void _visitWhenClause (WhenClause whenClause) {
3752
+ token (whenClause.whenKeyword);
3753
+ space ();
3754
+ visit (whenClause.expression);
3755
+ }
3756
+
3677
3757
/// Writes the separator between a type annotation and a variable or
3678
3758
/// parameter. If the preceding type annotation ends in a delimited list of
3679
3759
/// elements that have block formatting, then we don't split between the
0 commit comments