/* * Copyright 2000-2009 JetBrains s.r.o. * * 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.intellij.openapi.util; import com.intellij.openapi.diagnostic.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.Serializable; public class TextRange implements Segment, Serializable { private static final Logger LOG = Logger.getInstance(TextRange.class); private static final long serialVersionUID = -670091356599757430L; public static final TextRange EMPTY_RANGE = new TextRange(0,0); private final int myStartOffset; private final int myEndOffset; public TextRange(int startOffset, int endOffset) { this(startOffset, endOffset, true); } /** * @param checkForProperTextRange <code>true</code> if offsets should be checked by {@link #assertProperRange(int, int, Object)} * @see com.intellij.openapi.util.UnfairTextRange */ protected TextRange(int startOffset, int endOffset, boolean checkForProperTextRange) { myStartOffset = startOffset; myEndOffset = endOffset; if (checkForProperTextRange) { assertProperRange(this); } } @Override public final int getStartOffset() { return myStartOffset; } @Override public final int getEndOffset() { return myEndOffset; } public final int getLength() { return myEndOffset - myStartOffset; } public boolean equals(Object obj) { if (!(obj instanceof TextRange)) return false; TextRange range = (TextRange)obj; return myStartOffset == range.myStartOffset && myEndOffset == range.myEndOffset; } public int hashCode() { return myStartOffset + myEndOffset; } public boolean contains(@NotNull TextRange range) { return containsRange(range.getStartOffset(), range.getEndOffset()); } public boolean containsRange(int startOffset, int endOffset) { return myStartOffset <= startOffset && myEndOffset >= endOffset; } public boolean containsOffset(int offset) { return myStartOffset <= offset && offset <= myEndOffset; } public String toString() { return "(" + myStartOffset + "," + myEndOffset + ")"; } public boolean contains(int offset) { return myStartOffset <= offset && offset < myEndOffset; } @NotNull public String substring(@NotNull String str) { try { return str.substring(myStartOffset, myEndOffset); } catch (StringIndexOutOfBoundsException e) { throw new StringIndexOutOfBoundsException("Can't extract " + this + " range from " + str); } } @NotNull public TextRange cutOut(@NotNull TextRange subRange) { assert subRange.getStartOffset() <= getLength() : subRange + "; this="+this; assert subRange.getEndOffset() <= getLength() : subRange + "; this="+this; return new TextRange(myStartOffset + subRange.getStartOffset(), Math.min(myEndOffset, myStartOffset + subRange.getEndOffset())); } @NotNull public TextRange shiftRight(int delta) { if (delta == 0) return this; return new TextRange(myStartOffset + delta, myEndOffset + delta); } @NotNull public TextRange grown(int lengthDelta) { return from(myStartOffset, getLength() + lengthDelta); } @NotNull public static TextRange from(int offset, int length) { return create(offset, offset + length); } @NotNull public static TextRange create(int startOffset, int endOffset) { return new TextRange(startOffset, endOffset); } @NotNull public static TextRange create(@NotNull Segment segment) { return create(segment.getStartOffset(), segment.getEndOffset()); } public static boolean areSegmentsEqual(@NotNull Segment segment1, @NotNull Segment segment2) { return segment1.getStartOffset() == segment2.getStartOffset() && segment1.getEndOffset() == segment2.getEndOffset(); } @NotNull public String replace(@NotNull String original, @NotNull String replacement) { try { String beginning = original.substring(0, getStartOffset()); String ending = original.substring(getEndOffset(), original.length()); return beginning + replacement + ending; } catch (StringIndexOutOfBoundsException e) { throw new StringIndexOutOfBoundsException("Can't replace " + this + " range from '" + original + "' with '" + replacement + "'"); } } public boolean intersects(@NotNull TextRange textRange) { return intersects((Segment)textRange); } public boolean intersects(@NotNull Segment textRange) { return intersects(textRange.getStartOffset(), textRange.getEndOffset()); } public boolean intersects(int startOffset, int endOffset) { return Math.max(myStartOffset, startOffset) <= Math.min(myEndOffset, endOffset); } public boolean intersectsStrict(@NotNull TextRange textRange) { return intersectsStrict(textRange.getStartOffset(), textRange.getEndOffset()); } public boolean intersectsStrict(int startOffset, int endOffset) { return Math.max(myStartOffset, startOffset) < Math.min(myEndOffset, endOffset); } @Nullable public TextRange intersection(@NotNull TextRange range) { if (!intersects(range)) return null; return new TextRange(Math.max(myStartOffset, range.getStartOffset()), Math.min(myEndOffset, range.getEndOffset())); } public boolean isEmpty() { return myStartOffset >= myEndOffset; } @NotNull public TextRange union(@NotNull TextRange textRange) { return new TextRange(Math.min(myStartOffset, textRange.getStartOffset()), Math.max(myEndOffset, textRange.getEndOffset())); } public boolean equalsToRange(int startOffset, int endOffset) { return startOffset == myStartOffset && endOffset == myEndOffset; } public static TextRange allOf(String s) { return new TextRange(0, s.length()); } public static void assertProperRange(@NotNull Segment range) throws AssertionError { assertProperRange(range, ""); } public static void assertProperRange(@NotNull Segment range, Object message) throws AssertionError { assertProperRange(range.getStartOffset(), range.getEndOffset(), message); } public static void assertProperRange(int startOffset, int endOffset, Object message) { if (startOffset > endOffset) { LOG.error("Invalid range specified: (" + startOffset + "," + endOffset + "); " + message); } if (startOffset < 0) { LOG.error("Negative start offset: (" + startOffset + "," + endOffset + "); " + message); } } }