// Copyright 2012 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.collide.shared.document.util; import static com.google.collide.shared.document.util.LineUtils.getPositionBackwards; import static com.google.collide.shared.document.util.LineUtils.getPositionForward; import com.google.collide.json.shared.JsonArray; import com.google.collide.shared.document.Line; import com.google.collide.shared.document.LineInfo; import com.google.collide.shared.document.Position; import com.google.collide.shared.document.util.LineUtils.LineVisitor; import com.google.collide.shared.util.JsonCollections; /** * Utility methods relating to {@link Position}. */ public final class PositionUtils { public static int compare(Position a, Position b) { return LineUtils.comparePositions(a.getLineNumber(), a.getColumn(), b.getLineNumber(), b.getColumn()); } public static Position[] getIntersection(Position[] a, Position[] b) { // Ensure that A starts before B if (compare(a[0], b[0]) > 0) { return getIntersection(b, a); } if (compare(b[0], a[1]) > 0) { // No intersection return null; } Position earlierEnd = compare(a[1], b[1]) < 0 ? a[1] : b[1]; return new Position[] {b[0], earlierEnd}; } public static JsonArray<Position[]> getDifference(Position[] a, Position[] b) { // Ensure that A starts before B int abStartComparison = compare(a[0], b[0]); if (abStartComparison > 0) { return getDifference(b, a); } if (compare(b[0], a[1]) > 0) { // No intersection, so return both return JsonCollections.createArray(a, b); } JsonArray<Position[]> difference = JsonCollections.createArray(); if (abStartComparison != 0) { // Range from the start of A (inclusive) to the start of B (exclusive) difference.add(new Position[] {a[0], getPosition(b[0], -1)}); } int abEndComparison = compare(a[1], b[1]); if (abEndComparison != 0) { Position earlierEnd = abEndComparison < 0 ? a[1] : b[1]; Position laterEnd = abEndComparison < 0 ? b[1] : a[1]; difference.add(new Position[] {getPosition(earlierEnd, 1), laterEnd}); } return difference; } /** * Returns the position (line and column) which is {@code relativeOffset} * characters (including newlines) away from the given starting position ( * {@code line} and {@code column}). * */ public static Position getPosition(Line line, int lineNumber, int column, int relativeOffset) { return relativeOffset < 0 ? getPositionBackwards(line, lineNumber, column, -relativeOffset) : getPositionForward(line, lineNumber, column, relativeOffset); } /** * @see #getPosition(com.google.collide.shared.document.Line, int, int, int) */ public static Position getPosition(Position position, int relativeOffset) { return relativeOffset < 0 ? getPositionBackwards(position.getLine(), position.getLineNumber(), position.getColumn(), -relativeOffset) : getPositionForward(position.getLine(), position.getLineNumber(), position.getColumn(), relativeOffset); } /* public static Position getPosition(Position start, int relativeOffset) { return getPosition(start.getLine(), start.getLineNumber(), start.getColumn(), relativeOffset); }*/ /** * Visit each line in order from start to end, calling lineVisitor.accept() * for each line. If lineVisitor.accept returns false, stop execution, else * continue until end is reached. * * This method can search backwards if start is later than end. In this case, * ensure that start's column is exclusive. * * @param lineVisitor the {@code endColumn} given to the visitor is exclusive * @param start if searching backwards, the column should be exclusive. * @param end if searching forward, the column should be exclusive. If * searching backwards, the column should be inclusive */ public static void visit(LineVisitor lineVisitor, Position start, Position end) { if (start.getLine().equals(end.getLine())) { lineVisitor .accept(start.getLine(), start.getLineNumber(), start.getColumn(), end.getColumn()); return; } boolean iterateForward = compare(start, end) < 0; if (iterateForward) { if (!lineVisitor.accept(start.getLine(), start.getLineNumber(), start.getColumn(), start .getLine().length())) { return; } } else { if (!lineVisitor.accept(start.getLine(), start.getLineNumber(), 0, start.getColumn())) { return; } } LineInfo curLine = start.getLineInfo(); curLine.moveTo(iterateForward); while (curLine.line() != end.getLine()) { if (!lineVisitor.accept(curLine.line(), curLine.number(), 0, curLine.line().length())) { return; } if (!curLine.moveTo(iterateForward)) { throw new IllegalStateException( "Could not find the requested ending line while visiting position range"); } } if (iterateForward) { lineVisitor.accept(end.getLine(), end.getLineNumber(), 0, end.getColumn()); } else { lineVisitor.accept(end.getLine(), end.getLineNumber(), end.getColumn(), end.getLine() .length()); } } private PositionUtils() { } }