hugo

Unnamed repository; edit this file 'description' to name the repository.

git clone git://git.shimmy1996.com/hugo.git
commit ee3d2bb1d3974584f47cde7c973fbd1ae1f512b6
parent eb2a500367780b07d67c301ce7c866e6b67aa687
Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Date:   Thu, 15 Jul 2021 08:46:54 +0200

markup/goldmark: Support auto links in render hook

Fixes #8755

Diffstat:
Mhugolib/content_render_hooks_test.go | 11+++++++++--
Mmarkup/goldmark/convert_test.go | 13++++++++++++-
Mmarkup/goldmark/render_hooks.go | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 91 insertions(+), 3 deletions(-)
diff --git a/hugolib/content_render_hooks_test.go b/hugolib/content_render_hooks_test.go
@@ -56,7 +56,6 @@ title: P1
 	b.AssertFileContent("public/p1/index.html", `Link First Link|PARTIAL1_EDITED PARTIAL2_EDITEDEND`)
 }
 
-
 func TestRenderHooks(t *testing.T) {
 	config := `
 baseURL="https://example.org"
@@ -110,6 +109,10 @@ title: Cool Page
 ---
 
 [First Link](https://www.google.com "Google's Homepage")
+<https://foo.bar/>
+https://bar.baz/
+<fake@example.com>
+<mailto:fake2@example.com>
 
 {{< myshortcode3 >}}
 
@@ -209,7 +212,11 @@ title: No Template
 	b.Assert(int(counters.contentRenderCounter), qt.Equals, 45)
 
 	b.AssertFileContent("public/blog/p1/index.html", `
-<p>Cool Page|https://www.google.com|Title: Google's Homepage|Text: First Link|END</p>
+Cool Page|https://www.google.com|Title: Google's Homepage|Text: First Link|END
+Cool Page|https://foo.bar/|Title: |Text: https://foo.bar/|END
+Cool Page|https://bar.baz/|Title: |Text: https://bar.baz/|END
+Cool Page|mailto:fake@example.com|Title: |Text: fake@example.com|END
+Cool Page|mailto:fake2@example.com|Title: |Text: mailto:fake2@example.com|END
 Text: Second
 SHORT3|
 <p>IMAGE: Cool Page||/images/Dragster.jpg|Title: image title|Text: Drag Racing|END</p>
diff --git 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
@@ -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 {