Skip to content

Commit f42ef36

Browse files
committed
Resolved god class DifffRowGenerator.java into DeltaCompressor, InlineDiffAnnotator, InlineDiffAnnonatorConfig, InlineTagRender.java
1 parent 8e66487 commit f42ef36

5 files changed

Lines changed: 398 additions & 229 deletions

File tree

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.github.difflib.text;
2+
3+
import com.github.difflib.patch.AbstractDelta;
4+
import com.github.difflib.patch.ChangeDelta;
5+
import com.github.difflib.patch.Chunk;
6+
import com.github.difflib.patch.DeleteDelta;
7+
import com.github.difflib.patch.DeltaType;
8+
import com.github.difflib.patch.InsertDelta;
9+
import java.util.ArrayList;
10+
import java.util.Collections;
11+
import java.util.List;
12+
13+
/**
14+
* Utility that normalises asymmetric {@link ChangeDelta}s into equal-size pairs
15+
* so that DiffRow building stays simple.
16+
*
17+
* <p>When a CHANGE delta has a different number of source and target lines it is
18+
* split into a same-size {@link ChangeDelta} followed by either an {@link InsertDelta}
19+
* or a {@link DeleteDelta} for the surplus lines.
20+
*/
21+
public final class DeltaDecompressor {
22+
23+
private DeltaDecompressor() {}
24+
25+
/**
26+
* Decompresses a {@link ChangeDelta} whose source and target sizes differ into
27+
* a same-size {@link ChangeDelta} plus a trailing {@link InsertDelta} or
28+
* {@link DeleteDelta}. All other delta types are returned unchanged in a
29+
* singleton list.
30+
*
31+
* @param delta the delta to (possibly) decompress. Must not be {@code null}.
32+
* @return a list containing the original delta, or the two replacement deltas.
33+
*/
34+
public static List<AbstractDelta<String>> decompress(AbstractDelta<String> delta) {
35+
if (delta.getType() == DeltaType.CHANGE
36+
&& delta.getSource().size() != delta.getTarget().size()) {
37+
List<AbstractDelta<String>> deltas = new ArrayList<>();
38+
39+
int minSize = Math.min(delta.getSource().size(), delta.getTarget().size());
40+
Chunk<String> orig = delta.getSource();
41+
Chunk<String> rev = delta.getTarget();
42+
43+
deltas.add(new ChangeDelta<String>(
44+
new Chunk<>(orig.getPosition(), orig.getLines().subList(0, minSize)),
45+
new Chunk<>(rev.getPosition(), rev.getLines().subList(0, minSize))));
46+
47+
if (orig.getLines().size() < rev.getLines().size()) {
48+
deltas.add(new InsertDelta<String>(
49+
new Chunk<>(orig.getPosition() + minSize, Collections.emptyList()),
50+
new Chunk<>(
51+
rev.getPosition() + minSize,
52+
rev.getLines().subList(minSize, rev.getLines().size()))));
53+
} else {
54+
deltas.add(new DeleteDelta<String>(
55+
new Chunk<>(
56+
orig.getPosition() + minSize,
57+
orig.getLines().subList(minSize, orig.getLines().size())),
58+
new Chunk<>(rev.getPosition() + minSize, Collections.emptyList())));
59+
}
60+
return deltas;
61+
}
62+
63+
return Collections.singletonList(delta);
64+
}
65+
}

java-diff-utils/src/main/java/com/github/difflib/text/DiffRowGenerator.java

Lines changed: 28 additions & 229 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,9 @@
1515
*/
1616
package com.github.difflib.text;
1717

18-
import static java.util.stream.Collectors.toList;
19-
2018
import com.github.difflib.DiffUtils;
2119
import com.github.difflib.patch.AbstractDelta;
22-
import com.github.difflib.patch.ChangeDelta;
2320
import com.github.difflib.patch.Chunk;
24-
import com.github.difflib.patch.DeleteDelta;
25-
import com.github.difflib.patch.DeltaType;
26-
import com.github.difflib.patch.InsertDelta;
2721
import com.github.difflib.patch.Patch;
2822
import com.github.difflib.text.DiffRow.Tag;
2923
import com.github.difflib.text.deltamerge.DeltaMergeUtils;
@@ -117,67 +111,6 @@ protected static final List<String> splitStringPreserveDelimiter(String str, Pat
117111
return list;
118112
}
119113

