| // Copyright (c) 2018, 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. |
| |
| import 'package:analyzer/src/generated/java_engine.dart'; |
| import 'package:analyzer/src/generated/source.dart'; |
| |
| /** |
| * The location of a character represented as a line and column pair. |
| */ |
| // ignore: deprecated_member_use_from_same_package |
| class CharacterLocation extends LineInfo_Location { |
| // TODO(brianwilkerson) Replace the body of this class with the body of |
| // LineInfo_Location and remove LineInfo_Location. |
| /** |
| * Initialize a newly created location to represent the location of the |
| * character at the given [lineNumber] and [columnNumber]. |
| */ |
| CharacterLocation(int lineNumber, int columnNumber) |
| : super(lineNumber, columnNumber); |
| } |
| |
| /** |
| * Information about line and column information within a source file. |
| */ |
| class LineInfo { |
| /** |
| * A list containing the offsets of the first character of each line in the |
| * source code. |
| */ |
| final List<int> lineStarts; |
| |
| /** |
| * The zero-based [lineStarts] index resulting from the last call to |
| * [getLocation]. |
| */ |
| int _previousLine = 0; |
| |
| /** |
| * Initialize a newly created set of line information to represent the data |
| * encoded in the given list of [lineStarts]. |
| */ |
| LineInfo(this.lineStarts) { |
| if (lineStarts == null) { |
| throw new ArgumentError("lineStarts must be non-null"); |
| } else if (lineStarts.length < 1) { |
| throw new ArgumentError("lineStarts must be non-empty"); |
| } |
| } |
| |
| /** |
| * Initialize a newly created set of line information corresponding to the |
| * given file [content]. |
| */ |
| factory LineInfo.fromContent(String content) => |
| new LineInfo(StringUtilities.computeLineStarts(content)); |
| |
| /** |
| * The number of lines. |
| */ |
| int get lineCount => lineStarts.length; |
| |
| /** |
| * Return the location information for the character at the given [offset]. |
| * |
| * A future version of this API will return a [CharacterLocation] rather than |
| // ignore: deprecated_member_use_from_same_package |
| * a [LineInfo_Location]. |
| */ |
| // ignore: deprecated_member_use_from_same_package |
| LineInfo_Location getLocation(int offset) { |
| var min = 0; |
| var max = lineStarts.length - 1; |
| |
| // Subsequent calls to [getLocation] are often for offsets near each other. |
| // To take advantage of that, we cache the index of the line start we found |
| // when this was last called. If the current offset is on that line or |
| // later, we'll skip those early indices completely when searching. |
| if (offset >= lineStarts[_previousLine]) { |
| min = _previousLine; |
| |
| // Before kicking off a full binary search, do a quick check here to see |
| // if the new offset is on that exact line. |
| if (min == lineStarts.length - 1 || offset < lineStarts[min + 1]) { |
| return new CharacterLocation(min + 1, offset - lineStarts[min] + 1); |
| } |
| } |
| |
| // Binary search to fine the line containing this offset. |
| while (min < max) { |
| var midpoint = (max - min + 1) ~/ 2 + min; |
| |
| if (lineStarts[midpoint] > offset) { |
| max = midpoint - 1; |
| } else { |
| min = midpoint; |
| } |
| } |
| |
| _previousLine = min; |
| |
| return new CharacterLocation(min + 1, offset - lineStarts[min] + 1); |
| } |
| |
| /** |
| * Return the offset of the first character on the line with the given |
| * [lineNumber]. |
| */ |
| int getOffsetOfLine(int lineNumber) { |
| if (lineNumber < 0 || lineNumber >= lineCount) { |
| throw new ArgumentError( |
| 'Invalid line number: $lineNumber; must be between 0 and ${lineCount - 1}'); |
| } |
| return lineStarts[lineNumber]; |
| } |
| |
| /** |
| * Return the offset of the first character on the line following the line |
| * containing the given [offset]. |
| */ |
| int getOffsetOfLineAfter(int offset) { |
| return getOffsetOfLine(getLocation(offset).lineNumber); |
| } |
| } |