Refactor diff formatter

This commit is contained in:
2025-11-15 18:43:05 +09:00
parent 6898264076
commit 6507763e47
4 changed files with 64 additions and 49 deletions

View File

@@ -1,66 +1,60 @@
package format
import (
"bytes"
"html/template"
"strings"
)
func detectLine(data []byte) (int, int) {
lineFeed := bytes.IndexByte(data, '\n')
if lineFeed == -1 {
lineFeed = len(data)
}
lineEnd := lineFeed
if lineEnd > 0 {
c := data[lineEnd-1]
if c == '\r' {
lineEnd -= 1
}
}
nextLine := lineFeed + 1
return lineEnd, nextLine
}
// Diff formats diff text to HTML.
func Diff(text string) string {
data := []byte(text)
index := 0
var html bytes.Buffer
lineNo := 0
for index < len(data) {
lineEnd, nextLine := detectLine(data[index:])
lineEnd += index
nextLine += index
line := data[index:lineEnd]
lineNo += 1
// skip headers
lineNumber := 0
for index < len(text) {
_, index = indexLineEnd(text, index)
if lineNo < 3 {
index = nextLine
continue
lineNumber += 1
if lineNumber >= 3 {
break
}
}
var html strings.Builder
for index < len(text) {
lineEnd, nextLine := indexLineEnd(text, index)
line := text[index:lineEnd]
index = nextLine
if len(line) < 1 {
html.WriteString("<br />\n")
} else {
c := line[0]
htmlLine := template.HTMLEscapeString(string(line))
if c == '+' {
html.WriteString("<span class=\"plus\">+</span>")
html.WriteString("<span class=\"plus-line\">" + htmlLine[1:] + "</span><br />\n")
} else if c == '-' {
html.WriteString("<span class=\"minus\">-</span>")
html.WriteString("<span class=\"minus-line\">" + htmlLine[1:] + "</span><br />\n")
} else if c == '@' {
html.WriteString("<span class=\"hunk\">@")
html.WriteString(htmlLine[1:] + "</span><br />\n")
} else if c == ' ' {
html.WriteString("&nbsp;")
html.WriteString(htmlLine[1:] + "<br />\n")
} else {
html.WriteString(htmlLine + "<br />\n")
}
continue
}
c := line[0]
htmlLine := template.HTMLEscapeString(string(line))
if c == '+' {
html.WriteString("<span class=\"plus\">+</span>")
html.WriteString("<span class=\"plus-line\">")
html.WriteString(htmlLine[1:])
html.WriteString("</span><br />\n")
} else if c == '-' {
html.WriteString("<span class=\"minus\">-</span>")
html.WriteString("<span class=\"minus-line\">")
html.WriteString(htmlLine[1:])
html.WriteString("</span><br />\n")
} else if c == '@' {
html.WriteString("<span class=\"hunk\">@")
html.WriteString(htmlLine[1:])
html.WriteString("</span><br />\n")
} else if c == ' ' {
html.WriteString("&nbsp;")
html.WriteString(htmlLine[1:])
html.WriteString("<br />\n")
} else {
html.WriteString(htmlLine)
html.WriteString("<br />\n")
}
index = nextLine
}
return html.String()

2
internal/format/doc.go Normal file
View File

@@ -0,0 +1,2 @@
// Package format implements markup and other formatters.
package format

View File

@@ -4,7 +4,7 @@ import "testing"
var mockCfg = formatConfig{
image: imageConfig{
domains: []string{"example.org", "example.net"},
domains: []string{"example.org", "example.net"},
extensions: []string{"png", "jpeg"},
},
}

19
internal/format/util.go Normal file
View File

@@ -0,0 +1,19 @@
package format
import "strings"
// indexLineEnd finds line end and start of next line
func indexLineEnd(text string, index int) (int, int) {
lineFeed := strings.IndexByte(text[index:], '\n')
if lineFeed == -1 {
return len(text), len(text)
}
lineFeed += index
lineEnd := lineFeed
if lineEnd > 0 {
if text[lineEnd-1] == '\r' {
lineEnd -= 1
}
}
return lineEnd, lineFeed + 1
}