| 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 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 98 | 98 |
| 99 // If there is just one positional argument, it tends to look weird to | 99 // If there is just one positional argument, it tends to look weird to |
| 100 // split before it, so try not to. | 100 // split before it, so try not to. |
| 101 var singleArgument = node.arguments.length == 1 && | 101 var singleArgument = node.arguments.length == 1 && |
| 102 node.arguments.single is ! NamedExpression; | 102 node.arguments.single is ! NamedExpression; |
| 103 if (singleArgument) _writer.startSpan(); | 103 if (singleArgument) _writer.startSpan(); |
| 104 | 104 |
| 105 // Nest around the parentheses in case there are comments before or after | 105 // Nest around the parentheses in case there are comments before or after |
| 106 // them. | 106 // them. |
| 107 _writer.nestExpression(); | 107 _writer.nestExpression(); |
| 108 |
| 108 token(node.leftParenthesis); | 109 token(node.leftParenthesis); |
| 109 | 110 |
| 111 // Corner case: If the first argument to a method is a block-bodied |
| 112 // function, it looks bad if its parameter list gets wrapped to the next |
| 113 // line. Bump the cost to try to avoid that. This prefers: |
| 114 // |
| 115 // receiver |
| 116 // .method() |
| 117 // .chain((parameter, list) { |
| 118 // ... |
| 119 // }); |
| 120 // |
| 121 // over: |
| 122 // |
| 123 // receiver.method().chain( |
| 124 // (parameter, list) { |
| 125 // ... |
| 126 // }); |
| 127 // TODO(rnystrom): This causes a function expression's long parameter list |
| 128 // to get split instead, like: |
| 129 // |
| 130 // receiver.method((longParameter, |
| 131 // anotherParameter) { |
| 132 // ... |
| 133 // }); |
| 134 // |
| 135 // Instead of bumping the cost, this should wrap a span around the "(" |
| 136 // before the argument list and the function's parameter list. That requires |
| 137 // spans to not strictly be a stack, though, so would be a larger change |
| 138 // than I want to do right now. |
| 139 var cost = Cost.normal; |
| 140 if (node.arguments.isNotEmpty) { |
| 141 var firstArg = node.arguments.first; |
| 142 if (firstArg is FunctionExpression && |
| 143 firstArg.body is BlockFunctionBody) { |
| 144 cost = Cost.firstBlockArgument; |
| 145 } |
| 146 } |
| 147 |
| 110 // Allow splitting after "(". | 148 // Allow splitting after "(". |
| 111 var lastParam = zeroSplit(); | 149 var lastParam = zeroSplit(cost); |
| 112 | 150 |
| 113 // Try to keep the positional arguments together. | 151 // Try to keep the positional arguments together. |
| 114 _writer.startSpan(); | 152 _writer.startSpan(Cost.positionalArguments); |
| 115 | 153 |
| 116 var i = 0; | 154 var i = 0; |
| 117 for (; i < node.arguments.length; i++) { | 155 for (; i < node.arguments.length; i++) { |
| 118 var argument = node.arguments[i]; | 156 var argument = node.arguments[i]; |
| 119 | 157 |
| 120 if (argument is NamedExpression) break; | 158 if (argument is NamedExpression) break; |
| 121 | 159 |
| 122 visit(argument); | 160 visit(argument); |
| 123 | 161 |
| 124 // Write the trailing comma and split. | 162 // Write the trailing comma and split. |
| (...skipping 847 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 972 | 1010 |
| 973 visitLibraryIdentifier(LibraryIdentifier node) { | 1011 visitLibraryIdentifier(LibraryIdentifier node) { |
| 974 visit(node.components.first); | 1012 visit(node.components.first); |
| 975 for (var component in node.components.skip(1)) { | 1013 for (var component in node.components.skip(1)) { |
| 976 token(component.beginToken.previous); // "." | 1014 token(component.beginToken.previous); // "." |
| 977 visit(component); | 1015 visit(component); |
| 978 } | 1016 } |
| 979 } | 1017 } |
| 980 | 1018 |
| 981 visitListLiteral(ListLiteral node) { | 1019 visitListLiteral(ListLiteral node) { |
| 1020 // Corner case: Splitting inside a list looks bad if there's only one |
| 1021 // element, so make those more costly. |
| 1022 var cost = node.elements.length <= 1 ? Cost.singleElementList : Cost.normal; |
| 982 _visitCollectionLiteral( | 1023 _visitCollectionLiteral( |
| 983 node, node.leftBracket, node.elements, node.rightBracket); | 1024 node, node.leftBracket, node.elements, node.rightBracket, cost); |
| 984 } | 1025 } |
| 985 | 1026 |
| 986 visitMapLiteral(MapLiteral node) { | 1027 visitMapLiteral(MapLiteral node) { |
| 987 _visitCollectionLiteral( | 1028 _visitCollectionLiteral( |
| 988 node, node.leftBracket, node.entries, node.rightBracket); | 1029 node, node.leftBracket, node.entries, node.rightBracket); |
| 989 } | 1030 } |
| 990 | 1031 |
| 991 visitMapLiteralEntry(MapLiteralEntry node) { | 1032 visitMapLiteralEntry(MapLiteralEntry node) { |
| 992 visit(node.key); | 1033 visit(node.key); |
| 993 token(node.separator); | 1034 token(node.separator); |
| (...skipping 541 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1535 visit(node); | 1576 visit(node); |
| 1536 | 1577 |
| 1537 // The comma after the node. | 1578 // The comma after the node. |
| 1538 if (node.endToken.next.lexeme == ",") token(node.endToken.next); | 1579 if (node.endToken.next.lexeme == ",") token(node.endToken.next); |
| 1539 } | 1580 } |
| 1540 } | 1581 } |
| 1541 | 1582 |
| 1542 /// Visits the collection literal [node] whose body starts with [leftBracket], | 1583 /// Visits the collection literal [node] whose body starts with [leftBracket], |
| 1543 /// ends with [rightBracket] and contains [elements]. | 1584 /// ends with [rightBracket] and contains [elements]. |
| 1544 void _visitCollectionLiteral(TypedLiteral node, Token leftBracket, | 1585 void _visitCollectionLiteral(TypedLiteral node, Token leftBracket, |
| 1545 Iterable<AstNode> elements, Token rightBracket) { | 1586 Iterable<AstNode> elements, Token rightBracket, [int cost]) { |
| 1546 modifier(node.constKeyword); | 1587 modifier(node.constKeyword); |
| 1547 visit(node.typeArguments); | 1588 visit(node.typeArguments); |
| 1548 | 1589 |
| 1549 _startBody(leftBracket); | 1590 _startBody(leftBracket, cost: cost); |
| 1550 | 1591 |
| 1551 // Each list element takes at least 3 characters (one character for the | 1592 // Each list element takes at least 3 characters (one character for the |
| 1552 // element, one for the comma, one for the space), so force it to split if | 1593 // element, one for the comma, one for the space), so force it to split if |
| 1553 // we know that won't fit. | 1594 // we know that won't fit. |
| 1554 if (elements.length > _writer.pageWidth ~/ 3) _writer.preemptMultisplits(); | 1595 if (elements.length > _writer.pageWidth ~/ 3) _writer.preemptMultisplits(); |
| 1555 | 1596 |
| 1556 for (var element in elements) { | 1597 for (var element in elements) { |
| 1557 if (element != elements.first) _writer.multisplit(space: true); | 1598 if (element != elements.first) _writer.multisplit(space: true); |
| 1558 | 1599 |
| 1559 _writer.nestExpression(); | 1600 _writer.nestExpression(); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1642 // TODO(rnystrom): Can the analyzer move "semicolon" to some shared base | 1683 // TODO(rnystrom): Can the analyzer move "semicolon" to some shared base |
| 1643 // type? | 1684 // type? |
| 1644 token((node as dynamic).semicolon); | 1685 token((node as dynamic).semicolon); |
| 1645 _writer.unnest(); | 1686 _writer.unnest(); |
| 1646 } | 1687 } |
| 1647 /// Writes an opening bracket token ("(", "{", "[") and handles indenting and | 1688 /// Writes an opening bracket token ("(", "{", "[") and handles indenting and |
| 1648 /// starting the multisplit it contains. | 1689 /// starting the multisplit it contains. |
| 1649 /// | 1690 /// |
| 1650 /// If [space] is `true`, then the initial multisplit will use a space if not | 1691 /// If [space] is `true`, then the initial multisplit will use a space if not |
| 1651 /// split. | 1692 /// split. |
| 1652 void _startBody(Token leftBracket, {bool space: false}) { | 1693 void _startBody(Token leftBracket, {int cost, bool space: false}) { |
| 1653 token(leftBracket); | 1694 token(leftBracket); |
| 1654 | 1695 |
| 1655 // Indent the body. | 1696 // Indent the body. |
| 1656 _writer.startMultisplit(); | 1697 _writer.startMultisplit(cost: cost); |
| 1657 _writer.indent(); | 1698 _writer.indent(); |
| 1658 | 1699 |
| 1659 // Split after the bracket. | 1700 // Split after the bracket. |
| 1660 _writer.multisplit(space: space); | 1701 _writer.multisplit(space: space); |
| 1661 } | 1702 } |
| 1662 | 1703 |
| 1663 /// Writes a closing bracket token (")", "}", "]") and handles unindenting | 1704 /// Writes a closing bracket token (")", "}", "]") and handles unindenting |
| 1664 /// and ending the multisplit it contains. | 1705 /// and ending the multisplit it contains. |
| 1665 /// | 1706 /// |
| 1666 /// Used for blocks, other curly bodies, and collection literals. | 1707 /// Used for blocks, other curly bodies, and collection literals. |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1739 | 1780 |
| 1740 /// Writes a single-space split with the given [cost]. | 1781 /// Writes a single-space split with the given [cost]. |
| 1741 /// | 1782 /// |
| 1742 /// If [cost] is omitted, defaults to [Cost.normal]. Returns the newly created | 1783 /// If [cost] is omitted, defaults to [Cost.normal]. Returns the newly created |
| 1743 /// [SplitParam]. | 1784 /// [SplitParam]. |
| 1744 SplitParam split([int cost]) => _writer.writeSplit(cost: cost, space: true); | 1785 SplitParam split([int cost]) => _writer.writeSplit(cost: cost, space: true); |
| 1745 | 1786 |
| 1746 /// Writes a split that is the empty string when unsplit. | 1787 /// Writes a split that is the empty string when unsplit. |
| 1747 /// | 1788 /// |
| 1748 /// Returns the newly created [SplitParam]. | 1789 /// Returns the newly created [SplitParam]. |
| 1749 SplitParam zeroSplit() => _writer.writeSplit(); | 1790 SplitParam zeroSplit([int cost]) => _writer.writeSplit(cost: cost); |
| 1750 | 1791 |
| 1751 /// Emit [token], along with any comments and formatted whitespace that comes | 1792 /// Emit [token], along with any comments and formatted whitespace that comes |
| 1752 /// before it. | 1793 /// before it. |
| 1753 /// | 1794 /// |
| 1754 /// Does nothing if [token] is `null`. If [before] is given, it will be | 1795 /// Does nothing if [token] is `null`. If [before] is given, it will be |
| 1755 /// executed before the token is outout. Likewise, [after] will be called | 1796 /// executed before the token is outout. Likewise, [after] will be called |
| 1756 /// after the token is output. | 1797 /// after the token is output. |
| 1757 void token(Token token, {before(), after()}) { | 1798 void token(Token token, {before(), after()}) { |
| 1758 if (token == null) return; | 1799 if (token == null) return; |
| 1759 | 1800 |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1931 /// Gets the 1-based line number that the beginning of [token] lies on. | 1972 /// Gets the 1-based line number that the beginning of [token] lies on. |
| 1932 int _startLine(Token token) => _lineInfo.getLocation(token.offset).lineNumber; | 1973 int _startLine(Token token) => _lineInfo.getLocation(token.offset).lineNumber; |
| 1933 | 1974 |
| 1934 /// Gets the 1-based line number that the end of [token] lies on. | 1975 /// Gets the 1-based line number that the end of [token] lies on. |
| 1935 int _endLine(Token token) => _lineInfo.getLocation(token.end).lineNumber; | 1976 int _endLine(Token token) => _lineInfo.getLocation(token.end).lineNumber; |
| 1936 | 1977 |
| 1937 /// Gets the 1-based column number that the beginning of [token] lies on. | 1978 /// Gets the 1-based column number that the beginning of [token] lies on. |
| 1938 int _startColumn(Token token) => | 1979 int _startColumn(Token token) => |
| 1939 _lineInfo.getLocation(token.offset).columnNumber; | 1980 _lineInfo.getLocation(token.offset).columnNumber; |
| 1940 } | 1981 } |
| OLD | NEW |