diff options
author | mrsdizzie <info@mrsdizzie.com> | 2020-08-08 06:17:02 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-08 11:17:02 +0100 |
commit | 0171dda7288b73995f929c7627f7292ae81090f2 (patch) | |
tree | 130b5633d4308e589365af1582ab9b23a4136590 /services/gitdiff | |
parent | 96add8c319bd8299bfb8fdd4d98c6f71407e2475 (diff) | |
download | gitea-0171dda7288b73995f929c7627f7292ae81090f2.tar.gz gitea-0171dda7288b73995f929c7627f7292ae81090f2.zip |
Improved diff syntax highlighting fix (#12455)
Make previous fix from #12238 more robust since I saw a case where a diff changes only a single character in a chroma class instead of the entire thing. Add another more complicated test to match.
Co-authored-by: Lauris BH <lauris@nix.lv>
Diffstat (limited to 'services/gitdiff')
-rw-r--r-- | services/gitdiff/gitdiff.go | 47 | ||||
-rw-r--r-- | services/gitdiff/gitdiff_test.go | 10 |
2 files changed, 37 insertions, 20 deletions
diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 85354784d4..fca210bb10 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -16,6 +16,7 @@ import ( "net/url" "os" "os/exec" + "regexp" "sort" "strconv" "strings" @@ -180,55 +181,61 @@ var ( removedCodePrefix = []byte(`<span class="removed-code">`) codeTagSuffix = []byte(`</span>`) ) +var addSpanRegex = regexp.MustCompile(`<span class="[a-z]*$`) func diffToHTML(fileName string, diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML { buf := bytes.NewBuffer(nil) - var addSpan bool + var addSpan string for i := range diffs { switch { case diffs[i].Type == diffmatchpatch.DiffEqual: // Looking for the case where our 3rd party diff library previously detected a string difference // in the middle of a span class because we highlight them first. This happens when added/deleted code - // also changes the chroma class name. If found, just move the openining span code forward into the next section - if addSpan { - diffs[i].Text = "<span class=\"" + diffs[i].Text + // also changes the chroma class name, either partially or fully. If found, just move the openining span code forward into the next section + // see TestDiffToHTML for examples + if len(addSpan) > 0 { + diffs[i].Text = addSpan + diffs[i].Text + addSpan = "" } - if strings.HasSuffix(diffs[i].Text, "<span class=\"") { - addSpan = true - buf.WriteString(strings.TrimSuffix(diffs[i].Text, "<span class=\"")) + m := addSpanRegex.FindStringSubmatchIndex(diffs[i].Text) + if m != nil { + addSpan = diffs[i].Text[m[0]:m[1]] + buf.WriteString(strings.TrimSuffix(diffs[i].Text, addSpan)) } else { - addSpan = false + addSpan = "" buf.WriteString(getLineContent(diffs[i].Text)) } case diffs[i].Type == diffmatchpatch.DiffInsert && lineType == DiffLineAdd: - if addSpan { - addSpan = false - diffs[i].Text = "<span class=\"" + diffs[i].Text + if len(addSpan) > 0 { + diffs[i].Text = addSpan + diffs[i].Text + addSpan = "" } // Print existing closing span first before opening added-code span so it doesn't unintentionally close it if strings.HasPrefix(diffs[i].Text, "</span>") { buf.WriteString("</span>") diffs[i].Text = strings.TrimPrefix(diffs[i].Text, "</span>") } - if strings.HasSuffix(diffs[i].Text, "<span class=\"") { - addSpan = true - diffs[i].Text = strings.TrimSuffix(diffs[i].Text, "<span class=\"") + m := addSpanRegex.FindStringSubmatchIndex(diffs[i].Text) + if m != nil { + addSpan = diffs[i].Text[m[0]:m[1]] + diffs[i].Text = strings.TrimSuffix(diffs[i].Text, addSpan) } buf.Write(addedCodePrefix) buf.WriteString(getLineContent(diffs[i].Text)) buf.Write(codeTagSuffix) case diffs[i].Type == diffmatchpatch.DiffDelete && lineType == DiffLineDel: - if addSpan { - addSpan = false - diffs[i].Text = "<span class=\"" + diffs[i].Text + if len(addSpan) > 0 { + diffs[i].Text = addSpan + diffs[i].Text + addSpan = "" } if strings.HasPrefix(diffs[i].Text, "</span>") { buf.WriteString("</span>") diffs[i].Text = strings.TrimPrefix(diffs[i].Text, "</span>") } - if strings.HasSuffix(diffs[i].Text, "<span class=\"") { - addSpan = true - diffs[i].Text = strings.TrimSuffix(diffs[i].Text, "<span class=\"") + m := addSpanRegex.FindStringSubmatchIndex(diffs[i].Text) + if m != nil { + addSpan = diffs[i].Text[m[0]:m[1]] + diffs[i].Text = strings.TrimSuffix(diffs[i].Text, addSpan) } buf.Write(removedCodePrefix) buf.WriteString(getLineContent(diffs[i].Text)) diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go index dabb49654e..b927abf07b 100644 --- a/services/gitdiff/gitdiff_test.go +++ b/services/gitdiff/gitdiff_test.go @@ -50,6 +50,16 @@ func TestDiffToHTML(t *testing.T) { {Type: dmp.DiffInsert, Text: "</span> <span class=\"o\">||</span> <span class=\"nx\">r</span><span class=\"p\">.</span><span class=\"nx\">GuessLanguage</span><span class=\"p\">)"}, {Type: dmp.DiffEqual, Text: "</span> <span class=\"p\">{</span>"}, }, DiffLineAdd)) + + assertEqual(t, "<span class=\"nx\">tagURL</span> <span class=\"o\">:=</span> <span class=\"removed-code\"><span class=\"nx\">fmt</span><span class=\"p\">.</span><span class=\"nf\">Sprintf</span><span class=\"p\">(</span><span class=\"s\">"## [%s](%s/%s/%s/%s?q=&type=all&state=closed&milestone=%d) - %s"</span><span class=\"p\">,</span> <span class=\"nx\">ge</span><span class=\"p\">.</span><span class=\"nx\">Milestone\"</span></span><span class=\"p\">,</span> <span class=\"nx\">ge</span><span class=\"p\">.</span><span class=\"nx\">BaseURL</span><span class=\"p\">,</span> <span class=\"nx\">ge</span><span class=\"p\">.</span><span class=\"nx\">Owner</span><span class=\"p\">,</span> <span class=\"nx\">ge</span><span class=\"p\">.</span><span class=\"nx\">Repo</span><span class=\"p\">,</span> <span class=\"nx\"><span class=\"removed-code\">from</span><span class=\"p\">,</span> <span class=\"nx\">milestoneID</span><span class=\"p\">,</span> <span class=\"nx\">time</span><span class=\"p\">.</span><span class=\"nf\">Now</span><span class=\"p\">(</span><span class=\"p\">)</span><span class=\"p\">.</span><span class=\"nf\">Format</span><span class=\"p\">(</span><span class=\"s\">"2006-01-02"</span><span class=\"p\">)</span></span><span class=\"p\">)</span>", diffToHTML("", []dmp.Diff{ + {Type: dmp.DiffEqual, Text: "<span class=\"nx\">tagURL</span> <span class=\"o\">:=</span> <span class=\"n"}, + {Type: dmp.DiffDelete, Text: "x\">fmt</span><span class=\"p\">.</span><span class=\"nf\">Sprintf</span><span class=\"p\">(</span><span class=\"s\">"## [%s](%s/%s/%s/%s?q=&type=all&state=closed&milestone=%d) - %s"</span><span class=\"p\">,</span> <span class=\"nx\">ge</span><span class=\"p\">.</span><span class=\"nx\">Milestone\""}, + {Type: dmp.DiffInsert, Text: "f\">getGiteaTagURL</span><span class=\"p\">(</span><span class=\"nx\">client"}, + {Type: dmp.DiffEqual, Text: "</span><span class=\"p\">,</span> <span class=\"nx\">ge</span><span class=\"p\">.</span><span class=\"nx\">BaseURL</span><span class=\"p\">,</span> <span class=\"nx\">ge</span><span class=\"p\">.</span><span class=\"nx\">Owner</span><span class=\"p\">,</span> <span class=\"nx\">ge</span><span class=\"p\">.</span><span class=\"nx\">Repo</span><span class=\"p\">,</span> <span class=\"nx\">"}, + {Type: dmp.DiffDelete, Text: "from</span><span class=\"p\">,</span> <span class=\"nx\">milestoneID</span><span class=\"p\">,</span> <span class=\"nx\">time</span><span class=\"p\">.</span><span class=\"nf\">Now</span><span class=\"p\">(</span><span class=\"p\">)</span><span class=\"p\">.</span><span class=\"nf\">Format</span><span class=\"p\">(</span><span class=\"s\">"2006-01-02"</span><span class=\"p\">)"}, + {Type: dmp.DiffInsert, Text: "ge</span><span class=\"p\">.</span><span class=\"nx\">Milestone</span><span class=\"p\">,</span> <span class=\"nx\">from</span><span class=\"p\">,</span> <span class=\"nx\">milestoneID"}, + {Type: dmp.DiffEqual, Text: "</span><span class=\"p\">)</span>"}, + }, DiffLineDel)) } func TestParsePatch(t *testing.T) { |