package ilarkesto.core.diff; public class CharDiff { private String left; private String right; private DiffMarker marker; private String lcs; private int lcsLen; private int leftLen; private int rightLen; private StringBuilder out = new StringBuilder(); private char chLcs; private char chLeft; private char chRight; private boolean skipBurn; public CharDiff(String left, String right, DiffMarker marker) { super(); this.left = left == null ? "" : left; this.right = right == null ? "" : right; this.marker = marker; } public CharDiff diff() { lcs = LongestCommonSubsequenceString.execute(left, right); updateLengths(); while (skipBurn || (lcsLen > 0 && leftLen > 0 && rightLen > 0)) { burnNext(); } if (leftLen == 0 && rightLen == 0) return this; if (leftLen == 0) { out.append(marker.added(right)); return this; } if (rightLen == 0) { out.append(marker.removed(left)); return this; } if (lcsLen == 0) { out.append(marker.removed(left)); out.append(marker.added(right)); return this; } return this; } private void burnNext() { if (!nextChar()) return; if (chLcs == chLeft && chLcs == chRight) { burnSame(); return; } if (chLcs == chLeft) { burnAdded(); return; } burnRemoved(); } private void burnRemoved() { StringBuilder sb = new StringBuilder(); while (chLcs != chLeft) { sb.append(chLeft); if (!nextCharLeft()) break; } out.append(marker.removed(sb.toString())); skipBurn = true; } private void burnAdded() { StringBuilder sb = new StringBuilder(); while (chLcs == chLeft && chLcs != chRight) { sb.append(chRight); if (!nextCharRight()) break; } out.append(marker.added(sb.toString())); skipBurn = true; } private void burnSame() { StringBuilder sb = new StringBuilder(); boolean nextCharAvailable = false; while (chLcs == chLeft && chLcs == chRight) { sb.append(chLcs); nextCharAvailable = nextChar(); if (!nextCharAvailable) break; } out.append(marker.same(sb.toString())); if (nextCharAvailable) skipBurn = true; } private boolean nextChar() { if (skipBurn) { skipBurn = false; return true; } if (lcsLen == 0) return false; if (leftLen == 0) return false; if (rightLen == 0) return false; chLcs = lcs.charAt(0); chLeft = left.charAt(0); chRight = right.charAt(0); lcs = lcs.substring(1); left = left.substring(1); right = right.substring(1); lcsLen--; leftLen--; rightLen--; return true; } private boolean nextCharRight() { if (rightLen == 0) return false; chRight = right.charAt(0); right = right.substring(1); rightLen--; return true; } private boolean nextCharLeft() { if (leftLen == 0) return false; chLeft = left.charAt(0); left = left.substring(1); leftLen--; return true; } private void updateLengths() { leftLen = left.length(); rightLen = right.length(); lcsLen = lcs.length(); } @Override public String toString() { return out.toString(); } }