vole
Clone
Read only, no credentials:
https://rodent.software/vole.git
Write over SSH with a registered key:
git clone ssh://git@rodent.software: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/tokens.go +7−9
| @@ -1,9 +1,8 @@ | |||
| 1 | 1 | package web | |
| 2 | 2 | ||
| 3 | // The two token inputs: labels and assignees. Both are a set of names stored in | ||
| 4 | // a form field, with a text fallback for a browser without JavaScript and a chip | ||
| 5 | // UI (static/app.js) when it has one, so the parsing and normalising of that set | ||
| 6 | // lives here rather than beside either issue page. | ||
| 3 | // The two token inputs: labels and assignees. Both are a set of names the chip UI | ||
| 4 | // (static/app.js) writes into hidden form fields, so the parsing and normalising | ||
| 5 | // of that set lives here rather than beside either issue page. | ||
| 7 | 6 | ||
| 8 | 7 | import ( | |
| 9 | 8 | "sort" | |
| @@ -14,18 +13,17 @@ import ( | |||
| 14 | 13 | ) | |
| 15 | 14 | ||
| 16 | 15 | // tokenPickerData is the small view model behind the token input. It is used for | |
| 17 | // labels and assignees: Selected is the current set, All is what to suggest, and | ||
| 18 | // Field/Item name the form values the browser and the no-JS fallback submit. | ||
| 16 | // labels and assignees: Selected seeds the current set, All is what to suggest, | ||
| 17 | // and Item names the hidden form field the chip UI writes. | ||
| 19 | 18 | type tokenPickerData struct { | |
| 20 | 19 | Selected []string | |
| 21 | 20 | All []string | |
| 22 | Field string | ||
| 23 | 21 | Item string | |
| 24 | 22 | Placeholder string | |
| 25 | 23 | } | |
| 26 | 24 | ||
| 27 | func tokenPicker(selected, all []string, field, item, placeholder string) tokenPickerData { | ||
| 28 | return tokenPickerData{Selected: selected, All: all, Field: field, Item: item, Placeholder: placeholder} | ||
| 25 | func tokenPicker(selected, all []string, item, placeholder string) tokenPickerData { | ||
| 26 | return tokenPickerData{Selected: selected, All: all, Item: item, Placeholder: placeholder} | ||
| 29 | 27 | } | |
| 30 | 28 | ||
| 31 | 29 | // assignableAccounts lists active accounts that can see this repository. A | |