/*
* Second pass: look for single edits surrounded on both sides by equalities
* which can be shifted sideways to eliminate an equality.
* e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
*/
boolean changes = false;
// Create a new iterator at the start.
// (As opposed to walking the current one back.)
pointer = diffs.listIterator();
Diff prevDiff = pointer.hasNext() ? pointer.next() : null;
thisDiff = pointer.hasNext() ? pointer.next() : null;
Diff nextDiff = pointer.hasNext() ? pointer.next() : null;
// Intentionally ignore the first and last element (don't need checking).
while (nextDiff != null) {
if (prevDiff.operation == Operation.EQUAL &&
nextDiff.operation == Operation.EQUAL) {
// This is a single edit surrounded by equalities.
if (thisDiff.text.endsWith(prevDiff.text)) {
// Shift the edit over the previous equality.
thisDiff.text = prevDiff.text
+ thisDiff.text.substring(0, thisDiff.text.length()
- prevDiff.text.length());
nextDiff.text = prevDiff.text + nextDiff.text;
pointer.previous(); // Walk past nextDiff.
pointer.previous(); // Walk past thisDiff.
pointer.previous(); // Walk past prevDiff.
pointer.remove(); // Delete prevDiff.
pointer.next(); // Walk past thisDiff.
thisDiff = pointer.next(); // Walk past nextDiff.
nextDiff = pointer.hasNext() ? pointer.next() : null;
changes = true;
} else if (thisDiff.text.startsWith(nextDiff.text)) {
// Shift the edit over the next equality.
prevDiff.text += nextDiff.text;
thisDiff.text = thisDiff.text.substring(nextDiff.text.length())
+ nextDiff.text;
pointer.remove(); // Delete nextDiff.
nextDiff = pointer.hasNext() ? pointer.next() : null;
changes = true;
}
}
prevDiff = thisDiff;
thisDiff = nextDiff;
nextDiff = pointer.hasNext() ? pointer.next() : null;
}
// If shifts were made, the diff needs reordering and another shift sweep.
if (changes) {
diff_cleanupMerge(diffs);
}
}
/**
* loc is a location in text1, compute and return the equivalent location in
* text2.
* e.g. "The cat" vs "The big cat", 1->1, 5->8
* @param diffs List of Diff objects.
* @param loc Location within text1.
* @return Location within text2.
*/
public int diff_xIndex(List<Diff> diffs, int loc) {
int chars1 = 0;
int chars2 = 0;
int last_chars1 = 0;
int last_chars2 = 0;
Diff lastDiff = null;
for (Diff aDiff : diffs) {
if (aDiff.operation != Operation.INSERT) {
// Equality or deletion.
chars1 += aDiff.text.length();
}
if (aDiff.operation != Operation.DELETE) {
// Equality or insertion.
chars2 += aDiff.text.length();
}
if (chars1 > loc) {
// Overshot the location.
lastDiff = aDiff;
break;
}
last_chars1 = chars1;
last_chars2 = chars2;
}
if (lastDiff != null && lastDiff.operation == Operation.DELETE) {
// The location was deleted.
return last_chars2;
}
// Add the remaining character length.
return last_chars2 + (loc - last_chars1);
}