Skip to content

Commit f0fc883

Browse files
committed
first try of implementing issue #42
1 parent 11b3c53 commit f0fc883

File tree

4 files changed

+146
-24
lines changed

4 files changed

+146
-24
lines changed

java-diff-utils/src/main/java/com/github/difflib/DiffUtils.java

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,41 +34,49 @@
3434
public final class DiffUtils {
3535

3636
/**
37-
* Computes the difference between the original and revised list of elements with default diff algorithm
37+
* Computes the difference between the original and revised list of elements with default diff
38+
* algorithm
3839
*
3940
* @param <T> types to be diffed
4041
* @param original The original text. Must not be {@code null}.
4142
* @param revised The revised text. Must not be {@code null}.
4243
* @param progress progress listener
43-
* @return The patch describing the difference between the original and revised sequences. Never {@code null}.
44+
* @return The patch describing the difference between the original and revised sequences. Never
45+
* {@code null}.
4446
*/
4547
public static <T> Patch<T> diff(List<T> original, List<T> revised, DiffAlgorithmListener progress) {
4648
return DiffUtils.diff(original, revised, new MyersDiff<>(), progress);
4749
}
48-
50+
4951
public static <T> Patch<T> diff(List<T> original, List<T> revised) {
5052
return DiffUtils.diff(original, revised, new MyersDiff<>(), null);
5153
}
54+
55+
public static <T> Patch<T> diff(List<T> original, List<T> revised, boolean includeEqualParts) {
56+
return DiffUtils.diff(original, revised, new MyersDiff<>(), null, includeEqualParts);
57+
}
5258

5359
/**
5460
* Computes the difference between the original and revised text.
5561
*/
5662
public static Patch<String> diff(String sourceText, String targetText,
5763
DiffAlgorithmListener progress) {
5864
return DiffUtils.diff(
59-
Arrays.asList(sourceText.split("\n")),
60-
Arrays.asList(targetText.split("\n")), progress);
65+
Arrays.asList(sourceText.split("\n")),
66+
Arrays.asList(targetText.split("\n")), progress);
6167
}
6268

