Skip to content

Commit 990df02

Browse files
authored
Format list pattern and rest pattern. (#1363)
* Format list pattern. * Add documentation for PatternExtensions.canBlockSplit. * Fix comment in if statement. * Fix comment nits.
1 parent 94f81dd commit 990df02

File tree

6 files changed

+142
-10
lines changed

6 files changed

+142
-10
lines changed

lib/src/ast_extensions.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,3 +313,15 @@ extension CascadeExpressionExtensions on CascadeExpression {
313313
return true;
314314
}
315315
}
316+
317+
extension PatternExtensions on DartPattern {
318+
/// Whether this expression is a non-empty delimited container for inner
319+
/// expressions that allows "block-like" formatting in some contexts.
320+
///
321+
/// See [ExpressionExtensions.canBlockSplit].
322+
bool get canBlockSplit => switch (this) {
323+
ListPattern(:var elements, :var rightBracket) =>
324+
elements.canSplit(rightBracket),
325+
_ => false,
326+
};
327+
}

lib/src/front_end/ast_node_visitor.dart

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -964,9 +964,22 @@ class AstNodeVisitor extends ThrowingAstVisitor<Piece> with PieceFactory {
964964
var expressionPiece = nodePiece(ifStatement.expression);
965965
if (ifStatement.caseClause case var caseClause?) {
966966
var caseClausePiece = nodePiece(caseClause);
967+
// If the case clause can have block formatting, then a newline in
968+
// it doesn't force the if-case to split before the `case` keyword,
969+
// like:
970+
//
971+
// if (obj case [
972+
// first,
973+
// second,
974+
// third,
975+
// ]) {
976+
// ;
977+
// }
978+
var allowInnerSplit = caseClause.guardedPattern.pattern.canBlockSplit;
967979
b.add(AssignPiece(
968980
expressionPiece,
969981
caseClausePiece,
982+
allowInnerSplit: allowInnerSplit,
970983
indentInValue: true,
971984
));
972985
} else {
@@ -1138,7 +1151,7 @@ class AstNodeVisitor extends ThrowingAstVisitor<Piece> with PieceFactory {
11381151
@override
11391152
Piece visitListLiteral(ListLiteral node) {
11401153
return createCollection(
1141-
node.constKeyword,
1154+
constKeyword: node.constKeyword,
11421155
typeArguments: node.typeArguments,
11431156
node.leftBracket,
11441157
node.elements,
@@ -1148,7 +1161,12 @@ class AstNodeVisitor extends ThrowingAstVisitor<Piece> with PieceFactory {
11481161

11491162
@override
11501163
Piece visitListPattern(ListPattern node) {
1151-
throw UnimplementedError();
1164+
return createCollection(
1165+
typeArguments: node.typeArguments,
1166+
node.leftBracket,
1167+
node.elements,
1168+
node.rightBracket,
1169+
);
11521170
}
11531171

11541172
@override
@@ -1405,7 +1423,7 @@ class AstNodeVisitor extends ThrowingAstVisitor<Piece> with PieceFactory {
14051423
}
14061424

14071425
return createCollection(
1408-
node.constKeyword,
1426+
constKeyword: node.constKeyword,
14091427
node.leftParenthesis,
14101428
node.fields,
14111429
node.rightParenthesis,
@@ -1487,7 +1505,10 @@ class AstNodeVisitor extends ThrowingAstVisitor<Piece> with PieceFactory {
14871505

14881506
@override
14891507
Piece visitRestPatternElement(RestPatternElement node) {
1490-
throw UnimplementedError();
1508+
return buildPiece((b) {
1509+
b.token(node.operator);
1510+
b.visit(node.pattern);
1511+
});
14911512
}
14921513

14931514
@override
@@ -1509,7 +1530,7 @@ class AstNodeVisitor extends ThrowingAstVisitor<Piece> with PieceFactory {
15091530
@override
15101531
Piece visitSetOrMapLiteral(SetOrMapLiteral node) {
15111532
return createCollection(
1512-
node.constKeyword,
1533+
constKeyword: node.constKeyword,
15131534
typeArguments: node.typeArguments,
15141535
node.leftBracket,
15151536
node.elements,

lib/src/front_end/delimited_list_builder.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ class DelimitedListBuilder {
157157
var format = switch (element) {
158158
FunctionExpression() when element.canBlockSplit => BlockFormat.function,
159159
Expression() when element.canBlockSplit => BlockFormat.block,
160+
DartPattern() when element.canBlockSplit => BlockFormat.block,
160161
_ => BlockFormat.none,
161162
};
162163

lib/src/front_end/piece_factory.dart

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,15 @@ mixin PieceFactory {
118118
});
119119
}
120120

121-
/// Creates a [ListPiece] for a collection literal.
122-
Piece createCollection(Token? constKeyword, Token leftBracket,
123-
List<AstNode> elements, Token rightBracket,
124-
{TypeArgumentList? typeArguments, ListStyle style = const ListStyle()}) {
121+
/// Creates a [ListPiece] for a collection literal or pattern.
122+
Piece createCollection(
123+
Token leftBracket,
124+
List<AstNode> elements,
125+
Token rightBracket, {
126+
Token? constKeyword,
127+
TypeArgumentList? typeArguments,
128+
ListStyle style = const ListStyle(),
129+
}) {
125130
return buildPiece((b) {
126131
b.modifier(constKeyword);
127132
b.visit(typeArguments);

lib/src/piece/assign.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,9 @@ class AssignPiece extends Piece {
114114

115115
writer.format(target);
116116
writer.splitIf(state == _atOperator);
117-
if (_indentInValue) {
117+
118+
// We need extra indentation when there's no inner splitting of the value.
119+
if (!_allowInnerSplit && _indentInValue) {
118120
writer.setIndent(Indent.expression * 2);
119121
}
120122
writer.format(value);

test/pattern/list.stmt

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
40 columns |
2+
>>> Basic list patterns.
3+
switch (obj) {
4+
case [ ] :
5+
case < int > [ ] :
6+
case [ 2 ] :
7+
case [ 2 , ] :
8+
case [ 2 , 3 ] :
9+
ok;
10+
}
11+
<<<
12+
switch (obj) {
13+
case []:
14+
case <int>[]:
15+
case [2]:
16+
case [2]:
17+
case [2, 3]:
18+
ok;
19+
}
20+
>>> Unsplit list.
21+
if (obj case [1, ...var x, 3]) {;}
22+
<<<
23+
if (obj case [1, ...var x, 3]) {
24+
;
25+
}
26+
>>> If it splits anywhere in the list, it splits at every element.
27+
if (obj case [first,second,third,fourth]) {;}
28+
<<<
29+
if (obj case [
30+
first,
31+
second,
32+
third,
33+
fourth,
34+
]) {
35+
;
36+
}
37+
>>> Unsplit short list even with a comma.
38+
if (obj case [1,]) {;}
39+
<<<
40+
if (obj case [1]) {
41+
;
42+
}
43+
>>> Nested list patterns don't force outer to split
44+
if (obj case [[1, 2], [[3]]]) {;}
45+
<<<
46+
if (obj case [[1, 2], [[3]]]) {
47+
;
48+
}
49+
>>> Split all elements and keep line comment on newline.
50+
if (obj case [
51+
// yeah
52+
a,b,c,
53+
d,e,f,
54+
]) {;}
55+
<<<
56+
if (obj case [
57+
// yeah
58+
a,
59+
b,
60+
c,
61+
d,
62+
e,
63+
f,
64+
]) {
65+
;
66+
}
67+
>>> Split in type argument, but not in the body.
68+
if (obj case <Map<VeryLongTypeArgument, VeryLongTypeArgument>>[e]) {;}
69+
<<<
70+
if (obj case <
71+
Map<
72+
VeryLongTypeArgument,
73+
VeryLongTypeArgument
74+
>
75+
>[e]) {
76+
;
77+
}
78+
>>> Split in type argument and body.
79+
if (obj case <Map<VeryLongTypeArgument, VeryLongTypeArgument>>[element,VeryLongElementElementElement]) {;}
80+
<<<
81+
if (obj case <
82+
Map<
83+
VeryLongTypeArgument,
84+
VeryLongTypeArgument
85+
>
86+
>[
87+
element,
88+
VeryLongElementElementElement,
89+
]) {
90+
;
91+
}

0 commit comments

Comments
 (0)