public void diff_cleanupMerge(LinkedList<Diff> diffs){
  diffs.add(new Diff(Operation.EQUAL,""));
  ListIterator<Diff> pointer=diffs.listIterator();
  int count_delete=0;
  int count_insert=0;
  String text_delete="";
  String text_insert="";
  Diff thisDiff=pointer.next();
  Diff prevEqual=null;
  int commonlength;
  while (thisDiff != null) {
switch (thisDiff.operation) {
case INSERT:
      count_insert++;
    text_insert+=thisDiff.text;
  prevEqual=null;
break;
case DELETE:
count_delete++;
text_delete+=thisDiff.text;
prevEqual=null;
break;
case EQUAL:
if (count_delete + count_insert > 1) {
boolean both_types=count_delete != 0 && count_insert != 0;
pointer.previous();
while (count_delete-- > 0) {
pointer.previous();
pointer.remove();
}
while (count_insert-- > 0) {
pointer.previous();
pointer.remove();
}
if (both_types) {
commonlength=diff_commonPrefix(text_insert,text_delete);
if (commonlength != 0) {
if (pointer.hasPrevious()) {
thisDiff=pointer.previous();
assert thisDiff.operation == Operation.EQUAL : "Previous diff should have been an equality.";
thisDiff.text+=text_insert.substring(0,commonlength);
pointer.next();
}
 else {
pointer.add(new Diff(Operation.EQUAL,text_insert.substring(0,commonlength)));
}
text_insert=text_insert.substring(commonlength);
text_delete=text_delete.substring(commonlength);
}
commonlength=diff_commonSuffix(text_insert,text_delete);
if (commonlength != 0) {
thisDiff=pointer.next();
thisDiff.text=text_insert.substring(text_insert.length() - commonlength) + thisDiff.text;
text_insert=text_insert.substring(0,text_insert.length() - commonlength);
text_delete=text_delete.substring(0,text_delete.length() - commonlength);
pointer.previous();
}
}
if (text_delete.length() != 0) {
pointer.add(new Diff(Operation.DELETE,text_delete));
}
if (text_insert.length() != 0) {
pointer.add(new Diff(Operation.INSERT,text_insert));
}
thisDiff=pointer.hasNext() ? pointer.next() : null;
}
 else if (prevEqual != null) {
prevEqual.text+=thisDiff.text;
pointer.remove();
thisDiff=pointer.previous();
pointer.next();
}
count_insert=0;
count_delete=0;
text_delete="";
text_insert="";
prevEqual=thisDiff;
break;
}
thisDiff=pointer.hasNext() ? pointer.next() : null;
}
if (diffs.getLast().text.length() == 0) {
diffs.removeLast();
}
boolean changes=false;
pointer=diffs.listIterator();
Diff prevDiff=pointer.hasNext() ? pointer.next() : null;
thisDiff=pointer.hasNext() ? pointer.next() : null;
Diff nextDiff=pointer.hasNext() ? pointer.next() : null;
while (nextDiff != null) {
if (prevDiff.operation == Operation.EQUAL && nextDiff.operation == Operation.EQUAL) {
if (thisDiff.text.endsWith(prevDiff.text)) {
thisDiff.text=prevDiff.text + thisDiff.text.substring(0,thisDiff.text.length() - prevDiff.text.length());
nextDiff.text=prevDiff.text + nextDiff.text;
pointer.previous();
pointer.previous();
pointer.previous();
pointer.remove();
pointer.next();
thisDiff=pointer.next();
nextDiff=pointer.hasNext() ? pointer.next() : null;
changes=true;
}
 else if (thisDiff.text.startsWith(nextDiff.text)) {
prevDiff.text+=nextDiff.text;
thisDiff.text=thisDiff.text.substring(nextDiff.text.length()) + nextDiff.text;
pointer.remove();
nextDiff=pointer.hasNext() ? pointer.next() : null;
changes=true;
}
}
prevDiff=thisDiff;
thisDiff=nextDiff;
nextDiff=pointer.hasNext() ? pointer.next() : null;
}
if (changes) {
diff_cleanupMerge(diffs);
}
}

