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>
This commit is contained in:
		
							parent
							
								
									96add8c319
								
							
						
					
					
						commit
						0171dda728
					
				| @ -16,6 +16,7 @@ import ( | |||||||
| 	"net/url" | 	"net/url" | ||||||
| 	"os" | 	"os" | ||||||
| 	"os/exec" | 	"os/exec" | ||||||
|  | 	"regexp" | ||||||
| 	"sort" | 	"sort" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
| @ -180,55 +181,61 @@ var ( | |||||||
| 	removedCodePrefix = []byte(`<span class="removed-code">`) | 	removedCodePrefix = []byte(`<span class="removed-code">`) | ||||||
| 	codeTagSuffix     = []byte(`</span>`) | 	codeTagSuffix     = []byte(`</span>`) | ||||||
| ) | ) | ||||||
|  | var addSpanRegex = regexp.MustCompile(`<span class="[a-z]*$`) | ||||||
| 
 | 
 | ||||||
| func diffToHTML(fileName string, diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML { | func diffToHTML(fileName string, diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML { | ||||||
| 	buf := bytes.NewBuffer(nil) | 	buf := bytes.NewBuffer(nil) | ||||||
| 	var addSpan bool | 	var addSpan string | ||||||
| 	for i := range diffs { | 	for i := range diffs { | ||||||
| 		switch { | 		switch { | ||||||
| 		case diffs[i].Type == diffmatchpatch.DiffEqual: | 		case diffs[i].Type == diffmatchpatch.DiffEqual: | ||||||
| 			// Looking for the case where our 3rd party diff library previously detected a string difference
 | 			// 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
 | 			// 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
 | 			// also changes the chroma class name, either partially or fully. If found, just move the openining span code forward into the next section
 | ||||||
| 			if addSpan { | 			// see TestDiffToHTML for examples
 | ||||||
| 				diffs[i].Text = "<span class=\"" + diffs[i].Text | 			if len(addSpan) > 0 { | ||||||
|  | 				diffs[i].Text = addSpan + diffs[i].Text | ||||||
|  | 				addSpan = "" | ||||||
| 			} | 			} | ||||||
| 			if strings.HasSuffix(diffs[i].Text, "<span class=\"") { | 			m := addSpanRegex.FindStringSubmatchIndex(diffs[i].Text) | ||||||
| 				addSpan = true | 			if m != nil { | ||||||
| 				buf.WriteString(strings.TrimSuffix(diffs[i].Text, "<span class=\"")) | 				addSpan = diffs[i].Text[m[0]:m[1]] | ||||||
|  | 				buf.WriteString(strings.TrimSuffix(diffs[i].Text, addSpan)) | ||||||
| 			} else { | 			} else { | ||||||
| 				addSpan = false | 				addSpan = "" | ||||||
| 				buf.WriteString(getLineContent(diffs[i].Text)) | 				buf.WriteString(getLineContent(diffs[i].Text)) | ||||||
| 			} | 			} | ||||||
| 		case diffs[i].Type == diffmatchpatch.DiffInsert && lineType == DiffLineAdd: | 		case diffs[i].Type == diffmatchpatch.DiffInsert && lineType == DiffLineAdd: | ||||||
| 			if addSpan { | 			if len(addSpan) > 0 { | ||||||
| 				addSpan = false | 				diffs[i].Text = addSpan + diffs[i].Text | ||||||
| 				diffs[i].Text = "<span class=\"" + diffs[i].Text | 				addSpan = "" | ||||||
| 			} | 			} | ||||||
| 			// Print existing closing span first before opening added-code span so it doesn't unintentionally close it
 | 			// Print existing closing span first before opening added-code span so it doesn't unintentionally close it
 | ||||||
| 			if strings.HasPrefix(diffs[i].Text, "</span>") { | 			if strings.HasPrefix(diffs[i].Text, "</span>") { | ||||||
| 				buf.WriteString("</span>") | 				buf.WriteString("</span>") | ||||||
| 				diffs[i].Text = strings.TrimPrefix(diffs[i].Text, "</span>") | 				diffs[i].Text = strings.TrimPrefix(diffs[i].Text, "</span>") | ||||||
| 			} | 			} | ||||||
| 			if strings.HasSuffix(diffs[i].Text, "<span class=\"") { | 			m := addSpanRegex.FindStringSubmatchIndex(diffs[i].Text) | ||||||
| 				addSpan = true | 			if m != nil { | ||||||
| 				diffs[i].Text = strings.TrimSuffix(diffs[i].Text, "<span class=\"") | 				addSpan = diffs[i].Text[m[0]:m[1]] | ||||||
|  | 				diffs[i].Text = strings.TrimSuffix(diffs[i].Text, addSpan) | ||||||
| 			} | 			} | ||||||
| 			buf.Write(addedCodePrefix) | 			buf.Write(addedCodePrefix) | ||||||
| 			buf.WriteString(getLineContent(diffs[i].Text)) | 			buf.WriteString(getLineContent(diffs[i].Text)) | ||||||
| 			buf.Write(codeTagSuffix) | 			buf.Write(codeTagSuffix) | ||||||
| 		case diffs[i].Type == diffmatchpatch.DiffDelete && lineType == DiffLineDel: | 		case diffs[i].Type == diffmatchpatch.DiffDelete && lineType == DiffLineDel: | ||||||
| 			if addSpan { | 			if len(addSpan) > 0 { | ||||||
| 				addSpan = false | 				diffs[i].Text = addSpan + diffs[i].Text | ||||||
| 				diffs[i].Text = "<span class=\"" + diffs[i].Text | 				addSpan = "" | ||||||
| 			} | 			} | ||||||
| 			if strings.HasPrefix(diffs[i].Text, "</span>") { | 			if strings.HasPrefix(diffs[i].Text, "</span>") { | ||||||
| 				buf.WriteString("</span>") | 				buf.WriteString("</span>") | ||||||
| 				diffs[i].Text = strings.TrimPrefix(diffs[i].Text, "</span>") | 				diffs[i].Text = strings.TrimPrefix(diffs[i].Text, "</span>") | ||||||
| 			} | 			} | ||||||
| 			if strings.HasSuffix(diffs[i].Text, "<span class=\"") { | 			m := addSpanRegex.FindStringSubmatchIndex(diffs[i].Text) | ||||||
| 				addSpan = true | 			if m != nil { | ||||||
| 				diffs[i].Text = strings.TrimSuffix(diffs[i].Text, "<span class=\"") | 				addSpan = diffs[i].Text[m[0]:m[1]] | ||||||
|  | 				diffs[i].Text = strings.TrimSuffix(diffs[i].Text, addSpan) | ||||||
| 			} | 			} | ||||||
| 			buf.Write(removedCodePrefix) | 			buf.Write(removedCodePrefix) | ||||||
| 			buf.WriteString(getLineContent(diffs[i].Text)) | 			buf.WriteString(getLineContent(diffs[i].Text)) | ||||||
|  | |||||||
| @ -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.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>"}, | 		{Type: dmp.DiffEqual, Text: "</span> <span class=\"p\">{</span>"}, | ||||||
| 	}, DiffLineAdd)) | 	}, 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) { | func TestParsePatch(t *testing.T) { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user