chroma at render time, emitting CSS classes rather than inline colour, handed to a `code` theme fragment. Highlighting works with scripting off, in a feed reader, in a browser that never runs JavaScript. No lighter pure-Go option exists — every "alternative to chroma" is JavaScript, which the reference theme is gated against. A fence's info string carries the rest: title, numbers, start, hl=3,7-9, and file=name lines=A-B, which reads the snippet out of a file beside the bundle and numbers it by that file's own lines. So a post quotes several parts of one program without the copies drifting from it, and a reader can find what they are looking at. Verified on the real binary: the same file at lines 5-10 and 12-14, each numbered as it really is, with different lines tinted. Not a new package: a new one could not import the key=value parser this repo already has, because ADR-0069 forbids a feature importing its sibling, and a second parser for the same syntax is what §6 stops. Two costs, both stated in the ADR rather than buried. The binary goes from ~15MB to 19MB, for a project whose story is one small binary. And the reference theme now carries a token palette — the first thing in it that is a taste rather than a demonstration — kept to eight classes for that reason. The demo quotes a shell file, not a Go one: a .go file under examples/ joins the module and has to compile, which the build gate caught before it shipped. 6 of 9 modules, ext 2188/3500.
85 lines
2.9 KiB
Go
85 lines
2.9 KiB
Go
package shortcodes
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"testing/fstest"
|
|
)
|
|
|
|
// codeFS is a bundle with a file a post quotes parts of.
|
|
func codeFS(body string) fstest.MapFS {
|
|
return fstest.MapFS{
|
|
"content/posts/c/index.md": {Data: []byte("---\ntitle: C\n---\n" + body)},
|
|
"content/posts/c/server.go": {Data: []byte(
|
|
"package main\n\nimport \"net/http\"\n\nfunc Serve() {\n\tmux := http.NewServeMux()\n\treturn\n}\n")},
|
|
}
|
|
}
|
|
|
|
func TestCodeIsHighlightedIntoClasses(t *testing.T) {
|
|
got := bundle(t, codeFS("```go\npackage main\n```\n"), "posts/c")
|
|
for _, want := range []string{`class="chroma"`, `class="kn"`, "package"} {
|
|
if !strings.Contains(got, want) {
|
|
t.Errorf("missing %q:\n%s", want, got)
|
|
}
|
|
}
|
|
// Classes, never inline colour: the palette is the theme's (ADR-0075).
|
|
if strings.Contains(got, "style=\"color:") {
|
|
t.Errorf("colour belongs in the stylesheet, not the markup:\n%s", got)
|
|
}
|
|
}
|
|
|
|
func TestAFenceCarriesATitleNumbersAndHighlights(t *testing.T) {
|
|
got := bundle(t, codeFS("```go title=\"main.go\" numbers=yes hl=2\npackage main\n\nfunc main() {}\n```\n"), "posts/c")
|
|
for _, want := range []string{"<figcaption>main.go</figcaption>", `class="ln"`, `class="line hl"`} {
|
|
if !strings.Contains(got, want) {
|
|
t.Errorf("missing %q:\n%s", want, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
// The point of reading from a file: quoting parts of the same one across a post, each keeping the line
|
|
// numbers it really has (ADR-0075).
|
|
func TestASnippetComesFromAFileWithItsOwnLineNumbers(t *testing.T) {
|
|
got := bundle(t, codeFS("```go file=server.go lines=5-7 hl=6\n```\n\n```go file=server.go lines=1-1\n```\n"), "posts/c")
|
|
if !strings.Contains(got, "NewServeMux") {
|
|
t.Errorf("the snippet should carry the file's lines:\n%s", got)
|
|
}
|
|
if strings.Contains(got, "import") {
|
|
t.Errorf("only the requested lines, not the whole file:\n%s", got)
|
|
}
|
|
for _, want := range []string{">5<", ">6<", ">7<"} {
|
|
if !strings.Contains(got, want) {
|
|
t.Errorf("the file's own numbering should show, missing %q:\n%s", want, got)
|
|
}
|
|
}
|
|
if strings.Count(got, `class="chroma"`) != 2 {
|
|
t.Errorf("both snippets should render:\n%s", got)
|
|
}
|
|
}
|
|
|
|
func TestACodeBlockCannotReadOutsideItsBundle(t *testing.T) {
|
|
fsys := codeFS("```go file=../../../secret.go\n```\n")
|
|
fsys["secret.go"] = &fstest.MapFile{Data: []byte("const Secret = 1\n")}
|
|
if got := bundle(t, fsys, "posts/c"); strings.Contains(got, "Secret") {
|
|
t.Errorf("a code block stays inside its bundle:\n%s", got)
|
|
}
|
|
}
|
|
|
|
func TestAnUnknownLanguageStillRenders(t *testing.T) {
|
|
got := bundle(t, codeFS("```nosuchlang\nsome text\n```\n"), "posts/c")
|
|
if !strings.Contains(got, "some text") {
|
|
t.Errorf("the code must survive an unknown language:\n%s", got)
|
|
}
|
|
}
|
|
|
|
func TestRangesReadsWhatChromaWants(t *testing.T) {
|
|
for _, c := range []struct {
|
|
in string
|
|
want int
|
|
}{{"", 0}, {"3", 1}, {"3,7-9", 2}, {"junk", 0}, {"2-4,junk,6", 2}} {
|
|
if got := len(ranges(c.in)); got != c.want {
|
|
t.Errorf("ranges(%q) gave %d pairs, want %d", c.in, got, c.want)
|
|
}
|
|
}
|
|
}
|