public void diff_cleanupMerge ( LinkedList < Diff > diffs ) { diffs . add ( new Diff ( Operation . EQUAL , "" ) ) ; ListIterator < Diff > pointer = diffs . listIterator ( ) ; int count_delete = 0 ; int count_insert = 0 ; String text_delete = "" ; String text_insert = "" ; Diff thisDiff = pointer . next ( ) ; Diff prevEqual = null ; int commonlength ; while ( thisDiff != null ) { switch ( thisDiff . operation ) { case INSERT : count_insert ++ ; text_insert += thisDiff . text ; prevEqual = null ; break ; case DELETE : count_delete ++ ; text_delete += thisDiff . text ; prevEqual = null ; break ; case EQUAL : if ( count_delete + count_insert > 1 ) { boolean both_types = count_delete != 0 && count_insert != 0 ; pointer . previous ( ) ; while ( count_delete -- > 0 ) { pointer . previous ( ) ; pointer . remove ( ) ; } while ( count_insert -- > 0 ) { pointer . previous ( ) ; pointer . remove ( ) ; } if ( both_types ) { commonlength = diff_commonPrefix ( text_insert , text_delete ) ; if ( commonlength != 0 ) { if ( pointer . hasPrevious ( ) ) { thisDiff = pointer . previous ( ) ; assert thisDiff . operation == Operation . EQUAL : "Previous diff should have been an equality." ; thisDiff . text += text_insert . substring ( 0 , commonlength ) ; pointer . next ( ) ; } else { pointer . add ( new Diff ( Operation . EQUAL , text_insert . substring ( 0 , commonlength ) ) ) ; } text_insert = text_insert . substring ( commonlength ) ; text_delete = text_delete . substring ( commonlength ) ; } commonlength = diff_commonSuffix ( text_insert , text_delete ) ; if ( commonlength != 0 ) { thisDiff = pointer . next ( ) ; thisDiff . text = text_insert . substring ( text_insert . length ( ) - commonlength ) + thisDiff . text ; text_insert = text_insert . substring ( 0 , text_insert . length ( ) - commonlength ) ; text_delete = text_delete . substring ( 0 , text_delete . length ( ) - commonlength ) ; pointer . previous ( ) ; } } if ( text_delete . length ( ) != 0 ) { pointer . add ( new Diff ( Operation . DELETE , text_delete ) ) ; } if ( text_insert . length ( ) != 0 ) { pointer . add ( new Diff ( Operation . INSERT , text_insert ) ) ; } thisDiff = pointer . hasNext ( ) ? pointer . next ( ) : null ; } else if ( prevEqual != null ) { prevEqual . text += thisDiff . text ; pointer . remove ( ) ; thisDiff = pointer . previous ( ) ; pointer . next ( ) ; } count_insert = 0 ; count_delete = 0 ; text_delete = "" ; text_insert = "" ; prevEqual = thisDiff ; break ; } thisDiff = pointer . hasNext ( ) ? pointer . next ( ) : null ; } if ( diffs . getLast ( ) . text . length ( ) == 0 ) { diffs . removeLast ( ) ; } boolean changes = false ; pointer = diffs . listIterator ( ) ; Diff prevDiff = pointer . hasNext ( ) ? pointer . next ( ) : null ; thisDiff = pointer . hasNext ( ) ? pointer . next ( ) : null ; Diff nextDiff = pointer . hasNext ( ) ? pointer . next ( ) : null ; while ( nextDiff != null ) { if ( prevDiff . operation == Operation . EQUAL && nextDiff . operation == Operation . EQUAL ) { if ( thisDiff . text . endsWith ( prevDiff . text ) ) { thisDiff . text = prevDiff . text + thisDiff . text . substring ( 0 , thisDiff . text . length ( ) - prevDiff . text . length ( ) ) ; nextDiff . text = prevDiff . text + nextDiff . text ; pointer . previous ( ) ; pointer . previous ( ) ; pointer . previous ( ) ; pointer . remove ( ) ; pointer . next ( ) ; thisDiff = pointer . next ( ) ; nextDiff = pointer . hasNext ( ) ? pointer . next ( ) : null ; changes = true ; } else if ( thisDiff . text . startsWith ( nextDiff . text ) ) { prevDiff . text += nextDiff . text ; thisDiff . text = thisDiff . text . substring ( nextDiff . text . length ( ) ) + nextDiff . text ; pointer . remove ( ) ; nextDiff = pointer . hasNext ( ) ? pointer . next ( ) : null ; changes = true ; } } prevDiff = thisDiff ; thisDiff = nextDiff ; nextDiff = pointer . hasNext ( ) ? pointer . next ( ) : null ; } if ( changes ) { diff_cleanupMerge ( diffs ) ; } }
reorder and merge like edit sections . merge equalities . any edit section can move as long as it doesn ' t cross an equality .
