Skip to content

Commit d42de12

Browse files
committed
- reverting original hunk-based syntax highlighting
- adding conditions for when full file based highlighting should occur - falling back to hunk based highlighting in certain conditions - reverting original hunk-based highlighting tests - updating types to express intent better and to be more accurate i.e. `template.HTML` instead of string where appropriate
1 parent 14d6c0e commit d42de12

File tree

4 files changed

+201
-29
lines changed

4 files changed

+201
-29
lines changed

modules/setting/git.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,12 @@ var Git = struct {
3838
Pull int
3939
GC int `ini:"GC"`
4040
} `ini:"git.timeout"`
41+
MaxDiffHighlightFileSize int64
4142
}{
4243
DisableDiffHighlight: false,
4344
MaxGitDiffLines: 1000,
4445
MaxGitDiffLineCharacters: 5000,
46+
MaxDiffHighlightFileSize: 5000,
4547
MaxGitDiffFiles: 100,
4648
CommitsRangeSize: 50,
4749
BranchesRangeSize: 20,

services/gitdiff/gitdiff.go

Lines changed: 126 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,14 @@ func DiffInlineWithUnicodeEscape(s template.HTML, locale translation.Locale) Dif
289289
return DiffInline{EscapeStatus: status, Content: content}
290290
}
291291

292-
// GetComputedInlineDiffFor computes inline diff for the given line.
293-
func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine, locale translation.Locale) DiffInline {
292+
// DiffInlineWithHighlightCode makes a DiffInline with code highlight and hidden unicode characters escaped
293+
func DiffInlineWithHighlightCode(fileName, language, code string, locale translation.Locale) DiffInline {
294+
highlighted, _ := highlight.Code(fileName, language, code)
295+
status, content := charset.EscapeControlHTML(highlighted, locale)
296+
return DiffInline{EscapeStatus: status, Content: content}
297+
}
298+
299+
func (diffSection *DiffSection) getComputedInlineDiffForHunk(diffLine *DiffLine, locale translation.Locale) DiffInline {
294300
if setting.Git.DisableDiffHighlight {
295301
return getLineContent(diffLine.Content[1:], locale)
296302
}
@@ -301,6 +307,55 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine, loc
301307
diff2 string
302308
)
303309

310+
language := ""
311+
if diffSection.file != nil {
312+
language = diffSection.file.Language
313+
}
314+
315+
// try to find equivalent diff line. ignore, otherwise
316+
switch diffLine.Type {
317+
case DiffLineSection:
318+
return getLineContent(diffLine.Content[1:], locale)
319+
case DiffLineAdd:
320+
compareDiffLine = diffSection.GetLine(DiffLineDel, diffLine.RightIdx)
321+
if compareDiffLine == nil {
322+
return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:], locale)
323+
}
324+
diff1 = compareDiffLine.Content
325+
diff2 = diffLine.Content
326+
case DiffLineDel:
327+
compareDiffLine = diffSection.GetLine(DiffLineAdd, diffLine.LeftIdx)
328+
if compareDiffLine == nil {
329+
return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:], locale)
330+
}
331+
diff1 = diffLine.Content
332+
diff2 = compareDiffLine.Content
333+
default:
334+
if strings.IndexByte(" +-", diffLine.Content[0]) > -1 {
335+
return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:], locale)
336+
}
337+
return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content, locale)
338+
}
339+
340+
hcd := newHighlightCodeDiff()
341+
diffRecord := hcd.diffWithHighlight(diffSection.FileName, language, diff1[1:], diff2[1:])
342+
// it seems that Gitea doesn't need the line wrapper of Chroma, so do not add them back
343+
// if the line wrappers are still needed in the future, it can be added back by "diffToHTML(hcd.lineWrapperTags. ...)"
344+
diffHTML := diffToHTML(nil, diffRecord, diffLine.Type)
345+
return DiffInlineWithUnicodeEscape(template.HTML(diffHTML), locale)
346+
}
347+
348+
func (diffSection *DiffSection) getComputedInlineDiffForFullFile(diffLine *DiffLine, locale translation.Locale) DiffInline {
349+
if setting.Git.DisableDiffHighlight {
350+
return getLineContent(diffLine.Content[1:], locale)
351+
}
352+
353+
var (
354+
compareDiffLine *DiffLine
355+
diff1 template.HTML
356+
diff2 template.HTML
357+
)
358+
304359
// try to find equivalent diff line. ignore, otherwise
305360
switch diffLine.Type {
306361
case DiffLineSection:
@@ -309,35 +364,46 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine, loc
309364
compareDiffLine = diffSection.GetLine(DiffLineDel, diffLine.RightIdx)
310365
if compareDiffLine == nil {
311366
highlightedLine := diffSection.file.highlightedNewLines[diffLine.RightIdx-1]
312-
return DiffInlineWithUnicodeEscape(template.HTML(highlightedLine), locale)
367+
return DiffInlineWithUnicodeEscape(highlightedLine, locale)
313368
}
314369
diff1 = diffSection.file.highlightedOldLines[compareDiffLine.LeftIdx-1]
315370
diff2 = diffSection.file.highlightedNewLines[diffLine.RightIdx-1]
316371
case DiffLineDel:
317372
compareDiffLine = diffSection.GetLine(DiffLineAdd, diffLine.LeftIdx)
318373
if compareDiffLine == nil {
319374
highlightedLine := diffSection.file.highlightedOldLines[diffLine.LeftIdx-1]
320-
return DiffInlineWithUnicodeEscape(template.HTML(highlightedLine), locale)
375+
return DiffInlineWithUnicodeEscape(highlightedLine, locale)
321376
}
322377
diff1 = diffSection.file.highlightedOldLines[diffLine.LeftIdx-1]
323378
diff2 = diffSection.file.highlightedNewLines[compareDiffLine.RightIdx-1]
324379
default:
325380
if strings.IndexByte(" +-", diffLine.Content[0]) > -1 {
326381
highlightedContent := diffSection.file.highlightedNewLines[diffLine.RightIdx-1]
327-
return DiffInlineWithUnicodeEscape(template.HTML(highlightedContent), locale)
382+
return DiffInlineWithUnicodeEscape(highlightedContent, locale)
328383
}
329384
highlightedContent := diffSection.file.highlightedOldLines[diffLine.LeftIdx-1]
330-
return DiffInlineWithUnicodeEscape(template.HTML(highlightedContent), locale)
385+
return DiffInlineWithUnicodeEscape(highlightedContent, locale)
331386
}
332387

333388
hcd := newHighlightCodeDiff()
334-
diffRecord := hcd.diffWithHighlight(diff1, diff2)
389+
diffRecord := hcd.diffWithFullFileHighlight(diff1, diff2)
335390
// it seems that Gitea doesn't need the line wrapper of Chroma, so do not add them back
336391
// if the line wrappers are still needed in the future, it can be added back by "diffToHTML(hcd.lineWrapperTags. ...)"
337392
diffHTML := diffToHTML(nil, diffRecord, diffLine.Type)
338393
return DiffInlineWithUnicodeEscape(template.HTML(diffHTML), locale)
339394
}
340395

