Skip to content

Commit ecd834f

Browse files
committed
1 parent 8c6679e commit ecd834f

File tree

3 files changed

+182
-11
lines changed

3 files changed

+182
-11
lines changed

src/main/java/com/github/difflib/patch/Chunk.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package com.github.difflib.patch;
1717

18+
import java.util.ArrayList;
1819
import java.util.Arrays;
1920
import java.util.List;
2021
import java.util.Objects;
@@ -23,9 +24,10 @@
2324
* Holds the information about the part of text involved in the diff process
2425
*
2526
* <p>
26-
* Text is represented as <code>Object[]</code> because the diff engine is capable of handling more than plain ascci. In
27-
* fact, arrays or lists of any type that implements {@link java.lang.Object#hashCode hashCode()} and
28-
* {@link java.lang.Object#equals equals()} correctly can be subject to differencing using this library.
27+
* Text is represented as <code>Object[]</code> because the diff engine is capable of handling more
28+
* than plain ascci. In fact, arrays or lists of any type that implements
29+
* {@link java.lang.Object#hashCode hashCode()} and {@link java.lang.Object#equals equals()}
30+
* correctly can be subject to differencing using this library.
2931
* </p>
3032
*
3133
* @author <a href="dm.naumenko@gmail.com>Dmitry Naumenko</a>
@@ -44,7 +46,7 @@ public final class Chunk<T> {
4446
*/
4547
public Chunk(int position, List<T> lines) {
4648
this.position = position;
47-
this.lines = lines;
49+
this.lines = new ArrayList<>(lines);
4850
}
4951

5052
/**

src/main/java/com/github/difflib/unifieddiff/UnifiedDiffWriter.java

Lines changed: 155 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,187 @@
1515
*/
1616
package com.github.difflib.unifieddiff;
1717

18+
import com.github.difflib.patch.AbstractDelta;
1819
import java.io.IOException;
1920
import java.io.Writer;
21+
import java.util.ArrayList;
22+
import java.util.List;
23+
import java.util.function.Consumer;
24+
import java.util.logging.Level;
25+
import java.util.logging.Logger;
2026

2127
/**
2228
*
2329
* @author Tobias Warneke (t.warneke@gmx.net)
2430
*/
2531
public class UnifiedDiffWriter {
2632

33+
private static final Logger LOG = Logger.getLogger(UnifiedDiffWriter.class.getName());
34+
2735
public static void write(UnifiedDiff diff, Writer writer) throws IOException {
28-
writer.write(diff.getHeader());
36+
write(diff, line -> {
37+
try {
38+
writer.append(line).append("\n");
39+
} catch (IOException ex) {
40+
LOG.log(Level.SEVERE, null, ex);
41+
}
42+
});
43+
}
44+
45+
public static void write(UnifiedDiff diff, Consumer<String> writer) throws IOException {
46+
writer.accept(diff.getHeader());
2947

3048
for (UnifiedDiffFile file : diff.getFiles()) {
3149
writeOrNothing(writer, file.getDiffCommand());
3250
if (file.getIndex() != null) {
33-
writer.write("index " + file.getIndex() + "\n");
51+
writer.accept("index " + file.getIndex());
3452
}
3553
if (file.getFromFile() != null) {
36-
writer.write("--- " + file.getFromFile() + "\n");
54+
writer.accept("--- " + file.getFromFile());
3755
}
3856
if (file.getToFile() != null) {
39-
writer.write("+++ " + file.getToFile() + "\n");
57+
writer.accept("+++ " + file.getToFile());
4058
}
4159

60+
List<AbstractDelta<String>> patchDeltas = new ArrayList<>(
61+
file.getPatch().getDeltas());
62+
63+
List<AbstractDelta<String>> deltas = new ArrayList<>();
64+
65+
int contextSize = 0;
66+
List<String> originalLines = new ArrayList<>();
67+
68+
AbstractDelta<String> delta = patchDeltas.get(0);
69+
deltas.add(delta); // add the first Delta to the current set
70+
// if there's more than 1 Delta, we may need to output them together
71+
if (patchDeltas.size() > 1) {
72+
for (int i = 1; i < patchDeltas.size(); i++) {
73+
int position = delta.getSource().getPosition();
74+
75+
// Check if the next Delta is too close to the current
76+
// position.
77+
// And if it is, add it to the current set
78+
AbstractDelta<String> nextDelta = patchDeltas.get(i);
79+
if ((position + delta.getSource().size() + contextSize) >= (nextDelta
80+
.getSource().getPosition() - contextSize)) {
81+
deltas.add(nextDelta);
82+
} else {
83+
// if it isn't, output the current set,
84+
// then create a new set and add the current Delta to
85+
// it.
86+
processDeltas(writer, originalLines, deltas, contextSize);
87+
deltas.clear();
88+
deltas.add(nextDelta);
89+
}
90+
delta = nextDelta;
91+
}
92+
93+
}
94+
// don't forget to process the last set of Deltas
95+
processDeltas(writer, originalLines, deltas, contextSize);
96+
4297
}
4398
if (diff.getTail() != null) {
44-
writer.write("--\n" + diff.getTail());
99+
writer.accept("--");
100+
writer.accept(diff.getTail());
101+
}
102+
}
103+
104+
private static void processDeltas(Consumer<String> writer,
105+
List<String> origLines,
106+
List<AbstractDelta<String>> deltas, int contextSize) {
107+
List<String> buffer = new ArrayList<>();
108+
int origTotal = 0; // counter for total lines output from Original
109+
int revTotal = 0; // counter for total lines output from Original
110+
int line;
111+
112+
AbstractDelta<String> curDelta = deltas.get(0);
113+
114+
// NOTE: +1 to overcome the 0-offset Position
115+
int origStart = curDelta.getSource().getPosition() + 1 - contextSize;
116+
if (origStart < 1) {
117+
origStart = 1;
118+
}
119+
120+
int revStart = curDelta.getTarget().getPosition() + 1 - contextSize;
121+
if (revStart < 1) {
122+
revStart = 1;
123+
}
124+
125+
// find the start of the wrapper context code
126+
int contextStart = curDelta.getSource().getPosition() - contextSize;
127+
if (contextStart < 0) {
128+
contextStart = 0; // clamp to the start of the file
129+
}
130+
131+
// output the context before the first Delta
132+
for (line = contextStart; line < curDelta.getSource().getPosition(); line++) { //
133+
buffer.add(" " + origLines.get(line));
134+
origTotal++;
135+
revTotal++;
136+
}
137+
138+
// output the first Delta
139+
getDeltaText(txt -> buffer.add(txt), curDelta);
140+
origTotal += curDelta.getSource().getLines().size();
141+
revTotal += curDelta.getTarget().getLines().size();
142+
143+
int deltaIndex = 1;
144+
while (deltaIndex < deltas.size()) { // for each of the other Deltas
145+
AbstractDelta<String> nextDelta = deltas.get(deltaIndex);
146+
int intermediateStart = curDelta.getSource().getPosition()
147+
+ curDelta.getSource().getLines().size();
148+
for (line = intermediateStart; line < nextDelta.getSource()
149+
.getPosition(); line++) {
150+
// output the code between the last Delta and this one
151+
buffer.add(" " + origLines.get(line));
152+
origTotal++;
153+
revTotal++;
154+
}
155+
getDeltaText(txt -> buffer.add(txt), nextDelta); // output the Delta
156+
origTotal += nextDelta.getSource().getLines().size();
157+
revTotal += nextDelta.getTarget().getLines().size();
158+
curDelta = nextDelta;
159+
deltaIndex++;
160+
}
161+
162+
// Now output the post-Delta context code, clamping the end of the file
163+
contextStart = curDelta.getSource().getPosition()
164+
+ curDelta.getSource().getLines().size();
165+
for (line = contextStart; (line < (contextStart + contextSize))
166+
&& (line < origLines.size()); line++) {
167+
buffer.add(" " + origLines.get(line));
168+
origTotal++;
169+
revTotal++;
170+
}
171+
172+
// Create and insert the block header, conforming to the Unified Diff
173+
// standard
174+
writer.accept("@@ -" + origStart + "," + origTotal + " +" + revStart + "," + revTotal + " @@");
175+
buffer.forEach(txt -> {
176+
writer.accept(txt);
177+
});
178+
}
179+
180+
/**
181+
* getDeltaText returns the lines to be added to the Unified Diff text from the Delta parameter
182+
*
183+
* @param delta - the Delta to output
184+
* @return list of String lines of code.
185+
* @author Bill James (tankerbay@gmail.com)
186+
*/
187+
private static void getDeltaText(Consumer<String> writer, AbstractDelta<String> delta) {
188+
for (String line : delta.getSource().getLines()) {
189+
writer.accept("-" + line);
190+
}
191+
for (String line : delta.getTarget().getLines()) {
192+
writer.accept("+" + line);
45193
}
46194
}
47195

48-
private static void writeOrNothing(Writer writer, String str) throws IOException {
196+
private static void writeOrNothing(Consumer<String> writer, String str) throws IOException {
49197
if (str != null) {
50-
writer.append(str).append("\n");
198+
writer.accept(str);
51199
}
52200
}
53201
}

src/test/java/com/github/difflib/unifieddiff/UnifiedDiffReaderTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package com.github.difflib.unifieddiff;
1717

18+
import com.github.difflib.patch.AbstractDelta;
1819
import java.io.IOException;
1920
import java.util.regex.Matcher;
2021
import java.util.regex.Pattern;
@@ -71,4 +72,24 @@ public void testChunkHeaderParsing2() {
7172
assertEquals("189", matcher.group(3));
7273
}
7374

75+
@Test
76+
public void testSimpleParse2() throws IOException {
77+
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(UnifiedDiffReaderTest.class.getResourceAsStream("jsqlparser_patch_1.diff"));
78+
79+
System.out.println(diff);
80+
81+
assertThat(diff.getFiles().size()).isEqualTo(2);
82+
83+
UnifiedDiffFile file1 = diff.getFiles().get(0);
84+
assertThat(file1.getFromFile()).isEqualTo("src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt");
85+
assertThat(file1.getPatch().getDeltas().size()).isEqualTo(3);
86+
87+
AbstractDelta<String> first = file1.getPatch().getDeltas().get(0);
88+
89+
assertThat(first.getSource().size()).isGreaterThan(0);
90+
assertThat(first.getTarget().size()).isGreaterThan(0);
91+
92+
assertThat(diff.getTail()).isEqualTo("2.17.1.windows.2\n\n");
93+
}
94+
7495
}

0 commit comments

Comments
 (0)