diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ef13224..28c4d4c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # 1.0.1 * Ensure space between `-` and `--` (#170). +* Preserve a blank line between enum cases (#606). # 1.0.0 diff --git a/bin/format.dart b/bin/format.dart index 65a5d833..85f53e20 100644 --- a/bin/format.dart +++ b/bin/format.dart @@ -14,7 +14,7 @@ import 'package:dart_style/src/io.dart'; import 'package:dart_style/src/source_code.dart'; // Note: The following line of code is modified by tool/grind.dart. -const version = "1.0.0"; +const version = "1.0.1"; void main(List args) { var parser = new ArgParser(allowTrailingOptions: true); diff --git a/lib/src/argument_list_visitor.dart b/lib/src/argument_list_visitor.dart index 29125fa3..3d0f7dcc 100644 --- a/lib/src/argument_list_visitor.dart +++ b/lib/src/argument_list_visitor.dart @@ -236,18 +236,16 @@ class ArgumentListVisitor { // Allow functions wrapped in dotted method calls like "a.b.c(() { ... })". if (expression is MethodInvocation) { - var invocation = expression as MethodInvocation; - if (!_isValidWrappingTarget(invocation.target)) return false; - if (invocation.argumentList.arguments.length != 1) return false; + if (!_isValidWrappingTarget(expression.target)) return false; + if (expression.argumentList.arguments.length != 1) return false; - return _isBlockFunction(invocation.argumentList.arguments.single); + return _isBlockFunction(expression.argumentList.arguments.single); } if (expression is InstanceCreationExpression) { - var creation = expression as InstanceCreationExpression; - if (creation.argumentList.arguments.length != 1) return false; + if (expression.argumentList.arguments.length != 1) return false; - return _isBlockFunction(creation.argumentList.arguments.single); + return _isBlockFunction(expression.argumentList.arguments.single); } // Allow immediately-invoked functions like "() { ... }()". diff --git a/lib/src/chunk_builder.dart b/lib/src/chunk_builder.dart index 5678e8c9..e926859f 100644 --- a/lib/src/chunk_builder.dart +++ b/lib/src/chunk_builder.dart @@ -101,6 +101,7 @@ class ChunkBuilder { /// token pair. bool get needsToPreserveNewlines => _pendingWhitespace == Whitespace.oneOrTwoNewlines || + _pendingWhitespace == Whitespace.splitOrTwoNewlines || _pendingWhitespace == Whitespace.splitOrNewline; /// The number of characters of code that can fit in a single line. @@ -309,6 +310,15 @@ class ChunkBuilder { } break; + case Whitespace.splitOrTwoNewlines: + if (numLines > 1) { + _pendingWhitespace = Whitespace.twoNewlines; + } else { + _pendingWhitespace = Whitespace.none; + split(space: true); + } + break; + case Whitespace.oneOrTwoNewlines: if (numLines > 1) { _pendingWhitespace = Whitespace.twoNewlines; @@ -604,6 +614,7 @@ class ChunkBuilder { break; case Whitespace.splitOrNewline: + case Whitespace.splitOrTwoNewlines: case Whitespace.oneOrTwoNewlines: // We should have pinned these down before getting here. assert(false); diff --git a/lib/src/source_visitor.dart b/lib/src/source_visitor.dart index 22122f7a..faab9e88 100644 --- a/lib/src/source_visitor.dart +++ b/lib/src/source_visitor.dart @@ -842,7 +842,7 @@ class SourceVisitor extends ThrowingAstVisitor { space(); _beginBody(node.leftBracket, space: true); - visitCommaSeparatedNodes(node.constants, between: split); + visitCommaSeparatedNodes(node.constants, between: splitOrTwoNewlines); // If there is a trailing comma, always force the constants to split. if (node.constants.last.endToken.next.type == TokenType.COMMA) { @@ -2497,6 +2497,13 @@ class SourceVisitor extends ThrowingAstVisitor { builder.writeWhitespace(Whitespace.splitOrNewline); } + /// Allow either a single split or newline to be emitted before the next + /// non-whitespace token based on whether a newline exists in the source + /// between the last token and the next one. + void splitOrTwoNewlines() { + builder.writeWhitespace(Whitespace.splitOrTwoNewlines); + } + /// Allow either one or two newlines to be emitted before the next /// non-whitespace token based on whether more than one newline exists in the /// source between the last token and the next one. diff --git a/lib/src/whitespace.dart b/lib/src/whitespace.dart index 712d9d0b..c4050639 100644 --- a/lib/src/whitespace.dart +++ b/lib/src/whitespace.dart @@ -54,6 +54,16 @@ class Whitespace { /// less prescriptive over the user's whitespace. static const splitOrNewline = const Whitespace._("splitOrNewline"); + /// A split or blank line (two newlines) should be output based on whether + /// the current token is on the same line as the previous one or not. + /// + /// This is used between enum cases, which will collapse if possible but + /// also allow a blank line to be preserved between cases. + /// + /// In general, we like to avoid using this because it makes the formatter + /// less prescriptive over the user's whitespace. + static const splitOrTwoNewlines = const Whitespace._("splitOrTwoNewlines"); + /// One or two newlines should be output based on how many newlines are /// present between the next token and the previous one. /// diff --git a/pubspec.yaml b/pubspec.yaml index 46f9a3b6..b6d7c02a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: dart_style # Note: See tool/grind.dart for how to bump the version. -version: 1.0.1-dev +version: 1.0.1 author: Dart Team description: Opinionated, automatic Dart source code formatter. homepage: https://github.com/dart-lang/dart_style diff --git a/test/regression/0600/0606.unit b/test/regression/0600/0606.unit new file mode 100644 index 00000000..0a65246e --- /dev/null +++ b/test/regression/0600/0606.unit @@ -0,0 +1,118 @@ +>>> +enum ErrorKind { + AbstractNotSync, + AsciiControlCharacter, + AsyncAsIdentifier, + AwaitAsIdentifier, + AwaitForNotAsync, + AwaitNotAsync, + BuiltInIdentifierAsType, + BuiltInIdentifierInDeclaration, + EmptyNamedParameterList, + EmptyOptionalParameterList, + Encoding, + ExpectedBlockToSkip, + ExpectedBody, + ExpectedButGot, + ExpectedClassBody, + + /// This error code can be used to support non-compliant (with respect to + /// Dart Language Specification) Dart VM native clauses. See + /// [dart_vm_native.dart]. + ExpectedClassBodyToSkip, + + ExpectedDeclaration, + ExpectedExpression, + ExpectedFunctionBody, + ExpectedHexDigit, + ExpectedIdentifier, + ExpectedOpenParens, + ExpectedString, + ExpectedType, + ExtraneousModifier, + ExtraneousModifierReplace, + FactoryNotSync, + GeneratorReturnsValue, + InvalidAwaitFor, + InvalidInlineFunctionType, + InvalidSyncModifier, + InvalidVoid, + MissingExponent, + NonAsciiIdentifier, + NonAsciiWhitespace, + OnlyTry, + PositionalParameterWithEquals, + RequiredParameterWithDefault, + SetterNotSync, + StackOverflow, + UnexpectedDollarInString, + UnexpectedToken, + UnmatchedToken, + UnsupportedPrefixPlus, + UnterminatedComment, + UnterminatedString, + UnterminatedToken, + YieldAsIdentifier, + YieldNotGenerator, + + Unspecified, +} +<<< +enum ErrorKind { + AbstractNotSync, + AsciiControlCharacter, + AsyncAsIdentifier, + AwaitAsIdentifier, + AwaitForNotAsync, + AwaitNotAsync, + BuiltInIdentifierAsType, + BuiltInIdentifierInDeclaration, + EmptyNamedParameterList, + EmptyOptionalParameterList, + Encoding, + ExpectedBlockToSkip, + ExpectedBody, + ExpectedButGot, + ExpectedClassBody, + + /// This error code can be used to support non-compliant (with respect to + /// Dart Language Specification) Dart VM native clauses. See + /// [dart_vm_native.dart]. + ExpectedClassBodyToSkip, + + ExpectedDeclaration, + ExpectedExpression, + ExpectedFunctionBody, + ExpectedHexDigit, + ExpectedIdentifier, + ExpectedOpenParens, + ExpectedString, + ExpectedType, + ExtraneousModifier, + ExtraneousModifierReplace, + FactoryNotSync, + GeneratorReturnsValue, + InvalidAwaitFor, + InvalidInlineFunctionType, + InvalidSyncModifier, + InvalidVoid, + MissingExponent, + NonAsciiIdentifier, + NonAsciiWhitespace, + OnlyTry, + PositionalParameterWithEquals, + RequiredParameterWithDefault, + SetterNotSync, + StackOverflow, + UnexpectedDollarInString, + UnexpectedToken, + UnmatchedToken, + UnsupportedPrefixPlus, + UnterminatedComment, + UnterminatedString, + UnterminatedToken, + YieldAsIdentifier, + YieldNotGenerator, + + Unspecified, +} \ No newline at end of file diff --git a/test/whitespace/enums.unit b/test/whitespace/enums.unit index ac05e427..26c2271c 100644 --- a/test/whitespace/enums.unit +++ b/test/whitespace/enums.unit @@ -1,23 +1,53 @@ 40 columns | >>> single -enum Unity {ONE} +enum Unity {one} <<< -enum Unity { ONE } +enum Unity { one } >>> single line -enum Primate{BONOBO,CHIMP,GORILLA} +enum Primate{bonobo,chimp,gorilla} <<< -enum Primate { BONOBO, CHIMP, GORILLA } +enum Primate { bonobo, chimp, gorilla } >>> trailing comma always splits -enum Primate{BONOBO,CHIMP,} +enum Primate{bonobo,chimp,} <<< enum Primate { - BONOBO, - CHIMP, + bonobo, + chimp, } >>> metadata @Awesome @Fierce("really") -enum Primate{BONOBO,CHIMP,GORILLA} +enum Primate{bonobo,chimp,gorilla} <<< @Awesome @Fierce("really") -enum Primate { BONOBO, CHIMP, GORILLA } \ No newline at end of file +enum Primate { bonobo, chimp, gorilla } +>>> preserve one blank line between enums +enum Primate { + + + bonobo, + + + chimp, + + + + gorilla + +} +<<< +enum Primate { + bonobo, + + chimp, + + gorilla +} +>>> do not preserve single newline +enum Primate { + bonobo, + chimp, + gorilla +} +<<< +enum Primate { bonobo, chimp, gorilla } \ No newline at end of file