DocumentDiff.java 7.91 KB
/*
 * Decompiled with CFR 0_118.
 */
package com.day.util.diff;

import com.day.util.diff.*;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;

public class DocumentDiff {
    static final String CVS_ID = "$URL$ $Rev$ $Date$";
    private Document left;
    private Document right;
    private final Diff.Change change;
    private Hunk hunks;
    private int numDelta = 0;

    public DocumentDiff(Document left, Document right) {
        this.left = left;
        this.right = right;
        Object[] leftElems = left.getElements();
        Object[] rightElems = right.getElements();
        this.change = new Diff(leftElems, rightElems).diff_2(false);
        this.init();
    }

    public int getNumDeltaElements() {
        return this.numDelta;
    }

    public Hunk getHunks() {
        return this.hunks;
    }

    public void write(StringBuffer buf, int numContextLines) {
        try {
            StringWriter out = new StringWriter();
            this.write(new DiffWriter(out), numContextLines);
            out.close();
            buf.append(out.getBuffer());
        }
        catch (IOException e) {
            throw new IllegalStateException(e.toString());
        }
    }

    public void write(StringBuffer buf, String lineSeparator, int numContextLines) {
        try {
            StringWriter out = new StringWriter();
            this.write(new DiffWriter(out, lineSeparator), numContextLines);
            out.close();
            buf.append(out.getBuffer());
        }
        catch (IOException e) {
            throw new IllegalStateException(e.toString());
        }
    }

    public void write(Writer out, int numContextLines) throws IOException {
        DiffWriter dw = new DiffWriter(out);
        this.write(dw, numContextLines);
        dw.flush();
    }

    public void write(DiffWriter out, int numContextLines) throws IOException {
        if (this.hunks != null) {
            if (this.left.getSource() != null && this.right.getSource() != null) {
                out.write("--- ");
                out.write(this.left.getSource().getLocation());
                out.writeNewLine();
                out.write("+++ ");
                out.write(this.right.getSource().getLocation());
                out.writeNewLine();
            } else {
                out.write("--- .mine");
                out.writeNewLine();
                out.write("+++ .theirs");
                out.writeNewLine();
            }
            for (Hunk hunk = this.hunks; hunk != null; hunk = hunk.write((DiffWriter)out, (int)numContextLines)) {
            }
        }
    }

    private void init() {
        int len;
        Hunk first;
        Diff.Change c = this.change;
        int leftPos = 0;
        int rightPos = 0;
        Hunk hunk = first = new Hunk(null, null, 0, null);
        while (c != null) {
            this.numDelta += Math.max(c.deleted, c.inserted);
            if (leftPos < c.line0) {
                len = c.line0 - leftPos;
                hunk = new Hunk(new Range(this.left, leftPos, leftPos + len), new Range(this.right, rightPos, rightPos + len), 0, hunk);
                leftPos += len;
                rightPos += len;
            }
            hunk = new Hunk(new Range(this.left, leftPos, leftPos + c.deleted), new Range(this.right, rightPos, rightPos + c.inserted), (c.deleted > 0 ? 2 : 0) | (c.inserted > 0 ? 1 : 0), hunk);
            leftPos += c.deleted;
            rightPos += c.inserted;
            c = c.nextChange;
        }
        if (leftPos < this.left.getElements().length) {
            len = this.left.getElements().length - leftPos;
            new Hunk(new Range(this.left, leftPos, leftPos + len), new Range(this.right, rightPos, rightPos + len), 0, hunk);
        }
        this.hunks = first.next();
    }

    public void showChanges(ChangeListener listener, int numContextLines) {
        Diff.Change c = this.change;
        Document.Element[] lines0 = this.left.getElements();
        Document.Element[] lines1 = this.right.getElements();
        listener.onDocumentsStart(this.left, this.right);
        while (c != null) {
            int i;
            Diff.Change first = c;
            int start0 = Math.max(c.line0 - numContextLines, 0);
            int end0 = Math.min(c.line0 + c.deleted + numContextLines, lines0.length);
            int start1 = Math.max(c.line1 - numContextLines, 0);
            int end1 = Math.min(c.line1 + c.inserted + numContextLines, lines1.length);
            while (c != null && c.line0 <= end0) {
                end0 = Math.min(c.line0 + c.deleted + numContextLines, lines0.length);
                end1 = Math.min(c.line1 + c.inserted + numContextLines, lines1.length);
                c = c.nextChange;
            }
            listener.onChangeStart(start0, end0 - start0 - 1, start1, end1 - start1 - 1);
            while (first != c) {
                while (start0 < first.line0) {
                    listener.onUnmodified(start0, start1, lines0[start0]);
                    ++start0;
                    ++start1;
                }
                for (i = 0; i < first.deleted; ++i) {
                    listener.onDeleted(start0, first.line1, lines0[start0]);
                    ++start0;
                }
                for (i = 0; i < first.inserted; ++i) {
                    listener.onInserted(first.line0, start1, lines1[start1]);
                    ++start1;
                }
                first = first.nextChange;
            }
            for (i = 0; i < numContextLines && start0 < lines0.length; ++i) {
                listener.onUnmodified(start0, start1, lines0[start0]);
                ++start0;
                ++start1;
            }
            listener.onChangeEnd();
        }
        listener.onDocumentsEnd(this.left, this.right);
    }

    public ElementsFactory getMergedLeft() {
        return new MergeElementFactory(true);
    }

    public ElementsFactory getMergedRight() {
        return new MergeElementFactory(false);
    }

    private class MergeElementFactory
    implements ElementsFactory {
        boolean reverse;

        public MergeElementFactory(boolean reverse) {
            this.reverse = reverse;
        }

        public Document.Element[] getElements() {
            Diff.Change c = DocumentDiff.this.change;
            Document.Element[] lines0 = DocumentDiff.this.left.getElements();
            Document.Element[] lines1 = DocumentDiff.this.right.getElements();
            ArrayList<Document.Element> elems = new ArrayList<Document.Element>();
            while (c != null) {
                Diff.Change first = c;
                int start0 = 0;
                int end0 = lines0.length;
                int start1 = 0;
                int end1 = lines1.length;
                while (c != null && c.line0 <= end0) {
                    end0 = lines0.length;
                    end1 = lines1.length;
                    c = c.nextChange;
                }
                while (first != c) {
                    int i;
                    while (start0 < first.line0) {
                        elems.add(lines0[start0]);
                        ++start0;
                        ++start1;
                    }
                    for (i = 0; i < first.deleted; ++i) {
                        if (this.reverse) {
                            elems.add(lines0[start0]);
                        }
                        ++start0;
                    }
                    for (i = 0; i < first.inserted; ++i) {
                        if (!this.reverse) {
                            elems.add(lines1[start1]);
                        }
                        ++start1;
                    }
                    first = first.nextChange;
                }
                while (start0 < lines0.length) {
                    elems.add(lines0[start0]);
                    ++start0;
                    ++start1;
                }
            }
            return elems.toArray(new Document.Element[elems.size()]);
        }
    }

}