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 |