396+
// GetComputedInlineDiffFor computes inline diff for the given line.
397+
func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine, locale translation.Locale) DiffInline {
398+
if diffSection.file == nil {
399+
return diffSection.getComputedInlineDiffForHunk(diffLine, locale)
400+
}
401+
if diffSection.file.shouldHighlightEntireFile {
402+
return diffSection.getComputedInlineDiffForFullFile(diffLine, locale)
403+
}
404+
return diffSection.getComputedInlineDiffForHunk(diffLine, locale)
405+
}
406+
341407
// DiffFile represents a file diff.
342408
type DiffFile struct {
343409
Name string
@@ -367,8 +433,9 @@ type DiffFile struct {
367433
IsSubmodule bool // if IsSubmodule==true, then there must be a SubmoduleDiffInfo
368434
SubmoduleDiffInfo *SubmoduleDiffInfo
369435

370-
highlightedOldLines []string
371-
highlightedNewLines []string
436+
shouldHighlightEntireFile bool
437+
highlightedOldLines []template.HTML
438+
highlightedNewLines []template.HTML
372439
}
373440

374441
// GetType returns type of diff file.
@@ -433,6 +500,46 @@ func (diffFile *DiffFile) ModeTranslationKey(mode string) string {
433500
}
434501
}
435502

