// 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.anchor;
import com.google.collide.shared.document.DocumentMutator;
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;
import com.google.collide.shared.document.util.PositionUtils;
import com.google.common.base.Preconditions;
/**
* Utility methods relating to anchors.
*/
public final class AnchorUtils {
/**
* Returns a negative number if {@code a} is earlier than {@code b}, a
* positive number if the inverse, and zero if they are positioned the same.
*
* Comparing an anchor that ignores either a line number or column to another
* anchor that does not ignore that same property is invalid and will have
* strange results.
*
* @param a an anchor with both a line number and a column
* @param b an anchor with both a line number and a column
*/
public static int compare(Anchor a, Anchor b) {
assert (a.hasLineNumber() == b.hasLineNumber());
assert ((a.getColumn() == AnchorManager.IGNORE_COLUMN) == (b.getColumn() ==
AnchorManager.IGNORE_COLUMN));
return LineUtils.comparePositions(a.getLineNumber(), a.getColumn(), b.getLineNumber(),
b.getColumn());
}
/**
* @param a an anchor with both a line number and a column
* @see #compare(Anchor, Anchor)
*/
public static int compare(Anchor a, int bLineNumber, int bColumn) {
assert a.hasLineNumber();
assert (a.getColumn() != AnchorManager.IGNORE_COLUMN);
return LineUtils.comparePositions(a.getLineNumber(), a.getColumn(), bLineNumber, bColumn);
}
/**
* Replace all text between line anchors {@code begin} and {@code end}
* with {@code text}.
*/
public static void setTextBetweenAnchors(String text, Anchor begin, Anchor end,
DocumentMutator documentMutator) {
Preconditions.checkArgument(begin.isAttached(), "begin must be attached");
Preconditions.checkArgument(begin.isLineAnchor(), "begin must be line anchor");
Preconditions.checkArgument(end.isLineAnchor(), "end must be line anchor");
Preconditions.checkArgument(end.isAttached(), "end must be attached");
Preconditions.checkArgument(
begin.getLineNumber() <= end.getLineNumber(), "begin line below end line");
// TODO: Fix same-line text replacement.
LineInfo topLineInfo = begin.getLineInfo();
Line topLine = topLineInfo.line();
Line bottomLine = end.getLine();
/*
* At the very end of the document, the text being inserted will have a
* trailing "\n" that needs to be deleted to avoid an empty line at the
* end.
*/
boolean deleteEndingNewline = !bottomLine.getText().endsWith("\n");
if (!text.endsWith("\n")) {
text = text + "\n";
}
// Delete all of the existing text, minus the last newline.
int deleteCount =
LineUtils.getTextCount(topLine, 0, bottomLine, bottomLine.getText().length() -
(deleteEndingNewline ? 0 : 1));
documentMutator.insertText(topLine, topLineInfo.number(), 0, text, false);
Position endOfInsertion =
PositionUtils.getPosition(topLine, topLineInfo.number(), 0, text.length() - 1);
documentMutator.deleteText(endOfInsertion.getLine(), endOfInsertion.getColumn(), deleteCount);
}
private AnchorUtils() {
}
public static void visitAnchorsOnLine(Line line, AnchorManager.AnchorVisitor visitor) {
AnchorList anchors = AnchorManager.getAnchorsOrNull(line);
if (anchors == null) {
return;
}
for (int i = 0; i < anchors.size(); i++) {
visitor.visitAnchor(anchors.get(i));
}
}
}