appview: markdown: introduce syntax highlighting to code blocks #335

Changed files
+28 -4
appview
pages
markup
+20 -1
appview/pages/markup/markdown.go
··· 5 "bytes" 6 "fmt" 7 "io" 8 "net/url" 9 "path" 10 "strings" 11 12 "github.com/microcosm-cc/bluemonday" 13 "github.com/yuin/goldmark" 14 "github.com/yuin/goldmark/ast" 15 "github.com/yuin/goldmark/extension" 16 "github.com/yuin/goldmark/parser" ··· 43 } 44 45 func (rctx *RenderContext) RenderMarkdown(source string) string { 46 md := goldmark.New( 47 - goldmark.WithExtensions(extension.GFM), 48 goldmark.WithParserOptions( 49 parser.WithAutoHeadingID(), 50 ), 51 goldmark.WithRendererOptions(html.WithUnsafe()), 52 ) 53 54 if rctx != nil { ··· 63 64 var buf bytes.Buffer 65 if err := md.Convert([]byte(source), &buf); err != nil { 66 return source 67 } 68 ··· 173 "margin-top", 174 "margin-bottom", 175 ) 176 return policy.Sanitize(html) 177 } 178
··· 5 "bytes" 6 "fmt" 7 "io" 8 + "log" 9 "net/url" 10 "path" 11 "strings" 12 13 + "github.com/alecthomas/chroma/v2" 14 + chromahtml "github.com/alecthomas/chroma/v2/formatters/html" 15 + "github.com/alecthomas/chroma/v2/styles" 16 "github.com/microcosm-cc/bluemonday" 17 "github.com/yuin/goldmark" 18 + highlighting "github.com/yuin/goldmark-highlighting/v2" 19 "github.com/yuin/goldmark/ast" 20 "github.com/yuin/goldmark/extension" 21 "github.com/yuin/goldmark/parser" ··· 48 } 49 50 func (rctx *RenderContext) RenderMarkdown(source string) string { 51 + var style *chroma.Style = styles.Get("catppuccin-latte") 52 md := goldmark.New( 53 goldmark.WithParserOptions( 54 parser.WithAutoHeadingID(), 55 ), 56 goldmark.WithRendererOptions(html.WithUnsafe()), 57 + goldmark.WithExtensions( 58 + extension.GFM, 59 + highlighting.NewHighlighting( 60 + highlighting.WithFormatOptions( 61 + chromahtml.Standalone(false), 62 + chromahtml.WithClasses(true), 63 + ), 64 + highlighting.WithCustomStyle(style), 65 + ), 66 + ), 67 ) 68 69 if rctx != nil { ··· 78 79 var buf bytes.Buffer 80 if err := md.Convert([]byte(source), &buf); err != nil { 81 + log.Println("failed to convert markdown:", err) 82 return source 83 } 84 ··· 189 "margin-top", 190 "margin-bottom", 191 ) 192 + 193 + policy.AllowAttrs("class").OnElements("code", "pre", "span") 194 + 195 return policy.Sanitize(html) 196 } 197
+1 -1
flake.nix
··· 61 inherit (gitignore.lib) gitignoreSource; 62 in { 63 overlays.default = final: prev: let 64 - goModHash = "sha256-2RUwj16RNaZ/gCOcd7b3LRCHiROCRj9HuzbBdLdgWGo="; 65 appviewDeps = { 66 inherit htmx-src htmx-ws-src lucide-src inter-fonts-src ibm-plex-mono-src goModHash gitignoreSource; 67 };
··· 61 inherit (gitignore.lib) gitignoreSource; 62 in { 63 overlays.default = final: prev: let 64 + goModHash = "sha256-7l5x9qeesQI+HCh9YS2EBba86lS2CQGugqMVbqvfEqw="; 65 appviewDeps = { 66 inherit htmx-src htmx-ws-src lucide-src inter-fonts-src ibm-plex-mono-src goModHash gitignoreSource; 67 };
+2 -1
go.mod
··· 36 github.com/stretchr/testify v1.10.0 37 github.com/urfave/cli/v3 v3.3.3 38 github.com/whyrusleeping/cbor-gen v0.3.1 39 - github.com/yuin/goldmark v1.4.13 40 golang.org/x/crypto v0.38.0 41 golang.org/x/net v0.40.0 42 golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da
··· 36 github.com/stretchr/testify v1.10.0 37 github.com/urfave/cli/v3 v3.3.3 38 github.com/whyrusleeping/cbor-gen v0.3.1 39 + github.com/yuin/goldmark v1.4.15 40 + github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc 41 golang.org/x/crypto v0.38.0 42 golang.org/x/net v0.40.0 43 golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da
+5 -1
go.sum
··· 75 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= 76 github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= 77 github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= 78 github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= 79 github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= 80 github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw= ··· 403 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 404 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 405 github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 406 - github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= 407 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 408 gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRySiX3drau9C6Q5CAbNIApmLdat5jPMqChvDA= 409 gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8= 410 gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q=
··· 75 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= 76 github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= 77 github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= 78 + github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= 79 github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= 80 github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= 81 github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw= ··· 404 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 405 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 406 github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 407 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 408 + github.com/yuin/goldmark v1.4.15 h1:CFa84T0goNn/UIXYS+dmjjVxMyTAvpOmzld40N/nfK0= 409 + github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 410 + github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ= 411 + github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I= 412 gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRySiX3drau9C6Q5CAbNIApmLdat5jPMqChvDA= 413 gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8= 414 gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q=