// SPDX-License-Identifier: AGPL-3.0-or-later package web // Commit is a commit: the message and facts, the diff tools, the diff. templ Commit(l Layout, p CommitPage) { @Shell(l, commitRail(p)) {

{ p.Subject }

if p.Body != "" {
{ p.Body }
}
commit
{ p.SHA }
author
@personView(p.Author)
if p.Committer != nil {
committer
@personView(*p.Committer)
}
if p.Merge { merge of } else { parent }
if p.Root { none (root commit) } for i, par := range p.Parents { if i > 0 { { " + " } } { par.Label } } if p.Merge { { " · diff against the first parent" } }
if p.Checks.Total > 0 {
checks
@CommitChecks(p.Checks)
} if len(p.Refs) > 0 {
refs
for _, r := range p.Refs { { r } }
}
{ plural(p.NFiles, "file", "files") } · +{ itoa(p.Adds) } -{ itoa(p.Dels) } @viewLink(p.DiffView, "unified", "Unified", "u", p.UnifiedHref) @viewLink(p.DiffView, "split", "Split", "d", p.SplitHref) @collapseButton()
if p.Invisible {

this diff holds invisible characters (direction controls, zero-width characters). They are shown as <U+XXXX> markers, never applied.

} if p.Note != "" {

{ p.Note }

}
for _, f := range p.Files { @DiffFileView(f, p.DiffView) } if len(p.Files) == 0 {

no changed files{ " " } if p.Merge { against the first parent. } else { in this commit. }

}
} } // viewLink is a button of the diff tools. It is a link, so that the split // layout works without JavaScript; with it, and when both layouts are in the // page, a click only flips the layout. templ viewLink(p DiffView, view, label, key, href string) { { label } } // collapseButton folds every file of the diff, or opens them all again when // none is open; its label follows the state. templ collapseButton() { } templ personView(pr Person) { { pr.Name } if pr.WhenAt != "" { { " · " }{ " · " + pr.Abs } } } templ commitRail(p CommitPage) {

Files { itoa(len(p.Files)) }

@FileList(p.Files)
} // FileList is the table of contents of a diff: status letter, path, +n -m // and an ASCII bar. The row of the file in view is marked. templ FileList(files []DiffFile) { if len(files) > fileFilterMin {
}
    for _, f := range files {
  1. { f.Status } { f.Name }{ " " }{ f.Dir } if f.OpenNotes > 0 { { itoa(f.OpenNotes) } } else if f.Notes > 0 { { itoa(f.Notes) } } if f.Bin { bin } else { +{ itoa(f.Add) } -{ itoa(f.Del) } }
  2. }
} // DiffFileView is one file of the diff: a
(per-file collapse). The // unified and the split tables are both in it; #diffs[data-diff] shows one. // Every changed line keeps its +/- marker, so a change is never conveyed by // colour alone. templ DiffFileView(f DiffFile, p DiffView) {
{ f.Status }{ " " }{ f.Path }{ " " }+{ itoa(f.Add) }{ " " }-{ itoa(f.Del) } if f.Note != "" { { " " }{ f.Note } } if f.Lazy { // A placeholder: mr.js fetches the window of the file when it comes // near the screen and swaps the files of the window in. Without // scripts the link opens the page of that window. } else if len(f.Hunks) > 0 {
if p.ShowUnified { for _, h := range f.Hunks { if h.Gap != nil { @gapRow(*h.Gap, 4) } for _, ln := range h.Lines { if len(ln.Notes) > 0 || ln.Form != nil { } } } if f.Tail != nil { @gapRow(*f.Tail, 4) }
{ h.Header }
@gutter(ln.Old, ln.OldHref) @gutter(ln.New, ln.NewHref) { ln.Mark } @codeLine(ln)
@lineNotes(ln.Notes, ln.Form, "")
} if p.ShowSplit { for _, h := range f.Hunks { if h.Gap != nil { @gapRow(*h.Gap, 6) } for _, row := range h.Split { @splitSide(row.L, true) @splitSide(row.R, false) if notes, form := row.Notes(), row.Form(); len(notes) > 0 || form != nil { } } } if f.Tail != nil { @gapRow(*f.Tail, 6) }
{ h.Header }
@lineNotes(notes, form, "-s")
}
} else {

if f.Note != "" { { f.Note } } else { no textual change. }

} if len(f.Loose) > 0 {
for _, c := range f.Loose { @commentView(c, "") }
}
} // MRFiles is a window of files of a merge request, for the placeholders of // the page: the files only, which replace the placeholders of the same ids. templ MRFiles(p MRFilesPage) { for _, f := range p.Files { @DiffFileView(f, p.DiffView) } } // MRFilesMoved answers a window of a diff that is not the one of the page any // more: the placeholder shows it instead of a file of another diff. templ MRFilesMoved() {

this merge request changed since the page was loaded — reload

} // gapRow is the row of the hidden lines before a hunk, or of the rest of the // file: a button that loads them in their place (ermite.js, ermite.expand). // Without scripts nothing loads them: hidden. templ gapRow(g DiffGap, cols int) { } // DiffContext is the hidden lines of a gap, for /context: one body a layout, // whose rows replace the rows of the gap in the table of that layout. templ DiffContext(c ContextRows) { for _, ln := range c.Lines { } if c.More != nil { @gapRow(*c.More, 4) } for i := range c.Lines { @splitSide(&c.Lines[i], true) @splitSide(&c.Lines[i], false) } if c.More != nil { @gapRow(*c.More, 6) }
{ ln.Old } { ln.New } { ln.Mark } @codeLine(ln)
} // splitSide is one half of a row of the split view; a side without a line is // an empty cell. templ splitSide(ln *DiffLine, old bool) { if ln == nil { } else { if old { @gutter(ln.Old, ln.OldHref) } else { @gutter(ln.New, ln.NewHref) } { ln.Mark } @codeLine(*ln) } } // gutter is a line number of the gutter. On a merge request that can be // commented on, it links to the form that comments on that line. templ gutter(n, href string) { if href != "" { { n } } else { { n } } }