diff --git a/README.md b/README.md index cbcba7a..924342d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Build Status](https://travis-ci.org/java-diff-utils/java-diff-utils.svg?branch=master)](https://travis-ci.org/java-diff-utils/java-diff-utils) -[![Build Status using Github Actions](https://github.com/java-diff-utils/java-diff-utils/workflows/Java%20CI%20with%20Maven/badge.svg)](https://github.com/java-diff-utils/java-diff-utils/actions?query=workflow%3A%22Java+CI+with+Maven%22) +[![Build Status using GitHub Actions](https://github.com/java-diff-utils/java-diff-utils/workflows/Java%20CI%20with%20Maven/badge.svg)](https://github.com/java-diff-utils/java-diff-utils/actions?query=workflow%3A%22Java+CI+with+Maven%22) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/002c53aa0c924f71ac80a2f65446dfdd)](https://www.codacy.com/gh/java-diff-utils/java-diff-utils/dashboard?utm_source=github.com&utm_medium=referral&utm_content=java-diff-utils/java-diff-utils&utm_campaign=Badge_Grade) @@ -12,51 +12,51 @@ ## Intro -Diff Utils library is an OpenSource library for performing the comparison operations between texts: computing diffs, applying patches, generating unified diffs or parsing them, generating diff output for easy future displaying (like side-by-side view) and so on. +Diff Utils library is an open source library for performing comparison operations between texts: computing diffs, applying patches, generating unified diffs or parsing them, generating diff output for easy future displaying (like side-by-side view) and so on. -Main reason to build this library was the lack of easy-to-use libraries with all the usual stuff you need while working with diff files. Originally it was inspired by JRCS library and it's nice design of diff module. +The main reason to build this library was the lack of easy-to-use libraries with all the usual stuff you need while working with diff files. Originally it was inspired by JRCS library and its nice design of diff module. **This is originally a fork of java-diff-utils from Google Code Archive.** ## GPG Signature Validation -The gpg singing key in [KEYS] is used for this projects artifacts. +The GPG signing key in [KEYS] is used for this project's artifacts. ## API -Javadocs of the actual release version: [JavaDocs java-diff-utils](https://java-diff-utils.github.io/java-diff-utils/4.10/docs/apidocs/) +Javadocs of the actual release version: [Javadocs java-diff-utils](https://java-diff-utils.github.io/java-diff-utils/4.10/docs/apidocs/) ## Examples -Look [here](https://github.com/java-diff-utils/java-diff-utils/wiki) to find more helpful informations and examples. +Look [here](https://github.com/java-diff-utils/java-diff-utils/wiki) to find more helpful information and examples. -These two outputs are generated using this java-diff-utils. The source code can also be found at the *Examples* page: +These two outputs are generated using java-diff-utils. The source code can also be found on the [Examples](https://github.com/java-diff-utils/java-diff-utils/wiki/Examples) page: **Producing a one liner including all difference information.** -```Java -//create a configured DiffRowGenerator +```java +// Create a configured DiffRowGenerator DiffRowGenerator generator = DiffRowGenerator.create() .showInlineDiffs(true) .mergeOriginalRevised(true) .inlineDiffByWord(true) - .oldTag(f -> "~") //introduce markdown style for strikethrough - .newTag(f -> "**") //introduce markdown style for bold + .oldTag(f -> "~") // Introduce markdown style for strikethrough + .newTag(f -> "**") // Introduce markdown style for bold .build(); -//compute the differences for two test texts. +// Compute the differences for two test texts List rows = generator.generateDiffRows( - Arrays.asList("This is a test senctence."), + Arrays.asList("This is a test sentence."), Arrays.asList("This is a test for diffutils.")); - + System.out.println(rows.get(0).getOldLine()); ``` -This is a test ~senctence~**for diffutils**. +This is a test ~sentence~**for diffutils**. -**Producing a side by side view of computed differences.** +**Producing a side-by-side view of computed differences.** -```Java +```java DiffRowGenerator generator = DiffRowGenerator.create() .showInlineDiffs(true) .inlineDiffByWord(true) @@ -64,9 +64,9 @@ DiffRowGenerator generator = DiffRowGenerator.create() .newTag(f -> "**") .build(); List rows = generator.generateDiffRows( - Arrays.asList("This is a test senctence.", "This is the second line.", "And here is the finish."), + Arrays.asList("This is a test sentence.", "This is the second line.", "And here is the finish."), Arrays.asList("This is a test for diffutils.", "This is the second line.")); - + System.out.println("|original|new|"); System.out.println("|--------|---|"); for (DiffRow row : rows) { @@ -76,33 +76,33 @@ for (DiffRow row : rows) { |original|new| |--------|---| -|This is a test ~senctence~.|This is a test **for diffutils**.| +|This is a test ~sentence~.|This is a test **for diffutils**.| |This is the second line.|This is the second line.| |~And here is the finish.~|| ## Main Features -* computing the difference between two texts. -* capable to hand more than plain ascii. Arrays or List of any type that implements hashCode() and equals() correctly can be subject to differencing using this library -* patch and unpatch the text with the given patch -* parsing the unified diff format -* producing human-readable differences -* inline difference construction +* Computing the difference between two texts. +* Capable of handling more than plain ASCII. Arrays or lists of any type that implement `hashCode()` and `equals()` correctly can be subject to differencing using this library +* Patch and unpatch the text with the given patch +* Parsing the unified diff format +* Producing human-readable differences +* Inline difference construction * Algorithms: - * Myers Standard Algorithm + * Myers standard algorithm * Myers with linear space improvement - * HistogramDiff using JGit Library + * HistogramDiff using the JGit library ### Algorithms -* Myer's diff +* Myers diff * HistogramDiff -But it can easily replaced by any other which is better for handing your texts. I have plan to add implementation of some in future. +But it can easily be replaced by any other which is better for handling your texts. I have a plan to add the implementation of some in the future. ## Source Code conventions -Recently a checkstyle process was integrated into the build process. java-diff-utils follows the sun java format convention. There are no TABs allowed. Use spaces. +Recently a checkstyle process was integrated into the build process. java-diff-utils follows the Sun Java format convention. There are no tabs allowed. Use spaces. ```java public static Patch diff(List original, List revised, @@ -123,7 +123,7 @@ This is a valid piece of source code: ### To Install -Just add the code below to your maven dependencies: +Just add the code below to your Maven dependencies: ```xml @@ -133,7 +133,7 @@ Just add the code below to your maven dependencies: ``` -or using gradle: +or using Gradle: ```groovy // https://mvnrepository.com/artifact/io.github.java-diff-utils/java-diff-utils 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"); + } +}