@@ -16,6 +16,7 @@ import (
1616 "net/url"
1717 "os"
1818 "os/exec"
19+ "regexp"
1920 "sort"
2021 "strconv"
2122 "strings"
@@ -180,55 +181,61 @@ var (
180181 removedCodePrefix = []byte (`<span class="removed-code">` )
181182 codeTagSuffix = []byte (`</span>` )
182183)
184+ var re = regexp .MustCompile (`<span class="[a-z]*$` )
183185
184186func diffToHTML (fileName string , diffs []diffmatchpatch.Diff , lineType DiffLineType ) template.HTML {
185187 buf := bytes .NewBuffer (nil )
186- var addSpan bool
188+ var addSpan string
187189 for i := range diffs {
188190 switch {
189191 case diffs [i ].Type == diffmatchpatch .DiffEqual :
190192 // Looking for the case where our 3rd party diff library previously detected a string difference
191193 // in the middle of a span class because we highlight them first. This happens when added/deleted code
192- // also changes the chroma class name. If found, just move the openining span code forward into the next section
193- if addSpan {
194- diffs [i ].Text = "<span class=\" " + diffs [i ].Text
194+ // also changes the chroma class name, either partially or fully. If found, just move the openining span code forward into the next section
195+ // see TestDiffToHTML for examples
196+ if len (addSpan ) > 0 {
197+ diffs [i ].Text = addSpan + diffs [i ].Text
198+ addSpan = ""
195199 }
196- if strings .HasSuffix (diffs [i ].Text , "<span class=\" " ) {
197- addSpan = true
198- buf .WriteString (strings .TrimSuffix (diffs [i ].Text , "<span class=\" " ))
200+ m := re .FindStringSubmatchIndex (diffs [i ].Text )
201+ if m != nil {
202+ addSpan = diffs [i ].Text [m [0 ]:m [1 ]]
203+ buf .WriteString (strings .TrimSuffix (diffs [i ].Text , addSpan ))
199204 } else {
200- addSpan = false
205+ addSpan = ""
201206 buf .WriteString (getLineContent (diffs [i ].Text ))
202207 }
203208 case diffs [i ].Type == diffmatchpatch .DiffInsert && lineType == DiffLineAdd :
204- if addSpan {
205- addSpan = false
206- diffs [ i ]. Text = "<span class= \" " + diffs [ i ]. Text
209+ if len ( addSpan ) > 0 {
210+ diffs [ i ]. Text = addSpan + diffs [ i ]. Text
211+ addSpan = ""
207212 }
208213 // Print existing closing span first before opening added-code span so it doesn't unintentionally close it
209214 if strings .HasPrefix (diffs [i ].Text , "</span>" ) {
210215 buf .WriteString ("</span>" )
211216 diffs [i ].Text = strings .TrimPrefix (diffs [i ].Text , "</span>" )
212217 }
213- if strings .HasSuffix (diffs [i ].Text , "<span class=\" " ) {
214- addSpan = true
215- diffs [i ].Text = strings .TrimSuffix (diffs [i ].Text , "<span class=\" " )
218+ m := re .FindStringSubmatchIndex (diffs [i ].Text )
219+ if m != nil {
220+ addSpan = diffs [i ].Text [m [0 ]:m [1 ]]
221+ diffs [i ].Text = strings .TrimSuffix (diffs [i ].Text , addSpan )
216222 }
217223 buf .Write (addedCodePrefix )
218224 buf .WriteString (getLineContent (diffs [i ].Text ))
219225 buf .Write (codeTagSuffix )
220226 case diffs [i ].Type == diffmatchpatch .DiffDelete && lineType == DiffLineDel :
221- if addSpan {
222- addSpan = false
223- diffs [ i ]. Text = "<span class= \" " + diffs [ i ]. Text
227+ if len ( addSpan ) > 0 {
228+ diffs [ i ]. Text = addSpan + diffs [ i ]. Text
229+ addSpan = ""
224230 }
225231 if strings .HasPrefix (diffs [i ].Text , "</span>" ) {
226232 buf .WriteString ("</span>" )
227233 diffs [i ].Text = strings .TrimPrefix (diffs [i ].Text , "</span>" )
228234 }
229- if strings .HasSuffix (diffs [i ].Text , "<span class=\" " ) {
230- addSpan = true
231- diffs [i ].Text = strings .TrimSuffix (diffs [i ].Text , "<span class=\" " )
235+ m := re .FindStringSubmatchIndex (diffs [i ].Text )
236+ if m != nil {
237+ addSpan = diffs [i ].Text [m [0 ]:m [1 ]]
238+ diffs [i ].Text = strings .TrimSuffix (diffs [i ].Text , addSpan )
232239 }
233240 buf .Write (removedCodePrefix )
234241 buf .WriteString (getLineContent (diffs [i ].Text ))
0 commit comments