diff --git a/java-diff-utils/src/main/java/com/github/difflib/text/DiffRowGenerator.java b/java-diff-utils/src/main/java/com/github/difflib/text/DiffRowGenerator.java index e7e09ac..82a5b94 100644 --- a/java-diff-utils/src/main/java/com/github/difflib/text/DiffRowGenerator.java +++ b/java-diff-utils/src/main/java/com/github/difflib/text/DiffRowGenerator.java @@ -189,6 +189,8 @@ static void wrapInTag( private final Function lineNormalizer; private final Function processDiffs; private final Function>> inlineDeltaMerger; + // processor for equal (unchanged) lines + private final Function equalityProcessor; private final boolean showInlineDiffs; private final boolean replaceOriginalLinefeedInChangesWithSpaces; @@ -214,6 +216,7 @@ private DiffRowGenerator(Builder builder) { lineNormalizer = builder.lineNormalizer; processDiffs = builder.processDiffs; inlineDeltaMerger = builder.inlineDeltaMerger; + equalityProcessor = builder.equalityProcessor; replaceOriginalLinefeedInChangesWithSpaces = builder.replaceOriginalLinefeedInChangesWithSpaces; @@ -262,7 +265,8 @@ public List generateDiffRows(final List original, Patch // Copy the final matching chunk if any. for (String line : original.subList(endPos, original.size())) { - diffRows.add(buildDiffRow(Tag.EQUAL, line, line)); + String processed = processEqualities(line); + diffRows.add(buildDiffRow(Tag.EQUAL, processed, processed)); } return diffRows; } @@ -276,7 +280,8 @@ private int transformDeltaIntoDiffRow( Chunk rev = delta.getTarget(); for (String line : original.subList(endPos, orig.getPosition())) { - diffRows.add(buildDiffRow(Tag.EQUAL, line, line)); + String processed = processEqualities(line); + diffRows.add(buildDiffRow(Tag.EQUAL, processed, processed)); } switch (delta.getType()) { @@ -496,6 +501,19 @@ private String preprocessLine(String line) { } } + /** + * Hook for processing equal (unchanged) text segments. + * Delegates to the builder-configured equalityProcessor if present. + * + * @author tusharsoni52 + * @param text + * @return + * + */ + protected String processEqualities(final String text) { + return equalityProcessor != null ? equalityProcessor.apply(text) : text; + } + /** * This class used for building the DiffRowGenerator. * @@ -521,6 +539,8 @@ public static class Builder { private boolean replaceOriginalLinefeedInChangesWithSpaces = false; private Function>> inlineDeltaMerger = DEFAULT_INLINE_DELTA_MERGER; + // Processor for equalities + private Function equalityProcessor = null; private Builder() {} @@ -613,6 +633,20 @@ public Builder processDiffs(Function processDiffs) { return this; } + /** + * Processor for equal (unchanged) text parts. + * Allows applying the same escaping/transformation as for diffs. + * + * @author tusharsoni52 + * @param equalityProcessor + * @return + * + */ + public Builder processEqualities(Function equalityProcessor) { + this.equalityProcessor = equalityProcessor; + return this; + } + /** * Set the column width of generated lines of original and revised * texts. diff --git a/java-diff-utils/src/test/java/com/github/difflib/text/DiffRowGeneratorEqualitiesTest.java b/java-diff-utils/src/test/java/com/github/difflib/text/DiffRowGeneratorEqualitiesTest.java new file mode 100644 index 0000000..c71f455 --- /dev/null +++ b/java-diff-utils/src/test/java/com/github/difflib/text/DiffRowGeneratorEqualitiesTest.java @@ -0,0 +1,92 @@ +package com.github.difflib.text; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class DiffRowGeneratorEqualitiesTest { + + @Test + public void testDefaultEqualityProcessingLeavesTextUnchanged() { + DiffRowGenerator generator = + DiffRowGenerator.create().showInlineDiffs(false).build(); + + List rows = generator.generateDiffRows(Arrays.asList("hello world"), Arrays.asList("hello world")); + + assertEquals(1, rows.size()); + assertEquals("hello world", rows.get(0).getOldLine()); + assertEquals("hello world", rows.get(0).getNewLine()); + assertEquals(DiffRow.Tag.EQUAL, rows.get(0).getTag()); + } + + @Test + public void testCustomEqualityProcessingIsApplied() { + DiffRowGenerator generator = DiffRowGenerator.create() + .showInlineDiffs(false) + .processEqualities(text -> "[" + text + "]") + .build(); + + List rows = generator.generateDiffRows(Arrays.asList("A", "B"), Arrays.asList("A", "B")); + + assertEquals(2, rows.size()); + assertEquals("[A]", rows.get(0).getOldLine()); + assertEquals("[B]", rows.get(1).getOldLine()); + } + + /** + * Verifies that processEqualities can be used to HTML-escape unchanged + * lines while still working together with the default HTML-oriented + * lineNormalizer. + */ + @Test + public void testHtmlEscapingEqualitiesWorksWithDefaultNormalizer() { + DiffRowGenerator generator = DiffRowGenerator.create() + .showInlineDiffs(true) + .inlineDiffByWord(true) + .processEqualities(s -> s.replace("<", "<").replace(">", ">")) + .build(); + + // both lines are equal -> Tag.EQUAL, processEqualities is invoked + List rows = generator.generateDiffRows(Arrays.asList("hello "), Arrays.asList("hello ")); + + DiffRow row = rows.get(0); + + assertTrue(row.getOldLine().contains("<world>")); + assertTrue(row.getNewLine().contains("<world>")); + } + + /** + * Ensures equalities are processed while inline diff markup is still + * present somewhere in the line. + */ + @Test + public void testEqualitiesProcessedButInlineDiffStillPresent() { + DiffRowGenerator generator = DiffRowGenerator.create() + .showInlineDiffs(true) + .inlineDiffByWord(true) + .processEqualities(s -> "(" + s + ")") + .build(); + + List rows = generator.generateDiffRows(Arrays.asList("hello world"), Arrays.asList("hello there")); + + DiffRow row = rows.get(0); + + System.out.println("OLD = " + row.getOldLine()); + System.out.println("NEW = " + row.getNewLine()); + + // Row must be CHANGE + assertEquals(DiffRow.Tag.CHANGE, row.getTag()); + + // Inline diff markup must appear + assertTrue( + row.getOldLine().contains("span") || row.getNewLine().contains("span"), + "Expected inline diff markup in old or new line"); + + // Equalities inside CHANGE row must NOT be wrapped by processEqualities + // Option 3 does NOT modify inline equalities + assertTrue(row.getOldLine().startsWith("hello "), "Equal (unchanged) inline segment should remain unchanged"); + } +}