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

Side by Side Diff: lib/src/chunk_builder.dart

Issue 1180443003: Don't allow inline block comments to eat pending newlines. (Closed) Base URL: https://github.com/dart-lang/dart_style.git@master
Patch Set: Add a test. Created 5 years, 6 months 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
« no previous file with comments | « lib/src/chunk.dart ('k') | lib/src/whitespace.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_builder; 5 library dart_style.src.chunk_builder;
6 6
7 import 'chunk.dart'; 7 import 'chunk.dart';
8 import 'dart_formatter.dart'; 8 import 'dart_formatter.dart';
9 import 'line_splitter.dart'; 9 import 'line_splitter.dart';
10 import 'line_writer.dart'; 10 import 'line_writer.dart';
(...skipping 14 matching lines...) Expand all
25 25
26 /// The builder for the code surrounding the block that this writer is for, or 26 /// The builder for the code surrounding the block that this writer is for, or
27 /// `null` if this is writing the top-level code. 27 /// `null` if this is writing the top-level code.
28 final ChunkBuilder _parent; 28 final ChunkBuilder _parent;
29 29
30 final SourceCode _source; 30 final SourceCode _source;
31 31
32 final List<Chunk> _chunks; 32 final List<Chunk> _chunks;
33 33
34 /// The whitespace that should be written to [_chunks] before the next 34 /// The whitespace that should be written to [_chunks] before the next
35 /// non-whitespace token or `null` if no whitespace is pending. 35 /// non-whitespace token.
36 /// 36 ///
37 /// This ensures that changes to indentation and nesting also apply to the 37 /// This ensures that changes to indentation and nesting also apply to the
38 /// most recent split, even if the visitor "creates" the split before changing 38 /// most recent split, even if the visitor "creates" the split before changing
39 /// indentation or nesting. 39 /// indentation or nesting.
40 Whitespace _pendingWhitespace; 40 Whitespace _pendingWhitespace = Whitespace.none;
41 41
42 /// The nested stack of rules that are currently in use. 42 /// The nested stack of rules that are currently in use.
43 /// 43 ///
44 /// New chunks are implicitly split by the innermost rule when the chunk is 44 /// New chunks are implicitly split by the innermost rule when the chunk is
45 /// ended. 45 /// ended.
46 final _rules = <Rule>[]; 46 final _rules = <Rule>[];
47 47
48 /// The list of rules that are waiting until the next whitespace has been 48 /// The list of rules that are waiting until the next whitespace has been
49 /// written before they start. 49 /// written before they start.
50 final _lazyRules = <Rule>[]; 50 final _lazyRules = <Rule>[];
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 Chunk split({int nesting, bool space, bool flushLeft}) => 138 Chunk split({int nesting, bool space, bool flushLeft}) =>
139 _writeSplit(_rules.last, 139 _writeSplit(_rules.last,
140 nesting: nesting, flushLeft: flushLeft, spaceWhenUnsplit: space); 140 nesting: nesting, flushLeft: flushLeft, spaceWhenUnsplit: space);
141 141
142 /// Outputs the series of [comments] and associated whitespace that appear 142 /// Outputs the series of [comments] and associated whitespace that appear
143 /// before [token] (which is not written by this). 143 /// before [token] (which is not written by this).
144 /// 144 ///
145 /// The list contains each comment as it appeared in the source between the 145 /// The list contains each comment as it appeared in the source between the
146 /// last token written and the next one that's about to be written. 146 /// last token written and the next one that's about to be written.
147 /// 147 ///
148 /// [linesBeforeToken] is number of lines between the last comment (or 148 /// [linesBeforeToken] is the number of lines between the last comment (or
149 /// previous token if there are no comments) and the next token. 149 /// previous token if there are no comments) and the next token.
150 void writeComments(List<SourceComment> comments, int linesBeforeToken, 150 void writeComments(List<SourceComment> comments, int linesBeforeToken,
151 String token) { 151 String token) {
152 // Corner case: if we require a blank line, but there exists one between 152 // Corner case: if we require a blank line, but there exists one between
153 // some of the comments, or after the last one, then we don't need to 153 // some of the comments, or after the last one, then we don't need to
154 // enforce one before the first comment. Example: 154 // enforce one before the first comment. Example:
155 // 155 //
156 // library foo; 156 // library foo;
157 // // comment 157 // // comment
158 // 158 //
(...skipping 10 matching lines...) Expand all
169 } else { 169 } else {
170 for (var i = 1; i < comments.length; i++) { 170 for (var i = 1; i < comments.length; i++) {
171 if (comments[i].linesBefore > 1) { 171 if (comments[i].linesBefore > 1) {
172 _pendingWhitespace = Whitespace.newline; 172 _pendingWhitespace = Whitespace.newline;
173 break; 173 break;
174 } 174 }
175 } 175 }
176 } 176 }
177 } 177 }
178 178
179 // Corner case: if the comments are completely inline (i.e. just a series
180 // of block comments with no newlines before, after, or between them), then
181 // they will eat any pending newlines. Make sure that doesn't happen by
182 // putting the pending whitespace before the first comment and moving them
183 // to their own line. Turns this:
184 //
185 // library foo; /* a */ /* b */ import 'a.dart';
186 //
187 // into:
188 //
189 // library foo;
190 //
191 // /* a */ /* b */
192 // import 'a.dart';
193 if (linesBeforeToken == 0 &&
194 comments.every((comment) => comment.isInline)) {
195 if (_pendingWhitespace.minimumLines > 0) {
196 comments.first.linesBefore = _pendingWhitespace.minimumLines;
197 linesBeforeToken = 1;
198 }
199 }
200
179 // Write each comment and the whitespace between them. 201 // Write each comment and the whitespace between them.
180 for (var i = 0; i < comments.length; i++) { 202 for (var i = 0; i < comments.length; i++) {
181 var comment = comments[i]; 203 var comment = comments[i];
182 204
183 preserveNewlines(comment.linesBefore); 205 preserveNewlines(comment.linesBefore);
184 206
185 // Don't emit a space because we'll handle it below. If we emit it here, 207 // Don't emit a space because we'll handle it below. If we emit it here,
186 // we may get a trailing space if the comment needs a line before it. 208 // we may get a trailing space if the comment needs a line before it.
187 if (_pendingWhitespace == Whitespace.space) _pendingWhitespace = null; 209 if (_pendingWhitespace == Whitespace.space) {
210 _pendingWhitespace = Whitespace.none;
211 }
188 _emitPendingWhitespace(); 212 _emitPendingWhitespace();
189 213
190 if (comment.linesBefore == 0) { 214 if (comment.linesBefore == 0) {
191 // If we're sitting on a split, move the comment before it to adhere it 215 // If we're sitting on a split, move the comment before it to adhere it
192 // to the preceding text. 216 // to the preceding text.
193 if (_shouldMoveCommentBeforeSplit()) { 217 if (_shouldMoveCommentBeforeSplit()) {
194 _chunks.last.allowText(); 218 _chunks.last.allowText();
195 } 219 }
196 220
197 // The comment follows other text, so we need to decide if it gets a 221 // The comment follows other text, so we need to decide if it gets a
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after
485 isCompilationUnit: _source.isCompilationUnit, 509 isCompilationUnit: _source.isCompilationUnit,
486 selectionStart: selectionStart, 510 selectionStart: selectionStart,
487 selectionLength: selectionLength); 511 selectionLength: selectionLength);
488 } 512 }
489 513
490 /// Writes the current pending [Whitespace] to the output, if any. 514 /// Writes the current pending [Whitespace] to the output, if any.
491 /// 515 ///
492 /// This should only be called after source lines have been preserved to turn 516 /// This should only be called after source lines have been preserved to turn
493 /// any ambiguous whitespace into a concrete choice. 517 /// any ambiguous whitespace into a concrete choice.
494 void _emitPendingWhitespace() { 518 void _emitPendingWhitespace() {
495 if (_pendingWhitespace == null) return;
496 // Output any pending whitespace first now that we know it won't be 519 // Output any pending whitespace first now that we know it won't be
497 // trailing. 520 // trailing.
498 switch (_pendingWhitespace) { 521 switch (_pendingWhitespace) {
499 case Whitespace.space: 522 case Whitespace.space:
500 _writeText(" "); 523 _writeText(" ");
501 break; 524 break;
502 525
503 case Whitespace.newline: 526 case Whitespace.newline:
504 _writeHardSplit(); 527 _writeHardSplit();
505 break; 528 break;
(...skipping 10 matching lines...) Expand all
516 _writeHardSplit(double: true); 539 _writeHardSplit(double: true);
517 break; 540 break;
518 541
519 case Whitespace.spaceOrNewline: 542 case Whitespace.spaceOrNewline:
520 case Whitespace.oneOrTwoNewlines: 543 case Whitespace.oneOrTwoNewlines:
521 // We should have pinned these down before getting here. 544 // We should have pinned these down before getting here.
522 assert(false); 545 assert(false);
523 break; 546 break;
524 } 547 }
525 548
526 _pendingWhitespace = null; 549 _pendingWhitespace = Whitespace.none;
527 } 550 }
528 551
529 /// Returns `true` if the last chunk is a split that should be move after the 552 /// Returns `true` if the last chunk is a split that should be move after the
530 /// comment that is about to be written. 553 /// comment that is about to be written.
531 bool _shouldMoveCommentBeforeSplit() { 554 bool _shouldMoveCommentBeforeSplit() {
532 // Not if there is nothing before it. 555 // Not if there is nothing before it.
533 if (_chunks.isEmpty) return false; 556 if (_chunks.isEmpty) return false;
534 557
535 // If the text before the split is an open grouping character, we don't 558 // If the text before the split is an open grouping character, we don't
536 // want to adhere the comment to that. 559 // want to adhere the comment to that.
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after
820 if (rule.constrain(rule.fullySplitValue, other) == 843 if (rule.constrain(rule.fullySplitValue, other) ==
821 other.fullySplitValue) { 844 other.fullySplitValue) {
822 harden(other); 845 harden(other);
823 } 846 }
824 } 847 }
825 } 848 }
826 849
827 harden(rule); 850 harden(rule);
828 } 851 }
829 } 852 }
OLDNEW
« no previous file with comments | « lib/src/chunk.dart ('k') | lib/src/whitespace.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698