summaryrefslogtreecommitdiffstats
path: root/markup
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2021-07-15 08:46:54 +0200
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2021-07-15 10:14:52 +0200
commitee3d2bb1d3974584f47cde7c973fbd1ae1f512b6 (patch)
tree6ce5324b0e5f935cd1834c514495c3eb7cc5dc60 /markup
parenteb2a500367780b07d67c301ce7c866e6b67aa687 (diff)
markup/goldmark: Support auto links in render hook
Fixes #8755
Diffstat (limited to 'markup')
-rw-r--r--markup/goldmark/convert_test.go13
-rw-r--r--markup/goldmark/render_hooks.go70
2 files changed, 82 insertions, 1 deletions
diff --git a/markup/goldmark/convert_test.go b/markup/goldmark/convert_test.go
index 2b66a1910..6e6b0009f 100644
--- a/markup/goldmark/convert_test.go
+++ b/markup/goldmark/convert_test.go
@@ -14,6 +14,7 @@
package goldmark
import (
+ "fmt"
"strings"
"testing"
@@ -59,6 +60,10 @@ https://github.com/gohugoio/hugo/issues/6528
[Live Demo here!](https://docuapi.netlify.com/)
[I'm an inline-style link with title](https://www.google.com "Google's Homepage")
+<https://foo.bar/>
+https://bar.baz/
+<fake@example.com>
+<mailto:fake2@example.com>
## Code Fences
@@ -132,8 +137,14 @@ description
b := convert(c, mconf, content)
got := string(b.Bytes())
+ fmt.Println(got)
+
// Links
- // c.Assert(got, qt.Contains, `<a href="https://docuapi.netlify.com/">Live Demo here!</a>`)
+ c.Assert(got, qt.Contains, `<a href="https://docuapi.netlify.com/">Live Demo here!</a>`)
+ c.Assert(got, qt.Contains, `<a href="https://foo.bar/">https://foo.bar/</a>`)
+ c.Assert(got, qt.Contains, `<a href="https://bar.baz/">https://bar.baz/</a>`)
+ c.Assert(got, qt.Contains, `<a href="mailto:fake@example.com">fake@example.com</a>`)
+ c.Assert(got, qt.Contains, `<a href="mailto:fake2@example.com">mailto:fake2@example.com</a></p>`)
// Header IDs
c.Assert(got, qt.Contains, `<h2 id="custom">Custom ID</h2>`, qt.Commentf(got))
diff --git a/markup/goldmark/render_hooks.go b/markup/goldmark/render_hooks.go
index 5e0865a70..9c159f9cf 100644
--- a/markup/goldmark/render_hooks.go
+++ b/markup/goldmark/render_hooks.go
@@ -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 {