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.
Highlight with Prism in a worker and gzip text responses
306f36fcef89c145abcd0c5331453d0b179f37ce · Keenan Nemetz · 12d ago · parent e5542ac6
Highlight with Prism in a worker and gzip text responses
The code browser now names a blob's language and lets the browser colour it.
Chroma is gone: server/web/highlight.go is an extension table, and
static/prism-worker.js runs Prism — every language Prism ships — off the main
thread. The server sends escaped lines with their numbers and L# anchors, so a
page is complete and scrollable before any script runs and the worker only swaps
the contents of each line cell. The table covers 186 languages; a file it does
not claim stays plain rather than being coloured by a guess.
The bundle those grammars make is 545 KB, so the instance now gzips text
responses itself instead of relying on a proxy, and static assets carry a
content ETag so a browser revalidates with a 304 rather than re-downloading the
bundle on every code page. The raw-download route opts out with
Cache-Control: no-transform because it promises an exact Content-Length.
This also makes JavaScript a requirement rather than a nicety: the label and
assignee token inputs lose their noscript save buttons and their comma-separated
text fallback, and the docs say so.
Measured: release binary 26.08 MB -> 22.70 MB; /r/{repo}/code 11.1 KB -> 2.6 KB
over the wire; the Prism bundle 545 KB -> 206 KB gzipped, fetched once.
scripts/vendor-prism.py regenerates the bundle from Prism's components.json
require graph, and --check fails if the committed assets drift.
server/web/writes.go +5−5
| @@ -40,8 +40,8 @@ func (w *Web) CreateIssue(rw http.ResponseWriter, r *http.Request) { | |||
| 40 | 40 | http.Error(rw, "an issue needs a title", http.StatusBadRequest) | |
| 41 | 41 | return | |
| 42 | 42 | } | |
| 43 | labels := normalizeLabelSet(append([]string{r.PostFormValue("labels")}, r.PostForm["label"]...)) | ||
| 44 | assignees := metadata.NormalizeAssignees(append([]string{r.PostFormValue("assignees")}, r.PostForm["assignee"]...)) | ||
| 43 | labels := normalizeLabelSet(r.PostForm["label"]) | ||
| 44 | assignees := metadata.NormalizeAssignees(r.PostForm["assignee"]) | ||
| 45 | 45 | if bad := unknownNames(assignees, w.assignableAccounts(m)); len(bad) > 0 { | |
| 46 | 46 | http.Error(rw, "unknown or unavailable assignee: "+strings.Join(bad, ", "), http.StatusBadRequest) | |
| 47 | 47 | return | |
| @@ -65,7 +65,7 @@ func (w *Web) CreateIssue(rw http.ResponseWriter, r *http.Request) { | |||
| 65 | 65 | ||
| 66 | 66 | // SetIssueLabels replaces an issue's labels. Labels are shared state, but the | |
| 67 | 67 | // author may label their own issue; a maintainer may label any issue as triage. | |
| 68 | // The form sends existing labels as checkboxes and new ones as free text. | ||
| 68 | // The form sends labels as hidden inputs written by the chip UI. | ||
| 69 | 69 | func (w *Web) SetIssueLabels(rw http.ResponseWriter, r *http.Request) { | |
| 70 | 70 | ctx, ok := w.beginWrite(rw, r, maxSmallForm) | |
| 71 | 71 | if !ok { | |
| @@ -87,7 +87,7 @@ func (w *Web) SetIssueLabels(rw http.ResponseWriter, r *http.Request) { | |||
| 87 | 87 | labelsView := func(msg string) (string, any) { | |
| 88 | 88 | return "issue_labels", w.issueSidebar(r, m, iss, "", msg) | |
| 89 | 89 | } | |
| 90 | labels := normalizeLabelSet(append([]string{r.PostFormValue("labels")}, r.PostForm["label"]...)) | ||
| 90 | labels := normalizeLabelSet(r.PostForm["label"]) | ||
| 91 | 91 | updated, err := metadata.UpdateIssue(m.Git(), id, func(iss *metadata.Issue) error { | |
| 92 | 92 | if sameStrings(metadata.NormalizeLabels(iss.Labels), labels) { | |
| 93 | 93 | return metadata.ErrNoChange | |
| @@ -134,7 +134,7 @@ func (w *Web) SetIssueAssignees(rw http.ResponseWriter, r *http.Request) { | |||
| 134 | 134 | assigneesView := func(msg string) (string, any) { | |
| 135 | 135 | return "issue_assignees", w.issueSidebar(r, m, iss, "", msg) | |
| 136 | 136 | } | |
| 137 | assignees := metadata.NormalizeAssignees(append([]string{r.PostFormValue("assignees")}, r.PostForm["assignee"]...)) | ||
| 137 | assignees := metadata.NormalizeAssignees(r.PostForm["assignee"]) | ||
| 138 | 138 | // A current assignee may have lost access since being assigned. Keep them in | |
| 139 | 139 | // the allowed set so an edit can remove the others without silently dropping | |
| 140 | 140 | // that name. | |