Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(683)

Side by Side Diff: packages/dart_style/lib/src/chunk.dart

Issue 1521693002: Roll Observatory deps (charted -> ^0.3.0) (Closed) Base URL: https://chromium.googlesource.com/external/github.com/dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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.chunk; 5 library dart_style.src.chunk;
6 6
7 import 'fast_hash.dart'; 7 import 'fast_hash.dart';
8 import 'nesting_level.dart'; 8 import 'nesting_level.dart';
9 import 'rule/rule.dart'; 9 import 'rule/rule.dart';
10 10
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 /// line starts after this chunk. A single statement may be indented multiple 85 /// line starts after this chunk. A single statement may be indented multiple
86 /// times if the splits occur in more deeply nested expressions, for example: 86 /// times if the splits occur in more deeply nested expressions, for example:
87 /// 87 ///
88 /// // 40 columns | 88 /// // 40 columns |
89 /// someFunctionName(argument, argument, 89 /// someFunctionName(argument, argument,
90 /// argument, anotherFunction(argument, 90 /// argument, anotherFunction(argument,
91 /// argument)); 91 /// argument));
92 NestingLevel get nesting => _nesting; 92 NestingLevel get nesting => _nesting;
93 NestingLevel _nesting; 93 NestingLevel _nesting;
94 94
95 /// If this chunk marks the beginning of a block, these are the chunks 95 /// If this chunk marks the beginning of a block, this contains the child
96 /// contained in the block. 96 /// chunks and other data about that nested block.
97 final blockChunks = <Chunk>[]; 97 ChunkBlock get block => _block;
98 ChunkBlock _block;
99
100 /// Whether this chunk has a [block].
101 bool get isBlock => _block != null;
98 102
99 /// Whether it's valid to add more text to this chunk or not. 103 /// Whether it's valid to add more text to this chunk or not.
100 /// 104 ///
101 /// Chunks are built up by adding text and then "capped off" by having their 105 /// Chunks are built up by adding text and then "capped off" by having their
102 /// split information set by calling [handleSplit]. Once the latter has been 106 /// split information set by calling [handleSplit]. Once the latter has been
103 /// called, no more text should be added to the chunk since it would appear 107 /// called, no more text should be added to the chunk since it would appear
104 /// *before* the split. 108 /// *before* the split.
105 bool get canAddText => _rule == null; 109 bool get canAddText => _rule == null;
106 110
107 /// The [Rule] that controls when a split should occur after this chunk. 111 /// The [Rule] that controls when a split should occur after this chunk.
108 /// 112 ///
109 /// Multiple splits may share a [Rule]. 113 /// Multiple splits may share a [Rule].
110 Rule get rule => _rule; 114 Rule get rule => _rule;
111 Rule _rule; 115 Rule _rule;
112 116
113 /// Whether this chunk is always followed by a newline or whether the line
114 /// splitter may choose to keep the next chunk on the same line.
115 bool get isHardSplit => _rule is HardSplitRule;
116
117 /// Whether or not an extra blank line should be output after this chunk if 117 /// Whether or not an extra blank line should be output after this chunk if
118 /// it's split. 118 /// it's split.
119 /// 119 ///
120 /// Internally, this can be either `true`, `false`, or `null`. The latter is 120 /// Internally, this can be either `true`, `false`, or `null`. The latter is
121 /// an indeterminate state that lets later modifications to the split decide 121 /// an indeterminate state that lets later modifications to the split decide
122 /// whether it should be double or not. 122 /// whether it should be double or not.
123 /// 123 ///
124 /// However, this getter does not expose that. It will return `false` if the 124 /// However, this getter does not expose that. It will return `false` if the
125 /// chunk is still indeterminate. 125 /// chunk is still indeterminate.
126 bool get isDouble => _isDouble != null ? _isDouble : false; 126 bool get isDouble => _isDouble != null ? _isDouble : false;
127 bool _isDouble; 127 bool _isDouble;
128 128
129 /// If `true`, then the line after this chunk should always be at column 129 /// If `true`, then the line after this chunk should always be at column
130 /// zero regardless of any indentation or expression nesting. 130 /// zero regardless of any indentation or expression nesting.
131 /// 131 ///
132 /// Used for multi-line strings and commented out code. 132 /// Used for multi-line strings and commented out code.
133 bool get flushLeft => _flushLeft; 133 bool get flushLeft => _flushLeft;
134 bool _flushLeft = false; 134 bool _flushLeft = false;
135 135
136 /// If `true`, then the line after this chunk and its contained block should 136 /// If `true`, then the line after this chunk and its contained block should
137 /// be flush left. 137 /// be flush left.
138 bool get flushLeftAfter { 138 bool get flushLeftAfter {
139 if (blockChunks.isEmpty) return _flushLeft; 139 if (!isBlock) return _flushLeft;
140 140
141 return blockChunks.last.flushLeftAfter; 141 return _block.chunks.last.flushLeftAfter;
142 } 142 }
143 143
144 /// Whether this chunk should append an extra space if it does not split. 144 /// Whether this chunk should append an extra space if it does not split.
145 /// 145 ///
146 /// This is `true`, for example, in a chunk that ends with a ",". 146 /// This is `true`, for example, in a chunk that ends with a ",".
147 bool get spaceWhenUnsplit => _spaceWhenUnsplit; 147 bool get spaceWhenUnsplit => _spaceWhenUnsplit;
148 bool _spaceWhenUnsplit = false; 148 bool _spaceWhenUnsplit = false;
149 149
150 /// Whether this chunk marks the end of a range of chunks that can be line 150 /// Whether this chunk marks the end of a range of chunks that can be line
151 /// split independently of the following chunks. 151 /// split independently of the following chunks.
152 bool get canDivide { 152 bool get canDivide {
153 // Have to call markDivide() before accessing this. 153 // Have to call markDivide() before accessing this.
154 assert(_canDivide != null); 154 assert(_canDivide != null);
155 return _canDivide; 155 return _canDivide;
156 } 156 }
157 157
158 bool _canDivide; 158 bool _canDivide;
159 159
160 /// The number of characters in this chunk when unsplit. 160 /// The number of characters in this chunk when unsplit.
161 int get length => _text.length + (spaceWhenUnsplit ? 1 : 0); 161 int get length => _text.length + (spaceWhenUnsplit ? 1 : 0);
162 162
163 /// The unsplit length of all of this chunk's block contents. 163 /// The unsplit length of all of this chunk's block contents.
164 /// 164 ///
165 /// Does not include this chunk's own length, just the length of its child 165 /// Does not include this chunk's own length, just the length of its child
166 /// block chunks (recursively). 166 /// block chunks (recursively).
167 int get unsplitBlockLength { 167 int get unsplitBlockLength {
168 if (_block == null) return 0;
169
168 var length = 0; 170 var length = 0;
169 for (var chunk in blockChunks) { 171 for (var chunk in _block.chunks) {
170 length += chunk.length + chunk.unsplitBlockLength; 172 length += chunk.length + chunk.unsplitBlockLength;
171 } 173 }
172 174
173 return length; 175 return length;
174 } 176 }
175 177
176 /// The [Span]s that contain this chunk. 178 /// The [Span]s that contain this chunk.
177 final spans = <Span>[]; 179 final spans = <Span>[];
178 180
179 /// Creates a new chunk starting with [_text]. 181 /// Creates a new chunk starting with [_text].
180 Chunk(this._text); 182 Chunk(this._text);
181 183
182 /// Discard the split for the chunk and put it back into the state where more 184 /// Discard the split for the chunk and put it back into the state where more
183 /// text can be appended. 185 /// text can be appended.
184 void allowText() { 186 void allowText() {
185 _rule = null; 187 _rule = null;
186 } 188 }
187 189
188 /// Append [text] to the end of the split's text. 190 /// Append [text] to the end of the split's text.
189 void appendText(String text) { 191 void appendText(String text) {
190 assert(canAddText); 192 assert(canAddText);
191 _text += text; 193 _text += text;
192 } 194 }
193 195
194 /// Forces this soft split to become a hard split.
195 ///
196 /// This is called on the soft splits owned by a rule that decides to harden
197 /// when it finds out another hard split occurs within its chunks.
198 void harden() {
199 _rule = new HardSplitRule();
200 spans.clear();
201 }
202
203 /// Finishes off this chunk with the given [rule] and split information. 196 /// Finishes off this chunk with the given [rule] and split information.
204 /// 197 ///
205 /// This may be called multiple times on the same split since the splits 198 /// This may be called multiple times on the same split since the splits
206 /// produced by walking the source and the splits coming from comments and 199 /// produced by walking the source and the splits coming from comments and
207 /// preserved whitespace often overlap. When that happens, this has logic to 200 /// preserved whitespace often overlap. When that happens, this has logic to
208 /// combine that information into a single split. 201 /// combine that information into a single split.
209 void applySplit(Rule rule, int indent, NestingLevel nesting, 202 void applySplit(Rule rule, int indent, NestingLevel nesting,
210 {bool flushLeft, bool spaceWhenUnsplit, bool isDouble}) { 203 {bool flushLeft, bool isDouble, bool space}) {
211 if (flushLeft == null) flushLeft = false; 204 if (flushLeft == null) flushLeft = false;
212 if (spaceWhenUnsplit == null) spaceWhenUnsplit = false; 205 if (space == null) space = false;
213 if (isHardSplit || rule is HardSplitRule) { 206 if (rule.isHardened) {
214 // A hard split always wins. 207 // A hard split always wins.
215 _rule = rule; 208 _rule = rule;
216 } else if (_rule == null) { 209 } else if (_rule == null) {
217 // If the chunk hasn't been initialized yet, just inherit the rule. 210 // If the chunk hasn't been initialized yet, just inherit the rule.
218 _rule = rule; 211 _rule = rule;
219 } 212 }
220 213
221 // Last split settings win. 214 // Last split settings win.
222 _flushLeft = flushLeft; 215 _flushLeft = flushLeft;
223 _nesting = nesting; 216 _nesting = nesting;
224 _indent = indent; 217 _indent = indent;
225 218
226 _spaceWhenUnsplit = spaceWhenUnsplit; 219 _spaceWhenUnsplit = space;
227 220
228 // Pin down the double state, if given and we haven't already. 221 // Pin down the double state, if given and we haven't already.
229 if (_isDouble == null) _isDouble = isDouble; 222 if (_isDouble == null) _isDouble = isDouble;
230 } 223 }
231 224
225 /// Turns this chunk into one that can contain a block of child chunks.
226 void makeBlock(Chunk blockArgument) {
227 assert(_block == null);
228 _block = new ChunkBlock(blockArgument);
229 }
230
231 /// Returns `true` if the block body owned by this chunk should be expression
232 /// indented given a set of rule values provided by [getValue].
233 bool indentBlock(int getValue(Rule rule)) {
234 if (_block == null) return false;
235 if (_block.argument == null) return false;
236
237 return _block.argument.rule
238 .isSplit(getValue(_block.argument.rule), _block.argument);
239 }
240
232 // Mark whether this chunk can divide the range of chunks. 241 // Mark whether this chunk can divide the range of chunks.
233 void markDivide(canDivide) { 242 void markDivide(canDivide) {
234 // Should only do this once. 243 // Should only do this once.
235 assert(_canDivide == null); 244 assert(_canDivide == null);
236 245
237 _canDivide = canDivide; 246 _canDivide = canDivide;
238 } 247 }
239 248
240 String toString() { 249 String toString() {
241 var parts = []; 250 var parts = [];
242 251
243 if (text.isNotEmpty) parts.add(text); 252 if (text.isNotEmpty) parts.add(text);
244 253
245 if (_indent != null) parts.add("indent:$_indent"); 254 if (_indent != null) parts.add("indent:$_indent");
246 if (spaceWhenUnsplit) parts.add("space"); 255 if (spaceWhenUnsplit == true) parts.add("space");
247 if (_isDouble) parts.add("double"); 256 if (_isDouble == true) parts.add("double");
248 if (_flushLeft) parts.add("flush"); 257 if (_flushLeft == true) parts.add("flush");
249 258
250 if (_rule == null) { 259 if (_rule == null) {
251 parts.add("(no split)"); 260 parts.add("(no split)");
252 } else if (isHardSplit) {
253 parts.add("hard");
254 } else { 261 } else {
255 parts.add(rule.toString()); 262 parts.add(rule.toString());
263 if (rule.isHardened) parts.add("(hard)");
256 264
257 if (_rule.outerRules.isNotEmpty) { 265 if (_rule.constrainedRules.isNotEmpty) {
258 parts.add("-> ${_rule.outerRules.join(' ')}"); 266 parts.add("-> ${_rule.constrainedRules.join(' ')}");
259 } 267 }
260 } 268 }
261 269
262 return parts.join(" "); 270 return parts.join(" ");
263 } 271 }
264 } 272 }
265 273
274 /// The child chunks owned by a chunk that begins a "block" -- an actual block
275 /// statement, function expression, or collection literal.
276 class ChunkBlock {
277 /// If this block is for a collection literal in an argument list, this will
278 /// be the chunk preceding this literal argument.
279 ///
280 /// That chunk is owned by the argument list and if it splits, this collection
281 /// may need extra expression-level indentation.
282 final Chunk argument;
283
284 /// The child chunks in this block.
285 final List<Chunk> chunks = [];
286
287 ChunkBlock(this.argument);
288 }
289
266 /// Constants for the cost heuristics used to determine which set of splits is 290 /// Constants for the cost heuristics used to determine which set of splits is
267 /// most desirable. 291 /// most desirable.
268 class Cost { 292 class Cost {
269 /// The cost of splitting after the `=>` in a lambda or arrow-bodied member. 293 /// The cost of splitting after the `=>` in a lambda or arrow-bodied member.
270 /// 294 ///
271 /// We make this zero because there is already a span around the entire body 295 /// We make this zero because there is already a span around the entire body
272 /// and we generally do prefer splitting after the `=>` over other places. 296 /// and we generally do prefer splitting after the `=>` over other places.
273 static const arrow = 0; 297 static const arrow = 0;
274 298
275 /// The default cost. 299 /// The default cost.
276 /// 300 ///
277 /// This isn't zero because we want to ensure all splitting has *some* cost, 301 /// This isn't zero because we want to ensure all splitting has *some* cost,
278 /// otherwise, the formatter won't try to keep things on one line at all. 302 /// otherwise, the formatter won't try to keep things on one line at all.
279 /// Most splits and spans use this. Greater costs tend to come from a greater 303 /// Most splits and spans use this. Greater costs tend to come from a greater
280 /// number of nested spans. 304 /// number of nested spans.
281 static const normal = 1; 305 static const normal = 1;
282 306
283 /// Splitting after a "=" both for assignment and initialization. 307 /// Splitting after a "=".
284 static const assignment = 2; 308 static const assign = 1;
309
310 /// Splitting after a "=" when the right-hand side is a collection or cascade.
311 static const assignBlock = 2;
285 312
286 /// Splitting before the first argument when it happens to be a function 313 /// Splitting before the first argument when it happens to be a function
287 /// expression with a block body. 314 /// expression with a block body.
288 static const firstBlockArgument = 2; 315 static const firstBlockArgument = 2;
289 316
290 /// The series of positional arguments. 317 /// The series of positional arguments.
291 static const positionalArguments = 2; 318 static const positionalArguments = 2;
292 319
293 /// Splitting inside the brackets of a list with only one element. 320 /// Splitting inside the brackets of a list with only one element.
294 static const singleElementList = 2; 321 static const singleElementList = 2;
295 322
296 /// Splitting the internals of collection literal arguments. 323 /// Splitting the internals of collection literal arguments.
297 /// 324 ///
298 /// Used to prefer splitting at the argument boundary over splitting the 325 /// Used to prefer splitting at the argument boundary over splitting the
299 /// collection contents. 326 /// collection contents.
300 static const splitCollections = 2; 327 static const splitCollections = 2;
301 328
329 /// Splitting on the "." in a named constructor.
330 static const constructorName = 3;
331
302 /// Splitting before a type argument or type parameter. 332 /// Splitting before a type argument or type parameter.
303 static const typeArgument = 4; 333 static const typeArgument = 4;
304 } 334 }
305 335
306 /// The in-progress state for a [Span] that has been started but has not yet 336 /// The in-progress state for a [Span] that has been started but has not yet
307 /// been completed. 337 /// been completed.
308 class OpenSpan { 338 class OpenSpan {
309 /// Index of the first chunk contained in this span. 339 /// Index of the first chunk contained in this span.
310 int get start => _start; 340 int get start => _start;
311 int _start; 341 int _start;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 /// output. This way, commented out chunks of code do not get erroneously 389 /// output. This way, commented out chunks of code do not get erroneously
360 /// re-indented. 390 /// re-indented.
361 final bool flushLeft; 391 final bool flushLeft;
362 392
363 /// Whether this comment is an inline block comment. 393 /// Whether this comment is an inline block comment.
364 bool get isInline => linesBefore == 0 && !isLineComment; 394 bool get isInline => linesBefore == 0 && !isLineComment;
365 395
366 SourceComment(this.text, this.linesBefore, 396 SourceComment(this.text, this.linesBefore,
367 {this.isLineComment, this.flushLeft}); 397 {this.isLineComment, this.flushLeft});
368 } 398 }
OLDNEW
« no previous file with comments | « packages/dart_style/lib/src/call_chain_visitor.dart ('k') | packages/dart_style/lib/src/chunk_builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698