diff --git a/.gitignore b/.gitignore
index 8aabf2c..6c0de98 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,4 @@ target
.project
.settings
*.iml
-
+.idea
diff --git a/.idea/ant.xml b/.idea/ant.xml
deleted file mode 100644
index 6ddee46..0000000
--- a/.idea/ant.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index 5267941..0000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
deleted file mode 100644
index b385f01..0000000
--- a/.idea/copyright/profiles_settings.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
deleted file mode 100644
index 7c62b52..0000000
--- a/.idea/encodings.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/.idea/libraries/Maven__junit_junit_4_8_1.xml b/.idea/libraries/Maven__junit_junit_4_8_1.xml
deleted file mode 100644
index 21ab8f0..0000000
--- a/.idea/libraries/Maven__junit_junit_4_8_1.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 9835fae..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index fd2ff8f..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
deleted file mode 100644
index 1e7cce4..0000000
--- a/.idea/uiDesigner.xml
+++ /dev/null
@@ -1,125 +0,0 @@
-
-
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
- -
-
-
-
-
- -
-
-
- -
-
-
-
-
-
-
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index cce6fd9..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
diff --git a/README.md b/README.md
index 5d5bbcc..7b31268 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,18 @@ A fork of [java-diff-utils](https://code.google.com/p/java-diff-utils/)
# Changelog
+## 2.0.0
+
+- Change groupId and artifactId to prevent conflit with origin library: now 'com.github.java-diff-utils:java-diff-utils' instead of 'jp.skypencil.java-diff-utils:diffutils'
+- Adds the ability to differentiate the inserted and deleted tags and class-names in inline-diff
+- Default class-name is now `null` for deleted and inserted data, and "`change`" for change data
+- Default tag for deleted data is `del`
+- Default tag for inserted data is `ins`
+- can now customize diff algorithm in `DiffRowGenerator.Builder`
+- fix "equal" lines when lines isn't really equals (when Equalizer return equals on different strings)
+- fix imbrication tag bug in lineDiff (when inline is on a multi-line chunk)
+- Adds tha ability to skip data
+
## 1.5.0
- make Equalizer configurable. ([pull #1](https://github.com/eller86/java-diff-utils/pull/1))
diff --git a/pom.xml b/pom.xml
index aba4014..74bcb63 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,9 +1,9 @@
4.0.0
- jp.skypencil.java-diff-utils
- diffutils
+ com.github.java-diff-utils
+ java-diff-utils
jar
- 1.5.1-SNAPSHOT
+ 2.0.0-SNAPSHOT
java-diff-utils
The DiffUtils library for computing diffs, applying patches, generationg side-by-side view in Java.
@@ -15,9 +15,9 @@
7
- scm:git:git@github.com:eller86/java-diff-utils.git
- scm:git:git@github.com:eller86/java-diff-utils.git
- git@github.com:eller86/java-diff-utils.git
+ scm:git:git@github.com:jcronier/java-diff-utils.git
+ scm:git:git@github.com:jcronier/java-diff-utils.git
+ git@github.com:jcronier/java-diff-utils.git
@@ -31,6 +31,10 @@
andreaskumlehn
https://github.com/andreaskumlehn
+
+ JY Cr
+ https://github.com/jcronier
+
@@ -42,60 +46,48 @@
+ 1.7
UTF-8
+ ${project.build.sourceEncoding}
+ ${project.build.sourceEncoding}
+ ${maven.compiler.target}
com.google.guava
guava
- 15.0
+ 18.0
com.google.code.findbugs
jsr305
- 2.0.2
+ 3.0.0
true
org.hamcrest
hamcrest-library
- 1.2.1
+ 1.3
test
junit
junit
- 4.11
+ 4.12
test
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 2.5.1
-
- 1.7
- 1.7
- ${project.build.sourceEncoding}
-
-
-
- org.apache.maven.plugins
- maven-javadoc-plugin
- 2.9.1
-
-
maven-jar-plugin
- 2.4
+ 2.6
${project.build.outputDirectory}/META-INF/MANIFEST.MF
@@ -105,7 +97,7 @@
org.apache.felix
maven-bundle-plugin
- 2.3.7
+ 2.5.3
bundle-manifest
@@ -116,9 +108,6 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/src/main/java/difflib/DiffAlgorithm.java b/src/main/java/difflib/DiffAlgorithm.java
index 21ccd16..5a2ddea 100644
--- a/src/main/java/difflib/DiffAlgorithm.java
+++ b/src/main/java/difflib/DiffAlgorithm.java
@@ -15,7 +15,9 @@
*/
package difflib;
-import java.util.*;
+import java.util.List;
+
+import difflib.myers.Equalizer;
/**
* The general interface for computing diffs between two lists of elements of type T.
@@ -44,4 +46,10 @@ public interface DiffAlgorithm {
* @return The patch representing the diff of the given sequences. Never {@code null}.
*/
public Patch diff(List original, List revised);
+
+ /**
+ * Get equalizer use to compare data.
+ * @return
+ */
+ public Equalizer getEqualizer();
}
diff --git a/src/main/java/difflib/DiffRow.java b/src/main/java/difflib/DiffRow.java
index 59b22df..2f975f0 100644
--- a/src/main/java/difflib/DiffRow.java
+++ b/src/main/java/difflib/DiffRow.java
@@ -41,7 +41,7 @@ public DiffRow(@Nonnull Tag tag, @Nullable String oldLine, @Nullable String newL
}
public static enum Tag {
- INSERT, DELETE, CHANGE, EQUAL
+ INSERT, DELETE, CHANGE, EQUAL, SKIP
}
/**
diff --git a/src/main/java/difflib/DiffRowGenerator.java b/src/main/java/difflib/DiffRowGenerator.java
index 130aa33..0dfe346 100644
--- a/src/main/java/difflib/DiffRowGenerator.java
+++ b/src/main/java/difflib/DiffRowGenerator.java
@@ -15,10 +15,14 @@
*/
package difflib;
-import difflib.DiffRow.Tag;
-import difflib.myers.Equalizer;
-
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -27,6 +31,10 @@
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
+import difflib.DiffRow.Tag;
+import difflib.myers.Equalizer;
+import difflib.myers.MyersDiff;
+
/**
* 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
@@ -40,26 +48,50 @@
* ...
*
* 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();
+ * ignoreWhiteSpaces(true).columnWidth(100).build();
*
*
* @author Dmitry Naumenko
- */
+ */
public class DiffRowGenerator {
- private static final Joiner LF_JOINER = Joiner.on("\n");
+ private static final String NEW_LINE = "\n";
+ private static final Joiner LF_JOINER = Joiner.on(NEW_LINE);
+ private static final Joiner JOINER = Joiner.on("");
+
+ private static final String DEFAULT_TAG_DELETE = "del";
+ private static final String DEFAULT_TAG_INSERT = "ins";
+ private static final String DEFAULT_TAG_CHANGE = "span";
+ private static final String DEFAULT_CSSCLASS_DELETE = null;
+ private static final String DEFAULT_CSSCLASS_INSERT = null;
+ private static final String DEFAULT_CSSCLASS_CHANGE = "change";
+ private static final DiffAlgorithm DEFAULT_DIFFALGORITHM = new MyersDiff(new Equalizer() {
+ public boolean equals(String original, String revised) {
+ return Objects.equals(original, revised);
+ }
+
+ @Override
+ public boolean skip(String original) {
+ return false;
+ }
+ });
private final boolean showInlineDiffs;
private final boolean ignoreWhiteSpaces;
- private final String InlineOldTag;
- private final String InlineNewTag;
- private final String InlineOldCssClass;
- private final String InlineNewCssClass;
+ private final String inlineOriginDeleteTag;
+ private final String inlineRevisedInsertTag;
+ private final String inlineOriginChangeTag;
+ private final String inlineRevisedChangeTag;
+ private final String inlineOriginDeleteCssClass;
+ private final String inlineRevisedInsertCssClass;
+ private final String inlineOriginChangeCssClass;
+ private final String inlineRevisedChangeCssClass;
private final int columnWidth;
@Nullable
private final String defaultString;
- private final Equalizer equalizer;
+ private final DiffAlgorithm diffAlgorithm;
/**
* This class used for building the DiffRowGenerator.
@@ -69,18 +101,18 @@ public class DiffRowGenerator {
public static class Builder {
private boolean showInlineDiffs = false;
private boolean ignoreWhiteSpaces = false;
- private String InlineOldTag = "span";
- private String InlineNewTag = "span";
- private String InlineOldCssClass = "editOldInline";
- private String InlineNewCssClass = "editNewInline";
- private int columnWidth = 80;
+ private String inlineOriginDeleteTag = DEFAULT_TAG_DELETE;
+ private String inlineOriginChangeTag = DEFAULT_TAG_CHANGE;
+ private String inlineRevisedInsertTag = DEFAULT_TAG_INSERT;
+ private String inlineRevisedChangeTag = DEFAULT_TAG_CHANGE;
+ private String inlineOriginDeleteCssClass = DEFAULT_CSSCLASS_DELETE;
+ private String inlineRevisedInsertCssClass = DEFAULT_CSSCLASS_INSERT;
+ private String inlineOriginChangeCssClass = DEFAULT_CSSCLASS_CHANGE;
+ private String inlineRevisedChangeCssClass = DEFAULT_CSSCLASS_CHANGE;
+ private int columnWidth = -1;
@Nullable
private String defaultString = "";
- private Equalizer stringEqualizer = new Equalizer() {
- public boolean equals(String original, String revised) {
- return Objects.equals(original, revised);
- }
- };
+ private DiffAlgorithm diffAlgorithm = DEFAULT_DIFFALGORITHM;
/**
* Show inline diffs in generating diff rows or not.
@@ -104,53 +136,96 @@ public Builder ignoreWhiteSpaces(boolean val) {
/**
* 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
+ * @param tag the tag to set. Without angle brackets. Default: {@value #DEFAULT_TAG_DELETE}.
+ * @return builder with configured inlineOriginDeleteTag parameter
+ * @deprecated Use {@link #inlineOriginDeleteTag(String)}
*/
+ @Deprecated
public Builder InlineOldTag(String tag) {
- InlineOldTag = tag;
+ inlineOriginDeleteTag = tag;
+ return this;
+ }
+
+ /**
+ * Set the tag used for displaying delete data in the original text.
+ * @param tag the tag to set. Without angle brackets. Default: {@value #DEFAULT_TAG_DELETE}.
+ * @return builder with configured inlineOriginDeleteTag parameter
+ */
+ public Builder inlineOriginDeleteTag(String tag) {
+ inlineOriginDeleteTag = 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
+ * @param tag the tag to set. Without angle brackets. Default: {@value #DEFAULT_TAG_INSERT}.
+ * @return builder with configured inlineRevisedInsertTag parameter
+ * @deprecated Use {@link #inlineRevisedInsertTag(String)}
*/
public Builder InlineNewTag(String tag) {
- InlineNewTag = tag;
+ inlineRevisedInsertTag = tag;
+ return this;
+ }
+
+ /**
+ * Set the tag used for displaying changes in the revised text.
+ * @param tag the tag to set. Without angle brackets. Default: {@value #DEFAULT_TAG_INSERT}.
+ * @return builder with configured inlineRevisedInsertTag parameter
+ */
+ public Builder inlineRevisedInsertTag(String tag) {
+ inlineRevisedInsertTag = 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
+ * @param cssClass the tag to set. Without any quotes, just word. Default: {@value #DEFAULT_CSSCLASS_DELETE}.
+ * @return builder with configured inlineOriginDeleteCssClass parameter
+ * @deprecated Use {@link #inlineOriginDeleteCssClass(String)}
*/
public Builder InlineOldCssClass(String cssClass) {
- InlineOldCssClass = cssClass;
+ inlineOriginDeleteCssClass = cssClass;
+ return this;
+ }
+
+ /**
+ * Set the css class used for displaying delete data in the original text.
+ * @param cssClass the tag to set. Without any quotes, just word. Default: {@value #DEFAULT_CSSCLASS_DELETE}.
+ * @return builder with configured inlineOriginDeleteCssClass parameter
+ */
+ public Builder inlineOriginDeleteCssClass(String cssClass) {
+ inlineOriginDeleteCssClass = 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
+ * @param cssClass the tag to set. Without any quotes, just word. Default: {@value #DEFAULT_CSSCLASS_INSERT}.
+ * @return builder with configured inlineRevisedInsertCssClass parameter
+ * @deprecated Use {@link #inlineRevisedInsertCssClass(String)}
*/
public Builder InlineNewCssClass(String cssClass) {
- InlineNewCssClass = cssClass;
+ inlineRevisedInsertCssClass = cssClass;
+ return this;
+ }
+
+ /**
+ * Set the css class used for displaying insert data in the revised text.
+ * @param cssClass the tag to set. Without any quotes, just word. Default: {@value #DEFAULT_CSSCLASS_INSERT}.
+ * @return builder with configured inlineRevisedInsertCssClass parameter
+ */
+ public Builder inlineRevisedInsertCssClass(String cssClass) {
+ inlineRevisedInsertCssClass = 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
+ * @param width the width to set. Making it < 0 disable line breaking.
+ * @return builder with configured columnWidth parameter
*/
public Builder columnWidth(int width) {
- if (width > 0) {
- columnWidth = width;
- }
+ columnWidth = width;
return this;
}
@@ -166,7 +241,18 @@ public Builder defaultString(@Nullable String defaultString) {
* @return builder with configured stringEqualizer
*/
public Builder stringEqualizer(Equalizer stringEqualizer) {
- this.stringEqualizer = stringEqualizer;
+ this.diffAlgorithm = new MyersDiff<>(stringEqualizer);
+ return this;
+ }
+
+ /**
+ * Set the custom {@link DiffAlgorithm} to use while comparing the lines
+ * of the revisions.
+ * @param stringEqualizer to use (custom one)
+ * @return builder with configured stringEqualizer
+ */
+ public Builder diffAlgorithm(DiffAlgorithm diffAlgorithm) {
+ this.diffAlgorithm = diffAlgorithm;
return this;
}
@@ -182,14 +268,23 @@ public DiffRowGenerator build() {
private DiffRowGenerator(Builder builder) {
showInlineDiffs = builder.showInlineDiffs;
- ignoreWhiteSpaces = builder.ignoreWhiteSpaces; //
- InlineOldTag = builder.InlineOldTag;
- InlineNewTag = builder.InlineNewTag;
- InlineOldCssClass = builder.InlineOldCssClass;
- InlineNewCssClass = builder.InlineNewCssClass;
- columnWidth = builder.columnWidth; //
+ ignoreWhiteSpaces = builder.ignoreWhiteSpaces;
+
+ inlineOriginDeleteTag = builder.inlineOriginDeleteTag;
+ inlineOriginDeleteCssClass = builder.inlineOriginDeleteCssClass;
+
+ inlineOriginChangeTag = builder.inlineOriginChangeTag;
+ inlineOriginChangeCssClass = builder.inlineOriginChangeCssClass;
+
+ inlineRevisedInsertTag = builder.inlineRevisedInsertTag;
+ inlineRevisedInsertCssClass = builder.inlineRevisedInsertCssClass;
+
+ inlineRevisedChangeTag = builder.inlineRevisedChangeTag;
+ inlineRevisedChangeCssClass = builder.inlineRevisedChangeCssClass;
+
+ columnWidth = builder.columnWidth;
defaultString = builder.defaultString;
- equalizer = builder.stringEqualizer;
+ diffAlgorithm = builder.diffAlgorithm;
}
/**
@@ -202,7 +297,7 @@ private DiffRowGenerator(Builder builder) {
*/
public List generateDiffRows(List original, List revised) {
if (ignoreWhiteSpaces) {
- Function whiteSpaceReplacer = new Function(){
+ Function whiteSpaceReplacer = new Function() {
@Override
public String apply(String string) {
if (string == null) {
@@ -215,7 +310,7 @@ public String apply(String string) {
original = Lists.transform(original, whiteSpaceReplacer);
revised = Lists.transform(revised, whiteSpaceReplacer);
}
- return generateDiffRows(original, revised, DiffUtils.diff(original, revised, equalizer));
+ return generateDiffRows(original, revised, DiffUtils.diff(original, revised, diffAlgorithm));
}
/**
@@ -233,43 +328,58 @@ public List generateDiffRows(List original, List revise
revised = StringUtills.normalize(revised);
// wrap to the column width
- original = StringUtills.wrapText(original, this.columnWidth);
- revised = StringUtills.wrapText(revised, this.columnWidth);
-
+ if (columnWidth > 0) {
+ original = StringUtills.wrapText(original, this.columnWidth);
+ revised = StringUtills.wrapText(revised, this.columnWidth);
+ }
List diffRows = new ArrayList();
- int endPos = 0;
+ int orgEndPos = 0;
+ int revEndPos = 0;
final List> deltaList = patch.getDeltas();
+
+ Equalizer equalizer = diffAlgorithm.getEqualizer();
+
for (int i = 0; i < deltaList.size(); i++) {
Delta delta = deltaList.get(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));
+ orig.setLines(StringUtills.normalize(orig.getLines()));
+ rev.setLines(StringUtills.normalize(rev.getLines()));
- // catch the equal prefix for each chunk
- for (String line : original.subList(endPos, orig.getPosition())) {
- diffRows.add(new DiffRow(Tag.EQUAL, line, line));
+ if (columnWidth > 0) {
+ orig.setLines(StringUtills.wrapText(orig.getLines(), this.columnWidth));
+ rev.setLines(StringUtills.wrapText(rev.getLines(), this.columnWidth));
}
+ // catch the equal prefix for each chunk
+ copyEqualsLines(equalizer, diffRows, original, orgEndPos, orig.getPosition(), revised, revEndPos,
+ rev.getPosition());
// Inserted DiffRow
- if (delta.getClass().equals(InsertDelta.class)) {
- endPos = orig.last() + 1;
- for (String line : (List) rev.getLines()) {
- diffRows.add(new DiffRow(Tag.INSERT, defaultString, line));
+ if (delta.getClass() == InsertDelta.class) {
+ orgEndPos = orig.last() + 1;
+ revEndPos = rev.last() + 1;
+ for (String line : rev.getLines()) {
+ if (equalizer.skip(line)) {
+ diffRows.add(new DiffRow(Tag.SKIP, defaultString, line));
+ } else {
+ diffRows.add(new DiffRow(Tag.INSERT, defaultString, 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, defaultString));
+ if (delta.getClass() == DeleteDelta.class) {
+ orgEndPos = orig.last() + 1;
+ revEndPos = rev.last() + 1;
+ for (String line : orig.getLines()) {
+ if (equalizer.skip(line)) {
+ diffRows.add(new DiffRow(Tag.SKIP, line, defaultString));
+ } else {
+ diffRows.add(new DiffRow(Tag.DELETE, line, defaultString));
+ }
}
continue;
}
@@ -280,78 +390,113 @@ public List generateDiffRows(List original, List revise
// the changed size is match
if (orig.size() == rev.size()) {
for (int j = 0; j < orig.size(); j++) {
- diffRows.add(new DiffRow(Tag.CHANGE, (String) orig.getLines().get(j),
- (String) rev.getLines().get(j)));
+ addChangeDiffRow(equalizer, diffRows, orig.getLines().get(j), rev.getLines().get(j), defaultString);
}
} else if (orig.size() > rev.size()) {
for (int j = 0; j < orig.size(); j++) {
- diffRows.add(new DiffRow(Tag.CHANGE, (String) orig.getLines().get(j), rev
- .getLines().size() > j ? (String) rev.getLines().get(j) : defaultString));
+ final String orgLine = orig.getLines().get(j);
+ final String revLine = rev.getLines().size() > j ? rev.getLines().get(j) : defaultString;
+ addChangeDiffRow(equalizer, diffRows, orgLine, revLine, defaultString);
}
} else {
for (int j = 0; j < rev.size(); j++) {
- diffRows.add(new DiffRow(Tag.CHANGE, orig.getLines().size() > j ? (String) orig
- .getLines().get(j) : defaultString, (String) rev.getLines().get(j)));
+ final String orgLine = orig.getLines().size() > j ? orig.getLines().get(j) : defaultString;
+ final String revLine = rev.getLines().get(j);
+ addChangeDiffRow(equalizer, diffRows, orgLine, revLine, defaultString);
}
}
- endPos = orig.last() + 1;
+ orgEndPos = orig.last() + 1;
+ revEndPos = rev.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));
- }
+ copyEqualsLines(equalizer, diffRows, original, orgEndPos, original.size(), revised, revEndPos, revised.size());
return diffRows;
}
+ private static final void addChangeDiffRow(Equalizer equalizer, List diffRows, String orgLine,
+ String revLine, String defaultString) {
+ boolean skipOrg = equalizer.skip(orgLine);
+ boolean skipRev = equalizer.skip(revLine);
+ if (skipOrg && skipRev) {
+ diffRows.add(new DiffRow(Tag.SKIP, orgLine, revLine));
+ } else if (skipOrg) {
+ diffRows.add(new DiffRow(Tag.SKIP, orgLine, defaultString));
+ diffRows.add(new DiffRow(Tag.CHANGE, defaultString, revLine));
+ } else if (skipRev) {
+ diffRows.add(new DiffRow(Tag.CHANGE, orgLine, defaultString));
+ diffRows.add(new DiffRow(Tag.SKIP, defaultString, revLine));
+ } else {
+ diffRows.add(new DiffRow(Tag.CHANGE, orgLine, revLine));
+ }
+ }
+
+ protected void copyEqualsLines(Equalizer equalizer, List diffRows, List original,
+ int originalStartPos, int originalEndPos, List revised, int revisedStartPos, int revisedEndPos) {
+ String[][] lines = new String[originalEndPos - originalStartPos][2];
+ int idx = 0;
+ for (String line : original.subList(originalStartPos, originalEndPos)) {
+ lines[idx++][0] = line;
+ }
+ idx = 0;
+ for (String line : revised.subList(revisedStartPos, revisedEndPos)) {
+ lines[idx++][1] = line;
+ }
+ for (String[] line : lines) {
+ String orgLine = line[0];
+ String revLine = line[1];
+ if (equalizer.skip(orgLine) && equalizer.skip(revLine)) {
+ diffRows.add(new DiffRow(Tag.SKIP, orgLine, revLine));
+ } else {
+ diffRows.add(new DiffRow(Tag.EQUAL, orgLine, revLine));
+ }
+ }
+ }
+
/**
* Add the inline diffs for given delta
+ *
* @param delta the given delta
*/
private void addInlineDiffs(Delta delta) {
- List orig = (List) delta.getOriginal().getLines();
- List rev = (List) delta.getRevised().getLines();
- LinkedList origList = new LinkedList();
- for (Character character : LF_JOINER.join(orig).toCharArray()) {
- origList.add(character.toString());
- }
- LinkedList revList = new LinkedList();
- for (Character character : LF_JOINER.join(rev).toCharArray()) {
- revList.add(character.toString());
- }
+ List orig = delta.getOriginal().getLines();
+ List rev = delta.getRevised().getLines();
+ LinkedList origList = charArrayToStringList(LF_JOINER.join(orig).toCharArray());
+ LinkedList revList = charArrayToStringList(LF_JOINER.join(rev).toCharArray());
+
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.size() + 1, this.InlineOldTag, this.InlineOldCssClass);
- } else if (inlineDelta.getClass().equals(InsertDelta.class)) {
- revList = wrapInTag(revList, inlineRev.getPosition(), inlineRev.getPosition()
- + inlineRev.size() + 1, this.InlineNewTag, this.InlineNewCssClass);
- } else if (inlineDelta.getClass().equals(ChangeDelta.class)) {
- origList = wrapInTag(origList, inlineOrig.getPosition(), inlineOrig
- .getPosition()
- + inlineOrig.size() + 1, this.InlineOldTag, this.InlineOldCssClass);
- revList = wrapInTag(revList, inlineRev.getPosition(), inlineRev.getPosition()
- + inlineRev.size() + 1, this.InlineNewTag, this.InlineNewCssClass);
- }
- }
- StringBuilder origResult = new StringBuilder(), revResult = new StringBuilder();
- for (String character : origList) {
- origResult.append(character);
+ 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.size()
+ + 1, this.inlineOriginDeleteTag, this.inlineOriginDeleteCssClass);
+ } else if (inlineDelta.getClass().equals(InsertDelta.class)) {
+ revList = wrapInTag(revList, inlineRev.getPosition(), inlineRev.getPosition() + inlineRev.size() + 1,
+ this.inlineRevisedInsertTag, this.inlineRevisedInsertCssClass);
+ } else if (inlineDelta.getClass().equals(ChangeDelta.class)) {
+ origList = wrapInTag(origList, inlineOrig.getPosition(), inlineOrig.getPosition() + inlineOrig.size()
+ + 1, this.inlineOriginChangeTag, this.inlineOriginChangeCssClass);
+ revList = wrapInTag(revList, inlineRev.getPosition(), inlineRev.getPosition() + inlineRev.size() + 1,
+ this.inlineRevisedChangeTag, this.inlineRevisedChangeCssClass);
}
- 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")));
}
+
+ delta.getOriginal().setLines(Arrays.asList(JOINER.join(origList).split(NEW_LINE)));
+ delta.getRevised().setLines(Arrays.asList(JOINER.join(revList).split(NEW_LINE)));
}
+ private static final LinkedList charArrayToStringList(char[] cs) {
+ LinkedList result = new LinkedList();
+ for (Character character : cs) {
+ result.add(character.toString());
+ }
+ return result;
+ }
+
+ private static final Pattern PATTERN_CRLF = Pattern.compile("([\\n\\r]+)");
+
/**
* 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.
@@ -359,8 +504,8 @@ private void addInlineDiffs(Delta delta) {
* @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) {
+ 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("<");
@@ -371,17 +516,26 @@ public static LinkedList wrapInTag(LinkedList sequence, int star
tagBuilder.append("\"");
}
tagBuilder.append(">");
- String startTag = tagBuilder.toString();
+ final String startTag = tagBuilder.toString();
tagBuilder.delete(0, tagBuilder.length());
tagBuilder.append("");
tagBuilder.append(tag);
tagBuilder.append(">");
- String endTag = tagBuilder.toString();
+ final String endTag = tagBuilder.toString();
result.add(startPosition, startTag);
result.add(endPosition, endTag);
+ final String joinTag = new StringBuilder(Matcher.quoteReplacement(endTag)).append("$1")
+ .append(Matcher.quoteReplacement(startTag)).toString();
+
+ for (int i = startPosition + 1; i < endPosition; ++i) {
+ final String val = result.get(i);
+ if (val.contains("\n") || val.contains("\r")) {
+ result.set(i, PATTERN_CRLF.matcher(val).replaceAll(joinTag));
+ }
+ }
return result;
}
@@ -393,7 +547,7 @@ public static LinkedList wrapInTag(LinkedList sequence, int star
* @return the wrapped string
*/
public static String wrapInTag(String line, String tag, String cssClass) {
- StringBuilder tagBuilder = new StringBuilder();
+ final StringBuilder tagBuilder = new StringBuilder();
tagBuilder.append("<");
tagBuilder.append(tag);
if (cssClass != null) {
@@ -402,15 +556,18 @@ public static String wrapInTag(String line, String tag, String cssClass) {
tagBuilder.append("\"");
}
tagBuilder.append(">");
- String startTag = tagBuilder.toString();
+ final String startTag = tagBuilder.toString();
tagBuilder.delete(0, tagBuilder.length());
tagBuilder.append("");
tagBuilder.append(tag);
tagBuilder.append(">");
- String endTag = tagBuilder.toString();
+ final String endTag = tagBuilder.toString();
+
+ final String joinTag = new StringBuilder(Matcher.quoteReplacement(endTag)).append("$1")
+ .append(Matcher.quoteReplacement(startTag)).toString();
- return startTag + line + endTag;
+ return startTag + PATTERN_CRLF.matcher(line).replaceAll(joinTag) + endTag;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/difflib/myers/Equalizer.java b/src/main/java/difflib/myers/Equalizer.java
index bff7b65..4202ca3 100644
--- a/src/main/java/difflib/myers/Equalizer.java
+++ b/src/main/java/difflib/myers/Equalizer.java
@@ -9,13 +9,21 @@
* @param T The type of the compared elements in the 'lines'.
*/
public interface Equalizer {
-
- /**
- * Indicates if two elements are equal according to the diff mechanism.
- * @param original The original element. Must not be {@code null}.
- * @param revised The revised element. Must not be {@code null}.
- * @return Returns true if the elements are equal.
- */
+
+ /**
+ * Indicates if two elements are equal according to the diff mechanism.
+ * @param original The original element. Must not be {@code null}.
+ * @param revised The revised element. Must not be {@code null}.
+ * @return Returns true if the elements are equal.
+ */
+ @CheckReturnValue
+ public boolean equals(@Nullable T original, @Nullable T revised);
+
+ /**
+ * Indicates if elements must be skipped.
+ * @param original
+ * @return
+ */
@CheckReturnValue
- public boolean equals(@Nullable T original, @Nullable T revised);
+ public boolean skip(@Nullable T original);
}
diff --git a/src/main/java/difflib/myers/MyersDiff.java b/src/main/java/difflib/myers/MyersDiff.java
index 40be478..9cccc85 100644
--- a/src/main/java/difflib/myers/MyersDiff.java
+++ b/src/main/java/difflib/myers/MyersDiff.java
@@ -75,11 +75,21 @@
* @param T The type of the compared elements in the 'lines'.
*/
public class MyersDiff implements DiffAlgorithm {
-
- /** Default equalizer. */
- private final Equalizer DEFAULT_EQUALIZER = new Equalizer() {
+ /** Default equalizer. */
+ private final Equalizer DEFAULT_EQUALIZER = new Equalizer() {
public boolean equals(final T original, final T revised) {
- return original.equals(revised);
+ if (original == null && revised == null) {
+ return true;
+ }
+ if (original != null) {
+ return original.equals(revised);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean skip(T original) {
+ return false;
}
};
@@ -295,5 +305,8 @@ public static T[] copyOfRange2(U[] original, int from, int to,
System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength));
return copy;
}
-
-}
+
+ public Equalizer getEqualizer() {
+ return equalizer;
+ }
+}
\ No newline at end of file