markup/goldmark: Support auto links in render hook

Fixes #8755
This commit is contained in:
Bjørn Erik Pedersen 2021-07-15 08:46:54 +02:00
parent eb2a500367
commit ee3d2bb1d3
3 changed files with 91 additions and 3 deletions

View file

@ -15,6 +15,7 @@ package goldmark
import (
"bytes"
"strings"
"sync"
"github.com/spf13/cast"
@ -134,6 +135,7 @@ func (r *hookedRenderer) SetOption(name renderer.OptionName, value interface{})
// RegisterFuncs implements NodeRenderer.RegisterFuncs.
func (r *hookedRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
reg.Register(ast.KindLink, r.renderLink)
reg.Register(ast.KindAutoLink, r.renderAutoLink)
reg.Register(ast.KindImage, r.renderImage)
reg.Register(ast.KindHeading, r.renderHeading)
}
@ -307,6 +309,74 @@ func (r *hookedRenderer) renderLink(w util.BufWriter, source []byte, node ast.No
return ast.WalkContinue, err
}
func (r *hookedRenderer) renderAutoLink(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
n := node.(*ast.AutoLink)
var h hooks.Renderers
ctx, ok := w.(*renderContext)
if ok {
h = ctx.RenderContext().RenderHooks
ok = h.LinkRenderer != nil
}
if !ok {
return r.renderDefaultAutoLink(w, source, node, entering)
}
url := string(n.URL(source))
label := string(n.Label(source))
if n.AutoLinkType == ast.AutoLinkEmail && !strings.HasPrefix(strings.ToLower(url), "mailto:") {
url = "mailto:" + url
}
err := h.LinkRenderer.RenderLink(
w,
linkContext{
page: ctx.DocumentContext().Document,
destination: url,
text: label,
plainText: label,
},
)
// TODO(bep) I have a working branch that fixes these rather confusing identity types,
// but for now it's important that it's not .GetIdentity() that's added here,
// to make sure we search the entire chain on changes.
ctx.AddIdentity(h.LinkRenderer)
return ast.WalkContinue, err
}
// Fall back to the default Goldmark render funcs. Method below borrowed from:
// https://github.com/yuin/goldmark/blob/5588d92a56fe1642791cf4aa8e9eae8227cfeecd/renderer/html/html.go#L439
func (r *hookedRenderer) renderDefaultAutoLink(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
n := node.(*ast.AutoLink)
if !entering {
return ast.WalkContinue, nil
}
_, _ = w.WriteString(`<a href="`)
url := n.URL(source)
label := n.Label(source)
if n.AutoLinkType == ast.AutoLinkEmail && !bytes.HasPrefix(bytes.ToLower(url), []byte("mailto:")) {
_, _ = w.WriteString("mailto:")
}
_, _ = w.Write(util.EscapeHTML(util.URLEscape(url, false)))
if n.Attributes() != nil {
_ = w.WriteByte('"')
html.RenderAttributes(w, n, html.LinkAttributeFilter)
_ = w.WriteByte('>')
} else {
_, _ = w.WriteString(`">`)
}
_, _ = w.Write(util.EscapeHTML(label))
_, _ = w.WriteString(`</a>`)
return ast.WalkContinue, nil
}
func (r *hookedRenderer) renderDefaultHeading(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
n := node.(*ast.Heading)
if entering {