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.
diff --git a/benchmark/case/curry.expect b/benchmark/case/curry.expect
new file mode 100644
index 0000000..f6641a8
--- /dev/null
+++ b/benchmark/case/curry.expect
@@ -0,0 +1,54 @@
+// Test deeply nested lambdas.
+main() {
+  success(
+        (x1) =>
+            (x2) =>
+                (x3) =>
+                    (x4) =>
+                        (x5) =>
+                            (x6) =>
+                                (x7) =>
+                                    (x8) =>
+                                        (x9) =>
+                                            (x10) =>
+                                                (x11) =>
+                                                    (x12) =>
+                                                        (x13) =>
+                                                            (x14) =>
+                                                                (x15) =>
+                                                                    (x16) => [
+                                                                      x1,
+                                                                      x2,
+                                                                      x3,
+                                                                      x4,
+                                                                      x5,
+                                                                      x6,
+                                                                      x7,
+                                                                      x8,
+                                                                      x9,
+                                                                      x10,
+                                                                      x11,
+                                                                      x12,
+                                                                      x13,
+                                                                      x14,
+                                                                      x15,
+                                                                      x16,
+                                                                    ],
+      ) *
+      p1 *
+      p2 *
+      p3 *
+      p4 *
+      p5 *
+      p6 *
+      p7 *
+      p8 *
+      p9 *
+      p10 *
+      p11 *
+      p12 *
+      p13 *
+      p14 *
+      p15 *
+      p16;
+}
diff --git a/benchmark/case/curry.expect_short b/benchmark/case/curry.expect_short
new file mode 100644
index 0000000..7832b14
--- /dev/null
+++ b/benchmark/case/curry.expect_short
@@ -0,0 +1,39 @@
+// Test deeply nested lambdas.
+main() {
+  success((x1) => (x2) => (x3) => (x4) => (x5) => (x6) => (x7) => (x8) =>
+          (x9) => (x10) => (x11) => (x12) => (x13) => (x14) => (x15) => (x16) =>
+              [
+                x1,
+                x2,
+                x3,
+                x4,
+                x5,
+                x6,
+                x7,
+                x8,
+                x9,
+                x10,
+                x11,
+                x12,
+                x13,
+                x14,
+                x15,
+                x16
+              ]) *
+      p1 *
+      p2 *
+      p3 *
+      p4 *
+      p5 *
+      p6 *
+      p7 *
+      p8 *
+      p9 *
+      p10 *
+      p11 *
+      p12 *
+      p13 *
+      p14 *
+      p15 *
+      p16;
+}
diff --git a/benchmark/case/curry.unit b/benchmark/case/curry.unit
new file mode 100644
index 0000000..d314855
--- /dev/null
+++ b/benchmark/case/curry.unit
@@ -0,0 +1,7 @@
+// Test deeply nested lambdas.
+main() {
+success((x1) => (x2) => (x3) => (x4) => (x5) => (x6) => (x7) => (x8) => (x9) =>
+(x10) => (x11) => (x12) => (x13) => (x14) => (x15) => (x16) => [x1, x2, x3, x4,
+x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16]) * p1 * p2 * p3 * p4 *
+p5 * p6 * p7 * p8 * p9 * p10 * p11 * p12 * p13 * p14 * p15 * p16;
+}
\ No newline at end of file
diff --git a/lib/src/piece/assign.dart b/lib/src/piece/assign.dart
index 4f27803..52bb8da 100644
--- a/lib/src/piece/assign.dart
+++ b/lib/src/piece/assign.dart
@@ -206,4 +206,44 @@
     callback(_operator);
     callback(_right);
   }
+
+  @override
+  State? fixedStateForPageWidth(int pageWidth) {
+    // If either side (or both) can block split, then they may allow a long
+    // assignment to still not end up splitting at the operator.
+    if (_canBlockSplitLeft || _canBlockSplitRight) return null;
+
+    // Edge case: If the left operand is only a single character, then splitting
+    // at the operator won't actually make the line any smaller, so don't apply
+    // the optimization in that case:
+    //
+    //     e = someVeryLongExpression;
+    //
+    // Is no worse than:
+    //
+    //     e =
+    //         someVeryLongExpression;
+    if (_left case var left? when left.totalCharacters == 1) return null;
+
+    // If either operand contains a newline or the whole assignment doesn't
+    // fit then it will split at the operator since there's no other way it
+    // can split because there are no block operands.
+    var totalLength = 0;
+    if (_left case var left? when !_canBlockSplitLeft) {
+      if (left.containsNewline) return _atOperator;
+
+      totalLength += left.totalCharacters;
+    }
+
+    totalLength += _operator.totalCharacters;
+
+    if (!_canBlockSplitRight) {
+      if (_right.containsNewline) return _atOperator;
+      totalLength += _right.totalCharacters;
+    }
+
+    if (totalLength > pageWidth) return _atOperator;
+
+    return null;
+  }
 }