mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-04 09:44:21 +00:00 
			
		
		
		
	Improve diff highlight (#3390)
- Try to reduce memory allocations - Add possibility to disable diff highlight (can improve performance for large diffs) - Tweaking with cost for prettier (cleaner) diffs - Do not calculate diff when the number of removed lines in a block is not equal to the number of added lines (this usually resulted in ugly diffs)
This commit is contained in:
		@@ -334,11 +334,13 @@ RUN_AT_START = true
 | 
				
			|||||||
SCHEDULE = @every 24h
 | 
					SCHEDULE = @every 24h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[git]
 | 
					[git]
 | 
				
			||||||
; Max number of lines allowed of a single file in diff view.
 | 
					; Disables highlight of added and removed changes
 | 
				
			||||||
 | 
					DISABLE_DIFF_HIGHLIGHT = false
 | 
				
			||||||
 | 
					; Max number of lines allowed of a single file in diff view
 | 
				
			||||||
MAX_GIT_DIFF_LINES = 1000
 | 
					MAX_GIT_DIFF_LINES = 1000
 | 
				
			||||||
; Max number of characters of a line allowed in diff view.
 | 
					; Max number of characters of a line allowed in diff view
 | 
				
			||||||
MAX_GIT_DIFF_LINE_CHARACTERS = 500
 | 
					MAX_GIT_DIFF_LINE_CHARACTERS = 500
 | 
				
			||||||
; Max number of files shown in diff view.
 | 
					; Max number of files shown in diff view
 | 
				
			||||||
MAX_GIT_DIFF_FILES = 100
 | 
					MAX_GIT_DIFF_FILES = 100
 | 
				
			||||||
; Arguments for command 'git gc', e.g. "--aggressive --auto"
 | 
					; Arguments for command 'git gc', e.g. "--aggressive --auto"
 | 
				
			||||||
; see more on http://git-scm.com/docs/git-gc/1.7.5
 | 
					; see more on http://git-scm.com/docs/git-gc/1.7.5
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,7 @@ import (
 | 
				
			|||||||
	"github.com/gogits/gogs/modules/base"
 | 
						"github.com/gogits/gogs/modules/base"
 | 
				
			||||||
	"github.com/gogits/gogs/modules/log"
 | 
						"github.com/gogits/gogs/modules/log"
 | 
				
			||||||
	"github.com/gogits/gogs/modules/process"
 | 
						"github.com/gogits/gogs/modules/process"
 | 
				
			||||||
 | 
						"github.com/gogits/gogs/modules/setting"
 | 
				
			||||||
	"github.com/gogits/gogs/modules/template/highlight"
 | 
						"github.com/gogits/gogs/modules/template/highlight"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -70,17 +71,18 @@ var (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML {
 | 
					func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML {
 | 
				
			||||||
	var buf bytes.Buffer
 | 
						buf := bytes.NewBuffer(nil)
 | 
				
			||||||
	for i := range diffs {
 | 
						for i := range diffs {
 | 
				
			||||||
		if diffs[i].Type == diffmatchpatch.DiffInsert && lineType == DIFF_LINE_ADD {
 | 
							switch {
 | 
				
			||||||
 | 
							case diffs[i].Type == diffmatchpatch.DiffInsert && lineType == DIFF_LINE_ADD:
 | 
				
			||||||
			buf.Write(addedCodePrefix)
 | 
								buf.Write(addedCodePrefix)
 | 
				
			||||||
			buf.WriteString(html.EscapeString(diffs[i].Text))
 | 
								buf.WriteString(html.EscapeString(diffs[i].Text))
 | 
				
			||||||
			buf.Write(codeTagSuffix)
 | 
								buf.Write(codeTagSuffix)
 | 
				
			||||||
		} else if diffs[i].Type == diffmatchpatch.DiffDelete && lineType == DIFF_LINE_DEL {
 | 
							case diffs[i].Type == diffmatchpatch.DiffDelete && lineType == DIFF_LINE_DEL:
 | 
				
			||||||
			buf.Write(removedCodePrefix)
 | 
								buf.Write(removedCodePrefix)
 | 
				
			||||||
			buf.WriteString(html.EscapeString(diffs[i].Text))
 | 
								buf.WriteString(html.EscapeString(diffs[i].Text))
 | 
				
			||||||
			buf.Write(codeTagSuffix)
 | 
								buf.Write(codeTagSuffix)
 | 
				
			||||||
		} else if diffs[i].Type == diffmatchpatch.DiffEqual {
 | 
							case diffs[i].Type == diffmatchpatch.DiffEqual:
 | 
				
			||||||
			buf.WriteString(html.EscapeString(diffs[i].Text))
 | 
								buf.WriteString(html.EscapeString(diffs[i].Text))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -90,62 +92,86 @@ func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTM
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// get an specific line by type (add or del) and file line number
 | 
					// get an specific line by type (add or del) and file line number
 | 
				
			||||||
func (diffSection *DiffSection) GetLine(lineType DiffLineType, idx int) *DiffLine {
 | 
					func (diffSection *DiffSection) GetLine(lineType DiffLineType, idx int) *DiffLine {
 | 
				
			||||||
	difference := 0
 | 
						var (
 | 
				
			||||||
 | 
							difference    = 0
 | 
				
			||||||
 | 
							addCount      = 0
 | 
				
			||||||
 | 
							delCount      = 0
 | 
				
			||||||
 | 
							matchDiffLine *DiffLine
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LOOP:
 | 
				
			||||||
	for _, diffLine := range diffSection.Lines {
 | 
						for _, diffLine := range diffSection.Lines {
 | 
				
			||||||
		if diffLine.Type == DIFF_LINE_PLAIN {
 | 
							switch diffLine.Type {
 | 
				
			||||||
			// get the difference of line numbers between ADD and DEL versions
 | 
							case DIFF_LINE_ADD:
 | 
				
			||||||
 | 
								addCount++
 | 
				
			||||||
 | 
							case DIFF_LINE_DEL:
 | 
				
			||||||
 | 
								delCount++
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								if matchDiffLine != nil {
 | 
				
			||||||
 | 
									break LOOP
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			difference = diffLine.RightIdx - diffLine.LeftIdx
 | 
								difference = diffLine.RightIdx - diffLine.LeftIdx
 | 
				
			||||||
			continue
 | 
								addCount = 0
 | 
				
			||||||
 | 
								delCount = 0
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if lineType == DIFF_LINE_DEL {
 | 
							switch lineType {
 | 
				
			||||||
 | 
							case DIFF_LINE_DEL:
 | 
				
			||||||
			if diffLine.RightIdx == 0 && diffLine.LeftIdx == idx-difference {
 | 
								if diffLine.RightIdx == 0 && diffLine.LeftIdx == idx-difference {
 | 
				
			||||||
				return diffLine
 | 
									matchDiffLine = diffLine
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else if lineType == DIFF_LINE_ADD {
 | 
							case DIFF_LINE_ADD:
 | 
				
			||||||
			if diffLine.LeftIdx == 0 && diffLine.RightIdx == idx+difference {
 | 
								if diffLine.LeftIdx == 0 && diffLine.RightIdx == idx+difference {
 | 
				
			||||||
				return diffLine
 | 
									matchDiffLine = diffLine
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if addCount == delCount {
 | 
				
			||||||
 | 
							return matchDiffLine
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var diffMatchPatch = diffmatchpatch.New()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						diffMatchPatch.DiffEditCost = 100
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// computes inline diff for the given line
 | 
					// computes inline diff for the given line
 | 
				
			||||||
func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) template.HTML {
 | 
					func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) template.HTML {
 | 
				
			||||||
	var compareDiffLine *DiffLine
 | 
						if setting.Git.DisableDiffHighlight {
 | 
				
			||||||
	var diff1, diff2 string
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	getDefaultReturn := func() template.HTML {
 | 
					 | 
				
			||||||
		return template.HTML(html.EscapeString(diffLine.Content[1:]))
 | 
							return template.HTML(html.EscapeString(diffLine.Content[1:]))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						var (
 | 
				
			||||||
	// just compute diff for adds and removes
 | 
							compareDiffLine *DiffLine
 | 
				
			||||||
	if diffLine.Type != DIFF_LINE_ADD && diffLine.Type != DIFF_LINE_DEL {
 | 
							diff1           string
 | 
				
			||||||
		return getDefaultReturn()
 | 
							diff2           string
 | 
				
			||||||
	}
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// try to find equivalent diff line. ignore, otherwise
 | 
						// try to find equivalent diff line. ignore, otherwise
 | 
				
			||||||
	if diffLine.Type == DIFF_LINE_ADD {
 | 
						switch diffLine.Type {
 | 
				
			||||||
 | 
						case DIFF_LINE_ADD:
 | 
				
			||||||
		compareDiffLine = diffSection.GetLine(DIFF_LINE_DEL, diffLine.RightIdx)
 | 
							compareDiffLine = diffSection.GetLine(DIFF_LINE_DEL, diffLine.RightIdx)
 | 
				
			||||||
		if compareDiffLine == nil {
 | 
							if compareDiffLine == nil {
 | 
				
			||||||
			return getDefaultReturn()
 | 
								return template.HTML(html.EscapeString(diffLine.Content[1:]))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		diff1 = compareDiffLine.Content
 | 
							diff1 = compareDiffLine.Content
 | 
				
			||||||
		diff2 = diffLine.Content
 | 
							diff2 = diffLine.Content
 | 
				
			||||||
	} else {
 | 
						case DIFF_LINE_DEL:
 | 
				
			||||||
		compareDiffLine = diffSection.GetLine(DIFF_LINE_ADD, diffLine.LeftIdx)
 | 
							compareDiffLine = diffSection.GetLine(DIFF_LINE_ADD, diffLine.LeftIdx)
 | 
				
			||||||
		if compareDiffLine == nil {
 | 
							if compareDiffLine == nil {
 | 
				
			||||||
			return getDefaultReturn()
 | 
								return template.HTML(html.EscapeString(diffLine.Content[1:]))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		diff1 = diffLine.Content
 | 
							diff1 = diffLine.Content
 | 
				
			||||||
		diff2 = compareDiffLine.Content
 | 
							diff2 = compareDiffLine.Content
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return template.HTML(html.EscapeString(diffLine.Content[1:]))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dmp := diffmatchpatch.New()
 | 
						diffRecord := diffMatchPatch.DiffMain(diff1[1:], diff2[1:], true)
 | 
				
			||||||
	diffRecord := dmp.DiffMain(diff1[1:], diff2[1:], true)
 | 
						diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord)
 | 
				
			||||||
	diffRecord = dmp.DiffCleanupSemantic(diffRecord)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return diffToHTML(diffRecord, diffLine.Type)
 | 
						return diffToHTML(diffRecord, diffLine.Type)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,38 +33,3 @@ func TestDiffToHTML(t *testing.T) {
 | 
				
			|||||||
		dmp.Diff{dmp.DiffEqual, " biz"},
 | 
							dmp.Diff{dmp.DiffEqual, " biz"},
 | 
				
			||||||
	}, DIFF_LINE_DEL))
 | 
						}, DIFF_LINE_DEL))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
// test if GetLine is return the correct lines
 | 
					 | 
				
			||||||
func TestGetLine(t *testing.T) {
 | 
					 | 
				
			||||||
	ds := DiffSection{Lines: []*DiffLine{
 | 
					 | 
				
			||||||
		&DiffLine{LeftIdx: 28, RightIdx: 28, Type: DIFF_LINE_PLAIN},
 | 
					 | 
				
			||||||
		&DiffLine{LeftIdx: 29, RightIdx: 29, Type: DIFF_LINE_PLAIN},
 | 
					 | 
				
			||||||
		&DiffLine{LeftIdx: 30, RightIdx: 30, Type: DIFF_LINE_PLAIN},
 | 
					 | 
				
			||||||
		&DiffLine{LeftIdx: 31, RightIdx: 0, Type: DIFF_LINE_DEL},
 | 
					 | 
				
			||||||
		&DiffLine{LeftIdx: 0, RightIdx: 31, Type: DIFF_LINE_ADD},
 | 
					 | 
				
			||||||
		&DiffLine{LeftIdx: 0, RightIdx: 32, Type: DIFF_LINE_ADD},
 | 
					 | 
				
			||||||
		&DiffLine{LeftIdx: 32, RightIdx: 33, Type: DIFF_LINE_PLAIN},
 | 
					 | 
				
			||||||
		&DiffLine{LeftIdx: 33, RightIdx: 0, Type: DIFF_LINE_DEL},
 | 
					 | 
				
			||||||
		&DiffLine{LeftIdx: 34, RightIdx: 0, Type: DIFF_LINE_DEL},
 | 
					 | 
				
			||||||
		&DiffLine{LeftIdx: 35, RightIdx: 0, Type: DIFF_LINE_DEL},
 | 
					 | 
				
			||||||
		&DiffLine{LeftIdx: 36, RightIdx: 0, Type: DIFF_LINE_DEL},
 | 
					 | 
				
			||||||
		&DiffLine{LeftIdx: 0, RightIdx: 34, Type: DIFF_LINE_ADD},
 | 
					 | 
				
			||||||
		&DiffLine{LeftIdx: 0, RightIdx: 35, Type: DIFF_LINE_ADD},
 | 
					 | 
				
			||||||
		&DiffLine{LeftIdx: 0, RightIdx: 36, Type: DIFF_LINE_ADD},
 | 
					 | 
				
			||||||
		&DiffLine{LeftIdx: 0, RightIdx: 37, Type: DIFF_LINE_ADD},
 | 
					 | 
				
			||||||
		&DiffLine{LeftIdx: 37, RightIdx: 38, Type: DIFF_LINE_PLAIN},
 | 
					 | 
				
			||||||
		&DiffLine{LeftIdx: 38, RightIdx: 39, Type: DIFF_LINE_PLAIN},
 | 
					 | 
				
			||||||
	}}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 31), ds.Lines[4])
 | 
					 | 
				
			||||||
	assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 31), ds.Lines[3])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 33), ds.Lines[11])
 | 
					 | 
				
			||||||
	assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 34), ds.Lines[12])
 | 
					 | 
				
			||||||
	assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 35), ds.Lines[13])
 | 
					 | 
				
			||||||
	assertLineEqual(t, ds.GetLine(DIFF_LINE_ADD, 36), ds.Lines[14])
 | 
					 | 
				
			||||||
	assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 34), ds.Lines[7])
 | 
					 | 
				
			||||||
	assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 35), ds.Lines[8])
 | 
					 | 
				
			||||||
	assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 36), ds.Lines[9])
 | 
					 | 
				
			||||||
	assertLineEqual(t, ds.GetLine(DIFF_LINE_DEL, 37), ds.Lines[10])
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -191,6 +191,7 @@ var (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Git settings
 | 
						// Git settings
 | 
				
			||||||
	Git struct {
 | 
						Git struct {
 | 
				
			||||||
 | 
							DisableDiffHighlight     bool
 | 
				
			||||||
		MaxGitDiffLines          int
 | 
							MaxGitDiffLines          int
 | 
				
			||||||
		MaxGitDiffLineCharacters int
 | 
							MaxGitDiffLineCharacters int
 | 
				
			||||||
		MaxGitDiffFiles          int
 | 
							MaxGitDiffFiles          int
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user