lastLine += repetitionField;
// get enclosing range: search for a consistent block of at least the size of our
// change before and after the change.
final RangeDifference consistentBefore, consistentAfter;
if (leftToRight) {
consistentBefore= findConsistentRangeBeforeLeft(fFirstLine, size);
consistentAfter= findConsistentRangeAfterLeft(lastLine, size);
} else {
consistentBefore= findConsistentRangeBeforeRight(fFirstLine, size);
consistentAfter= findConsistentRangeAfterRight(lastLine, size);
}
// optimize unchanged blocks: if the consistent blocks around the change are larger than
// size, we redimension them (especially important when there are only few changes.
int shiftBefore= 0;
if (consistentBefore.kind() == RangeDifference.NOCHANGE) {
int unchanged;
if (leftToRight)
unchanged= Math.min(fFirstLine, consistentBefore.leftEnd()) - consistentBefore.leftStart();
else
unchanged= Math.min(fFirstLine, consistentBefore.rightEnd()) - consistentBefore.rightStart();
shiftBefore= Math.max(0, unchanged - size);
}
int shiftAfter= 0;
if (consistentAfter.kind() == RangeDifference.NOCHANGE) {
int unchanged;
if (leftToRight)
unchanged= consistentAfter.leftEnd() - Math.max(lastLine + 1, consistentAfter.leftStart());
else
unchanged= consistentAfter.rightEnd() - Math.max(lastLine + 1, consistentAfter.rightStart());
shiftAfter= Math.max(0, unchanged - size);
}
// get the document regions that will be rediffed, take into account that on the
// document, the change has already happened.
// left (reference) document
int leftStartLine= consistentBefore.leftStart() + shiftBefore;
int leftLine= consistentAfter.leftEnd();
if (leftToRight)
leftLine += lineDelta;
int leftEndLine= leftLine - shiftAfter;
ILineRange leftRange= new LineRange(leftStartLine, leftEndLine - leftStartLine);
IRangeComparator reference= new DocEquivalenceComparator(leftEquivalent, leftRange);
// right (actual) document
int rightStartLine= consistentBefore.rightStart() + shiftBefore;
int rightLine= consistentAfter.rightEnd();
if (!leftToRight)
rightLine += lineDelta;
int rightEndLine= rightLine - shiftAfter;
ILineRange rightRange= new LineRange(rightStartLine, rightEndLine - rightStartLine);
IRangeComparator change= new DocEquivalenceComparator(rightEquivalent, rightRange);
// put an upper bound to the delay we can afford
if (leftLine - shiftAfter - leftStartLine > 50 || rightLine - shiftAfter - rightStartLine > 50) {
initialize();
return;
}
// debug
// System.out.println("compare window: "+size+"\n\n<" + left.get(leftRegion.getOffset(), leftRegion.getLength()) + //$NON-NLS-1$//$NON-NLS-2$
// ">\n\n<" + right.get(rightRegion.getOffset(), rightRegion.getLength()) + ">\n"); //$NON-NLS-1$ //$NON-NLS-2$
// compare
List diffs= RangeDifferencer.findRanges(reference, change);
if (diffs.size() == 0) {
diffs.add(new RangeDifference(RangeDifference.CHANGE, 0, 0, 0, 0));
}
// shift the partial diffs to the absolute document positions
for (Iterator it= diffs.iterator(); it.hasNext();) {
RangeDifference d= (RangeDifference) it.next();
d.shiftLeft(leftStartLine);
d.shiftRight(rightStartLine);
}
// undo optimization shifting
if (shiftBefore > 0) {
RangeDifference first= (RangeDifference) diffs.get(0);
if (first.kind() == RangeDifference.NOCHANGE)
first.extendStart(-shiftBefore);
else
diffs.add(0, new RangeDifference(RangeDifference.NOCHANGE, first.rightStart() - shiftBefore, shiftBefore, first.leftStart() - shiftBefore, shiftBefore));
}
RangeDifference last= (RangeDifference) diffs.get(diffs.size() - 1);
if (shiftAfter > 0) {
if (last.kind() == RangeDifference.NOCHANGE)
last.extendEnd(shiftAfter);
else
diffs.add(new RangeDifference(RangeDifference.NOCHANGE, last.rightEnd(), shiftAfter , last.leftEnd(), shiftAfter));
}
// replace changed diff range
synchronized (fDifferences) {
final ListIterator it= fDifferences.listIterator();
Iterator newIt= diffs.iterator();
RangeDifference current;
boolean changed= false;
// replace regions from consistentBefore to consistentAfter with new diffs
// search for consistentBefore
do {
Assert.isTrue(it.hasNext());
current= (RangeDifference) it.next();
} while (current != consistentBefore);
Assert.isTrue(current == consistentBefore);
fChanged.clear();
fRemoved.clear();
fAdded.clear();
// replace until consistentAfter
while (current != consistentAfter) {
if (newIt.hasNext()) {
Object o= newIt.next();
if (!current.equals(o)) {
fRemoved.add(current);
fAdded.add(o);
changed= true;
it.set(o);
}
} else {
fRemoved.add(current);
it.remove();
changed= true;
}
Assert.isTrue(it.hasNext());
current= (RangeDifference) it.next();
}
// replace consistentAfter
Assert.isTrue(current == consistentAfter);
if (newIt.hasNext()) {
Object o= newIt.next();
if (!current.equals(o)) {
fRemoved.add(current);
fAdded.add(o);
changed= true;
it.set(o);
}
} else {
fRemoved.add(current);
it.remove();
changed= true;
}
// add remaining new diffs
while (newIt.hasNext()) {
Object next= newIt.next();
fAdded.add(next);
it.add(next);
changed= true;
}
// shift the old remaining diffs
boolean init= true;
int leftShift= 0;
int rightShift= 0;
while (it.hasNext()) {
current= (RangeDifference) it.next();
if (init) {
init= false;
leftShift= last.leftEnd() - current.leftStart();
rightShift= last.rightEnd() - current.rightStart();
if (leftShift != 0 || rightShift != 0)
changed= true;
else
break;
}
// fChanged.add(current); // not needed since positional shifting is not handled by an annotation model
current.shiftLeft(leftShift);
current.shiftRight(rightShift);
}
fUpdateNeeded= changed;
}