Created
October 7, 2020 19:28
-
-
Save benhoyt/ef85c0bd52bfbdf6d92fd34a80a755b7 to your computer and use it in GitHub Desktop.
Diff to override goldmark's code block output
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/internal/markdown/markdown.go b/internal/markdown/markdown.go | |
index a729b9f..94d29c1 100644 | |
--- a/internal/markdown/markdown.go | |
+++ b/internal/markdown/markdown.go | |
@@ -13,8 +13,11 @@ import ( | |
"bytes" | |
"github.com/yuin/goldmark" | |
+ "github.com/yuin/goldmark/ast" | |
"github.com/yuin/goldmark/parser" | |
+ "github.com/yuin/goldmark/renderer" | |
"github.com/yuin/goldmark/renderer/html" | |
+ "github.com/yuin/goldmark/util" | |
) | |
// Render converts a limited and opinionated flavor of Markdown (compliant with | |
@@ -25,14 +28,65 @@ import ( | |
// untrusted content is not performed: the caller is responsible for ensuring | |
// that only trusted content is provided. | |
func Render(src []byte) ([]byte, error) { | |
+ hr := html.NewRenderer(html.WithUnsafe()) | |
+ nr := &CustomNodeRenderer{hr, html.DefaultWriter} | |
+ r := renderer.NewRenderer(renderer.WithNodeRenderers(util.Prioritized(nr, 1000))) | |
+ | |
// parser.WithHeadingAttribute allows custom ids on headings. | |
// html.WithUnsafe allows use of raw HTML, which we need for tables. | |
md := goldmark.New( | |
goldmark.WithParserOptions(parser.WithHeadingAttribute()), | |
- goldmark.WithRendererOptions(html.WithUnsafe())) | |
+ goldmark.WithRenderer(r)) | |
var buf bytes.Buffer | |
if err := md.Convert(src, &buf); err != nil { | |
return nil, err | |
} | |
return buf.Bytes(), nil | |
} | |
+ | |
+type CustomNodeRenderer struct { | |
+ nr renderer.NodeRenderer | |
+ Writer html.Writer | |
+} | |
+ | |
+func (r *CustomNodeRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { | |
+ r.nr.RegisterFuncs(reg) | |
+ reg.Register(ast.KindCodeBlock, r.renderCodeBlock) | |
+ reg.Register(ast.KindFencedCodeBlock, r.renderFencedCodeBlock) | |
+} | |
+ | |
+func (r *CustomNodeRenderer) renderCodeBlock(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) { | |
+ if entering { | |
+ _, _ = w.WriteString("<pre>") | |
+ r.writeLines(w, source, n) | |
+ } else { | |
+ _, _ = w.WriteString("</pre>\n") | |
+ } | |
+ return ast.WalkContinue, nil | |
+} | |
+ | |
+func (r *CustomNodeRenderer) renderFencedCodeBlock(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { | |
+ n := node.(*ast.FencedCodeBlock) | |
+ if entering { | |
+ _, _ = w.WriteString("<pre") | |
+ language := n.Language(source) | |
+ if language != nil { | |
+ _, _ = w.WriteString(" class=\"language-") | |
+ r.Writer.Write(w, language) | |
+ _, _ = w.WriteString("\"") | |
+ } | |
+ _ = w.WriteByte('>') | |
+ r.writeLines(w, source, n) | |
+ } else { | |
+ _, _ = w.WriteString("</pre>\n") | |
+ } | |
+ return ast.WalkContinue, nil | |
+} | |
+ | |
+func (r *CustomNodeRenderer) writeLines(w util.BufWriter, source []byte, n ast.Node) { | |
+ l := n.Lines().Len() | |
+ for i := 0; i < l; i++ { | |
+ line := n.Lines().At(i) | |
+ r.Writer.RawWrite(w, line.Value(source)) | |
+ } | |
+} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment