Skip to content

Commit 62eb155

Browse files
committed
clear edge cases, fine tune tests
1 parent de042fc commit 62eb155

File tree

3 files changed

+100
-63
lines changed

3 files changed

+100
-63
lines changed

modules/highlight/highlight.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,11 @@ var (
4040
// NewContext loads custom highlight map from local config
4141
func NewContext() {
4242
once.Do(func() {
43-
keys := setting.Cfg.Section("highlight.mapping").Keys()
44-
for i := range keys {
45-
highlightMapping[keys[i].Name()] = keys[i].Value()
43+
if setting.Cfg != nil {
44+
keys := setting.Cfg.Section("highlight.mapping").Keys()
45+
for i := range keys {
46+
highlightMapping[keys[i].Name()] = keys[i].Value()
47+
}
4648
}
4749

4850
// The size 512 is simply a conservative rule of thumb

services/gitdiff/gitdiff.go

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ var (
190190
codeTagSuffix = []byte(`</span>`)
191191
)
192192

193-
func diffToHTML(hcd *HighlightCodeDiff, diffs []diffmatchpatch.Diff, lineType DiffLineType) DiffInline {
193+
func diffToHTML(hcd *HighlightCodeDiff, diffs []diffmatchpatch.Diff, lineType DiffLineType) string {
194194
buf := bytes.NewBuffer(nil)
195195
if hcd != nil {
196196
for _, tag := range hcd.lineWrapperTags {
@@ -216,7 +216,7 @@ func diffToHTML(hcd *HighlightCodeDiff, diffs []diffmatchpatch.Diff, lineType Di
216216
buf.WriteString("</span>")
217217
}
218218
}
219-
return DiffInlineWithUnicodeEscape(template.HTML(buf.String()))
219+
return buf.String()
220220
}
221221

222222
// 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 {
289289
type HighlightCodeDiff struct {
290290
placeholderBegin rune
291291
placeholderMaxCount int
292-
placeholderCounter int
292+
placeholderIndex int
293293
placeholderTagMap map[rune]string
294294
tagPlaceholderMap map[string]rune
295295

@@ -305,12 +305,49 @@ func NewHighlightCodeDiff() *HighlightCodeDiff {
305305
}
306306
}
307307

308+
// nextPlaceholder returns 0 if no more placeholder can be used
308309
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
314351
}
315352

316353
func (hcd *HighlightCodeDiff) convertToPlaceholders(highlightCode string) string {
@@ -362,12 +399,19 @@ func (hcd *HighlightCodeDiff) convertToPlaceholders(highlightCode string) string
362399
placeholder, ok := hcd.tagPlaceholderMap[tagInMap]
363400
if !ok {
364401
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+
}
367406
}
368407

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+
}
370413
}
414+
371415
res.WriteString(s)
372416
return res.String()
373417
}
@@ -378,7 +422,7 @@ func (hcd *HighlightCodeDiff) recoverOneDiff(diff *diffmatchpatch.Diff) {
378422

379423
for _, r := range diff.Text {
380424
tag, ok := hcd.placeholderTagMap[r]
381-
if !ok {
425+
if !ok || tag == "" {
382426
sb.WriteRune(r)
383427
continue
384428
}
@@ -413,12 +457,6 @@ func (hcd *HighlightCodeDiff) recoverOneDiff(diff *diffmatchpatch.Diff) {
413457
diff.Text = sb.String()
414458
}
415459

416-
func (hcd *HighlightCodeDiff) recoverFromPlaceholders(diffs []diffmatchpatch.Diff) {
417-
for i := range diffs {
418-
hcd.recoverOneDiff(&diffs[i])
419-
}
420-
}
421-
422460
// GetComputedInlineDiffFor computes inline diff for the given line.
423461
func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) DiffInline {
424462
if setting.Git.DisableDiffHighlight {
@@ -461,19 +499,10 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) Dif
461499
return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content)
462500
}
463501

464-
highlightCodeA := highlight.Code(diffSection.FileName, language, diff1[1:])
465-
highlightCodeB := highlight.Code(diffSection.FileName, language, diff2[1:])
466-
467502
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))
477506
}
478507

479508
// DiffFile represents a file diff.

services/gitdiff/gitdiff_test.go

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package gitdiff
77

88
import (
99
"fmt"
10-
"html/template"
1110
"strconv"
1211
"strings"
1312
"testing"
@@ -17,36 +16,27 @@ import (
1716
"code.gitea.io/gitea/models/unittest"
1817
user_model "code.gitea.io/gitea/models/user"
1918
"code.gitea.io/gitea/modules/git"
20-
"code.gitea.io/gitea/modules/highlight"
2119
"code.gitea.io/gitea/modules/json"
2220
"code.gitea.io/gitea/modules/setting"
2321

2422
dmp "github.com/sergi/go-diff/diffmatchpatch"
2523
"github.com/stretchr/testify/assert"
26-
"gopkg.in/ini.v1"
2724
)
2825

29-
func assertEqual(t *testing.T, expected string, actual template.HTML) {
30-
if expected != string(actual) {
31-
t.Errorf("Did not receive expected results:\nExpected: %s\nActual: %s", expected, actual)
32-
}
33-
}
34-
3526
func TestDiffToHTML(t *testing.T) {
36-
setting.Cfg = ini.Empty()
37-
assertEqual(t, "foo <span class=\"added-code\">bar</span> biz", diffToHTML(nil, []dmp.Diff{
27+
assert.Equal(t, "foo <span class=\"added-code\">bar</span> biz", diffToHTML(nil, []dmp.Diff{
3828
{Type: dmp.DiffEqual, Text: "foo "},
3929
{Type: dmp.DiffInsert, Text: "bar"},
4030
{Type: dmp.DiffDelete, Text: " baz"},
4131
{Type: dmp.DiffEqual, Text: " biz"},
42-
}, DiffLineAdd).Content)
32+
}, DiffLineAdd))
4333

44-
assertEqual(t, "foo <span class=\"removed-code\">bar</span> biz", diffToHTML(nil, []dmp.Diff{
34+
assert.Equal(t, "foo <span class=\"removed-code\">bar</span> biz", diffToHTML(nil, []dmp.Diff{
4535
{Type: dmp.DiffEqual, Text: "foo "},
4636
{Type: dmp.DiffDelete, Text: "bar"},
4737
{Type: dmp.DiffInsert, Text: " baz"},
4838
{Type: dmp.DiffEqual, Text: " biz"},
49-
}, DiffLineDel).Content)
39+
}, DiffLineDel))
5040
}
5141

5242
func TestParsePatch_skipTo(t *testing.T) {
@@ -654,26 +644,42 @@ func TestGetDiffRangeWithWhitespaceBehavior(t *testing.T) {
654644
}
655645
}
656646

657-
func TestDiffToHTML_14231(t *testing.T) {
658-
setting.Cfg = ini.Empty()
659-
647+
func TestDiffWithHighlight(t *testing.T) {
660648
hcd := NewHighlightCodeDiff()
661-
662-
highlightCodeA := highlight.Code("main.v", "", " run()\n")
663-
highlightCodeB := highlight.Code("main.v", "", " run(db)\n")
664-
highlightCodeA = hcd.convertToPlaceholders(highlightCodeA)
665-
highlightCodeB = hcd.convertToPlaceholders(highlightCodeB)
666-
667-
diffRecord := diffMatchPatch.DiffMain(highlightCodeA, highlightCodeB, true)
668-
diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord)
669-
670-
hcd.recoverFromPlaceholders(diffRecord)
671-
649+
diffs := hcd.diffWithHighlight(
650+
"main.v", "",
651+
" run()\n",
652+
" run(db)\n",
653+
)
672654
expected := `<span class="line"><span class="cl"> <span class="n">run</span><span class="added-code"><span class="o">(</span><span class="n">db</span><span class="o">)</span></span>
673655
</span></span>`
674-
output := diffToHTML(hcd, diffRecord, DiffLineAdd)
656+
output := diffToHTML(hcd, diffs, DiffLineAdd)
657+
assert.Equal(t, expected, output)
658+
}
675659

676-
assertEqual(t, expected, output.Content)
660+
func TestDiffWithHighlightPlaceholder(t *testing.T) {
661+
hcd := NewHighlightCodeDiff()
662+
diffs := hcd.diffWithHighlight(
663+
"main.js", "",
664+
"a='\uE000'",
665+
"a='\uF8FF'",
666+
)
667+
assert.Equal(t, "", hcd.placeholderTagMap[0xE000])
668+
assert.Equal(t, "", hcd.placeholderTagMap[0xF8FF])
669+
670+
expected := fmt.Sprintf(`<span class="line"><span class="cl"><span class="nx">a</span><span class="o">=</span><span class="s1">&#39;</span><span class="added-code">%s</span>&#39;</span></span>`, "\uF8FF")
671+
output := diffToHTML(hcd, diffs, DiffLineAdd)
672+
assert.Equal(t, expected, output)
673+
674+
hcd = NewHighlightCodeDiff()
675+
diffs = hcd.diffWithHighlight(
676+
"main.js", "",
677+
"a='\uE000'",
678+
"a='\uF8FF'",
679+
)
680+
expected = fmt.Sprintf(`<span class="line"><span class="cl"><span class="nx">a</span><span class="o">=</span><span class="s1">&#39;</span><span class="removed-code">%s</span>&#39;</span></span>`, "\uE000")
681+
output = diffToHTML(hcd, diffs, DiffLineDel)
682+
assert.Equal(t, expected, output)
677683
}
678684

679685
func TestNoCrashes(t *testing.T) {

0 commit comments

Comments
 (0)