Formatting support for spread and if control flow elements.
(I'll do "for" in a separate commit.)
diff --git a/lib/src/argument_list_visitor.dart b/lib/src/argument_list_visitor.dart
index c71b9f0..c17264c 100644
--- a/lib/src/argument_list_visitor.dart
+++ b/lib/src/argument_list_visitor.dart
@@ -453,7 +453,7 @@
rule.disableSplitOnInnerRules();
// Tell it to use the rule we've already created.
- visitor.beforeBlock(_blocks[argument], this);
+ visitor.beforeBlock(_blocks[argument], blockRule, previousSplit);
} else if (_allArguments.length > 1) {
// Edge case: Only bump the nesting if there are multiple arguments. This
// lets us avoid spurious indentation in cases like:
diff --git a/lib/src/dart_formatter.dart b/lib/src/dart_formatter.dart
index afd0626..4a3950c 100644
--- a/lib/src/dart_formatter.dart
+++ b/lib/src/dart_formatter.dart
@@ -114,6 +114,9 @@
// Parse it.
var parser = new Parser(stringSource, errorListener);
parser.enableOptionalNewAndConst = true;
+ parser.enableSetLiterals = true;
+ parser.enableSpreadCollections = true;
+ parser.enableControlFlowCollections = true;
AstNode node;
if (source.isCompilationUnit) {
diff --git a/lib/src/nesting_builder.dart b/lib/src/nesting_builder.dart
index 2efebb3..544ab57 100644
--- a/lib/src/nesting_builder.dart
+++ b/lib/src/nesting_builder.dart
@@ -64,22 +64,11 @@
NestingLevel get currentNesting =>
_pendingNesting != null ? _pendingNesting : _nesting;
- /// The top "nesting level" that represents no expression nesting for the
- /// current block.
- NestingLevel get blockNesting {
- // Walk the nesting levels until we bottom out.
- var result = _nesting;
- while (result.parent != null) {
- result = result.parent;
- }
- return result;
- }
-
/// Creates a new indentation level [spaces] deeper than the current one.
///
/// If omitted, [spaces] defaults to [Indent.block].
void indent([int spaces]) {
- if (spaces == null) spaces = Indent.block;
+ spaces ??= Indent.block;
// Indentation should only change outside of nesting.
assert(_pendingNesting == null);
diff --git a/lib/src/source_visitor.dart b/lib/src/source_visitor.dart
index 6aa452a..85c02e1 100644
--- a/lib/src/source_visitor.dart
+++ b/lib/src/source_visitor.dart
@@ -153,7 +153,12 @@
/// Before a block argument is visited, [ArgumentSublist] binds itself to the
/// beginning token of each block it controls. When we later visit that
/// literal, we use the token to find that association.
- final Map<Token, ArgumentSublist> _blockArgumentLists = {};
+ ///
+ /// This mapping is also used for spread collection literals that appear
+ /// inside control flow elements to ensure that when a "then" collection
+ /// splits, the corresponding "else" one does too.
+ final Map<Token, Rule> _blockRules = {};
+ final Map<Token, Chunk> _blockPreviousChunks = {};
/// Initialize a newly created visitor to write source code representing
/// the visited nodes to the given [writer].
@@ -1387,6 +1392,121 @@
_visitCombinator(node.keyword, node.hiddenNames);
}
+ void visitIfElement(IfElement node) {
+ // Wrap the whole thing in a single rule. If a split happens inside the
+ // condition or the then clause, we want the then and else clauses to split.
+ builder.startRule();
+
+ token(node.ifKeyword);
+ space();
+ token(node.leftParenthesis);
+ visit(node.condition);
+ token(node.rightParenthesis);
+
+ // If the body of the then or else branch is a spread of a collection
+ // literal, then we want to format those collections more like blocks than
+ // like standalone objects. In particular, if both the then and else branch
+ // are spread collection literals, we want to ensure that they both split
+ // if either splits. So this:
+ //
+ // [
+ // if (condition) ...[
+ // thenClause
+ // ] else ...[
+ // elseClause
+ // ]
+ // ]
+ //
+ // And not something like this:
+ //
+ // [
+ // if (condition) ...[
+ // thenClause
+ // ] else ...[elseClause]
+ // ]
+ //
+ // To do that, if we see that either clause is a spread collection, we
+ // create a single rule and force both collections to use it.
+ var thenSpreadBracket = _findSpreadCollectionBracket(node.thenElement);
+ var elseSpreadBracket = _findSpreadCollectionBracket(node.elseElement);
+
+ if (thenSpreadBracket != null || elseSpreadBracket != null) {
+ var spreadRule = Rule();
+ if (thenSpreadBracket != null) {
+ beforeBlock(thenSpreadBracket, spreadRule, null);
+ }
+
+ if (elseSpreadBracket != null) {
+ beforeBlock(elseSpreadBracket, spreadRule, null);
+ }
+ }
+
+ builder.nestExpression(indent: 2, now: true);
+
+ // Treat a spread of a collection literal like a block in an if statement
+ // and don't split after the "else".
+ if (thenSpreadBracket != null) {
+ space();
+ } else {
+ split();
+
+ // If the then clause is a non-spread collection or lambda, make sure the
+ // body is indented.
+ builder.startBlockArgumentNesting();
+ }
+
+ visit(node.thenElement);
+
+ if (thenSpreadBracket == null) builder.endBlockArgumentNesting();
+ builder.unnest();
+
+ if (node.elseElement != null) {
+ if (thenSpreadBracket != null) {
+ space();
+ } else {
+ split();
+ }
+
+ token(node.elseKeyword);
+
+ builder.nestExpression(indent: 2, now: true);
+
+ if (elseSpreadBracket != null) {
+ space();
+ } else {
+ split();
+
+ // If the else clause is a non-spread collection or lambda, make sure
+ // the body is indented.
+ builder.startBlockArgumentNesting();
+ }
+
+ visit(node.elseElement);
+
+ if (elseSpreadBracket == null) builder.endBlockArgumentNesting();
+ builder.unnest();
+ }
+
+ builder.endRule();
+ }
+
+ /// If [node] is a spread of a collection literal, then this returns the
+ /// token for the opening bracket of the collection, as in:
+ ///
+ /// [ ...[a, list] ]
+ /// // ^
+ ///
+ /// Otherwise, returns `null`.
+ Token _findSpreadCollectionBracket(AstNode node) {
+ if (node is SpreadElement) {
+ var expression = node.expression;
+ if (expression is ListLiteral) return expression.leftBracket;
+ if (expression is SetOrMapLiteral) return expression.leftBracket;
+ }
+
+ return null;
+ }
+
visitIfStatement(IfStatement node) {
builder.nestExpression();
token(node.ifKeyword);
@@ -1611,10 +1731,12 @@
}
visitMapLiteralEntry(MapLiteralEntry node) {
+ builder.nestExpression();
visit(node.key);
token(node.separator);
soloSplit();
visit(node.value);
+ builder.unnest();
}
visitMethodDeclaration(MethodDeclaration node) {
@@ -1882,6 +2004,11 @@
_writeStringLiteral(node.literal);
}
+ visitSpreadElement(SpreadElement node) {
+ token(node.spreadOperator);
+ visit(node.expression);
+ }
+
visitStringInterpolation(StringInterpolation node) {
for (var element in node.elements) {
visit(element);
@@ -2511,15 +2638,12 @@
}
}
- builder.nestExpression();
visit(element);
// The comma after the element.
if (element.endToken.next.type == TokenType.COMMA) {
token(element.endToken.next);
}
-
- builder.unnest();
}
builder.endRule();
@@ -2741,14 +2865,17 @@
void _startLiteralBody(Token leftBracket) {
token(leftBracket);
- // See if this literal is associated with an argument list that wants to
- // handle splitting and indenting it. If not, we'll use a default rule.
- var rule;
- var argumentChunk;
- if (_blockArgumentLists.containsKey(leftBracket)) {
- var argumentList = _blockArgumentLists[leftBracket];
- rule = argumentList.blockRule;
- argumentChunk = argumentList.previousSplit;
+ // See if this literal is associated with an argument list or if element
+ // that wants to handle splitting and indenting it. If not, we'll use a
+ // default rule.
+ Rule rule;
+ if (_blockRules.containsKey(leftBracket)) {
+ rule = _blockRules[leftBracket];
+ }
+
+ Chunk argumentChunk;
+ if (_blockPreviousChunks.containsKey(leftBracket)) {
+ argumentChunk = _blockPreviousChunks[leftBracket];
}
// Create a rule for whether or not to split the block contents.
@@ -2844,12 +2971,15 @@
}
/// Marks the block that starts with [token] as being controlled by
- /// [argumentList].
+ /// [rule] and following [previousChunk].
///
- /// When the block is visited, [argumentList] will determine the
- /// indentation and splitting rule for the block.
- void beforeBlock(Token token, ArgumentSublist argumentList) {
- _blockArgumentLists[token] = argumentList;
+ /// When the block is visited, these will determine the indentation and
+ /// splitting rule for the block. These are used for handling block-like
+ /// expressions inside argument lists and spread collections inside if
+ /// elements.
+ void beforeBlock(Token token, Rule rule, [Chunk previousChunk]) {
+ _blockRules[token] = rule;
+ if (previousChunk != null) _blockPreviousChunks[token] = previousChunk;
}
/// Writes the beginning of a brace-delimited body and handles indenting and
diff --git a/test/splitting/list_collection_if.stmt b/test/splitting/list_collection_if.stmt
new file mode 100644
index 0000000..7f272a7
--- /dev/null
+++ b/test/splitting/list_collection_if.stmt
@@ -0,0 +1,217 @@
+40 columns |
+>>> split in condition
+var list = [1, if (veryLongConditionExpression || anotherPart) 2];
+<<<
+var list = [
+ 1,
+ if (veryLongConditionExpression ||
+ anotherPart)
+ 2
+];
+>>> without else on one line
+var list = [1, if (c) 2, 3];
+<<<
+var list = [1, if (c) 2, 3];
+>>> with else on one line
+var list = [1, if (c) 2 else 2, 3];
+<<<
+var list = [1, if (c) 2 else 2, 3];
+>>> split collection before if
+var list = [if (c) somewhatLongThingHere];
+<<<
+var list = [
+ if (c) somewhatLongThingHere
+];
+>>> one line in multi-line
+var list = [veryLongThingThatForcesASplit, if (c) 2, 3];
+<<<
+var list = [
+ veryLongThingThatForcesASplit,
+ if (c) 2,
+ 3
+];
+>>> one line in multi-line with else
+var list = [veryLongThingThatForcesASplit, if (c) 2 else 2, 3];
+<<<
+var list = [
+ veryLongThingThatForcesASplit,
+ if (c) 2 else 2,
+ 3
+];
+>>> long then branch forces split
+var list = [1, if (condition) veryLongThingThatForcesASplit, 3];
+<<<
+var list = [
+ 1,
+ if (condition)
+ veryLongThingThatForcesASplit,
+ 3
+];
+>>> long then branch forces both to split
+var list = [1, if (condition) veryLongThingThatForcesASplit else 2, 3];
+<<<
+var list = [
+ 1,
+ if (condition)
+ veryLongThingThatForcesASplit
+ else
+ 2,
+ 3
+];
+>>> long else branch forces both to split
+var list = [1, if (condition) 2 else veryLongThingThatForcesASplit, 3];
+<<<
+var list = [
+ 1,
+ if (condition)
+ 2
+ else
+ veryLongThingThatForcesASplit,
+ 3
+];
+>>> split inside then
+var list = [1, if (condition) veryLongThingThatForcesASplit + anotherLongThing, 3];
+<<<
+var list = [
+ 1,
+ if (condition)
+ veryLongThingThatForcesASplit +
+ anotherLongThing,
+ 3
+];
+>>> split inside else
+var list = [1, if (condition) ok else veryLongThingThatForcesASplit + anotherLongThing, 3];
+<<<
+var list = [
+ 1,
+ if (condition)
+ ok
+ else
+ veryLongThingThatForcesASplit +
+ anotherLongThing,
+ 3
+];
+>>> trailing comma
+var list = [if (c) 2,];
+<<<
+var list = [
+ if (c) 2,
+];
+>>> spread list inside if stays on one line if it fits
+var list = [if (c) ...[1, 2]];
+<<<
+var list = [
+ if (c) ...[1, 2]
+];
+>>> spread list inside if formats like block if it splits
+var list = [if (c) ...[1, 2,]];
+<<<
+var list = [
+ if (c) ...[
+ 1,
+ 2,
+ ]
+];
+>>> both spreads split if then must
+var list = [if (c) ...[1, 2,] else ...[1, 2]];
+<<<
+var list = [
+ if (c) ...[
+ 1,
+ 2,
+ ] else ...[
+ 1,
+ 2
+ ]
+];
+>>> both spreads split if else must
+var list = [if (c) ...[1, 2] else ...[1, 2,]];
+<<<
+var list = [
+ if (c) ...[
+ 1,
+ 2
+ ] else ...[
+ 1,
+ 2,
+ ]
+];
+>>> a split collection that isn't spread wraps and indents
+var list = [if (c) [1,2,]];
+<<<
+var list = [
+ if (c)
+ [
+ 1,
+ 2,
+ ]
+];
+>>> a split collection that isn't spread wraps and indents
+var list = [if (c) [1,2,] else thing];
+<<<
+var list = [
+ if (c)
+ [
+ 1,
+ 2,
+ ]
+ else
+ thing
+];
+>>> a split collection that isn't spread wraps and indents
+var list = [if (c) thing else [1,2,]];
+<<<
+var list = [
+ if (c)
+ thing
+ else
+ [
+ 1,
+ 2,
+ ]
+];
+>>> lambda inside then
+var list = [if (c) () { body; }];
+<<<
+var list = [
+ if (c)
+ () {
+ body;
+ }
+];
+>>> lambda inside else
+var list = [if (c) thing else () { body; }];
+<<<
+var list = [
+ if (c)
+ thing
+ else
+ () {
+ body;
+ }
+];
+>>> nested if doesn't split if it fits
+var list = [if (c) if (d) thing];
+<<<
+var list = [if (c) if (d) thing];
+>>> split collection before nested if
+var list = [if (c) if (d) fairlyLongThingHere];
+<<<
+var list = [
+ if (c) if (d) fairlyLongThingHere
+];
+>>> just split outer if
+var list = [if (condition) if (another) longThingHereThatIsLong];
+<<<
+var list = [
+ if (condition)
+ if (another) longThingHereThatIsLong
+];
+>>> split inside condition
+var list = [if (veryLongCondition + thatNeedsToSplit) thing];
+<<<
+var list = [
+ if (veryLongCondition +
+ thatNeedsToSplit)
+ thing
+];
\ No newline at end of file
diff --git a/test/splitting/lists.stmt b/test/splitting/lists.stmt
index 86698f6..4b45a1e 100644
--- a/test/splitting/lists.stmt
+++ b/test/splitting/lists.stmt
@@ -167,4 +167,28 @@
element,
element
+];
+>>> a spread list literal splits an outer list even if it fits
+var list = [1, ...[2, 3], 4];
+<<<
+var list = [
+ 1,
+ ...[2, 3],
+ 4
+];
+>>> spread empty list does not force outer split
+var list = [1, ...[], 4];
+<<<
+var list = [1, ...[], 4];
+>>> split inside spread expression
+var list = [1, ...some + very + long + spread + expression, 3];
+<<<
+var list = [
+ 1,
+ ...some +
+ very +
+ long +
+ spread +
+ expression,
+ 3
];
\ No newline at end of file
diff --git a/test/splitting/map_collection_if.stmt b/test/splitting/map_collection_if.stmt
new file mode 100644
index 0000000..ef4758a
--- /dev/null
+++ b/test/splitting/map_collection_if.stmt
@@ -0,0 +1,203 @@
+40 columns |
+>>> split in condition
+var map = {1: 1, if (veryLongConditionExpression || anotherPart) 2: 2};
+<<<
+var map = {
+ 1: 1,
+ if (veryLongConditionExpression ||
+ anotherPart)
+ 2: 2
+};
+>>> without else on one line
+var map = {1: 1, if (c) 2: 2, 3: 3};
+<<<
+var map = {1: 1, if (c) 2: 2, 3: 3};
+>>> with else on one line
+var map = {1: 1, if (c) 2: 2 else 2: 2};
+<<<
+var map = {1: 1, if (c) 2: 2 else 2: 2};
+>>> split collection before if
+var map = {if (c) somewhatLongThingHere: 1};
+<<<
+var map = {
+ if (c) somewhatLongThingHere: 1
+};
+>>> one line in multi-line
+var map = {veryLongThingThatForcesASplit, if (c) 2: 2, 3: 3};
+<<<
+var map = {
+ veryLongThingThatForcesASplit,
+ if (c) 2: 2,
+ 3: 3
+};
+>>> one line in multi-line with else
+var map = {veryLongThingThatForcesASplit: 1, if (c) 2: 2 else 2: 2, 3: 3};
+<<<
+var map = {
+ veryLongThingThatForcesASplit: 1,
+ if (c) 2: 2 else 2: 2,
+ 3: 3
+};
+>>> long then branch forces split
+var map = {1: 1, if (condition) veryLongThingThatForcesASplit: 2, 3: 3};
+<<<
+var map = {
+ 1: 1,
+ if (condition)
+ veryLongThingThatForcesASplit: 2,
+ 3: 3
+};
+>>> long then branch forces both to split
+var map = {1: 1, if (condition) veryLongThingThatForcesASplit: 2 else 2: 2, 3: 3};
+<<<
+var map = {
+ 1: 1,
+ if (condition)
+ veryLongThingThatForcesASplit: 2
+ else
+ 2: 2,
+ 3: 3
+};
+>>> long else branch forces both to split
+var map = {1: 1, if (condition) 2: 2 else veryLongThingThatForcesASplit: 2, 3: 3};
+<<<
+var map = {
+ 1: 1,
+ if (condition)
+ 2: 2
+ else
+ veryLongThingThatForcesASplit: 2,
+ 3: 3
+};
+>>> trailing comma
+var map = {if (c) 2: 2,};
+<<<
+var map = {
+ if (c) 2: 2,
+};
+>>> spread list inside if stays on one line if it fits
+var map = {if (c) ...{1: 1, 2: 2}};
+<<<
+var map = {
+ if (c) ...{1: 1, 2: 2}
+};
+>>> spread list inside if formats like block if it splits
+var map = {if (c) ...{1: 1, 2: 2,}};
+<<<
+var map = {
+ if (c) ...{
+ 1: 1,
+ 2: 2,
+ }
+};
+>>> both spreads split if then must
+var map = {if (c) ...{1: 1, 2: 2,} else ...{1: 1, 2: 2}};
+<<<
+var map = {
+ if (c) ...{
+ 1: 1,
+ 2: 2,
+ } else ...{
+ 1: 1,
+ 2: 2
+ }
+};
+>>> both spreads split if else must
+var map = {if (c) ...{1: 1, 2: 2} else ...{1: 1, 2: 2,}};
+<<<
+var map = {
+ if (c) ...{
+ 1: 1,
+ 2: 2
+ } else ...{
+ 1: 1,
+ 2: 2,
+ }
+};
+>>> a split collection that isn't spread wraps and indents
+var map = {if (c) {1: 1,2: 2,}};
+<<<
+var map = {
+ if (c)
+ {
+ 1: 1,
+ 2: 2,
+ }
+};
+>>> a split collection that isn't spread wraps and indents
+var map = {if (c) {1: 1,2: 2,} else thing: 3};
+<<<
+var map = {
+ if (c)
+ {
+ 1: 1,
+ 2: 2,
+ }
+ else
+ thing: 3
+};
+>>> a split collection that isn't spread wraps and indents
+var map = {if (c) thing: 0 else {1: 1,2: 2,}};
+<<<
+var map = {
+ if (c)
+ thing: 0
+ else
+ {
+ 1: 1,
+ 2: 2,
+ }
+};
+>>> lambda inside then
+var map = {if (c) k: () { body; }};
+<<<
+var map = {
+ if (c)
+ k: () {
+ body;
+ }
+};
+>>> lambda inside else
+var map = {if (c) thing: 1 else k: () { body; }};
+<<<
+var map = {
+ if (c)
+ thing: 1
+ else
+ k: () {
+ body;
+ }
+};
+>>> nested if doesn't split if it fits
+var map = {if (c) if (d) thing: 1};
+<<<
+var map = {if (c) if (d) thing: 1};
+>>> split collection before nested if
+var map = {if (c) if (d) fairlyLongThingHere: 1};
+<<<
+var map = {
+ if (c) if (d) fairlyLongThingHere: 1
+};
+>>> just split outer if
+var map = {if (condition) if (another) longThingThatIsLong: 1};
+<<<
+var map = {
+ if (condition)
+ if (another) longThingThatIsLong: 1
+};
+>>> split inside condition
+var map = {if (veryLongCondition + thatNeedsToSplit) thing: 1};
+<<<
+var map = {
+ if (veryLongCondition +
+ thatNeedsToSplit)
+ thing: 1
+};
+>>> split entry inside if
+var map = { if (condition) veryLongKeyExpression: andAVeryLongValueExpression};
+<<<
+var map = {
+ if (condition)
+ veryLongKeyExpression:
+ andAVeryLongValueExpression
+};
\ No newline at end of file
diff --git a/test/splitting/set_collection_if.stmt b/test/splitting/set_collection_if.stmt
new file mode 100644
index 0000000..86375ad
--- /dev/null
+++ b/test/splitting/set_collection_if.stmt
@@ -0,0 +1,195 @@
+40 columns |
+>>> split in condition
+var set = {1, if (veryLongConditionExpression || anotherPart) 2};
+<<<
+var set = {
+ 1,
+ if (veryLongConditionExpression ||
+ anotherPart)
+ 2
+};
+>>> without else on one line
+var set = {1, if (c) 2, 3};
+<<<
+var set = {1, if (c) 2, 3};
+>>> with else on one line
+var set = {1, if (c) 2 else 2, 3};
+<<<
+var set = {1, if (c) 2 else 2, 3};
+>>> split collection before if
+var set = {if (c) somewhatLongThingHere};
+<<<
+var set = {
+ if (c) somewhatLongThingHere
+};
+>>> one line in multi-line
+var set = {veryLongThingThatForcesASplit, if (c) 2, 3};
+<<<
+var set = {
+ veryLongThingThatForcesASplit,
+ if (c) 2,
+ 3
+};
+>>> one line in multi-line with else
+var set = {veryLongThingThatForcesASplit, if (c) 2 else 2, 3};
+<<<
+var set = {
+ veryLongThingThatForcesASplit,
+ if (c) 2 else 2,
+ 3
+};
+>>> long then branch forces split
+var set = {1, if (condition) veryLongThingThatForcesASplit, 3};
+<<<
+var set = {
+ 1,
+ if (condition)
+ veryLongThingThatForcesASplit,
+ 3
+};
+>>> long then branch forces both to split
+var set = {1, if (condition) veryLongThingThatForcesASplit else 2, 3};
+<<<
+var set = {
+ 1,
+ if (condition)
+ veryLongThingThatForcesASplit
+ else
+ 2,
+ 3
+};
+>>> long else branch forces both to split
+var set = {1, if (condition) 2 else veryLongThingThatForcesASplit, 3};
+<<<
+var set = {
+ 1,
+ if (condition)
+ 2
+ else
+ veryLongThingThatForcesASplit,
+ 3
+};
+>>> trailing comma
+var set = {if (c) 2,};
+<<<
+var set = {
+ if (c) 2,
+};
+>>> spread list inside if stays on one line if it fits
+var set = {if (c) ...{1, 2}};
+<<<
+var set = {
+ if (c) ...{1, 2}
+};
+>>> spread list inside if formats like block if it splits
+var set = {if (c) ...{1, 2,}};
+<<<
+var set = {
+ if (c) ...{
+ 1,
+ 2,
+ }
+};
+>>> both spreads split if then must
+var set = {if (c) ...{1, 2,} else ...{1, 2}};
+<<<
+var set = {
+ if (c) ...{
+ 1,
+ 2,
+ } else ...{
+ 1,
+ 2
+ }
+};
+>>> both spreads split if else must
+var set = {if (c) ...{1, 2} else ...{1, 2,}};
+<<<
+var set = {
+ if (c) ...{
+ 1,
+ 2
+ } else ...{
+ 1,
+ 2,
+ }
+};
+>>> a split collection that isn't spread wraps and indents
+var set = {if (c) {1,2,}};
+<<<
+var set = {
+ if (c)
+ {
+ 1,
+ 2,
+ }
+};
+>>> a split collection that isn't spread wraps and indents
+var set = {if (c) {1,2,} else thing};
+<<<
+var set = {
+ if (c)
+ {
+ 1,
+ 2,
+ }
+ else
+ thing
+};
+>>> a split collection that isn't spread wraps and indents
+var set = {if (c) thing else {1,2,}};
+<<<
+var set = {
+ if (c)
+ thing
+ else
+ {
+ 1,
+ 2,
+ }
+};
+>>> lambda inside then
+var set = {if (c) () { body; }};
+<<<
+var set = {
+ if (c)
+ () {
+ body;
+ }
+};
+>>> lambda inside else
+var set = {if (c) thing else () { body; }};
+<<<
+var set = {
+ if (c)
+ thing
+ else
+ () {
+ body;
+ }
+};
+>>> nested if doesn't split if it fits
+var set = {if (c) if (d) thing};
+<<<
+var set = {if (c) if (d) thing};
+>>> split collection before nested if
+var set = {if (c) if (d) fairlyLongThingHere};
+<<<
+var set = {
+ if (c) if (d) fairlyLongThingHere
+};
+>>> just split outer if
+var set = {if (condition) if (another) longThingHereThatIsLong};
+<<<
+var set = {
+ if (condition)
+ if (another) longThingHereThatIsLong
+};
+>>> split inside condition
+var set = {if (veryLongCondition + thatNeedsToSplit) thing};
+<<<
+var set = {
+ if (veryLongCondition +
+ thatNeedsToSplit)
+ thing
+};
\ No newline at end of file
diff --git a/test/whitespace/collections.stmt b/test/whitespace/collections.stmt
new file mode 100644
index 0000000..bcf7119
--- /dev/null
+++ b/test/whitespace/collections.stmt
@@ -0,0 +1,59 @@
+40 columns |
+>>> empty map literal (dartbug.com/16382)
+var m = { };
+<<<
+var m = {};
+>>>
+var m = {};
+<<<
+var m = {};
+>>> generic map literal
+< int,int >{ };
+<<<
+<int, int>{};
+>>> generic set literal
+< int >{ };
+<<<
+<int>{};
+>>> list spread
+var list = [ ... a,...b, ...
+c];
+<<<
+var list = [...a, ...b, ...c];
+>>> map spread
+var map = { ... a,...b,1:2, ...
+c};
+<<<
+var map = {...a, ...b, 1: 2, ...c};
+>>> set spread
+var set = { ... a,...b, 1, ...
+c};
+<<<
+var set = {...a, ...b, 1, ...c};
+>>> list null aware spread
+var list = [ ...? a,...?b, ...?
+c];
+<<<
+var list = [...?a, ...?b, ...?c];
+>>> map null aware spread
+var map = { ...? a,...?b,1:2, ...?
+c};
+<<<
+var map = {...?a, ...?b, 1: 2, ...?c};
+>>> set null aware spread
+var set = { ...? a,...?b, 1, ...?
+c};
+<<<
+var set = {...?a, ...?b, 1, ...?c};
+>>> if
+var list = [ if ( c ) 1 ,];
+<<<
+var list = [
+ if (c) 1,
+];
+>>> if else
+var list = [ if ( c ) 1 else 2 ,];
+<<<
+var list = [
+ if (c) 1 else 2,
+];
\ No newline at end of file
diff --git a/test/whitespace/expressions.stmt b/test/whitespace/expressions.stmt
index c1ed6b2..10980d5 100644
--- a/test/whitespace/expressions.stmt
+++ b/test/whitespace/expressions.stmt
@@ -32,22 +32,6 @@
y;
<<<
x && y;
->>> empty map literal (dartbug.com/16382)
-var m = { };
-<<<
-var m = {};
->>>
-var m = {};
-<<<
-var m = {};
->>> generic map literal
-< int,int >{ };
-<<<
-<int, int>{};
->>> generic set literal
-< int >{ };
-<<<
-<int>{};
>>> unqualified symbol
var x = #foo;
<<<