| Index: utils/css/source.dart
|
| diff --git a/utils/css/source.dart b/utils/css/source.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..38be4a687f0222e0629dbdef6cb45ab28c0c3398
|
| --- /dev/null
|
| +++ b/utils/css/source.dart
|
| @@ -0,0 +1,186 @@
|
| +// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +// TODO(jimhug): This should be an interface to work better with tools.
|
| +/**
|
| + * Represents a file of source code.
|
| + */
|
| +class SourceFile implements Comparable {
|
| + // TODO(terry): This filename for in memory buffer. May need to rework if
|
| + // filename is used for more than informational.
|
| + static String IN_MEMORY_FILE = '<buffer>';
|
| +
|
| + /** The name of the file. */
|
| + final String filename;
|
| +
|
| + /** The text content of the file. */
|
| + String _text;
|
| +
|
| + /**
|
| + * The order of the source file in a given library. This is used while we're
|
| + * writing code for a library. A single source file can be used
|
| + */
|
| + // TODO(jmesserly): I don't like having properties that are only valid
|
| + // sometimes. An alternative would be to store it in a Map that's used by
|
| + // WorldGenerator while it's emitting code. This seems simpler.
|
| + int orderInLibrary;
|
| +
|
| + List<int> _lineStarts;
|
| +
|
| + SourceFile(this.filename, this._text);
|
| +
|
| + String get text() => _text;
|
| +
|
| + set text(String newText) {
|
| + if (newText != _text) {
|
| + _text = newText;
|
| + _lineStarts = null;
|
| + orderInLibrary = null;
|
| + }
|
| + }
|
| +
|
| + List<int> get lineStarts() {
|
| + if (_lineStarts == null) {
|
| + var starts = [0];
|
| + var index = 0;
|
| + while (index < text.length) {
|
| + index = text.indexOf('\n', index) + 1;
|
| + if (index <= 0) break;
|
| + starts.add(index);
|
| + }
|
| + starts.add(text.length + 1);
|
| + _lineStarts = starts;
|
| + }
|
| + return _lineStarts;
|
| + }
|
| +
|
| + int getLine(int position) {
|
| + // TODO(jimhug): Implement as binary search.
|
| + var starts = lineStarts;
|
| + for (int i=0; i < starts.length; i++) {
|
| + if (starts[i] > position) return i-1;
|
| + }
|
| + world.internalError('bad position');
|
| + }
|
| +
|
| + int getColumn(int line, int position) {
|
| + return position - lineStarts[line];
|
| + }
|
| +
|
| + /**
|
| + * Create a pretty string representation from a character position
|
| + * in the file.
|
| + */
|
| + String getLocationMessage(String message, int start,
|
| + [int end, bool includeText=false]) {
|
| + var line = getLine(start);
|
| + var column = getColumn(line, start);
|
| +
|
| + var buf = new StringBuffer(
|
| + '${filename}:${line + 1}:${column + 1}: $message');
|
| + if (includeText) {
|
| + buf.add('\n');
|
| + var textLine;
|
| + // +1 for 0-indexing, +1 again to avoid the last line of the file
|
| + if ((line + 2) < _lineStarts.length) {
|
| + textLine = text.substring(_lineStarts[line], _lineStarts[line+1]);
|
| + } else {
|
| + textLine = text.substring(_lineStarts[line]) + '\n';
|
| + }
|
| +
|
| + int toColumn = Math.min(column + (end-start), textLine.length);
|
| + if (options.useColors) {
|
| + buf.add(textLine.substring(0, column));
|
| + buf.add(_RED_COLOR);
|
| + buf.add(textLine.substring(column, toColumn));
|
| + buf.add(_NO_COLOR);
|
| + buf.add(textLine.substring(toColumn));
|
| + } else {
|
| + buf.add(textLine);
|
| + }
|
| +
|
| + int i = 0;
|
| + for (; i < column; i++) {
|
| + buf.add(' ');
|
| + }
|
| +
|
| + if (options.useColors) buf.add(_RED_COLOR);
|
| + for (; i < toColumn; i++) {
|
| + buf.add('^');
|
| + }
|
| + if (options.useColors) buf.add(_NO_COLOR);
|
| + }
|
| +
|
| + return buf.toString();
|
| + }
|
| +
|
| + /** Compares two source files. */
|
| + int compareTo(SourceFile other) {
|
| + if (orderInLibrary != null && other.orderInLibrary != null) {
|
| + return orderInLibrary - other.orderInLibrary;
|
| + } else {
|
| + return filename.compareTo(other.filename);
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +/**
|
| + * A range of characters in a [SourceFile]. Used to represent the source
|
| + * positions of [Token]s and [Node]s for error reporting or other tooling
|
| + * work.
|
| + */
|
| + // TODO(jmesserly): Rename to Span - but first write cool refactoring tool
|
| +class SourceSpan implements Comparable {
|
| + /** The [SourceFile] that contains this span. */
|
| + final SourceFile file;
|
| +
|
| + /** The character position of the start of this span. */
|
| + final int start;
|
| +
|
| + /** The character position of the end of this span. */
|
| + final int end;
|
| +
|
| + SourceSpan(this.file, this.start, this.end);
|
| +
|
| + /** Returns the source text corresponding to this [Span]. */
|
| + String get text() {
|
| + return file.text.substring(start, end);
|
| + }
|
| +
|
| + toMessageString(String message) {
|
| + return file.getLocationMessage(message, start, end: end, includeText: true);
|
| + }
|
| +
|
| + int get line() {
|
| + return file.getLine(start);
|
| + }
|
| +
|
| + int get column() {
|
| + return file.getColumn(line, start);
|
| + }
|
| +
|
| + int get endLine() {
|
| + return file.getLine(end);
|
| + }
|
| +
|
| + int get endColumn() {
|
| + return file.getColumn(endLine, end);
|
| + }
|
| +
|
| + String get locationText() {
|
| + var line = file.getLine(start);
|
| + var column = file.getColumn(line, start);
|
| + return '${file.filename}:${line + 1}:${column + 1}';
|
| + }
|
| +
|
| + /** Compares two source spans by file and position. Handles nulls. */
|
| + int compareTo(SourceSpan other) {
|
| + if (file == other.file) {
|
| + int d = start - other.start;
|
| + return d == 0 ? (end - other.end) : d;
|
| + }
|
| + return file.compareTo(other.file);
|
| + }
|
| +}
|
|
|