Skip to content

Commit 1cc5a25

Browse files
authored
Eagerly bind AssignPiece if it can't block split and operands don't fit. (#1477)
Eagerly bind AssignPiece if it can't block split and operands don't fit. If neither of the two operands to an AssignPiece can be block formatted, and they contain newlines or the whole thing doesn't fit the page width, then the AssignPiece will definitely split at the operator. This optimization helps a few rare cases (like deeply nested curried-style functions) from going pathological. I noticed it when migrating one of the regression tests over. It doesn't have a noticeable affect on formatting the whole Flutter repo, but it doesn't hurt either.
1 parent 1e3b808 commit 1cc5a25

File tree

4 files changed

+140
-0
lines changed

4 files changed

+140
-0
lines changed

benchmark/case/curry.expect

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Test deeply nested lambdas.
2+
main() {
3+
success(
4+
(x1) =>
5+
(x2) =>
6+
(x3) =>
7+
(x4) =>
8+
(x5) =>
9+
(x6) =>
10+
(x7) =>
11+
(x8) =>
12+
(x9) =>
13+
(x10) =>
14+
(x11) =>
15+
(x12) =>
16+
(x13) =>
17+
(x14) =>
18+
(x15) =>
19+
(x16) => [
20+
x1,
21+
x2,
22+
x3,
23+
x4,
24+
x5,
25+
x6,
26+
x7,
27+
x8,
28+
x9,
29+
x10,
30+
x11,
31+
x12,
32+
x13,
33+
x14,
34+
x15,
35+
x16,
36+
],
37+
) *
38+
p1 *
39+
p2 *
40+
p3 *
41+
p4 *
42+
p5 *
43+
p6 *
44+
p7 *
45+
p8 *
46+
p9 *
47+
p10 *
48+
p11 *
49+
p12 *
50+
p13 *
51+
p14 *
52+
p15 *
53+
p16;
54+
}

benchmark/case/curry.expect_short

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Test deeply nested lambdas.
2+
main() {
3+
success((x1) => (x2) => (x3) => (x4) => (x5) => (x6) => (x7) => (x8) =>
4+
(x9) => (x10) => (x11) => (x12) => (x13) => (x14) => (x15) => (x16) =>
5+
[
6+
x1,
7+
x2,
8+
x3,
9+
x4,
10+
x5,
11+
x6,
12+
x7,
13+
x8,
14+
x9,
15+
x10,
16+
x11,
17+
x12,
18+
x13,
19+
x14,
20+
x15,
21+
x16
22+
]) *
23+
p1 *
24+
p2 *
25+
p3 *
26+
p4 *
27+
p5 *
28+
p6 *
29+
p7 *
30+
p8 *
31+
p9 *
32+
p10 *
33+
p11 *
34+
p12 *
35+
p13 *
36+
p14 *
37+
p15 *
38+
p16;
39+
}

benchmark/case/curry.unit

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Test deeply nested lambdas.
2+
main() {
3+
success((x1) => (x2) => (x3) => (x4) => (x5) => (x6) => (x7) => (x8) => (x9) =>
4+
(x10) => (x11) => (x12) => (x13) => (x14) => (x15) => (x16) => [x1, x2, x3, x4,
5+
x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16]) * p1 * p2 * p3 * p4 *
6+
p5 * p6 * p7 * p8 * p9 * p10 * p11 * p12 * p13 * p14 * p15 * p16;
7+
}

lib/src/piece/assign.dart

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,4 +206,44 @@ class AssignPiece extends Piece {
206206
callback(_operator);
207207
callback(_right);
208208
}
209+
210+
@override
211+
State? fixedStateForPageWidth(int pageWidth) {
212+
// If either side (or both) can block split, then they may allow a long
213+
// assignment to still not end up splitting at the operator.
214+
if (_canBlockSplitLeft || _canBlockSplitRight) return null;
215+
216+
// Edge case: If the left operand is only a single character, then splitting
217+
// at the operator won't actually make the line any smaller, so don't apply
218+
// the optimization in that case:
219+
//
220+
// e = someVeryLongExpression;
221+
//
222+
// Is no worse than:
223+
//
224+
// e =
225+
// someVeryLongExpression;
226+
if (_left case var left? when left.totalCharacters == 1) return null;
227+
228+
// If either operand contains a newline or the whole assignment doesn't
229+
// fit then it will split at the operator since there's no other way it
230+
// can split because there are no block operands.
231+
var totalLength = 0;
232+
if (_left case var left? when !_canBlockSplitLeft) {
233+
if (left.containsNewline) return _atOperator;
234+
235+
totalLength += left.totalCharacters;
236+
}
237+
238+
totalLength += _operator.totalCharacters;
239+
240+
if (!_canBlockSplitRight) {
241+
if (_right.containsNewline) return _atOperator;
242+
totalLength += _right.totalCharacters;
243+
}
244+
245+
if (totalLength > pageWidth) return _atOperator;
246+
247+
return null;
248+
}
209249
}

0 commit comments

Comments
 (0)