4747 * </code>
4848 */
4949public class DiffRowGenerator {
50+
5051public static final Pattern SPLIT_BY_WORD_PATTERN =Pattern .compile ("\\ s+|[,.\\ [\\ ](){}/\\ \\ *+\\ -#]" );
51-
52+
5253public static final BiPredicate <String ,String >IGNORE_WHITESPACE_EQUALIZER = (original ,revised )
5354 ->original .trim ().replaceAll ("\\ s+" ," " ).equals (revised .trim ().replaceAll ("\\ s+" ," " ));
54-
55+
5556public static final BiPredicate <String ,String >DEFAULT_EQUALIZER =Object ::equals ;
56-
57+
5758/**
5859 * Splitting lines by word to achieve word by word diff checking.
5960 */
@@ -69,7 +70,7 @@ public class DiffRowGenerator {
6970 }
7071return list ;
7172 };
72-
73+
7374private final boolean showInlineDiffs ;
7475private final boolean ignoreWhiteSpaces ;
7576private final Function <Boolean ,String >oldTag ;
@@ -195,11 +196,10 @@ public Builder mergeOriginalRevised(boolean mergeOriginalRevised) {
195196 * deliver no in word changes.
196197 */
197198public Builder inlineDiffByWord (boolean inlineDiffByWord ) {
198- inlineDiffSplitter =inlineDiffByWord ? SPLITTER_BY_WORD : SPLITTER_BY_CHARACTER ;
199+ inlineDiffSplitter =inlineDiffByWord ? SPLITTER_BY_WORD : SPLITTER_BY_CHARACTER ;
199200return this ;
200201 }
201-
202-
202+
203203public Builder inlineDiffBySplitter (Function <String ,List <String >>inlineDiffSplitter ) {
204204this .inlineDiffSplitter =inlineDiffSplitter ;
205205return this ;
@@ -220,7 +220,7 @@ private DiffRowGenerator(Builder builder) {
220220inlineDiffSplitter =builder .inlineDiffSplitter ;
221221equalizer =ignoreWhiteSpaces ?IGNORE_WHITESPACE_EQUALIZER :DEFAULT_EQUALIZER ;
222222reportLinesUnchanged =builder .reportLinesUnchanged ;
223-
223+
224224Objects .requireNonNull (inlineDiffSplitter );
225225 }
226226
@@ -356,32 +356,32 @@ private List<DiffRow> generateInlineDiffs(AbstractDelta<String> delta) throws Di
356356if (inlineDelta instanceof DeleteDelta ) {
357357wrapInTag (origList ,inlineOrig .getPosition (),inlineOrig
358358 .getPosition ()
359- +inlineOrig .size () + 1 ,oldTag );
359+ +inlineOrig .size (),oldTag );
360360 }else if (inlineDelta instanceof InsertDelta ) {
361361if (mergeOriginalRevised ) {
362362origList .addAll (inlineOrig .getPosition (),
363363revList .subList (inlineRev .getPosition (),inlineRev .getPosition ()
364364 +inlineRev .size ()));
365365wrapInTag (origList ,inlineOrig .getPosition (),inlineOrig .getPosition ()
366- +inlineRev .size () + 1 ,newTag );
366+ +inlineRev .size (),newTag );
367367 }else {
368368wrapInTag (revList ,inlineRev .getPosition (),inlineRev .getPosition ()
369- +inlineRev .size () + 1 ,newTag );
369+ +inlineRev .size (),newTag );
370370 }
371371 }else if (inlineDelta instanceof ChangeDelta ) {
372372if (mergeOriginalRevised ) {
373373origList .addAll (inlineOrig .getPosition () +inlineOrig .size (),
374374revList .subList (inlineRev .getPosition (),inlineRev .getPosition ()
375375 +inlineRev .size ()));
376376wrapInTag (origList ,inlineOrig .getPosition () +inlineOrig .size (),inlineOrig .getPosition () +inlineOrig .size ()
377- +inlineRev .size () + 1 ,newTag );
377+ +inlineRev .size (),newTag );
378378 }else {
379379wrapInTag (revList ,inlineRev .getPosition (),inlineRev .getPosition ()
380- +inlineRev .size () + 1 ,newTag );
380+ +inlineRev .size (),newTag );
381381 }
382382wrapInTag (origList ,inlineOrig .getPosition (),inlineOrig
383383 .getPosition ()
384- +inlineOrig .size () + 1 ,oldTag );
384+ +inlineOrig .size (),oldTag );
385385 }
386386 }
387387StringBuilder origResult =new StringBuilder ();
@@ -413,10 +413,41 @@ private List<DiffRow> generateInlineDiffs(AbstractDelta<String> delta) throws Di
413413 * @param tag the tag name without angle brackets, just a word
414414 * @param cssClass the optional css class
415415 */
416- private static void wrapInTag (List <String >sequence ,int startPosition ,
417- int endPosition ,Function <Boolean ,String >generator ) {
418- sequence .add (startPosition ,generator .apply (true ));
419- sequence .add (endPosition ,generator .apply (false ));
416+ static void wrapInTag (List <String >sequence ,int startPosition ,
417+ int endPosition ,Function <Boolean ,String >tagGenerator ) {
418+ int endPos =endPosition ;
419+
420+ while (endPos >=startPosition ) {
421+
422+ //search position for end tag
423+ while (endPos >startPosition ) {
424+ if (!"\n " .equals (sequence .get (endPos -1 ))) {
425+ break ;
426+ }
427+ endPos --;
428+ }
429+
430+ if (endPos ==startPosition ) {
431+ break ;
432+ }
433+
434+ sequence .add (endPos ,tagGenerator .apply (false ));
435+ endPos --;
436+
437+ //search position for end tag
438+ while (endPos >startPosition ) {
439+ if ("\n " .equals (sequence .get (endPos -1 ))) {
440+ break ;
441+ }
442+ endPos --;
443+ }
444+
445+ sequence .add (endPos ,tagGenerator .apply (true ));
446+ endPos --;
447+ }
448+
449+ // sequence.add(endPosition, tagGenerator.apply(false));
450+ // sequence.add(startPosition, tagGenerator.apply(true));
420451 }
421452
422453protected final static List <String >splitStringPreserveDelimiter (String str ,Pattern SPLIT_PATTERN ) {