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_writer; | 5 library dart_style.src.source_writer; |
6 | 6 |
7 import 'dart_formatter.dart'; | 7 import 'dart_formatter.dart'; |
8 import 'chunk.dart'; | 8 import 'chunk.dart'; |
9 import 'debug.dart'; | 9 import 'debug.dart'; |
10 import 'line_splitter.dart'; | 10 import 'line_splitter.dart'; |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 return _chunks.length; | 161 return _chunks.length; |
162 } | 162 } |
163 | 163 |
164 /// Whether there is pending whitespace that depends on the number of | 164 /// Whether there is pending whitespace that depends on the number of |
165 /// newlines in the source. | 165 /// newlines in the source. |
166 /// | 166 /// |
167 /// This is used to avoid calculating the newlines between tokens unless | 167 /// This is used to avoid calculating the newlines between tokens unless |
168 /// actually needed since doing so is slow when done between every single | 168 /// actually needed since doing so is slow when done between every single |
169 /// token pair. | 169 /// token pair. |
170 bool get needsToPreserveNewlines => | 170 bool get needsToPreserveNewlines => |
171 _pendingWhitespace == Whitespace.ONE_OR_TWO_NEWLINES || | 171 _pendingWhitespace == Whitespace.oneOrTwoNewlines || |
172 _pendingWhitespace == Whitespace.SPACE_OR_NEWLINE; | 172 _pendingWhitespace == Whitespace.spaceOrNewline; |
173 | 173 |
174 /// The number of characters of code that can fit in a single line. | 174 /// The number of characters of code that can fit in a single line. |
175 int get pageWidth => _formatter.pageWidth; | 175 int get pageWidth => _formatter.pageWidth; |
176 | 176 |
177 LineWriter(this._formatter, this._buffer) { | 177 LineWriter(this._formatter, this._buffer) { |
178 indent(_formatter.indent); | 178 indent(_formatter.indent); |
179 _beginningIndent = _formatter.indent; | 179 _beginningIndent = _formatter.indent; |
180 } | 180 } |
181 | 181 |
182 /// Writes [string], the text for a single token, to the output. | 182 /// Writes [string], the text for a single token, to the output. |
(...skipping 21 matching lines...) Expand all Loading... |
204 | 204 |
205 /// Writes a [WhitespaceChunk] of [type]. | 205 /// Writes a [WhitespaceChunk] of [type]. |
206 void writeWhitespace(Whitespace type) { | 206 void writeWhitespace(Whitespace type) { |
207 _pendingWhitespace = type; | 207 _pendingWhitespace = type; |
208 } | 208 } |
209 | 209 |
210 /// Write a soft split with its own param at [cost]. | 210 /// Write a soft split with its own param at [cost]. |
211 /// | 211 /// |
212 /// If unsplit, it expands to a space if [space] is `true`. | 212 /// If unsplit, it expands to a space if [space] is `true`. |
213 /// | 213 /// |
214 /// If [cost] is omitted, defaults to [Cost.NORMAL]. Returns the new param. | 214 /// If [cost] is omitted, defaults to [Cost.normal]. Returns the new param. |
215 SplitParam writeSplit({int cost, bool space}) { | 215 SplitParam writeSplit({int cost, bool space}) { |
216 if (cost == null) cost = Cost.NORMAL; | 216 if (cost == null) cost = Cost.normal; |
217 | 217 |
218 var param = new SplitParam(cost); | 218 var param = new SplitParam(cost); |
219 _writeSplit(_indent, _nesting, param, spaceWhenUnsplit: space); | 219 _writeSplit(_indent, _nesting, param, spaceWhenUnsplit: space); |
220 | 220 |
221 // If a split inside a multisplit is chosen, this forces the multisplit too. | 221 // If a split inside a multisplit is chosen, this forces the multisplit too. |
222 // This ensures that, for example, a split inside a collection literal | 222 // This ensures that, for example, a split inside a collection literal |
223 // forces the collection to also go multiline. Since a multisplit's param | 223 // forces the collection to also go multiline. Since a multisplit's param |
224 // also implies *its* surrounding multisplit, this will split the whole | 224 // also implies *its* surrounding multisplit, this will split the whole |
225 // chain of contained multisplits. | 225 // chain of contained multisplits. |
226 if (_multisplits.isNotEmpty && _multisplits.last.param != null) { | 226 if (_multisplits.isNotEmpty && _multisplits.last.param != null) { |
(...skipping 18 matching lines...) Expand all Loading... |
245 // enforce one before the first comment. Example: | 245 // enforce one before the first comment. Example: |
246 // | 246 // |
247 // library foo; | 247 // library foo; |
248 // // comment | 248 // // comment |
249 // | 249 // |
250 // class Bar {} | 250 // class Bar {} |
251 // | 251 // |
252 // Normally, a blank line is required after `library`, but since there is | 252 // Normally, a blank line is required after `library`, but since there is |
253 // one after the comment, we don't need one before it. This is mainly so | 253 // one after the comment, we don't need one before it. This is mainly so |
254 // that commented out directives stick with their preceding group. | 254 // that commented out directives stick with their preceding group. |
255 if (_pendingWhitespace == Whitespace.TWO_NEWLINES && | 255 if (_pendingWhitespace == Whitespace.twoNewlines && |
256 comments.isNotEmpty && | 256 comments.isNotEmpty && |
257 comments.first.linesBefore < 2) { | 257 comments.first.linesBefore < 2) { |
258 if (linesBeforeToken > 1) { | 258 if (linesBeforeToken > 1) { |
259 _pendingWhitespace = Whitespace.NEWLINE; | 259 _pendingWhitespace = Whitespace.newline; |
260 } else { | 260 } else { |
261 for (var i = 1; i < comments.length; i++) { | 261 for (var i = 1; i < comments.length; i++) { |
262 if (comments[i].linesBefore > 1) { | 262 if (comments[i].linesBefore > 1) { |
263 _pendingWhitespace = Whitespace.NEWLINE; | 263 _pendingWhitespace = Whitespace.newline; |
264 break; | 264 break; |
265 } | 265 } |
266 } | 266 } |
267 } | 267 } |
268 } | 268 } |
269 | 269 |
270 // Write each comment and the whitespace between them. | 270 // Write each comment and the whitespace between them. |
271 for (var i = 0; i < comments.length; i++) { | 271 for (var i = 0; i < comments.length; i++) { |
272 var comment = comments[i]; | 272 var comment = comments[i]; |
273 | 273 |
274 preserveNewlines(comment.linesBefore); | 274 preserveNewlines(comment.linesBefore); |
275 | 275 |
276 // Don't emit a space because we'll handle it below. If we emit it here, | 276 // Don't emit a space because we'll handle it below. If we emit it here, |
277 // we may get a trailing space if the comment needs a line before it. | 277 // we may get a trailing space if the comment needs a line before it. |
278 if (_pendingWhitespace == Whitespace.SPACE) _pendingWhitespace = null; | 278 if (_pendingWhitespace == Whitespace.space) _pendingWhitespace = null; |
279 _emitPendingWhitespace(); | 279 _emitPendingWhitespace(); |
280 | 280 |
281 if (comment.linesBefore == 0) { | 281 if (comment.linesBefore == 0) { |
282 // If we're sitting on a split, move the comment before it to adhere it | 282 // If we're sitting on a split, move the comment before it to adhere it |
283 // to the preceding text. | 283 // to the preceding text. |
284 if (_shouldMoveCommentBeforeSplit()) { | 284 if (_shouldMoveCommentBeforeSplit()) { |
285 _chunks.last.allowText(); | 285 _chunks.last.allowText(); |
286 } | 286 } |
287 | 287 |
288 // The comment follows other text, so we need to decide if it gets a | 288 // The comment follows other text, so we need to decide if it gets a |
(...skipping 27 matching lines...) Expand all Loading... |
316 linesAfter = 1; | 316 linesAfter = 1; |
317 } | 317 } |
318 } | 318 } |
319 | 319 |
320 if (linesAfter > 0) _writeHardSplit(nest: true, double: linesAfter > 1); | 320 if (linesAfter > 0) _writeHardSplit(nest: true, double: linesAfter > 1); |
321 } | 321 } |
322 | 322 |
323 // If the comment has text following it (aside from a grouping character), | 323 // If the comment has text following it (aside from a grouping character), |
324 // it needs a trailing space. | 324 // it needs a trailing space. |
325 if (_needsSpaceAfterLastComment(comments, token)) { | 325 if (_needsSpaceAfterLastComment(comments, token)) { |
326 _pendingWhitespace = Whitespace.SPACE; | 326 _pendingWhitespace = Whitespace.space; |
327 } | 327 } |
328 | 328 |
329 preserveNewlines(linesBeforeToken); | 329 preserveNewlines(linesBeforeToken); |
330 } | 330 } |
331 | 331 |
332 /// If the current pending whitespace allows some source discretion, pins | 332 /// If the current pending whitespace allows some source discretion, pins |
333 /// that down given that the source contains [numLines] newlines at that | 333 /// that down given that the source contains [numLines] newlines at that |
334 /// point. | 334 /// point. |
335 void preserveNewlines(int numLines) { | 335 void preserveNewlines(int numLines) { |
336 // If we didn't know how many newlines the user authored between the last | 336 // If we didn't know how many newlines the user authored between the last |
337 // token and this one, now we do. | 337 // token and this one, now we do. |
338 switch (_pendingWhitespace) { | 338 switch (_pendingWhitespace) { |
339 case Whitespace.SPACE_OR_NEWLINE: | 339 case Whitespace.spaceOrNewline: |
340 if (numLines > 0) { | 340 if (numLines > 0) { |
341 _pendingWhitespace = Whitespace.NESTED_NEWLINE; | 341 _pendingWhitespace = Whitespace.nestedNewline; |
342 } else { | 342 } else { |
343 _pendingWhitespace = Whitespace.SPACE; | 343 _pendingWhitespace = Whitespace.space; |
344 } | 344 } |
345 break; | 345 break; |
346 | 346 |
347 case Whitespace.ONE_OR_TWO_NEWLINES: | 347 case Whitespace.oneOrTwoNewlines: |
348 if (numLines > 1) { | 348 if (numLines > 1) { |
349 _pendingWhitespace = Whitespace.TWO_NEWLINES; | 349 _pendingWhitespace = Whitespace.twoNewlines; |
350 } else { | 350 } else { |
351 _pendingWhitespace = Whitespace.NEWLINE; | 351 _pendingWhitespace = Whitespace.newline; |
352 } | 352 } |
353 break; | 353 break; |
354 } | 354 } |
355 } | 355 } |
356 | 356 |
357 /// Increases indentation of the next line by [levels]. | 357 /// Increases indentation of the next line by [levels]. |
358 void indent([int levels = 1]) { | 358 void indent([int levels = 1]) { |
359 while (levels-- > 0) _indentStack.add(-1); | 359 while (levels-- > 0) _indentStack.add(-1); |
360 } | 360 } |
361 | 361 |
362 /// Decreases indentation of the next line by [levels]. | 362 /// Decreases indentation of the next line by [levels]. |
363 void unindent([int levels = 1]) { | 363 void unindent([int levels = 1]) { |
364 while (levels-- > 0) _indentStack.removeLast(); | 364 while (levels-- > 0) _indentStack.removeLast(); |
365 } | 365 } |
366 | 366 |
367 /// Starts a new span with [cost]. | 367 /// Starts a new span with [cost]. |
368 /// | 368 /// |
369 /// Each call to this needs a later matching call to [endSpan]. | 369 /// Each call to this needs a later matching call to [endSpan]. |
370 void startSpan([int cost = Cost.NORMAL]) { | 370 void startSpan([int cost = Cost.normal]) { |
371 _openSpans.add(new Span(_currentChunkIndex, cost)); | 371 _openSpans.add(new Span(_currentChunkIndex, cost)); |
372 } | 372 } |
373 | 373 |
374 /// Ends the innermost span. | 374 /// Ends the innermost span. |
375 void endSpan() { | 375 void endSpan() { |
376 var span = _openSpans.removeLast(); | 376 var span = _openSpans.removeLast(); |
377 span.close(_currentChunkIndex); | 377 span.close(_currentChunkIndex); |
378 | 378 |
379 // A span that just covers a single chunk can't be split anyway. | 379 // A span that just covers a single chunk can't be split anyway. |
380 if (span.start == span.end) return; | 380 if (span.start == span.end) return; |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 | 459 |
460 /// Writes the current pending [Whitespace] to the output, if any. | 460 /// Writes the current pending [Whitespace] to the output, if any. |
461 /// | 461 /// |
462 /// This should only be called after source lines have been preserved to turn | 462 /// This should only be called after source lines have been preserved to turn |
463 /// any ambiguous whitespace into a concrete choice. | 463 /// any ambiguous whitespace into a concrete choice. |
464 void _emitPendingWhitespace() { | 464 void _emitPendingWhitespace() { |
465 if (_pendingWhitespace == null) return; | 465 if (_pendingWhitespace == null) return; |
466 // Output any pending whitespace first now that we know it won't be | 466 // Output any pending whitespace first now that we know it won't be |
467 // trailing. | 467 // trailing. |
468 switch (_pendingWhitespace) { | 468 switch (_pendingWhitespace) { |
469 case Whitespace.SPACE: | 469 case Whitespace.space: |
470 _writeText(" "); | 470 _writeText(" "); |
471 break; | 471 break; |
472 | 472 |
473 case Whitespace.NEWLINE: | 473 case Whitespace.newline: |
474 _writeHardSplit(); | 474 _writeHardSplit(); |
475 break; | 475 break; |
476 | 476 |
477 case Whitespace.NESTED_NEWLINE: | 477 case Whitespace.nestedNewline: |
478 _writeHardSplit(nest: true); | 478 _writeHardSplit(nest: true); |
479 break; | 479 break; |
480 | 480 |
481 case Whitespace.NEWLINE_FLUSH_LEFT: | 481 case Whitespace.newlineFlushLeft: |
482 _writeHardSplit(allowIndent: false); | 482 _writeHardSplit(allowIndent: false); |
483 break; | 483 break; |
484 | 484 |
485 case Whitespace.TWO_NEWLINES: | 485 case Whitespace.twoNewlines: |
486 _writeHardSplit(double: true); | 486 _writeHardSplit(double: true); |
487 break; | 487 break; |
488 | 488 |
489 case Whitespace.SPACE_OR_NEWLINE: | 489 case Whitespace.spaceOrNewline: |
490 case Whitespace.ONE_OR_TWO_NEWLINES: | 490 case Whitespace.oneOrTwoNewlines: |
491 // We should have pinned these down before getting here. | 491 // We should have pinned these down before getting here. |
492 assert(false); | 492 assert(false); |
493 break; | 493 break; |
494 } | 494 } |
495 | 495 |
496 _pendingWhitespace = null; | 496 _pendingWhitespace = null; |
497 } | 497 } |
498 | 498 |
499 /// Returns `true` if the last chunk is a split that should be move after the | 499 /// Returns `true` if the last chunk is a split that should be move after the |
500 /// comment that is about to be written. | 500 /// comment that is about to be written. |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
689 if (splitParams.contains(chunk.param)) { | 689 if (splitParams.contains(chunk.param)) { |
690 chunk.harden(); | 690 chunk.harden(); |
691 } else { | 691 } else { |
692 // If the chunk isn't hardened, but implies something that is, we can | 692 // If the chunk isn't hardened, but implies something that is, we can |
693 // discard the implication since it is always satisfied now. | 693 // discard the implication since it is always satisfied now. |
694 chunk.param.implies.removeWhere(splitParams.contains); | 694 chunk.param.implies.removeWhere(splitParams.contains); |
695 } | 695 } |
696 } | 696 } |
697 } | 697 } |
698 } | 698 } |
OLD | NEW |