Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit adaf320

Browse files
committed
fine tune
1 parent 6226d38 commit adaf320

File tree

1 file changed

+23
-19
lines changed

1 file changed

+23
-19
lines changed

services/gitdiff/gitdiff.go

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,9 @@ var (
192192

193193
func diffToHTML(lineWrapperTags []string, diffs []diffmatchpatch.Diff, lineType DiffLineType) string {
194194
buf := bytes.NewBuffer(nil)
195+
// restore the line wrapper tags <span class="line"> and <span class="cl">, if necessary
195196
for _, tag := range lineWrapperTags {
196-
buf.WriteString(tag) // restore the line wrapper tags <span class="line"> and <span class="cl">
197+
buf.WriteString(tag)
197198
}
198199
for _, diff := range diffs {
199200
switch {
@@ -282,6 +283,11 @@ func DiffInlineWithHighlightCode(fileName, language, code string) DiffInline {
282283
return DiffInline{EscapeStatus: status, Content: template.HTML(content)}
283284
}
284285

286+
// HighlightCodeDiff is used to do diff with highlighted HTML code.
287+
// The HTML tags will be replaced by Unicode placeholders: "<span>{TEXT}</span>" => "\uE000{TEXT}\uE001"
288+
// These Unicode placeholders are friendly to the diff.
289+
// Then after diff, the placeholders in diff result will be recovered to the HTML tags.
290+
// It's guaranteed that the tags in final diff result are paired correctly.
285291
type HighlightCodeDiff struct {
286292
placeholderBegin rune
287293
placeholderMaxCount int
@@ -346,34 +352,33 @@ func (hcd *HighlightCodeDiff) diffWithHighlight(filename, language, codeA, codeB
346352
return diffs
347353
}
348354

349-
func (hcd *HighlightCodeDiff) convertToPlaceholders(highlightCode string) string {
355+
func (hcd *HighlightCodeDiff) convertToPlaceholders(htmlCode string) string {
350356
var tagStack []string
351357
res := strings.Builder{}
352-
s := highlightCode
353358

354359
firstRunForLineTags := hcd.lineWrapperTags == nil
355360

356361
// the standard chroma highlight HTML is "<span class="line [hl]"><span class="cl"> ... </span></span>"
357362
for {
358363
// find the next HTML tag
359-
pos1 := strings.IndexByte(s, '<')
360-
pos2 := strings.IndexByte(s, '>')
364+
pos1 := strings.IndexByte(htmlCode, '<')
365+
pos2 := strings.IndexByte(htmlCode, '>')
361366
if pos1 == -1 || pos2 == -1 || pos2 < pos1 {
362367
break
363368
}
364-
tag := s[pos1 : pos2+1]
369+
tag := htmlCode[pos1 : pos2+1]
365370

366371
// write the content before the tag into result string, and consume the tag in the string
367-
res.WriteString(s[:pos1])
368-
s = s[pos2+1:]
372+
res.WriteString(htmlCode[:pos1])
373+
htmlCode = htmlCode[pos2+1:]
369374

370375
// the line wrapper tags should be removed before diff
371376
if strings.HasPrefix(tag, `<span class="line`) || strings.HasPrefix(tag, `<span class="cl"`) {
372377
if firstRunForLineTags {
373378
// if this is the first run for converting, save the line wrapper tags for later use, they should be added back
374379
hcd.lineWrapperTags = append(hcd.lineWrapperTags, tag)
375380
}
376-
s = strings.TrimSuffix(s, "</span>")
381+
htmlCode = strings.TrimSuffix(htmlCode, "</span>")
377382
continue
378383
}
379384

@@ -404,11 +409,11 @@ func (hcd *HighlightCodeDiff) convertToPlaceholders(highlightCode string) string
404409
if placeholder != 0 {
405410
res.WriteRune(placeholder) // use the placeholder to replace the tag
406411
} else {
407-
res.WriteString(tag) // unfortunately, all private use runes has been exhausted, no more placeholder could be used, so do not covert the tag
412+
res.WriteString(tag) // unfortunately, all private use runes has been exhausted, no more placeholder could be used, so do not convert the tag
408413
}
409414
}
410-
411-
res.WriteString(s)
415+
// write the remaining string
416+
res.WriteString(htmlCode)
412417
return res.String()
413418
}
414419

@@ -419,14 +424,15 @@ func (hcd *HighlightCodeDiff) recoverOneDiff(diff *diffmatchpatch.Diff) {
419424
for _, r := range diff.Text {
420425
tag, ok := hcd.placeholderTagMap[r]
421426
if !ok || tag == "" {
422-
sb.WriteRune(r)
427+
sb.WriteRune(r) // if the run is not a placeholder, write it as it is
423428
continue
424429
}
425430
var tagToRecover string
426431
if tag[1] == '/' {
432+
// only get the tag itself, ignore the trailing comment (for how the comment is generated, see the code in `convert` function)
427433
tagToRecover = tag[:strings.IndexByte(tag, '>')+1]
428434
if len(tagStack) == 0 {
429-
continue // if no open tag yet, skip the closed tag
435+
continue // if no open tag in stack yet, skip the closed tag
430436
}
431437
tagStack = tagStack[:len(tagStack)-1]
432438
} else {
@@ -440,13 +446,11 @@ func (hcd *HighlightCodeDiff) recoverOneDiff(diff *diffmatchpatch.Diff) {
440446
// close all open tags
441447
for i := len(tagStack) - 1; i >= 0; i-- {
442448
tagToClose := tagStack[i]
443-
pos := strings.IndexByte(tagToClose, ' ')
444-
if pos == -1 {
445-
pos = strings.IndexByte(tagToClose, '>')
446-
}
449+
// get the closed tag "</span>" from "<span class=...>" or "<span>"
450+
pos := strings.IndexAny(tagToClose, " >")
447451
if pos != -1 {
448452
sb.WriteString("</" + tagToClose[1:pos] + ">")
449-
}
453+
} // else: impossible. every tag was pushed into the stack by the code above and is valid HTML open tag
450454
}
451455
}
452456

0 commit comments

Comments
 (0)