Chromium Code Reviews| Index: lib/src/dart_formatter.dart |
| diff --git a/lib/src/dart_formatter.dart b/lib/src/dart_formatter.dart |
| index 480f40de1099242c249bc5c6705d3be79d2f5ffa..87576a5ee0e0787a3f693ac5b899c4e6d4ecdf36 100644 |
| --- a/lib/src/dart_formatter.dart |
| +++ b/lib/src/dart_formatter.dart |
| @@ -12,6 +12,63 @@ import 'package:analyzer/src/generated/source.dart'; |
| import 'error_listener.dart'; |
| import 'source_visitor.dart'; |
| +/// Describes a chunk of source code that is to be formatted or has been |
| +/// formatted. |
| +class SourceCode { |
| + /// The [uri] where the source code is from. |
| + /// |
| + /// Used in error messages if the code cannot be parsed. |
| + final String uri; |
| + |
| + /// The Dart source code text. |
| + final String text; |
| + |
| + /// Whether the source is a compilation unit or a bare statement. |
| + final bool isCompilationUnit; |
| + |
| + /// The offset in [text] where the selection begins, or `null` if there is |
| + /// no selection. |
| + final int selectionStart; |
| + |
| + /// The number of selected characters or `null` if there is no selection. |
| + final int selectionLength; |
| + |
| + SourceCode(this.text, |
| + {this.uri, this.isCompilationUnit: true, this.selectionStart, |
| + this.selectionLength}) { |
| + // Must either provide both selection bounds or neither. |
| + if ((selectionStart == null) != (selectionLength == null)) { |
| + throw new ArgumentError( |
| + "Is selectionStart is provided, selectionLength must be too."); |
| + } |
| + |
| + if (selectionStart != null) { |
| + if (selectionStart < 0) { |
| + throw new ArgumentError("selectionStart must be non-negative."); |
| + } |
| + |
| + if (selectionStart > text.length) { |
| + throw new ArgumentError("selectionStart must be within text."); |
| + } |
| + |
| + if (selectionLength == null) { |
|
Brian Wilkerson
2015/01/08 00:17:45
I think this case is covered by line 40.
Bob Nystrom
2015/01/08 00:36:38
Oops, forgot to delete this! Done.
|
| + throw new ArgumentError( |
| + "Is selectionStart is provided, selectionLength must be too."); |
| + } |
| + } |
| + |
| + if (selectionLength != null) { |
| + if (selectionLength < 0) { |
| + throw new ArgumentError("selectionLength must be non-negative."); |
| + } |
| + |
| + if (selectionStart + selectionLength > text.length) { |
| + throw new ArgumentError("selectionLength must end within text."); |
| + } |
| + } |
| + } |
| +} |
| + |
| /// Dart source code formatter. |
| class DartFormatter { |
| /// The string that newlines should use. |
| @@ -38,7 +95,7 @@ class DartFormatter { |
| DartFormatter({this.lineEnding, int pageWidth, this.indent: 0}) |
| : this.pageWidth = (pageWidth == null) ? 80 : pageWidth; |
| - /// Format the given [source] string containing an entire Dart compilation |
| + /// Formats the given [source] string containing an entire Dart compilation |
| /// unit. |
| /// |
| /// If [uri] is given, it is a [String] or [Uri] used to identify the file |
| @@ -54,20 +111,25 @@ class DartFormatter { |
| throw new ArgumentError("uri must be `null`, a Uri, or a String."); |
| } |
| - return _format(source, uri: uri, isCompilationUnit: true); |
| + return formatSource( |
| + new SourceCode(source, uri: uri, isCompilationUnit: true)).text; |
| } |
| - /// Format the given [source] string containing a single Dart statement. |
| + /// Formats the given [source] string containing a single Dart statement. |
| String formatStatement(String source) { |
| - return _format(source, isCompilationUnit: false); |
| + return formatSource(new SourceCode(source, isCompilationUnit: false)).text; |
| } |
| - String _format(String source, {String uri, bool isCompilationUnit}) { |
| + /// Formats the given [source]. |
| + /// |
| + /// Returns a new [SourceCode] containing the formatted code and the resulting |
| + /// selection, if any. |
| + SourceCode formatSource(SourceCode source) { |
| var errorListener = new ErrorListener(); |
| // Tokenize the source. |
| - var reader = new CharSequenceReader(source); |
| - var stringSource = new StringSource(source, uri); |
| + var reader = new CharSequenceReader(source.text); |
| + var stringSource = new StringSource(source.text, source.uri); |
| var scanner = new Scanner(stringSource, reader, errorListener); |
| var startToken = scanner.tokenize(); |
| var lineInfo = new LineInfo(scanner.lineStarts); |
| @@ -78,7 +140,7 @@ class DartFormatter { |
| // If the first newline is "\r\n", use that. Otherwise, use "\n". |
| if (scanner.lineStarts.length > 1 && |
| scanner.lineStarts[1] >= 2 && |
| - source[scanner.lineStarts[1] - 2] == '\r') { |
| + source.text[scanner.lineStarts[1] - 2] == '\r') { |
| lineEnding = "\r\n"; |
| } else { |
| lineEnding = "\n"; |
| @@ -92,7 +154,7 @@ class DartFormatter { |
| parser.parseAsync = true; |
|
Brian Wilkerson
2015/01/08 00:17:45
This should no longer be necessary. Async support
Bob Nystrom
2015/01/08 00:36:38
dart_style is using this constraint for the analyz
Brian Wilkerson
2015/01/08 05:31:29
In that case, you probably also want to add:
pa
|
| var node; |
| - if (isCompilationUnit) { |
| + if (source.isCompilationUnit) { |
| node = parser.parseCompilationUnit(startToken); |
| } else { |
| node = parser.parseStatement(startToken); |
| @@ -101,14 +163,7 @@ class DartFormatter { |
| errorListener.throwIfErrors(); |
| // Format it. |
| - var buffer = new StringBuffer(); |
| - var visitor = new SourceVisitor(this, lineInfo, source, buffer); |
| - |
| - visitor.run(node); |
| - |
| - // Be a good citizen, end with a newline. |
| - if (isCompilationUnit) buffer.write(lineEnding); |
| - |
| - return buffer.toString(); |
| + var visitor = new SourceVisitor(this, lineInfo, source); |
| + return visitor.run(node); |
| } |
| } |