@@ -290,6 +290,9 @@ func init() {
290
290
diffMatchPatch .DiffEditCost = 100
291
291
}
292
292
293
+ var unterminatedEntityRE = regexp .MustCompile (`&[^ ;]*$` )
294
+ var unstartedEntiyRE = regexp .MustCompile (`^[^ ;]*;` )
295
+
293
296
// GetComputedInlineDiffFor computes inline diff for the given line.
294
297
func (diffSection * DiffSection ) GetComputedInlineDiffFor (diffLine * DiffLine ) template.HTML {
295
298
if setting .Git .DisableDiffHighlight {
@@ -329,9 +332,90 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) tem
329
332
330
333
diffRecord := diffMatchPatch .DiffMain (highlight .Code (diffSection .FileName , diff1 [1 :]), highlight .Code (diffSection .FileName , diff2 [1 :]), true )
331
334
diffRecord = diffMatchPatch .DiffCleanupEfficiency (diffRecord )
335
+
336
+ // Now we need to clean up the split entities
337
+ diffRecord = unsplitEntities (diffRecord )
338
+ diffRecord = diffMatchPatch .DiffCleanupEfficiency (diffRecord )
339
+
332
340
return diffToHTML (diffSection .FileName , diffRecord , diffLine .Type )
333
341
}
334
342
343
+ // unsplitEntities looks for broken up html entities. It relies on records being presimplified and the data being passed in being valid html
344
+ func unsplitEntities (records []diffmatchpatch.Diff ) []diffmatchpatch.Diff {
345
+ // Unsplitting entities is simple...
346
+ //
347
+ // Iterate through all be the last records because if we're the last record then there's nothing we can do
348
+ for i := 0 ; i + 1 < len (records ); i ++ {
349
+ record := & records [i ]
350
+
351
+ // Look for an unterminated entity at the end of the line
352
+ unterminated := unterminatedEntityRE .FindString (record .Text )
353
+ if len (unterminated ) == 0 {
354
+ continue
355
+ }
356
+
357
+ switch record .Type {
358
+ case diffmatchpatch .DiffEqual :
359
+ // If we're an diff equal we want to give this unterminated entity to our next delete and insert
360
+ record .Text = record .Text [0 : len (record .Text )- len (unterminated )]
361
+ records [i + 1 ].Text = unterminated + records [i + 1 ].Text
362
+
363
+ nextType := records [i + 1 ].Type
364
+
365
+ if nextType == diffmatchpatch .DiffEqual {
366
+ continue
367
+ }
368
+
369
+ // if the next in line is a delete then we will want the thing after that to be an insert and so on.
370
+ oneAfterType := diffmatchpatch .DiffInsert
371
+ if nextType == diffmatchpatch .DiffInsert {
372
+ oneAfterType = diffmatchpatch .DiffDelete
373
+ }
374
+
375
+ if i + 2 < len (records ) && records [i + 2 ].Type == oneAfterType {
376
+ records [i + 2 ].Text = unterminated + records [i + 2 ].Text
377
+ } else {
378
+ records = append (records [:i + 2 ], append ([]diffmatchpatch.Diff {
379
+ {
380
+ Type : oneAfterType ,
381
+ Text : unterminated ,
382
+ }}, records [i + 2 :]... )... )
383
+ }
384
+ case diffmatchpatch .DiffDelete :
385
+ fallthrough
386
+ case diffmatchpatch .DiffInsert :
387
+ // if we're an insert or delete we want to claim the terminal bit of the entity from the next equal in line
388
+ targetType := diffmatchpatch .DiffInsert
389
+ if record .Type == diffmatchpatch .DiffInsert {
390
+ targetType = diffmatchpatch .DiffDelete
391
+ }
392
+ next := & records [i + 1 ]
393
+ if next .Type == diffmatchpatch .DiffEqual {
394
+ // if the next is an equal we need to snaffle the entity end off the start and add an delete/insert
395
+ if terminal := unstartedEntiyRE .FindString (next .Text ); len (terminal ) > 0 {
396
+ record .Text += terminal
397
+ next .Text = next .Text [len (terminal ):]
398
+ records = append (records [:i + 2 ], append ([]diffmatchpatch.Diff {
399
+ {
400
+ Type : targetType ,
401
+ Text : unterminated ,
402
+ }}, records [i + 2 :]... )... )
403
+ }
404
+ } else if next .Type == targetType {
405
+ // if the next is an insert we need to snaffle the entity end off the one after that and add it to both.
406
+ if i + 2 < len (records ) && records [i + 2 ].Type == diffmatchpatch .DiffEqual {
407
+ if terminal := unstartedEntiyRE .FindString (records [i + 2 ].Text ); len (terminal ) > 0 {
408
+ record .Text += terminal
409
+ next .Text += terminal
410
+ records [i + 2 ].Text = records [i + 2 ].Text [len (terminal ):]
411
+ }
412
+ }
413
+ }
414
+ }
415
+ }
416
+ return records
417
+ }
418
+
335
419
// DiffFile represents a file diff.
336
420
type DiffFile struct {
337
421
Name string
0 commit comments