* Server-side syntax hilighting for all code This PR does a few things: * Remove all traces of highlight.js * Use chroma library to provide fast syntax hilighting directly on the server * Provide syntax hilighting for diffs * Re-style both unified and split diffs views * Add custom syntax hilighting styling for both regular and arc-green Fixes #7729 Fixes #10157 Fixes #11825 Fixes #7728 Fixes #3872 Fixes #3682 And perhaps gets closer to #9553 * fix line marker * fix repo search * Fix single line select * properly load settings * npm uninstall highlight.js * review suggestion * code review * forgot to call function * fix test * Apply suggestions from code review suggestions from @silverwind thanks Co-authored-by: silverwind <me@silverwind.io> * code review * copy/paste error * Use const for highlight size limit * Update web_src/less/_repository.less Co-authored-by: Lauris BH <lauris@nix.lv> * update size limit to 1MB and other styling tweaks * fix highlighting for certain diff sections * fix test * add worker back as suggested
Showing the changes to services/gitdiff/gitdiff.go (1 of 336 files). Show all
Unified · Split
| @@ -10,7 +10,6 @@ import ( · 9 unmodified lines | |||
| 10 | "bytes" | 10 | "bytes" |
| 11 | "context" | 11 | "context" |
| 12 | "fmt" | 12 | "fmt" |
| 13 | "html" | ||
| 14 | "html/template" | 13 | "html/template" |
| 15 | "io" | 14 | "io" |
| 16 | "io/ioutil" | 15 | "io/ioutil" |
| @@ -164,15 +163,16 @@ func getDiffLineSectionInfo(treePath, line string, lastLeftIdx, lastRightIdx int · 147 unmodified lines | |||
| 164 | // escape a line's content or return <br> needed for copy/paste purposes | 163 | // escape a line's content or return <br> needed for copy/paste purposes |
| 165 | func getLineContent(content string) string { | 164 | func getLineContent(content string) string { |
| 166 | if len(content) > 0 { | 165 | if len(content) > 0 { |
| 167 | return html.EscapeString(content) | 166 | return content |
| 168 | } | 167 | } |
| 169 | return "<br>" | 168 | return "\n" |
| 170 | } | 169 | } |
| 171 | 170 | ||
| 172 | // DiffSection represents a section of a DiffFile. | 171 | // DiffSection represents a section of a DiffFile. |
| 173 | type DiffSection struct { | 172 | type DiffSection struct { |
| 174 | Name string | 173 | FileName string |
| 175 | Lines []*DiffLine | 174 | Name string |
| 175 | Lines []*DiffLine | ||
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | var ( | 178 | var ( |
| @@ -181,24 +181,23 @@ var ( · 2 unmodified lines | |||
| 181 | codeTagSuffix = []byte(`</span>`) | 181 | codeTagSuffix = []byte(`</span>`) |
| 182 | ) | 182 | ) |
| 183 | 183 | ||
| 184 | func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML { | 184 | func diffToHTML(fileName string, diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML { |
| 185 | buf := bytes.NewBuffer(nil) | 185 | buf := bytes.NewBuffer(nil) |
| 186 | 186 | ||
| 187 | for i := range diffs { | 187 | for i := range diffs { |
| 188 | switch { | 188 | switch { |
| 189 | case diffs[i].Type == diffmatchpatch.DiffInsert && lineType == DiffLineAdd: | 189 | case diffs[i].Type == diffmatchpatch.DiffInsert && lineType == DiffLineAdd: |
| 190 | buf.Write(addedCodePrefix) | 190 | buf.Write(addedCodePrefix) |
| 191 | buf.WriteString(getLineContent(diffs[i].Text)) | 191 | buf.WriteString(highlight.Code(fileName, diffs[i].Text)) |
| 192 | buf.Write(codeTagSuffix) | 192 | buf.Write(codeTagSuffix) |
| 193 | case diffs[i].Type == diffmatchpatch.DiffDelete && lineType == DiffLineDel: | 193 | case diffs[i].Type == diffmatchpatch.DiffDelete && lineType == DiffLineDel: |
| 194 | buf.Write(removedCodePrefix) | 194 | buf.Write(removedCodePrefix) |
| 195 | buf.WriteString(getLineContent(diffs[i].Text)) | 195 | buf.WriteString(highlight.Code(fileName, diffs[i].Text)) |
| 196 | buf.Write(codeTagSuffix) | 196 | buf.Write(codeTagSuffix) |
| 197 | case diffs[i].Type == diffmatchpatch.DiffEqual: | 197 | case diffs[i].Type == diffmatchpatch.DiffEqual: |
| 198 | buf.WriteString(getLineContent(diffs[i].Text)) | 198 | buf.WriteString(highlight.Code(fileName, getLineContent(diffs[i].Text))) |
| 199 | } | 199 | } |
| 200 | } | 200 | } |
| 201 | |||
| 202 | return template.HTML(buf.Bytes()) | 201 | return template.HTML(buf.Bytes()) |
| 203 | } | 202 | } |
| 204 | 203 | ||
| @@ -256,6 +255,7 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) tem · 51 unmodified lines | |||
| 256 | if setting.Git.DisableDiffHighlight { | 255 | if setting.Git.DisableDiffHighlight { |
| 257 | return template.HTML(getLineContent(diffLine.Content[1:])) | 256 | return template.HTML(getLineContent(diffLine.Content[1:])) |
| 258 | } | 257 | } |
| 258 | |||
| 259 | var ( | 259 | var ( |
| 260 | compareDiffLine *DiffLine | 260 | compareDiffLine *DiffLine |
| 261 | diff1 string | 261 | diff1 string |
| @@ -264,31 +264,32 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) tem · 2 unmodified lines | |||
| 264 | 264 | ||
| 265 | // try to find equivalent diff line. ignore, otherwise | 265 | // try to find equivalent diff line. ignore, otherwise |
| 266 | switch diffLine.Type { | 266 | switch diffLine.Type { |
| 267 | case DiffLineSection: | ||
| 268 | return template.HTML(getLineContent(diffLine.Content[1:])) | ||
| 267 | case DiffLineAdd: | 269 | case DiffLineAdd: |
| 268 | compareDiffLine = diffSection.GetLine(DiffLineDel, diffLine.RightIdx) | 270 | compareDiffLine = diffSection.GetLine(DiffLineDel, diffLine.RightIdx) |
| 269 | if compareDiffLine == nil { | 271 | if compareDiffLine == nil { |
| 270 | return template.HTML(getLineContent(diffLine.Content[1:])) | 272 | return template.HTML(highlight.Code(diffSection.FileName, diffLine.Content[1:]+"\n")) |
| 271 | } | 273 | } |
| 272 | diff1 = compareDiffLine.Content | 274 | diff1 = compareDiffLine.Content |
| 273 | diff2 = diffLine.Content | 275 | diff2 = diffLine.Content |
| 274 | case DiffLineDel: | 276 | case DiffLineDel: |
| 275 | compareDiffLine = diffSection.GetLine(DiffLineAdd, diffLine.LeftIdx) | 277 | compareDiffLine = diffSection.GetLine(DiffLineAdd, diffLine.LeftIdx) |
| 276 | if compareDiffLine == nil { | 278 | if compareDiffLine == nil { |
| 277 | return template.HTML(getLineContent(diffLine.Content[1:])) | 279 | return template.HTML(highlight.Code(diffSection.FileName, diffLine.Content[1:]+"\n")) |
| 278 | } | 280 | } |
| 279 | diff1 = diffLine.Content | 281 | diff1 = diffLine.Content |
| 280 | diff2 = compareDiffLine.Content | 282 | diff2 = compareDiffLine.Content |
| 281 | default: | 283 | default: |
| 282 | if strings.IndexByte(" +-", diffLine.Content[0]) > -1 { | 284 | if strings.IndexByte(" +-", diffLine.Content[0]) > -1 { |
| 283 | return template.HTML(getLineContent(diffLine.Content[1:])) | 285 | return template.HTML(highlight.Code(diffSection.FileName, diffLine.Content[1:]+"\n")) |
| 284 | } | 286 | } |
| 285 | return template.HTML(getLineContent(diffLine.Content)) | 287 | return template.HTML(highlight.Code(diffSection.FileName, diffLine.Content)) |
| 286 | } | 288 | } |
| 287 | 289 | ||
| 288 | diffRecord := diffMatchPatch.DiffMain(diff1[1:], diff2[1:], true) | 290 | diffRecord := diffMatchPatch.DiffMain(diff1[1:], diff2[1:], true) |
| 289 | diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) | 291 | diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) |
| 290 | 292 | return diffToHTML(diffSection.FileName, diffRecord, diffLine.Type) | |
| 291 | return diffToHTML(diffRecord, diffLine.Type) | ||
| 292 | } | 293 | } |
| 293 | 294 | ||
| 294 | // DiffFile represents a file diff. | 295 | // DiffFile represents a file diff. |
| @@ -313,11 +314,6 @@ func (diffFile *DiffFile) GetType() int { · 18 unmodified lines | |||
| 313 | return int(diffFile.Type) | 314 | return int(diffFile.Type) |
| 314 | } | 315 | } |
| 315 | 316 | ||
| 316 | // GetHighlightClass returns highlight class for a filename. | ||
| 317 | func (diffFile *DiffFile) GetHighlightClass() string { | ||
| 318 | return highlight.FileNameToHighlightClass(diffFile.Name) | ||
| 319 | } | ||
| 320 | |||
| 321 | // GetTailSection creates a fake DiffLineSection if the last section is not the end of the file | 317 | // GetTailSection creates a fake DiffLineSection if the last section is not the end of the file |
| 322 | func (diffFile *DiffFile) GetTailSection(gitRepo *git.Repository, leftCommitID, rightCommitID string) *DiffSection { | 318 | func (diffFile *DiffFile) GetTailSection(gitRepo *git.Repository, leftCommitID, rightCommitID string) *DiffSection { |
| 323 | if len(diffFile.Sections) == 0 || diffFile.Type != DiffFileChange || diffFile.IsBin || diffFile.IsLFSFile { | 319 | if len(diffFile.Sections) == 0 || diffFile.Type != DiffFileChange || diffFile.IsBin || diffFile.IsLFSFile { |
| @@ -348,7 +344,7 @@ func (diffFile *DiffFile) GetTailSection(gitRepo *git.Repository, leftCommitID, · 24 unmodified lines | |||
| 348 | LeftIdx: leftLineCount, | 344 | LeftIdx: leftLineCount, |
| 349 | RightIdx: rightLineCount, | 345 | RightIdx: rightLineCount, |
| 350 | }} | 346 | }} |
| 351 | tailSection := &DiffSection{Lines: []*DiffLine{tailDiffLine}} | 347 | tailSection := &DiffSection{FileName: diffFile.Name, Lines: []*DiffLine{tailDiffLine}} |
| 352 | return tailSection | 348 | return tailSection |
| 353 | 349 | ||
| 354 | } | 350 | } |
| @@ -405,8 +401,7 @@ const cmdDiffHead = "diff --git " · 50 unmodified lines | |||
| 405 | // TODO: move this function to gogits/git-module | 401 | // TODO: move this function to gogits/git-module |
| 406 | func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*Diff, error) { | 402 | func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*Diff, error) { |
| 407 | var ( | 403 | var ( |
| 408 | diff = &Diff{Files: make([]*DiffFile, 0)} | 404 | diff = &Diff{Files: make([]*DiffFile, 0)} |
| 409 | |||
| 410 | curFile = &DiffFile{} | 405 | curFile = &DiffFile{} |
| 411 | curSection = &DiffSection{ | 406 | curSection = &DiffSection{ |
| 412 | Lines: make([]*DiffLine, 0, 10), | 407 | Lines: make([]*DiffLine, 0, 10), |
| @@ -481,6 +476,7 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D · 68 unmodified lines | |||
| 481 | leftLine++ | 476 | leftLine++ |
| 482 | rightLine++ | 477 | rightLine++ |
| 483 | curSection.Lines = append(curSection.Lines, diffLine) | 478 | curSection.Lines = append(curSection.Lines, diffLine) |
| 479 | curSection.FileName = curFile.Name | ||
| 484 | continue | 480 | continue |
| 485 | case line[0] == '@': | 481 | case line[0] == '@': |
| 486 | curSection = &DiffSection{} | 482 | curSection = &DiffSection{} |
| @@ -492,6 +488,7 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D · 5 unmodified lines | |||
| 492 | SectionInfo: lineSectionInfo, | 488 | SectionInfo: lineSectionInfo, |
| 493 | } | 489 | } |
| 494 | curSection.Lines = append(curSection.Lines, diffLine) | 490 | curSection.Lines = append(curSection.Lines, diffLine) |
| 491 | curSection.FileName = curFile.Name | ||
| 495 | // update line number. | 492 | // update line number. |
| 496 | leftLine = lineSectionInfo.LeftIdx | 493 | leftLine = lineSectionInfo.LeftIdx |
| 497 | rightLine = lineSectionInfo.RightIdx | 494 | rightLine = lineSectionInfo.RightIdx |
| @@ -502,6 +499,7 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D · 4 unmodified lines | |||
| 502 | diffLine := &DiffLine{Type: DiffLineAdd, Content: line, RightIdx: rightLine} | 499 | diffLine := &DiffLine{Type: DiffLineAdd, Content: line, RightIdx: rightLine} |
| 503 | rightLine++ | 500 | rightLine++ |
| 504 | curSection.Lines = append(curSection.Lines, diffLine) | 501 | curSection.Lines = append(curSection.Lines, diffLine) |
| 502 | curSection.FileName = curFile.Name | ||
| 505 | continue | 503 | continue |
| 506 | case line[0] == '-': | 504 | case line[0] == '-': |
| 507 | curFile.Deletion++ | 505 | curFile.Deletion++ |
| @@ -511,6 +509,7 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D · 3 unmodified lines | |||
| 511 | leftLine++ | 509 | leftLine++ |
| 512 | } | 510 | } |
| 513 | curSection.Lines = append(curSection.Lines, diffLine) | 511 | curSection.Lines = append(curSection.Lines, diffLine) |
| 512 | curSection.FileName = curFile.Name | ||
| 514 | case strings.HasPrefix(line, "Binary"): | 513 | case strings.HasPrefix(line, "Binary"): |
| 515 | curFile.IsBin = true | 514 | curFile.IsBin = true |
| 516 | continue | 515 | continue |