@@ -298,15 +298,21 @@ func (hcd *highlightCodeDiff) convertToPlaceholders(htmlContent template.HTML) s
298298 return res .String ()
299299}
300300
301- func (hcd * highlightCodeDiff ) extractNextPlaceholder (buf []byte , lastIdx int ) (idx int , placeholder rune , runeLen int , token string ) {
302- for idx = lastIdx ; idx < len (buf ); {
303- placeholder , runeLen = utf8 .DecodeRune (buf [idx :])
304- if token = hcd .placeholderTokenMap [placeholder ]; token != "" {
305- break
301+ // recoverOneRune tries to recover one rune
302+ // * if the rune is a placeholder, it will be recovered to the corresponding content
303+ // * otherwise it will be returned as is
304+ func (hcd * highlightCodeDiff ) recoverOneRune (buf []byte ) (r rune , runeLen int , isSingleTag bool , recovered string ) {
305+ r , runeLen = utf8 .DecodeRune (buf )
306+ token := hcd .placeholderTokenMap [r ]
307+ if token == "" {
308+ return r , runeLen , false , "" // rune itself, not a placeholder
309+ } else if token [0 ] == '<' {
310+ if token [1 ] == '<' {
311+ return 0 , runeLen , false , token [1 : len (token )- 1 ] // full tag `<<span>content</span>>`, recover to `<span>content</span>`
306312 }
307- idx += runeLen
313+ return r , runeLen , true , token // single tag
308314 }
309- return idx , placeholder , runeLen , token
315+ return 0 , runeLen , false , token // HTML entity
310316}
311317
312318func (hcd * highlightCodeDiff ) recoverOneDiff (str string ) template.HTML {
@@ -315,49 +321,65 @@ func (hcd *highlightCodeDiff) recoverOneDiff(str string) template.HTML {
315321 var diffCodeOpenTag string
316322 diffCodeCloseTag := hcd .placeholderTokenMap [hcd .diffCodeClose ]
317323 strBytes := util .UnsafeStringToBytes (str )
324+
325+ // this loop is slightly longer than expected, for performance consideration
318326 for idx := 0 ; idx < len (strBytes ); {
319- newIdx , placeholder , lastRuneLen , token := hcd .extractNextPlaceholder (strBytes , idx )
320- if newIdx != idx {
327+ // take a look at the next rune
328+ r , runeLen , isSingleTag , recovered := hcd .recoverOneRune (strBytes [idx :])
329+ idx += runeLen
330+
331+ // loop section 1: if it isn't a single tag, then try to find the following runes until the next single tag, and recover them together
332+ if ! isSingleTag {
321333 if diffCodeOpenTag != "" {
334+ // start the "added/removed diff tag" if the current token is in the diff part
322335 sb .WriteString (diffCodeOpenTag )
323- sb .Write (strBytes [idx :newIdx ])
324- sb .WriteString (diffCodeCloseTag )
336+ }
337+ if recovered != "" {
338+ sb .WriteString (recovered )
325339 } else {
326- sb .Write (strBytes [idx :newIdx ])
340+ sb .WriteRune (r )
341+ }
342+ // inner loop to recover following runes until the next single tag
343+ for idx < len (strBytes ) {
344+ r , runeLen , isSingleTag , recovered = hcd .recoverOneRune (strBytes [idx :])
345+ idx += runeLen
346+ if isSingleTag {
347+ break
348+ }
349+ if recovered != "" {
350+ sb .WriteString (recovered )
351+ } else {
352+ sb .WriteRune (r )
353+ }
354+ }
355+ if diffCodeOpenTag != "" {
356+ // end the "added/removed diff tag" if the current token is in the diff part
357+ sb .WriteString (diffCodeCloseTag )
327358 }
328- } // else: no text content before, the current token is a placeholder
329- if token == "" {
330- break // reaches the string end, no more placeholder
331359 }
332- idx = newIdx + lastRuneLen
333360
334- // for HTML entity
335- if token [0 ] == '&' {
336- sb .WriteString (token )
337- continue
361+ if ! isSingleTag {
362+ break // the inner loop has already consumed all remaining runes, no more single tag found
338363 }
339364
340- // for various HTML tags
341- var recovered string
342- if token [1 ] == '<' { // full tag `<<span>content</span>>`, recover to `<span>content</span>`
343- recovered = token [1 : len (token )- 1 ]
344- if diffCodeOpenTag != "" {
345- recovered = diffCodeOpenTag + recovered + diffCodeCloseTag
346- } // else: just use the recovered content
347- } else if token [1 ] != '/' { // opening tag
365+ // loop section 2: for opening/closing HTML tags
366+ placeholder := r
367+ if recovered [1 ] != '/' { // opening tag
348368 if placeholder == hcd .diffCodeAddedOpen || placeholder == hcd .diffCodeRemovedOpen {
349- diffCodeOpenTag = token
369+ diffCodeOpenTag = recovered
370+ recovered = ""
350371 } else {
351- recovered = token
352372 tagStack = append (tagStack , recovered )
353373 }
354374 } else { // closing tag
355375 if placeholder == hcd .diffCodeClose {
356376 diffCodeOpenTag = "" // the highlighted diff is closed, no more diff
377+ recovered = ""
357378 } else if len (tagStack ) != 0 {
358- recovered = token
359379 tagStack = tagStack [:len (tagStack )- 1 ]
360- } // else: if no opening tag in stack yet, skip the closing tag
380+ } else {
381+ recovered = ""
382+ }
361383 }
362384 sb .WriteString (recovered )
363385 }
0 commit comments