vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Open one file at a time on the commit page
628d45239eb09af4e46c9dc779d30144e96c7e6f · Keenan Nemetz · 11d ago · parent 816cc543
Open one file at a time on the commit page
A commit page rendered every patch it contained, so a broad commit turned one
page load into every blob it touched. It now opens the file tree beside the diff
of a single file, the same shape a change request's Files tab uses: the tree is
built from `git show --name-status`, only the selected path's patch is read, and
a tree click swaps the pane over HTMX. `/commit/{sha}/{path}` deep-links a file
and a 512 KiB cap still bounds one file's patch.
The file tree became one widget for three surfaces rather than two, so its
context gained a Commit field and its href/target/status rules moved onto the
view (Branch, Diff, Href).
The pane's header is now one row: the file's name on the left and its line
counts on the right, with the separate "1 file changed" summary line dropped
when a single file fills the pane. The total-line remains for the multi-file
diff a compare renders.
server/web/code_tree.go +33−10
| @@ -32,13 +32,15 @@ type treeNode struct { | |||
| 32 | 32 | // cannot build a struct literal, so this carries the repository, the ref and the | |
| 33 | 33 | // change down the recursion. | |
| 34 | 34 | // | |
| 35 | // One context serves both trees because they are the same widget: the code | ||
| 36 | // browser writes Review empty, and a change's Files tab names the request, which | ||
| 37 | // is all the difference between "open this blob" and "open this changed file". | ||
| 35 | // One context serves every tree because they are the same widget: the code | ||
| 36 | // browser leaves Review and Commit empty, a change's Files tab names the request, | ||
| 37 | // and a commit page names the commit. That field is all the difference between | ||
| 38 | // "open this blob" and "open this changed file". | ||
| 38 | 39 | type treeView struct { | |
| 39 | 40 | Name string | |
| 40 | 41 | Ref string | |
| 41 | 42 | Review string | |
| 43 | Commit string | ||
| 42 | 44 | Nodes []*treeNode | |
| 43 | 45 | } | |
| 44 | 46 | ||
| @@ -46,14 +48,35 @@ func treeContext(name, ref, review string, nodes []*treeNode) treeView { | |||
| 46 | 48 | return treeView{Name: name, Ref: ref, Review: review, Nodes: nodes} | |
| 47 | 49 | } | |
| 48 | 50 | ||
| 49 | // treeHref is where a row points: a blob at this ref, or the file's diff inside | ||
| 50 | // the change whose id is Review. The tree and the pane it swaps share it so a | ||
| 51 | // link and its hx-get can never disagree. | ||
| 52 | func treeHref(name, ref, review, path string) string { | ||
| 53 | if review != "" { | ||
| 54 | return "/r/" + name + "/requests/" + review + "/files/" + pathURL(path) | ||
| 51 | // commitTreeContext is the tree of the files one commit touched. A row opens that | ||
| 52 | // file's diff in the commit's own pane rather than a blob at the commit. | ||
| 53 | func commitTreeContext(name, commit string, nodes []*treeNode) treeView { | ||
| 54 | return treeView{Name: name, Commit: commit, Nodes: nodes} | ||
| 55 | } | ||
| 56 | |||
| 57 | // Branch re-roots the same tree one level down. The recursive template passes its | ||
| 58 | // own context back so a child row keeps the repository and the change it belongs | ||
| 59 | // to instead of rebuilding them from a subset of the fields. | ||
| 60 | func (t treeView) Branch(nodes []*treeNode) treeView { | ||
| 61 | t.Nodes = nodes | ||
| 62 | return t | ||
| 63 | } | ||
| 64 | |||
| 65 | // Diff reports whether the rows are changed files rather than repository blobs: a | ||
| 66 | // review or a commit opens a diff pane and marks each row with its change status. | ||
| 67 | func (t treeView) Diff() bool { return t.Review != "" || t.Commit != "" } | ||
| 68 | |||
| 69 | // Href is where a row points: a blob at this ref, the file's diff inside the | ||
| 70 | // change whose id is Review, or the file's diff inside a commit. The tree and the | ||
| 71 | // pane it swaps share it so a link and its hx-get can never disagree. | ||
| 72 | func (t treeView) Href(path string) string { | ||
| 73 | switch { | ||
| 74 | case t.Review != "": | ||
| 75 | return "/r/" + t.Name + "/requests/" + t.Review + "/files/" + pathURL(path) | ||
| 76 | case t.Commit != "": | ||
| 77 | return "/r/" + t.Name + "/commit/" + t.Commit + "/" + pathURL(path) | ||
| 55 | 78 | } | |
| 56 | return "/r/" + name + "/blob/" + url.PathEscape(ref) + "/" + pathURL(path) | ||
| 79 | return "/r/" + t.Name + "/blob/" + url.PathEscape(t.Ref) + "/" + pathURL(path) | ||
| 57 | 80 | } | |
| 58 | 81 | ||
| 59 | 82 | // buildFileTree flattens the repository's blobs and folds them back into the | |