From 8ff578974295d803618c56f1766a829f3e54da0f Mon Sep 17 00:00:00 2001
From: oppiliappan
Date: Fri, 18 Jul 2025 20:32:56 +0000
Subject: [PATCH] appview/pages: initial support for split diffs
Signed-off-by: oppiliappan
---
types/diff.go | 26 ++++++++++++++++++++++++++
appview/pages/pages.go | 3 +++
appview/pulls/pulls.go | 6 ++++++
appview/repo/repo.go | 13 ++++++++++++-
appview/pages/templates/repo/commit.html | 2 +-
appview/pages/templates/repo/compare/compare.html | 2 +-
appview/pages/templates/repo/fragments/diff.html | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------
appview/pages/templates/repo/fragments/diffChangedFiles.html | 2 +-
appview/pages/templates/repo/fragments/interdiffFiles.html | 2 +-
appview/pages/templates/repo/pulls/patch.html | 2 +-
appview/pages/templates/repo/pulls/pull.html | 1 -
11 file(s) changed, 170 insertion(s)(+), 46 deletion(s)(-)
diff --git a/types/diff.go b/types/diff.go
--- a/types/diff.go
+++ b/types/diff.go
@@ -5,6 +5,10 @@
"github.com/go-git/go-git/v5/plumbing/object"
)
+type DiffOpts struct {
+ Split bool `json:"split"`
+}
+
type TextFragment struct {
Header string `json:"comment"`
Lines []gitdiff.Line `json:"lines"`
@@ -76,4 +80,26 @@
}
return files
+}
+
+// used by html elements as a unique ID for hrefs
+func (d *Diff) Id() string {
+ return d.Name.New
+}
+
+func (d *Diff) Split() *SplitDiff {
+ fragments := make([]SplitFragment, len(d.TextFragments))
+ for i, fragment := range d.TextFragments {
+ leftLines, rightLines := SeparateLines(&fragment)
+ fragments[i] = SplitFragment{
+ Header: fragment.Header(),
+ LeftLines: leftLines,
+ RightLines: rightLines,
+ }
+ }
+
+ return &SplitDiff{
+ Name: d.Id(),
+ TextFragments: fragments,
+ }
}
diff --git a/appview/pages/pages.go b/appview/pages/pages.go
--- a/appview/pages/pages.go
+++ b/appview/pages/pages.go
@@ -527,6 +527,7 @@
Active string
EmailToDidOrHandle map[string]string
Pipeline *db.Pipeline
+ DiffOpts types.DiffOpts
// singular because it's always going to be just one
VerifiedCommit commitverify.VerifiedCommits
@@ -859,6 +860,7 @@
Round int
Submission *db.PullSubmission
OrderedReactionKinds []db.ReactionKind
+ DiffOpts types.DiffOpts
}
// this name is a mouthful
@@ -964,6 +966,7 @@
Base string
Head string
Diff *types.NiceDiff
+ DiffOpts types.DiffOpts
Active string
}
diff --git a/appview/pulls/pulls.go b/appview/pulls/pulls.go
--- a/appview/pulls/pulls.go
+++ b/appview/pulls/pulls.go
@@ -355,6 +355,11 @@
return
}
+ var diffOpts types.DiffOpts
+ if d := r.URL.Query().Get("diff"); d == "split" {
+ diffOpts.Split = true
+ }
+
pull, ok := r.Context().Value("pull").(*db.Pull)
if !ok {
log.Println("failed to get pull")
@@ -395,6 +400,7 @@
Round: roundIdInt,
Submission: pull.Submissions[roundIdInt],
Diff: &diff,
+ DiffOpts: diffOpts,
})
}
diff --git a/appview/repo/repo.go b/appview/repo/repo.go
--- a/appview/repo/repo.go
+++ b/appview/repo/repo.go
@@ -268,6 +268,11 @@
protocol = "https"
}
+ var diffOpts types.DiffOpts
+ if d := r.URL.Query().Get("diff"); d == "split" {
+ diffOpts.Split = true
+ }
+
if !plumbing.IsHash(ref) {
rp.pages.Error404(w)
return
@@ -321,8 +326,8 @@
EmailToDidOrHandle: emailToDidOrHandle(rp, emailToDidMap),
VerifiedCommit: vc,
Pipeline: pipeline,
+ DiffOpts: diffOpts,
})
- return
}
func (rp *Repo) RepoTree(w http.ResponseWriter, r *http.Request) {
@@ -1269,6 +1274,11 @@
return
}
+ var diffOpts types.DiffOpts
+ if d := r.URL.Query().Get("diff"); d == "split" {
+ diffOpts.Split = true
+ }
+
// if user is navigating to one of
// /compare/{base}/{head}
// /compare/{base}...{head}
@@ -1331,6 +1341,7 @@
Base: base,
Head: head,
Diff: &diff,
+ DiffOpts: diffOpts,
})
}
diff --git a/appview/pages/templates/repo/commit.html b/appview/pages/templates/repo/commit.html
--- a/appview/pages/templates/repo/commit.html
+++ b/appview/pages/templates/repo/commit.html
@@ -119,7 +119,7 @@
{{ end }}
{{ define "contentAfter" }}
- {{ template "repo/fragments/diff" (list .RepoInfo.FullName .Diff) }}
+ {{ template "repo/fragments/diff" (list .RepoInfo.FullName .Diff .DiffOpts) }}
{{end}}
{{ define "contentAfterLeft" }}
diff --git a/appview/pages/templates/repo/compare/compare.html b/appview/pages/templates/repo/compare/compare.html
--- a/appview/pages/templates/repo/compare/compare.html
+++ b/appview/pages/templates/repo/compare/compare.html
@@ -50,7 +50,7 @@
{{ end }}
{{ define "contentAfter" }}
- {{ template "repo/fragments/diff" (list .RepoInfo.FullName .Diff) }}
+ {{ template "repo/fragments/diff" (list .RepoInfo.FullName .Diff .DiffOpts) }}
{{end}}
{{ define "contentAfterLeft" }}
diff --git a/appview/pages/templates/repo/fragments/diff.html b/appview/pages/templates/repo/fragments/diff.html
--- a/appview/pages/templates/repo/fragments/diff.html
+++ b/appview/pages/templates/repo/fragments/diff.html
@@ -1,8 +1,11 @@
{{ define "repo/fragments/diff" }}
{{ $repo := index . 0 }}
{{ $diff := index . 1 }}
+{{ $opts := index . 2 }}
+
{{ $commit := $diff.Commit }}
{{ $diff := $diff.Diff }}
+{{ $isSplit := $opts.Split }}
{{ $this := $commit.This }}
{{ $parent := $commit.Parent }}
@@ -85,45 +88,11 @@
This is a binary file and will not be displayed.
{{ else }}
- {{ $name := .Name.New }}
- {{- range .TextFragments -}}
···
- {{- $oldStart := .OldPosition -}}
- {{- $newStart := .NewPosition -}}
- {{- $lineNrStyle := "min-w-[3.5rem] flex-shrink-0 select-none text-right bg-white dark:bg-gray-800 scroll-mt-10 target:border target:border-amber-500 target:rounded " -}}
- {{- $linkStyle := "text-gray-400 dark:text-gray-500 hover:underline" -}}
- {{- $lineNrSepStyle1 := "" -}}
- {{- $lineNrSepStyle2 := "pr-2" -}}
- {{- range .Lines -}}
- {{- if eq .Op.String "+" -}}
-
-
{{$newStart}}
-
-
{{ .Op.String }}
-
{{ .Line }}
-
- {{- $newStart = add64 $newStart 1 -}}
- {{- end -}}
- {{- if eq .Op.String "-" -}}
-
-
-
{{$oldStart}}
-
{{ .Op.String }}
-
{{ .Line }}
-
- {{- $oldStart = add64 $oldStart 1 -}}
- {{- end -}}
- {{- if eq .Op.String " " -}}
-
-
-
-
{{ .Op.String }}
-
{{ .Line }}
-
- {{- $newStart = add64 $newStart 1 -}}
- {{- $oldStart = add64 $oldStart 1 -}}
- {{- end -}}
- {{- end -}}
- {{- end -}}
+ {{ if $isSplit }}
+ {{- template "repo/fragments/splitDiff" .Split -}}
+ {{ else }}
+ {{- template "repo/fragments/unifiedDiff" . -}}
+ {{ end }}
{{- end -}}
@@ -134,6 +103,115 @@
{{ end }}
{{ end }}
+{{ end }}
+
+{{ define "unifiedDiffLines" }}
+{{ $name := .Name.New }}
+{{- range .TextFragments -}}
···
+ {{- $oldStart := .OldPosition -}}
+ {{- $newStart := .NewPosition -}}
+ {{- $lineNrStyle := "min-w-[3.5rem] flex-shrink-0 select-none text-right bg-white dark:bg-gray-800 target:bg-yellow-200 target:dark:bg-yellow-600" -}}
+ {{- $linkStyle := "text-gray-400 dark:text-gray-500 hover:underline" -}}
+ {{- $lineNrSepStyle1 := "" -}}
+ {{- $lineNrSepStyle2 := "pr-2 border-r border-gray-200 dark:border-gray-700" -}}
+ {{- $containerStyle := "flex min-w-full items-center target:border target:rounded-sm target:border-yellow-200 target:dark:border-yellow-700 scroll-mt-20" -}}
+ {{- $addStyle := "bg-green-100 dark:bg-green-800/30 text-green-700 dark:text-green-400 " -}}
+ {{- $delStyle := "bg-red-100 dark:bg-red-800/30 text-red-700 dark:text-red-400 " -}}
+ {{- $ctxStyle := "bg-white dark:bg-gray-800 text-gray-500 dark:text-gray-400" -}}
+ {{- $opStyle := "w-5 flex-shrink-0 select-none text-center" -}}
+ {{- range .Lines -}}
+ {{- if eq .Op.String "+" -}}
+
+
{{$newStart}}
+
+
{{ .Op.String }}
+
{{ .Line }}
+
+ {{- $newStart = add64 $newStart 1 -}}
+ {{- end -}}
+ {{- if eq .Op.String "-" -}}
+
+
+
{{$oldStart}}
+
{{ .Op.String }}
+
{{ .Line }}
+
+ {{- $oldStart = add64 $oldStart 1 -}}
+ {{- end -}}
+ {{- if eq .Op.String " " -}}
+
+
+
+
{{ .Op.String }}
+
{{ .Line }}
+
+ {{- $newStart = add64 $newStart 1 -}}
+ {{- $oldStart = add64 $oldStart 1 -}}
+ {{- end -}}
+ {{- end -}}
+ {{- end -}}
+{{ end }}
+
+{{ define "splitDiffLines" }}
+{{ $name := .Name.New }}
+{{- $lineNrStyle := "min-w-[3.5rem] flex-shrink-0 select-none text-right bg-white dark:bg-gray-800" -}}
+{{- $linkStyle := "text-gray-400 dark:text-gray-500 hover:underline" -}}
+{{- $lineNrSepStyle := "pr-2 border-r border-gray-200 dark:border-gray-700" -}}
+{{- $containerStyle := "flex min-w-full items-center target:border target:rounded-sm target:border-yellow-200 target:dark:border-yellow-700 scroll-mt-20" -}}
+{{- $emptyStyle := "bg-gray-200/30 dark:bg-gray-700/30" -}}
+{{- $addStyle := "bg-green-100 dark:bg-green-800/30 text-green-700 dark:text-green-400" -}}
+{{- $delStyle := "bg-red-100 dark:bg-red-800/30 text-red-700 dark:text-red-400 " -}}
+{{- $ctxStyle := "bg-white dark:bg-gray-800 text-gray-500 dark:text-gray-400" -}}
+{{- $opStyle := "w-5 flex-shrink-0 select-none text-center" -}}
+
+
{{- range .TextFragments -}}
···
+ {{- range .LeftLines -}}
+ {{- if .IsEmpty -}}
+
+
{{.LineNumber}}
+
{{ .Op.String }}
+
{{ .Content }}
+
+ {{- else if eq .Op.String "-" -}}
+
+
+
{{ .Op.String }}
+
{{ .Content }}
+
+ {{- else if eq .Op.String " " -}}
+
+
+
{{ .Op.String }}
+
{{ .Content }}
+
+ {{- end -}}
+ {{- end -}}
+ {{- end -}}
+
+
{{- range .TextFragments -}}
···
+ {{- range .RightLines -}}
+ {{- if .IsEmpty -}}
+
+
{{.LineNumber}}
+
{{ .Op.String }}
+
{{ .Content }}
+
+ {{- else if eq .Op.String "+" -}}
+
+
+
{{ .Op.String }}
+
{{ .Content }}
+
+ {{- else if eq .Op.String " " -}}
+
+
+
{{ .Op.String }}
+
{{ .Content }}
+
+ {{- end -}}
+ {{- end -}}
+ {{- end -}}
+
{{ end }}
{{ define "statPill" }}
@@ -148,3 +226,4 @@
{{ end }}
{{ end }}
+
diff --git a/appview/pages/templates/repo/fragments/diffChangedFiles.html b/appview/pages/templates/repo/fragments/diffChangedFiles.html
--- a/appview/pages/templates/repo/fragments/diffChangedFiles.html
+++ b/appview/pages/templates/repo/fragments/diffChangedFiles.html
@@ -2,7 +2,7 @@
{{ $stat := .Stat }}
{{ $fileTree := fileTree .ChangedFiles }}
-
+
Changed files
diff --git a/appview/pages/templates/repo/fragments/interdiffFiles.html b/appview/pages/templates/repo/fragments/interdiffFiles.html
--- a/appview/pages/templates/repo/fragments/interdiffFiles.html
+++ b/appview/pages/templates/repo/fragments/interdiffFiles.html
@@ -1,6 +1,6 @@
{{ define "repo/fragments/interdiffFiles" }}
{{ $fileTree := fileTree .AffectedFiles }}
-
+
files
diff --git a/appview/pages/templates/repo/pulls/patch.html b/appview/pages/templates/repo/pulls/patch.html
--- a/appview/pages/templates/repo/pulls/patch.html
+++ b/appview/pages/templates/repo/pulls/patch.html
@@ -74,7 +74,7 @@
{{ end }}
{{ define "contentAfter" }}
- {{ template "repo/fragments/diff" (list .RepoInfo.FullName .Diff) }}
+ {{ template "repo/fragments/diff" (list .RepoInfo.FullName .Diff .DiffOpts) }}
{{end}}
{{ define "contentAfterLeft" }}
diff --git a/appview/pages/templates/repo/pulls/pull.html b/appview/pages/templates/repo/pulls/pull.html
--- a/appview/pages/templates/repo/pulls/pull.html
+++ b/appview/pages/templates/repo/pulls/pull.html
@@ -179,7 +179,6 @@
{{ end }}
-
{{ end }}
{{ end }}
{{ end }}
--
tangled.sh