@@ -190,7 +190,7 @@ var (
190
190
codeTagSuffix = []byte (`</span>` )
191
191
)
192
192
193
- func diffToHTML (hcd * HighlightCodeDiff , diffs []diffmatchpatch.Diff , lineType DiffLineType ) DiffInline {
193
+ func diffToHTML (hcd * HighlightCodeDiff , diffs []diffmatchpatch.Diff , lineType DiffLineType ) string {
194
194
buf := bytes .NewBuffer (nil )
195
195
if hcd != nil {
196
196
for _ , tag := range hcd .lineWrapperTags {
@@ -216,7 +216,7 @@ func diffToHTML(hcd *HighlightCodeDiff, diffs []diffmatchpatch.Diff, lineType Di
216
216
buf .WriteString ("</span>" )
217
217
}
218
218
}
219
- return DiffInlineWithUnicodeEscape ( template . HTML ( buf .String ()) )
219
+ return buf .String ()
220
220
}
221
221
222
222
// GetLine gets a specific line by type (add or del) and file line number
@@ -289,7 +289,7 @@ func DiffInlineWithHighlightCode(fileName, language, code string) DiffInline {
289
289
type HighlightCodeDiff struct {
290
290
placeholderBegin rune
291
291
placeholderMaxCount int
292
- placeholderCounter int
292
+ placeholderIndex int
293
293
placeholderTagMap map [rune ]string
294
294
tagPlaceholderMap map [string ]rune
295
295
@@ -305,12 +305,49 @@ func NewHighlightCodeDiff() *HighlightCodeDiff {
305
305
}
306
306
}
307
307
308
+ // nextPlaceholder returns 0 if no more placeholder can be used
308
309
func (hcd * HighlightCodeDiff ) nextPlaceholder () rune {
309
- // TODO: handle placeholder rune conflicts ( case 1: counter reaches placeholderMaxCount, case 2: there are placeholder runes in code )
310
- r := hcd .placeholderBegin + rune (hcd .placeholderCounter % hcd .placeholderMaxCount )
311
- hcd .placeholderCounter ++
312
- hcd .placeholderCounter %= hcd .placeholderMaxCount
313
- return r
310
+ for hcd .placeholderIndex < hcd .placeholderMaxCount {
311
+ r := hcd .placeholderBegin + rune (hcd .placeholderIndex )
312
+ hcd .placeholderIndex ++
313
+ // only use non-existing (not used by code) rune as placeholders
314
+ if _ , ok := hcd .placeholderTagMap [r ]; ! ok {
315
+ return r
316
+ }
317
+ }
318
+ return 0 // no more available placeholder
319
+ }
320
+
321
+ func (hcd * HighlightCodeDiff ) isInPlaceholderRange (r rune ) bool {
322
+ return hcd .placeholderBegin <= r && r < hcd .placeholderBegin + rune (hcd .placeholderMaxCount )
323
+ }
324
+
325
+ func (hcd * HighlightCodeDiff ) collectUsedRunes (code string ) {
326
+ for _ , r := range code {
327
+ if hcd .isInPlaceholderRange (r ) {
328
+ // put the existing rune (used by code) in map, then this rune won't be used a placeholder anymore.
329
+ hcd .placeholderTagMap [r ] = ""
330
+ }
331
+ }
332
+ }
333
+
334
+ func (hcd * HighlightCodeDiff ) diffWithHighlight (filename , language , codeA , codeB string ) []diffmatchpatch.Diff {
335
+ hcd .collectUsedRunes (codeA )
336
+ hcd .collectUsedRunes (codeB )
337
+
338
+ highlightCodeA := highlight .Code (filename , language , codeA )
339
+ highlightCodeB := highlight .Code (filename , language , codeB )
340
+
341
+ highlightCodeA = hcd .convertToPlaceholders (highlightCodeA )
342
+ highlightCodeB = hcd .convertToPlaceholders (highlightCodeB )
343
+
344
+ diffs := diffMatchPatch .DiffMain (highlightCodeA , highlightCodeB , true )
345
+ diffs = diffMatchPatch .DiffCleanupEfficiency (diffs )
346
+
347
+ for i := range diffs {
348
+ hcd .recoverOneDiff (& diffs [i ])
349
+ }
350
+ return diffs
314
351
}
315
352
316
353
func (hcd * HighlightCodeDiff ) convertToPlaceholders (highlightCode string ) string {
@@ -362,12 +399,19 @@ func (hcd *HighlightCodeDiff) convertToPlaceholders(highlightCode string) string
362
399
placeholder , ok := hcd .tagPlaceholderMap [tagInMap ]
363
400
if ! ok {
364
401
placeholder = hcd .nextPlaceholder ()
365
- hcd .tagPlaceholderMap [tagInMap ] = placeholder
366
- hcd .placeholderTagMap [placeholder ] = tagInMap
402
+ if placeholder != 0 {
403
+ hcd .tagPlaceholderMap [tagInMap ] = placeholder
404
+ hcd .placeholderTagMap [placeholder ] = tagInMap
405
+ }
367
406
}
368
407
369
- res .WriteRune (placeholder ) // use the placeholder to replace the tag
408
+ if placeholder != 0 {
409
+ res .WriteRune (placeholder ) // use the placeholder to replace the tag
410
+ } else {
411
+ res .WriteString (tag ) // unfortunately, all private use runes has been exhausted, no more placeholder could be used, so do not covert the tag
412
+ }
370
413
}
414
+
371
415
res .WriteString (s )
372
416
return res .String ()
373
417
}
@@ -378,7 +422,7 @@ func (hcd *HighlightCodeDiff) recoverOneDiff(diff *diffmatchpatch.Diff) {
378
422
379
423
for _ , r := range diff .Text {
380
424
tag , ok := hcd .placeholderTagMap [r ]
381
- if ! ok {
425
+ if ! ok || tag == "" {
382
426
sb .WriteRune (r )
383
427
continue
384
428
}
@@ -413,12 +457,6 @@ func (hcd *HighlightCodeDiff) recoverOneDiff(diff *diffmatchpatch.Diff) {
413
457
diff .Text = sb .String ()
414
458
}
415
459
416
- func (hcd * HighlightCodeDiff ) recoverFromPlaceholders (diffs []diffmatchpatch.Diff ) {
417
- for i := range diffs {
418
- hcd .recoverOneDiff (& diffs [i ])
419
- }
420
- }
421
-
422
460
// GetComputedInlineDiffFor computes inline diff for the given line.
423
461
func (diffSection * DiffSection ) GetComputedInlineDiffFor (diffLine * DiffLine ) DiffInline {
424
462
if setting .Git .DisableDiffHighlight {
@@ -461,19 +499,10 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) Dif
461
499
return DiffInlineWithHighlightCode (diffSection .FileName , language , diffLine .Content )
462
500
}
463
501
464
- highlightCodeA := highlight .Code (diffSection .FileName , language , diff1 [1 :])
465
- highlightCodeB := highlight .Code (diffSection .FileName , language , diff2 [1 :])
466
-
467
502
hcd := NewHighlightCodeDiff ()
468
- highlightCodeA = hcd .convertToPlaceholders (highlightCodeA )
469
- highlightCodeB = hcd .convertToPlaceholders (highlightCodeB )
470
-
471
- diffRecord := diffMatchPatch .DiffMain (highlightCodeA , highlightCodeB , true )
472
- diffRecord = diffMatchPatch .DiffCleanupEfficiency (diffRecord )
473
-
474
- hcd .recoverFromPlaceholders (diffRecord )
475
-
476
- return diffToHTML (hcd , diffRecord , diffLine .Type )
503
+ diffRecord := hcd .diffWithHighlight (diffSection .FileName , language , diff1 [1 :], diff2 [1 :])
504
+ diffHTML := diffToHTML (hcd , diffRecord , diffLine .Type )
505
+ return DiffInlineWithUnicodeEscape (template .HTML (diffHTML ))
477
506
}
478
507
479
508
// DiffFile represents a file diff.
0 commit comments