blob: 553215e3322888610d6157ec481267a4b9a635b8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jface.internal.text.revisions;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.text.revisions.Revision;
import org.eclipse.jface.text.source.ILineRange;
import org.eclipse.jface.text.source.LineRange;
/**
* A change region describes a contiguous range of lines that was changed in the same revision of a
* document. Once it is adjusted to diff information, the originally contiguous range may be split
* into several ranges or even be empty.
*
* @since 3.2
*/
public final class ChangeRegion {
private final Revision fRevision;
private final ILineRange fLines;
private final List fAdjusted= new LinkedList();
/**
* Creates a new change region for the given revision and line range.
*
* @param revision the revision of the new region
* @param lines the line range of the new region
* @throws IndexOutOfBoundsException if the line range is not well-formed
*/
public ChangeRegion(Revision revision, ILineRange lines) throws IndexOutOfBoundsException {
Assert.isLegal(revision != null);
Assert.isLegal(lines != null);
fLines= Range.copy(lines);
fRevision=revision;
clearDiff();
}
/**
* Returns the revision that this region belongs to.
*
* @return the revision that this region belongs to
*/
public Revision getRevision() {
return fRevision;
}
/**
* Returns the original (before applying diff information) line range of this change region.
*
* @return the original (before applying diff information) line range of this change region
*/
public ILineRange getOriginalRange() {
return fLines;
}
/**
* Returns the list of {@link ILineRange}s of this change region for which the revision
* information is still valid.
*
* @return the list of adjusted line ranges
*/
public List getAdjustedRanges() {
return fAdjusted;
}
/**
* Returns the line coverage of the adjusted ranges, an empty range if the coverage is empty.
*
* @return the line coverage of the adjusted ranges
*/
public ILineRange getAdjustedCoverage() {
if (fAdjusted.isEmpty())
return new LineRange(fLines.getStartLine(), 0);
Range first= (Range) fAdjusted.get(0);
Range last= (Range) fAdjusted.get(fAdjusted.size() - 1);
return Range.createAbsolute(first.start(), last.end());
}
/**
* Clears any adjusted ranges, restoring the original range.
*/
public void clearDiff() {
fAdjusted.clear();
fAdjusted.add(Range.copy(fLines));
}
/**
* Adjusts this change region to a diff hunk. This will change the adjusted ranges.
*
* @param hunk the diff hunk to adjust to
*/
public void adjustTo(Hunk hunk) {
for (ListIterator it= fAdjusted.listIterator(); it.hasNext();) {
Range range= (Range) it.next();
// do we need a split?
int unchanged= getUnchanged(hunk, range.start());
if (unchanged > 0) {
if (unchanged >= range.length())
continue;
range= range.split(unchanged);
it.add(range);
it.previous(); it.next(); // needed so we can remove below
}
int line= range.start();
Assert.isTrue(hunk.line <= line);
// by how much do we shrink?
int overlap= getOverlap(hunk, line);
if (overlap >= range.length()) {
it.remove();
continue;
}
// by how much do we move?
range.moveBy(hunk.delta + overlap);
range.resizeBy(-overlap);
}
}
private int getUnchanged(Hunk hunk, int line) {
return Math.max(0, hunk.line - line);
}
/*
* Returns the number of lines after line that the hunk reports as changed.
*/
private int getOverlap(Hunk hunk, int line) {
int deltaLine= hunk.line + hunk.changed;
if (hunk.delta >= 0) {
if (deltaLine <= line)
return 0;
return deltaLine - line;
}
// hunk.delta < 0
int hunkEnd= deltaLine - hunk.delta;
int cutCount= hunkEnd - line;
return Math.max(0, cutCount);
}
/*
* @see java.lang.Object#toString()
*/
public String toString() {
return "ChangeRegion [" + fRevision.toString() + ", [" + fLines.getStartLine() + "+" + fLines.getNumberOfLines() + ")]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
}