From 3c4724d70e4ac7bfc06b97f6fad8936f97479b6b Mon Sep 17 00:00:00 2001 From: zeripath Date: Wed, 17 Nov 2021 20:37:00 +0000 Subject: Add .gitattribute assisted language detection to blame, diff and render (#17590) Use check attribute code to check the assigned language of a file and send that in to chroma as a hint for the language of the file. Signed-off-by: Andrew Thornton --- services/gitdiff/gitdiff.go | 45 +++++++++++++++++++++------------------- services/gitdiff/gitdiff_test.go | 2 +- 2 files changed, 25 insertions(+), 22 deletions(-) (limited to 'services/gitdiff') diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 614f8104ec..33e66e89ec 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -31,7 +31,6 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/util" "github.com/sergi/go-diff/diffmatchpatch" stdcharset "golang.org/x/net/html/charset" @@ -178,6 +177,7 @@ func getLineContent(content string) string { // DiffSection represents a section of a DiffFile. type DiffSection struct { + file *DiffFile FileName string Name string Lines []*DiffLine @@ -546,6 +546,11 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) tem diff2 string ) + language := "" + if diffSection.file != nil { + language = diffSection.file.Language + } + // try to find equivalent diff line. ignore, otherwise switch diffLine.Type { case DiffLineSection: @@ -553,25 +558,25 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) tem case DiffLineAdd: compareDiffLine = diffSection.GetLine(DiffLineDel, diffLine.RightIdx) if compareDiffLine == nil { - return template.HTML(highlight.Code(diffSection.FileName, diffLine.Content[1:])) + return template.HTML(highlight.Code(diffSection.FileName, language, diffLine.Content[1:])) } diff1 = compareDiffLine.Content diff2 = diffLine.Content case DiffLineDel: compareDiffLine = diffSection.GetLine(DiffLineAdd, diffLine.LeftIdx) if compareDiffLine == nil { - return template.HTML(highlight.Code(diffSection.FileName, diffLine.Content[1:])) + return template.HTML(highlight.Code(diffSection.FileName, language, diffLine.Content[1:])) } diff1 = diffLine.Content diff2 = compareDiffLine.Content default: if strings.IndexByte(" +-", diffLine.Content[0]) > -1 { - return template.HTML(highlight.Code(diffSection.FileName, diffLine.Content[1:])) + return template.HTML(highlight.Code(diffSection.FileName, language, diffLine.Content[1:])) } - return template.HTML(highlight.Code(diffSection.FileName, diffLine.Content)) + return template.HTML(highlight.Code(diffSection.FileName, language, diffLine.Content)) } - diffRecord := diffMatchPatch.DiffMain(highlight.Code(diffSection.FileName, diff1[1:]), highlight.Code(diffSection.FileName, diff2[1:]), true) + diffRecord := diffMatchPatch.DiffMain(highlight.Code(diffSection.FileName, language, diff1[1:]), highlight.Code(diffSection.FileName, language, diff2[1:]), true) diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) return diffToHTML(diffSection.FileName, diffRecord, diffLine.Type) @@ -597,6 +602,7 @@ type DiffFile struct { IsProtected bool IsGenerated bool IsVendored bool + Language string } // GetType returns type of diff file. @@ -1008,7 +1014,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio line := sb.String() // Create a new section to represent this hunk - curSection = &DiffSection{} + curSection = &DiffSection{file: curFile} lastLeftIdx = -1 curFile.Sections = append(curFile.Sections, curSection) @@ -1048,7 +1054,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio rightLine++ if curSection == nil { // Create a new section to represent this hunk - curSection = &DiffSection{} + curSection = &DiffSection{file: curFile} curFile.Sections = append(curFile.Sections, curSection) lastLeftIdx = -1 } @@ -1074,7 +1080,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio } if curSection == nil { // Create a new section to represent this hunk - curSection = &DiffSection{} + curSection = &DiffSection{file: curFile} curFile.Sections = append(curFile.Sections, curSection) lastLeftIdx = -1 } @@ -1094,7 +1100,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio lastLeftIdx = -1 if curSection == nil { // Create a new section to represent this hunk - curSection = &DiffSection{} + curSection = &DiffSection{file: curFile} curFile.Sections = append(curFile.Sections, curSection) } curSection.Lines = append(curSection.Lines, diffLine) @@ -1302,23 +1308,15 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, var checker *git.CheckAttributeReader if git.CheckGitVersionAtLeast("1.7.8") == nil { - indexFilename, deleteTemporaryFile, err := gitRepo.ReadTreeToTemporaryIndex(afterCommitID) + indexFilename, worktree, deleteTemporaryFile, err := gitRepo.ReadTreeToTemporaryIndex(afterCommitID) if err == nil { defer deleteTemporaryFile() - workdir, err := os.MkdirTemp("", "empty-work-dir") - if err != nil { - log.Error("Unable to create temporary directory: %v", err) - return nil, err - } - defer func() { - _ = util.RemoveAll(workdir) - }() checker = &git.CheckAttributeReader{ - Attributes: []string{"linguist-vendored", "linguist-generated"}, + Attributes: []string{"linguist-vendored", "linguist-generated", "linguist-language", "gitlab-language"}, Repo: gitRepo, IndexFile: indexFilename, - WorkTree: workdir, + WorkTree: worktree, } ctx, cancel := context.WithCancel(git.DefaultContext) if err := checker.Init(ctx); err != nil { @@ -1361,6 +1359,11 @@ func GetDiffRangeWithWhitespaceBehavior(gitRepo *git.Repository, beforeCommitID, gotGenerated = generated == "false" } } + if language, has := attrs["linguist-language"]; has && language != "unspecified" && language != "" { + diffFile.Language = language + } else if language, has := attrs["gitlab-language"]; has && language != "unspecified" && language != "" { + diffFile.Language = language + } } else { log.Error("Unexpected error: %v", err) } diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go index aefd396ebb..c6c6f3b0e3 100644 --- a/services/gitdiff/gitdiff_test.go +++ b/services/gitdiff/gitdiff_test.go @@ -533,7 +533,7 @@ func TestGetDiffRangeWithWhitespaceBehavior(t *testing.T) { func TestDiffToHTML_14231(t *testing.T) { setting.Cfg = ini.Empty() - diffRecord := diffMatchPatch.DiffMain(highlight.Code("main.v", " run()\n"), highlight.Code("main.v", " run(db)\n"), true) + diffRecord := diffMatchPatch.DiffMain(highlight.Code("main.v", "", " run()\n"), highlight.Code("main.v", "", " run(db)\n"), true) diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) expected := ` run(db)` -- cgit v1.2.3