mirror of
https://github.com/gohugoio/hugo.git
synced 2026-08-24 15:28:54 +00:00
Fix panic when passthrough elements are used in headings
Fixes #14677 Co-Authored-By: xingzihai <1315258019@qq.com> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -122,6 +122,12 @@ func newMarkdown(pcfg converter.ProviderConfig) goldmark.Markdown {
|
||||
)
|
||||
}
|
||||
|
||||
if cfg.Extensions.Passthrough.Enable {
|
||||
tocRendererOptions = append(tocRendererOptions,
|
||||
renderer.WithNodeRenderers(util.Prioritized(&tocPassthroughRenderer{}, 90)),
|
||||
)
|
||||
}
|
||||
|
||||
var (
|
||||
extensions = []goldmark.Extender{
|
||||
hugocontext.New(pcfg.Logger),
|
||||
|
||||
+28
-1
@@ -24,6 +24,7 @@ import (
|
||||
emojiAst "github.com/yuin/goldmark-emoji/ast"
|
||||
|
||||
"github.com/gohugoio/hugo-goldmark-extensions/extras"
|
||||
"github.com/gohugoio/hugo-goldmark-extensions/passthrough"
|
||||
"github.com/gohugoio/hugo/markup/tableofcontents"
|
||||
|
||||
"github.com/yuin/goldmark"
|
||||
@@ -116,7 +117,9 @@ func (t *tocTransformer) Transform(n *ast.Document, reader text.Reader, pc parse
|
||||
ast.KindAutoLink,
|
||||
ast.KindRawHTML,
|
||||
ast.KindText,
|
||||
ast.KindString:
|
||||
ast.KindString,
|
||||
passthrough.KindPassthroughInline,
|
||||
passthrough.KindPassthroughBlock:
|
||||
err := t.r.Render(&headingText, reader.Source(), n)
|
||||
if err != nil {
|
||||
return s, err
|
||||
@@ -171,6 +174,30 @@ func newTOCSanitizerPolicy() *bluemonday.Policy {
|
||||
return p
|
||||
}
|
||||
|
||||
// tocPassthroughRenderer renders passthrough nodes as raw text for the TOC.
|
||||
type tocPassthroughRenderer struct{}
|
||||
|
||||
func (r *tocPassthroughRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
|
||||
reg.Register(passthrough.KindPassthroughInline, r.render)
|
||||
reg.Register(passthrough.KindPassthroughBlock, r.render)
|
||||
}
|
||||
|
||||
func (r *tocPassthroughRenderer) render(w util.BufWriter, src []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||
if !entering {
|
||||
return ast.WalkContinue, nil
|
||||
}
|
||||
switch nn := node.(type) {
|
||||
case *passthrough.PassthroughInline:
|
||||
w.Write(nn.Segment.Value(src))
|
||||
case *passthrough.PassthroughBlock:
|
||||
for i := range nn.Lines().Len() {
|
||||
line := nn.Lines().At(i)
|
||||
w.Write(line.Value(src))
|
||||
}
|
||||
}
|
||||
return ast.WalkSkipChildren, nil
|
||||
}
|
||||
|
||||
var whiteSpaceRe = regexp.MustCompile(`\s+`)
|
||||
|
||||
// sanitizeTOCHeadingTitle sanitizes s for use as a TOC heading title.
|
||||
|
||||
@@ -364,3 +364,37 @@ title: home
|
||||
`<li><a href="#1st">1^st^</a></li>`,
|
||||
)
|
||||
}
|
||||
|
||||
// Issue 14677
|
||||
func TestTableOfContentsWithPassthrough(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
files := `
|
||||
-- hugo.toml --
|
||||
disableKinds = ['page','rss','section','sitemap','taxonomy','term']
|
||||
[markup.goldmark.extensions.passthrough]
|
||||
enable = true
|
||||
[markup.goldmark.extensions.passthrough.delimiters]
|
||||
inline = [['$', '$']]
|
||||
-- content/_index.md --
|
||||
---
|
||||
title: home
|
||||
---
|
||||
## Heading with **$a$**
|
||||
|
||||
## Heading with $b$
|
||||
|
||||
## Heading with *$x + y$*
|
||||
|
||||
-- layouts/home.html --
|
||||
{{ .TableOfContents }}
|
||||
`
|
||||
|
||||
b := hugolib.Test(t, files)
|
||||
|
||||
b.AssertFileContent("public/index.html",
|
||||
`<li><a href="#heading-with">Heading with <strong>$a$</strong></a></li>`,
|
||||
`<li><a href="#heading-with-1">Heading with $b$</a></li>`,
|
||||
`<li><a href="#heading-with-2">Heading with <em>$x + y$</em></a></li>`,
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user