Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 source_writer; | 5 library source_writer; |
| 6 | 6 |
| 7 | 7 |
| 8 class Line { | 8 class Line { |
| 9 | 9 |
| 10 final int lineLength; | |
| 11 final tokens = <LineToken>[]; | 10 final tokens = <LineToken>[]; |
| 12 final bool useTabs; | 11 final bool useTabs; |
| 13 final int spacesPerIndent; | 12 final int spacesPerIndent; |
| 13 final LinePrinter printer; | |
| 14 | 14 |
| 15 Line({indent: 0, this.lineLength: 80, this.useTabs: false, | 15 Line({indent: 0, this.useTabs: false, this.spacesPerIndent: 2, |
| 16 this.spacesPerIndent: 2}) { | 16 this.printer: const SimpleLinePrinter()}) { |
| 17 if (indent > 0) { | 17 if (indent > 0) { |
| 18 _indent(indent); | 18 _indent(indent); |
| 19 } | 19 } |
| 20 } | 20 } |
| 21 | 21 |
| 22 void addSpace() { | 22 void addSpace() { |
| 23 addSpaces(1); | 23 addSpaces(1); |
| 24 } | 24 } |
| 25 | 25 |
| 26 void addSpaces(int n) { | 26 void addSpaces(int n, {breakWeight: DEFAULT_SPACE_WEIGHT}) { |
| 27 if (n > 0) { | 27 if (n > 0) { |
| 28 tokens.add(new SpaceToken(n)); | 28 tokens.add(new SpaceToken(n, breakWeight: breakWeight)); |
| 29 } | 29 } |
| 30 } | 30 } |
| 31 | 31 |
| 32 void addToken(LineToken token) { | 32 void addToken(LineToken token) { |
| 33 tokens.add(token); | 33 tokens.add(token); |
| 34 } | 34 } |
| 35 | 35 |
| 36 bool isWhitespace() => tokens.every((tok) => tok is SpaceToken); | 36 bool isWhitespace() => tokens.every((tok) => tok is SpaceToken); |
| 37 | 37 |
| 38 void _indent(int n) { | 38 void _indent(int n) { |
| 39 tokens.add(useTabs ? new TabToken(n) : new SpaceToken(n * spacesPerIndent)); | 39 tokens.add(useTabs ? new TabToken(n) : new SpaceToken(n * spacesPerIndent)); |
| 40 } | 40 } |
| 41 | 41 |
| 42 String toString() { | 42 String toString() => printer.printLine(this); |
| 43 | |
| 44 } | |
| 45 | |
| 46 | |
| 47 /// Base class for line printers | |
| 48 abstract class LinePrinter { | |
| 49 | |
| 50 const LinePrinter(); | |
| 51 | |
| 52 /// Convert this [line] to a [String] representation. | |
| 53 String printLine(Line line); | |
| 54 } | |
| 55 | |
| 56 | |
| 57 /// A simple line breaking [LinePrinter] | |
| 58 class SimpleLineBreaker extends LinePrinter { | |
| 59 | |
| 60 final chunks = <Chunk>[]; | |
| 61 final int maxLength; | |
| 62 | |
| 63 SimpleLineBreaker(this.maxLength); | |
| 64 | |
| 65 String printLine(Line line) { | |
| 66 //TODO(pquitslund): implement | |
| 67 } | |
| 68 | |
| 69 List<Chunk> breakLine(Line line) { | |
|
Brian Wilkerson
2014/01/09 19:29:24
Try as I might, I don't understand how this method
pquitslund
2014/01/09 23:04:12
Ah yes. 'tent' was short-hand for 'tentative'. A
| |
| 70 var chunks = <Chunk>[]; | |
| 71 var current = new Chunk(maxLength: maxLength); | |
| 72 var tent = new Chunk(maxLength: maxLength); | |
| 73 | |
| 74 line.tokens.forEach((tok) { | |
| 75 | |
| 76 if (goodStart(tok, tent)) { | |
| 77 if (current.fits(tent)) { | |
| 78 current.add(tent); | |
| 79 } else { | |
| 80 if (current.length > 0) { | |
| 81 chunks.add(current); | |
| 82 } | |
| 83 current = tent; | |
| 84 } | |
| 85 tent = new Chunk(start: tok, maxLength: maxLength - current.length); | |
| 86 } else { | |
| 87 if (tent.fits(tok)) { | |
| 88 tent.add(tok); | |
| 89 } else { | |
| 90 current.add(tent); | |
| 91 if (current.length > 0) { | |
| 92 chunks.add(current); | |
| 93 current = new Chunk(maxLength: maxLength); | |
| 94 } | |
| 95 tent = new Chunk(maxLength: maxLength); | |
| 96 tent.add(tok); | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 }); | |
| 101 | |
| 102 current.add(tent); | |
| 103 if (current.length > 0) { | |
| 104 chunks.add(current); | |
| 105 } | |
| 106 return chunks; | |
| 107 } | |
| 108 | |
| 109 bool goodStart(LineToken tok, Chunk tent) => | |
| 110 tok is SpaceToken && tok.breakWeight >= tent.start.breakWeight; | |
| 111 | |
| 112 } | |
| 113 | |
| 114 | |
| 115 /// Special token indicating a line start | |
| 116 final LINE_START = new SpaceToken(0); | |
| 117 | |
| 118 const DEFAULT_SPACE_WEIGHT = -1; | |
| 119 | |
| 120 /// Simple non-breaking printer | |
| 121 class SimpleLinePrinter extends LinePrinter { | |
| 122 | |
| 123 const SimpleLinePrinter(); | |
| 124 | |
| 125 String printLine(Line line) { | |
| 43 var buffer = new StringBuffer(); | 126 var buffer = new StringBuffer(); |
| 44 tokens.forEach((tok) => buffer.write(tok.toString())); | 127 line.tokens.forEach((tok) => buffer.write(tok.toString())); |
| 45 return buffer.toString(); | 128 return buffer.toString(); |
| 46 } | 129 } |
| 47 | 130 |
| 48 } | 131 } |
| 49 | 132 |
| 50 | 133 |
| 51 class LineToken { | 134 /// Describes a piece of text in a [Line]. |
| 135 abstract class LineText { | |
| 136 int get length; | |
| 137 void addTo(Chunk chunk); | |
| 138 } | |
| 139 | |
| 140 | |
| 141 /// A working piece of text used in calculating line breaks | |
| 142 class Chunk implements LineText { | |
| 143 | |
| 144 final buffer = new StringBuffer(); | |
| 145 | |
| 146 int maxLength; | |
| 147 SpaceToken start; | |
| 148 | |
| 149 Chunk({this.start, this.maxLength}) { | |
| 150 if (start == null) { | |
| 151 start = LINE_START; | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 bool fits(LineText text) => length + text.length < maxLength; | |
| 156 | |
| 157 int get length => start.value.length + buffer.length; | |
| 158 | |
| 159 void add(LineText text) { | |
| 160 text.addTo(this); | |
| 161 } | |
| 162 | |
| 163 String toString() => buffer.toString().trim(); | |
| 164 | |
| 165 void addTo(Chunk chunk) { | |
| 166 chunk.buffer.write(start.value); | |
| 167 chunk.buffer.write(buffer.toString()); | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 | |
| 172 class LineToken implements LineText { | |
| 52 | 173 |
| 53 final String value; | 174 final String value; |
| 54 | 175 |
| 55 LineToken(this.value); | 176 LineToken(this.value); |
| 56 | 177 |
| 57 String toString() => value; | 178 String toString() => value; |
| 179 | |
| 180 int get length => value.length; | |
| 181 | |
| 182 void addTo(Chunk chunk) { | |
| 183 chunk.buffer.write(value); | |
| 184 } | |
| 58 } | 185 } |
| 59 | 186 |
| 187 | |
| 60 class SpaceToken extends LineToken { | 188 class SpaceToken extends LineToken { |
| 61 | 189 |
| 62 SpaceToken(int n) : super(getSpaces(n)); | 190 final int breakWeight; |
| 191 | |
| 192 SpaceToken(int n, {this.breakWeight: DEFAULT_SPACE_WEIGHT}) : | |
| 193 super(getSpaces(n)); | |
| 63 } | 194 } |
| 64 | 195 |
| 196 | |
| 65 class TabToken extends LineToken { | 197 class TabToken extends LineToken { |
| 66 | 198 |
| 67 TabToken(int n) : super(getTabs(n)); | 199 TabToken(int n) : super(getTabs(n)); |
| 68 } | 200 } |
| 69 | 201 |
| 70 | 202 |
| 71 class NewlineToken extends LineToken { | 203 class NewlineToken extends LineToken { |
| 72 | 204 |
| 73 NewlineToken(String value) : super(value); | 205 NewlineToken(String value) : super(value); |
| 74 } | 206 } |
| 75 | 207 |
| 76 | 208 |
| 77 | |
| 78 class SourceWriter { | 209 class SourceWriter { |
| 79 | 210 |
| 80 final StringBuffer buffer = new StringBuffer(); | 211 final buffer = new StringBuffer(); |
|
Brian Wilkerson
2014/01/09 19:29:24
Not sure why you deleted the type. Because this is
pquitslund
2014/01/09 23:04:12
That was overzealous on my part. Added back.
| |
| 81 Line currentLine; | 212 Line currentLine; |
| 82 | 213 |
| 83 final String lineSeparator; | 214 final String lineSeparator; |
| 84 int indentCount = 0; | 215 int indentCount = 0; |
| 85 | 216 |
| 217 LinePrinter linePrinter; | |
| 86 LineToken _lastToken; | 218 LineToken _lastToken; |
| 87 | 219 |
| 88 SourceWriter({this.indentCount: 0, this.lineSeparator: NEW_LINE}) { | 220 SourceWriter({this.indentCount: 0, this.lineSeparator: NEW_LINE, |
| 89 currentLine = new Line(indent: indentCount); | 221 int maxLineLength: 80}) { |
| 222 linePrinter = new SimpleLinePrinter(); | |
| 223 currentLine = new Line(indent: indentCount, printer: linePrinter); | |
| 90 } | 224 } |
| 91 | 225 |
| 92 LineToken get lastToken => _lastToken; | 226 LineToken get lastToken => _lastToken; |
| 93 | 227 |
| 94 _addToken(LineToken token) { | 228 _addToken(LineToken token) { |
| 95 _lastToken = token; | 229 _lastToken = token; |
| 96 currentLine.addToken(token); | 230 currentLine.addToken(token); |
| 97 } | 231 } |
| 98 | 232 |
| 99 void indent() { | 233 void indent() { |
| 100 ++indentCount; | 234 ++indentCount; |
| 101 } | 235 } |
| 102 | 236 |
| 103 void newline() { | 237 void newline() { |
| 104 if (currentLine.isWhitespace()) { | 238 if (currentLine.isWhitespace()) { |
| 105 currentLine.tokens.clear(); | 239 currentLine.tokens.clear(); |
| 106 } | 240 } |
| 107 _addToken(new NewlineToken(this.lineSeparator)); | 241 _addToken(new NewlineToken(this.lineSeparator)); |
| 108 buffer.write(currentLine.toString()); | 242 buffer.write(currentLine.toString()); |
| 109 currentLine = new Line(indent: indentCount); | 243 currentLine = new Line(indent: indentCount, printer: linePrinter); |
| 110 } | 244 } |
| 111 | 245 |
| 112 void newlines(int num) { | 246 void newlines(int num) { |
| 113 while (num-- > 0) { | 247 while (num-- > 0) { |
| 114 newline(); | 248 newline(); |
| 115 } | 249 } |
| 116 } | 250 } |
| 117 | 251 |
| 118 void print(x) { | 252 void print(x) { |
| 119 _addToken(new LineToken(x)); | 253 _addToken(new LineToken(x)); |
| 120 } | 254 } |
| 121 | 255 |
| 122 void println(String s) { | 256 void println(String s) { |
| 123 print(s); | 257 print(s); |
| 124 newline(); | 258 newline(); |
| 125 } | 259 } |
| 126 | 260 |
| 127 void space() { | 261 void space() { |
| 128 spaces(1); | 262 spaces(1); |
| 129 } | 263 } |
| 130 | 264 |
| 131 void spaces(n) { | 265 void spaces(n, {breakWeight: null}) { |
| 132 currentLine.addSpaces(n); | 266 currentLine.addSpaces(n, breakWeight: breakWeight); |
| 133 } | 267 } |
| 134 | 268 |
| 135 void unindent() { | 269 void unindent() { |
| 136 --indentCount; | 270 --indentCount; |
| 137 } | 271 } |
| 138 | 272 |
| 139 String toString() { | 273 String toString() { |
| 140 var source = new StringBuffer(buffer.toString()); | 274 var source = new StringBuffer(buffer.toString()); |
| 141 if (!currentLine.isWhitespace()) { | 275 if (!currentLine.isWhitespace()) { |
| 142 source.write(currentLine); | 276 source.write(currentLine); |
| 143 } | 277 } |
| 144 return source.toString(); | 278 return source.toString(); |
| 145 } | 279 } |
| 146 | 280 |
| 147 } | 281 } |
| 148 | 282 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 193 | 327 |
| 194 String getTabs(int n) => n < TABS.length ? TABS[n] : repeat('\t', n); | 328 String getTabs(int n) => n < TABS.length ? TABS[n] : repeat('\t', n); |
| 195 | 329 |
| 196 String repeat(String ch, int times) { | 330 String repeat(String ch, int times) { |
| 197 var sb = new StringBuffer(); | 331 var sb = new StringBuffer(); |
| 198 for (var i = 0; i < times; ++i) { | 332 for (var i = 0; i < times; ++i) { |
| 199 sb.write(ch); | 333 sb.write(ch); |
| 200 } | 334 } |
| 201 return sb.toString(); | 335 return sb.toString(); |
| 202 } | 336 } |
| OLD | NEW |