diff --git a/history/histweb/histview.go b/history/histweb/histview.go index 4737817..1f59d77 100644 --- a/history/histweb/histview.go +++ b/history/histweb/histview.go @@ -11,6 +11,7 @@ import ( "github.com/bouncepaw/mycorrhiza/util" "github.com/bouncepaw/mycorrhiza/viewutil" "github.com/gorilla/mux" + "html/template" "log" "net/http" "path/filepath" @@ -125,6 +126,7 @@ var ( {{define "diff for at title"}}Разница для {{beautifulName .HyphaName}} для {{.Hash}}{{end}} {{define "diff for at heading"}}Разница для {{beautifulName .HyphaName}} для {{.Hash}}{{end}} +{{define "no text diff available"}}Нет текстовой разницы.{{end}} {{define "count pre"}}Отобразить{{end}} {{define "count post"}}свежих правок.{{end}} @@ -158,15 +160,49 @@ type primitiveDiffData struct { *viewutil.BaseData HyphaName string Hash string - Text string + Text template.HTML } func primitiveDiff(meta viewutil.Meta, h hyphae.Hypha, hash, text string) { + hunks := history.SplitPrimitiveDiff(text) + if len(hunks) > 0 { + var buf strings.Builder + for _, hunk := range hunks { + lines := strings.Split(hunk, "\n") + buf.WriteString(`
`)
+			for i, line := range lines {
+				line = strings.Trim(line, "\r")
+				var class string
+				if len(line) > 0 {
+					switch line[0] {
+					case '+':
+						class = "primitive-diff__addition"
+					case '-':
+						class = "primitive-diff__deletion"
+					case '@':
+						class = "primitive-diff__context"
+					}
+				}
+				if i > 0 {
+					buf.WriteString("\n")
+				}
+				line = template.HTMLEscapeString(line)
+				fmt.Fprintf(&buf, `%s`,
+					class, line)
+			}
+			buf.WriteString(`
`) + } + text = buf.String() + } else if text != "" { + text = template.HTMLEscapeString(text) + text = fmt.Sprintf( + `
%s
`, text) + } viewutil.ExecutePage(meta, chainPrimitiveDiff, primitiveDiffData{ BaseData: &viewutil.BaseData{}, HyphaName: h.CanonicalName(), Hash: hash, - Text: text, + Text: template.HTML(text), }) } diff --git a/history/histweb/view_primitive_diff.html b/history/histweb/view_primitive_diff.html index c2025a0..135f41f 100644 --- a/history/histweb/view_primitive_diff.html +++ b/history/histweb/view_primitive_diff.html @@ -1,11 +1,12 @@ {{define "diff for at title"}}Diff of {{beautifulName .HyphaName}} at {{.Hash}}{{end}} {{define "diff for at heading"}}Diff of {{beautifulName .HyphaName}} at {{.Hash}}{{end}} +{{define "no text diff available"}}No text diff available.{{end}} {{define "title"}}{{template "diff for at title" .}}{{end}} {{define "body"}}

{{template "diff for at heading" .}}

-
{{.Text}}
+ {{if .Text}}{{.Text}}{{else}}{{template "no text diff available" .}}{{end}}
-{{end}} \ No newline at end of file +{{end}} diff --git a/history/revision.go b/history/revision.go index 4817aa1..74759c3 100644 --- a/history/revision.go +++ b/history/revision.go @@ -252,3 +252,21 @@ func PrimitiveDiffAtRevision(filepath, hash string) (string, error) { } return out.String(), err } + +// SplitPrimitiveDiff splits a primitive diff of a single file into hunks. +func SplitPrimitiveDiff(text string) (result []string) { + idx := strings.Index(text, "@@ -") + if idx < 0 { + return + } + text = text[idx:] + for { + idx = strings.Index(text, "\n@@ -") + if idx < 0 { + result = append(result, text) + return + } + result = append(result, text[:idx+1]) + text = text[idx+1:] + } +} diff --git a/static/default.css b/static/default.css index e966da0..8d09d53 100644 --- a/static/default.css +++ b/static/default.css @@ -911,3 +911,21 @@ body[data-rrh-addr^="/interwiki"] main form + form { .img-gallery img { max-width: 100%; max-height: 50vh; } figure { margin: 0; } figcaption { padding-bottom: .5rem; } + +/* + * Primitive diff + */ +.primitive-diff__addition { + color: green; +} +.primitive-diff__deletion { + color: red; +} +.primitive-diff__context { + opacity: .5; +} +@media (prefers-color-scheme: dark) { + .primitive-diff__addition { + color: #4cd74c; + } +}