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

Unified Diff: pkg/analyzer/lib/src/services/writer.dart

Issue 381663004: Improve wrapping during formatting. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Clean up tweaks Created 6 years, 5 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 side-by-side diff with in-line comments
Download patch
Index: pkg/analyzer/lib/src/services/writer.dart
diff --git a/pkg/analyzer/lib/src/services/writer.dart b/pkg/analyzer/lib/src/services/writer.dart
index cf0dd74718aaa05917a1b55124c04cfadd0987a8..94a3bc9675a203c7cfa0e84a7e6224a974258b02 100644
--- a/pkg/analyzer/lib/src/services/writer.dart
+++ b/pkg/analyzer/lib/src/services/writer.dart
@@ -84,63 +84,82 @@ class SimpleLineBreaker extends LinePrinter {
var buf = new StringBuffer();
var chunks = breakLine(line);
for (var i = 0; i < chunks.length; ++i) {
+ var chunk = chunks[i];
if (i > 0) {
- buf.write(indent(chunks[i], line.indentLevel));
+ buf.write(indent(chunk, chunk.indent));
} else {
- buf.write(chunks[i]);
+ buf.write(chunk);
}
}
return buf.toString();
}
- String indent(Chunk chunk, int level) =>
- '\n' + indenter(level + 2) + chunk.toString();
+ String indent(Chunk chunk, int level) {
+ return '\n' + indenter(level) + chunk.toString();
+ }
List<Chunk> breakLine(Line line) {
-
- var tokens = preprocess(line.tokens);
-
- var chunks = <Chunk>[];
-
- // The current unbroken line
- var current = new Chunk(maxLength: maxLength);
-
- // A tentative working chunk that will either start a new line or get
- // absorbed into 'current'
- var work = new Chunk(maxLength: maxLength);
-
- tokens.forEach((tok) {
-
- if (goodStart(tok, work)) {
- if (current.fits(work)) {
- current.add(work);
- } else {
- if (current.length > 0) {
- chunks.add(current);
+ List<LineToken> tokens = preprocess(line.tokens);
+ List<Chunk> chunks = <Chunk>[new Chunk(line.indentLevel, maxLength, tokens)];
+ while (true) {
+ List<Chunk> newChunks = <Chunk>[];
+ bool hasChanges = false;
+ for (Chunk chunk in chunks) {
+ tokens = chunk.tokens;
+ if (chunk.length > maxLength) {
+ if (chunk.hasAnySpace()) {
+ int weight = chunk.findMinSpaceWeight();
+ int newIndent = chunk.indent;
+ if (weight == DEFAULT_SPACE_WEIGHT) {
+ int start = 0;
+ int length = 0;
+ for (int i = 0; i < tokens.length; i++) {
+ LineToken token = tokens[i];
+ if (token is SpaceToken && token.breakWeight == weight
+ && i < tokens.length - 1) {
+ LineToken nextToken = tokens[i + 1];
+ if (length + token.length + nextToken.length > maxLength) {
+ newChunks.add(chunk.subChunk(newIndent, start, i));
+ newIndent = chunk.indent + 2;
+ start = i + 1;
+ length = 0;
+ continue;
+ }
+ }
+ length += token.length;
+ }
+ if (start < tokens.length) {
+ newChunks.add(chunk.subChunk(newIndent, start));
+ }
+ } else {
+ List<LineToken> part = [];
+ int start = 0;
+ for (int i = 0; i < tokens.length; i++) {
+ LineToken token = tokens[i];
+ if (token is SpaceToken && token.breakWeight == weight) {
+ newChunks.add(chunk.subChunk(newIndent, start, i));
+ newIndent = chunk.indent + 2;
+ start = i + 1;
+ }
+ }
+ if (start < tokens.length) {
+ newChunks.add(chunk.subChunk(newIndent, start));
+ }
+ }
+ } else {
+ newChunks.add(chunk);
}
- current = work;
- }
- work = new Chunk(start: tok, maxLength: maxLength - current.length);
- } else {
- if (work.fits(tok)) {
- work.add(tok);
} else {
- if (!isAllWhitespace(work) || isLineStart(current)) {
- current.add(work);
- } else if (current.length > 0) {
- chunks.add(current);
- current = new Chunk(maxLength: maxLength);
- }
- work = new Chunk(maxLength: maxLength);
- work.add(tok);
+ newChunks.add(chunk);
+ }
+ if (newChunks.length > chunks.length) {
+ hasChanges = true;
}
}
-
- });
-
- current.add(work);
- if (current.length > 0) {
- chunks.add(current);
+ if (!hasChanges) {
+ break;
+ }
+ chunks = newChunks;
}
return chunks;
}
@@ -150,7 +169,7 @@ class SimpleLineBreaker extends LinePrinter {
var tokens = <LineToken>[];
var curr;
- tok.forEach((token){
+ tok.forEach((token) {
if (token is! SpaceToken) {
if (curr == null) {
curr = token;
@@ -182,15 +201,6 @@ class SimpleLineBreaker extends LinePrinter {
static LineToken merge(LineToken first, LineToken second) =>
new LineToken(first.value + second.value);
-
- bool isAllWhitespace(Chunk chunk) => isWhitespace(chunk.buffer.toString());
-
- bool isLineStart(chunk) => chunk.length == 0 && chunk.start == LINE_START;
-
- /// Test whether this token is a good start for a new working chunk
- bool goodStart(LineToken tok, Chunk workingChunk) =>
- tok is SpaceToken && tok.breakWeight >= workingChunk.start.breakWeight;
-
}
/// Test if this [string] contains only whitespace characters
@@ -200,8 +210,8 @@ bool isWhitespace(String string) => string.codeUnits.every(
/// Special token indicating a line start
final LINE_START = new SpaceToken(0);
-const DEFAULT_SPACE_WEIGHT = 0;
-const UNBREAKABLE_SPACE_WEIGHT = -1;
+const DEFAULT_SPACE_WEIGHT = UNBREAKABLE_SPACE_WEIGHT - 1;
+const UNBREAKABLE_SPACE_WEIGHT = 1000;
/// Simple non-breaking printer
class SimpleLinePrinter extends LinePrinter {
@@ -220,38 +230,58 @@ class SimpleLinePrinter extends LinePrinter {
/// Describes a piece of text in a [Line].
abstract class LineText {
int get length;
- void addTo(Chunk chunk);
}
/// A working piece of text used in calculating line breaks
-class Chunk implements LineText {
+class Chunk {
+ final int indent;
+ final int maxLength;
+ final List<LineToken> tokens = <LineToken>[];
- final StringBuffer buffer = new StringBuffer();
+ Chunk(this.indent, this.maxLength, [List<LineToken> tokens]) {
+ this.tokens.addAll(tokens);
+ }
- int maxLength;
- SpaceToken start;
+ int get length => tokens.fold(0, (len, token) => len + token.length);
- Chunk({this.start, this.maxLength}) {
- if (start == null) {
- start = LINE_START;
- }
+ bool fits(LineToken a, LineToken b) {
+ return length + a.length + a.length <= maxLength;
}
- bool fits(LineText text) => length + text.length <= maxLength;
+ void add(LineToken token) {
+ tokens.add(token);
+ }
- int get length => start.value.length + buffer.length;
+ bool hasAnySpace() {
+ return tokens.any((token) => token is SpaceToken);
+ }
- void add(LineText text) {
- text.addTo(this);
+ bool hasSpaceTokenWithWeight(int weight) {
+ for (var token in tokens) {
+ if (token is SpaceToken && token.breakWeight == weight) {
+ return true;
+ }
+ }
+ return false;
}
- String toString() => buffer.toString();
+ int findMinSpaceWeight() {
Brian Wilkerson 2014/07/09 19:47:15 This seems really inefficient. And what happens if
scheglov 2014/07/09 20:01:41 Ouch... Forgot to optimize it. Thanks!
+ int weight = 0;
+ while (true) {
+ if (hasSpaceTokenWithWeight(weight)) {
+ return weight;
+ }
+ weight++;
+ }
+ }
- void addTo(Chunk chunk) {
- chunk.buffer.write(start.value);
- chunk.buffer.write(buffer.toString());
+ Chunk subChunk(int indentLevel, int start, [int end]) {
+ List<LineToken> subTokens = tokens.sublist(start, end);
+ return new Chunk(indentLevel, maxLength, subTokens);
}
+
+ String toString() => tokens.join();
}
@@ -265,10 +295,6 @@ class LineToken implements LineText {
int get length => lengthLessNewlines(value);
- void addTo(Chunk chunk) {
- chunk.buffer.write(value);
- }
-
int lengthLessNewlines(String str) =>
str.endsWith('\n') ? str.length - 1 : str.length;

Powered by Google App Engine
This is Rietveld 408576698