120-
/**
121-
* Wrap the elements in the sequence with the given tag
122-
*
123-
* @param startPosition the position from which tag should start. The
124-
* counting start from a zero.
125-
* @param endPosition the position before which tag should should be closed.
126-
* @param tagGenerator the tag generator
127-
*/
128-
static void wrapInTag(
129-
List<String> sequence,
130-
int startPosition,
131-
int endPosition,
132-
Tag tag,
133-
BiFunction<Tag, Boolean, String> tagGenerator,
134-
Function<String, String> processDiffs,
135-
boolean replaceLinefeedWithSpace) {
136-
int endPos = endPosition;
137-
138-
while (endPos >= startPosition) {
139-
140-
// search position for end tag
141-
while (endPos > startPosition) {
142-
if (!"\n".equals(sequence.get(endPos - 1))) {
143-
break;
144-
} else if (replaceLinefeedWithSpace) {
145-
sequence.set(endPos - 1, " ");
146-
break;
147-
}
148-
endPos--;
149-
}
150-
151-
if (endPos == startPosition) {
152-
break;
153-
}
154-
155-
sequence.add(endPos, tagGenerator.apply(tag, false));
156-
if (processDiffs != null) {
157-
sequence.set(endPos - 1, processDiffs.apply(sequence.get(endPos - 1)));
158-
}
159-
endPos--;
160-
161-
// search position for end tag
162-
while (endPos > startPosition) {
163-
if ("\n".equals(sequence.get(endPos - 1))) {
164-
if (replaceLinefeedWithSpace) {
165-
sequence.set(endPos - 1, " ");
166-
} else {
167-
break;
168-
}
169-
}
170-
if (processDiffs != null) {
171-
sequence.set(endPos - 1, processDiffs.apply(sequence.get(endPos - 1)));
172-
}
173-
endPos--;
174-
}
175-
176-
sequence.add(endPos, tagGenerator.apply(tag, true));
177-
endPos--;
178-
}
179-
}
180-
181114
private final int columnWidth;
182115
private final BiPredicate<String, String> equalizer;
183116
private final boolean ignoreWhiteSpaces;
@@ -196,6 +129,9 @@ static void wrapInTag(
196129
private final boolean replaceOriginalLinefeedInChangesWithSpaces;
197130
private final boolean decompressDeltas;
198131

132+
/** Pre-built config object passed to {@link InlineDiffAnnotator} for each changed delta. */
133+
private final InlineDiffAnnotatorConfig annotatorConfig;
134+
199135
private DiffRowGenerator(Builder builder) {
200136
showInlineDiffs = builder.showInlineDiffs;
201137
ignoreWhiteSpaces = builder.ignoreWhiteSpaces;
@@ -223,6 +159,29 @@ private DiffRowGenerator(Builder builder) {
223159
Objects.requireNonNull(inlineDiffSplitter);
224160
Objects.requireNonNull(lineNormalizer);
225161
Objects.requireNonNull(inlineDeltaMerger);
162+
163+
annotatorConfig = new InlineDiffAnnotatorConfig(
164+
reportLinesUnchanged,
165+
lineNormalizer,
166+
inlineDiffSplitter,
167+
equalizer,
168+
inlineDeltaMerger,
169+
oldTag,
170+
newTag,
171+
processDiffs,
172+
mergeOriginalRevised,
173+
replaceOriginalLinefeedInChangesWithSpaces,
174+
columnWidth);
175+
}
176+
177+
/**
178+
* Applies the configured line normalizer to each line, unless
179+
* {@code reportLinesUnchanged} is set. Package-visible for testing.
180+
*/
181+
List<String> normalizeLines(List<String> list) {
182+
return reportLinesUnchanged
183+
? list
184+
: list.stream().map(lineNormalizer::apply).collect(java.util.stream.Collectors.toList());
226185
}
227186

228187
/**
@@ -253,7 +212,7 @@ public List<DiffRow> generateDiffRows(final List<String> original, Patch<String>
253212

254213
if (decompressDeltas) {
255214
for (AbstractDelta<String> originalDelta : deltaList) {
256-
for (AbstractDelta<String> delta : decompressDeltas(originalDelta)) {
215+
for (AbstractDelta<String> delta : DeltaDecompressor.decompress(originalDelta)) {
257216
endPos = transformDeltaIntoDiffRow(original, endPos, diffRows, delta);
258217
}
259218
}
@@ -297,7 +256,7 @@ private int transformDeltaIntoDiffRow(
297256
break;
298257
default:
299258
if (showInlineDiffs) {
300-
diffRows.addAll(generateInlineDiffs(delta));
259+
diffRows.addAll(InlineDiffAnnotator.annotate(delta, annotatorConfig));
301260
} else {
302261
for (int j = 0; j < Math.max(orig.size(), rev.size()); j++) {
303262
diffRows.add(buildDiffRow(
@@ -311,46 +270,6 @@ private int transformDeltaIntoDiffRow(
311270
return orig.last() + 1;
312271
}
313272

314-
/**
315-
* Decompresses ChangeDeltas with different source and target size to a
316-
* ChangeDelta with same size and a following InsertDelta or DeleteDelta.
317-
* With this problems of building DiffRows getting smaller.
318-
*
319-
* @param deltaList
320-
*/
321-
private List<AbstractDelta<String>> decompressDeltas(AbstractDelta<String> delta) {
322-
if (delta.getType() == DeltaType.CHANGE
323-
&& delta.getSource().size() != delta.getTarget().size()) {
324-
List<AbstractDelta<String>> deltas = new ArrayList<>();
325-
// System.out.println("decompress this " + delta);
326-
327-
int minSize = Math.min(delta.getSource().size(), delta.getTarget().size());
328-
Chunk<String> orig = delta.getSource();
329-
Chunk<String> rev = delta.getTarget();
330-
331-
deltas.add(new ChangeDelta<String>(
332-
new Chunk<>(orig.getPosition(), orig.getLines().subList(0, minSize)),
333-
new Chunk<>(rev.getPosition(), rev.getLines().subList(0, minSize))));
334-
335-
if (orig.getLines().size() < rev.getLines().size()) {
336-
deltas.add(new InsertDelta<String>(
337-
new Chunk<>(orig.getPosition() + minSize, Collections.emptyList()),
338-
new Chunk<>(
339-
rev.getPosition() + minSize,
340-
rev.getLines().subList(minSize, rev.getLines().size()))));
341-
} else {
342-
deltas.add(new DeleteDelta<String>(
343-
new Chunk<>(
344-
orig.getPosition() + minSize,
345-
orig.getLines().subList(minSize, orig.getLines().size())),
346-
new Chunk<>(rev.getPosition() + minSize, Collections.emptyList())));
347-
}
348-
return deltas;
349-
}
350-
351-
return Collections.singletonList(delta);
352-
}
353-
354273
private DiffRow buildDiffRow(Tag type, String orgline, String newline) {
355274
if (reportLinesUnchanged) {
356275
return new DiffRow(type, orgline, newline);
@@ -373,126 +292,6 @@ private DiffRow buildDiffRow(Tag type, String orgline, String newline) {
373292
}
374293
}
375294

376-
private DiffRow buildDiffRowWithoutNormalizing(Tag type, String orgline, String newline) {
377-
return new DiffRow(
378-
type, StringUtils.wrapText(orgline, columnWidth), StringUtils.wrapText(newline, columnWidth));
379-
}
380-
381-
List<String> normalizeLines(List<String> list) {
382-
return reportLinesUnchanged
383-
? list
384-
: list.stream().map(lineNormalizer::apply).collect(toList());
385-
}
386-
387-
/**
388-
* Add the inline diffs for given delta
389-
*
390-
* @param delta the given delta
391-
*/
392-
private List<DiffRow> generateInlineDiffs(AbstractDelta<String> delta) {
393-
List<String> orig = normalizeLines(delta.getSource().getLines());
394-
List<String> rev = normalizeLines(delta.getTarget().getLines());
395-
List<String> origList;
396-
List<String> revList;
397-
String joinedOrig = String.join("\n", orig);
398-
String joinedRev = String.join("\n", rev);
399-
400-
origList = inlineDiffSplitter.apply(joinedOrig);
401-
revList = inlineDiffSplitter.apply(joinedRev);
402-
403-
List<AbstractDelta<String>> originalInlineDeltas =
404-
DiffUtils.diff(origList, revList, equalizer).getDeltas();
405-
List<AbstractDelta<String>> inlineDeltas =
406-
inlineDeltaMerger.apply(new InlineDeltaMergeInfo(originalInlineDeltas, origList, revList));
407-
408-
Collections.reverse(inlineDeltas);
409-
for (AbstractDelta<String> inlineDelta : inlineDeltas) {
410-
Chunk<String> inlineOrig = inlineDelta.getSource();
411-
Chunk<String> inlineRev = inlineDelta.getTarget();
412-
if (inlineDelta.getType() == DeltaType.DELETE) {
413-
wrapInTag(
414-
origList,
415-
inlineOrig.getPosition(),
416-
inlineOrig.getPosition() + inlineOrig.size(),
417-
Tag.DELETE,
418-
oldTag,
419-
processDiffs,
420-
replaceOriginalLinefeedInChangesWithSpaces && mergeOriginalRevised);
421-
} else if (inlineDelta.getType() == DeltaType.INSERT) {
422-
if (mergeOriginalRevised) {
423-
origList.addAll(
424-
inlineOrig.getPosition(),
425-
revList.subList(inlineRev.getPosition(), inlineRev.getPosition() + inlineRev.size()));
426-
wrapInTag(
427-
origList,
428-
inlineOrig.getPosition(),
429-
inlineOrig.getPosition() + inlineRev.size(),
430-
Tag.INSERT,
431-
newTag,
432-
processDiffs,
433-
false);
434-
} else {
435-
wrapInTag(
436-
revList,
437-
inlineRev.getPosition(),
438-
inlineRev.getPosition() + inlineRev.size(),
439-
Tag.INSERT,
440-
newTag,
441-
processDiffs,
442-
false);
443-
}
444-
} else if (inlineDelta.getType() == DeltaType.CHANGE) {
445-
if (mergeOriginalRevised) {
446-
origList.addAll(
447-
inlineOrig.getPosition() + inlineOrig.size(),
448-
revList.subList(inlineRev.getPosition(), inlineRev.getPosition() + inlineRev.size()));
449-
wrapInTag(
450-
origList,
451-
inlineOrig.getPosition() + inlineOrig.size(),
452-
inlineOrig.getPosition() + inlineOrig.size() + inlineRev.size(),
453-
Tag.CHANGE,
454-
newTag,
455-
processDiffs,
456-
false);
457-
} else {
458-
wrapInTag(
459-
revList,
460-
inlineRev.getPosition(),
461-
inlineRev.getPosition() + inlineRev.size(),
462-
Tag.CHANGE,
463-
newTag,
464-
processDiffs,
465-
false);
466-
}
467-
wrapInTag(
468-
origList,
469-
inlineOrig.getPosition(),
470-
inlineOrig.getPosition() + inlineOrig.size(),
471-
Tag.CHANGE,
472-
oldTag,
473-
processDiffs,
474-
replaceOriginalLinefeedInChangesWithSpaces && mergeOriginalRevised);
475-
}
476-
}
477-
StringBuilder origResult = new StringBuilder();
478-
StringBuilder revResult = new StringBuilder();
479-
for (String character : origList) {
480-
origResult.append(character);
481-
}
482-
for (String character : revList) {
483-
revResult.append(character);
484-
}
485-
486-
List<String> original = Arrays.asList(origResult.toString().split("\n"));
487-
List<String> revised = Arrays.asList(revResult.toString().split("\n"));
488-
List<DiffRow> diffRows = new ArrayList<>();
489-
for (int j = 0; j < Math.max(original.size(), revised.size()); j++) {
490-
diffRows.add(buildDiffRowWithoutNormalizing(
491-
Tag.CHANGE, original.size() > j ? original.get(j) : "", revised.size() > j ? revised.get(j) : ""));
492-
}
493-
return diffRows;
494-
}
495-
496295
private String preprocessLine(String line) {
497296
if (columnWidth == 0) {
498297
return lineNormalizer.apply(line);

0 commit comments

Comments
 (0)