Better handling for binary operators in => bodies.
Treat them specially in two ways:
- Don't increase the expression nesting.
- Force the => to split if the body does.
This has the nice effect of lining up all operands, even the first:
function() =>
expression ||
expression ||
expression;
Fix #434.
R=kevmoo@google.com
Review URL: https://codereview.chromium.org//1504553002 .
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 28a7dd8..93ae7dd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@
* Better indentation of collection literals (#421, #469).
* Only show a hidden directory once in the output (#428).
* Allow splitting between type and variable name (#429, #439, #454).
+* Better indentation for binary operators in `=>` bodies (#434.
* Tweak splitting around assignment (#436, #437).
* Indent multi-line collections in default values (#441).
* Don't drop metadata on part directives (#443).
diff --git a/lib/src/source_visitor.dart b/lib/src/source_visitor.dart
index 0da60dd..6c9f013 100644
--- a/lib/src/source_visitor.dart
+++ b/lib/src/source_visitor.dart
@@ -185,7 +185,17 @@
visitBinaryExpression(BinaryExpression node) {
builder.startSpan();
- builder.nestExpression();
+
+ // If a binary operator sequence appears immediately after a `=>`, don't
+ // add an extra level of nesting. Instead, let the subsequent operands line
+ // up with the first, as in:
+ //
+ // method() =>
+ // argument &&
+ // argument &&
+ // argument;
+ var isArrowBody = node.parent is ExpressionFunctionBody;
+ if (!isArrowBody) builder.nestExpression();
// Start lazily so we don't force the operator to split if a line comment
// appears before the first operand.
@@ -217,7 +227,7 @@
builder.endBlockArgumentNesting();
- builder.unnest();
+ if (!isArrowBody) builder.unnest();
builder.endSpan();
builder.endRule();
}
@@ -715,7 +725,10 @@
// Split after the "=>", using the rule created before the parameters
// by _visitBody().
split();
- builder.endRule();
+
+ // If the body is a binary operator expression, then we want to force the
+ // split at `=>` if the operators split. See visitBinaryExpression().
+ if (node.expression is! BinaryExpression) builder.endRule();
if (_isInLambda(node)) builder.endSpan();
@@ -725,6 +738,8 @@
builder.endSpan();
builder.endBlockArgumentNesting();
+ if (node.expression is BinaryExpression) builder.endRule();
+
token(node.semicolon);
}
diff --git a/test/regression/0000/0005.stmt b/test/regression/0000/0005.stmt
index e1d9b89..cba7a18 100644
--- a/test/regression/0000/0005.stmt
+++ b/test/regression/0000/0005.stmt
@@ -4,7 +4,8 @@
path.isWithin(rootDirectory, directory)).toList();
<<<
var overlapping = _directories.keys
- .where((directory) => path.isWithin(directory, rootDirectory) ||
+ .where((directory) =>
+ path.isWithin(directory, rootDirectory) ||
path.isWithin(rootDirectory, directory))
.toList();
>>>
diff --git a/test/regression/0000/0006.stmt b/test/regression/0000/0006.stmt
index ed8ad97..e7d45c2 100644
--- a/test/regression/0000/0006.stmt
+++ b/test/regression/0000/0006.stmt
@@ -10,5 +10,6 @@
messageMentions(id.toString()) ||
messageMentions(path.fromUri(entry.assetId.path));
<<<
-messageMentionsAsset(id) => messageMentions(id.toString()) ||
+messageMentionsAsset(id) =>
+ messageMentions(id.toString()) ||
messageMentions(path.fromUri(entry.assetId.path));
\ No newline at end of file
diff --git a/test/regression/0000/0026.stmt b/test/regression/0000/0026.stmt
index b5a1c7e..4fa6c76 100644
--- a/test/regression/0000/0026.stmt
+++ b/test/regression/0000/0026.stmt
@@ -6,4 +6,4 @@
<<<
experimentalBootstrap = document.querySelectorAll('link').any((link) =>
link.attributes['rel'] == 'import' &&
- link.attributes['href'] == POLYMER_EXPERIMENTAL_HTML);
\ No newline at end of file
+ link.attributes['href'] == POLYMER_EXPERIMENTAL_HTML);
\ No newline at end of file
diff --git a/test/regression/0000/0076.unit b/test/regression/0000/0076.unit
index 0c6dd96..632b8e1 100644
--- a/test/regression/0000/0076.unit
+++ b/test/regression/0000/0076.unit
@@ -4,7 +4,8 @@
}
<<<
class TokenType {
- bool get isUserDefinableOperator => identical(lexeme, "==") ||
+ bool get isUserDefinableOperator =>
+ identical(lexeme, "==") ||
identical(lexeme, "~") ||
identical(lexeme, "[]") ||
identical(lexeme, "[]=") ||
diff --git a/test/regression/0100/0130.unit b/test/regression/0100/0130.unit
index 8974b73..d63287b 100644
--- a/test/regression/0100/0130.unit
+++ b/test/regression/0100/0130.unit
@@ -4,7 +4,8 @@
_borderWidth +
clientY;
<<<
- int get screenY => window.screenTop +
+ int get screenY =>
+ window.screenTop +
window.outerHeight -
window.innerHeight -
_borderWidth +
diff --git a/test/regression/0400/0434.unit b/test/regression/0400/0434.unit
new file mode 100644
index 0000000..4089412
--- /dev/null
+++ b/test/regression/0400/0434.unit
@@ -0,0 +1,20 @@
+>>> (indent 2)
+ @eventHandler
+ bool computeChangePasswordDisabled(
+ String email, String password, String newPassword) =>
+ email == null ||
+ email.isEmpty ||
+ password == null ||
+ password.isEmpty ||
+ newPassword == null ||
+ newPassword.isEmpty;
+<<<
+ @eventHandler
+ bool computeChangePasswordDisabled(
+ String email, String password, String newPassword) =>
+ email == null ||
+ email.isEmpty ||
+ password == null ||
+ password.isEmpty ||
+ newPassword == null ||
+ newPassword.isEmpty;
\ No newline at end of file
diff --git a/test/splitting/mixed.stmt b/test/splitting/mixed.stmt
index 5e641cb..33cdba4 100644
--- a/test/splitting/mixed.stmt
+++ b/test/splitting/mixed.stmt
@@ -95,14 +95,15 @@
receiver.firstMethod().next((parameter) => longIdentifier == veryLongIdentifier);
<<<
receiver.firstMethod().next(
- (parameter) => longIdentifier ==
+ (parameter) =>
+ longIdentifier ==
veryLongIdentifier);
>>> wrap after =>
receiver.firstMethod().next(() => veryveryveryverylongIdentifier == veryLongIdentifier);
<<<
receiver.firstMethod().next(() =>
veryveryveryverylongIdentifier ==
- veryLongIdentifier);
+ veryLongIdentifier);
>>> wrap at nested binary operator
receiver.firstMethod().next(longIdentifier == veryLongIdentifier);
<<<
@@ -197,4 +198,16 @@
<<<
longIdentifier +
(longIdentifier ? 0 : 1) ==
- identifier;
\ No newline at end of file
+ identifier;
+>>> normal indent before unsplit binary operators in => body
+veryLongFunction() => extremelyLongArgument + argument;
+<<<
+veryLongFunction() =>
+ extremelyLongArgument + argument;
+>>> no extra indent before binary operators in => body
+veryLongFunction() => longArgument + longArgument + longArgument;
+<<<
+veryLongFunction() =>
+ longArgument +
+ longArgument +
+ longArgument;
\ No newline at end of file