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.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 'debug.dart' as debug; | 9 import 'debug.dart' as debug; |
10 import 'line_splitter.dart'; | 10 import 'line_splitter.dart'; |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
84 bool _firstFlushLeft = false; | 84 bool _firstFlushLeft = false; |
85 | 85 |
86 /// Whether there is pending whitespace that depends on the number of | 86 /// Whether there is pending whitespace that depends on the number of |
87 /// newlines in the source. | 87 /// newlines in the source. |
88 /// | 88 /// |
89 /// This is used to avoid calculating the newlines between tokens unless | 89 /// This is used to avoid calculating the newlines between tokens unless |
90 /// actually needed since doing so is slow when done between every single | 90 /// actually needed since doing so is slow when done between every single |
91 /// token pair. | 91 /// token pair. |
92 bool get needsToPreserveNewlines => | 92 bool get needsToPreserveNewlines => |
93 _pendingWhitespace == Whitespace.oneOrTwoNewlines || | 93 _pendingWhitespace == Whitespace.oneOrTwoNewlines || |
94 _pendingWhitespace == Whitespace.spaceOrNewline; | 94 _pendingWhitespace == Whitespace.spaceOrNewline; |
95 | 95 |
96 /// The number of characters of code that can fit in a single line. | 96 /// The number of characters of code that can fit in a single line. |
97 int get pageWidth => _formatter.pageWidth; | 97 int get pageWidth => _formatter.pageWidth; |
98 | 98 |
99 /// The current innermost rule. | 99 /// The current innermost rule. |
100 Rule get rule => _rules.last; | 100 Rule get rule => _rules.last; |
101 | 101 |
102 ChunkBuilder(this._formatter, this._source) | 102 ChunkBuilder(this._formatter, this._source) |
103 : _parent = null, | 103 : _parent = null, |
104 _chunks = [] { | 104 _chunks = [] { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
141 /// Write a split owned by the current innermost rule. | 141 /// Write a split owned by the current innermost rule. |
142 /// | 142 /// |
143 /// If [nesting] is given, uses that. Otherwise, uses the current nesting | 143 /// If [nesting] is given, uses that. Otherwise, uses the current nesting |
144 /// level. If unsplit, it expands to a space if [space] is `true`. | 144 /// level. If unsplit, it expands to a space if [space] is `true`. |
145 /// | 145 /// |
146 /// If [flushLeft] is `true`, then forces the next line to start at column | 146 /// If [flushLeft] is `true`, then forces the next line to start at column |
147 /// one regardless of any indentation or nesting. | 147 /// one regardless of any indentation or nesting. |
148 /// | 148 /// |
149 /// If [isDouble] is passed, forces the split to either be a single or double | 149 /// If [isDouble] is passed, forces the split to either be a single or double |
150 /// newline. Otherwise, leaves it indeterminate. | 150 /// newline. Otherwise, leaves it indeterminate. |
151 Chunk split({bool space, bool isDouble, bool flushLeft}) => | 151 Chunk split({bool space, bool isDouble, bool flushLeft}) => _writeSplit( |
152 _writeSplit(_rules.last, null, | 152 _rules.last, null, |
153 flushLeft: flushLeft, isDouble: isDouble, spaceWhenUnsplit: space); | 153 flushLeft: flushLeft, isDouble: isDouble, spaceWhenUnsplit: space); |
154 | 154 |
155 /// Write a split owned by the current innermost rule. | 155 /// Write a split owned by the current innermost rule. |
156 /// | 156 /// |
157 /// Unlike [split()], this ignores any current expression nesting. It always | 157 /// Unlike [split()], this ignores any current expression nesting. It always |
158 /// indents the next line at the statement level. | 158 /// indents the next line at the statement level. |
159 Chunk blockSplit({bool space, bool isDouble}) => | 159 Chunk blockSplit({bool space, bool isDouble}) => _writeSplit( |
160 _writeSplit(_rules.last, _nesting.blockNesting, | 160 _rules.last, _nesting.blockNesting, |
161 isDouble: isDouble, | 161 isDouble: isDouble, spaceWhenUnsplit: space); |
162 spaceWhenUnsplit: space); | |
163 | 162 |
164 /// Outputs the series of [comments] and associated whitespace that appear | 163 /// Outputs the series of [comments] and associated whitespace that appear |
165 /// before [token] (which is not written by this). | 164 /// before [token] (which is not written by this). |
166 /// | 165 /// |
167 /// The list contains each comment as it appeared in the source between the | 166 /// The list contains each comment as it appeared in the source between the |
168 /// last token written and the next one that's about to be written. | 167 /// last token written and the next one that's about to be written. |
169 /// | 168 /// |
170 /// [linesBeforeToken] is the number of lines between the last comment (or | 169 /// [linesBeforeToken] is the number of lines between the last comment (or |
171 /// previous token if there are no comments) and the next token. | 170 /// previous token if there are no comments) and the next token. |
172 void writeComments(List<SourceComment> comments, int linesBeforeToken, | 171 void writeComments( |
173 String token) { | 172 List<SourceComment> comments, int linesBeforeToken, String token) { |
174 // Corner case: if we require a blank line, but there exists one between | 173 // Corner case: if we require a blank line, but there exists one between |
175 // some of the comments, or after the last one, then we don't need to | 174 // some of the comments, or after the last one, then we don't need to |
176 // enforce one before the first comment. Example: | 175 // enforce one before the first comment. Example: |
177 // | 176 // |
178 // library foo; | 177 // library foo; |
179 // // comment | 178 // // comment |
180 // | 179 // |
181 // class Bar {} | 180 // class Bar {} |
182 // | 181 // |
183 // Normally, a blank line is required after `library`, but since there is | 182 // Normally, a blank line is required after `library`, but since there is |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
240 _chunks.last.allowText(); | 239 _chunks.last.allowText(); |
241 } | 240 } |
242 | 241 |
243 // The comment follows other text, so we need to decide if it gets a | 242 // The comment follows other text, so we need to decide if it gets a |
244 // space before it or not. | 243 // space before it or not. |
245 if (_needsSpaceBeforeComment(isLineComment: comment.isLineComment)) { | 244 if (_needsSpaceBeforeComment(isLineComment: comment.isLineComment)) { |
246 _writeText(" "); | 245 _writeText(" "); |
247 } | 246 } |
248 } else { | 247 } else { |
249 // The comment starts a line, so make sure it stays on its own line. | 248 // The comment starts a line, so make sure it stays on its own line. |
250 _writeHardSplit(nest: true, flushLeft: comment.flushLeft, | 249 _writeHardSplit( |
| 250 nest: true, |
| 251 flushLeft: comment.flushLeft, |
251 double: comment.linesBefore > 1); | 252 double: comment.linesBefore > 1); |
252 } | 253 } |
253 | 254 |
254 _writeText(comment.text); | 255 _writeText(comment.text); |
255 | 256 |
256 if (comment.selectionStart != null) { | 257 if (comment.selectionStart != null) { |
257 startSelectionFromEnd(comment.text.length - comment.selectionStart); | 258 startSelectionFromEnd(comment.text.length - comment.selectionStart); |
258 } | 259 } |
259 | 260 |
260 if (comment.selectionEnd != null) { | 261 if (comment.selectionEnd != null) { |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
453 | 454 |
454 /// Releases the last nesting level captured by [startBlockArgumentNesting]. | 455 /// Releases the last nesting level captured by [startBlockArgumentNesting]. |
455 void endBlockArgumentNesting() { | 456 void endBlockArgumentNesting() { |
456 _blockArgumentNesting.removeLast(); | 457 _blockArgumentNesting.removeLast(); |
457 } | 458 } |
458 | 459 |
459 /// Starts a new block as a child of the current chunk. | 460 /// Starts a new block as a child of the current chunk. |
460 /// | 461 /// |
461 /// Nested blocks are handled using their own independent [LineWriter]. | 462 /// Nested blocks are handled using their own independent [LineWriter]. |
462 ChunkBuilder startBlock() { | 463 ChunkBuilder startBlock() { |
463 var builder = new ChunkBuilder._(this, _formatter, _source, | 464 var builder = |
464 _chunks.last.blockChunks); | 465 new ChunkBuilder._(this, _formatter, _source, _chunks.last.blockChunks); |
465 | 466 |
466 // A block always starts off indented one level. | 467 // A block always starts off indented one level. |
467 builder.indent(); | 468 builder.indent(); |
468 | 469 |
469 return builder; | 470 return builder; |
470 } | 471 } |
471 | 472 |
472 /// Ends this [ChunkBuilder], which must have been created by [startBlock()]. | 473 /// Ends this [ChunkBuilder], which must have been created by [startBlock()]. |
473 /// | 474 /// |
474 /// Forces the chunk that owns the block to split if it can tell that the | 475 /// Forces the chunk that owns the block to split if it can tell that the |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
636 /// was just written and the token that will be written. | 637 /// was just written and the token that will be written. |
637 bool _needsSpaceAfterLastComment(List<SourceComment> comments, String token) { | 638 bool _needsSpaceAfterLastComment(List<SourceComment> comments, String token) { |
638 // Not if there are no comments. | 639 // Not if there are no comments. |
639 if (comments.isEmpty) return false; | 640 if (comments.isEmpty) return false; |
640 | 641 |
641 // Not at the beginning of a line. | 642 // Not at the beginning of a line. |
642 if (!_chunks.last.canAddText) return false; | 643 if (!_chunks.last.canAddText) return false; |
643 | 644 |
644 // Otherwise, it gets a space if the following token is not a delimiter or | 645 // Otherwise, it gets a space if the following token is not a delimiter or |
645 // the empty string, for EOF. | 646 // the empty string, for EOF. |
646 return token != ")" && token != "]" && token != "}" && | 647 return token != ")" && |
647 token != "," && token != ";" && token != ""; | 648 token != "]" && |
| 649 token != "}" && |
| 650 token != "," && |
| 651 token != ";" && |
| 652 token != ""; |
648 } | 653 } |
649 | 654 |
650 /// Appends a hard split with the current indentation and nesting (the latter | 655 /// Appends a hard split with the current indentation and nesting (the latter |
651 /// only if [nest] is `true`). | 656 /// only if [nest] is `true`). |
652 /// | 657 /// |
653 /// If [double] is `true` or `false`, forces a since or double line to be | 658 /// If [double] is `true` or `false`, forces a since or double line to be |
654 /// output. Otherwise, it is left indeterminate. | 659 /// output. Otherwise, it is left indeterminate. |
655 /// | 660 /// |
656 /// If [flushLeft] is `true`, then the split will always cause the next line | 661 /// If [flushLeft] is `true`, then the split will always cause the next line |
657 /// to be at column zero. Otherwise, it uses the normal indentation and | 662 /// to be at column zero. Otherwise, it uses the normal indentation and |
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
882 if (rule.constrain(rule.fullySplitValue, other) == | 887 if (rule.constrain(rule.fullySplitValue, other) == |
883 other.fullySplitValue) { | 888 other.fullySplitValue) { |
884 harden(other); | 889 harden(other); |
885 } | 890 } |
886 } | 891 } |
887 } | 892 } |
888 | 893 |
889 harden(rule); | 894 harden(rule); |
890 } | 895 } |
891 } | 896 } |
OLD | NEW |