From d131d9481736bb64122c3151260d16c0cfb10fd5 Mon Sep 17 00:00:00 2001
From: "dm.naumenko@gmail.com"
Date: Sun, 4 Oct 2009 08:49:25 +0000
Subject: [PATCH] New version which was lost after removing repo.
---
src/difflib/ChangeDelta.java | 54 +++-
src/difflib/Chunk.java | 41 +++
src/difflib/DeleteDelta.java | 44 ++-
src/difflib/Delta.java | 77 ++++-
src/difflib/DiffAlgorithm.java | 18 ++
src/difflib/DiffException.java | 37 +++
src/difflib/DiffRow.java | 72 ++++-
src/difflib/DiffRowGenerator.java | 405 ++++++++++++++++++++++++
src/difflib/DiffUtils.java | 63 ++--
src/difflib/InsertDelta.java | 48 ++-
src/difflib/Patch.java | 77 ++++-
src/difflib/PatchFailedException.java | 36 +++
src/difflib/StringUtills.java | 53 ++++
src/difflib/myers/package.html | 80 ++---
src/difflib/package.html | 70 ++++
test/testcase/diffutills/PatchTest.java | 24 +-
16 files changed, 1101 insertions(+), 98 deletions(-)
create mode 100644 src/difflib/DiffException.java
create mode 100644 src/difflib/DiffRowGenerator.java
create mode 100644 src/difflib/PatchFailedException.java
create mode 100644 src/difflib/StringUtills.java
create mode 100644 src/difflib/package.html
diff --git a/src/difflib/ChangeDelta.java b/src/difflib/ChangeDelta.java
index c9a2e99..828e43f 100644
--- a/src/difflib/ChangeDelta.java
+++ b/src/difflib/ChangeDelta.java
@@ -1,3 +1,21 @@
+/*
+ Copyright 2009 Dmitry Naumenko (dm.naumenko@gmail.com)
+
+ This file is part of Java Diff Utills Library.
+
+ Java Diff Utills Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Java Diff Utills Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Java Diff Utills Library. If not, see .
+*/
package difflib;
import java.util.List;
@@ -18,12 +36,14 @@ public class ChangeDelta extends Delta {
/**
* {@inheritDoc}
+ * @throws PatchFailedException
*/
@Override
- public void applyTo(List target) {
+ public void applyTo(List target) throws PatchFailedException {
+ verify(target);
int position = getOriginal().getPosition();
- int originalSize = getOriginal().getSize();
- for (int i = 0; i < originalSize; i++) {
+ int size = getOriginal().getSize();
+ for (int i = 0; i < size; i++) {
target.remove(position);
}
int i = 0;
@@ -33,4 +53,32 @@ public class ChangeDelta extends Delta {
}
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void restore(List target) {
+ int position = getRevised().getPosition();
+ int size = getRevised().getSize();
+ for (int i = 0; i < size; i++) {
+ target.remove(position);
+ }
+ int i = 0;
+ for (Object line: getOriginal().getLines()) {
+ target.add(position + i, line);
+ i++;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void verify(List> target) throws PatchFailedException {
+ getOriginal().verify(target);
+ if (getOriginal().getPosition() > target.size()) {
+ throw new PatchFailedException("Incorrect patch for delta: " +
+ "delta original position > target size");
+ }
+ }
+
}
diff --git a/src/difflib/Chunk.java b/src/difflib/Chunk.java
index be2d217..3a389de 100644
--- a/src/difflib/Chunk.java
+++ b/src/difflib/Chunk.java
@@ -1,3 +1,21 @@
+/*
+ Copyright 2009 Dmitry Naumenko (dm.naumenko@gmail.com)
+
+ This file is part of Java Diff Utills Library.
+
+ Java Diff Utills Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Java Diff Utills Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Java Diff Utills Library. If not, see .
+*/
package difflib;
import java.util.*;
@@ -46,6 +64,22 @@ public class Chunk {
this.lines = Arrays.asList(lines);
}
+ /**
+ * Verifies that this chunk's saved text matches the corresponding
+ * text in the given sequence.
+ * @param target the sequence to verify against.
+ */
+ public void verify(List> target) throws PatchFailedException{
+ if (last() > target.size()) {
+ throw new PatchFailedException("Incorrect Chunk: the position of chunk > target size");
+ }
+ for (int i = 0; i < size; i++) {
+ if (!target.get(position + i).equals(lines.get(i))) {
+ throw new PatchFailedException("Incorrect Chunk: the chunk content doesn't match the target");
+ }
+ }
+ }
+
/**
* @return the start position of chunk in the text
*/
@@ -84,6 +118,13 @@ public class Chunk {
public void setLines(List> lines) {
this.lines = lines;
}
+
+ /**
+ * Returns the index of the last line of the chunk.
+ */
+ public int last(){
+ return getPosition() + getSize() - 1;
+ }
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
diff --git a/src/difflib/DeleteDelta.java b/src/difflib/DeleteDelta.java
index 334cfe6..6a0ee71 100644
--- a/src/difflib/DeleteDelta.java
+++ b/src/difflib/DeleteDelta.java
@@ -1,3 +1,21 @@
+/*
+ Copyright 2009 Dmitry Naumenko (dm.naumenko@gmail.com)
+
+ This file is part of Java Diff Utills Library.
+
+ Java Diff Utills Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Java Diff Utills Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Java Diff Utills Library. If not, see .
+*/
package difflib;
import java.util.List;
@@ -18,9 +36,11 @@ public class DeleteDelta extends Delta {
/**
* {@inheritDoc}
+ * @throws PatchFailedException
*/
@Override
- public void applyTo(List target) {
+ public void applyTo(List target) throws PatchFailedException {
+ verify(target);
int position = getOriginal().getPosition();
int size = getOriginal().getSize();
for (int i = 0; i < size; i++) {
@@ -28,4 +48,26 @@ public class DeleteDelta extends Delta {
}
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void restore(List target) {
+ int position = this.getRevised().getPosition();
+ List> lines = this.getOriginal().getLines();
+ for (int i = 0; i < lines.size(); i++) {
+ target.add(position + i, lines.get(i));
+ }
+ }
+
+ @Override
+ public void verify(List> target) throws PatchFailedException {
+ getOriginal().verify(target);
+ }
+
+ @Override
+ public String toString() {
+ return "[DeleteDelta, position: " + getOriginal().getPosition() + ", lines: " +
+ getOriginal().getLines() + "]";
+ }
}
diff --git a/src/difflib/Delta.java b/src/difflib/Delta.java
index c6731cb..58242e7 100644
--- a/src/difflib/Delta.java
+++ b/src/difflib/Delta.java
@@ -1,3 +1,21 @@
+/*
+ Copyright 2009 Dmitry Naumenko (dm.naumenko@gmail.com)
+
+ This file is part of Java Diff Utills Library.
+
+ Java Diff Utills Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Java Diff Utills Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Java Diff Utills Library. If not, see .
+*/
package difflib;
import java.util.*;
@@ -22,12 +40,27 @@ public abstract class Delta {
this.revised = revised;
}
+ /**
+ * Verifies that this delta can be used to patch the given text.
+ * @param target the text to patch.
+ * @throws PatchFailedException if the patch cannot be applied.
+ */
+ public abstract void verify(List> target) throws PatchFailedException;
+
/**
* Applies this delta as the patch for a given target
*
- * @param target the given target
+ * @param target the given target
+ * @throws PatchFailedException
*/
- public abstract void applyTo(List target);
+ public abstract void applyTo(List target) throws PatchFailedException;
+
+ /**
+ * Cancel this delta for a given revised text. The action is opposite to patch.
+ *
+ * @param target the given revised text
+ */
+ public abstract void restore(List target);
/**
* @return the Chunk describing the original text
@@ -54,4 +87,44 @@ public abstract class Delta {
public void setRevised(Chunk revised) {
this.revised = revised;
}
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + ((original == null) ? 0 : original.hashCode());
+ result = prime * result + ((revised == null) ? 0 : revised.hashCode());
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Delta other = (Delta) obj;
+ if (original == null) {
+ if (other.original != null)
+ return false;
+ } else if (!original.equals(other.original))
+ return false;
+ if (revised == null) {
+ if (other.revised != null)
+ return false;
+ } else if (!revised.equals(other.revised))
+ return false;
+ return true;
+ }
+
+
}
diff --git a/src/difflib/DiffAlgorithm.java b/src/difflib/DiffAlgorithm.java
index f49a804..1a71695 100644
--- a/src/difflib/DiffAlgorithm.java
+++ b/src/difflib/DiffAlgorithm.java
@@ -1,3 +1,21 @@
+/*
+ Copyright 2009 Dmitry Naumenko (dm.naumenko@gmail.com)
+
+ This file is part of Java Diff Utills Library.
+
+ Java Diff Utills Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Java Diff Utills Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Java Diff Utills Library. If not, see .
+*/
package difflib;
import java.util.*;
diff --git a/src/difflib/DiffException.java b/src/difflib/DiffException.java
new file mode 100644
index 0000000..5bcf9da
--- /dev/null
+++ b/src/difflib/DiffException.java
@@ -0,0 +1,37 @@
+/*
+ Copyright 2009 Dmitry Naumenko (dm.naumenko@gmail.com)
+
+ This file is part of Java Diff Utills Library.
+
+ Java Diff Utills Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Java Diff Utills Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Java Diff Utills Library. If not, see .
+*/
+package difflib;
+
+/**
+ * Base class for all exceptions emanating from this package.
+ *
+ * @author Juanco Anez
+ */
+public class DiffException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public DiffException() {
+ }
+
+ public DiffException(String msg) {
+ super(msg);
+ }
+}
+
diff --git a/src/difflib/DiffRow.java b/src/difflib/DiffRow.java
index a8d3aeb..444980c 100644
--- a/src/difflib/DiffRow.java
+++ b/src/difflib/DiffRow.java
@@ -1,3 +1,21 @@
+/*
+ Copyright 2009 Dmitry Naumenko (dm.naumenko@gmail.com)
+
+ This file is part of Java Diff Utills Library.
+
+ Java Diff Utills Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Java Diff Utills Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Java Diff Utills Library. If not, see .
+*/
package difflib;
/**
@@ -11,8 +29,14 @@ public class DiffRow {
private String oldLine;
private String newLine;
+ public DiffRow(Tag tag, String oldLine, String newLine) {
+ this.tag = tag;
+ this.oldLine = oldLine;
+ this.newLine = newLine;
+ }
+
public enum Tag {
- INSERT, DELETE, CHANGE
+ INSERT, DELETE, CHANGE, EQUAL
}
/**
@@ -53,4 +77,50 @@ public class DiffRow {
public void setNewLine(String newLine) {
this.newLine = newLine;
}
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((newLine == null) ? 0 : newLine.hashCode());
+ result = prime * result + ((oldLine == null) ? 0 : oldLine.hashCode());
+ result = prime * result + ((tag == null) ? 0 : tag.hashCode());
+ return result;
+ }
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ DiffRow other = (DiffRow) obj;
+ if (newLine == null) {
+ if (other.newLine != null)
+ return false;
+ } else if (!newLine.equals(other.newLine))
+ return false;
+ if (oldLine == null) {
+ if (other.oldLine != null)
+ return false;
+ } else if (!oldLine.equals(other.oldLine))
+ return false;
+ if (tag == null) {
+ if (other.tag != null)
+ return false;
+ } else if (!tag.equals(other.tag))
+ return false;
+ return true;
+ }
+
+ public String toString() {
+ return "[" + this.tag + "," + this.oldLine + "," + this.newLine + "]";
+ }
}
diff --git a/src/difflib/DiffRowGenerator.java b/src/difflib/DiffRowGenerator.java
new file mode 100644
index 0000000..da79dd4
--- /dev/null
+++ b/src/difflib/DiffRowGenerator.java
@@ -0,0 +1,405 @@
+/*
+ Copyright 2009 Dmitry Naumenko (dm.naumenko@gmail.com)
+
+ This file is part of Java Diff Utills Library.
+
+ Java Diff Utills Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Java Diff Utills Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Java Diff Utills Library. If not, see .
+*/
+package difflib;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import difflib.DiffRow.Tag;
+
+/**
+ * This class for generating DiffRows for side-by-sidy view.
+ * You can customize the way of generating. For example, show inline diffs on not, ignoring
+ * white spaces or/and blank lines and so on. All parameters for generating are optional. If you do
+ * not specify them, the class will use the default values.
+ *
+ * These values are:
+ * showInlineDiffs = false;
+ * ignoreWhiteSpaces = true;
+ * ignoreBlankLines = true;
+ * ...
+ *
+ * For instantiating the DiffRowGenerator you should use the its builder. Like in example
+ *
+ * DiffRowGenerator generator = new DiffRowGenerator.Builder().showInlineDiffs(true).
+ * ignoreWhiteSpaces(true).columnWidth(100).build();
+ *
+ *
+ * @author Dmitry Naumenko
+ */
+public class DiffRowGenerator {
+ private final boolean showInlineDiffs;
+ private final boolean ignoreWhiteSpaces;
+ private final boolean ignoreBlankLines;
+ private final String InlineOldTag;
+ private final String InlineNewTag;
+ private final String InlineOldCssClass;
+ private final String InlineNewCssClass;
+ private final int columnWidth;
+
+ /**
+ * This class used for building the DiffRowGenerator.
+ * @author dmitry
+ *
+ */
+ public static class Builder {
+ private boolean showInlineDiffs = false;
+ private boolean ignoreWhiteSpaces = true;
+ private boolean ignoreBlankLines = true;
+ private String InlineOldTag = "span";
+ private String InlineNewTag = "span";
+ private String InlineOldCssClass = "editOldInline";
+ private String InlineNewCssClass = "editNewInline";
+ private int columnWidth = 80;
+
+ /**
+ * Show inline diffs in generating diff rows or not.
+ * @param val the value to set. Default: false.
+ * @return builder with configured showInlineDiff parameter
+ */
+ public Builder showInlineDiffs(boolean val) {
+ showInlineDiffs = val;
+ return this;
+ }
+
+ /**
+ * Ignore white spaces in generating diff rows or not.
+ * @param val the value to set. Default: true.
+ * @return builder with configured ignoreWhiteSpaces parameter
+ */
+ public Builder ignoreWhiteSpaces(boolean val) {
+ ignoreWhiteSpaces = val;
+ return this;
+ }
+
+ /**
+ * Ignore blank lines in generating diff rows or not.
+ * @param val the value to set. Default: true.
+ * @return builder with configured ignoreBlankLines parameter
+ */
+ public Builder ignoreBlankLines(boolean val) {
+ ignoreBlankLines = val;
+ return this;
+ }
+
+ /**
+ * Set the tag used for displaying changes in the original text.
+ * @param tag the tag to set. Without angle brackets. Default: span.
+ * @return builder with configured ignoreBlankLines parameter
+ */
+ public Builder InlineOldTag(String tag) {
+ InlineOldTag = tag;
+ return this;
+ }
+
+ /**
+ * Set the tag used for displaying changes in the revised text.
+ * @param tag the tag to set. Without angle brackets. Default: span.
+ * @return builder with configured ignoreBlankLines parameter
+ */
+ public Builder InlineNewTag(String tag) {
+ InlineNewTag = tag;
+ return this;
+ }
+
+ /**
+ * Set the css class used for displaying changes in the original text.
+ * @param cssClass the tag to set. Without any quotes, just word. Default: editOldInline.
+ * @return builder with configured ignoreBlankLines parameter
+ */
+ public Builder InlineOldCssClass(String cssClass) {
+ InlineOldCssClass = cssClass;
+ return this;
+ }
+
+ /**
+ * Set the css class used for displaying changes in the revised text.
+ * @param cssClass the tag to set. Without any quotes, just word. Default: editNewInline.
+ * @return builder with configured ignoreBlankLines parameter
+ */
+ public Builder InlineNewCssClass(String cssClass) {
+ InlineNewCssClass = cssClass;
+ return this;
+ }
+
+ /**
+ * Set the column with of generated lines of original and revised texts.
+ * @param width the width to set. Making it < 0 doesn't have any sense. Default 80.
+ * @return builder with configured ignoreBlankLines parameter
+ */
+ public Builder columnWidth(int width) {
+ if (width > 0) {
+ columnWidth = width;
+ }
+ return this;
+ }
+
+ /**
+ * Build the DiffRowGenerator. If some parameters is not set, the default values are used.
+ * @return the customized DiffRowGenerator
+ */
+ public DiffRowGenerator build() {
+ return new DiffRowGenerator(this);
+ }
+ }
+
+ private DiffRowGenerator(Builder builder) {
+ showInlineDiffs = builder.showInlineDiffs;
+ ignoreWhiteSpaces = builder.ignoreWhiteSpaces; //
+ ignoreBlankLines = builder.ignoreBlankLines; //
+ InlineOldTag = builder.InlineOldTag;
+ InlineNewTag = builder.InlineNewTag;
+ InlineOldCssClass = builder.InlineOldCssClass;
+ InlineNewCssClass = builder.InlineNewCssClass;
+ columnWidth = builder.columnWidth; //
+ }
+
+ /**
+ * Get the DiffRows describing the difference between original and revised texts using the
+ * given patch. Useful for displaying side-by-side diff.
+ *
+ * @param original the original text
+ * @param revised the revised text
+ * @return the DiffRows between original and revised texts
+ */
+ public List generateDiffRows(List original, List revised) {
+ return generateDiffRows(original, revised, DiffUtils.diff(original, revised));
+ }
+
+ /**
+ * Generates the DiffRows describing the difference between original and revised texts using the
+ * given patch. Useful for displaying side-by-side diff.
+ *
+ * @param original the original text
+ * @param revised the revised text
+ * @param patch the given patch
+ * @return the DiffRows between original and revised texts
+ */
+ @SuppressWarnings("unchecked")
+ public List generateDiffRows(List original, List revised, Patch patch) {
+ // normalize the lines (expand tabs, escape html entities)
+ original = StringUtills.normalize((List)original);
+ revised = StringUtills.normalize((List)revised);
+
+ // wrap to the column width
+ original = StringUtills.wrapText((List)original, this.columnWidth);
+ revised = StringUtills.wrapText((List)revised, this.columnWidth);
+
+ List diffRows = new ArrayList();
+ int endPos = 0;
+ for (int i = 0; i < patch.getDeltas().size(); i++) {
+ Delta delta = patch.getDelta(i);
+ Chunk orig = delta.getOriginal();
+ Chunk rev = delta.getRevised();
+
+ // We should normalize and wrap lines in deltas too.
+ orig.setLines(StringUtills.normalize((List)orig.getLines()));
+ rev.setLines(StringUtills.normalize((List)rev.getLines()));
+
+ orig.setLines(StringUtills.wrapText((List)orig.getLines(), this.columnWidth));
+ rev.setLines(StringUtills.wrapText((List)rev.getLines(), this.columnWidth));
+
+ // catch the equal prefix for each chunk
+ for (String line: original.subList(endPos, orig.getPosition())) {
+ diffRows.add(new DiffRow(Tag.EQUAL, line, line));
+ }
+
+ // Inserted DiffRow
+ if (delta.getClass().equals(InsertDelta.class)) {
+ endPos = orig.last() + 1;
+ for (String line: (List)rev.getLines()) {
+ diffRows.add(new DiffRow(Tag.INSERT, "", line));
+ }
+ continue;
+ }
+
+ // Deleted DiffRow
+ if (delta.getClass().equals(DeleteDelta.class)) {
+ endPos = orig.last() + 1;
+ for (String line: (List)orig.getLines()) {
+ diffRows.add(new DiffRow(Tag.DELETE, line, ""));
+ }
+ continue;
+ }
+
+ if (showInlineDiffs) {
+ addInlineDiffs(delta);
+ }
+ // the changed size is match
+ if (orig.getSize() == rev.getSize()) {
+ for (int j = 0; j < orig.getSize(); j++) {
+ diffRows.add(new DiffRow(Tag.CHANGE, (String)orig.getLines().get(j),
+ (String)rev.getLines().get(j)));
+ }
+ } else if (orig.getSize() > rev.getSize()) {
+ for (int j = 0; j < orig.getSize(); j++) {
+ diffRows.add(new DiffRow(Tag.CHANGE, (String)orig.getLines().get(j),
+ rev.getLines().size() > j ? (String)rev.getLines().get(j) : ""));
+ }
+ } else {
+ for (int j = 0; j < rev.getSize(); j++) {
+ diffRows.add(new DiffRow(Tag.CHANGE, orig.getLines().size() > j ?
+ (String)orig.getLines().get(j) : "", (String)rev.getLines().get(j)));
+ }
+ }
+ endPos = orig.last() + 1;
+ }
+
+ // Copy the final matching chunk if any.
+ for (String line: original.subList(endPos, original.size())) {
+ diffRows.add(new DiffRow(Tag.EQUAL, line, line));
+ }
+ return diffRows;
+ }
+
+ /**
+ * Add the inline diffs for given delta
+ * @param delta the given delta
+ */
+ @SuppressWarnings("unchecked")
+ private void addInlineDiffs(Delta delta) {
+ List orig = (List)delta.getOriginal().getLines();
+ List rev = (List)delta.getRevised().getLines();
+ LinkedList origList = new LinkedList();
+ for (Character character: join(orig, "\n").toCharArray()) {
+ origList.add(character.toString());
+ }
+ LinkedList revList = new LinkedList();
+ for (Character character: join(rev, "\n").toCharArray()) {
+ revList.add(character.toString());
+ }
+ List inlineDeltas = DiffUtils.diff(origList, revList).getDeltas();
+ if (inlineDeltas.size() < 3) {
+ Collections.reverse(inlineDeltas);
+ for (Delta inlineDelta: inlineDeltas) {
+ Chunk inlineOrig = inlineDelta.getOriginal();
+ Chunk inlineRev = inlineDelta.getRevised();
+ if (inlineDelta.getClass().equals(DeleteDelta.class)) {
+ origList = wrapInTag(origList, inlineOrig.getPosition(),
+ inlineOrig.getPosition() + inlineOrig.getSize() + 1,
+ this.InlineOldTag, this.InlineOldCssClass);
+ } else if (inlineDelta.getClass().equals(InsertDelta.class)) {
+ revList = wrapInTag(revList, inlineRev.getPosition(),
+ inlineRev.getPosition() + inlineRev.getSize() + 1,
+ this.InlineNewTag, this.InlineNewCssClass);
+ } else if (inlineDelta.getClass().equals(ChangeDelta.class)) {
+ origList = wrapInTag(origList, inlineOrig.getPosition(),
+ inlineOrig.getPosition() + inlineOrig.getSize() + 1,
+ this.InlineOldTag, this.InlineOldCssClass);
+ revList = wrapInTag(revList, inlineRev.getPosition(),
+ inlineRev.getPosition() + inlineRev.getSize() + 1,
+ this.InlineNewTag, this.InlineNewCssClass);
+ }
+ }
+ StringBuilder origResult = new StringBuilder(), revResult = new StringBuilder();
+ for (String character: origList) {
+ origResult.append(character);
+ }
+ for (String character: revList) {
+ revResult.append(character);
+ }
+ delta.getOriginal().setLines(Arrays.asList(origResult.toString().split("\n")));
+ delta.getRevised().setLines(Arrays.asList(revResult.toString().split("\n")));
+ }
+ }
+
+ /**
+ * Wrap the elements in the sequence with the given tag
+ * @param startPosition the position from which tag should start. The counting start from a zero.
+ * @param endPosition the position before which tag should should be closed.
+ * @param tag the tag name without angle brackets, just a word
+ * @param cssClass the optional css class
+ */
+ public static LinkedList wrapInTag(LinkedList sequence, int startPosition, int endPosition, String tag, String cssClass) {
+ LinkedList result = (LinkedList)sequence.clone();
+ StringBuilder tagBuilder = new StringBuilder();
+ tagBuilder.append("<");
+ tagBuilder.append(tag);
+ if (cssClass != null) {
+ tagBuilder.append(" class=\"");
+ tagBuilder.append(cssClass);
+ tagBuilder.append("\"");
+ }
+ tagBuilder.append(">");
+ String startTag = tagBuilder.toString();
+
+ tagBuilder.delete(0, tagBuilder.length());
+
+ tagBuilder.append("");
+ tagBuilder.append(tag);
+ tagBuilder.append(">");
+ String endTag = tagBuilder.toString();
+
+ result.add(startPosition, startTag);
+ result.add(endPosition, endTag);
+ return result;
+ }
+
+ /**
+ * Wrap the given line with the given tag
+ * @param line the given line
+ * @param tag the tag name without angle brackets, just a word
+ * @param cssClass the optional css class
+ * @return the wrapped string
+ */
+ public static String wrapInTag(String line, String tag, String cssClass) {
+ StringBuilder tagBuilder = new StringBuilder();
+ tagBuilder.append("<");
+ tagBuilder.append(tag);
+ if (cssClass != null) {
+ tagBuilder.append(" class=\"");
+ tagBuilder.append(cssClass);
+ tagBuilder.append("\"");
+ }
+ tagBuilder.append(">");
+ String startTag = tagBuilder.toString();
+
+ tagBuilder.delete(0, tagBuilder.length());
+
+ tagBuilder.append("");
+ tagBuilder.append(tag);
+ tagBuilder.append(">");
+ String endTag = tagBuilder.toString();
+
+ return startTag + line + endTag;
+ }
+
+ /**
+ * The helper method for joining collections
+ * @param
+ * @param objs the collection to join
+ * @param delimiter the delimiter to use
+ * @return the joined string
+ */
+ private static String join(final Iterable objs, final String delimiter) {
+ Iterator iter = objs.iterator();
+ if (!iter.hasNext()) {
+ return "";
+ }
+ StringBuffer buffer = new StringBuffer(String.valueOf(iter.next()));
+ while (iter.hasNext()) {
+ buffer.append(delimiter).append(String.valueOf(iter.next()));
+ }
+ return buffer.toString();
+ }
+}
diff --git a/src/difflib/DiffUtils.java b/src/difflib/DiffUtils.java
index 0302c7c..479dca0 100644
--- a/src/difflib/DiffUtils.java
+++ b/src/difflib/DiffUtils.java
@@ -1,3 +1,21 @@
+/*
+ Copyright 2009 Dmitry Naumenko (dm.naumenko@gmail.com)
+
+ This file is part of Java Diff Utills Library.
+
+ Java Diff Utills Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Java Diff Utills Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Java Diff Utills Library. If not, see .
+*/
package difflib;
import java.util.*;
@@ -10,6 +28,7 @@ import difflib.myers.*;
* Implements the difference and patching engine
*
* @author Dmitry Naumenko
+ * @version 0.4.1
*/
public class DiffUtils {
private static DiffAlgorithm defaultDiffAlgorithm = new MyersDiff();
@@ -45,8 +64,9 @@ public class DiffUtils {
* @param original the original text
* @param patch the given patch
* @return the revised text
+ * @throws PatchFailedException if can't apply patch
*/
- public static List> patch(List> original, Patch patch) {
+ public static List> patch(List> original, Patch patch) throws PatchFailedException {
return patch.applyTo(original);
}
@@ -57,15 +77,15 @@ public class DiffUtils {
* @param patch the given patch
* @return the original text
*/
- public static String unpatch(String revised, Patch patch) {
- // TODO: Not-implemented
- return null;
+ public static List> unpatch(List> revised, Patch patch) {
+ return patch.restore(revised);
}
/**
* Parse the given text in unified format and creates the list of deltas for it.
*
* @param diff the text in unified format
+ * @return the patch with deltas.
*/
public static Patch parseUnifiedDiff(List diff) {
boolean inPrelude = true;
@@ -104,15 +124,25 @@ public class DiffUtils {
rawChunk.clear();
}
// Parse the @@ header
+ old_ln = m.group(1) == null ? 1 : Integer.parseInt(m.group(1));
+ old_n = m.group(2) == null ? 1 : Integer.parseInt(m.group(2));
+ new_ln = m.group(3) == null ? 1 : Integer.parseInt(m.group(3));
+ new_n = m.group(4) == null ? 1 : Integer.parseInt(m.group(4));
old_ln = Integer.parseInt(m.group(1));
- old_n = Integer.parseInt(m.group(2));
- new_ln = Integer.parseInt(m.group(3));
- new_n = Integer.parseInt(m.group(4));
+
+ if (old_ln == 0) {
+ old_ln += 1;
+ }
+ if (new_ln == 0) {
+ new_ln += 1;
+ }
} else {
- tag = line.substring(0, 1);
- rest = line.substring(1);
- if (tag.equals(" ") || tag.equals("+") || tag.equals("-")) {
- rawChunk.add(new Object[] {tag, rest});
+ if (line.length() > 0) {
+ tag = line.substring(0, 1);
+ rest = line.substring(1);
+ if (tag.equals(" ") || tag.equals("+") || tag.equals("-")) {
+ rawChunk.add(new Object[] {tag, rest});
+ }
}
}
}
@@ -141,15 +171,4 @@ public class DiffUtils {
return patch;
}
- /**
- * Get the DiffRows describing the difference between original and revised texts. Useful for
- * displaying side-by-side diff. Computes the Patch before generate the diffs.
- *
- * @param original the original text
- * @param revised the revised text
- * @return the DiffRows between original and revised texts
- */
- public static List getDiffRows(List> original, List> revised) {
- return null;
- }
}
diff --git a/src/difflib/InsertDelta.java b/src/difflib/InsertDelta.java
index 3c30475..4785144 100644
--- a/src/difflib/InsertDelta.java
+++ b/src/difflib/InsertDelta.java
@@ -1,3 +1,21 @@
+/*
+ Copyright 2009 Dmitry Naumenko (dm.naumenko@gmail.com)
+
+ This file is part of Java Diff Utills Library.
+
+ Java Diff Utills Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Java Diff Utills Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Java Diff Utills Library. If not, see .
+*/
package difflib;
import java.util.List;
@@ -18,9 +36,11 @@ public class InsertDelta extends Delta {
/**
* {@inheritDoc}
+ * @throws PatchFailedException
*/
@Override
- public void applyTo(List target) {
+ public void applyTo(List target) throws PatchFailedException {
+ verify(target);
int position = this.getOriginal().getPosition();
List> lines = this.getRevised().getLines();
for (int i = 0; i < lines.size(); i++) {
@@ -28,4 +48,30 @@ public class InsertDelta extends Delta {
}
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void restore(List target) {
+ int position = getRevised().getPosition();
+ int size = getRevised().getSize();
+ for (int i = 0; i < size; i++) {
+ target.remove(position);
+ }
+ }
+
+ @Override
+ public void verify(List> target) throws PatchFailedException {
+ if (getOriginal().getPosition() > target.size()) {
+ throw new PatchFailedException("Incorrect patch for delta: " +
+ "delta original position > target size");
+ }
+
+ }
+
+ @Override
+ public String toString() {
+ return "[InsertDelta, position: " + getOriginal().getPosition() + ", lines: " +
+ getRevised().getLines() + "]";
+ }
}
diff --git a/src/difflib/Patch.java b/src/difflib/Patch.java
index 379b8d7..d24ae00 100644
--- a/src/difflib/Patch.java
+++ b/src/difflib/Patch.java
@@ -1,3 +1,21 @@
+/*
+ Copyright 2009 Dmitry Naumenko (dm.naumenko@gmail.com)
+
+ This file is part of Java Diff Utills Library.
+
+ Java Diff Utills Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Java Diff Utills Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Java Diff Utills Library. If not, see .
+*/
package difflib;
import java.util.*;
@@ -9,21 +27,46 @@ import java.util.*;
*/
public class Patch {
private List deltas = new LinkedList();
+ private boolean isSorted = false;
- public List> applyTo(List> target) {
+ /**
+ * Apply this patch to the given target
+ * @param target
+ * @return the patched text
+ * @throws PatchFailedException if can't apply patch
+ */
+ public List> applyTo(List> target) throws PatchFailedException {
List result = new LinkedList(target);
- for (Delta delta: deltas) {
- delta.applyTo(result);
- }
+ ListIterator it = getDeltas().listIterator(deltas.size());
+ while (it.hasPrevious()) {
+ Delta delta = (Delta) it.previous();
+ delta.applyTo(result);
+ }
return result;
}
+ /**
+ * Restore the text to original. Opposite to applyTo() method.
+ * @param target the given target
+ * @return the restored text
+ */
+ public List> restore(List> target) {
+ List result = new LinkedList(target);
+ ListIterator it = getDeltas().listIterator(deltas.size());
+ while (it.hasPrevious()) {
+ Delta delta = (Delta) it.previous();
+ delta.restore(result);
+ }
+ return result;
+ }
+
/**
* Add the given delta to this patch
* @param delta the given delta
*/
public void addDelta(Delta delta) {
deltas.add(delta);
+ isSorted = false;
}
/**
@@ -31,12 +74,38 @@ public class Patch {
*/
public void setDeltas(List deltas) {
this.deltas = deltas;
+ isSorted = false;
}
/**
+ * Get the list of computed deltas
* @return the deltas
*/
public List getDeltas() {
+ if (!this.isSorted) {
+ Collections.sort(deltas, new Comparator() {
+ public int compare(Delta d1, Delta d2) {
+ if (d1.getOriginal().getPosition() > d2.getOriginal().getPosition()) {
+ return 1;
+ } else if (d1.getOriginal().getPosition() > d2.getOriginal().getPosition()) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+ }
+ );
+ isSorted = true;
+ }
return deltas;
}
+
+ /**
+ * Get the specific delta from patch deltas
+ * @param index the index of delta
+ * @return the needed delta
+ */
+ public Delta getDelta(int index) {
+ return deltas.get(index);
+ }
}
diff --git a/src/difflib/PatchFailedException.java b/src/difflib/PatchFailedException.java
new file mode 100644
index 0000000..c30fc0f
--- /dev/null
+++ b/src/difflib/PatchFailedException.java
@@ -0,0 +1,36 @@
+/*
+ Copyright 2009 Dmitry Naumenko (dm.naumenko@gmail.com)
+
+ This file is part of Java Diff Utills Library.
+
+ Java Diff Utills Library is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Java Diff Utills Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Java Diff Utills Library. If not, see .
+*/
+package difflib;
+
+/**
+ * Thrown whenever a delta cannot be applied as a patch to a given text.
+ *
+ * @author Juanco Anez
+ */
+public class PatchFailedException extends DiffException {
+
+ private static final long serialVersionUID = 1L;
+
+ public PatchFailedException() {
+ }
+
+ public PatchFailedException(String msg) {
+ super(msg);
+ }
+}
\ No newline at end of file
diff --git a/src/difflib/StringUtills.java b/src/difflib/StringUtills.java
new file mode 100644
index 0000000..8cd5bd3
--- /dev/null
+++ b/src/difflib/StringUtills.java
@@ -0,0 +1,53 @@
+package difflib;
+
+import java.util.*;
+
+public class StringUtills {
+
+ public static String join(final Iterable objs, final String delimiter) {
+ Iterator iter = objs.iterator();
+ if (!iter.hasNext()) {
+ return "";
+ }
+ StringBuffer buffer = new StringBuffer(String.valueOf(iter.next()));
+ while (iter.hasNext()) {
+ buffer.append(delimiter).append(String.valueOf(iter.next()));
+ }
+ return buffer.toString();
+ }
+
+ public static String expandTabs(String str) {
+ return str.replace("\t", " ");
+ }
+
+ public static String htmlEntites(String str) {
+ return str.replace("<", "<").replace(">", ">");
+ }
+
+ public static String normalize(String str) {
+ return expandTabs(htmlEntites(str));
+ }
+
+ public static List normalize(List list) {
+ List result = new LinkedList();
+ for (String line: list) {
+ result.add(normalize(line));
+ }
+ return result;
+ }
+
+ public static List wrapText(List list, int columnWidth) {
+ List result = new LinkedList();
+ for (String line: list) {
+ result.add(wrapText(line, columnWidth));
+ }
+ return result;
+ }
+
+ public static String wrapText(String line, int columnWidth) {
+ if (line.length() > columnWidth) {
+ return line.subSequence(0, columnWidth) + " " + line.substring(columnWidth);
+ }
+ return line;
+ }
+}
diff --git a/src/difflib/myers/package.html b/src/difflib/myers/package.html
index eb148c7..3ccec66 100644
--- a/src/difflib/myers/package.html
+++ b/src/difflib/myers/package.html
@@ -1,58 +1,23 @@
@@ -61,8 +26,8 @@
-
- The {@link org.apache.maven.jrcs.diff.myers diff.myers} package
+
+ The {@link difflib.myers diff.myers} package
implements Gene Myers '
differencing algorithm.
@@ -71,10 +36,7 @@
Myer's algorithm produces optimum results (minimum diffs), but
consumes considerably more memory than SimpleDiff, so its not
suitable for very large files.
-
+
@author Juanco Anez
-@version $Id: package.html 60 2003-05-10 18:56:10Z juanco $
-@see Diff
-@see org.apache.maven.jrcs.rcs.Archive
diff --git a/src/difflib/package.html b/src/difflib/package.html
new file mode 100644
index 0000000..0f82244
--- /dev/null
+++ b/src/difflib/package.html
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+ The {@link difflib difflib} package
+ implements general operation with diff files.
+
+@author Dmitry Naumenko
+
+
diff --git a/test/testcase/diffutills/PatchTest.java b/test/testcase/diffutills/PatchTest.java
index 2f1dd93..6c9506b 100644
--- a/test/testcase/diffutills/PatchTest.java
+++ b/test/testcase/diffutills/PatchTest.java
@@ -1,9 +1,11 @@
package testcase.diffutills;
-import java.util.*;
+import java.util.Arrays;
+import java.util.List;
import junit.framework.TestCase;
-import difflib.*;
+import difflib.DiffUtils;
+import difflib.Patch;
public class PatchTest extends TestCase {
private List changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
@@ -17,16 +19,28 @@ public class PatchTest extends TestCase {
public void testPatch_Insert() {
Patch patch = DiffUtils.diff(insertTest_from, insertTest_to);
- assertEquals(insertTest_to, DiffUtils.patch(insertTest_from, patch));
+ try {
+ assertEquals(insertTest_to, DiffUtils.patch(insertTest_from, patch));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
}
public void testPatch_Delete() {
Patch patch = DiffUtils.diff(deleteTest_from, deleteTest_to);
- assertEquals(deleteTest_to, DiffUtils.patch(deleteTest_from, patch));
+ try {
+ assertEquals(deleteTest_to, DiffUtils.patch(deleteTest_from, patch));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
}
public void testPatch_Change() {
Patch patch = DiffUtils.diff(changeTest_from, changeTest_to);
- assertEquals(changeTest_to, DiffUtils.patch(changeTest_from, patch));
+ try {
+ assertEquals(changeTest_to, DiffUtils.patch(changeTest_from, patch));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
}
}