6369
/**
64-
* Computes the difference between the original and revised list of elements with default diff algorithm
70+
* Computes the difference between the original and revised list of elements with default diff
71+
* algorithm
6572
*
6673
* @param source The original text. Must not be {@code null}.
6774
* @param target The revised text. Must not be {@code null}.
6875
*
69-
* @param equalizer the equalizer object to replace the default compare algorithm (Object.equals). If {@code null}
70-
* the default equalizer of the default algorithm is used..
71-
* @return The patch describing the difference between the original and revised sequences. Never {@code null}.
76+
* @param equalizer the equalizer object to replace the default compare algorithm
77+
* (Object.equals). If {@code null} the default equalizer of the default algorithm is used..
78+
* @return The patch describing the difference between the original and revised sequences. Never
79+
* {@code null}.
7280
*/
7381
public static <T> Patch<T> diff(List<T> source, List<T> target,
7482
BiPredicate<T, T> equalizer) {
@@ -79,40 +87,51 @@ public static <T> Patch<T> diff(List<T> source, List<T> target,
7987
return DiffUtils.diff(source, target, new MyersDiff<>());
8088
}
8189

90+
public static <T> Patch<T> diff(List<T> original, List<T> revised,
91+
DiffAlgorithmI<T> algorithm, DiffAlgorithmListener progress) {
92+
return diff(original, revised, algorithm, progress, false);
93+
}
94+
8295
/**
83-
* Computes the difference between the original and revised list of elements with default diff algorithm
96+
* Computes the difference between the original and revised list of elements with default diff
97+
* algorithm
8498
*
8599
* @param original The original text. Must not be {@code null}.
86100
* @param revised The revised text. Must not be {@code null}.
87101
* @param algorithm The diff algorithm. Must not be {@code null}.
88102
* @param progress The diff algorithm listener.
89-
* @return The patch describing the difference between the original and revised sequences. Never {@code null}.
103+
* @param includeEqualParts Include equal data parts into the patch.
104+
* @return The patch describing the difference between the original and revised sequences. Never
105+
* {@code null}.
90106
*/
91107
public static <T> Patch<T> diff(List<T> original, List<T> revised,
92-
DiffAlgorithmI<T> algorithm, DiffAlgorithmListener progress) {
108+
DiffAlgorithmI<T> algorithm, DiffAlgorithmListener progress,
109+
boolean includeEqualParts) {
93110
Objects.requireNonNull(original, "original must not be null");
94111
Objects.requireNonNull(revised, "revised must not be null");
95112
Objects.requireNonNull(algorithm, "algorithm must not be null");
96113

97-
return Patch.generate(original, revised, algorithm.computeDiff(original, revised, progress));
114+
return Patch.generate(original, revised, algorithm.computeDiff(original, revised, progress), includeEqualParts);
98115
}
99-
116+
100117
/**
101-
* Computes the difference between the original and revised list of elements with default diff algorithm
118+
* Computes the difference between the original and revised list of elements with default diff
119+
* algorithm
102120
*
103121
* @param original The original text. Must not be {@code null}.
104122
* @param revised The revised text. Must not be {@code null}.
105123
* @param algorithm The diff algorithm. Must not be {@code null}.
106-
* @return The patch describing the difference between the original and revised sequences. Never {@code null}.
124+
* @return The patch describing the difference between the original and revised sequences. Never
125+
* {@code null}.
107126
*/
108-
public static <T> Patch<T> diff(List<T> original, List<T> revised,
109-
DiffAlgorithmI<T> algorithm) {
110-
return diff(original, revised, algorithm, null);
111-
}
127+
public static <T> Patch<T> diff(List<T> original, List<T> revised, DiffAlgorithmI<T> algorithm) {
128+
return diff(original, revised, algorithm, null);
129+
}
112130

113131
/**
114-
* Computes the difference between the given texts inline. This one uses the "trick" to make out of texts lists of
115-
* characters, like DiffRowGenerator does and merges those changes at the end together again.
132+
* Computes the difference between the given texts inline. This one uses the "trick" to make out
133+
* of texts lists of characters, like DiffRowGenerator does and merges those changes at the end
134+
* together again.
116135
*
117136
* @param original
118137
* @param revised
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2020 java-diff-utils.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.github.difflib.patch;
17+
18+
import java.util.List;
19+
20+
/**
21+
* This delta contains equal lines of data. Therefore nothing is to do in applyTo and restore.
22+
* @author tobens
23+
*/
24+
public class EqualDelta<T> extends AbstractDelta<T> {
25+
26+
public EqualDelta(Chunk<T> source, Chunk<T> target) {
27+
super(DeltaType.EQUAL, source, target);
28+
}
29+
30+
@Override
31+
public void applyTo(List<T> target) throws PatchFailedException {
32+
verifyChunk(target);
33+
}
34+
35+
@Override
36+
public void restore(List<T> target) {
37+
}
38+
39+
@Override
40+
public String toString() {
41+
return "[EqualDelta, position: " + getSource().getPosition() + ", lines: "
42+
+ getSource().getLines() + "]";
43+
}
44+
}

java-diff-utils/src/main/java/com/github/difflib/patch/Patch.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,27 @@ public String toString() {
100100
}
101101

102102
public static <T> Patch<T> generate(List<T> original, List<T> revised, List<Change> changes) {
103+
return generate(original, revised, changes, false);
104+
}
105+
106+
private static <T> Chunk<T> buildChunk(int start, int end, List<T> data) {
107+
return new Chunk<>(start, new ArrayList<>(data.subList(start, end)));
108+
}
109+
110+
public static <T> Patch<T> generate(List<T> original, List<T> revised, List<Change> changes, boolean includeEquals) {
103111
Patch<T> patch = new Patch<>(changes.size());
112+
int startOriginal = 0;
113+
int startRevised = 0;
104114
for (Change change : changes) {
105-
Chunk<T> orgChunk = new Chunk<>(change.startOriginal, new ArrayList<>(original.subList(change.startOriginal, change.endOriginal)));
106-
Chunk<T> revChunk = new Chunk<>(change.startRevised, new ArrayList<>(revised.subList(change.startRevised, change.endRevised)));
115+
116+
if (includeEquals && startOriginal < change.startOriginal) {
117+
patch.addDelta(new EqualDelta(
118+
buildChunk(startOriginal, change.startOriginal, original),
119+
buildChunk(startRevised, change.startRevised, revised)));
120+
}
121+
122+
Chunk<T> orgChunk = buildChunk(change.startOriginal, change.endOriginal, original);
123+
Chunk<T> revChunk = buildChunk(change.startRevised, change.endRevised, revised);
107124
switch (change.deltaType) {
108125
case DELETE:
109126
patch.addDelta(new DeleteDelta<>(orgChunk, revChunk));
@@ -115,7 +132,17 @@ public static <T> Patch<T> generate(List<T> original, List<T> revised, List<Chan
115132
patch.addDelta(new ChangeDelta<>(orgChunk, revChunk));
116133
break;
117134
}
135+
136+
startOriginal = change.endOriginal + 1;
137+
startRevised = change.endRevised + 1;
118138
}
139+
140+
if (includeEquals && startOriginal < original.size()) {
141+
patch.addDelta(new EqualDelta(
142+
buildChunk(startOriginal, original.size(), original),
143+
buildChunk(startRevised, revised.size(), revised)));
144+
}
145+
119146
return patch;
120147
}
121148
}

java-diff-utils/src/test/java/com/github/difflib/DiffUtilsTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.github.difflib.patch.Chunk;
55
import com.github.difflib.patch.DeleteDelta;
66
import com.github.difflib.patch.AbstractDelta;
7+
import com.github.difflib.patch.EqualDelta;
78
import com.github.difflib.patch.InsertDelta;
89
import com.github.difflib.patch.Patch;
910
import java.io.BufferedReader;
@@ -159,4 +160,35 @@ public void testDiffMyersExample1() {
159160
assertEquals(4, patch.getDeltas().size());
160161
assertEquals("Patch{deltas=[[DeleteDelta, position: 0, lines: [A, B]], [InsertDelta, position: 3, lines: [B]], [DeleteDelta, position: 5, lines: [B]], [InsertDelta, position: 7, lines: [C]]]}", patch.toString());
161162
}
163+
164+
@Test
165+
public void testDiff_Equal() {
166+
final Patch<String> patch = DiffUtils.diff(
167+
Arrays.asList("hhh", "jjj", "kkk"),
168+
Arrays.asList("hhh", "jjj", "kkk"), true);
169+
assertNotNull(patch);
170+
assertEquals(1, patch.getDeltas().size());
171+
final AbstractDelta<String> delta = patch.getDeltas().get(0);
172+
assertTrue(delta instanceof EqualDelta);
173+
assertEquals(new Chunk<>(0, Arrays.asList("hhh", "jjj", "kkk")), delta.getSource());
174+
assertEquals(new Chunk<>(0, Arrays.asList("hhh", "jjj", "kkk")), delta.getTarget());
175+
}
176+
177+
@Test
178+
public void testDiff_InsertWithEqual() {
179+
final Patch<String> patch = DiffUtils.diff(Arrays.asList("hhh"), Arrays.
180+
asList("hhh", "jjj", "kkk"), true);
181+
assertNotNull(patch);
182+
assertEquals(2, patch.getDeltas().size());
183+
184+
AbstractDelta<String> delta = patch.getDeltas().get(0);
185+
assertTrue(delta instanceof EqualDelta);
186+
assertEquals(new Chunk<>(0, Arrays.asList("hhh")), delta.getSource());
187+
assertEquals(new Chunk<>(0, Arrays.asList("hhh")), delta.getTarget());
188+
189+
delta = patch.getDeltas().get(1);
190+
assertTrue(delta instanceof InsertDelta);
191+
assertEquals(new Chunk<>(1, Collections.<String>emptyList()), delta.getSource());
192+
assertEquals(new Chunk<>(1, Arrays.asList("jjj", "kkk")), delta.getTarget());
193+
}
162194
}

0 commit comments

Comments
 (0)