diff --git a/UPGRADING.md b/UPGRADING.md index 5f5a44ce..3ee99106 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -2,6 +2,13 @@ Notes for upgrading an existing GoBlog site across releases that need manual steps. Newest first. +## Code highlighting moved to the server + +Fenced code in posts and pages is now coloured when the markdown is rendered, and goblog no longer loads highlight.js. Two things to do: + +- **Label your code fences.** A fence with no language (```` ``` ```` rather than ```` ```go ````) is guessed, and chroma's guess only works for code with a clear signature, such as Go's `package` line or a `#!/bin/bash` shebang. Anything else renders as plain text until you add the language: ```` ```bash ````, ```` ```python ````, ```` ```yaml ```` and so on ([chroma's list](https://github.com/alecthomas/chroma#supported-languages)). +- **Themes:** drop any `hljs.highlightAll()` call from `footer.html`; `hljs` is no longer defined, so the call throws. To restyle code, override the `.chroma` classes in your `goblog.css`; the defaults are in `www/css/base.css`. + ## Moving an existing site into `GOBLOG_DATA_DIR` Optional, from 0.14.0. A site set up before `GOBLOG_DATA_DIR` existed keeps its files in goblog's working directory (`/go/src/github.com/compscidr/goblog` in the Docker image), usually with one bind mount per path. It keeps working as it is. To move it to a single data directory instead: diff --git a/blog/render.go b/blog/render.go index 1111e499..9fe5bd8d 100644 --- a/blog/render.go +++ b/blog/render.go @@ -4,8 +4,10 @@ import ( "bytes" "html/template" + chromahtml "github.com/alecthomas/chroma/v2/formatters/html" "github.com/microcosm-cc/bluemonday" "github.com/yuin/goldmark" + highlighting "github.com/yuin/goldmark-highlighting/v2" "github.com/yuin/goldmark/extension" "github.com/yuin/goldmark/renderer/html" ) @@ -15,8 +17,17 @@ import ( // iframes, Instagram scripts) depend on it. This is a deliberate decision, // recorded in docs/superpowers/specs/2026-09-22-server-side-markdown-design.md; // a post or page can therefore run JavaScript on the site. +// +// Fenced code is coloured here rather than by highlight.js in the browser +// (#625). Almost no fence in existing posts names its language, so an +// unlabelled one is guessed; a guess chroma cannot make renders as plain +// text, and labelling that fence fixes it. The colours are CSS classes, +// styled in www/css/base.css so a theme can restyle them. var authorMarkdown = goldmark.New( - goldmark.WithExtensions(extension.GFM), + goldmark.WithExtensions(extension.GFM, highlighting.NewHighlighting( + highlighting.WithGuessLanguage(true), + highlighting.WithFormatOptions(chromahtml.WithClasses(true)), + )), goldmark.WithRendererOptions(html.WithUnsafe()), ) diff --git a/blog/render_test.go b/blog/render_test.go index 9a1ff05a..20896515 100644 --- a/blog/render_test.go +++ b/blog/render_test.go @@ -26,13 +26,37 @@ func TestPostHTML_KeepsRawHTML(t *testing.T) { func TestPostHTML_RendersGFM(t *testing.T) { p := Post{Content: "# Title\n\nSome **bold** and a [link](/x).\n\n| a | b |\n|---|---|\n| 1 | 2 |\n\n```go\nfunc main() {}\n```\n\n- [x] done\n- [ ] todo\n\n~~struck~~\n"} got := string(p.HTML()) - for _, want := range []string{"