File tree Expand file tree Collapse file tree 7 files changed +73
-5
lines changed Expand file tree Collapse file tree 7 files changed +73
-5
lines changed Original file line number Diff line number Diff line change @@ -135,7 +135,7 @@ final class GroupCode extends Code {
135135
136136/// A [Code] object for a newline followed by any leading indentation.
137137final class _NewlineCode extends Code {
138- /// True if a blank line (two newlines) should be written.
138+ /// Whether a blank line (two newlines) should be written.
139139 final bool _blank;
140140
141141 /// The number of spaces of indentation after this newline.
Original file line number Diff line number Diff line change @@ -199,6 +199,35 @@ final class CodeWriter {
199199 }
200200
201201 /// The 3.7 style of indentation and collapsible indentation tracking.
202+ ///
203+ /// Splits in if-case and for-in loop headers are tricky to indent gracefully.
204+ /// For example, if an infix expression inside the case splits, we don't want
205+ /// it to be double indented:
206+ ///
207+ /// if (object
208+ /// case veryLongConstant
209+ /// as VeryLongType) {
210+ /// ;
211+ /// }
212+ ///
213+ /// That suggests that the [IfCasePiece] shouldn't add indentation for the
214+ /// case pattern since the [InfixPiece] inside it will already indent the RHS.
215+ ///
216+ /// But if the case is a variable pattern that splits, the [VariablePiece]
217+ /// does *not* add indentation because in most other places where it occurs,
218+ /// that's what we want. If the [IfCasePiece] doesn't indent the pattern, you
219+ /// get:
220+ ///
221+ /// if (object
222+ /// case VeryLongType
223+ /// veryLongVariable
224+ /// ) {
225+ /// ;
226+ /// }
227+ ///
228+ /// To deal with this, 3.7 had a notion of "collapsible" indentation. In 3.8
229+ /// and later, there is a different mechanism for merging indentation kinds.
230+ /// This function implements the former.
202231 void _pushIndentV37 (Indent indent, {bool canCollapse = false }) {
203232 var parentIndent = _indentStack.last.spaces;
204233 var parentCollapse = _indentStack.last.collapsible;
Original file line number Diff line number Diff line change @@ -23,7 +23,7 @@ import 'solver.dart';
2323/// indentation. When that happens, sharing this cache allows us to reuse that
2424/// cached subtree Solution.
2525final class SolutionCache {
26- /// True if this cache and all solutions in it use the 3.7 style solver.
26+ /// Whether this cache and all solutions in it use the 3.7 style solver.
2727 final bool isVersion37;
2828
2929 final _cache = < _Key , Solution > {};
Original file line number Diff line number Diff line change @@ -115,7 +115,7 @@ mixin PieceFactory {
115115
116116 NodeContext get parentContext;
117117
118- /// True if the code being formatted is at language version 3.7.
118+ /// Whether the code being formatted is at language version 3.7.
119119 bool get isVersion37 => formatter.languageVersion == Version (3 , 7 , 0 );
120120
121121 void visitNode (AstNode node, NodeContext context);
Original file line number Diff line number Diff line change @@ -6,7 +6,9 @@ import 'piece.dart';
66
77/// A piece for the 3.7 style of an assignment-like construct where an operator
88/// is followed by an expression but where the left side of the operator isn't
9- /// also an expression. Used for:
9+ /// also an expression.
10+ ///
11+ /// Used for:
1012///
1113/// - Assignment (`=` , `+=` , etc.)
1214/// - Named arguments (`:` )
Original file line number Diff line number Diff line change @@ -48,6 +48,43 @@ import 'piece.dart';
4848/// argument,
4949/// argument,
5050/// );
51+ ///
52+ /// A challenge with formatting call chains is how they look inside an
53+ /// assignment, named argument, or `=>` . We don't a newline in a call chain to
54+ /// force the surrounding assignment to split, because that's unnecessarily
55+ /// spread out:
56+ ///
57+ /// variable =
58+ /// target
59+ /// .method()
60+ /// .another();
61+ ///
62+ /// It's better as:
63+ ///
64+ /// variable = target
65+ /// .method()
66+ /// .another();
67+ ///
68+ /// But if the target itself splits, then we do want to force the assignment to
69+ /// split:
70+ ///
71+ /// // Worse:
72+ /// variable = (veryLongTarget +
73+ /// anotherOperand)
74+ /// .method()
75+ /// .another();
76+ ///
77+ /// // Better:
78+ /// variable =
79+ /// (veryLongTarget
80+ /// anotherOperand)
81+ /// .method()
82+ /// .another();
83+ ///
84+ /// The 3.7 formatter had a limited ability to handle code like the above. In
85+ /// 3.8 and later, [Shape.headline] lets us express the constraint we want here
86+ /// directly. Since the logic is different, there are two different [ChainPiece]
87+ /// subclasses for each.
5188abstract base class ChainPiece extends Piece {
5289 /// Allow newlines in the last (or next-to-last) call but nowhere else.
5390 static const State _blockFormatTrailingCall = State (1 , cost: 0 );
Original file line number Diff line number Diff line change @@ -52,7 +52,7 @@ final class ConstructorPiece extends Piece {
5252
5353 static const _splitBetweenInitializers = State (2 , cost: 2 );
5454
55- /// True if there are parameters or comments inside the parameter list.
55+ /// Whether there are parameters or comments inside the parameter list.
5656 ///
5757 /// If so, then we allow splitting the parameter list while leaving the `:`
5858 /// on the same line as the `)` .
You can’t perform that action at this time.
0 commit comments