blob: e8665fbd6b0b096564727ea2d76931939f8cf0ab [file] [log] [blame]
// Copyright (c) 2012, 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.
library dart2js.io.line_column;
import 'code_output.dart';
/// Interface for providing line/column information.
abstract class LineColumnProvider {
/// Returns the line number (0-based) for [offset].
int getLine(int offset);
/// Returns the column number (0-based) for [offset] at the given [line].
int getColumn(int line, int offset);
/// Returns the offset for 0-based [line] and [column] numbers.
int getOffset(int line, int column);
}
/// [CodeOutputListener] that collects line information.
class LineColumnCollector extends CodeOutputListener
implements LineColumnProvider {
int length = 0;
List<int> lineStarts = <int>[0];
void _collect(String text) {
int index = 0;
while (index < text.length) {
// Unix uses '\n' and Windows uses '\r\n', so this algorithm works for
// both platforms.
index = text.indexOf('\n', index) + 1;
if (index <= 0) break;
lineStarts.add(length + index);
}
length += text.length;
}
@override
void onText(String text) {
_collect(text);
}
@override
int getLine(int offset) {
List<int> starts = lineStarts;
if (offset < 0 || starts.last <= offset) {
throw 'bad position #$offset in buffer with length ${length}.';
}
int first = 0;
int count = starts.length;
while (count > 1) {
int step = count ~/ 2;
int middle = first + step;
int lineStart = starts[middle];
if (offset < lineStart) {
count = step;
} else {
first = middle;
count -= step;
}
}
return first;
}
@override
int getColumn(int line, int offset) {
return offset - lineStarts[line];
}
int getOffset(int line, int column) => lineStarts[line] + column;
@override
void onDone(int length) {
lineStarts.add(length + 1);
this.length = length;
}
String toString() {
return 'lineStarts=$lineStarts,length=$length';
}
}