| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart_style.src.source_visitor; | 5 library dart_style.src.source_visitor; |
| 6 | 6 |
| 7 import 'package:analyzer/analyzer.dart'; | 7 import 'package:analyzer/analyzer.dart'; |
| 8 import 'package:analyzer/src/generated/scanner.dart'; | 8 import 'package:analyzer/src/generated/scanner.dart'; |
| 9 import 'package:analyzer/src/generated/source.dart'; | 9 import 'package:analyzer/src/generated/source.dart'; |
| 10 | 10 |
| 11 import 'argument_list_visitor.dart'; | 11 import 'argument_list_visitor.dart'; |
| 12 import 'call_chain_visitor.dart'; | 12 import 'call_chain_visitor.dart'; |
| 13 import 'chunk.dart'; | 13 import 'chunk.dart'; |
| 14 import 'chunk_builder.dart'; | 14 import 'chunk_builder.dart'; |
| 15 import 'dart_formatter.dart'; | 15 import 'dart_formatter.dart'; |
| 16 import 'rule/argument.dart'; | 16 import 'rule/argument.dart'; |
| 17 import 'rule/combinator.dart'; | 17 import 'rule/combinator.dart'; |
| 18 import 'rule/metadata.dart'; |
| 18 import 'rule/rule.dart'; | 19 import 'rule/rule.dart'; |
| 19 import 'rule/type_argument.dart'; | 20 import 'rule/type_argument.dart'; |
| 20 import 'source_code.dart'; | 21 import 'source_code.dart'; |
| 21 import 'whitespace.dart'; | 22 import 'whitespace.dart'; |
| 22 | 23 |
| 23 /// Visits every token of the AST and passes all of the relevant bits to a | 24 /// Visits every token of the AST and passes all of the relevant bits to a |
| 24 /// [ChunkBuilder]. | 25 /// [ChunkBuilder]. |
| 25 class SourceVisitor implements AstVisitor { | 26 class SourceVisitor implements AstVisitor { |
| 26 /// The builder for the block that is currently being visited. | 27 /// The builder for the block that is currently being visited. |
| 27 ChunkBuilder builder; | 28 ChunkBuilder builder; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 40 | 41 |
| 41 /// `true` if the visitor has written past the end of the selection in the | 42 /// `true` if the visitor has written past the end of the selection in the |
| 42 /// original source text. | 43 /// original source text. |
| 43 bool _passedSelectionEnd = false; | 44 bool _passedSelectionEnd = false; |
| 44 | 45 |
| 45 /// The character offset of the end of the selection, if there is a selection. | 46 /// The character offset of the end of the selection, if there is a selection. |
| 46 /// | 47 /// |
| 47 /// This is calculated and cached by [_findSelectionEnd]. | 48 /// This is calculated and cached by [_findSelectionEnd]. |
| 48 int _selectionEnd; | 49 int _selectionEnd; |
| 49 | 50 |
| 50 /// The rule that should be used for the contents of a literal body that are | |
| 51 /// about to be written. | |
| 52 /// | |
| 53 /// This is set by [visitArgumentList] to ensure that all block arguments | |
| 54 /// share a rule. | |
| 55 /// | |
| 56 /// If `null`, a literal body creates its own rule. | |
| 57 Rule _nextLiteralBodyRule; | |
| 58 | |
| 59 /// A stack that tracks forcing nested collections to split. | 51 /// A stack that tracks forcing nested collections to split. |
| 60 /// | 52 /// |
| 61 /// Each entry corresponds to a collection currently being visited and the | 53 /// Each entry corresponds to a collection currently being visited and the |
| 62 /// value is whether or not it should be forced to split. Every time a | 54 /// value is whether or not it should be forced to split. Every time a |
| 63 /// collection is entered, it sets all of the existing elements to `true` | 55 /// collection is entered, it sets all of the existing elements to `true` |
| 64 /// then it pushes `false` for itself. | 56 /// then it pushes `false` for itself. |
| 65 /// | 57 /// |
| 66 /// When done visiting the elements, it removes its value. If it was set to | 58 /// When done visiting the elements, it removes its value. If it was set to |
| 67 /// `true`, we know we visited a nested collection so we force this one to | 59 /// `true`, we know we visited a nested collection so we force this one to |
| 68 /// split. | 60 /// split. |
| 69 final List<bool> _collectionSplits = []; | 61 final List<bool> _collectionSplits = []; |
| 70 | 62 |
| 63 /// The stack of current rules for handling parameter metadata. |
| 64 /// |
| 65 /// Each time a parameter (or type parameter) list is begun, a single rule |
| 66 /// for all of the metadata annotations on parameters in that list is pushed |
| 67 /// onto this stack. We reuse this rule for all annotations so that they split |
| 68 /// in unison. |
| 69 final List<MetadataRule> _metadataRules = []; |
| 70 |
| 71 /// The mapping for collection literals that are managed by the argument |
| 72 /// list that contains them. |
| 73 /// |
| 74 /// When a collection literal appears inside an [ArgumentSublist], the |
| 75 /// argument list provides a rule for the body to split to ensure that all |
| 76 /// collections split in unison. It also tracks the chunk before the |
| 77 /// argument that determines whether or not the collection body is indented |
| 78 /// like an expression or a statement. |
| 79 /// |
| 80 /// Before a collection literal argument is visited, [ArgumentSublist] binds |
| 81 /// itself to the left bracket token of each collection literal it controls. |
| 82 /// When we later visit that literal, we use the token to find that |
| 83 /// association. |
| 84 final Map<Token, ArgumentSublist> _collectionArgumentLists = {}; |
| 85 |
| 71 /// Initialize a newly created visitor to write source code representing | 86 /// Initialize a newly created visitor to write source code representing |
| 72 /// the visited nodes to the given [writer]. | 87 /// the visited nodes to the given [writer]. |
| 73 SourceVisitor(this._formatter, this._lineInfo, this._source) { | 88 SourceVisitor(this._formatter, this._lineInfo, this._source) { |
| 74 builder = new ChunkBuilder(_formatter, _source); | 89 builder = new ChunkBuilder(_formatter, _source); |
| 75 } | 90 } |
| 76 | 91 |
| 77 /// Runs the visitor on [node], formatting its contents. | 92 /// Runs the visitor on [node], formatting its contents. |
| 78 /// | 93 /// |
| 79 /// Returns a [SourceCode] containing the resulting formatted source and | 94 /// Returns a [SourceCode] containing the resulting formatted source and |
| 80 /// updated selection, if any. | 95 /// updated selection, if any. |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 163 } | 178 } |
| 164 | 179 |
| 165 visitAwaitExpression(AwaitExpression node) { | 180 visitAwaitExpression(AwaitExpression node) { |
| 166 token(node.awaitKeyword); | 181 token(node.awaitKeyword); |
| 167 space(); | 182 space(); |
| 168 visit(node.expression); | 183 visit(node.expression); |
| 169 } | 184 } |
| 170 | 185 |
| 171 visitBinaryExpression(BinaryExpression node) { | 186 visitBinaryExpression(BinaryExpression node) { |
| 172 builder.startSpan(); | 187 builder.startSpan(); |
| 173 builder.nestExpression(); | 188 |
| 189 // If a binary operator sequence appears immediately after a `=>`, don't |
| 190 // add an extra level of nesting. Instead, let the subsequent operands line |
| 191 // up with the first, as in: |
| 192 // |
| 193 // method() => |
| 194 // argument && |
| 195 // argument && |
| 196 // argument; |
| 197 var isArrowBody = node.parent is ExpressionFunctionBody; |
| 198 if (!isArrowBody) builder.nestExpression(); |
| 174 | 199 |
| 175 // Start lazily so we don't force the operator to split if a line comment | 200 // Start lazily so we don't force the operator to split if a line comment |
| 176 // appears before the first operand. | 201 // appears before the first operand. |
| 177 builder.startLazyRule(); | 202 builder.startLazyRule(); |
| 178 | 203 |
| 179 // Flatten out a tree/chain of the same precedence. If we split on this | 204 // Flatten out a tree/chain of the same precedence. If we split on this |
| 180 // precedence level, we will break all of them. | 205 // precedence level, we will break all of them. |
| 181 var precedence = node.operator.type.precedence; | 206 var precedence = node.operator.type.precedence; |
| 182 | 207 |
| 183 traverse(Expression e) { | 208 traverse(Expression e) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 195 } | 220 } |
| 196 | 221 |
| 197 // Blocks as operands to infix operators should always nest like regular | 222 // Blocks as operands to infix operators should always nest like regular |
| 198 // operands. (Granted, this case is exceedingly rare in real code.) | 223 // operands. (Granted, this case is exceedingly rare in real code.) |
| 199 builder.startBlockArgumentNesting(); | 224 builder.startBlockArgumentNesting(); |
| 200 | 225 |
| 201 traverse(node); | 226 traverse(node); |
| 202 | 227 |
| 203 builder.endBlockArgumentNesting(); | 228 builder.endBlockArgumentNesting(); |
| 204 | 229 |
| 205 builder.unnest(); | 230 if (!isArrowBody) builder.unnest(); |
| 206 builder.endSpan(); | 231 builder.endSpan(); |
| 207 builder.endRule(); | 232 builder.endRule(); |
| 208 } | 233 } |
| 209 | 234 |
| 210 visitBlock(Block node) { | 235 visitBlock(Block node) { |
| 236 // Don't allow splitting in an empty block. |
| 237 if (node.statements.isEmpty && |
| 238 node.rightBracket.precedingComments == null) { |
| 239 token(node.leftBracket); |
| 240 token(node.rightBracket); |
| 241 return; |
| 242 } |
| 243 |
| 211 // For a block that is not a function body, just bump the indentation and | 244 // For a block that is not a function body, just bump the indentation and |
| 212 // keep it in the current block. | 245 // keep it in the current block. |
| 213 if (node.parent is! BlockFunctionBody) { | 246 if (node.parent is! BlockFunctionBody) { |
| 214 _writeBody(node.leftBracket, node.rightBracket, body: () { | 247 _writeBody(node.leftBracket, node.rightBracket, body: () { |
| 215 visitNodes(node.statements, between: oneOrTwoNewlines, after: newline); | 248 visitNodes(node.statements, between: oneOrTwoNewlines, after: newline); |
| 216 }); | 249 }); |
| 217 return; | 250 return; |
| 218 } | 251 } |
| 219 | 252 |
| 220 _startLiteralBody(node.leftBracket); | 253 _startLiteralBody(node.leftBracket); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 277 builder.startBlockArgumentNesting(); | 310 builder.startBlockArgumentNesting(); |
| 278 | 311 |
| 279 // If the cascade sections have consistent names they can be broken | 312 // If the cascade sections have consistent names they can be broken |
| 280 // normally otherwise they always get their own line. | 313 // normally otherwise they always get their own line. |
| 281 if (_allowInlineCascade(node.cascadeSections)) { | 314 if (_allowInlineCascade(node.cascadeSections)) { |
| 282 builder.startRule(); | 315 builder.startRule(); |
| 283 zeroSplit(); | 316 zeroSplit(); |
| 284 visitNodes(node.cascadeSections, between: zeroSplit); | 317 visitNodes(node.cascadeSections, between: zeroSplit); |
| 285 builder.endRule(); | 318 builder.endRule(); |
| 286 } else { | 319 } else { |
| 287 builder.startRule(new HardSplitRule()); | 320 builder.startRule(new Rule.hard()); |
| 288 zeroSplit(); | 321 zeroSplit(); |
| 289 visitNodes(node.cascadeSections, between: zeroSplit); | 322 visitNodes(node.cascadeSections, between: zeroSplit); |
| 290 builder.endRule(); | 323 builder.endRule(); |
| 291 } | 324 } |
| 292 | 325 |
| 293 builder.endBlockArgumentNesting(); | 326 builder.endBlockArgumentNesting(); |
| 294 builder.unnest(); | 327 builder.unnest(); |
| 295 | 328 |
| 296 if (node.target is MethodInvocation) builder.unnest(); | 329 if (node.target is MethodInvocation) builder.unnest(); |
| 297 } | 330 } |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 508 modifier(node.factoryKeyword); | 541 modifier(node.factoryKeyword); |
| 509 visit(node.returnType); | 542 visit(node.returnType); |
| 510 token(node.period); | 543 token(node.period); |
| 511 visit(node.name); | 544 visit(node.name); |
| 512 | 545 |
| 513 // Make the rule for the ":" span both the preceding parameter list and | 546 // Make the rule for the ":" span both the preceding parameter list and |
| 514 // the entire initialization list. This ensures that we split before the | 547 // the entire initialization list. This ensures that we split before the |
| 515 // ":" if the parameters and initialization list don't all fit on one line. | 548 // ":" if the parameters and initialization list don't all fit on one line. |
| 516 builder.startRule(); | 549 builder.startRule(); |
| 517 | 550 |
| 551 // If the redirecting constructor happens to wrap, we want to make sure |
| 552 // the parameter list gets more deeply indented. |
| 553 if (node.redirectedConstructor != null) builder.nestExpression(); |
| 554 |
| 518 _visitBody(node.parameters, node.body, () { | 555 _visitBody(node.parameters, node.body, () { |
| 519 // Check for redirects or initializer lists. | 556 // Check for redirects or initializer lists. |
| 520 if (node.redirectedConstructor != null) { | 557 if (node.redirectedConstructor != null) { |
| 521 _visitConstructorRedirects(node); | 558 _visitConstructorRedirects(node); |
| 559 builder.unnest(); |
| 522 } else if (node.initializers.isNotEmpty) { | 560 } else if (node.initializers.isNotEmpty) { |
| 523 _visitConstructorInitializers(node); | 561 _visitConstructorInitializers(node); |
| 524 } | 562 } |
| 525 }); | 563 }); |
| 526 } | 564 } |
| 527 | 565 |
| 528 void _visitConstructorRedirects(ConstructorDeclaration node) { | 566 void _visitConstructorRedirects(ConstructorDeclaration node) { |
| 529 token(node.separator /* = */, before: space, after: space); | 567 token(node.separator /* = */, before: space); |
| 568 soloSplit(); |
| 530 visitCommaSeparatedNodes(node.initializers); | 569 visitCommaSeparatedNodes(node.initializers); |
| 531 visit(node.redirectedConstructor); | 570 visit(node.redirectedConstructor); |
| 532 } | 571 } |
| 533 | 572 |
| 534 void _visitConstructorInitializers(ConstructorDeclaration node) { | 573 void _visitConstructorInitializers(ConstructorDeclaration node) { |
| 535 // Shift the ":" forward. | 574 // Shift the ":" forward. |
| 536 builder.indent(Indent.constructorInitializer); | 575 builder.indent(Indent.constructorInitializer); |
| 537 | 576 |
| 538 split(); | 577 split(); |
| 539 token(node.separator); // ":". | 578 token(node.separator); // ":". |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 593 visitDefaultFormalParameter(DefaultFormalParameter node) { | 632 visitDefaultFormalParameter(DefaultFormalParameter node) { |
| 594 visit(node.parameter); | 633 visit(node.parameter); |
| 595 if (node.separator != null) { | 634 if (node.separator != null) { |
| 596 builder.startSpan(); | 635 builder.startSpan(); |
| 597 builder.nestExpression(); | 636 builder.nestExpression(); |
| 598 | 637 |
| 599 // The '=' separator is preceded by a space, ":" is not. | 638 // The '=' separator is preceded by a space, ":" is not. |
| 600 if (node.separator.type == TokenType.EQ) space(); | 639 if (node.separator.type == TokenType.EQ) space(); |
| 601 token(node.separator); | 640 token(node.separator); |
| 602 | 641 |
| 603 soloSplit(Cost.assignment); | 642 soloSplit(_assignmentCost(node.defaultValue)); |
| 604 visit(node.defaultValue); | 643 visit(node.defaultValue); |
| 605 | 644 |
| 606 builder.unnest(); | 645 builder.unnest(); |
| 607 builder.endSpan(); | 646 builder.endSpan(); |
| 608 } | 647 } |
| 609 } | 648 } |
| 610 | 649 |
| 611 visitDoStatement(DoStatement node) { | 650 visitDoStatement(DoStatement node) { |
| 612 _simpleStatement(node, () { | 651 builder.nestExpression(); |
| 613 token(node.doKeyword); | 652 token(node.doKeyword); |
| 614 space(); | 653 space(); |
| 615 visit(node.body); | 654 builder.unnest(now: false); |
| 616 space(); | 655 visit(node.body); |
| 617 token(node.whileKeyword); | 656 |
| 618 space(); | 657 builder.nestExpression(); |
| 619 token(node.leftParenthesis); | 658 space(); |
| 620 soloZeroSplit(); | 659 token(node.whileKeyword); |
| 621 visit(node.condition); | 660 space(); |
| 622 token(node.rightParenthesis); | 661 token(node.leftParenthesis); |
| 623 }); | 662 soloZeroSplit(); |
| 663 visit(node.condition); |
| 664 token(node.rightParenthesis); |
| 665 token(node.semicolon); |
| 666 builder.unnest(); |
| 624 } | 667 } |
| 625 | 668 |
| 626 visitDoubleLiteral(DoubleLiteral node) { | 669 visitDoubleLiteral(DoubleLiteral node) { |
| 627 token(node.literal); | 670 token(node.literal); |
| 628 } | 671 } |
| 629 | 672 |
| 630 visitEmptyFunctionBody(EmptyFunctionBody node) { | 673 visitEmptyFunctionBody(EmptyFunctionBody node) { |
| 631 token(node.semicolon); | 674 token(node.semicolon); |
| 632 } | 675 } |
| 633 | 676 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 675 | 718 |
| 676 // Try to keep the "(...) => " with the start of the body for anonymous | 719 // Try to keep the "(...) => " with the start of the body for anonymous |
| 677 // functions. | 720 // functions. |
| 678 if (_isInLambda(node)) builder.startSpan(); | 721 if (_isInLambda(node)) builder.startSpan(); |
| 679 | 722 |
| 680 token(node.functionDefinition); // "=>". | 723 token(node.functionDefinition); // "=>". |
| 681 | 724 |
| 682 // Split after the "=>", using the rule created before the parameters | 725 // Split after the "=>", using the rule created before the parameters |
| 683 // by _visitBody(). | 726 // by _visitBody(). |
| 684 split(); | 727 split(); |
| 685 builder.endRule(); | 728 |
| 729 // If the body is a binary operator expression, then we want to force the |
| 730 // split at `=>` if the operators split. See visitBinaryExpression(). |
| 731 if (node.expression is! BinaryExpression) builder.endRule(); |
| 686 | 732 |
| 687 if (_isInLambda(node)) builder.endSpan(); | 733 if (_isInLambda(node)) builder.endSpan(); |
| 688 | 734 |
| 689 builder.startBlockArgumentNesting(); | 735 builder.startBlockArgumentNesting(); |
| 690 builder.startSpan(); | 736 builder.startSpan(); |
| 691 visit(node.expression); | 737 visit(node.expression); |
| 692 builder.endSpan(); | 738 builder.endSpan(); |
| 693 builder.endBlockArgumentNesting(); | 739 builder.endBlockArgumentNesting(); |
| 694 | 740 |
| 741 if (node.expression is BinaryExpression) builder.endRule(); |
| 742 |
| 695 token(node.semicolon); | 743 token(node.semicolon); |
| 696 } | 744 } |
| 697 | 745 |
| 698 visitExpressionStatement(ExpressionStatement node) { | 746 visitExpressionStatement(ExpressionStatement node) { |
| 699 _simpleStatement(node, () { | 747 _simpleStatement(node, () { |
| 700 visit(node.expression); | 748 visit(node.expression); |
| 701 }); | 749 }); |
| 702 } | 750 } |
| 703 | 751 |
| 704 visitExtendsClause(ExtendsClause node) { | 752 visitExtendsClause(ExtendsClause node) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 737 if (node.loopVariable != null) { | 785 if (node.loopVariable != null) { |
| 738 visit(node.loopVariable); | 786 visit(node.loopVariable); |
| 739 } else { | 787 } else { |
| 740 visit(node.identifier); | 788 visit(node.identifier); |
| 741 } | 789 } |
| 742 soloSplit(); | 790 soloSplit(); |
| 743 token(node.inKeyword); | 791 token(node.inKeyword); |
| 744 space(); | 792 space(); |
| 745 visit(node.iterable); | 793 visit(node.iterable); |
| 746 token(node.rightParenthesis); | 794 token(node.rightParenthesis); |
| 747 space(); | 795 builder.unnest(now: false); |
| 748 visit(node.body); | 796 |
| 749 builder.unnest(); | 797 _visitLoopBody(node.body); |
| 750 } | 798 } |
| 751 | 799 |
| 752 visitFormalParameterList(FormalParameterList node) { | 800 visitFormalParameterList(FormalParameterList node) { |
| 753 // Corner case: empty parameter lists. | 801 // Corner case: empty parameter lists. |
| 754 if (node.parameters.isEmpty) { | 802 if (node.parameters.isEmpty) { |
| 755 token(node.leftParenthesis); | 803 token(node.leftParenthesis); |
| 756 | 804 |
| 757 // If there is a comment, do allow splitting before it. | 805 // If there is a comment, do allow splitting before it. |
| 758 if (node.rightParenthesis.precedingComments != null) soloZeroSplit(); | 806 if (node.rightParenthesis.precedingComments != null) soloZeroSplit(); |
| 759 | 807 |
| 760 token(node.rightParenthesis); | 808 token(node.rightParenthesis); |
| 761 return; | 809 return; |
| 762 } | 810 } |
| 763 | 811 |
| 764 var requiredParams = node.parameters | 812 var requiredParams = node.parameters |
| 765 .where((param) => param is! DefaultFormalParameter) | 813 .where((param) => param is! DefaultFormalParameter) |
| 766 .toList(); | 814 .toList(); |
| 767 var optionalParams = node.parameters | 815 var optionalParams = node.parameters |
| 768 .where((param) => param is DefaultFormalParameter) | 816 .where((param) => param is DefaultFormalParameter) |
| 769 .toList(); | 817 .toList(); |
| 770 | 818 |
| 771 builder.nestExpression(); | 819 builder.nestExpression(); |
| 772 token(node.leftParenthesis); | 820 token(node.leftParenthesis); |
| 773 | 821 |
| 822 _metadataRules.add(new MetadataRule()); |
| 823 |
| 774 var rule; | 824 var rule; |
| 775 if (requiredParams.isNotEmpty) { | 825 if (requiredParams.isNotEmpty) { |
| 776 if (requiredParams.length > 1) { | 826 if (requiredParams.length > 1) { |
| 777 rule = new MultiplePositionalRule(null, 0, 0); | 827 rule = new MultiplePositionalRule(null, 0, 0); |
| 778 } else { | 828 } else { |
| 779 rule = new SinglePositionalRule(null); | 829 rule = new SinglePositionalRule(null); |
| 780 } | 830 } |
| 781 | 831 |
| 832 _metadataRules.last.bindPositionalRule(rule); |
| 833 |
| 782 builder.startRule(rule); | 834 builder.startRule(rule); |
| 783 if (_isInLambda(node)) { | 835 if (_isInLambda(node)) { |
| 784 // Don't allow splitting before the first argument (i.e. right after | 836 // Don't allow splitting before the first argument (i.e. right after |
| 785 // the bare "(" in a lambda. Instead, just stuff a null chunk in there | 837 // the bare "(" in a lambda. Instead, just stuff a null chunk in there |
| 786 // to avoid confusing the arg rule. | 838 // to avoid confusing the arg rule. |
| 787 rule.beforeArgument(null); | 839 rule.beforeArgument(null); |
| 788 } else { | 840 } else { |
| 789 // Split before the first argument. | 841 // Split before the first argument. |
| 790 rule.beforeArgument(zeroSplit()); | 842 rule.beforeArgument(zeroSplit()); |
| 791 } | 843 } |
| 792 | 844 |
| 793 builder.startSpan(); | 845 builder.startSpan(); |
| 794 | 846 |
| 795 for (var param in requiredParams) { | 847 for (var param in requiredParams) { |
| 796 visit(param); | 848 visit(param); |
| 797 | 849 |
| 798 // Write the trailing comma. | 850 // Write the trailing comma. |
| 799 if (param != node.parameters.last) token(param.endToken.next); | 851 if (param != node.parameters.last) token(param.endToken.next); |
| 800 | 852 |
| 801 if (param != requiredParams.last) rule.beforeArgument(split()); | 853 if (param != requiredParams.last) rule.beforeArgument(split()); |
| 802 } | 854 } |
| 803 | 855 |
| 804 builder.endSpan(); | 856 builder.endSpan(); |
| 805 builder.endRule(); | 857 builder.endRule(); |
| 806 } | 858 } |
| 807 | 859 |
| 808 if (optionalParams.isNotEmpty) { | 860 if (optionalParams.isNotEmpty) { |
| 809 var namedRule = new NamedRule(null); | 861 var namedRule = new NamedRule(null, 0, 0); |
| 810 if (rule != null) rule.setNamedArgsRule(namedRule); | 862 if (rule != null) rule.setNamedArgsRule(namedRule); |
| 811 | 863 |
| 864 _metadataRules.last.bindNamedRule(namedRule); |
| 865 |
| 812 builder.startRule(namedRule); | 866 builder.startRule(namedRule); |
| 813 | 867 |
| 814 namedRule | 868 // Make sure multi-line default values are indented. |
| 815 .beforeArguments(builder.split(space: requiredParams.isNotEmpty)); | 869 builder.startBlockArgumentNesting(); |
| 870 |
| 871 namedRule.beforeArgument(builder.split(space: requiredParams.isNotEmpty)); |
| 816 | 872 |
| 817 // "[" or "{" for optional parameters. | 873 // "[" or "{" for optional parameters. |
| 818 token(node.leftDelimiter); | 874 token(node.leftDelimiter); |
| 819 | 875 |
| 820 for (var param in optionalParams) { | 876 for (var param in optionalParams) { |
| 821 visit(param); | 877 visit(param); |
| 822 | 878 |
| 823 // Write the trailing comma. | 879 // Write the trailing comma. |
| 824 if (param != node.parameters.last) token(param.endToken.next); | 880 if (param != node.parameters.last) token(param.endToken.next); |
| 825 if (param != optionalParams.last) split(); | 881 if (param != optionalParams.last) namedRule.beforeArgument(split()); |
| 826 } | 882 } |
| 827 | 883 |
| 884 builder.endBlockArgumentNesting(); |
| 828 builder.endRule(); | 885 builder.endRule(); |
| 829 | 886 |
| 830 // "]" or "}" for optional parameters. | 887 // "]" or "}" for optional parameters. |
| 831 token(node.rightDelimiter); | 888 token(node.rightDelimiter); |
| 832 } | 889 } |
| 833 | 890 |
| 891 _metadataRules.removeLast(); |
| 892 |
| 834 token(node.rightParenthesis); | 893 token(node.rightParenthesis); |
| 835 builder.unnest(); | 894 builder.unnest(); |
| 836 } | 895 } |
| 837 | 896 |
| 838 visitForStatement(ForStatement node) { | 897 visitForStatement(ForStatement node) { |
| 839 builder.nestExpression(); | 898 builder.nestExpression(); |
| 840 token(node.forKeyword); | 899 token(node.forKeyword); |
| 841 space(); | 900 space(); |
| 842 token(node.leftParenthesis); | 901 token(node.leftParenthesis); |
| 843 | 902 |
| 844 builder.startRule(); | 903 builder.startRule(); |
| 845 | 904 |
| 846 // The initialization clause. | 905 // The initialization clause. |
| 847 if (node.initialization != null) { | 906 if (node.initialization != null) { |
| 848 visit(node.initialization); | 907 visit(node.initialization); |
| 849 } else if (node.variables != null) { | 908 } else if (node.variables != null) { |
| 850 // Indent split variables more so they aren't at the same level | 909 // Nest split variables more so they aren't at the same level |
| 851 // as the rest of the loop clauses. | 910 // as the rest of the loop clauses. |
| 852 builder.indent(Indent.loopVariable); | 911 builder.nestExpression(); |
| 853 | 912 |
| 854 // Allow the variables to stay unsplit even if the clauses split. | 913 // Allow the variables to stay unsplit even if the clauses split. |
| 855 builder.startRule(); | 914 builder.startRule(); |
| 856 | 915 |
| 857 var declaration = node.variables; | 916 var declaration = node.variables; |
| 858 visitDeclarationMetadata(declaration.metadata); | 917 visitDeclarationMetadata(declaration.metadata); |
| 859 modifier(declaration.keyword); | 918 modifier(declaration.keyword); |
| 860 visit(declaration.type, after: space); | 919 visit(declaration.type, after: space); |
| 861 | 920 |
| 862 visitCommaSeparatedNodes(declaration.variables, between: () { | 921 visitCommaSeparatedNodes(declaration.variables, between: () { |
| 863 split(); | 922 split(); |
| 864 }); | 923 }); |
| 865 | 924 |
| 866 builder.endRule(); | 925 builder.endRule(); |
| 867 builder.unindent(); | 926 builder.unnest(); |
| 868 } | 927 } |
| 869 | 928 |
| 870 token(node.leftSeparator); | 929 token(node.leftSeparator); |
| 871 | 930 |
| 872 // The condition clause. | 931 // The condition clause. |
| 873 if (node.condition != null) split(); | 932 if (node.condition != null) split(); |
| 874 visit(node.condition); | 933 visit(node.condition); |
| 875 token(node.rightSeparator); | 934 token(node.rightSeparator); |
| 876 | 935 |
| 877 // The update clause. | 936 // The update clause. |
| 878 if (node.updaters.isNotEmpty) { | 937 if (node.updaters.isNotEmpty) { |
| 879 split(); | 938 split(); |
| 880 | 939 |
| 881 // Allow the updates to stay unsplit even if the clauses split. | 940 // Allow the updates to stay unsplit even if the clauses split. |
| 882 builder.startRule(); | 941 builder.startRule(); |
| 883 | 942 |
| 884 visitCommaSeparatedNodes(node.updaters, between: split); | 943 visitCommaSeparatedNodes(node.updaters, between: split); |
| 885 | 944 |
| 886 builder.endRule(); | 945 builder.endRule(); |
| 887 } | 946 } |
| 888 | 947 |
| 889 token(node.rightParenthesis); | 948 token(node.rightParenthesis); |
| 890 builder.endRule(); | 949 builder.endRule(); |
| 891 builder.unnest(); | 950 builder.unnest(); |
| 892 | 951 |
| 893 // The body. | 952 _visitLoopBody(node.body); |
| 894 if (node.body is! EmptyStatement) space(); | |
| 895 visit(node.body); | |
| 896 } | 953 } |
| 897 | 954 |
| 898 visitFunctionDeclaration(FunctionDeclaration node) { | 955 visitFunctionDeclaration(FunctionDeclaration node) { |
| 899 visitMemberMetadata(node.metadata); | 956 _visitMemberDeclaration(node, node.functionExpression); |
| 900 | |
| 901 builder.nestExpression(); | |
| 902 modifier(node.externalKeyword); | |
| 903 visit(node.returnType, after: space); | |
| 904 modifier(node.propertyKeyword); | |
| 905 visit(node.name); | |
| 906 visit(node.functionExpression); | |
| 907 builder.unnest(); | |
| 908 } | 957 } |
| 909 | 958 |
| 910 visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { | 959 visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { |
| 911 visit(node.functionDeclaration); | 960 visit(node.functionDeclaration); |
| 912 } | 961 } |
| 913 | 962 |
| 914 visitFunctionExpression(FunctionExpression node) { | 963 visitFunctionExpression(FunctionExpression node) { |
| 915 _visitBody(node.parameters, node.body); | 964 _visitBody(node.parameters, node.body); |
| 916 } | 965 } |
| 917 | 966 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 949 _visitCombinator(node.keyword, node.hiddenNames); | 998 _visitCombinator(node.keyword, node.hiddenNames); |
| 950 } | 999 } |
| 951 | 1000 |
| 952 visitIfStatement(IfStatement node) { | 1001 visitIfStatement(IfStatement node) { |
| 953 builder.nestExpression(); | 1002 builder.nestExpression(); |
| 954 token(node.ifKeyword); | 1003 token(node.ifKeyword); |
| 955 space(); | 1004 space(); |
| 956 token(node.leftParenthesis); | 1005 token(node.leftParenthesis); |
| 957 visit(node.condition); | 1006 visit(node.condition); |
| 958 token(node.rightParenthesis); | 1007 token(node.rightParenthesis); |
| 1008 builder.unnest(now: false); |
| 959 | 1009 |
| 960 space(); | 1010 visitClause(Statement clause) { |
| 961 visit(node.thenStatement); | 1011 if (clause is Block || clause is IfStatement) { |
| 962 builder.unnest(); | 1012 space(); |
| 1013 visit(clause); |
| 1014 } else { |
| 1015 // Allow splitting in an expression-bodied if even though it's against |
| 1016 // the style guide. Since we can't fix the code itself to follow the |
| 1017 // style guide, we should at least format it as well as we can. |
| 1018 builder.nestExpression(indent: 2, now: true); |
| 1019 builder.startRule(); |
| 1020 |
| 1021 // If there is an else clause, always split before both the then and |
| 1022 // else statements. |
| 1023 if (node.elseStatement != null) { |
| 1024 builder.writeWhitespace(Whitespace.nestedNewline); |
| 1025 } else { |
| 1026 split(); |
| 1027 } |
| 1028 |
| 1029 visit(clause); |
| 1030 |
| 1031 builder.endRule(); |
| 1032 builder.unnest(); |
| 1033 } |
| 1034 } |
| 1035 |
| 1036 visitClause(node.thenStatement); |
| 963 | 1037 |
| 964 if (node.elseStatement != null) { | 1038 if (node.elseStatement != null) { |
| 965 if (node.thenStatement is Block) { | 1039 if (node.thenStatement is Block) { |
| 966 space(); | 1040 space(); |
| 967 } else { | 1041 } else { |
| 968 // Corner case where an else follows a single-statement then clause. | 1042 // Corner case where an else follows a single-statement then clause. |
| 969 // This is against the style guide, but we still need to handle it. If | 1043 // This is against the style guide, but we still need to handle it. If |
| 970 // it happens, put the else on the next line. | 1044 // it happens, put the else on the next line. |
| 971 newline(); | 1045 newline(); |
| 972 } | 1046 } |
| 973 | 1047 |
| 974 token(node.elseKeyword); | 1048 token(node.elseKeyword); |
| 975 space(); | 1049 visitClause(node.elseStatement); |
| 976 visit(node.elseStatement); | |
| 977 } | 1050 } |
| 978 } | 1051 } |
| 979 | 1052 |
| 980 visitImplementsClause(ImplementsClause node) { | 1053 visitImplementsClause(ImplementsClause node) { |
| 981 _visitCombinator(node.implementsKeyword, node.interfaces); | 1054 _visitCombinator(node.implementsKeyword, node.interfaces); |
| 982 } | 1055 } |
| 983 | 1056 |
| 984 visitImportDirective(ImportDirective node) { | 1057 visitImportDirective(ImportDirective node) { |
| 985 visitDeclarationMetadata(node.metadata); | 1058 visitDeclarationMetadata(node.metadata); |
| 986 | 1059 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1005 | 1078 |
| 1006 visitIndexExpression(IndexExpression node) { | 1079 visitIndexExpression(IndexExpression node) { |
| 1007 builder.nestExpression(); | 1080 builder.nestExpression(); |
| 1008 | 1081 |
| 1009 if (node.isCascaded) { | 1082 if (node.isCascaded) { |
| 1010 token(node.period); | 1083 token(node.period); |
| 1011 } else { | 1084 } else { |
| 1012 visit(node.target); | 1085 visit(node.target); |
| 1013 } | 1086 } |
| 1014 | 1087 |
| 1088 finishIndexExpression(node); |
| 1089 |
| 1090 builder.unnest(); |
| 1091 } |
| 1092 |
| 1093 /// Visit the index part of [node], excluding the target. |
| 1094 /// |
| 1095 /// Called by [CallChainVisitor] to handle index expressions in the middle of |
| 1096 /// call chains. |
| 1097 void finishIndexExpression(IndexExpression node) { |
| 1015 if (node.target is IndexExpression) { | 1098 if (node.target is IndexExpression) { |
| 1016 // Corner case: On a chain of [] accesses, allow splitting between them. | 1099 // Edge case: On a chain of [] accesses, allow splitting between them. |
| 1017 // Produces nicer output in cases like: | 1100 // Produces nicer output in cases like: |
| 1018 // | 1101 // |
| 1019 // someJson['property']['property']['property']['property']... | 1102 // someJson['property']['property']['property']['property']... |
| 1020 soloZeroSplit(); | 1103 soloZeroSplit(); |
| 1021 } | 1104 } |
| 1022 | 1105 |
| 1023 builder.startSpan(); | 1106 builder.startSpan(); |
| 1024 token(node.leftBracket); | 1107 token(node.leftBracket); |
| 1025 soloZeroSplit(); | 1108 soloZeroSplit(); |
| 1026 visit(node.index); | 1109 visit(node.index); |
| 1027 token(node.rightBracket); | 1110 token(node.rightBracket); |
| 1028 builder.endSpan(); | 1111 builder.endSpan(); |
| 1029 builder.unnest(); | |
| 1030 } | 1112 } |
| 1031 | 1113 |
| 1032 visitInstanceCreationExpression(InstanceCreationExpression node) { | 1114 visitInstanceCreationExpression(InstanceCreationExpression node) { |
| 1033 builder.startSpan(); | 1115 builder.startSpan(); |
| 1034 token(node.keyword); | 1116 token(node.keyword); |
| 1035 space(); | 1117 space(); |
| 1118 builder.startSpan(Cost.constructorName); |
| 1036 visit(node.constructorName); | 1119 visit(node.constructorName); |
| 1120 builder.endSpan(); |
| 1037 visit(node.argumentList); | 1121 visit(node.argumentList); |
| 1038 builder.endSpan(); | 1122 builder.endSpan(); |
| 1039 } | 1123 } |
| 1040 | 1124 |
| 1041 visitIntegerLiteral(IntegerLiteral node) { | 1125 visitIntegerLiteral(IntegerLiteral node) { |
| 1042 token(node.literal); | 1126 token(node.literal); |
| 1043 } | 1127 } |
| 1044 | 1128 |
| 1045 visitInterpolationExpression(InterpolationExpression node) { | 1129 visitInterpolationExpression(InterpolationExpression node) { |
| 1046 token(node.leftBracket); | 1130 token(node.leftBracket); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1105 } | 1189 } |
| 1106 | 1190 |
| 1107 visitMapLiteralEntry(MapLiteralEntry node) { | 1191 visitMapLiteralEntry(MapLiteralEntry node) { |
| 1108 visit(node.key); | 1192 visit(node.key); |
| 1109 token(node.separator); | 1193 token(node.separator); |
| 1110 soloSplit(); | 1194 soloSplit(); |
| 1111 visit(node.value); | 1195 visit(node.value); |
| 1112 } | 1196 } |
| 1113 | 1197 |
| 1114 visitMethodDeclaration(MethodDeclaration node) { | 1198 visitMethodDeclaration(MethodDeclaration node) { |
| 1115 visitMemberMetadata(node.metadata); | 1199 _visitMemberDeclaration(node, node); |
| 1116 | |
| 1117 modifier(node.externalKeyword); | |
| 1118 modifier(node.modifierKeyword); | |
| 1119 visit(node.returnType, after: space); | |
| 1120 modifier(node.propertyKeyword); | |
| 1121 modifier(node.operatorKeyword); | |
| 1122 visit(node.name); | |
| 1123 | |
| 1124 _visitBody(node.parameters, node.body); | |
| 1125 } | 1200 } |
| 1126 | 1201 |
| 1127 visitMethodInvocation(MethodInvocation node) { | 1202 visitMethodInvocation(MethodInvocation node) { |
| 1128 // If there's no target, this is a "bare" function call like "foo(1, 2)", | 1203 // If there's no target, this is a "bare" function call like "foo(1, 2)", |
| 1129 // or a section in a cascade. Handle this case specially. | 1204 // or a section in a cascade. Handle this case specially. |
| 1130 if (node.target == null) { | 1205 if (node.target == null) { |
| 1131 // Try to keep the entire method invocation one line. | 1206 // Try to keep the entire method invocation one line. |
| 1132 builder.startSpan(); | 1207 builder.startSpan(); |
| 1133 builder.nestExpression(); | 1208 builder.nestExpression(); |
| 1134 | 1209 |
| 1135 // This will be non-null for cascade sections. | 1210 // This will be non-null for cascade sections. |
| 1136 token(node.operator); | 1211 token(node.operator); |
| 1137 token(node.methodName.token); | 1212 token(node.methodName.token); |
| 1138 visit(node.argumentList); | 1213 visit(node.argumentList); |
| 1139 | 1214 |
| 1140 builder.unnest(); | 1215 builder.unnest(); |
| 1141 builder.endSpan(); | 1216 builder.endSpan(); |
| 1142 return; | 1217 return; |
| 1143 } | 1218 } |
| 1144 | 1219 |
| 1145 new CallChainVisitor(this, node).visit(); | 1220 new CallChainVisitor(this, node).visit(); |
| 1146 } | 1221 } |
| 1147 | 1222 |
| 1148 visitNamedExpression(NamedExpression node) { | 1223 visitNamedExpression(NamedExpression node) { |
| 1149 builder.nestExpression(); | 1224 builder.nestExpression(); |
| 1150 builder.startSpan(); | 1225 builder.startSpan(); |
| 1151 visit(node.name); | 1226 visit(node.name); |
| 1152 visit(node.expression, before: soloSplit); | 1227 |
| 1228 // Don't allow a split between a name and a collection. Instead, we want |
| 1229 // the collection itself to split, or to split before the argument. |
| 1230 if (node.expression is ListLiteral || node.expression is MapLiteral) { |
| 1231 space(); |
| 1232 } else { |
| 1233 soloSplit(); |
| 1234 } |
| 1235 |
| 1236 visit(node.expression); |
| 1153 builder.endSpan(); | 1237 builder.endSpan(); |
| 1154 builder.unnest(); | 1238 builder.unnest(); |
| 1155 } | 1239 } |
| 1156 | 1240 |
| 1157 visitNativeClause(NativeClause node) { | 1241 visitNativeClause(NativeClause node) { |
| 1158 token(node.nativeKeyword); | 1242 token(node.nativeKeyword); |
| 1159 space(); | 1243 space(); |
| 1160 visit(node.name); | 1244 visit(node.name); |
| 1161 } | 1245 } |
| 1162 | 1246 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1177 | 1261 |
| 1178 visitParenthesizedExpression(ParenthesizedExpression node) { | 1262 visitParenthesizedExpression(ParenthesizedExpression node) { |
| 1179 builder.nestExpression(); | 1263 builder.nestExpression(); |
| 1180 token(node.leftParenthesis); | 1264 token(node.leftParenthesis); |
| 1181 visit(node.expression); | 1265 visit(node.expression); |
| 1182 builder.unnest(); | 1266 builder.unnest(); |
| 1183 token(node.rightParenthesis); | 1267 token(node.rightParenthesis); |
| 1184 } | 1268 } |
| 1185 | 1269 |
| 1186 visitPartDirective(PartDirective node) { | 1270 visitPartDirective(PartDirective node) { |
| 1271 visitDeclarationMetadata(node.metadata); |
| 1272 |
| 1187 _simpleStatement(node, () { | 1273 _simpleStatement(node, () { |
| 1188 token(node.keyword); | 1274 token(node.keyword); |
| 1189 space(); | 1275 space(); |
| 1190 visit(node.uri); | 1276 visit(node.uri); |
| 1191 }); | 1277 }); |
| 1192 } | 1278 } |
| 1193 | 1279 |
| 1194 visitPartOfDirective(PartOfDirective node) { | 1280 visitPartOfDirective(PartOfDirective node) { |
| 1281 visitDeclarationMetadata(node.metadata); |
| 1282 |
| 1195 _simpleStatement(node, () { | 1283 _simpleStatement(node, () { |
| 1196 token(node.keyword); | 1284 token(node.keyword); |
| 1197 space(); | 1285 space(); |
| 1198 token(node.ofKeyword); | 1286 token(node.ofKeyword); |
| 1199 space(); | 1287 space(); |
| 1200 visit(node.libraryName); | 1288 visit(node.libraryName); |
| 1201 }); | 1289 }); |
| 1202 } | 1290 } |
| 1203 | 1291 |
| 1204 visitPostfixExpression(PostfixExpression node) { | 1292 visitPostfixExpression(PostfixExpression node) { |
| 1205 visit(node.operand); | 1293 visit(node.operand); |
| 1206 token(node.operator); | 1294 token(node.operator); |
| 1207 } | 1295 } |
| 1208 | 1296 |
| 1209 visitPrefixedIdentifier(PrefixedIdentifier node) { | 1297 visitPrefixedIdentifier(PrefixedIdentifier node) { |
| 1210 visit(node.prefix); | 1298 new CallChainVisitor(this, node).visit(); |
| 1211 token(node.period); | |
| 1212 visit(node.identifier); | |
| 1213 } | 1299 } |
| 1214 | 1300 |
| 1215 visitPrefixExpression(PrefixExpression node) { | 1301 visitPrefixExpression(PrefixExpression node) { |
| 1216 token(node.operator); | 1302 token(node.operator); |
| 1217 | 1303 |
| 1218 // Corner case: put a space between successive "-" operators so we don't | 1304 // Corner case: put a space between successive "-" operators so we don't |
| 1219 // inadvertently turn them into a "--" decrement operator. | 1305 // inadvertently turn them into a "--" decrement operator. |
| 1220 if (node.operand is PrefixExpression && | 1306 if (node.operand is PrefixExpression && |
| 1221 (node.operand as PrefixExpression).operator.lexeme == "-") { | 1307 (node.operand as PrefixExpression).operator.lexeme == "-") { |
| 1222 space(); | 1308 space(); |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1350 visitSwitchStatement(SwitchStatement node) { | 1436 visitSwitchStatement(SwitchStatement node) { |
| 1351 builder.nestExpression(); | 1437 builder.nestExpression(); |
| 1352 token(node.switchKeyword); | 1438 token(node.switchKeyword); |
| 1353 space(); | 1439 space(); |
| 1354 token(node.leftParenthesis); | 1440 token(node.leftParenthesis); |
| 1355 soloZeroSplit(); | 1441 soloZeroSplit(); |
| 1356 visit(node.expression); | 1442 visit(node.expression); |
| 1357 token(node.rightParenthesis); | 1443 token(node.rightParenthesis); |
| 1358 space(); | 1444 space(); |
| 1359 token(node.leftBracket); | 1445 token(node.leftBracket); |
| 1446 builder.unnest(); |
| 1360 builder.indent(); | 1447 builder.indent(); |
| 1361 newline(); | 1448 newline(); |
| 1362 | 1449 |
| 1363 visitNodes(node.members, between: oneOrTwoNewlines, after: newline); | 1450 visitNodes(node.members, between: oneOrTwoNewlines, after: newline); |
| 1364 token(node.rightBracket, before: () { | 1451 token(node.rightBracket, before: () { |
| 1365 builder.unindent(); | 1452 builder.unindent(); |
| 1366 newline(); | 1453 newline(); |
| 1367 }); | 1454 }); |
| 1368 builder.unnest(); | |
| 1369 } | 1455 } |
| 1370 | 1456 |
| 1371 visitSymbolLiteral(SymbolLiteral node) { | 1457 visitSymbolLiteral(SymbolLiteral node) { |
| 1372 token(node.poundSign); | 1458 token(node.poundSign); |
| 1373 var components = node.components; | 1459 var components = node.components; |
| 1374 for (var component in components) { | 1460 for (var component in components) { |
| 1375 // The '.' separator | 1461 // The '.' separator |
| 1376 if (component.previous.lexeme == '.') { | 1462 if (component.previous.lexeme == '.') { |
| 1377 token(component.previous); | 1463 token(component.previous); |
| 1378 } | 1464 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1418 | 1504 |
| 1419 visitTypeParameter(TypeParameter node) { | 1505 visitTypeParameter(TypeParameter node) { |
| 1420 visitParameterMetadata(node.metadata, () { | 1506 visitParameterMetadata(node.metadata, () { |
| 1421 visit(node.name); | 1507 visit(node.name); |
| 1422 token(node.extendsKeyword, before: space, after: space); | 1508 token(node.extendsKeyword, before: space, after: space); |
| 1423 visit(node.bound); | 1509 visit(node.bound); |
| 1424 }); | 1510 }); |
| 1425 } | 1511 } |
| 1426 | 1512 |
| 1427 visitTypeParameterList(TypeParameterList node) { | 1513 visitTypeParameterList(TypeParameterList node) { |
| 1514 _metadataRules.add(new MetadataRule()); |
| 1515 |
| 1428 _visitGenericList(node.leftBracket, node.rightBracket, node.typeParameters); | 1516 _visitGenericList(node.leftBracket, node.rightBracket, node.typeParameters); |
| 1517 |
| 1518 _metadataRules.removeLast(); |
| 1429 } | 1519 } |
| 1430 | 1520 |
| 1431 visitVariableDeclaration(VariableDeclaration node) { | 1521 visitVariableDeclaration(VariableDeclaration node) { |
| 1432 visit(node.name); | 1522 visit(node.name); |
| 1433 if (node.initializer == null) return; | 1523 if (node.initializer == null) return; |
| 1434 | 1524 |
| 1435 _visitAssignment(node.equals, node.initializer); | 1525 _visitAssignment(node.equals, node.initializer); |
| 1436 } | 1526 } |
| 1437 | 1527 |
| 1438 visitVariableDeclarationList(VariableDeclarationList node) { | 1528 visitVariableDeclarationList(VariableDeclarationList node) { |
| 1439 visitDeclarationMetadata(node.metadata); | 1529 visitDeclarationMetadata(node.metadata); |
| 1530 |
| 1531 // Allow but try to avoid splitting between the type and name. |
| 1532 builder.startSpan(); |
| 1533 |
| 1440 modifier(node.keyword); | 1534 modifier(node.keyword); |
| 1441 visit(node.type, after: space); | 1535 visit(node.type, after: soloSplit); |
| 1536 |
| 1537 builder.endSpan(); |
| 1442 | 1538 |
| 1443 // Use a single rule for all of the variables. If there are multiple | 1539 // Use a single rule for all of the variables. If there are multiple |
| 1444 // declarations, we will try to keep them all on one line. If that isn't | 1540 // declarations, we will try to keep them all on one line. If that isn't |
| 1445 // possible, we split after *every* declaration so that each is on its own | 1541 // possible, we split after *every* declaration so that each is on its own |
| 1446 // line. | 1542 // line. |
| 1447 builder.startRule(); | 1543 builder.startRule(); |
| 1448 visitCommaSeparatedNodes(node.variables, between: split); | 1544 visitCommaSeparatedNodes(node.variables, between: split); |
| 1449 builder.endRule(); | 1545 builder.endRule(); |
| 1450 } | 1546 } |
| 1451 | 1547 |
| 1452 visitVariableDeclarationStatement(VariableDeclarationStatement node) { | 1548 visitVariableDeclarationStatement(VariableDeclarationStatement node) { |
| 1453 _simpleStatement(node, () { | 1549 _simpleStatement(node, () { |
| 1454 visit(node.variables); | 1550 visit(node.variables); |
| 1455 }); | 1551 }); |
| 1456 } | 1552 } |
| 1457 | 1553 |
| 1458 visitWhileStatement(WhileStatement node) { | 1554 visitWhileStatement(WhileStatement node) { |
| 1459 builder.nestExpression(); | 1555 builder.nestExpression(); |
| 1460 token(node.whileKeyword); | 1556 token(node.whileKeyword); |
| 1461 space(); | 1557 space(); |
| 1462 token(node.leftParenthesis); | 1558 token(node.leftParenthesis); |
| 1463 soloZeroSplit(); | 1559 soloZeroSplit(); |
| 1464 visit(node.condition); | 1560 visit(node.condition); |
| 1465 token(node.rightParenthesis); | 1561 token(node.rightParenthesis); |
| 1466 if (node.body is! EmptyStatement) space(); | 1562 builder.unnest(now: false); |
| 1467 visit(node.body); | 1563 |
| 1468 builder.unnest(); | 1564 _visitLoopBody(node.body); |
| 1469 } | 1565 } |
| 1470 | 1566 |
| 1471 visitWithClause(WithClause node) { | 1567 visitWithClause(WithClause node) { |
| 1472 _visitCombinator(node.withKeyword, node.mixinTypes); | 1568 _visitCombinator(node.withKeyword, node.mixinTypes); |
| 1473 } | 1569 } |
| 1474 | 1570 |
| 1475 visitYieldStatement(YieldStatement node) { | 1571 visitYieldStatement(YieldStatement node) { |
| 1476 _simpleStatement(node, () { | 1572 _simpleStatement(node, () { |
| 1477 token(node.yieldKeyword); | 1573 token(node.yieldKeyword); |
| 1478 token(node.star); | 1574 token(node.star); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1517 } else { | 1613 } else { |
| 1518 visitNodes(metadata, between: space, after: spaceOrNewline); | 1614 visitNodes(metadata, between: space, after: spaceOrNewline); |
| 1519 } | 1615 } |
| 1520 } | 1616 } |
| 1521 | 1617 |
| 1522 /// Visits metadata annotations on parameters and type parameters. | 1618 /// Visits metadata annotations on parameters and type parameters. |
| 1523 /// | 1619 /// |
| 1524 /// These are always on the same line as the parameter. | 1620 /// These are always on the same line as the parameter. |
| 1525 void visitParameterMetadata( | 1621 void visitParameterMetadata( |
| 1526 NodeList<Annotation> metadata, void visitParameter()) { | 1622 NodeList<Annotation> metadata, void visitParameter()) { |
| 1623 if (metadata == null || metadata.isEmpty) { |
| 1624 visitParameter(); |
| 1625 return; |
| 1626 } |
| 1627 |
| 1527 // Split before all of the annotations or none. | 1628 // Split before all of the annotations or none. |
| 1528 builder.startRule(); | 1629 builder.startLazyRule(_metadataRules.last); |
| 1529 visitNodes(metadata, between: split, after: split); | 1630 |
| 1631 visitNodes(metadata, between: split, after: () { |
| 1632 // Don't nest until right before the last metadata. Ensures we only |
| 1633 // indent the parameter and not any of the metadata: |
| 1634 // |
| 1635 // function( |
| 1636 // @LongAnnotation |
| 1637 // @LongAnnotation |
| 1638 // indentedParameter) {} |
| 1639 builder.nestExpression(now: true); |
| 1640 split(); |
| 1641 }); |
| 1530 visitParameter(); | 1642 visitParameter(); |
| 1531 | 1643 |
| 1644 builder.unnest(); |
| 1645 |
| 1532 // Wrap the rule around the parameter too. If it splits, we want to force | 1646 // Wrap the rule around the parameter too. If it splits, we want to force |
| 1533 // the annotations to split as well. | 1647 // the annotations to split as well. |
| 1534 builder.endRule(); | 1648 builder.endRule(); |
| 1535 } | 1649 } |
| 1536 | 1650 |
| 1537 /// Visits the `=` and the following expression in any place where an `=` | 1651 /// Visits the `=` and the following expression in any place where an `=` |
| 1538 /// appears: | 1652 /// appears: |
| 1539 /// | 1653 /// |
| 1540 /// * Assignment | 1654 /// * Assignment |
| 1541 /// * Variable declaration | 1655 /// * Variable declaration |
| 1542 /// * Constructor initialization | 1656 /// * Constructor initialization |
| 1543 void _visitAssignment(Token equalsOperator, Expression rightHandSide) { | 1657 void _visitAssignment(Token equalsOperator, Expression rightHandSide) { |
| 1544 space(); | 1658 space(); |
| 1545 token(equalsOperator); | 1659 token(equalsOperator); |
| 1546 soloSplit(Cost.assignment); | 1660 soloSplit(_assignmentCost(rightHandSide)); |
| 1547 builder.startSpan(); | 1661 builder.startSpan(); |
| 1548 visit(rightHandSide); | 1662 visit(rightHandSide); |
| 1549 builder.endSpan(); | 1663 builder.endSpan(); |
| 1550 } | 1664 } |
| 1551 | 1665 |
| 1552 /// Visits a type parameter or type argument list. | 1666 /// Visits a type parameter or type argument list. |
| 1553 void _visitGenericList( | 1667 void _visitGenericList( |
| 1554 Token leftBracket, Token rightBracket, List<AstNode> nodes) { | 1668 Token leftBracket, Token rightBracket, List<AstNode> nodes) { |
| 1555 var rule = new TypeArgumentRule(); | 1669 var rule = new TypeArgumentRule(); |
| 1556 builder.startRule(rule); | 1670 builder.startRule(rule); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1570 } | 1684 } |
| 1571 } | 1685 } |
| 1572 | 1686 |
| 1573 token(rightBracket); | 1687 token(rightBracket); |
| 1574 | 1688 |
| 1575 builder.unnest(); | 1689 builder.unnest(); |
| 1576 builder.endSpan(); | 1690 builder.endSpan(); |
| 1577 builder.endRule(); | 1691 builder.endRule(); |
| 1578 } | 1692 } |
| 1579 | 1693 |
| 1694 /// Visits a top-level function or method declaration. |
| 1695 /// |
| 1696 /// The two AST node types are very similar but, alas, share no common |
| 1697 /// interface type in analyzer, hence the dynamic typing. |
| 1698 void _visitMemberDeclaration( |
| 1699 /* FunctionDeclaration|MethodDeclaration */ node, |
| 1700 /* FunctionExpression|MethodDeclaration */ function) { |
| 1701 visitMemberMetadata(node.metadata); |
| 1702 |
| 1703 // Nest the signature in case we have to split between the return type and |
| 1704 // name. |
| 1705 builder.nestExpression(); |
| 1706 builder.startSpan(); |
| 1707 modifier(node.externalKeyword); |
| 1708 if (node is MethodDeclaration) modifier(node.modifierKeyword); |
| 1709 visit(node.returnType, after: soloSplit); |
| 1710 modifier(node.propertyKeyword); |
| 1711 if (node is MethodDeclaration) modifier(node.operatorKeyword); |
| 1712 visit(node.name); |
| 1713 builder.endSpan(); |
| 1714 |
| 1715 // If the body is a block, we need to exit any nesting first. If it's an |
| 1716 // expression, we want to wrap the nesting around that so that the body |
| 1717 // gets nested farther. |
| 1718 if (function.body is! ExpressionFunctionBody) builder.unnest(); |
| 1719 |
| 1720 _visitBody(function.parameters, function.body); |
| 1721 |
| 1722 if (function.body is ExpressionFunctionBody) builder.unnest(); |
| 1723 } |
| 1724 |
| 1580 /// Visit the given function [parameters] followed by its [body], printing a | 1725 /// Visit the given function [parameters] followed by its [body], printing a |
| 1581 /// space before it if it's not empty. | 1726 /// space before it if it's not empty. |
| 1582 /// | 1727 /// |
| 1583 /// If [afterParameters] is provided, it is invoked between the parameters | 1728 /// If [afterParameters] is provided, it is invoked between the parameters |
| 1584 /// and body. (It's used for constructor initialization lists.) | 1729 /// and body. (It's used for constructor initialization lists.) |
| 1585 void _visitBody(FormalParameterList parameters, FunctionBody body, | 1730 void _visitBody(FormalParameterList parameters, FunctionBody body, |
| 1586 [afterParameters()]) { | 1731 [afterParameters()]) { |
| 1587 // If the body is "=>", add an extra level of indentation around the | 1732 // If the body is "=>", add an extra level of indentation around the |
| 1588 // parameters and a rule that spans the parameters and the "=>". This | 1733 // parameters and a rule that spans the parameters and the "=>". This |
| 1589 // ensures that if the parameters wrap, they wrap more deeply than the "=>" | 1734 // ensures that if the parameters wrap, they wrap more deeply than the "=>" |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1604 // level when they are actually unrelated. Splitting at "=>" forces: | 1749 // level when they are actually unrelated. Splitting at "=>" forces: |
| 1605 // | 1750 // |
| 1606 // someFunction(parameter, | 1751 // someFunction(parameter, |
| 1607 // parameter) => | 1752 // parameter) => |
| 1608 // function( | 1753 // function( |
| 1609 // argument); | 1754 // argument); |
| 1610 if (body is ExpressionFunctionBody) { | 1755 if (body is ExpressionFunctionBody) { |
| 1611 builder.nestExpression(); | 1756 builder.nestExpression(); |
| 1612 | 1757 |
| 1613 // This rule is ended by visitExpressionFunctionBody(). | 1758 // This rule is ended by visitExpressionFunctionBody(). |
| 1614 builder.startLazyRule(new SimpleRule(cost: Cost.arrow)); | 1759 builder.startLazyRule(new Rule(Cost.arrow)); |
| 1615 } | 1760 } |
| 1616 | 1761 |
| 1617 if (parameters != null) { | 1762 if (parameters != null) { |
| 1618 builder.nestExpression(); | 1763 builder.nestExpression(); |
| 1764 visit(parameters); |
| 1765 builder.unnest(); |
| 1619 | 1766 |
| 1620 visit(parameters); | |
| 1621 if (afterParameters != null) afterParameters(); | 1767 if (afterParameters != null) afterParameters(); |
| 1622 | |
| 1623 builder.unnest(); | |
| 1624 } | 1768 } |
| 1625 | 1769 |
| 1626 visit(body); | 1770 visit(body); |
| 1627 | 1771 |
| 1628 if (body is ExpressionFunctionBody) builder.unnest(); | 1772 if (body is ExpressionFunctionBody) builder.unnest(); |
| 1629 } | 1773 } |
| 1630 | 1774 |
| 1775 /// Visits the body statement of a `for` or `for in` loop. |
| 1776 void _visitLoopBody(Statement body) { |
| 1777 if (body is EmptyStatement) { |
| 1778 // No space before the ";". |
| 1779 visit(body); |
| 1780 } else if (body is Block) { |
| 1781 space(); |
| 1782 visit(body); |
| 1783 } else { |
| 1784 // Allow splitting in an expression-bodied for even though it's against |
| 1785 // the style guide. Since we can't fix the code itself to follow the |
| 1786 // style guide, we should at least format it as well as we can. |
| 1787 builder.nestExpression(indent: 2, now: true); |
| 1788 builder.startRule(); |
| 1789 |
| 1790 split(); |
| 1791 visit(body); |
| 1792 |
| 1793 builder.endRule(); |
| 1794 builder.unnest(); |
| 1795 } |
| 1796 } |
| 1797 |
| 1631 /// Visit a list of [nodes] if not null, optionally separated and/or preceded | 1798 /// Visit a list of [nodes] if not null, optionally separated and/or preceded |
| 1632 /// and followed by the given functions. | 1799 /// and followed by the given functions. |
| 1633 void visitNodes(Iterable<AstNode> nodes, {before(), between(), after()}) { | 1800 void visitNodes(Iterable<AstNode> nodes, {before(), between(), after()}) { |
| 1634 if (nodes == null || nodes.isEmpty) return; | 1801 if (nodes == null || nodes.isEmpty) return; |
| 1635 | 1802 |
| 1636 if (before != null) before(); | 1803 if (before != null) before(); |
| 1637 | 1804 |
| 1638 visit(nodes.first); | 1805 visit(nodes.first); |
| 1639 for (var node in nodes.skip(1)) { | 1806 for (var node in nodes.skip(1)) { |
| 1640 if (between != null) between(); | 1807 if (between != null) between(); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1667 void _visitCollectionLiteral(TypedLiteral node, Token leftBracket, | 1834 void _visitCollectionLiteral(TypedLiteral node, Token leftBracket, |
| 1668 Iterable<AstNode> elements, Token rightBracket, | 1835 Iterable<AstNode> elements, Token rightBracket, |
| 1669 [int cost]) { | 1836 [int cost]) { |
| 1670 modifier(node.constKeyword); | 1837 modifier(node.constKeyword); |
| 1671 visit(node.typeArguments); | 1838 visit(node.typeArguments); |
| 1672 | 1839 |
| 1673 // Don't allow splitting in an empty collection. | 1840 // Don't allow splitting in an empty collection. |
| 1674 if (elements.isEmpty && rightBracket.precedingComments == null) { | 1841 if (elements.isEmpty && rightBracket.precedingComments == null) { |
| 1675 token(leftBracket); | 1842 token(leftBracket); |
| 1676 token(rightBracket); | 1843 token(rightBracket); |
| 1677 | |
| 1678 // Clear this out in case this empty collection is in an argument list. | |
| 1679 // We don't want this rule to bleed over to some other collection. | |
| 1680 _nextLiteralBodyRule = null; | |
| 1681 return; | 1844 return; |
| 1682 } | 1845 } |
| 1683 | 1846 |
| 1684 // Force all of the surrounding collections to split. | 1847 // Force all of the surrounding collections to split. |
| 1685 for (var i = 0; i < _collectionSplits.length; i++) { | 1848 for (var i = 0; i < _collectionSplits.length; i++) { |
| 1686 _collectionSplits[i] = true; | 1849 _collectionSplits[i] = true; |
| 1687 } | 1850 } |
| 1688 | 1851 |
| 1689 // Add this collection to the stack. | 1852 // Add this collection to the stack. |
| 1690 _collectionSplits.add(false); | 1853 _collectionSplits.add(false); |
| 1691 | 1854 |
| 1692 _startLiteralBody(leftBracket); | 1855 _startLiteralBody(leftBracket); |
| 1693 | 1856 |
| 1694 // Always use a hard rule to split the elements. The parent chunk of | 1857 // Always use a hard rule to split the elements. The parent chunk of |
| 1695 // the collection will handle the unsplit case, so this only comes | 1858 // the collection will handle the unsplit case, so this only comes |
| 1696 // into play when the collection is split. | 1859 // into play when the collection is split. |
| 1697 var rule = new HardSplitRule(); | 1860 var rule = new Rule.hard(); |
| 1698 builder.startRule(rule); | 1861 builder.startRule(rule); |
| 1699 | 1862 |
| 1700 // If a collection contains a line comment, we assume it's a big complex | 1863 // If a collection contains a line comment, we assume it's a big complex |
| 1701 // blob of data with some documented structure. In that case, the user | 1864 // blob of data with some documented structure. In that case, the user |
| 1702 // probably broke the elements into lines deliberately, so preserve those. | 1865 // probably broke the elements into lines deliberately, so preserve those. |
| 1703 var preserveNewlines = _containsLineComments(elements, rightBracket); | 1866 var preserveNewlines = _containsLineComments(elements, rightBracket); |
| 1704 | 1867 |
| 1705 for (var element in elements) { | 1868 for (var element in elements) { |
| 1706 if (element != elements.first) { | 1869 if (element != elements.first) { |
| 1707 if (preserveNewlines) { | 1870 if (preserveNewlines) { |
| 1708 if (_endLine(element.beginToken.previous) != | 1871 if (_endLine(element.beginToken.previous) != |
| 1709 _startLine(element.beginToken)) { | 1872 _startLine(element.beginToken)) { |
| 1710 oneOrTwoNewlines(); | 1873 oneOrTwoNewlines(); |
| 1711 } else { | 1874 } else { |
| 1712 soloSplit(); | 1875 soloSplit(); |
| 1713 } | 1876 } |
| 1714 } else { | 1877 } else { |
| 1715 builder.blockSplit(space: true); | 1878 builder.split(nest: false, space: true); |
| 1716 } | 1879 } |
| 1717 } | 1880 } |
| 1718 | 1881 |
| 1719 builder.nestExpression(); | 1882 builder.nestExpression(); |
| 1720 visit(element); | 1883 visit(element); |
| 1721 | 1884 |
| 1722 // The comma after the element. | 1885 // The comma after the element. |
| 1723 if (element.endToken.next.lexeme == ",") token(element.endToken.next); | 1886 if (element.endToken.next.lexeme == ",") token(element.endToken.next); |
| 1724 | 1887 |
| 1725 builder.unnest(); | 1888 builder.unnest(); |
| 1726 } | 1889 } |
| 1727 | 1890 |
| 1728 builder.endRule(); | 1891 builder.endRule(); |
| 1729 | 1892 |
| 1730 // If there is a collection inside this one, it forces this one to split. | 1893 // If there is a collection inside this one, it forces this one to split. |
| 1731 var force = _collectionSplits.removeLast(); | 1894 var force = _collectionSplits.removeLast(); |
| 1732 | 1895 |
| 1733 _endLiteralBody(rightBracket, ignoredRule: rule, forceSplit: force); | 1896 _endLiteralBody(rightBracket, ignoredRule: rule, forceSplit: force); |
| 1734 } | 1897 } |
| 1735 | 1898 |
| 1899 /// Gets the cost to split at an assignment (or `:` in the case of a named |
| 1900 /// default value) with the given [rightHandSide]. |
| 1901 /// |
| 1902 /// "Block-like" expressions (collections and cascades) bind a bit tighter |
| 1903 /// because it looks better to have code like: |
| 1904 /// |
| 1905 /// var list = [ |
| 1906 /// element, |
| 1907 /// element, |
| 1908 /// element |
| 1909 /// ]; |
| 1910 /// |
| 1911 /// var builder = new SomeBuilderClass() |
| 1912 /// ..method() |
| 1913 /// ..method(); |
| 1914 /// |
| 1915 /// over: |
| 1916 /// |
| 1917 /// var list = |
| 1918 /// [element, element, element]; |
| 1919 /// |
| 1920 /// var builder = |
| 1921 /// new SomeBuilderClass()..method()..method(); |
| 1922 int _assignmentCost(Expression rightHandSide) { |
| 1923 if (rightHandSide is ListLiteral) return Cost.assignBlock; |
| 1924 if (rightHandSide is MapLiteral) return Cost.assignBlock; |
| 1925 if (rightHandSide is CascadeExpression) return Cost.assignBlock; |
| 1926 |
| 1927 return Cost.assign; |
| 1928 } |
| 1929 |
| 1736 /// Returns `true` if the collection withs [elements] delimited by | 1930 /// Returns `true` if the collection withs [elements] delimited by |
| 1737 /// [rightBracket] contains any line comments. | 1931 /// [rightBracket] contains any line comments. |
| 1738 /// | 1932 /// |
| 1739 /// This only looks for comments at the element boundary. Comments within an | 1933 /// This only looks for comments at the element boundary. Comments within an |
| 1740 /// element are ignored. | 1934 /// element are ignored. |
| 1741 bool _containsLineComments(Iterable<AstNode> elements, Token rightBracket) { | 1935 bool _containsLineComments(Iterable<AstNode> elements, Token rightBracket) { |
| 1742 hasLineCommentBefore(token) { | 1936 hasLineCommentBefore(token) { |
| 1743 var comment = token.precedingComments; | 1937 var comment = token.precedingComments; |
| 1744 for (; comment != null; comment = comment.next) { | 1938 for (; comment != null; comment = comment.next) { |
| 1745 if (comment.type == TokenType.SINGLE_LINE_COMMENT) return true; | 1939 if (comment.type == TokenType.SINGLE_LINE_COMMENT) return true; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1758 } | 1952 } |
| 1759 | 1953 |
| 1760 /// Begins writing a literal body: a collection or block-bodied function | 1954 /// Begins writing a literal body: a collection or block-bodied function |
| 1761 /// expression. | 1955 /// expression. |
| 1762 /// | 1956 /// |
| 1763 /// Writes the delimiter and then creates the [Rule] that handles splitting | 1957 /// Writes the delimiter and then creates the [Rule] that handles splitting |
| 1764 /// the body. | 1958 /// the body. |
| 1765 void _startLiteralBody(Token leftBracket) { | 1959 void _startLiteralBody(Token leftBracket) { |
| 1766 token(leftBracket); | 1960 token(leftBracket); |
| 1767 | 1961 |
| 1768 // Split the literal. Use the explicitly given rule if we have one. | 1962 // See if this literal is associated with an argument list that wants to |
| 1769 // Otherwise, create a new rule. | 1963 // handle splitting and indenting it. If not, we'll use a default rule. |
| 1770 var rule = _nextLiteralBodyRule; | 1964 var rule; |
| 1771 _nextLiteralBodyRule = null; | 1965 var argumentChunk; |
| 1966 if (_collectionArgumentLists.containsKey(leftBracket)) { |
| 1967 var argumentList = _collectionArgumentLists[leftBracket]; |
| 1968 rule = argumentList.collectionRule; |
| 1969 argumentChunk = argumentList.previousSplit; |
| 1970 } |
| 1772 | 1971 |
| 1773 // Create a rule for whether or not to split the block contents. | 1972 // Create a rule for whether or not to split the block contents. |
| 1774 builder.startRule(rule); | 1973 builder.startRule(rule); |
| 1775 | 1974 |
| 1776 // Process the collection contents as a separate set of chunks. | 1975 // Process the collection contents as a separate set of chunks. |
| 1777 builder = builder.startBlock(); | 1976 builder = builder.startBlock(argumentChunk); |
| 1778 } | 1977 } |
| 1779 | 1978 |
| 1780 /// Ends the literal body started by a call to [_startLiteralBody()]. | 1979 /// Ends the literal body started by a call to [_startLiteralBody()]. |
| 1781 /// | 1980 /// |
| 1782 /// If [forceSplit] is `true`, forces the body to split. If [ignoredRule] is | 1981 /// If [forceSplit] is `true`, forces the body to split. If [ignoredRule] is |
| 1783 /// given, ignores that rule inside the body when determining if it should | 1982 /// given, ignores that rule inside the body when determining if it should |
| 1784 /// split. | 1983 /// split. |
| 1785 void _endLiteralBody(Token rightBracket, | 1984 void _endLiteralBody(Token rightBracket, |
| 1786 {Rule ignoredRule, bool forceSplit}) { | 1985 {Rule ignoredRule, bool forceSplit}) { |
| 1787 if (forceSplit == null) forceSplit = false; | 1986 if (forceSplit == null) forceSplit = false; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1827 void _simpleStatement(AstNode node, body()) { | 2026 void _simpleStatement(AstNode node, body()) { |
| 1828 builder.nestExpression(); | 2027 builder.nestExpression(); |
| 1829 body(); | 2028 body(); |
| 1830 | 2029 |
| 1831 // TODO(rnystrom): Can the analyzer move "semicolon" to some shared base | 2030 // TODO(rnystrom): Can the analyzer move "semicolon" to some shared base |
| 1832 // type? | 2031 // type? |
| 1833 token((node as dynamic).semicolon); | 2032 token((node as dynamic).semicolon); |
| 1834 builder.unnest(); | 2033 builder.unnest(); |
| 1835 } | 2034 } |
| 1836 | 2035 |
| 1837 /// Makes [rule] the rule that will be used for the contents of a collection | 2036 /// Marks the collection literal that starts with [leftBracket] as being |
| 1838 /// or function literal body that are about to be visited. | 2037 /// controlled by [argumentList]. |
| 1839 void setNextLiteralBodyRule(Rule rule) { | 2038 /// |
| 1840 _nextLiteralBodyRule = rule; | 2039 /// When the collection is visited, [argumentList] will determine the |
| 2040 /// indentation and splitting rule for the collection. |
| 2041 void beforeCollection(Token leftBracket, ArgumentSublist argumentList) { |
| 2042 _collectionArgumentLists[leftBracket] = argumentList; |
| 1841 } | 2043 } |
| 1842 | 2044 |
| 1843 /// Writes an bracket-delimited body and handles indenting and starting the | 2045 /// Writes an bracket-delimited body and handles indenting and starting the |
| 1844 /// rule used to split the contents. | 2046 /// rule used to split the contents. |
| 1845 /// | 2047 /// |
| 1846 /// If [space] is `true`, then the contents and delimiters will have a space | 2048 /// If [space] is `true`, then the contents and delimiters will have a space |
| 1847 /// between then when unsplit. | 2049 /// between then when unsplit. |
| 1848 void _writeBody(Token leftBracket, Token rightBracket, | 2050 void _writeBody(Token leftBracket, Token rightBracket, |
| 1849 {bool space: false, body()}) { | 2051 {bool space: false, body()}) { |
| 1850 token(leftBracket); | 2052 token(leftBracket); |
| 1851 | 2053 |
| 1852 // Indent the body. | 2054 // Indent the body. |
| 1853 builder.indent(); | 2055 builder.indent(); |
| 1854 | 2056 |
| 1855 // Split after the bracket. | 2057 // Split after the bracket. |
| 1856 builder.startRule(); | 2058 builder.startRule(); |
| 1857 builder.blockSplit(space: space, isDouble: false); | 2059 builder.split(isDouble: false, nest: false, space: space); |
| 1858 | 2060 |
| 1859 body(); | 2061 body(); |
| 1860 | 2062 |
| 1861 token(rightBracket, before: () { | 2063 token(rightBracket, before: () { |
| 1862 // Split before the closing bracket character. | 2064 // Split before the closing bracket character. |
| 1863 builder.unindent(); | 2065 builder.unindent(); |
| 1864 builder.blockSplit(space: space); | 2066 builder.split(nest: false, space: space); |
| 1865 }); | 2067 }); |
| 1866 | 2068 |
| 1867 builder.endRule(); | 2069 builder.endRule(); |
| 1868 } | 2070 } |
| 1869 | 2071 |
| 1870 /// Returns `true` if [node] is immediately contained within an anonymous | 2072 /// Returns `true` if [node] is immediately contained within an anonymous |
| 1871 /// [FunctionExpression]. | 2073 /// [FunctionExpression]. |
| 1872 bool _isInLambda(AstNode node) => node.parent is FunctionExpression && | 2074 bool _isInLambda(AstNode node) => |
| 2075 node.parent is FunctionExpression && |
| 1873 node.parent.parent is! FunctionDeclaration; | 2076 node.parent.parent is! FunctionDeclaration; |
| 1874 | 2077 |
| 1875 /// Writes the string literal [string] to the output. | 2078 /// Writes the string literal [string] to the output. |
| 1876 /// | 2079 /// |
| 1877 /// Splits multiline strings into separate chunks so that the line splitter | 2080 /// Splits multiline strings into separate chunks so that the line splitter |
| 1878 /// can handle them correctly. | 2081 /// can handle them correctly. |
| 1879 void _writeStringLiteral(String string, int offset) { | 2082 void _writeStringLiteral(String string, int offset) { |
| 1880 // Split each line of a multiline string into separate chunks. | 2083 // Split each line of a multiline string into separate chunks. |
| 1881 var lines = string.split(_formatter.lineEnding); | 2084 var lines = string.split(_formatter.lineEnding); |
| 1882 | 2085 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1938 /// Returns the chunk the split was applied to. | 2141 /// Returns the chunk the split was applied to. |
| 1939 Chunk split() => builder.split(space: true); | 2142 Chunk split() => builder.split(space: true); |
| 1940 | 2143 |
| 1941 /// Writes a zero-space split owned by the current rule. | 2144 /// Writes a zero-space split owned by the current rule. |
| 1942 /// | 2145 /// |
| 1943 /// Returns the chunk the split was applied to. | 2146 /// Returns the chunk the split was applied to. |
| 1944 Chunk zeroSplit() => builder.split(); | 2147 Chunk zeroSplit() => builder.split(); |
| 1945 | 2148 |
| 1946 /// Writes a single space split with its own rule. | 2149 /// Writes a single space split with its own rule. |
| 1947 void soloSplit([int cost]) { | 2150 void soloSplit([int cost]) { |
| 1948 builder.startRule(new SimpleRule(cost: cost)); | 2151 builder.startRule(new Rule(cost)); |
| 1949 split(); | 2152 split(); |
| 1950 builder.endRule(); | 2153 builder.endRule(); |
| 1951 } | 2154 } |
| 1952 | 2155 |
| 1953 /// Writes a zero-space split with its own rule. | 2156 /// Writes a zero-space split with its own rule. |
| 1954 void soloZeroSplit() { | 2157 void soloZeroSplit() { |
| 1955 builder.startRule(); | 2158 builder.startRule(); |
| 1956 builder.split(); | 2159 builder.split(); |
| 1957 builder.endRule(); | 2160 builder.endRule(); |
| 1958 } | 2161 } |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2159 /// Gets the 1-based line number that the beginning of [token] lies on. | 2362 /// Gets the 1-based line number that the beginning of [token] lies on. |
| 2160 int _startLine(Token token) => _lineInfo.getLocation(token.offset).lineNumber; | 2363 int _startLine(Token token) => _lineInfo.getLocation(token.offset).lineNumber; |
| 2161 | 2364 |
| 2162 /// Gets the 1-based line number that the end of [token] lies on. | 2365 /// Gets the 1-based line number that the end of [token] lies on. |
| 2163 int _endLine(Token token) => _lineInfo.getLocation(token.end).lineNumber; | 2366 int _endLine(Token token) => _lineInfo.getLocation(token.end).lineNumber; |
| 2164 | 2367 |
| 2165 /// Gets the 1-based column number that the beginning of [token] lies on. | 2368 /// Gets the 1-based column number that the beginning of [token] lies on. |
| 2166 int _startColumn(Token token) => | 2369 int _startColumn(Token token) => |
| 2167 _lineInfo.getLocation(token.offset).columnNumber; | 2370 _lineInfo.getLocation(token.offset).columnNumber; |
| 2168 } | 2371 } |
| OLD | NEW |