@@ -182,6 +182,7 @@ var (
182182 codeTagSuffix = []byte (`</span>` )
183183)
184184var trailingSpanRegex = regexp .MustCompile (`<span\s*[[:alpha:]="]*?[>]?$` )
185+ var entityRegex = regexp .MustCompile (`&[#]*?[0-9a-z]*$` )
185186
186187// shouldWriteInline represents combinations where we manually write inline changes
187188func shouldWriteInline (diff diffmatchpatch.Diff , lineType DiffLineType ) bool {
@@ -213,6 +214,11 @@ func diffToHTML(fileName string, diffs []diffmatchpatch.Diff, lineType DiffLineT
213214 match = diff .Text [m [0 ]:m [1 ]]
214215 diff .Text = strings .TrimSuffix (diff .Text , match )
215216 }
217+ m = entityRegex .FindStringSubmatchIndex (diff .Text )
218+ if m != nil {
219+ match = diff .Text [m [0 ]:m [1 ]]
220+ diff .Text = strings .TrimSuffix (diff .Text , match )
221+ }
216222 // Print an existing closing span first before opening added/remove-code span so it doesn't unintentionally close it
217223 if strings .HasPrefix (diff .Text , "</span>" ) {
218224 buf .WriteString ("</span>" )
@@ -290,9 +296,6 @@ func init() {
290296 diffMatchPatch .DiffEditCost = 100
291297}
292298
293- var unterminatedEntityRE = regexp .MustCompile (`&[^ ;]*$` )
294- var unstartedEntiyRE = regexp .MustCompile (`^[^ ;]*;` )
295-
296299// GetComputedInlineDiffFor computes inline diff for the given line.
297300func (diffSection * DiffSection ) GetComputedInlineDiffFor (diffLine * DiffLine ) template.HTML {
298301 if setting .Git .DisableDiffHighlight {
@@ -333,89 +336,11 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) tem
333336 diffRecord := diffMatchPatch .DiffMain (highlight .Code (diffSection .FileName , diff1 [1 :]), highlight .Code (diffSection .FileName , diff2 [1 :]), true )
334337 diffRecord = diffMatchPatch .DiffCleanupEfficiency (diffRecord )
335338
336- // Now we need to clean up the split entities
337- diffRecord = unsplitEntities (diffRecord )
338339 diffRecord = diffMatchPatch .DiffCleanupEfficiency (diffRecord )
339340
340341 return diffToHTML (diffSection .FileName , diffRecord , diffLine .Type )
341342}
342343
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-
419344// DiffFile represents a file diff.
420345type DiffFile struct {
421346 Name string
0 commit comments