Monorepo for Tangled tangled.org

appview/pages: initial support for split diffs

Signed-off-by: oppiliappan <me@oppi.li>

oppi.li 4c477c06 56590c67

verified
Changed files
+170 -46
appview
types
+3
appview/pages/pages.go
··· 527 527 Active string 528 528 EmailToDidOrHandle map[string]string 529 529 Pipeline *db.Pipeline 530 + DiffOpts types.DiffOpts 530 531 531 532 // singular because it's always going to be just one 532 533 VerifiedCommit commitverify.VerifiedCommits ··· 859 860 Round int 860 861 Submission *db.PullSubmission 861 862 OrderedReactionKinds []db.ReactionKind 863 + DiffOpts types.DiffOpts 862 864 } 863 865 864 866 // this name is a mouthful ··· 964 966 Base string 965 967 Head string 966 968 Diff *types.NiceDiff 969 + DiffOpts types.DiffOpts 967 970 968 971 Active string 969 972 }
+1 -1
appview/pages/templates/repo/commit.html
··· 119 119 {{ end }} 120 120 121 121 {{ define "contentAfter" }} 122 - {{ template "repo/fragments/diff" (list .RepoInfo.FullName .Diff) }} 122 + {{ template "repo/fragments/diff" (list .RepoInfo.FullName .Diff .DiffOpts) }} 123 123 {{end}} 124 124 125 125 {{ define "contentAfterLeft" }}
+1 -1
appview/pages/templates/repo/compare/compare.html
··· 50 50 {{ end }} 51 51 52 52 {{ define "contentAfter" }} 53 - {{ template "repo/fragments/diff" (list .RepoInfo.FullName .Diff) }} 53 + {{ template "repo/fragments/diff" (list .RepoInfo.FullName .Diff .DiffOpts) }} 54 54 {{end}} 55 55 56 56 {{ define "contentAfterLeft" }}
+118 -39
appview/pages/templates/repo/fragments/diff.html
··· 1 1 {{ define "repo/fragments/diff" }} 2 2 {{ $repo := index . 0 }} 3 3 {{ $diff := index . 1 }} 4 + {{ $opts := index . 2 }} 5 + 4 6 {{ $commit := $diff.Commit }} 5 7 {{ $diff := $diff.Diff }} 8 + {{ $isSplit := $opts.Split }} 6 9 {{ $this := $commit.This }} 7 10 {{ $parent := $commit.Parent }} 8 11 ··· 85 88 This is a binary file and will not be displayed. 86 89 </p> 87 90 {{ else }} 88 - {{ $name := .Name.New }} 89 - <pre class="overflow-x-auto"><div class="overflow-x-auto"><div class="min-w-full inline-block">{{- range .TextFragments -}}<div class="bg-gray-100 dark:bg-gray-700 text-gray-500 dark:text-gray-400 select-none text-center">&middot;&middot;&middot;</div> 90 - {{- $oldStart := .OldPosition -}} 91 - {{- $newStart := .NewPosition -}} 92 - {{- $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 " -}} 93 - {{- $linkStyle := "text-gray-400 dark:text-gray-500 hover:underline" -}} 94 - {{- $lineNrSepStyle1 := "" -}} 95 - {{- $lineNrSepStyle2 := "pr-2" -}} 96 - {{- range .Lines -}} 97 - {{- if eq .Op.String "+" -}} 98 - <div class="bg-green-100 dark:bg-green-800/30 text-green-700 dark:text-green-400 flex min-w-full items-center"> 99 - <div class="{{$lineNrStyle}} {{$lineNrSepStyle1}}"><span aria-hidden="true" class="invisible">{{$newStart}}</span></div> 100 - <div class="{{$lineNrStyle}} {{$lineNrSepStyle2}}" id="{{$name}}-N{{$newStart}}"><a class="{{$linkStyle}}" href="#{{$name}}-N{{$newStart}}">{{ $newStart }}</a></div> 101 - <div class="w-5 flex-shrink-0 select-none text-center">{{ .Op.String }}</div> 102 - <div class="px-2">{{ .Line }}</div> 103 - </div> 104 - {{- $newStart = add64 $newStart 1 -}} 105 - {{- end -}} 106 - {{- if eq .Op.String "-" -}} 107 - <div class="bg-red-100 dark:bg-red-800/30 text-red-700 dark:text-red-400 flex min-w-full items-center"> 108 - <div class="{{$lineNrStyle}} {{$lineNrSepStyle1}}" id="{{$name}}-O{{$oldStart}}"><a class="{{$linkStyle}}" href="#{{$name}}-O{{$oldStart}}">{{ $oldStart }}</a></div> 109 - <div class="{{$lineNrStyle}} {{$lineNrSepStyle2}}"><span aria-hidden="true" class="invisible">{{$oldStart}}</span></div> 110 - <div class="w-5 flex-shrink-0 select-none text-center">{{ .Op.String }}</div> 111 - <div class="px-2">{{ .Line }}</div> 112 - </div> 113 - {{- $oldStart = add64 $oldStart 1 -}} 114 - {{- end -}} 115 - {{- if eq .Op.String " " -}} 116 - <div class="bg-white dark:bg-gray-800 text-gray-500 dark:text-gray-400 flex min-w-full items-center"> 117 - <div class="{{$lineNrStyle}} {{$lineNrSepStyle1}}" id="{{$name}}-O{{$oldStart}}"><a class="{{$linkStyle}}" href="#{{$name}}-O{{$oldStart}}">{{ $oldStart }}</a></div> 118 - <div class="{{$lineNrStyle}} {{$lineNrSepStyle2}}" id="{{$name}}-N{{$newStart}}"><a class="{{$linkStyle}}" href="#{{$name}}-N{{$newStart}}">{{ $newStart }}</a></div> 119 - <div class="w-5 flex-shrink-0 select-none text-center">{{ .Op.String }}</div> 120 - <div class="px-2">{{ .Line }}</div> 121 - </div> 122 - {{- $newStart = add64 $newStart 1 -}} 123 - {{- $oldStart = add64 $oldStart 1 -}} 124 - {{- end -}} 125 - {{- end -}} 126 - {{- end -}}</div></div></pre> 91 + {{ if $isSplit }} 92 + {{- template "repo/fragments/splitDiff" .Split -}} 93 + {{ else }} 94 + {{- template "repo/fragments/unifiedDiff" . -}} 95 + {{ end }} 127 96 {{- end -}} 128 97 </div> 129 98 ··· 136 105 {{ end }} 137 106 {{ end }} 138 107 108 + {{ define "unifiedDiffLines" }} 109 + {{ $name := .Name.New }} 110 + <pre class="overflow-x-auto"><div class="overflow-x-auto"><div class="min-w-full inline-block">{{- range .TextFragments -}}<div class="bg-gray-100 dark:bg-gray-700 text-gray-500 dark:text-gray-400 select-none text-center">&middot;&middot;&middot;</div> 111 + {{- $oldStart := .OldPosition -}} 112 + {{- $newStart := .NewPosition -}} 113 + {{- $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" -}} 114 + {{- $linkStyle := "text-gray-400 dark:text-gray-500 hover:underline" -}} 115 + {{- $lineNrSepStyle1 := "" -}} 116 + {{- $lineNrSepStyle2 := "pr-2 border-r border-gray-200 dark:border-gray-700" -}} 117 + {{- $containerStyle := "flex min-w-full items-center target:border target:rounded-sm target:border-yellow-200 target:dark:border-yellow-700 scroll-mt-20" -}} 118 + {{- $addStyle := "bg-green-100 dark:bg-green-800/30 text-green-700 dark:text-green-400 " -}} 119 + {{- $delStyle := "bg-red-100 dark:bg-red-800/30 text-red-700 dark:text-red-400 " -}} 120 + {{- $ctxStyle := "bg-white dark:bg-gray-800 text-gray-500 dark:text-gray-400" -}} 121 + {{- $opStyle := "w-5 flex-shrink-0 select-none text-center" -}} 122 + {{- range .Lines -}} 123 + {{- if eq .Op.String "+" -}} 124 + <div class="{{ $addStyle }} {{ $containerStyle }}" id="{{$name}}-N{{$newStart}}"> 125 + <div class="{{$lineNrStyle}} {{$lineNrSepStyle1}}"><span aria-hidden="true" class="invisible">{{$newStart}}</span></div> 126 + <div class="{{$lineNrStyle}} {{$lineNrSepStyle2}}"><a class="{{$linkStyle}}" href="#{{$name}}-N{{$newStart}}">{{ $newStart }}</a></div> 127 + <div class="{{ $opStyle }}">{{ .Op.String }}</div> 128 + <div class="px-2">{{ .Line }}</div> 129 + </div> 130 + {{- $newStart = add64 $newStart 1 -}} 131 + {{- end -}} 132 + {{- if eq .Op.String "-" -}} 133 + <div class="{{ $delStyle }} {{ $containerStyle }}" id="{{$name}}-O{{$oldStart}}"> 134 + <div class="{{$lineNrStyle}} {{$lineNrSepStyle1}}"><a class="{{$linkStyle}}" href="#{{$name}}-O{{$oldStart}}">{{ $oldStart }}</a></div> 135 + <div class="{{$lineNrStyle}} {{$lineNrSepStyle2}}"><span aria-hidden="true" class="invisible">{{$oldStart}}</span></div> 136 + <div class="{{ $opStyle }}">{{ .Op.String }}</div> 137 + <div class="px-2">{{ .Line }}</div> 138 + </div> 139 + {{- $oldStart = add64 $oldStart 1 -}} 140 + {{- end -}} 141 + {{- if eq .Op.String " " -}} 142 + <div class="{{ $ctxStyle }} {{ $containerStyle }}" id="{{$name}}-O{{$oldStart}}-N{{$newStart}}"> 143 + <div class="{{$lineNrStyle}} {{$lineNrSepStyle1}}"><a class="{{$linkStyle}}" href="#{{$name}}-O{{$oldStart}}-N{{$newStart}}">{{ $oldStart }}</a></div> 144 + <div class="{{$lineNrStyle}} {{$lineNrSepStyle2}}"><a class="{{$linkStyle}}" href="#{{$name}}-O{{$oldStart}}-N{{$newStart}}">{{ $newStart }}</a></div> 145 + <div class="{{ $opStyle }}">{{ .Op.String }}</div> 146 + <div class="px-2">{{ .Line }}</div> 147 + </div> 148 + {{- $newStart = add64 $newStart 1 -}} 149 + {{- $oldStart = add64 $oldStart 1 -}} 150 + {{- end -}} 151 + {{- end -}} 152 + {{- end -}}</div></div></pre> 153 + {{ end }} 154 + 155 + {{ define "splitDiffLines" }} 156 + {{ $name := .Name.New }} 157 + {{- $lineNrStyle := "min-w-[3.5rem] flex-shrink-0 select-none text-right bg-white dark:bg-gray-800" -}} 158 + {{- $linkStyle := "text-gray-400 dark:text-gray-500 hover:underline" -}} 159 + {{- $lineNrSepStyle := "pr-2 border-r border-gray-200 dark:border-gray-700" -}} 160 + {{- $containerStyle := "flex min-w-full items-center target:border target:rounded-sm target:border-yellow-200 target:dark:border-yellow-700 scroll-mt-20" -}} 161 + {{- $emptyStyle := "bg-gray-200/30 dark:bg-gray-700/30" -}} 162 + {{- $addStyle := "bg-green-100 dark:bg-green-800/30 text-green-700 dark:text-green-400" -}} 163 + {{- $delStyle := "bg-red-100 dark:bg-red-800/30 text-red-700 dark:text-red-400 " -}} 164 + {{- $ctxStyle := "bg-white dark:bg-gray-800 text-gray-500 dark:text-gray-400" -}} 165 + {{- $opStyle := "w-5 flex-shrink-0 select-none text-center" -}} 166 + <div class="grid grid-cols-2 divide-x divide-gray-200 dark:divide-gray-700"> 167 + <pre class="overflow-x-auto col-span-1"><div class="overflow-x-auto"><div class="min-w-full inline-block">{{- range .TextFragments -}}<div class="bg-gray-100 dark:bg-gray-700 text-gray-500 dark:text-gray-400 select-none text-center">&middot;&middot;&middot;</div> 168 + {{- range .LeftLines -}} 169 + {{- if .IsEmpty -}} 170 + <div class="{{ $emptyStyle }} {{ $containerStyle }}"> 171 + <div class="{{$lineNrStyle}} {{$lineNrSepStyle}}"><span aria-hidden="true" class="invisible">{{.LineNumber}}</span></div> 172 + <div class="{{ $opStyle }}"><span aria-hidden="true" class="invisible">{{ .Op.String }}</span></div> 173 + <div class="px-2 invisible" aria-hidden="true">{{ .Content }}</div> 174 + </div> 175 + {{- else if eq .Op.String "-" -}} 176 + <div class="{{ $delStyle }} {{ $containerStyle }}" id="{{$name}}-O{{.LineNumber}}"> 177 + <div class="{{ $lineNrStyle }} {{ $lineNrSepStyle }}"><a class="{{$linkStyle}}" href="#{{$name}}-O{{.LineNumber}}">{{ .LineNumber }}</a></div> 178 + <div class="{{ $opStyle }}">{{ .Op.String }}</div> 179 + <div class="px-2">{{ .Content }}</div> 180 + </div> 181 + {{- else if eq .Op.String " " -}} 182 + <div class="{{ $ctxStyle }} {{ $containerStyle }}" id="{{$name}}-O{{.LineNumber}}"> 183 + <div class="{{ $lineNrStyle }} {{ $lineNrSepStyle }}"><a class="{{$linkStyle}}" href="#{{$name}}-O{{.LineNumber}}">{{ .LineNumber }}</a></div> 184 + <div class="{{ $opStyle }}">{{ .Op.String }}</div> 185 + <div class="px-2">{{ .Content }}</div> 186 + </div> 187 + {{- end -}} 188 + {{- end -}} 189 + {{- end -}}</div></div></pre> 190 + 191 + <pre class="overflow-x-auto col-span-1"><div class="overflow-x-auto"><div class="min-w-full inline-block">{{- range .TextFragments -}}<div class="bg-gray-100 dark:bg-gray-700 text-gray-500 dark:text-gray-400 select-none text-center">&middot;&middot;&middot;</div> 192 + {{- range .RightLines -}} 193 + {{- if .IsEmpty -}} 194 + <div class="{{ $emptyStyle }} {{ $containerStyle }}"> 195 + <div class="{{$lineNrStyle}} {{$lineNrSepStyle}}"><span aria-hidden="true" class="invisible">{{.LineNumber}}</span></div> 196 + <div class="{{ $opStyle }}"><span aria-hidden="true" class="invisible">{{ .Op.String }}</span></div> 197 + <div class="px-2 invisible" aria-hidden="true">{{ .Content }}</div> 198 + </div> 199 + {{- else if eq .Op.String "+" -}} 200 + <div class="{{ $addStyle }} {{ $containerStyle }}" id="{{$name}}-N{{.LineNumber}}"> 201 + <div class="{{$lineNrStyle}} {{$lineNrSepStyle}}"><a class="{{$linkStyle}}" href="#{{$name}}-N{{.LineNumber}}">{{ .LineNumber }}</a></div> 202 + <div class="{{ $opStyle }}">{{ .Op.String }}</div> 203 + <div class="px-2" >{{ .Content }}</div> 204 + </div> 205 + {{- else if eq .Op.String " " -}} 206 + <div class="{{ $ctxStyle }} {{ $containerStyle }}" id="{{$name}}-N{{.LineNumber}}"> 207 + <div class="{{$lineNrStyle}} {{$lineNrSepStyle}}"><a class="{{$linkStyle}}" href="#{{$name}}-N{{.LineNumber}}">{{ .LineNumber }}</a></div> 208 + <div class="{{ $opStyle }}">{{ .Op.String }}</div> 209 + <div class="px-2">{{ .Content }}</div> 210 + </div> 211 + {{- end -}} 212 + {{- end -}} 213 + {{- end -}}</div></div></pre> 214 + </div> 215 + {{ end }} 216 + 139 217 {{ define "statPill" }} 140 218 <div class="flex items-center font-mono text-sm"> 141 219 {{ if and .Insertions .Deletions }} ··· 148 226 {{ end }} 149 227 </div> 150 228 {{ end }} 229 +
+1 -1
appview/pages/templates/repo/fragments/diffChangedFiles.html
··· 2 2 {{ $stat := .Stat }} 3 3 {{ $fileTree := fileTree .ChangedFiles }} 4 4 <div class="col-span-1 md:col-span-2 mt-4"> 5 - <section class="sticky top-0 overflow-x-auto px-6 py-4 border border-gray-200 dark:border-gray-700 w-full mx-auto rounded bg-white dark:bg-gray-800 drop-shadow-sm"> 5 + <section class="sticky top-0 overflow-x-auto text-sm px-6 py-2 border border-gray-200 dark:border-gray-700 w-full mx-auto md:min-h-screen rounded bg-white dark:bg-gray-800 drop-shadow-sm"> 6 6 <div class="diff-stat"> 7 7 <div class="flex gap-2 items-center"> 8 8 <strong class="text-sm uppercase dark:text-gray-200">Changed files</strong>
+1 -1
appview/pages/templates/repo/fragments/interdiffFiles.html
··· 1 1 {{ define "repo/fragments/interdiffFiles" }} 2 2 {{ $fileTree := fileTree .AffectedFiles }} 3 - <section class="mt-4 p-6 border border-gray-200 dark:border-gray-700 w-full mx-auto rounded bg-white dark:bg-gray-800 drop-shadow-sm"> 3 + <section class="mt-4 px-6 py-2 border border-gray-200 dark:border-gray-700 w-full mx-auto rounded bg-white dark:bg-gray-800 drop-shadow-sm md:min-h-screen text-sm"> 4 4 <div class="diff-stat"> 5 5 <div class="flex gap-2 items-center"> 6 6 <strong class="text-sm uppercase dark:text-gray-200">files</strong>
+1 -1
appview/pages/templates/repo/pulls/patch.html
··· 74 74 {{ end }} 75 75 76 76 {{ define "contentAfter" }} 77 - {{ template "repo/fragments/diff" (list .RepoInfo.FullName .Diff) }} 77 + {{ template "repo/fragments/diff" (list .RepoInfo.FullName .Diff .DiffOpts) }} 78 78 {{end}} 79 79 80 80 {{ define "contentAfterLeft" }}
-1
appview/pages/templates/repo/pulls/pull.html
··· 179 179 {{ end }} 180 180 </div> 181 181 </details> 182 - <hr class="md:hidden border-t border-gray-300 dark:border-gray-600"/> 183 182 {{ end }} 184 183 {{ end }} 185 184 {{ end }}
+6
appview/pulls/pulls.go
··· 355 355 return 356 356 } 357 357 358 + var diffOpts types.DiffOpts 359 + if d := r.URL.Query().Get("diff"); d == "split" { 360 + diffOpts.Split = true 361 + } 362 + 358 363 pull, ok := r.Context().Value("pull").(*db.Pull) 359 364 if !ok { 360 365 log.Println("failed to get pull") ··· 395 400 Round: roundIdInt, 396 401 Submission: pull.Submissions[roundIdInt], 397 402 Diff: &diff, 403 + DiffOpts: diffOpts, 398 404 }) 399 405 400 406 }
+12 -1
appview/repo/repo.go
··· 268 268 protocol = "https" 269 269 } 270 270 271 + var diffOpts types.DiffOpts 272 + if d := r.URL.Query().Get("diff"); d == "split" { 273 + diffOpts.Split = true 274 + } 275 + 271 276 if !plumbing.IsHash(ref) { 272 277 rp.pages.Error404(w) 273 278 return ··· 321 326 EmailToDidOrHandle: emailToDidOrHandle(rp, emailToDidMap), 322 327 VerifiedCommit: vc, 323 328 Pipeline: pipeline, 329 + DiffOpts: diffOpts, 324 330 }) 325 - return 326 331 } 327 332 328 333 func (rp *Repo) RepoTree(w http.ResponseWriter, r *http.Request) { ··· 1269 1274 return 1270 1275 } 1271 1276 1277 + var diffOpts types.DiffOpts 1278 + if d := r.URL.Query().Get("diff"); d == "split" { 1279 + diffOpts.Split = true 1280 + } 1281 + 1272 1282 // if user is navigating to one of 1273 1283 // /compare/{base}/{head} 1274 1284 // /compare/{base}...{head} ··· 1331 1341 Base: base, 1332 1342 Head: head, 1333 1343 Diff: &diff, 1344 + DiffOpts: diffOpts, 1334 1345 }) 1335 1346 1336 1347 }
+26
types/diff.go
··· 5 5 "github.com/go-git/go-git/v5/plumbing/object" 6 6 ) 7 7 8 + type DiffOpts struct { 9 + Split bool `json:"split"` 10 + } 11 + 8 12 type TextFragment struct { 9 13 Header string `json:"comment"` 10 14 Lines []gitdiff.Line `json:"lines"` ··· 77 81 78 82 return files 79 83 } 84 + 85 + // used by html elements as a unique ID for hrefs 86 + func (d *Diff) Id() string { 87 + return d.Name.New 88 + } 89 + 90 + func (d *Diff) Split() *SplitDiff { 91 + fragments := make([]SplitFragment, len(d.TextFragments)) 92 + for i, fragment := range d.TextFragments { 93 + leftLines, rightLines := SeparateLines(&fragment) 94 + fragments[i] = SplitFragment{ 95 + Header: fragment.Header(), 96 + LeftLines: leftLines, 97 + RightLines: rightLines, 98 + } 99 + } 100 + 101 + return &SplitDiff{ 102 + Name: d.Id(), 103 + TextFragments: fragments, 104 + } 105 + }