1515 */
1616package com .github .difflib .text ;
1717
18- import static java .util .stream .Collectors .toList ;
19-
2018import com .github .difflib .DiffUtils ;
2119import com .github .difflib .patch .AbstractDelta ;
22- import com .github .difflib .patch .ChangeDelta ;
2320import 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 ;
2721import com .github .difflib .patch .Patch ;
2822import com .github .difflib .text .DiffRow .Tag ;
2923import 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