| 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 formatter_impl; | 5 library formatter_impl; |
| 6 | 6 |
| 7 import 'dart:math'; | 7 import 'dart:math'; |
| 8 | 8 |
| 9 import 'package:analyzer_experimental/analyzer.dart'; | 9 import 'package:analyzer_experimental/analyzer.dart'; |
| 10 import 'package:analyzer_experimental/src/generated/parser.dart'; | 10 import 'package:analyzer_experimental/src/generated/parser.dart'; |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 final SourceWriter writer; | 327 final SourceWriter writer; |
| 328 | 328 |
| 329 /// Cached line info for calculating blank lines. | 329 /// Cached line info for calculating blank lines. |
| 330 LineInfo lineInfo; | 330 LineInfo lineInfo; |
| 331 | 331 |
| 332 /// Cached previous token for calculating preceding whitespace. | 332 /// Cached previous token for calculating preceding whitespace. |
| 333 Token previousToken; | 333 Token previousToken; |
| 334 | 334 |
| 335 /// A flag to indicate that a newline should be emitted before the next token. | 335 /// A flag to indicate that a newline should be emitted before the next token. |
| 336 bool needsNewline = false; | 336 bool needsNewline = false; |
| 337 |
| 338 /// A counter for spaces that should be emitted preceding the next token. |
| 339 int leadingSpaces = 0; |
| 337 | 340 |
| 338 /// Used for matching EOL comments | 341 /// Used for matching EOL comments |
| 339 final twoSlashes = new RegExp(r'//[^/]'); | 342 final twoSlashes = new RegExp(r'//[^/]'); |
| 340 | 343 |
| 341 /// Original pre-format selection information (may be null). | 344 /// Original pre-format selection information (may be null). |
| 342 final Selection preSelection; | 345 final Selection preSelection; |
| 343 | 346 |
| 344 /// Post format selection information. | 347 /// Post format selection information. |
| 345 Selection selection; | 348 Selection selection; |
| 346 | 349 |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 533 } | 536 } |
| 534 | 537 |
| 535 visitConstructorDeclaration(ConstructorDeclaration node) { | 538 visitConstructorDeclaration(ConstructorDeclaration node) { |
| 536 modifier(node.externalKeyword); | 539 modifier(node.externalKeyword); |
| 537 modifier(node.constKeyword); | 540 modifier(node.constKeyword); |
| 538 modifier(node.factoryKeyword); | 541 modifier(node.factoryKeyword); |
| 539 visit(node.returnType); | 542 visit(node.returnType); |
| 540 token(node.period); | 543 token(node.period); |
| 541 visit(node.name); | 544 visit(node.name); |
| 542 visit(node.parameters); | 545 visit(node.parameters); |
| 543 token(node.separator /* = or : */, precededBy: space, followedBy: space); | 546 |
| 544 visitNodes(node.initializers, separatedBy: commaSeperator); | 547 // Check for redirects or initializer lists |
| 545 visit(node.redirectedConstructor); | 548 if (node.separator != null) { |
| 549 if (node.redirectedConstructor != null) { |
| 550 visitConstructorRedirects(node); |
| 551 } else { |
| 552 visitConstructorInitializers(node); |
| 553 } |
| 554 } |
| 546 | 555 |
| 547 visitPrefixedBody(space, node.body); | 556 visitPrefixedBody(space, node.body); |
| 548 } | 557 } |
| 549 | 558 |
| 559 visitConstructorInitializers(ConstructorDeclaration node) { |
| 560 newlines(); |
| 561 indent(2); |
| 562 token(node.separator /* : */); |
| 563 space(); |
| 564 for (var i = 0; i < node.initializers.length; i++) { |
| 565 if (i > 0) { |
| 566 comma(); |
| 567 newlines(); |
| 568 space(2); |
| 569 } |
| 570 node.initializers[i].accept(this); |
| 571 } |
| 572 unindent(2); |
| 573 } |
| 574 |
| 575 visitConstructorRedirects(ConstructorDeclaration node) { |
| 576 token(node.separator /* = */, precededBy: space, followedBy: space); |
| 577 visitNodes(node.initializers, separatedBy: commaSeperator); |
| 578 visit(node.redirectedConstructor); |
| 579 } |
| 580 |
| 550 visitConstructorFieldInitializer(ConstructorFieldInitializer node) { | 581 visitConstructorFieldInitializer(ConstructorFieldInitializer node) { |
| 551 token(node.keyword); | 582 token(node.keyword); |
| 552 token(node.period); | 583 token(node.period); |
| 553 visit(node.fieldName); | 584 visit(node.fieldName); |
| 554 space(); | 585 space(); |
| 555 token(node.equals); | 586 token(node.equals); |
| 556 space(); | 587 space(); |
| 557 visit(node.expression); | 588 visit(node.expression); |
| 558 } | 589 } |
| 559 | 590 |
| (...skipping 687 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1247 } | 1278 } |
| 1248 checkForSelectionUpdate(token); | 1279 checkForSelectionUpdate(token); |
| 1249 append(token.lexeme); | 1280 append(token.lexeme); |
| 1250 if (followedBy != null) { | 1281 if (followedBy != null) { |
| 1251 followedBy(); | 1282 followedBy(); |
| 1252 } | 1283 } |
| 1253 previousToken = token; | 1284 previousToken = token; |
| 1254 } | 1285 } |
| 1255 } | 1286 } |
| 1256 | 1287 |
| 1288 emitSpaces() { |
| 1289 while (leadingSpaces > 0) { |
| 1290 writer.print(' '); |
| 1291 leadingSpaces--; |
| 1292 } |
| 1293 } |
| 1294 |
| 1257 checkForSelectionUpdate(Token token) { | 1295 checkForSelectionUpdate(Token token) { |
| 1258 // Cache the first token on or AFTER the selection offset | 1296 // Cache the first token on or AFTER the selection offset |
| 1259 if (preSelection != null && selection == null) { | 1297 if (preSelection != null && selection == null) { |
| 1260 // Check for overshots | 1298 // Check for overshots |
| 1261 var overshot = token.offset - preSelection.offset; | 1299 var overshot = token.offset - preSelection.offset; |
| 1262 if (overshot >= 0) { | 1300 if (overshot >= 0) { |
| 1263 //TODO(pquitslund): update length (may need truncating) | 1301 //TODO(pquitslund): update length (may need truncating) |
| 1264 selection = new Selection(writer.toString().length - overshot, | 1302 selection = new Selection( |
| 1303 writer.toString().length + leadingSpaces - overshot, |
| 1265 preSelection.length); | 1304 preSelection.length); |
| 1266 } | 1305 } |
| 1267 } | 1306 } |
| 1268 } | 1307 } |
| 1269 | 1308 |
| 1270 commaSeperator() { | 1309 commaSeperator() { |
| 1271 comma(); | 1310 comma(); |
| 1272 space(); | 1311 space(); |
| 1273 } | 1312 } |
| 1274 | 1313 |
| 1275 comma() { | 1314 comma() { |
| 1276 append(','); | 1315 writer.print(','); |
| 1277 } | 1316 } |
| 1278 | 1317 |
| 1318 |
| 1279 /// Emit a non-breakable space. | 1319 /// Emit a non-breakable space. |
| 1280 space() { | 1320 space([n = 1]) { |
| 1281 //TODO(pquitslund): replace with a proper space token | 1321 //TODO(pquitslund): replace with a proper space token |
| 1282 append(' '); | 1322 leadingSpaces+=n; |
| 1283 } | 1323 } |
| 1284 | 1324 |
| 1285 /// Emit a breakable space | 1325 /// Emit a breakable space |
| 1286 breakableSpace() { | 1326 breakableSpace() { |
| 1287 //Implement | 1327 //Implement |
| 1288 } | 1328 } |
| 1289 | 1329 |
| 1290 /// Append the given [string] to the source writer if it's non-null. | 1330 /// Append the given [string] to the source writer if it's non-null. |
| 1291 append(String string) { | 1331 append(String string) { |
| 1292 if (string != null && !string.isEmpty) { | 1332 if (string != null && !string.isEmpty) { |
| 1333 emitSpaces(); |
| 1293 writer.print(string); | 1334 writer.print(string); |
| 1294 } | 1335 } |
| 1295 } | 1336 } |
| 1296 | 1337 |
| 1297 /// Indent. | 1338 /// Indent. |
| 1298 indent() { | 1339 indent([n = 1]) { |
| 1299 writer.indent(); | 1340 while (n-- > 0) { |
| 1341 writer.indent(); |
| 1342 } |
| 1300 } | 1343 } |
| 1301 | 1344 |
| 1302 /// Unindent | 1345 /// Unindent |
| 1303 unindent() { | 1346 unindent([n = 1]) { |
| 1304 writer.unindent(); | 1347 while (n-- > 0) { |
| 1348 writer.unindent(); |
| 1349 } |
| 1305 } | 1350 } |
| 1306 | 1351 |
| 1307 /// Print this statement as if it were a block (e.g., surrounded by braces). | 1352 /// Print this statement as if it were a block (e.g., surrounded by braces). |
| 1308 printAsBlock(Statement statement) { | 1353 printAsBlock(Statement statement) { |
| 1309 if (statement is! Block) { | 1354 if (statement is! Block) { |
| 1310 token(OPEN_CURLY); | 1355 token(OPEN_CURLY); |
| 1311 indent(); | 1356 indent(); |
| 1312 newlines(); | 1357 newlines(); |
| 1313 visit(statement); | 1358 visit(statement); |
| 1314 newlines(); | 1359 newlines(); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1341 while (comment != null) { | 1386 while (comment != null) { |
| 1342 | 1387 |
| 1343 emitComment(comment, previousToken); | 1388 emitComment(comment, previousToken); |
| 1344 | 1389 |
| 1345 var nextToken = comment.next != null ? comment.next : token; | 1390 var nextToken = comment.next != null ? comment.next : token; |
| 1346 var newlines = calculateNewlinesBetweenComments(comment, nextToken); | 1391 var newlines = calculateNewlinesBetweenComments(comment, nextToken); |
| 1347 if (newlines > 0) { | 1392 if (newlines > 0) { |
| 1348 writer.newlines(newlines); | 1393 writer.newlines(newlines); |
| 1349 lines += newlines; | 1394 lines += newlines; |
| 1350 } else if (!isEOF(token)) { | 1395 } else if (!isEOF(token)) { |
| 1351 space(); | 1396 append(' '); |
| 1352 } | 1397 } |
| 1353 | 1398 |
| 1354 previousToken = comment; | 1399 previousToken = comment; |
| 1355 comment = comment.next; | 1400 comment = comment.next; |
| 1356 } | 1401 } |
| 1357 | 1402 |
| 1358 previousToken = token; | 1403 previousToken = token; |
| 1359 return lines; | 1404 return lines; |
| 1360 } | 1405 } |
| 1361 | 1406 |
| 1362 | 1407 |
| 1363 ensureTrailingNewline() { | 1408 ensureTrailingNewline() { |
| 1364 if (writer.lastToken is! NewlineToken) { | 1409 if (writer.lastToken is! NewlineToken) { |
| 1365 writer.newline(); | 1410 writer.newline(); |
| 1366 } | 1411 } |
| 1367 } | 1412 } |
| 1368 | 1413 |
| 1369 | 1414 |
| 1370 /// Test if this [comment] is at the end of a line. | 1415 /// Test if this [comment] is at the end of a line. |
| 1371 bool isAtEOL(Token comment) => | 1416 bool isAtEOL(Token comment) => |
| 1372 comment != null && comment.toString().trim().startsWith(twoSlashes) && | 1417 comment != null && comment.toString().trim().startsWith(twoSlashes) && |
| 1373 sameLine(comment, previousToken); | 1418 sameLine(comment, previousToken); |
| 1374 | 1419 |
| 1375 /// Emit this [comment], inserting leading whitespace if appropriate. | 1420 /// Emit this [comment], inserting leading whitespace if appropriate. |
| 1376 emitComment(Token comment, Token previousToken) { | 1421 emitComment(Token comment, Token previousToken) { |
| 1377 if (!writer.currentLine.isWhitespace() && !isBlock(comment)) { | 1422 if (!writer.currentLine.isWhitespace() && !isBlock(comment)) { |
| 1378 var ws = countSpacesBetween(previousToken, comment); | 1423 var ws = countSpacesBetween(previousToken, comment); |
| 1379 // Preserve one space but no more | 1424 // Preserve one space but no more |
| 1380 if (ws > 0) { | 1425 if (ws > 0) { |
| 1381 space(); | 1426 append(' '); |
| 1382 } | 1427 } |
| 1383 } | 1428 } |
| 1384 | 1429 |
| 1385 append(comment.toString().trim()); | 1430 append(comment.toString().trim()); |
| 1386 } | 1431 } |
| 1387 | 1432 |
| 1388 /// Count spaces between these tokens. Tokens on different lines return 0. | 1433 /// Count spaces between these tokens. Tokens on different lines return 0. |
| 1389 int countSpacesBetween(Token last, Token current) => isEOF(last) || | 1434 int countSpacesBetween(Token last, Token current) => isEOF(last) || |
| 1390 countNewlinesBetween(last, current) > 0 ? 0 : current.offset - last.end; | 1435 countNewlinesBetween(last, current) > 0 ? 0 : current.offset - last.end; |
| 1391 | 1436 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1449 var lastLine = | 1494 var lastLine = |
| 1450 lineInfo.getLocation(lastOffset).lineNumber; | 1495 lineInfo.getLocation(lastOffset).lineNumber; |
| 1451 var currentLine = | 1496 var currentLine = |
| 1452 lineInfo.getLocation(currentOffset).lineNumber; | 1497 lineInfo.getLocation(currentOffset).lineNumber; |
| 1453 return currentLine - lastLine; | 1498 return currentLine - lastLine; |
| 1454 } | 1499 } |
| 1455 | 1500 |
| 1456 String toString() => writer.toString(); | 1501 String toString() => writer.toString(); |
| 1457 | 1502 |
| 1458 } | 1503 } |
| OLD | NEW |