diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2022-02-16 13:44:09 +0100 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2022-02-16 17:46:30 +0100 |
commit | b2a827c52c91d9219306b5c996074d2e1ced5342 (patch) | |
tree | 014c859f5a0ea31ea41d4a64d13398a974f2b4a1 /markup/goldmark | |
parent | 77c7059ff832870c3920e87a87969b815e429a8a (diff) |
markup/goldmark: Fix mangling of headers/links in render hooks
```bash
name old time/op new time/op delta
SiteWithRenderHooks-10 11.9ms ± 1% 11.9ms ± 1% ~ (p=0.486 n=4+4)
name old alloc/op new alloc/op delta
SiteWithRenderHooks-10 11.2MB ± 0% 11.3MB ± 0% +0.16% (p=0.029 n=4+4)
name old allocs/op new allocs/op delta
SiteWithRenderHooks-10 145k ± 0% 145k ± 0% +0.14% (p=0.029 n=4+4)
```
Fixes #9504
Diffstat (limited to 'markup/goldmark')
-rw-r--r-- | markup/goldmark/convert.go | 16 | ||||
-rw-r--r-- | markup/goldmark/integration_test.go | 36 | ||||
-rw-r--r-- | markup/goldmark/render_hooks.go | 41 |
3 files changed, 69 insertions, 24 deletions
diff --git a/markup/goldmark/convert.go b/markup/goldmark/convert.go index dcaf8d3e1..c547fe1e0 100644 --- a/markup/goldmark/convert.go +++ b/markup/goldmark/convert.go @@ -47,8 +47,7 @@ import ( // Provider is the package entry point. var Provider converter.ProviderProvider = provide{} -type provide struct { -} +type provide struct{} func (p provide) New(cfg converter.ProviderConfig) (converter.Provider, error) { md := newMarkdown(cfg) @@ -199,10 +198,21 @@ func (b *bufWriter) Flush() error { type renderContext struct { *bufWriter - pos int + positions []int renderContextData } +func (ctx *renderContext) pushPos(n int) { + ctx.positions = append(ctx.positions, n) +} + +func (ctx *renderContext) popPos() int { + i := len(ctx.positions) - 1 + p := ctx.positions[i] + ctx.positions = ctx.positions[:i] + return p +} + type renderContextData interface { RenderContext() converter.RenderContext DocumentContext() converter.DocumentContext diff --git a/markup/goldmark/integration_test.go b/markup/goldmark/integration_test.go index fd90a6824..0f47f4ada 100644 --- a/markup/goldmark/integration_test.go +++ b/markup/goldmark/integration_test.go @@ -61,6 +61,42 @@ foo `) } +// Issue 9504 +func TestLinkInTitle(t *testing.T) { + t.Parallel() + + files := ` +-- config.toml -- +-- content/p1.md -- +--- +title: "p1" +--- +## Hello [Test](https://example.com) +-- layouts/_default/single.html -- +{{ .Content }} +-- layouts/_default/_markup/render-heading.html -- +<h{{ .Level }} id="{{ .Anchor | safeURL }}"> + {{ .Text | safeHTML }} + <a class="anchor" href="#{{ .Anchor | safeURL }}">#</a> +</h{{ .Level }}> +-- layouts/_default/_markup/render-link.html -- +<a href="{{ .Destination | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }}>{{ .Text | safeHTML }}</a> + +` + + b := hugolib.NewIntegrationTestBuilder( + hugolib.IntegrationTestConfig{ + T: t, + TxtarString: files, + NeedsOsFS: false, + }, + ).Build() + + b.AssertFileContent("public/p1/index.html", + "<h2 id=\"hello-testhttpsexamplecom\">\n Hello <a href=\"https://example.com\">Test</a>\n\n <a class=\"anchor\" href=\"#hello-testhttpsexamplecom\">#</a>\n</h2>", + ) +} + func BenchmarkSiteWithRenderHooks(b *testing.B) { files := ` -- config.toml -- diff --git a/markup/goldmark/render_hooks.go b/markup/goldmark/render_hooks.go index e6d959abf..5c600204c 100644 --- a/markup/goldmark/render_hooks.go +++ b/markup/goldmark/render_hooks.go @@ -144,16 +144,13 @@ func (r *hookedRenderer) renderAttributesForNode(w util.BufWriter, node ast.Node renderAttributes(w, false, node.Attributes()...) } -var ( - - // Attributes with special meaning that does not make sense to render in HTML. - attributeExcludes = map[string]bool{ - "hl_lines": true, - "hl_style": true, - "linenos": true, - "linenostart": true, - } -) +// Attributes with special meaning that does not make sense to render in HTML. +var attributeExcludes = map[string]bool{ + "hl_lines": true, + "hl_style": true, + "linenos": true, + "linenostart": true, +} func renderAttributes(w util.BufWriter, skipClass bool, attributes ...ast.Attribute) { for _, attr := range attributes { @@ -197,12 +194,13 @@ func (r *hookedRenderer) renderImage(w util.BufWriter, source []byte, node ast.N if entering { // Store the current pos so we can capture the rendered text. - ctx.pos = ctx.Buffer.Len() + ctx.pushPos(ctx.Buffer.Len()) return ast.WalkContinue, nil } - text := ctx.Buffer.Bytes()[ctx.pos:] - ctx.Buffer.Truncate(ctx.pos) + pos := ctx.popPos() + text := ctx.Buffer.Bytes()[pos:] + ctx.Buffer.Truncate(pos) err := h.ImageRenderer.RenderLink( w, @@ -263,12 +261,13 @@ func (r *hookedRenderer) renderLink(w util.BufWriter, source []byte, node ast.No if entering { // Store the current pos so we can capture the rendered text. - ctx.pos = ctx.Buffer.Len() + ctx.pushPos(ctx.Buffer.Len()) return ast.WalkContinue, nil } - text := ctx.Buffer.Bytes()[ctx.pos:] - ctx.Buffer.Truncate(ctx.pos) + pos := ctx.popPos() + text := ctx.Buffer.Bytes()[pos:] + ctx.Buffer.Truncate(pos) err := h.LinkRenderer.RenderLink( w, @@ -395,12 +394,13 @@ func (r *hookedRenderer) renderHeading(w util.BufWriter, source []byte, node ast if entering { // Store the current pos so we can capture the rendered text. - ctx.pos = ctx.Buffer.Len() + ctx.pushPos(ctx.Buffer.Len()) return ast.WalkContinue, nil } - text := ctx.Buffer.Bytes()[ctx.pos:] - ctx.Buffer.Truncate(ctx.pos) + pos := ctx.popPos() + text := ctx.Buffer.Bytes()[pos:] + ctx.Buffer.Truncate(pos) // All ast.Heading nodes are guaranteed to have an attribute called "id" // that is an array of bytes that encode a valid string. anchori, _ := n.AttributeString("id") @@ -440,8 +440,7 @@ func (r *hookedRenderer) renderHeadingDefault(w util.BufWriter, source []byte, n return ast.WalkContinue, nil } -type links struct { -} +type links struct{} // Extend implements goldmark.Extender. func (e *links) Extend(m goldmark.Markdown) { |