/* * Copyright (c) 2012 Sam Harwell, Tunnel Vision Laboratories LLC * All rights reserved. * * The source code of this document is proprietary work, and is not licensed for * distribution. For information about licensing, contact Sam Harwell at: * sam@tunnelvisionlabs.com */ package org.antlr.netbeans.editor.text; import org.netbeans.api.annotations.common.CheckForNull; import org.netbeans.api.annotations.common.NonNull; import org.openide.util.Parameters; /** * * @author Sam Harwell */ public final class SnapshotPositionRegion { @NonNull private final DocumentSnapshot snapshot; @NonNull private final OffsetRegion region; public SnapshotPositionRegion(@NonNull DocumentSnapshot snapshot, int start, int length) { this(snapshot, new OffsetRegion(start, length)); } public SnapshotPositionRegion(@NonNull DocumentSnapshot snapshot, @NonNull OffsetRegion region) { Parameters.notNull("snapshot", snapshot); Parameters.notNull("region", region); if (region.getEnd() > snapshot.length()) { throw new IllegalArgumentException("The specified region does not lie within the snapshot."); } this.snapshot = snapshot; this.region = region; } public SnapshotPositionRegion(@NonNull SnapshotPosition start, int length) { this(start.getSnapshot(), start.getOffset(), length); } public SnapshotPositionRegion(@NonNull SnapshotPosition start, @NonNull SnapshotPosition end) { this(start, start.difference(end)); } public @NonNull SnapshotPosition getStart() { return new SnapshotPosition(snapshot, region.getStart()); } public @NonNull SnapshotPosition getEnd() { return new SnapshotPosition(snapshot, region.getEnd()); } public int getLength() { return region.getLength(); } public boolean isEmpty() { return region.isEmpty(); } public @NonNull DocumentSnapshot getSnapshot() { return snapshot; } public @NonNull OffsetRegion getRegion() { return region; } public boolean contains(int offset) { return region.contains(offset); } public boolean contains(@NonNull SnapshotPosition position) { Parameters.notNull("position", position); if (!position.getSnapshot().equals(snapshot)) { throw new IllegalArgumentException(); } return contains(position.getOffset()); } public boolean contains(@NonNull SnapshotPositionRegion region) { Parameters.notNull("region", region); if (!region.getSnapshot().equals(snapshot)) { throw new IllegalArgumentException(); } return contains(region.getRegion()); } public boolean contains(@NonNull OffsetRegion region) { Parameters.notNull("region", region); return region.getStart() >= this.region.getStart() && region.getEnd() <= this.region.getEnd(); } public @NonNull String getText() { return snapshot.subSequence(region.getStart(), region.getEnd()).toString(); } public @CheckForNull SnapshotPositionRegion intersection(@NonNull SnapshotPositionRegion other) { Parameters.notNull("other", other); if (!other.getSnapshot().equals(snapshot)) { throw new IllegalArgumentException(); } return intersection(other.getRegion()); } public @CheckForNull SnapshotPositionRegion intersection(@NonNull OffsetRegion other) { Parameters.notNull("other", other); int newStart = Math.max(this.region.getStart(), other.getStart()); int newEnd = Math.min(this.region.getEnd(), other.getEnd()); if (newEnd < newStart) { return null; } return new SnapshotPositionRegion(snapshot, OffsetRegion.fromBounds(newStart, newEnd)); } public boolean intersectsWith(@NonNull SnapshotPositionRegion other) { Parameters.notNull("other", other); if (!other.getSnapshot().equals(snapshot)) { throw new IllegalArgumentException(); } return intersectsWith(other.getRegion()); } public boolean intersectsWith(@NonNull OffsetRegion other) { Parameters.notNull("other", other); int newStart = Math.max(this.region.getStart(), other.getStart()); int newEnd = Math.min(this.region.getEnd(), other.getEnd()); return newEnd >= newStart; } public @CheckForNull SnapshotPositionRegion overlap(@NonNull SnapshotPositionRegion other) { Parameters.notNull("other", other); if (!other.getSnapshot().equals(snapshot)) { throw new IllegalArgumentException(); } return overlap(other.getRegion()); } public @CheckForNull SnapshotPositionRegion overlap(@NonNull OffsetRegion other) { Parameters.notNull("other", other); int newStart = Math.max(this.region.getStart(), other.getStart()); int newEnd = Math.min(this.region.getEnd(), other.getEnd()); if (newEnd <= newStart) { return null; } return new SnapshotPositionRegion(snapshot, OffsetRegion.fromBounds(newStart, newEnd)); } public boolean overlapsWith(@NonNull SnapshotPositionRegion other) { Parameters.notNull("other", other); if (!other.getSnapshot().equals(snapshot)) { throw new IllegalArgumentException(); } return overlapsWith(other.getRegion()); } public boolean overlapsWith(@NonNull OffsetRegion other) { Parameters.notNull("other", other); int newStart = Math.max(this.region.getStart(), other.getStart()); int newEnd = Math.min(this.region.getEnd(), other.getEnd()); return newEnd > newStart; } public @NonNull SnapshotPositionRegion translateTo(@NonNull DocumentSnapshot targetSnapshot, @NonNull TrackingPositionRegion.Bias bias) { Parameters.notNull("targetSnapshot", targetSnapshot); Parameters.notNull("bias", bias); TrackingPosition.Bias startTrackingBias; TrackingPosition.Bias endTrackingBias; switch (bias) { case Exclusive: startTrackingBias = TrackingPosition.Bias.Forward; endTrackingBias = TrackingPosition.Bias.Backward; break; case Inclusive: startTrackingBias = TrackingPosition.Bias.Backward; endTrackingBias = TrackingPosition.Bias.Forward; break; case Forward: startTrackingBias = TrackingPosition.Bias.Forward; endTrackingBias = TrackingPosition.Bias.Forward; break; case Backward: startTrackingBias = TrackingPosition.Bias.Backward; endTrackingBias = TrackingPosition.Bias.Backward; break; case Custom: default: throw new UnsupportedOperationException(); } SnapshotPosition start = getStart().translateTo(targetSnapshot, startTrackingBias); SnapshotPosition end = getEnd().translateTo(targetSnapshot, endTrackingBias); assert targetSnapshot.getVersionedDocument().equals(snapshot.getVersionedDocument()) : "exception should have been thrown"; return new SnapshotPositionRegion(start, end); } @Override public boolean equals(Object obj) { if (!(obj instanceof SnapshotPositionRegion)) { return false; } return equals((SnapshotPositionRegion)obj); } public boolean equals(SnapshotPositionRegion other) { if (other == null) { return false; } return this.snapshot.equals(other.snapshot) && this.region.equals(other.region); } @Override public int hashCode() { int hash = 3; hash = 23 * hash + this.snapshot.hashCode(); hash = 23 * hash + this.region.hashCode(); return hash; } @Override public String toString() { int version = getSnapshot().getVersion().getVersionNumber(); String regionText = getRegion().toString(); int textLength = Math.min(this.getLength(), 40); String text = getSnapshot().subSequence(getStart().getOffset(), getStart().getOffset() + textLength).toString(); return String.format("v%d_%s_'%s'", version, regionText, text); } }