Skip to content

Commit 2a1239b

Browse files
committed
fixes #117
1 parent 8d38e10 commit 2a1239b

File tree

7 files changed

+148
-47
lines changed

7 files changed

+148
-47
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ This project uses a custom versioning scheme (and not [Semantic Versioning](http
1313

1414
### Changed
1515

16-
* bugfixing on new UnifiedDiff reader / writer for multifile useage
16+
* bugfixing on new UnifiedDiff reader / writer for multifile usage
1717
* bugfix for wrong DiffRow type while transforming from a patch that removed a line in one changeset
18+
* introduced change position into UnifiedDiff reader
1819

1920
## [4.9]
2021

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@
2525
* Holds the information about the part of text involved in the diff process
2626
*
2727
* <p>
28-
* Text is represented as <code>Object[]</code> because the diff engine is capable of handling more
29-
* than plain ascci. In fact, arrays or lists of any type that implements
30-
* {@link java.lang.Object#hashCode hashCode()} and {@link java.lang.Object#equals equals()}
31-
* correctly can be subject to differencing using this library.
28+
* Text is represented as <code>Object[]</code> because the diff engine is
29+
* capable of handling more than plain ascci. In fact, arrays or lists of any
30+
* type that implements {@link java.lang.Object#hashCode hashCode()} and
31+
* {@link java.lang.Object#equals equals()} correctly can be subject to
32+
* differencing using this library.
3233
* </p>
3334
*
3435
* @author <a href="dm.naumenko@gmail.com>Dmitry Naumenko</a>
@@ -50,7 +51,7 @@ public final class Chunk<T> implements Serializable {
5051
public Chunk(int position, List<T> lines, List<Integer> changePosition) {
5152
this.position = position;
5253
this.lines = new ArrayList<>(lines);
53-
this.changePosition = changePosition;
54+
this.changePosition = changePosition != null ? new ArrayList<>(changePosition) : null;
5455
}
5556

5657
/**
@@ -73,7 +74,7 @@ public Chunk(int position, List<T> lines) {
7374
public Chunk(int position, T[] lines, List<Integer> changePosition) {
7475
this.position = position;
7576
this.lines = Arrays.asList(lines);
76-
this.changePosition = changePosition;
77+
this.changePosition = changePosition != null ? new ArrayList<>(changePosition) : null;
7778
}
7879

7980
/**
@@ -87,7 +88,8 @@ public Chunk(int position, T[] lines) {
8788
}
8889

8990
/**
90-
* Verifies that this chunk's saved text matches the corresponding text in the given sequence.
91+
* Verifies that this chunk's saved text matches the corresponding text in
92+
* the given sequence.
9193
*
9294
* @param target the sequence to verify against.
9395
* @throws com.github.difflib.patch.PatchFailedException

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,30 @@ public List<T> applyTo(List<T> target) throws PatchFailedException {
7373
throw new PatchFailedException("could not apply patch due to " + verifyChunk.toString());
7474
};
7575

76+
/**
77+
* Git like merge conflict output.
78+
*/
79+
public static final ConflictOutput<String> CONFLICT_PRODUCES_MERGE_CONFLICT = (VerifyChunk verifyChunk, AbstractDelta<String> delta, List<String> result) -> {
80+
if (result.size() > delta.getSource().getPosition()) {
81+
List<String> orgData = new ArrayList<>();
82+
83+
for (int i = 0; i < delta.getSource().size(); i++) {
84+
orgData.add(result.get(delta.getSource().getPosition()));
85+
result.remove(delta.getSource().getPosition());
86+
}
87+
88+
orgData.add(0, "<<<<<< HEAD");
89+
orgData.add("======");
90+
orgData.addAll(delta.getSource().getLines());
91+
orgData.add(">>>>>>> PATCH");
92+
93+
result.addAll(delta.getSource().getPosition(), orgData);
94+
95+
} else {
96+
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
97+
}
98+
};
99+
76100
private ConflictOutput<T> conflictOutput = CONFLICT_PRODUCES_EXCEPTION;
77101

78102
/**

java-diff-utils/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffReader.java

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public final class UnifiedDiffReader {
5353
private final UnifiedDiffLine RENAME_TO = new UnifiedDiffLine(true, "^rename\\sto\\s(.+)$", this::processRenameTo);
5454

5555
private final UnifiedDiffLine NEW_FILE_MODE = new UnifiedDiffLine(true, "^new\\sfile\\smode\\s(\\d+)", this::processNewFileMode);
56-
56+
5757
private final UnifiedDiffLine DELETED_FILE_MODE = new UnifiedDiffLine(true, "^deleted\\sfile\\smode\\s(\\d+)", this::processDeletedFileMode);
5858

5959
private final UnifiedDiffLine CHUNK = new UnifiedDiffLine(false, UNIFIED_DIFF_CHUNK_REGEXP, this::processChunk);
@@ -94,9 +94,9 @@ private UnifiedDiff parse() throws IOException, UnifiedDiffParserException {
9494
if (!CHUNK.validLine(line)) {
9595
initFileIfNecessary();
9696
while (line != null && !CHUNK.validLine(line)) {
97-
if (!processLine(line, DIFF_COMMAND, SIMILARITY_INDEX, INDEX,
98-
FROM_FILE, TO_FILE,
99-
RENAME_FROM, RENAME_TO,
97+
if (!processLine(line, DIFF_COMMAND, SIMILARITY_INDEX, INDEX,
98+
FROM_FILE, TO_FILE,
99+
RENAME_FROM, RENAME_TO,
100100
NEW_FILE_MODE, DELETED_FILE_MODE)) {
101101
throw new UnifiedDiffParserException("expected file start line not found");
102102
}
@@ -117,8 +117,8 @@ private UnifiedDiff parse() throws IOException, UnifiedDiffParserException {
117117
}
118118
}
119119
line = READER.readLine();
120-
121-
if ("\\ No newline at end of file".equals(line)) {
120+
121+
if ("\\ No newline at end of file".equals(line)) {
122122
actualFile.setNoNewLineAtTheEndOfTheFile(true);
123123
line = READER.readLine();
124124
}
@@ -153,11 +153,12 @@ static String[] parseFileNames(String line) {
153153
private static final Logger LOG = Logger.getLogger(UnifiedDiffReader.class.getName());
154154

155155
/**
156-
* To parse a diff file use this method.
156+
* To parse a diff file use this method.
157+
*
157158
* @param stream This is the diff file data.
158159
* @return In a UnifiedDiff structure this diff file data is returned.
159160
* @throws IOException
160-
* @throws UnifiedDiffParserException
161+
* @throws UnifiedDiffParserException
161162
*/
162163
public static UnifiedDiff parseUnifiedDiff(InputStream stream) throws IOException, UnifiedDiffParserException {
163164
UnifiedDiffReader parser = new UnifiedDiffReader(new BufferedReader(new InputStreamReader(stream)));
@@ -198,44 +199,58 @@ private void processDiff(MatchResult match, String line) {
198199
actualFile.setToFile(fromTo[1]);
199200
actualFile.setDiffCommand(line);
200201
}
201-
202+
202203
private void processSimilarityIndex(MatchResult match, String line) {
203204
actualFile.setSimilarityIndex(Integer.valueOf(match.group(1)));
204205
}
205206

206207
private List<String> originalTxt = new ArrayList<>();
207208
private List<String> revisedTxt = new ArrayList<>();
209+
private List<Integer> addLineIdxList = new ArrayList<>();
210+
private List<Integer> delLineIdxList = new ArrayList<>();
208211
private int old_ln;
209212
private int old_size;
210213
private int new_ln;
211214
private int new_size;
215+
private int delLineIdx = 0;
216+
private int addLineIdx = 0;
212217

213218
private void finalizeChunk() {
214219
if (!originalTxt.isEmpty() || !revisedTxt.isEmpty()) {
215220
actualFile.getPatch().addDelta(new ChangeDelta<>(new Chunk<>(
216-
old_ln - 1, originalTxt), new Chunk<>(
217-
new_ln - 1, revisedTxt)));
221+
old_ln - 1, originalTxt, delLineIdxList), new Chunk<>(
222+
new_ln - 1, revisedTxt, addLineIdxList)));
218223
old_ln = 0;
219224
new_ln = 0;
220225
originalTxt.clear();
221226
revisedTxt.clear();
227+
addLineIdxList.clear();
228+
delLineIdxList.clear();
229+
delLineIdx = 0;
230+
addLineIdx = 0;
222231
}
223232
}
224233

225234
private void processNormalLine(MatchResult match, String line) {
226235
String cline = line.substring(1);
227236
originalTxt.add(cline);
228237
revisedTxt.add(cline);
238+
delLineIdx++;
239+
addLineIdx++;
229240
}
230241

231242
private void processAddLine(MatchResult match, String line) {
232243
String cline = line.substring(1);
233244
revisedTxt.add(cline);
245+
addLineIdx++;
246+
addLineIdxList.add(new_ln - 1 + addLineIdx);
234247
}
235248

236249
private void processDelLine(MatchResult match, String line) {
237250
String cline = line.substring(1);
238251
originalTxt.add(cline);
252+
delLineIdx++;
253+
delLineIdxList.add(old_ln - 1 + delLineIdx);
239254
}
240255

241256
private void processChunk(MatchResult match, String chunkStart) {
@@ -273,7 +288,7 @@ private void processToFile(MatchResult match, String line) {
273288
actualFile.setToFile(extractFileName(line));
274289
actualFile.setToTimestamp(extractTimestamp(line));
275290
}
276-
291+
277292
private void processRenameFrom(MatchResult match, String line) {
278293
actualFile.setRenameFrom(match.group(1));
279294
}
@@ -286,7 +301,7 @@ private void processNewFileMode(MatchResult match, String line) {
286301
//initFileIfNecessary();
287302
actualFile.setNewFileMode(match.group(1));
288303
}
289-
304+
290305
private void processDeletedFileMode(MatchResult match, String line) {
291306
//initFileIfNecessary();
292307
actualFile.setDeletedFileMode(match.group(1));

java-diff-utils/src/test/java/com/github/difflib/patch/PatchTest.java

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import org.junit.jupiter.api.Test;
1515

1616
import com.github.difflib.DiffUtils;
17-
import java.util.ArrayList;
1817

1918
public class PatchTest {
2019

@@ -89,29 +88,7 @@ public void testPatch_Change_withExceptionProcessor() {
8988

9089
changeTest_from.set(2, "CDC");
9190

92-
patch.withConflictOutput(new ConflictOutput<String>() {
93-
@Override
94-
public void processConflict(VerifyChunk verifyChunk, AbstractDelta<String> delta, List<String> result) throws PatchFailedException {
95-
if (result.size() > delta.getSource().getPosition()) {
96-
List<String> orgData = new ArrayList<>();
97-
98-
for (int i = 0; i < delta.getSource().size(); i++) {
99-
orgData.add(result.get(delta.getSource().getPosition()));
100-
result.remove(delta.getSource().getPosition());
101-
}
102-
103-
orgData.add(0, "<<<<<< HEAD");
104-
orgData.add("======");
105-
orgData.addAll(delta.getSource().getLines());
106-
orgData.add(">>>>>>> PATCH");
107-
108-
result.addAll(delta.getSource().getPosition(), orgData);
109-
110-
} else {
111-
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
112-
}
113-
}
114-
});
91+
patch.withConflictOutput(Patch.CONFLICT_PRODUCES_MERGE_CONFLICT);
11592

11693
try {
11794
List<String> data = DiffUtils.patch(changeTest_from, patch);

java-diff-utils/src/test/java/com/github/difflib/unifieddiff/UnifiedDiffReaderTest.java

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,41 @@ public void testParseIssue110() throws IOException {
295295
assertThat(file.getSimilarityIndex()).isEqualTo(87);
296296
assertThat(file.getRenameFrom()).isEqualTo("service-type-database/build-db.in");
297297
assertThat(file.getRenameTo()).isEqualTo("service-type-database/build-db");
298-
298+
299299
assertThat(file.getFromFile()).isEqualTo("service-type-database/build-db.in");
300-
assertThat(file.getToFile()).isEqualTo("service-type-database/build-db");
300+
assertThat(file.getToFile()).isEqualTo("service-type-database/build-db");
301+
}
302+
303+
@Test
304+
public void testParseIssue117() throws IOException {
305+
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
306+
UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue117.diff"));
307+
308+
assertThat(diff.getFiles().size()).isEqualTo(2);
309+
310+
assertThat(diff.getFiles().get(0).getPatch().getDeltas().get(0).getSource().getChangePosition())
311+
.containsExactly(24, 27);
312+
assertThat(diff.getFiles().get(0).getPatch().getDeltas().get(0).getTarget().getChangePosition())
313+
.containsExactly(24, 27);
314+
315+
assertThat(diff.getFiles().get(0).getPatch().getDeltas().get(1).getSource().getChangePosition())
316+
.containsExactly(64);
317+
assertThat(diff.getFiles().get(0).getPatch().getDeltas().get(1).getTarget().getChangePosition())
318+
.containsExactly(64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74);
319+
320+
// diff.getFiles().forEach(f -> {
321+
// System.out.println("File: " + f.getFromFile());
322+
// f.getPatch().getDeltas().forEach(delta -> {
323+
//
324+
// System.out.println(delta);
325+
// System.out.println("Source: ");
326+
// System.out.println(delta.getSource().getPosition());
327+
// System.out.println(delta.getSource().getChangePosition());
328+
//
329+
// System.out.println("Target: ");
330+
// System.out.println(delta.getTarget().getPosition());
331+
// System.out.println(delta.getTarget().getChangePosition());
332+
// });
333+
// });
301334
}
302335
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
diff --git a/java-diff-utils/src/main/java/com/github/difflib/text/StringUtils.java b/java-diff-utils/src/main/java/com/github/difflib/text/StringUtils.java
2+
index a142548..b7e3549 100644
3+
--- a/java-diff-utils/src/main/java/com/github/difflib/text/StringUtils.java
4+
+++ b/java-diff-utils/src/main/java/com/github/difflib/text/StringUtils.java
5+
@@ -21,10 +21,10 @@
6+
final class StringUtils {
7+
8+
/**
9+
- * Replaces all opening an closing tags with <code>&lt;</code> or <code>&gt;</code>.
10+
+ * Replaces all opening and closing tags with <code>&lt;</code> or <code>&gt;</code>.
11+
*
12+
* @param str
13+
- * @return
14+
+ * @return str with some HTML meta characters escaped.
15+
*/
16+
public static String htmlEntites(String str) {
17+
return str.replace("<", "&lt;").replace(">", "&gt;");
18+
@@ -61,7 +61,17 @@ public static String wrapText(String line, int columnWidth) {
19+
StringBuilder b = new StringBuilder(line);
20+
21+
for (int count = 0; length > widthIndex; count++) {
22+
- b.insert(widthIndex + delimiter * count, "<br/>");
23+
+ int breakPoint = widthIndex + delimiter * count;
24+
+ if (Character.isHighSurrogate(b.charAt(breakPoint - 1)) &&
25+
+ Character.isLowSurrogate(b.charAt(breakPoint))) {
26+
+ // Shift a breakpoint that would split a supplemental code-point.
27+
+ breakPoint += 1;
28+
+ if (breakPoint == b.length()) {
29+
+ // Break before instead of after if this is the last code-point.
30+
+ breakPoint -= 2;
31+
+ }
32+
+ }
33+
+ b.insert(breakPoint, "<br/>");
34+
widthIndex += columnWidth;
35+
}
36+
37+
diff --git a/java-diff-utils/src/test/java/com/github/difflib/text/StringUtilsTest.java b/java-diff-utils/src/test/java/com/github/difflib/text/StringUtilsTest.java
38+
index c4b2acc..6867072 100644
39+
--- a/java-diff-utils/src/test/java/com/github/difflib/text/StringUtilsTest.java
40+
+++ b/java-diff-utils/src/test/java/com/github/difflib/text/StringUtilsTest.java
41+
@@ -49,6 +49,8 @@ public void testWrapText_String_int() {
42+
assertEquals("te<br/>st", StringUtils.wrapText("test", 2));
43+
assertEquals("tes<br/>t", StringUtils.wrapText("test", 3));
44+
assertEquals("test", StringUtils.wrapText("test", 10));
45+
+ assertEquals(".\uD800\uDC01<br/>.", StringUtils.wrapText(".\uD800\uDC01.", 2));
46+
+ assertEquals("..<br/>\uD800\uDC01", StringUtils.wrapText("..\uD800\uDC01", 3));
47+
}
48+
49+
@Test

0 commit comments

Comments
 (0)