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

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

Issue 987223002: Discard unused nesting levels. (Closed) Base URL: https://github.com/dart-lang/dart_style.git@master
Patch Set: Created 5 years, 9 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') | no next file » | 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.line_splitter; 5 library dart_style.src.line_splitter;
6 6
7 import 'dart:math' as math; 7 import 'dart:math' as math;
8 8
9 import 'chunk.dart'; 9 import 'chunk.dart';
10 import 'debug.dart'; 10 import 'debug.dart';
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
96 /// return a single string that may contain one or more newline characters. 96 /// return a single string that may contain one or more newline characters.
97 /// 97 ///
98 /// Returns a two-element list. The first element will be an [int] indicating 98 /// Returns a two-element list. The first element will be an [int] indicating
99 /// where in [buffer] the selection start point should appear if it was 99 /// where in [buffer] the selection start point should appear if it was
100 /// contained in the formatted list of chunks. Otherwise it will be `null`. 100 /// contained in the formatted list of chunks. Otherwise it will be `null`.
101 /// Likewise, the second element will be non-`null` if the selection endpoint 101 /// Likewise, the second element will be non-`null` if the selection endpoint
102 /// is within the list of chunks. 102 /// is within the list of chunks.
103 List<int> apply(StringBuffer buffer) { 103 List<int> apply(StringBuffer buffer) {
104 if (debugFormatter) dumpLine(_chunks, _indent); 104 if (debugFormatter) dumpLine(_chunks, _indent);
105 105
106 _flattenNestingLevels();
107
106 var splits = _findBestSplits(new LinePrefix()); 108 var splits = _findBestSplits(new LinePrefix());
107 var selection = [null, null]; 109 var selection = [null, null];
108 110
109 // Write each chunk and the split after it. 111 // Write each chunk and the split after it.
110 buffer.write(" " * (_indent * spacesPerIndent)); 112 buffer.write(" " * (_indent * spacesPerIndent));
111 for (var i = 0; i < _chunks.length; i++) { 113 for (var i = 0; i < _chunks.length; i++) {
112 var chunk = _chunks[i]; 114 var chunk = _chunks[i];
113 115
114 // If this chunk contains one of the selection markers, tell the writer 116 // If this chunk contains one of the selection markers, tell the writer
115 // where it ended up in the final output. 117 // where it ended up in the final output.
(...skipping 19 matching lines...) Expand all
135 // Should have a valid set of splits when we get here. 137 // Should have a valid set of splits when we get here.
136 assert(indent != invalidSplits); 138 assert(indent != invalidSplits);
137 } else { 139 } else {
138 if (chunk.spaceWhenUnsplit) buffer.write(" "); 140 if (chunk.spaceWhenUnsplit) buffer.write(" ");
139 } 141 }
140 } 142 }
141 143
142 return selection; 144 return selection;
143 } 145 }
144 146
147 /// Removes any unused nesting levels from the chunks.
148 ///
149 /// The line splitter considers every possible combination of mapping
150 /// indentation to nesting levels when trying to find the best solution. For
151 /// example, it may assign 4 spaces of indentation to level 1, 8 spaces to
152 /// level 3, etc.
153 ///
154 /// It's fairly common for a nesting level to not actually appear at the
155 /// boundary of a chunk. The source visitor may enter more than one level of
156 /// nesting at a point where a split cannot happen. In that case, there's no
157 /// point in trying to assign an indentation level to that nesting level. It
158 /// will never be used because no line will begin at that level of
159 /// indentation.
160 ///
161 /// Worse, if the splitter *does* consider these levels, it can dramatically
162 /// increase solving time. To avoid that, this renumbers all of the nesting
163 /// levels in the chunks to not have any of these unused gaps.
164 void _flattenNestingLevels() {
165 var nestingLevels = _chunks
166 .map((chunk) => chunk.nesting)
167 .where((nesting) => nesting != -1)
168 .toSet()
169 .toList();
170 nestingLevels.sort();
171
172 var nestingMap = {-1: -1};
173 for (var i = 0; i < nestingLevels.length; i++) {
174 nestingMap[nestingLevels[i]] = i;
175 }
176
177 for (var chunk in _chunks) {
178 chunk.nesting = nestingMap[chunk.nesting];
179 }
180 }
181
145 /// Finds the best set of splits to apply to the remainder of the line 182 /// Finds the best set of splits to apply to the remainder of the line
146 /// following [prefix]. 183 /// following [prefix].
147 SplitSet _findBestSplits(LinePrefix prefix) { 184 SplitSet _findBestSplits(LinePrefix prefix) {
148 // Use the memoized result if we have it. 185 // Use the memoized result if we have it.
149 if (_bestSplits.containsKey(prefix)) return _bestSplits[prefix]; 186 if (_bestSplits.containsKey(prefix)) return _bestSplits[prefix];
150 187
151 var indent = prefix.getNextLineIndent(_chunks, _indent); 188 var indent = prefix.getNextLineIndent(_chunks, _indent);
152 189
153 var bestSplits; 190 var bestSplits;
154 var lowestCost; 191 var lowestCost;
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 } 358 }
322 359
323 return false; 360 return false;
324 } 361 }
325 362
326 /// Gets whether the suffix of the line after index [split] contains a soft 363 /// Gets whether the suffix of the line after index [split] contains a soft
327 /// split using [param]. 364 /// split using [param].
328 bool _suffixContainsParam(int split, SplitParam param) { 365 bool _suffixContainsParam(int split, SplitParam param) {
329 if (param == null) return false; 366 if (param == null) return false;
330 367
368 // TODO(rnystrom): Consider caching the set of params that appear at every
369 // suffix.
331 for (var i = split + 1; i < _chunks.length; i++) { 370 for (var i = split + 1; i < _chunks.length; i++) {
332 if (_chunks[i].isSoftSplit && _chunks[i].param == param) { 371 if (_chunks[i].isSoftSplit && _chunks[i].param == param) {
333 return true; 372 return true;
334 } 373 }
335 } 374 }
336 375
337 return false; 376 return false;
338 } 377 }
339 378
340 /// Evaluates the cost (i.e. the relative "badness") of splitting the line 379 /// Evaluates the cost (i.e. the relative "badness") of splitting the line
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
469 var result = []; 508 var result = [];
470 for (var i = 0; i < _splitNesting.length; i++) { 509 for (var i = 0; i < _splitNesting.length; i++) {
471 if (_splitNesting[i] != null) { 510 if (_splitNesting[i] != null) {
472 result.add("$i:${_splitNesting[i]}"); 511 result.add("$i:${_splitNesting[i]}");
473 } 512 }
474 } 513 }
475 514
476 return result.join(" "); 515 return result.join(" ");
477 } 516 }
478 } 517 }
OLDNEW
« no previous file with comments | « lib/src/chunk.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698