|
@@ -290,6 +290,9 @@ func init() { |
|
|
diffMatchPatch.DiffEditCost = 100 |
|
|
diffMatchPatch.DiffEditCost = 100 |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var unterminatedEntityRE = regexp.MustCompile(`&[^ ;]*$`) |
|
|
|
|
|
var unstartedEntiyRE = regexp.MustCompile(`^[^ ;]*;`) |
|
|
|
|
|
|
|
|
// GetComputedInlineDiffFor computes inline diff for the given line. |
|
|
// GetComputedInlineDiffFor computes inline diff for the given line. |
|
|
func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) template.HTML { |
|
|
func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) template.HTML { |
|
|
if setting.Git.DisableDiffHighlight { |
|
|
if setting.Git.DisableDiffHighlight { |
|
@@ -329,9 +332,90 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) tem |
|
|
|
|
|
|
|
|
diffRecord := diffMatchPatch.DiffMain(highlight.Code(diffSection.FileName, diff1[1:]), highlight.Code(diffSection.FileName, diff2[1:]), true) |
|
|
diffRecord := diffMatchPatch.DiffMain(highlight.Code(diffSection.FileName, diff1[1:]), highlight.Code(diffSection.FileName, diff2[1:]), true) |
|
|
diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) |
|
|
diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) |
|
|
|
|
|
|
|
|
|
|
|
// Now we need to clean up the split entities |
|
|
|
|
|
diffRecord = unsplitEntities(diffRecord) |
|
|
|
|
|
diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord) |
|
|
|
|
|
|
|
|
return diffToHTML(diffSection.FileName, diffRecord, diffLine.Type) |
|
|
return diffToHTML(diffSection.FileName, diffRecord, diffLine.Type) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// unsplitEntities looks for broken up html entities. It relies on records being presimplified and the data being passed in being valid html |
|
|
|
|
|
func unsplitEntities(records []diffmatchpatch.Diff) []diffmatchpatch.Diff { |
|
|
|
|
|
// Unsplitting entities is simple... |
|
|
|
|
|
// |
|
|
|
|
|
// Iterate through all be the last records because if we're the last record then there's nothing we can do |
|
|
|
|
|
for i := 0; i+1 < len(records); i++ { |
|
|
|
|
|
record := &records[i] |
|
|
|
|
|
|
|
|
|
|
|
// Look for an unterminated entity at the end of the line |
|
|
|
|
|
unterminated := unterminatedEntityRE.FindString(record.Text) |
|
|
|
|
|
if len(unterminated) == 0 { |
|
|
|
|
|
continue |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
switch record.Type { |
|
|
|
|
|
case diffmatchpatch.DiffEqual: |
|
|
|
|
|
// If we're an diff equal we want to give this unterminated entity to our next delete and insert |
|
|
|
|
|
record.Text = record.Text[0 : len(record.Text)-len(unterminated)] |
|
|
|
|
|
records[i+1].Text = unterminated + records[i+1].Text |
|
|
|
|
|
|
|
|
|
|
|
nextType := records[i+1].Type |
|
|
|
|
|
|
|
|
|
|
|
if nextType == diffmatchpatch.DiffEqual { |
|
|
|
|
|
continue |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// if the next in line is a delete then we will want the thing after that to be an insert and so on. |
|
|
|
|
|
oneAfterType := diffmatchpatch.DiffInsert |
|
|
|
|
|
if nextType == diffmatchpatch.DiffInsert { |
|
|
|
|
|
oneAfterType = diffmatchpatch.DiffDelete |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if i+2 < len(records) && records[i+2].Type == oneAfterType { |
|
|
|
|
|
records[i+2].Text = unterminated + records[i+2].Text |
|
|
|
|
|
} else { |
|
|
|
|
|
records = append(records[:i+2], append([]diffmatchpatch.Diff{ |
|
|
|
|
|
{ |
|
|
|
|
|
Type: oneAfterType, |
|
|
|
|
|
Text: unterminated, |
|
|
|
|
|
}}, records[i+2:]...)...) |
|
|
|
|
|
} |
|
|
|
|
|
case diffmatchpatch.DiffDelete: |
|
|
|
|
|
fallthrough |
|
|
|
|
|
case diffmatchpatch.DiffInsert: |
|
|
|
|
|
// if we're an insert or delete we want to claim the terminal bit of the entity from the next equal in line |
|
|
|
|
|
targetType := diffmatchpatch.DiffInsert |
|
|
|
|
|
if record.Type == diffmatchpatch.DiffInsert { |
|
|
|
|
|
targetType = diffmatchpatch.DiffDelete |
|
|
|
|
|
} |
|
|
|
|
|
next := &records[i+1] |
|
|
|
|
|
if next.Type == diffmatchpatch.DiffEqual { |
|
|
|
|
|
// if the next is an equal we need to snaffle the entity end off the start and add an delete/insert |
|
|
|
|
|
if terminal := unstartedEntiyRE.FindString(next.Text); len(terminal) > 0 { |
|
|
|
|
|
record.Text += terminal |
|
|
|
|
|
next.Text = next.Text[len(terminal):] |
|
|
|
|
|
records = append(records[:i+2], append([]diffmatchpatch.Diff{ |
|
|
|
|
|
{ |
|
|
|
|
|
Type: targetType, |
|
|
|
|
|
Text: unterminated, |
|
|
|
|
|
}}, records[i+2:]...)...) |
|
|
|
|
|
} |
|
|
|
|
|
} else if next.Type == targetType { |
|
|
|
|
|
// if the next is an insert we need to snaffle the entity end off the one after that and add it to both. |
|
|
|
|
|
if i+2 < len(records) && records[i+2].Type == diffmatchpatch.DiffEqual { |
|
|
|
|
|
if terminal := unstartedEntiyRE.FindString(records[i+2].Text); len(terminal) > 0 { |
|
|
|
|
|
record.Text += terminal |
|
|
|
|
|
next.Text += terminal |
|
|
|
|
|
records[i+2].Text = records[i+2].Text[len(terminal):] |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return records |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// DiffFile represents a file diff. |
|
|
// DiffFile represents a file diff. |
|
|
type DiffFile struct { |
|
|
type DiffFile struct { |
|
|
Name string |
|
|
Name string |
|
|