| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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.rule.argument; | 5 library dart_style.src.rule.argument; |
| 6 | 6 |
| 7 import '../chunk.dart'; | 7 import '../chunk.dart'; |
| 8 import 'rule.dart'; | 8 import 'rule.dart'; |
| 9 | 9 |
| 10 /// Base class for a rule that handles argument or parameter lists. | 10 /// Base class for a rule that handles argument or parameter lists. |
| 11 abstract class ArgumentRule extends Rule { | 11 abstract class ArgumentRule extends Rule { |
| 12 /// The chunks prior to each positional argument. |
| 13 final List<Chunk> _arguments = []; |
| 14 |
| 15 /// The rule used to split collections in the argument list, if any. |
| 16 Rule _collectionRule; |
| 17 |
| 18 /// The number of leading collection arguments. |
| 19 /// |
| 20 /// This and [_trailingCollections] cannot both be positive. If every |
| 21 /// argument is a collection, this will be [_arguments.length] and |
| 22 /// [_trailingCollections] will be 0. |
| 23 final int _leadingCollections; |
| 24 |
| 25 /// The number of trailing collections. |
| 26 /// |
| 27 /// This and [_leadingCollections] cannot both be positive. |
| 28 final int _trailingCollections; |
| 29 |
| 12 /// If true, then inner rules that are written will force this rule to split. | 30 /// If true, then inner rules that are written will force this rule to split. |
| 13 /// | 31 /// |
| 14 /// Temporarily disabled while writing collectio arguments so that they can be | 32 /// Temporarily disabled while writing collectio arguments so that they can be |
| 15 /// multi-line without forcing the whole argument list to split. | 33 /// multi-line without forcing the whole argument list to split. |
| 16 bool _trackInnerRules = true; | 34 bool _trackInnerRules = true; |
| 17 | 35 |
| 18 /// Don't split when an inner collection rule splits. | 36 /// Don't split when an inner collection rule splits. |
| 19 bool get splitsOnInnerRules => _trackInnerRules; | 37 bool get splitsOnInnerRules => _trackInnerRules; |
| 20 | 38 |
| 39 ArgumentRule(this._collectionRule, this._leadingCollections, |
| 40 this._trailingCollections); |
| 41 |
| 42 void addConstrainedRules(Set<Rule> rules) { |
| 43 super.addConstrainedRules(rules); |
| 44 if (_collectionRule != null) rules.add(_collectionRule); |
| 45 } |
| 46 |
| 47 void forgetUnusedRules() { |
| 48 super.forgetUnusedRules(); |
| 49 if (_collectionRule != null && _collectionRule.index == null) { |
| 50 _collectionRule = null; |
| 51 } |
| 52 } |
| 53 |
| 54 /// Remembers [chunk] as containing the split that occurs right before an |
| 55 /// argument in the list. |
| 56 void beforeArgument(Chunk chunk) { |
| 57 _arguments.add(chunk); |
| 58 } |
| 59 |
| 21 /// Called before a collection argument is written. | 60 /// Called before a collection argument is written. |
| 22 /// | 61 /// |
| 23 /// Disables tracking inner rules while a collection argument is written. | 62 /// Disables tracking inner rules while a collection argument is written. |
| 24 void beforeCollection() { | 63 void beforeCollection() { |
| 25 assert(_trackInnerRules == true); | 64 assert(_trackInnerRules == true); |
| 26 _trackInnerRules = false; | 65 _trackInnerRules = false; |
| 27 } | 66 } |
| 28 | 67 |
| 29 /// Called after a collection argument is complete. | 68 /// Called after a collection argument is complete. |
| 30 /// | 69 /// |
| 31 /// Re-enables tracking inner rules. | 70 /// Re-enables tracking inner rules. |
| 32 void afterCollection() { | 71 void afterCollection() { |
| 33 assert(_trackInnerRules == false); | 72 assert(_trackInnerRules == false); |
| 34 _trackInnerRules = true; | 73 _trackInnerRules = true; |
| 35 } | 74 } |
| 36 } | 75 } |
| 37 | 76 |
| 38 /// Base class for a rule for handling positional argument lists. | 77 /// Base class for a rule for handling positional argument lists. |
| 39 abstract class PositionalRule extends ArgumentRule { | 78 abstract class PositionalRule extends ArgumentRule { |
| 40 /// The chunks prior to each positional argument. | |
| 41 final List<Chunk> _arguments = []; | |
| 42 | |
| 43 /// The rule used to split collections in the argument list, if any. | |
| 44 Rule _collectionRule; | |
| 45 | |
| 46 /// If there are named arguments following these positional ones, this will | 79 /// If there are named arguments following these positional ones, this will |
| 47 /// be their rule. | 80 /// be their rule. |
| 48 Rule _namedArgsRule; | 81 Rule _namedArgsRule; |
| 49 | 82 |
| 50 /// Creates a new rule for a positional argument list. | 83 /// Creates a new rule for a positional argument list. |
| 51 /// | 84 /// |
| 52 /// If [_collectionRule] is given, it is the rule used to split the collection | 85 /// If [_collectionRule] is given, it is the rule used to split the collection |
| 53 /// arguments in the list. | 86 /// arguments in the list. |
| 54 PositionalRule(this._collectionRule); | 87 PositionalRule( |
| 88 Rule collectionRule, int leadingCollections, int trailingCollections) |
| 89 : super(collectionRule, leadingCollections, trailingCollections); |
| 55 | 90 |
| 56 void addConstrainedRules(Set<Rule> rules) { | 91 void addConstrainedRules(Set<Rule> rules) { |
| 57 if (_collectionRule != null) rules.add(_collectionRule); | 92 super.addConstrainedRules(rules); |
| 58 if (_namedArgsRule != null) rules.add(_namedArgsRule); | 93 if (_namedArgsRule != null) rules.add(_namedArgsRule); |
| 59 } | 94 } |
| 60 | 95 |
| 61 void forgetUnusedRules() { | 96 void forgetUnusedRules() { |
| 62 super.forgetUnusedRules(); | 97 super.forgetUnusedRules(); |
| 63 if (_namedArgsRule != null && _namedArgsRule.index == null) { | 98 if (_namedArgsRule != null && _namedArgsRule.index == null) { |
| 64 _namedArgsRule = null; | 99 _namedArgsRule = null; |
| 65 } | 100 } |
| 66 | |
| 67 if (_collectionRule != null && _collectionRule.index == null) { | |
| 68 _collectionRule = null; | |
| 69 } | |
| 70 } | 101 } |
| 71 | 102 |
| 72 /// Remembers [chunk] as containing the split that occurs right before an | 103 /// Remembers that [rule] is the [Rule] immediately following this positional |
| 73 /// argument in the list. | |
| 74 void beforeArgument(Chunk chunk) { | |
| 75 _arguments.add(chunk); | |
| 76 } | |
| 77 | |
| 78 /// Remembers that [rule] is the [NamedArgsRule] immediately following this | |
| 79 /// positional argument list. | 104 /// positional argument list. |
| 80 void setNamedArgsRule(NamedRule rule) { | 105 /// |
| 106 /// This is normally a [NamedRule] but [PositionalRule] is also used for the |
| 107 /// property accesses at the beginning of a call chain, in which case this |
| 108 /// is just a [SimpleRule]. |
| 109 void setNamedArgsRule(Rule rule) { |
| 81 _namedArgsRule = rule; | 110 _namedArgsRule = rule; |
| 82 } | 111 } |
| 83 | 112 |
| 84 /// Constrains the named argument list to at least move to the next line if | 113 /// Constrains the named argument list to at least move to the next line if |
| 85 /// there are any splits in the positional arguments. Prevents things like: | 114 /// there are any splits in the positional arguments. Prevents things like: |
| 86 /// | 115 /// |
| 87 /// function( | 116 /// function( |
| 88 /// argument, | 117 /// argument, |
| 89 /// argument, named: argument); | 118 /// argument, named: argument); |
| 90 int constrain(int value, Rule other) { | 119 int constrain(int value, Rule other) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 113 /// If there is only a single non-collection argument, allow it to split | 142 /// If there is only a single non-collection argument, allow it to split |
| 114 /// internally without forcing a split before the argument. | 143 /// internally without forcing a split before the argument. |
| 115 final bool splitsOnInnerRules; | 144 final bool splitsOnInnerRules; |
| 116 | 145 |
| 117 /// Creates a new rule for a positional argument list. | 146 /// Creates a new rule for a positional argument list. |
| 118 /// | 147 /// |
| 119 /// If [collectionRule] is given, it is the rule used to split the | 148 /// If [collectionRule] is given, it is the rule used to split the |
| 120 /// collections in the list. If [splitsOnInnerRules] is `true`, then we will | 149 /// collections in the list. If [splitsOnInnerRules] is `true`, then we will |
| 121 /// split before the argument if the argument itself contains a split. | 150 /// split before the argument if the argument itself contains a split. |
| 122 SinglePositionalRule(Rule collectionRule, {bool splitsOnInnerRules}) | 151 SinglePositionalRule(Rule collectionRule, {bool splitsOnInnerRules}) |
| 123 : super(collectionRule), | 152 : super(collectionRule, 0, 0), |
| 124 splitsOnInnerRules = | 153 splitsOnInnerRules = |
| 125 splitsOnInnerRules != null ? splitsOnInnerRules : false; | 154 splitsOnInnerRules != null ? splitsOnInnerRules : false; |
| 126 | 155 |
| 127 int constrain(int value, Rule other) { | 156 int constrain(int value, Rule other) { |
| 128 var constrained = super.constrain(value, other); | 157 var constrained = super.constrain(value, other); |
| 129 if (constrained != null) return constrained; | 158 if (constrained != null) return constrained; |
| 130 | 159 |
| 131 if (other != _collectionRule) return null; | 160 if (other != _collectionRule) return null; |
| 132 | 161 |
| 133 // If we aren't splitting any args, we can split the collection. | 162 // If we aren't splitting any args, we can split the collection. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 151 /// Then there is a value for each argument, to split before that argument. | 180 /// Then there is a value for each argument, to split before that argument. |
| 152 /// These values work back to front. So, for a two-argument list, value 2 splits | 181 /// These values work back to front. So, for a two-argument list, value 2 splits |
| 153 /// after the second argument and value 3 splits after the first. | 182 /// after the second argument and value 3 splits after the first. |
| 154 /// | 183 /// |
| 155 /// Then there is a value that splits before every argument. | 184 /// Then there is a value that splits before every argument. |
| 156 /// | 185 /// |
| 157 /// Finally, if there are collection arguments, there is another value that | 186 /// Finally, if there are collection arguments, there is another value that |
| 158 /// splits before all of the non-collection arguments, but does not split | 187 /// splits before all of the non-collection arguments, but does not split |
| 159 /// before the collections, so that they can split internally. | 188 /// before the collections, so that they can split internally. |
| 160 class MultiplePositionalRule extends PositionalRule { | 189 class MultiplePositionalRule extends PositionalRule { |
| 161 /// The number of leading collection arguments. | |
| 162 /// | |
| 163 /// This and [_trailingCollections] cannot both be positive. If every | |
| 164 /// argument is a collection, this will be [_arguments.length] and | |
| 165 /// [_trailingCollections] will be 0. | |
| 166 final int _leadingCollections; | |
| 167 | |
| 168 /// The number of trailing collections. | |
| 169 /// | |
| 170 /// This and [_leadingCollections] cannot both be positive. | |
| 171 final int _trailingCollections; | |
| 172 | |
| 173 int get numValues { | 190 int get numValues { |
| 174 // Can split before any one argument, none, or all. | 191 // Can split before any one argument, none, or all. |
| 175 var result = 2 + _arguments.length; | 192 var result = 2 + _arguments.length; |
| 176 | 193 |
| 177 // When there are collection arguments, there are two ways we can split on | 194 // When there are collection arguments, there are two ways we can split on |
| 178 // "all" arguments: | 195 // "all" arguments: |
| 179 // | 196 // |
| 180 // - Split on just the non-collection arguments, and force the collection | 197 // - Split on just the non-collection arguments, and force the collection |
| 181 // arguments to split internally. | 198 // arguments to split internally. |
| 182 // - Split on all of them including the collection arguments, and do not | 199 // - Split on all of them including the collection arguments, and do not |
| 183 // allow the collection arguments to split internally. | 200 // allow the collection arguments to split internally. |
| 184 if (_leadingCollections > 0 || _trailingCollections > 0) result++; | 201 if (_leadingCollections > 0 || _trailingCollections > 0) result++; |
| 185 | 202 |
| 186 return result; | 203 return result; |
| 187 } | 204 } |
| 188 | 205 |
| 189 MultiplePositionalRule( | 206 MultiplePositionalRule( |
| 190 Rule collectionRule, this._leadingCollections, this._trailingCollections) | 207 Rule collectionRule, int leadingCollections, int trailingCollections) |
| 191 : super(collectionRule); | 208 : super(collectionRule, leadingCollections, trailingCollections); |
| 192 | 209 |
| 193 String toString() => "*Pos${super.toString()}"; | 210 String toString() => "*Pos${super.toString()}"; |
| 194 | 211 |
| 195 bool isSplitAtValue(int value, Chunk chunk) { | 212 bool isSplitAtValue(int value, Chunk chunk) { |
| 196 // Split only before the first argument. Keep the entire argument list | 213 // Split only before the first argument. Keep the entire argument list |
| 197 // together on the next line. | 214 // together on the next line. |
| 198 if (value == 1) return chunk == _arguments.first; | 215 if (value == 1) return chunk == _arguments.first; |
| 199 | 216 |
| 200 // Split before a single argument. Try later arguments before earlier ones | 217 // Split before a single argument. Try later arguments before earlier ones |
| 201 // to try to keep as much on the first line as possible. | 218 // to try to keep as much on the first line as possible. |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 if (value == _arguments.length + 1) return 1; | 283 if (value == _arguments.length + 1) return 1; |
| 267 | 284 |
| 268 // Split before all of the arguments, even the collections. We'll allow | 285 // Split before all of the arguments, even the collections. We'll allow |
| 269 // them to split but indent their bodies if they do. | 286 // them to split but indent their bodies if they do. |
| 270 return null; | 287 return null; |
| 271 } | 288 } |
| 272 } | 289 } |
| 273 | 290 |
| 274 /// Splitting rule for a list of named arguments or parameters. Its values mean: | 291 /// Splitting rule for a list of named arguments or parameters. Its values mean: |
| 275 /// | 292 /// |
| 276 /// * 0: Do not split at all. | 293 /// * Do not split at all. |
| 277 /// * 1: Split only before first argument. | 294 /// * Split only before first argument. |
| 278 /// * 2: Split before all arguments, including the first. | 295 /// * Split before all arguments. |
| 279 class NamedRule extends ArgumentRule { | 296 class NamedRule extends ArgumentRule { |
| 280 /// The chunk prior to the first named argument. | |
| 281 Chunk _first; | |
| 282 | |
| 283 /// Whether any of the named arguments are collection literals. | |
| 284 final bool _containsCollections; | |
| 285 | |
| 286 int get numValues => 3; | 297 int get numValues => 3; |
| 287 | 298 |
| 288 NamedRule({bool containsCollections}) | 299 NamedRule( |
| 289 : _containsCollections = containsCollections ?? false; | 300 Rule collectionRule, int leadingCollections, int trailingCollections) |
| 301 : super(collectionRule, leadingCollections, trailingCollections); |
| 290 | 302 |
| 291 void beforeArguments(Chunk chunk) { | 303 bool isSplitAtValue(int value, Chunk chunk) { |
| 292 assert(_first == null); | 304 // Move all arguments to the second line as a unit. |
| 293 _first = chunk; | 305 if (value == 1) return chunk == _arguments.first; |
| 306 |
| 307 // Otherwise, split before all arguments. |
| 308 return true; |
| 294 } | 309 } |
| 295 | 310 |
| 296 bool isSplitAtValue(int value, Chunk chunk) { | 311 int constrain(int value, Rule other) { |
| 297 // Only split before the first argument. | 312 var constrained = super.constrain(value, other); |
| 298 if (value == 1) return chunk == _first; | 313 if (constrained != null) return constrained; |
| 299 | 314 |
| 300 // Split before every argument. | 315 // Decide how to constrain the collection rule. |
| 301 return true; | 316 if (other != _collectionRule) return null; |
| 317 |
| 318 // If all of the collections are in the named arguments, [_collectionRule] |
| 319 // will not be null, but we don't have to handle it. |
| 320 if (_leadingCollections == 0 && _trailingCollections == 0) return null; |
| 321 |
| 322 // If we aren't splitting any args, we can split the collection. |
| 323 if (value == Rule.unsplit) return null; |
| 324 |
| 325 // Split only before the first argument. Don't allow the collections to |
| 326 // split. |
| 327 if (value == 1) return Rule.unsplit; |
| 328 |
| 329 // Split before all of the arguments, even the collections. We'll allow |
| 330 // them to split but indent their bodies if they do. |
| 331 return null; |
| 302 } | 332 } |
| 303 | 333 |
| 304 String toString() => "Named${super.toString()}"; | 334 String toString() => "Named${super.toString()}"; |
| 305 } | 335 } |
| OLD | NEW |