1616package difflib ;
1717
1818import difflib .DiffRow .Tag ;
19+ import difflib .myers .Equalizer ;
1920
2021import java .util .*;
2122
2223/**
2324 * This class for generating DiffRows for side-by-sidy view.
24- * You can customize the way of generating. For example, show inline diffs on not, ignoring
25+ * You can customize the way of generating. For example, show inline diffs on not, ignoring
2526 * white spaces or/and blank lines and so on. All parameters for generating are optional. If you do
2627 * not specify them, the class will use the default values.
27- *
28+ *
2829 * These values are:
2930 * showInlineDiffs = false;
3031 * ignoreWhiteSpaces = true;
3132 * ignoreBlankLines = true;
3233 * ...
33- *
34+ *
3435 * For instantiating the DiffRowGenerator you should use the its builder. Like in example
3536 * <code>
3637 * DiffRowGenerator generator = new DiffRowGenerator.Builder().showInlineDiffs(true).
3738 * ignoreWhiteSpaces(true).columnWidth(100).build();
3839 * </code>
39- *
40+ *
4041 * @author <a href="dm.naumenko@gmail.com">Dmitry Naumenko</a>
4142 */
4243public class DiffRowGenerator {
@@ -48,32 +49,33 @@ public class DiffRowGenerator {
4849 private final String InlineOldCssClass ;
4950 private final String InlineNewCssClass ;
5051 private final int columnWidth ;
51-
52+ private final Equalizer equalizer ;
53+
5254 /**
5355 * This class used for building the DiffRowGenerator.
5456 * @author dmitry
5557 *
5658 */
5759 public static class Builder {
5860 private boolean showInlineDiffs = false ;
59- private boolean ignoreWhiteSpaces = true ;
60- private boolean ignoreBlankLines = true ;
61+ private boolean ignoreWhiteSpaces = false ;
62+ private boolean ignoreBlankLines = false ;
6163 private String InlineOldTag = "span" ;
6264 private String InlineNewTag = "span" ;
6365 private String InlineOldCssClass = "editOldInline" ;
6466 private String InlineNewCssClass = "editNewInline" ;
6567 private int columnWidth = 80 ;
66-
68+
6769 /**
6870 * Show inline diffs in generating diff rows or not.
6971 * @param val the value to set. Default: false.
70- * @return builder with configured showInlineDiff parameter
72+ * @return builder with configured showInlineDiff parameter
7173 */
7274 public Builder showInlineDiffs (boolean val ) {
7375 showInlineDiffs = val ;
7476 return this ;
7577 }
76-
78+
7779 /**
7880 * Ignore white spaces in generating diff rows or not.
7981 * @param val the value to set. Default: true.
@@ -83,7 +85,7 @@ public Builder ignoreWhiteSpaces(boolean val) {
8385 ignoreWhiteSpaces = val ;
8486 return this ;
8587 }
86-
88+
8789 /**
8890 * Ignore blank lines in generating diff rows or not.
8991 * @param val the value to set. Default: true.
@@ -93,7 +95,7 @@ public Builder ignoreBlankLines(boolean val) {
9395 ignoreBlankLines = val ;
9496 return this ;
9597 }
96-
98+
9799 /**
98100 * Set the tag used for displaying changes in the original text.
99101 * @param tag the tag to set. Without angle brackets. Default: span.
@@ -103,7 +105,7 @@ public Builder InlineOldTag(String tag) {
103105 InlineOldTag = tag ;
104106 return this ;
105107 }
106-
108+
107109 /**
108110 * Set the tag used for displaying changes in the revised text.
109111 * @param tag the tag to set. Without angle brackets. Default: span.
@@ -113,7 +115,7 @@ public Builder InlineNewTag(String tag) {
113115 InlineNewTag = tag ;
114116 return this ;
115117 }
116-
118+
117119 /**
118120 * Set the css class used for displaying changes in the original text.
119121 * @param cssClass the tag to set. Without any quotes, just word. Default: editOldInline.
@@ -123,7 +125,7 @@ public Builder InlineOldCssClass(String cssClass) {
123125 InlineOldCssClass = cssClass ;
124126 return this ;
125127 }
126-
128+
127129 /**
128130 * Set the css class used for displaying changes in the revised text.
129131 * @param cssClass the tag to set. Without any quotes, just word. Default: editNewInline.
@@ -133,7 +135,7 @@ public Builder InlineNewCssClass(String cssClass) {
133135 InlineNewCssClass = cssClass ;
134136 return this ;
135137 }
136-
138+
137139 /**
138140 * Set the column with of generated lines of original and revised texts.
139141 * @param width the width to set. Making it < 0 doesn't have any sense. Default 80.
@@ -145,7 +147,7 @@ public Builder columnWidth(int width) {
145147 }
146148 return this ;
147149 }
148-
150+
149151 /**
150152 * Build the DiffRowGenerator. If some parameters is not set, the default values are used.
151153 * @return the customized DiffRowGenerator
@@ -154,7 +156,7 @@ public DiffRowGenerator build() {
154156 return new DiffRowGenerator (this );
155157 }
156158 }
157-
159+
158160 private DiffRowGenerator (Builder builder ) {
159161 showInlineDiffs = builder .showInlineDiffs ;
160162 ignoreWhiteSpaces = builder .ignoreWhiteSpaces ; //
@@ -164,59 +166,79 @@ private DiffRowGenerator(Builder builder) {
164166 InlineOldCssClass = builder .InlineOldCssClass ;
165167 InlineNewCssClass = builder .InlineNewCssClass ;
166168 columnWidth = builder .columnWidth ; //
169+ equalizer = new Equalizer () {
170+ public boolean equals (Object original , Object revised ) {
171+ if (ignoreWhiteSpaces ) {
172+ original = ((String )original ).trim ().replaceAll ("\\ s+" , " " );
173+ revised = ((String )revised ).trim ().replaceAll ("\\ s+" , " " );
174+ }
175+ return original .equals (revised );
176+ }
177+ };
167178 }
168-
179+
169180 /**
170181 * Get the DiffRows describing the difference between original and revised texts using the
171182 * given patch. Useful for displaying side-by-side diff.
172- *
183+ *
173184 * @param original the original text
174- * @param revised the revised text
185+ * @param revised the revised text
175186 * @return the DiffRows between original and revised texts
176187 */
177188 public List <DiffRow > generateDiffRows (List <String > original , List <String > revised ) {
178- return generateDiffRows (original , revised , DiffUtils .diff (original , revised ));
189+ return generateDiffRows (original , revised , DiffUtils .diff (original , revised , equalizer ));
190+ }
191+
192+ private List <String > removeBlankLines (List <String > lines ) {
193+ List <String > result = new ArrayList <String >();
194+ for (String line : lines ) {
195+ if (line .trim ().length () == 0 ) {
196+ result .add ("" );
197+ }
198+ result .add (line );
199+ }
200+ return result ;
179201 }
180-
202+
181203 /**
182204 * Generates the DiffRows describing the difference between original and revised texts using the
183205 * given patch. Useful for displaying side-by-side diff.
184- *
206+ *
185207 * @param original the original text
186208 * @param revised the revised text
187- * @param patch the given patch
209+ * @param patch the given patch
188210 * @return the DiffRows between original and revised texts
189211 */
190212 @ SuppressWarnings ("unchecked" )
191213 public List <DiffRow > generateDiffRows (List <String > original , List <String > revised , Patch patch ) {
192214 // normalize the lines (expand tabs, escape html entities)
193215 original = StringUtills .normalize (original );
194216 revised = StringUtills .normalize (revised );
195-
217+
196218 // wrap to the column width
197219 original = StringUtills .wrapText (original , this .columnWidth );
198220 revised = StringUtills .wrapText (revised , this .columnWidth );
199-
221+
200222 List <DiffRow > diffRows = new ArrayList <DiffRow >();
201223 int endPos = 0 ;
202224 final List <Delta > deltaList = patch .getDeltas ();
203225 for (int i = 0 ; i < deltaList .size (); i ++) {
204226 Delta delta = deltaList .get (i );
205227 Chunk orig = delta .getOriginal ();
206228 Chunk rev = delta .getRevised ();
207-
229+
208230 // We should normalize and wrap lines in deltas too.
209231 orig .setLines (StringUtills .normalize ((List <String >) orig .getLines ()));
210232 rev .setLines (StringUtills .normalize ((List <String >) rev .getLines ()));
211-
233+
212234 orig .setLines (StringUtills .wrapText ((List <String >) orig .getLines (), this .columnWidth ));
213235 rev .setLines (StringUtills .wrapText ((List <String >) rev .getLines (), this .columnWidth ));
214-
236+
215237 // catch the equal prefix for each chunk
216238 for (String line : original .subList (endPos , orig .getPosition ())) {
217239 diffRows .add (new DiffRow (Tag .EQUAL , line , line ));
218240 }
219-
241+
220242 // Inserted DiffRow
221243 if (delta .getClass ().equals (InsertDelta .class )) {
222244 endPos = orig .last () + 1 ;
@@ -225,7 +247,7 @@ public List<DiffRow> generateDiffRows(List<String> original, List<String> revise
225247 }
226248 continue ;
227249 }
228-
250+
229251 // Deleted DiffRow
230252 if (delta .getClass ().equals (DeleteDelta .class )) {
231253 endPos = orig .last () + 1 ;
@@ -234,7 +256,7 @@ public List<DiffRow> generateDiffRows(List<String> original, List<String> revise
234256 }
235257 continue ;
236258 }
237-
259+
238260 if (showInlineDiffs ) {
239261 addInlineDiffs (delta );
240262 }
@@ -257,14 +279,14 @@ public List<DiffRow> generateDiffRows(List<String> original, List<String> revise
257279 }
258280 endPos = orig .last () + 1 ;
259281 }
260-
282+
261283 // Copy the final matching chunk if any.
262284 for (String line : original .subList (endPos , original .size ())) {
263285 diffRows .add (new DiffRow (Tag .EQUAL , line , line ));
264286 }
265287 return diffRows ;
266288 }
267-
289+
268290 /**
269291 * Add the inline diffs for given delta
270292 * @param delta the given delta
@@ -313,12 +335,12 @@ private void addInlineDiffs(Delta delta) {
313335 delta .getRevised ().setLines (Arrays .asList (revResult .toString ().split ("\n " )));
314336 }
315337 }
316-
338+
317339 /**
318340 * Wrap the elements in the sequence with the given tag
319341 * @param startPosition the position from which tag should start. The counting start from a zero.
320- * @param endPosition the position before which tag should should be closed.
321- * @param tag the tag name without angle brackets, just a word
342+ * @param endPosition the position before which tag should should be closed.
343+ * @param tag the tag name without angle brackets, just a word
322344 * @param cssClass the optional css class
323345 */
324346 public static LinkedList <String > wrapInTag (LinkedList <String > sequence , int startPosition ,
@@ -334,23 +356,23 @@ public static LinkedList<String> wrapInTag(LinkedList<String> sequence, int star
334356 }
335357 tagBuilder .append (">" );
336358 String startTag = tagBuilder .toString ();
337-
359+
338360 tagBuilder .delete (0 , tagBuilder .length ());
339-
361+
340362 tagBuilder .append ("</" );
341363 tagBuilder .append (tag );
342364 tagBuilder .append (">" );
343365 String endTag = tagBuilder .toString ();
344-
366+
345367 result .add (startPosition , startTag );
346368 result .add (endPosition , endTag );
347369 return result ;
348370 }
349-
371+
350372 /**
351373 * Wrap the given line with the given tag
352374 * @param line the given line
353- * @param tag the tag name without angle brackets, just a word
375+ * @param tag the tag name without angle brackets, just a word
354376 * @param cssClass the optional css class
355377 * @return the wrapped string
356378 */
@@ -365,17 +387,17 @@ public static String wrapInTag(String line, String tag, String cssClass) {
365387 }
366388 tagBuilder .append (">" );
367389 String startTag = tagBuilder .toString ();
368-
390+
369391 tagBuilder .delete (0 , tagBuilder .length ());
370-
392+
371393 tagBuilder .append ("</" );
372394 tagBuilder .append (tag );
373395 tagBuilder .append (">" );
374396 String endTag = tagBuilder .toString ();
375-
397+
376398 return startTag + line + endTag ;
377399 }
378-
400+
379401 /**
380402 * The helper method for joining collections
381403 * @param <T>
0 commit comments