Skip to content

Commit 5f93560

Browse files
committed
fix highlight problem of git diff
related go-gitea#23176 try fix it with @silverwind solution in go-gitea#23176 (comment) looks the result is good. but looks it will cost to much memorry when the file is large. maybe limt the max file size? Signed-off-by: a1012112796 <[email protected]>
1 parent 56d4893 commit 5f93560

File tree

2 files changed

+115
-13
lines changed

2 files changed

+115
-13
lines changed

routers/web/repo/compare.go

+23-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package repo
55

66
import (
77
"bufio"
8+
"bytes"
89
gocontext "context"
910
"encoding/csv"
1011
"errors"
@@ -27,6 +28,7 @@ import (
2728
"code.gitea.io/gitea/modules/context"
2829
csv_module "code.gitea.io/gitea/modules/csv"
2930
"code.gitea.io/gitea/modules/git"
31+
"code.gitea.io/gitea/modules/highlight"
3032
"code.gitea.io/gitea/modules/log"
3133
"code.gitea.io/gitea/modules/markup"
3234
"code.gitea.io/gitea/modules/setting"
@@ -929,8 +931,21 @@ func getExcerptLines(commit *git.Commit, filePath string, idxLeft, idxRight, chu
929931
if err != nil {
930932
return nil, err
931933
}
932-
defer reader.Close()
933-
scanner := bufio.NewScanner(reader)
934+
935+
content, err := io.ReadAll(reader)
936+
_ = reader.Close()
937+
if err != nil {
938+
log.Error("io.ReadAll: %v", err)
939+
return nil, err
940+
}
941+
942+
highlightedContent, _, err := highlight.File(filePath, "", content)
943+
if err != nil {
944+
log.Error("highlight.File: %v", err)
945+
return nil, err
946+
}
947+
948+
scanner := bufio.NewScanner(bytes.NewBuffer(content))
934949
var diffLines []*gitdiff.DiffLine
935950
for line := 0; line < idxRight+chunkSize; line++ {
936951
if ok := scanner.Scan(); !ok {
@@ -941,10 +956,12 @@ func getExcerptLines(commit *git.Commit, filePath string, idxLeft, idxRight, chu
941956
}
942957
lineText := scanner.Text()
943958
diffLine := &gitdiff.DiffLine{
944-
LeftIdx: idxLeft + (line - idxRight) + 1,
945-
RightIdx: line + 1,
946-
Type: gitdiff.DiffLinePlain,
947-
Content: " " + lineText,
959+
LeftIdx: idxLeft + (line - idxRight) + 1,
960+
RightIdx: line + 1,
961+
Type: gitdiff.DiffLinePlain,
962+
Content: " " + lineText,
963+
HighlightContent: highlightedContent[line],
964+
HasHighlightContent: true,
948965
}
949966
diffLines = append(diffLines, diffLine)
950967
}

services/gitdiff/gitdiff.go

+92-7
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,15 @@ const (
7676

7777
// DiffLine represents a line difference in a DiffSection.
7878
type DiffLine struct {
79-
LeftIdx int
80-
RightIdx int
81-
Match int
82-
Type DiffLineType
83-
Content string
84-
Comments []*issues_model.Comment
85-
SectionInfo *DiffLineSectionInfo
79+
LeftIdx int
80+
RightIdx int
81+
Match int
82+
Type DiffLineType
83+
Content string
84+
Comments []*issues_model.Comment
85+
SectionInfo *DiffLineSectionInfo
86+
HighlightContent string
87+
HasHighlightContent bool
8688
}
8789

8890
// DiffLineSectionInfo represents diff line section meta data
@@ -306,13 +308,23 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine, loc
306308
case DiffLineSection:
307309
return getLineContent(diffLine.Content[1:], locale)
308310
case DiffLineAdd:
311+
if diffLine.HasHighlightContent {
312+
status, content := charset.EscapeControlHTML(diffLine.HighlightContent, locale)
313+
return DiffInline{EscapeStatus: status, Content: template.HTML(content)}
314+
}
315+
309316
compareDiffLine = diffSection.GetLine(DiffLineDel, diffLine.RightIdx)
310317
if compareDiffLine == nil {
311318
return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:], locale)
312319
}
313320
diff1 = compareDiffLine.Content
314321
diff2 = diffLine.Content
315322
case DiffLineDel:
323+
if diffLine.HasHighlightContent {
324+
status, content := charset.EscapeControlHTML(diffLine.HighlightContent, locale)
325+
return DiffInline{EscapeStatus: status, Content: template.HTML(content)}
326+
}
327+
316328
compareDiffLine = diffSection.GetLine(DiffLineAdd, diffLine.LeftIdx)
317329
if compareDiffLine == nil {
318330
return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:], locale)
@@ -321,6 +333,11 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine, loc
321333
diff2 = compareDiffLine.Content
322334
default:
323335
if strings.IndexByte(" +-", diffLine.Content[0]) > -1 {
336+
if diffLine.HasHighlightContent {
337+
status, content := charset.EscapeControlHTML(diffLine.HighlightContent, locale)
338+
return DiffInline{EscapeStatus: status, Content: template.HTML(content)}
339+
}
340+
324341
return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:], locale)
325342
}
326343
return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content, locale)
@@ -1064,13 +1081,46 @@ type DiffOptions struct {
10641081
// Passing the empty string as beforeCommitID returns a diff from the parent commit.
10651082
// The whitespaceBehavior is either an empty string or a git flag
10661083
func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff, error) {
1084+
1085+
loadCommitFileContent := func(commit *git.Commit, path, lang string) ([]string, string) {
1086+
entry, err := commit.GetTreeEntryByPath(path)
1087+
if err != nil {
1088+
log.Error("GetTreeEntryByPath: %v", err)
1089+
return nil, ""
1090+
}
1091+
1092+
f, err := entry.Blob().DataAsync()
1093+
if err != nil {
1094+
log.Error("Blob.DataAsync: %v", err)
1095+
return nil, ""
1096+
}
1097+
1098+
// TODO: maybe should limit file size?
1099+
content, err := io.ReadAll(f)
1100+
_ = f.Close()
1101+
if err != nil {
1102+
log.Error("io.ReadAll: %v", err)
1103+
return nil, ""
1104+
}
1105+
1106+
highlightedContent, lang, err := highlight.File(path, lang, content)
1107+
if err != nil {
1108+
log.Error("highlight.File: %v", err)
1109+
return nil, ""
1110+
}
1111+
1112+
return highlightedContent, lang
1113+
}
1114+
10671115
repoPath := gitRepo.Path
10681116

10691117
commit, err := gitRepo.GetCommit(opts.AfterCommitID)
10701118
if err != nil {
10711119
return nil, err
10721120
}
10731121

1122+
var beforeCommit *git.Commit
1123+
10741124
cmdDiff := git.NewCommand(gitRepo.Ctx)
10751125
if (len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == git.EmptySHA) && commit.ParentCount() == 0 {
10761126
cmdDiff.AddArguments("diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M").
@@ -1082,6 +1132,12 @@ func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff
10821132
if len(actualBeforeCommitID) == 0 {
10831133
parentCommit, _ := commit.Parent(0)
10841134
actualBeforeCommitID = parentCommit.ID.String()
1135+
beforeCommit = parentCommit
1136+
} else {
1137+
beforeCommit, err = gitRepo.GetCommit(actualBeforeCommitID)
1138+
if err != nil {
1139+
return nil, err
1140+
}
10851141
}
10861142

10871143
cmdDiff.AddArguments("diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M").
@@ -1172,6 +1228,35 @@ func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff
11721228
if tailSection != nil {
11731229
diffFile.Sections = append(diffFile.Sections, tailSection)
11741230
}
1231+
1232+
// render full file for edited file
1233+
if diffFile.Type != DiffFileChange || beforeCommit == nil {
1234+
continue
1235+
}
1236+
1237+
var newContent []string
1238+
oldContent, _ := loadCommitFileContent(beforeCommit, diffFile.OldName, diffFile.Language)
1239+
newContent, diffFile.Language = loadCommitFileContent(commit, diffFile.Name, diffFile.Language)
1240+
1241+
for _, diffSection := range diffFile.Sections {
1242+
for _, diffLine := range diffSection.Lines {
1243+
switch diffLine.Type {
1244+
case DiffLineAdd:
1245+
fallthrough
1246+
case DiffLinePlain:
1247+
if diffLine.RightIdx > 0 && diffLine.RightIdx <= len(newContent) {
1248+
diffLine.HighlightContent = newContent[diffLine.RightIdx-1]
1249+
diffLine.HasHighlightContent = true
1250+
}
1251+
1252+
case DiffLineDel:
1253+
if diffLine.LeftIdx > 0 && diffLine.LeftIdx <= len(oldContent) {
1254+
diffLine.HighlightContent = oldContent[diffLine.LeftIdx-1]
1255+
diffLine.HasHighlightContent = true
1256+
}
1257+
}
1258+
}
1259+
}
11751260
}
11761261

11771262
separator := "..."

0 commit comments

Comments
 (0)