Preserve HTML Text for link render hooks
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Wed, 18 Dec 2019 16:23:09 +0000 (17:23 +0100)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Wed, 18 Dec 2019 21:55:19 +0000 (22:55 +0100)
The context now have two text methods:

* Text - rendered
* PlainText

Fixes #6629

docs/content/en/getting-started/configuration-markup.md
hugolib/content_render_hooks_test.go
markup/converter/hooks/hooks.go
markup/goldmark/convert.go
markup/goldmark/render_link.go

index b853af474ec222a2456b896b772f3c46e77c8bef..8c3633ce6ebcfcdcaf38672fed9bfbaf09f3a161 100644 (file)
@@ -117,7 +117,10 @@ Title
 : The title attribute.
 
 Text
-: The link text.
+: The rendered (HTML) link text.
+
+PlainText
+: The plain variant of the above.
 
 A Markdown example for a inline-style link with title:
 
index aa697220d1b3d6e0446e4a27b6e9a559d3e4a126..deccbff48f43cbfbc5c65750a713694293c1b681 100644 (file)
@@ -213,6 +213,37 @@ P3: <p>P3. xml-link: https://www.example.org|</p>
 
 }
 
+// https://github.com/gohugoio/hugo/issues/6629
+func TestRenderLinkWithMarkupInText(t *testing.T) {
+
+       b := newTestSitesBuilder(t)
+
+       b.WithTemplates("index.html", `
+{{ $p := site.GetPage "p1.md" }}
+P1: {{ $p.Content }}
+
+       `,
+               "_default/_markup/render-link.html", `html-link: {{ .Destination | safeURL }}|Text: {{ .Text | safeHTML }}|Plain: {{ .PlainText | safeHTML }}`,
+       )
+
+       b.WithContent("p1.md", `---
+title: "p1"
+---
+
+START: [**should be bold**](https://gohugo.io)END
+
+Some regular **markup**.
+`)
+
+       b.Build(BuildCfg{})
+
+       b.AssertFileContent("public/index.html", `
+  P1: <p>START: html-link: https://gohugo.io|Text: <strong>should be bold</strong>|Plain: should be boldEND</p>
+<p>Some regular <strong>markup</strong>.</p>
+`)
+
+}
+
 func TestRenderString(t *testing.T) {
 
        b := newTestSitesBuilder(t)
index 63beacc377eed16bd280d5d314bae0e2f94f405a..5dfb09e2d40cdd99d6334b07b7ecb7602503ad95 100644 (file)
@@ -24,6 +24,7 @@ type LinkContext interface {
        Destination() string
        Title() string
        Text() string
+       PlainText() string
 }
 
 type Render struct {
index 130f02a2fb7f02d487c609b5d5d5f54878b62f6d..af204125f03358aaeea0dc569e4cfcbe090fa376 100644 (file)
@@ -15,9 +15,9 @@
 package goldmark
 
 import (
-       "bufio"
        "bytes"
        "fmt"
+       "math/bits"
        "path/filepath"
        "runtime/debug"
 
@@ -162,8 +162,27 @@ func (c converterResult) GetIdentities() identity.Identities {
        return c.ids
 }
 
+type bufWriter struct {
+       *bytes.Buffer
+}
+
+const maxInt = 1<<(bits.UintSize-1) - 1
+
+func (b *bufWriter) Available() int {
+       return maxInt
+}
+
+func (b *bufWriter) Buffered() int {
+       return b.Len()
+}
+
+func (b *bufWriter) Flush() error {
+       return nil
+}
+
 type renderContext struct {
-       util.BufWriter
+       *bufWriter
+       pos int
        renderContextData
 }
 
@@ -205,7 +224,7 @@ func (c *goldmarkConverter) Convert(ctx converter.RenderContext) (result convert
                }
        }()
 
-       buf := &bytes.Buffer{}
+       buf := &bufWriter{Buffer: &bytes.Buffer{}}
        result = buf
        pctx := newParserContext(ctx)
        reader := text.NewReader(ctx.Src)
@@ -221,8 +240,8 @@ func (c *goldmarkConverter) Convert(ctx converter.RenderContext) (result convert
                ids:  identity.NewManager(converterIdentity),
        }
 
-       w := renderContext{
-               BufWriter:         bufio.NewWriter(buf),
+       w := &renderContext{
+               bufWriter:         buf,
                renderContextData: rcx,
        }
 
index 17ba5badaccae61bc7f80ab45b29ea1e80abcdf3..cefb786a69b0a0c67772889cbe0d965c50064110 100644 (file)
@@ -43,6 +43,7 @@ type linkContext struct {
        destination string
        title       string
        text        string
+       plainText   string
 }
 
 func (ctx linkContext) Destination() string {
@@ -61,6 +62,10 @@ func (ctx linkContext) Text() string {
        return ctx.text
 }
 
+func (ctx linkContext) PlainText() string {
+       return ctx.plainText
+}
+
 func (ctx linkContext) Title() string {
        return ctx.title
 }
@@ -146,13 +151,16 @@ func (r *linkRenderer) renderImage(w util.BufWriter, source []byte, node ast.Nod
                return ast.WalkContinue, nil
        }
 
+       text := string(n.Text(source))
+
        err := h.ImageRenderer.Render(
                w,
                linkContext{
                        page:        ctx.DocumentContext().Document,
                        destination: string(n.Destination),
                        title:       string(n.Title),
-                       text:        string(n.Text(source)),
+                       text:        text,
+                       plainText:   text,
                },
        )
 
@@ -166,7 +174,7 @@ func (r *linkRenderer) renderLink(w util.BufWriter, source []byte, node ast.Node
        n := node.(*ast.Link)
        var h *hooks.Render
 
-       ctx, ok := w.(renderContextData)
+       ctx, ok := w.(*renderContext)
        if ok {
                h = ctx.RenderContext().RenderHooks
                ok = h != nil && h.LinkRenderer != nil
@@ -176,24 +184,29 @@ func (r *linkRenderer) renderLink(w util.BufWriter, source []byte, node ast.Node
                return r.renderDefaultLink(w, source, node, entering)
        }
 
-       if !entering {
+       if entering {
+               // Store the current pos so we can capture the rendered text.
+               ctx.pos = ctx.Buffer.Len()
                return ast.WalkContinue, nil
        }
 
+       text := ctx.Buffer.Bytes()[ctx.pos:]
+       ctx.Buffer.Truncate(ctx.pos)
+
        err := h.LinkRenderer.Render(
                w,
                linkContext{
                        page:        ctx.DocumentContext().Document,
                        destination: string(n.Destination),
                        title:       string(n.Title),
-                       text:        string(n.Text(source)),
+                       text:        string(text),
+                       plainText:   string(n.Text(source)),
                },
        )
 
        ctx.AddIdentity(h.LinkRenderer.GetIdentity())
 
-       // Do not render the inner text.
-       return ast.WalkSkipChildren, err
+       return ast.WalkContinue, err
 
 }