503+
func (diffFile *DiffFile) getLineCount(commit *git.Commit) (int, error) {
504+
blob, err := commit.GetBlobByPath(diffFile.GetDiffFileName())
505+
if err != nil {
506+
return 0, err
507+
}
508+
return blob.GetBlobLineCount()
509+
}
510+
511+
func (diffFile *DiffFile) determineHighlightStrategy(commit, beforeCommit *git.Commit) {
512+
diffFile.shouldHighlightEntireFile = true
513+
if commit == nil {
514+
diffFile.shouldHighlightEntireFile = false
515+
}
516+
517+
currentLineCount, err := diffFile.getLineCount(commit)
518+
if err != nil {
519+
log.Debug("could not retrieve line count for current commit file - reverting to hunk based highlighting")
520+
diffFile.shouldHighlightEntireFile = false
521+
}
522+
523+
beforeLineCount := 0
524+
if beforeCommit != nil {
525+
// it's possible that the current commit is the first commit
526+
// this would make the before commit nil
527+
beforeLineCount, err = diffFile.getLineCount(beforeCommit)
528+
if err != nil {
529+
log.Debug("could not retrieve line count for previous commit file - reverting to hunk based highlighting")
530+
diffFile.shouldHighlightEntireFile = false
531+
}
532+
}
533+
534+
if beforeLineCount > int(setting.Git.MaxDiffHighlightFileSize) || currentLineCount > int(setting.Git.MaxDiffHighlightFileSize) {
535+
diffFile.shouldHighlightEntireFile = false
536+
}
537+
538+
if diffFile.shouldHighlightEntireFile {
539+
diffFile.highlightedOldLines, diffFile.highlightedNewLines = highlightEntireFile(commit, beforeCommit, diffFile)
540+
}
541+
}
542+
436543
func getCommitFileLineCount(commit *git.Commit, filePath string) int {
437544
blob, err := commit.GetBlobByPath(filePath)
438545
if err != nil {
@@ -1222,7 +1329,7 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi
12221329
}
12231330
diffFile.IsGenerated = isGenerated.Value()
12241331

1225-
diffFile.highlightedOldLines, diffFile.highlightedNewLines = highlightCode(commit, beforeCommit, diffFile)
1332+
diffFile.determineHighlightStrategy(commit, beforeCommit)
12261333

12271334
tailSection := diffFile.GetTailSection(gitRepo, beforeCommit, commit)
12281335
if tailSection != nil {
@@ -1244,9 +1351,9 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi
12441351
return diff, nil
12451352
}
12461353

1247-
func highlightCode(commit, beforeCommit *git.Commit, diffFile *DiffFile) ([]string, []string) {
1248-
var oldLines []string
1249-
var newLines []string
1354+
func highlightEntireFile(commit, beforeCommit *git.Commit, diffFile *DiffFile) ([]template.HTML, []template.HTML) {
1355+
var oldLines []template.HTML
1356+
var newLines []template.HTML
12501357

12511358
if beforeCommit != nil {
12521359
oldBlob, err := beforeCommit.GetBlobByPath(diffFile.Name)
@@ -1255,7 +1362,9 @@ func highlightCode(commit, beforeCommit *git.Commit, diffFile *DiffFile) ([]stri
12551362
highlightedOldContent, _ := highlight.Code(diffFile.Name, diffFile.Language, oldContent)
12561363

12571364
splitLines := strings.Split(string(highlightedOldContent), "\n")
1258-
oldLines = append(oldLines, splitLines...)
1365+
for _, line := range splitLines {
1366+
oldLines = append(oldLines, template.HTML(line))
1367+
}
12591368
}
12601369
}
12611370

@@ -1265,7 +1374,9 @@ func highlightCode(commit, beforeCommit *git.Commit, diffFile *DiffFile) ([]stri
12651374
highlightedNewContent, _ := highlight.Code(diffFile.Name, diffFile.Language, newContent)
12661375

12671376
splitLines := strings.Split(string(highlightedNewContent), "\n")
1268-
newLines = append(newLines, splitLines...)
1377+
for _, line := range splitLines {
1378+
newLines = append(newLines, template.HTML(line))
1379+
}
12691380
}
12701381

12711382
return oldLines, newLines

services/gitdiff/highlightdiff.go

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
package gitdiff
55

66
import (
7+
"html/template"
78
"strings"
89

10+
"code.gitea.io/gitea/modules/highlight"
11+
912
"github.com/sergi/go-diff/diffmatchpatch"
1013
)
1114

@@ -84,12 +87,31 @@ func (hcd *highlightCodeDiff) collectUsedRunes(code string) {
8487
}
8588
}
8689

87-
func (hcd *highlightCodeDiff) diffWithHighlight(codeA, codeB string) []diffmatchpatch.Diff {
90+
func (hcd *highlightCodeDiff) diffWithHighlight(filename, language, codeA, codeB string) []diffmatchpatch.Diff {
8891
hcd.collectUsedRunes(codeA)
8992
hcd.collectUsedRunes(codeB)
9093

91-
convertedCodeA := hcd.convertToPlaceholders(codeA)
92-
convertedCodeB := hcd.convertToPlaceholders(codeB)
94+
highlightCodeA, _ := highlight.Code(filename, language, codeA)
95+
highlightCodeB, _ := highlight.Code(filename, language, codeB)
96+
97+
convertedCodeA := hcd.convertToPlaceholders(string(highlightCodeA))
98+
convertedCodeB := hcd.convertToPlaceholders(string(highlightCodeB))
99+
100+
diffs := diffMatchPatch.DiffMain(convertedCodeA, convertedCodeB, true)
101+
diffs = diffMatchPatch.DiffCleanupEfficiency(diffs)
102+
103+
for i := range diffs {
104+
hcd.recoverOneDiff(&diffs[i])
105+
}
106+
return diffs
107+
}
108+
109+
func (hcd *highlightCodeDiff) diffWithFullFileHighlight(codeA, codeB template.HTML) []diffmatchpatch.Diff {
110+
hcd.collectUsedRunes(string(codeA))
111+
hcd.collectUsedRunes(string(codeB))
112+
113+
convertedCodeA := hcd.convertToPlaceholders(string(codeA))
114+
convertedCodeB := hcd.convertToPlaceholders(string(codeB))
93115

94116
diffs := diffMatchPatch.DiffMain(convertedCodeA, convertedCodeB, true)
95117
diffs = diffMatchPatch.DiffCleanupEfficiency(diffs)

0 commit comments

Comments
 (0)