Indent the parameter list more if the body is a wrapped "=>". Fix #144.
BUG=https://github.com/dart-lang/dart_style/issues/144
R=pquitslund@google.com
Review URL: https://chromiumcodereview.appspot.com//889943004
diff --git a/CHANGELOG.md b/CHANGELOG.md
index edb23db..8852031 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@
list is split across multiple lines (#151).
* Allow splitting in index operator calls (#140).
* Handle sync* and async* syntax (#151).
+* Indent the parameter list more if the body is a wrapped "=>" (#144).
# 0.1.2
diff --git a/lib/src/source_visitor.dart b/lib/src/source_visitor.dart
index ad089ff..a741e7c 100644
--- a/lib/src/source_visitor.dart
+++ b/lib/src/source_visitor.dart
@@ -460,7 +460,6 @@
visitConstructorDeclaration(ConstructorDeclaration node) {
visitMemberMetadata(node.metadata);
- _writer.nestExpression();
modifier(node.externalKeyword);
modifier(node.constKeyword);
modifier(node.factoryKeyword);
@@ -473,18 +472,14 @@
// line that the initialization list gets pushed to its own line too.
if (node.initializers.length == 1) _writer.startMultisplit();
- visit(node.parameters);
-
- // Check for redirects or initializer lists.
- if (node.redirectedConstructor != null) {
- _visitConstructorRedirects(node);
- } else if (node.initializers.isNotEmpty) {
- _visitConstructorInitializers(node);
- }
-
- _writer.unnest();
-
- visitBody(node.body);
+ _visitBody(node.parameters, node.body, () {
+ // Check for redirects or initializer lists.
+ if (node.redirectedConstructor != null) {
+ _visitConstructorRedirects(node);
+ } else if (node.initializers.isNotEmpty) {
+ _visitConstructorInitializers(node);
+ }
+ });
}
void _visitConstructorInitializers(ConstructorDeclaration node) {
@@ -714,6 +709,7 @@
}
visitFormalParameterList(FormalParameterList node) {
+ _writer.nestExpression();
token(node.leftParenthesis);
// Allow splitting after the "(" in non-empty parameter lists, but not for
@@ -758,6 +754,7 @@
token(node.rightDelimiter);
token(node.rightParenthesis);
+ _writer.unnest();
_writer.endSpan();
}
@@ -829,8 +826,7 @@
}
visitFunctionExpression(FunctionExpression node) {
- visit(node.parameters);
- visitBody(node.body);
+ _visitBody(node.parameters, node.body);
}
visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
@@ -1009,18 +1005,14 @@
visitMethodDeclaration(MethodDeclaration node) {
visitMemberMetadata(node.metadata);
- _writer.nestExpression();
modifier(node.externalKeyword);
modifier(node.modifierKeyword);
visit(node.returnType, after: space);
modifier(node.propertyKeyword);
modifier(node.operatorKeyword);
visit(node.name);
- if (!node.isGetter) visit(node.parameters);
- _writer.unnest();
-
- visitBody(node.body);
+ _visitBody(node.parameters, node.body);
}
visitMethodInvocation(MethodInvocation node) {
@@ -1485,9 +1477,29 @@
visitNodes(metadata, between: space, after: space);
}
- /// Visit the given function [body], printing a space before it if it's not
- /// empty.
- void visitBody(FunctionBody body) {
+ /// Visit the given function [parameters] followed by its [body], printing a
+ /// space before it if it's not empty.
+ ///
+ /// If [afterParameters] is provided, it is invoked between the parameters
+ /// and body. (It's used for constructor initialization lists.)
+ void _visitBody(FormalParameterList parameters, FunctionBody body,
+ [afterParameters()]) {
+ if (parameters != null) {
+ // If the body is "=>", add an extra level of indentation around the
+ // parameters. This ensures that if they wrap, they wrap more deeply than
+ // the "=>" does, as in:
+ //
+ // someFunction(parameter,
+ // parameter, parameter) =>
+ // "the body";
+ if (body is ExpressionFunctionBody) _writer.nestExpression();
+
+ visit(parameters);
+ if (afterParameters != null) afterParameters();
+
+ if (body is ExpressionFunctionBody) _writer.unnest();
+ }
+
if (body is! EmptyFunctionBody) space();
visit(body);
}
diff --git a/test/regression/144.unit b/test/regression/144.unit
new file mode 100644
index 0000000..8880048
--- /dev/null
+++ b/test/regression/144.unit
@@ -0,0 +1,26 @@
+>>>
+class Selector {
+ factory Selector.call(String name,
+ LibraryElement library,
+ int arity,
+ [List<String> namedArguments])
+ => new Selector(SelectorKind.CALL, name, library, arity, namedArguments);
+}
+<<<
+class Selector {
+ factory Selector.call(String name, LibraryElement library, int arity,
+ [List<String> namedArguments]) =>
+ new Selector(SelectorKind.CALL, name, library, arity, namedArguments);
+}
+>>> a knock-on issue caused by the initial fix for the above
+class Foo {
+ get getter => "result";
+
+ // Comment.
+}
+<<<
+class Foo {
+ get getter => "result";
+
+ // Comment.
+}
\ No newline at end of file
diff --git a/test/splitting/constructors.unit b/test/splitting/constructors.unit
index 0d7e474..99a932e 100644
--- a/test/splitting/constructors.unit
+++ b/test/splitting/constructors.unit
@@ -47,4 +47,14 @@
Foo(int longArg1, int longArg2,
int longArg3)
: this._(longArg1);
-}
\ No newline at end of file
+}
+>>> indent parameters more if body is a wrapped =>
+class Foo {
+ Foo(firstArgument, secondArgument, third) => "very long body that must wrap";
+}
+<<<
+class Foo {
+ Foo(firstArgument, secondArgument,
+ third) =>
+ "very long body that must wrap";
+}
diff --git a/test/splitting/parameters.unit b/test/splitting/parameters.unit
index 986eaa1..56d43f2 100644
--- a/test/splitting/parameters.unit
+++ b/test/splitting/parameters.unit
@@ -8,3 +8,9 @@
Foo(this.first, this.second,
this.third, this.fourth);
}
+>>> indent parameters more if body is a wrapped =>
+method(int firstArgument, int argumentTwo) => "very long body that must wrap";
+<<<
+method(int firstArgument,
+ int argumentTwo) =>
+ "very long body that must wrap";
\ No newline at end of file