1717
1818import com .github .difflib .DiffUtils ;
1919import com .github .difflib .patch .AbstractDelta ;
20+ import com .github .difflib .patch .ChangeDelta ;
2021import com .github .difflib .patch .Chunk ;
22+ import com .github .difflib .patch .DeleteDelta ;
2123import com .github .difflib .patch .DeltaType ;
24+ import com .github .difflib .patch .InsertDelta ;
2225import com .github .difflib .patch .Patch ;
2326import com .github .difflib .text .DiffRow .Tag ;
2427import java .util .*;
3033import static java .util .stream .Collectors .toList ;
3134
3235/**
33- * This class for generating DiffRows for side-by-sidy view. You can customize the way of
34- * generating. For example, show inline diffs on not, ignoring white spaces or/and blank lines and
35- * so on. All parameters for generating are optional. If you do not specify them, the class will use
36- * the default values.
36+ * This class for generating DiffRows for side-by-sidy view. You can customize
37+ * the way of generating. For example, show inline diffs on not, ignoring white
38+ * spaces or/and blank lines and so on. All parameters for generating are
39+ * optional. If you do not specify them, the class will use the default values.
3740 *
38- * These values are: showInlineDiffs = false; ignoreWhiteSpaces = true; ignoreBlankLines = true; ...
41+ * These values are: showInlineDiffs = false; ignoreWhiteSpaces = true;
42+ * ignoreBlankLines = true; ...
3943 *
40- * For instantiating the DiffRowGenerator you should use the its builder. Like in example <code>
44+ * For instantiating the DiffRowGenerator you should use the its builder. Like
45+ * in example <code>
4146 * DiffRowGenerator generator = new DiffRowGenerator.Builder().showInlineDiffs(true).
4247 * ignoreWhiteSpaces(true).columnWidth(100).build();
4348 * </code>
@@ -100,8 +105,8 @@ protected final static List<String> splitStringPreserveDelimiter(String str, Pat
100105 /**
101106 * Wrap the elements in the sequence with the given tag
102107 *
103- * @param startPosition the position from which tag should start. The counting start from a
104- * zero.
108+ * @param startPosition the position from which tag should start. The
109+ * counting start from a zero.
105110 * @param endPosition the position before which tag should should be closed.
106111 * @param tagGenerator the tag generator
107112 */
@@ -187,16 +192,16 @@ private DiffRowGenerator(Builder builder) {
187192 reportLinesUnchanged = builder .reportLinesUnchanged ;
188193 lineNormalizer = builder .lineNormalizer ;
189194 processDiffs = builder .processDiffs ;
190-
195+
191196 replaceOriginalLinefeedInChangesWithSpaces = builder .replaceOriginalLinefeedInChangesWithSpaces ;
192197
193198 Objects .requireNonNull (inlineDiffSplitter );
194199 Objects .requireNonNull (lineNormalizer );
195200 }
196201
197202 /**
198- * Get the DiffRows describing the difference between original and revised texts using the given
199- * patch. Useful for displaying side-by-side diff.
203+ * Get the DiffRows describing the difference between original and revised
204+ * texts using the given patch. Useful for displaying side-by-side diff.
200205 *
201206 * @param original the original text
202207 * @param revised the revised text
@@ -207,8 +212,9 @@ public List<DiffRow> generateDiffRows(List<String> original, List<String> revise
207212 }
208213
209214 /**
210- * Generates the DiffRows describing the difference between original and revised texts using the
211- * given patch. Useful for displaying side-by-side diff.
215+ * Generates the DiffRows describing the difference between original and
216+ * revised texts using the given patch. Useful for displaying side-by-side
217+ * diff.
212218 *
213219 * @param original the original text
214220 * @param patch the given patch
@@ -218,6 +224,9 @@ public List<DiffRow> generateDiffRows(final List<String> original, Patch<String>
218224 List <DiffRow > diffRows = new ArrayList <>();
219225 int endPos = 0 ;
220226 final List <AbstractDelta <String >> deltaList = patch .getDeltas ();
227+
228+ decompressDeltas (deltaList );
229+
221230 for (AbstractDelta <String > delta : deltaList ) {
222231 Chunk <String > orig = delta .getSource ();
223232 Chunk <String > rev = delta .getTarget ();
@@ -263,6 +272,44 @@ public List<DiffRow> generateDiffRows(final List<String> original, Patch<String>
263272 return diffRows ;
264273 }
265274
275+ /**
276+ * Decompresses ChangeDeltas with different source and target size to a ChangeDelta with same size and
277+ * a following InsertDelta or DeleteDelta. With this problems of building DiffRows getting smaller.
278+ * @param deltaList
279+ */
280+ private void decompressDeltas (final List <AbstractDelta <String >> deltaList ) {
281+ for (int idx = 0 ; idx < deltaList .size (); idx ++) {
282+ AbstractDelta <String > delta = deltaList .get (idx );
283+ if (delta .getType () == DeltaType .CHANGE && delta .getSource ().size () != delta .getTarget ().size ()) {
284+ //System.out.println("decompress this " + delta);
285+
286+ List <AbstractDelta <String >> corrected = new ArrayList <>();
287+ int minSize = Math .min (delta .getSource ().size (), delta .getTarget ().size ());
288+ Chunk <String > orig = delta .getSource ();
289+ Chunk <String > rev = delta .getTarget ();
290+
291+ deltaList .set (idx , new ChangeDelta <String >(
292+ new Chunk <>(orig .getPosition (), orig .getLines ().subList (0 , minSize )),
293+ new Chunk <>(rev .getPosition (), rev .getLines ().subList (0 , minSize ))));
294+
295+ if (orig .getLines ().size () < rev .getLines ().size ()) {
296+ deltaList .add (idx + 1 , new InsertDelta <String >(
297+ new Chunk <>(orig .getPosition () + minSize , Collections .emptyList ()),
298+ new Chunk <>(rev .getPosition () + minSize , rev .getLines ().subList (minSize , rev .getLines ().size ()))));
299+ } else {
300+ deltaList .add (idx + 1 , new DeleteDelta <String >(
301+ new Chunk <>(orig .getPosition () + minSize , orig .getLines ().subList (minSize , orig .getLines ().size ())),
302+ new Chunk <>(rev .getPosition () + minSize , Collections .emptyList ())));
303+ }
304+
305+ //System.out.println(" to " + corrected);
306+ }
307+ idx ++;
308+ }
309+
310+ //System.out.println("got now " + deltaList);
311+ }
312+
266313 private DiffRow buildDiffRow (Tag type , String orgline , String newline ) {
267314 if (reportLinesUnchanged ) {
268315 return new DiffRow (type , orgline , newline );
@@ -436,8 +483,8 @@ public Builder ignoreWhiteSpaces(boolean val) {
436483 }
437484
438485 /**
439- * Give the originial old and new text lines to Diffrow without any additional processing
440- * and without any tags to highlight the change.
486+ * Give the originial old and new text lines to Diffrow without any
487+ * additional processing and without any tags to highlight the change.
441488 *
442489 * @param val the value to set. Default: false.
443490 * @return builder with configured reportLinesUnWrapped parameter
@@ -492,8 +539,8 @@ public Builder newTag(Function<Boolean, String> generator) {
492539 }
493540
494541 /**
495- * Processor for diffed text parts. Here e.g. whitecharacters could be replaced by something
496- * visible.
542+ * Processor for diffed text parts. Here e.g. whitecharacters could be
543+ * replaced by something visible.
497544 *
498545 * @param processDiffs
499546 * @return
@@ -504,10 +551,11 @@ public Builder processDiffs(Function<String, String> processDiffs) {
504551 }
505552
506553 /**
507- * Set the column width of generated lines of original and revised texts.
554+ * Set the column width of generated lines of original and revised
555+ * texts.
508556 *
509- * @param width the width to set. Making it < 0 doesn't make any sense. Default 80.
510- * @return builder with config of column width
557+ * @param width the width to set. Making it < 0 doesn't make any sense.
558+ * Default 80. @return builder with config of column width
511559 */
512560 public Builder columnWidth (int width ) {
513561 if (width >= 0 ) {
@@ -517,7 +565,8 @@ public Builder columnWidth(int width) {
517565 }
518566
519567 /**
520- * Build the DiffRowGenerator. If some parameters is not set, the default values are used.
568+ * Build the DiffRowGenerator. If some parameters is not set, the
569+ * default values are used.
521570 *
522571 * @return the customized DiffRowGenerator
523572 */
@@ -526,8 +575,8 @@ public DiffRowGenerator build() {
526575 }
527576
528577 /**
529- * Merge the complete result within the original text. This makes sense for one line
530- * display.
578+ * Merge the complete result within the original text. This makes sense
579+ * for one line display.
531580 *
532581 * @param mergeOriginalRevised
533582 * @return
@@ -538,9 +587,9 @@ public Builder mergeOriginalRevised(boolean mergeOriginalRevised) {
538587 }
539588
540589 /**
541- * Per default each character is separatly processed. This variant introduces processing by
542- * word, which does not deliver in word changes. Therefore the whole word will be tagged as
543- * changed:
590+ * Per default each character is separatly processed. This variant
591+ * introduces processing by word, which does not deliver in word
592+ * changes. Therefore the whole word will be tagged as changed:
544593 *
545594 * <pre>
546595 * false: (aBa : aba) -- changed: a(B)a : a(b)a
@@ -553,8 +602,9 @@ public Builder inlineDiffByWord(boolean inlineDiffByWord) {
553602 }
554603
555604 /**
556- * To provide some customized splitting a splitter can be provided. Here someone could think
557- * about sentence splitter, comma splitter or stuff like that.
605+ * To provide some customized splitting a splitter can be provided. Here
606+ * someone could think about sentence splitter, comma splitter or stuff
607+ * like that.
558608 *
559609 * @param inlineDiffSplitter
560610 * @return
@@ -565,9 +615,10 @@ public Builder inlineDiffBySplitter(Function<String, List<String>> inlineDiffSpl
565615 }
566616
567617 /**
568- * By default DiffRowGenerator preprocesses lines for HTML output. Tabs and special HTML
569- * characters like "<" are replaced with its encoded value. To change this you can
570- * provide a customized line normalizer here.
618+ * By default DiffRowGenerator preprocesses lines for HTML output. Tabs
619+ * and special HTML characters like "<" are replaced with its encoded
620+ * value. To change this you can provide a customized line normalizer
621+ * here.
571622 *
572623 * @param lineNormalizer
573624 * @return
@@ -587,13 +638,14 @@ public Builder equalizer(BiPredicate<String, String> equalizer) {
587638 this .equalizer = equalizer ;
588639 return this ;
589640 }
590-
641+
591642 /**
592- * Sometimes it happens that a change contains multiple lines. If there is no correspondence
593- * in old and new. To keep the merged line more readable the linefeeds could be replaced
594- * by spaces.
643+ * Sometimes it happens that a change contains multiple lines. If there
644+ * is no correspondence in old and new. To keep the merged line more
645+ * readable the linefeeds could be replaced by spaces.
646+ *
595647 * @param replace
596- * @return
648+ * @return
597649 */
598650 public Builder replaceOriginalLinefeedInChangesWithSpaces (boolean replace ) {
599651 this .replaceOriginalLinefeedInChangesWithSpaces = replace ;
0 commit comments