web: diff syntax highlighting was never applying !87
merged
merged by cmc on 2026-08-26 22:56 UTC
· krz/gitbay:diff-highlight into main
3 files changed, +23 −3
Layout: unified · split
e2e/diffweb_test.go
+20
| @@ -82,6 +82,15 @@ func TestDiffRendering(t *testing.T) { |
| 82 | if !strings.Contains(body, "class=\"k\"") && !strings.Contains(body, "class=\"kd\"") { |
82 | if !strings.Contains(body, "class=\"k\"") && !strings.Contains(body, "class=\"kd\"") { |
| 83 | t.Error("diff content is not syntax highlighted") |
83 | t.Error("diff content is not syntax highlighted") |
| 84 | } |
84 | } |
| |
85 | // Token classes alone prove nothing: chroma scopes every colour rule |
| |
86 | // under .chroma, and the per-line markup has no wrapper of its own, so |
| |
87 | // the cell has to be that wrapper or the classes are inert. |
| |
88 | if !strings.Contains(body, `<td class="src chroma">`) { |
| |
89 | t.Error("diff cell is not a chroma wrapper, so token classes go unstyled") |
| |
90 | } |
| |
91 | if !strings.Contains(stylesheet(t, inst), ".chroma .k") { |
| |
92 | t.Error("stylesheet has no chroma token rules to match") |
| |
93 | } |
| 85 | // The +/- markers are CSS, so a copied selection is real source. |
94 | // The +/- markers are CSS, so a copied selection is real source. |
| 86 | if strings.Contains(body, `<td class="src">+`) { |
95 | if strings.Contains(body, `<td class="src">+`) { |
| 87 | t.Error("diff markers are in the markup, not the stylesheet") |
96 | t.Error("diff markers are in the markup, not the stylesheet") |
| @@ -107,3 +116,14 @@ func jsonField(blob, name string) string { |
| 107 | } |
116 | } |
| 108 | return rest[:j] |
117 | return rest[:j] |
| 109 | } |
118 | } |
| |
119 | |
| |
120 | // stylesheet fetches the served CSS, so a test can check that a rule the |
| |
121 | // markup depends on actually exists. |
| |
122 | func stylesheet(t *testing.T, inst *instance) string { |
| |
123 | t.Helper() |
| |
124 | status, body := inst.get(t, "/static/style.css") |
| |
125 | if status != 200 { |
| |
126 | t.Fatalf("stylesheet: %d", status) |
| |
127 | } |
| |
128 | return body |
| |
129 | } |
internal/web/static/style.css
+2 −2
| @@ -917,8 +917,8 @@ details.difffold summary:hover { background: var(--fill-subtle); } |
| 917 | summary .fpath { font-family: var(--mono); overflow-wrap: anywhere; } |
917 | summary .fpath { font-family: var(--mono); overflow-wrap: anywhere; } |
| 918 | summary .fpath .was { color: var(--muted); } |
918 | summary .fpath .was { color: var(--muted); } |
| 919 | summary .fstat { margin-left: auto; font-family: var(--mono); white-space: nowrap; } |
919 | summary .fstat { margin-left: auto; font-family: var(--mono); white-space: nowrap; } |
| 920 | details.difffold .add { color: var(--ok); } |
920 | details.difffold summary .add { color: var(--ok); } |
| 921 | details.difffold .del { color: var(--bad); } |
921 | details.difffold summary .del { color: var(--bad); } |
| 922 | details.difffold > .none { padding: var(--sp-3); margin: 0; } |
922 | details.difffold > .none { padding: var(--sp-3); margin: 0; } |
| 923 | details.difffold .tablewrap { border-radius: 0 0 var(--r-md) var(--r-md); } |
923 | details.difffold .tablewrap { border-radius: 0 0 var(--r-md) var(--r-md); } |
| 924 | |
924 | |
internal/web/templates/layout.html
+1 −1
| @@ -128,7 +128,7 @@ |
| 128 | {{else}}<div class="tablewrap"><table class="difftable"> |
128 | {{else}}<div class="tablewrap"><table class="difftable"> |
| 129 | {{range .Lines}}{{if eq .Class "hunk"}}<tr class="hunk"><td class="ln" colspan="2"></td><td class="src">{{.Text}}</td></tr> |
129 | {{range .Lines}}{{if eq .Class "hunk"}}<tr class="hunk"><td class="ln" colspan="2"></td><td class="src">{{.Text}}</td></tr> |
| 130 | {{else if eq .Class "meta"}}<tr class="dmeta"><td class="ln" colspan="2"></td><td class="src">{{.Text}}</td></tr> |
130 | {{else if eq .Class "meta"}}<tr class="dmeta"><td class="ln" colspan="2"></td><td class="src">{{.Text}}</td></tr> |
| 131 | {{else}}<tr class="{{.Class}}"><td class="ln">{{if .OldLine}}{{.OldLine}}{{end}}</td><td class="ln">{{if .NewLine}}{{.NewLine}}{{end}}</td><td class="src">{{if .Code}}{{.Code}}{{else}}{{.Content}}{{end}}</td></tr> |
131 | {{else}}<tr class="{{.Class}}"><td class="ln">{{if .OldLine}}{{.OldLine}}{{end}}</td><td class="ln">{{if .NewLine}}{{.NewLine}}{{end}}</td><td class="src chroma">{{if .Code}}{{.Code}}{{else}}{{.Content}}{{end}}</td></tr> |
| 132 | {{end}}{{range .Threads}}<tr class="threadrow"><td colspan="3"><div class="thread{{if .Resolved}} resolved{{end}}">{{if .Resolved}}<p class="threadstate">resolved by {{.Resolved}}</p>{{end}}{{range .Comments}}<p class="commenthead"><strong>{{.Author}}</strong> <span class="when">{{when .CreatedAt}}</span></p><div class="rendered">{{.BodyHTML}}</div>{{end}}{{template "threadact" dict "ID" .ID "Resolved" .Resolved "Base" $base "Can" $can}}</div></td></tr> |
132 | {{end}}{{range .Threads}}<tr class="threadrow"><td colspan="3"><div class="thread{{if .Resolved}} resolved{{end}}">{{if .Resolved}}<p class="threadstate">resolved by {{.Resolved}}</p>{{end}}{{range .Comments}}<p class="commenthead"><strong>{{.Author}}</strong> <span class="when">{{when .CreatedAt}}</span></p><div class="rendered">{{.BodyHTML}}</div>{{end}}{{template "threadact" dict "ID" .ID "Resolved" .Resolved "Base" $base "Can" $can}}</div></td></tr> |
| 133 | {{end}}{{end}} |
133 | {{end}}{{end}} |
| 134 | </table></div>{{end}} |
134 | </table></div>{{end}} |