]> git.maquefel.me Git - brevno-suite/hugo/commitdiff
Fix auto generated header ids so they don't contain e.g. hyperlink destinations ...
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Sun, 16 Feb 2025 20:52:46 +0000 (21:52 +0100)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 17 Feb 2025 11:23:49 +0000 (12:23 +0100)
This makes the header ids match the newly added dt ids.

Also make sure newlines are preserved in hooks' `.PlainText`.

Fixes #13405
Fixes #13410

hugolib/content_render_hooks_test.go
markup/goldmark/goldmark_integration_test.go
markup/goldmark/internal/extensions/attributes/attributes.go
markup/goldmark/internal/extensions/attributes/attributes_integration_test.go
markup/goldmark/internal/render/context.go
markup/goldmark/toc_integration_test.go

index de8eb720f22e26f85038b480ff54050f605fb8eb..9df8d2e2e051f6a94886f971d6b1c00d7bb086ce 100644 (file)
@@ -350,3 +350,31 @@ Image: ![alt-"<>&](/destination-"<> 'title-"<>&')
                })
        }
 }
+
+// Issue 13410.
+func TestRenderHooksMultilineTitlePlainText(t *testing.T) {
+       t.Parallel()
+
+       files := `
+-- hugo.toml --
+-- content/p1.md --
+---
+title: "p1"
+---
+
+First line.
+Second line.
+----------------
+-- layouts/_default/_markup/render-heading.html --
+Plain text: {{ .PlainText }}|Text: {{ .Text }}|
+-- layouts/_default/single.html --
+Content: {{ .Content}}|
+}
+`
+       b := Test(t, files)
+
+       b.AssertFileContent("public/p1/index.html",
+               "Content: Plain text: First line.\nSecond line.|",
+               "|Text: First line.\nSecond line.||\n",
+       )
+}
index 184d0d7fc8c4bb13745042330f7f81191547742a..a656009515eb36ae2fa526a82ab2722bd0217638 100644 (file)
@@ -157,7 +157,7 @@ title: "p1"
        b := hugolib.Test(t, files)
 
        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>",
+               "<h2 id=\"hello-test\">\n  Hello <a href=\"https://example.com\">Test</a>\n\n  <a class=\"anchor\" href=\"#hello-test\">#</a>\n</h2>",
        )
 }
 
index 526635f4575fcae0c4a265ff1f6491112cb86bb1..f5f6f97b4debf6ba588185a16e18228f4b01dbe7 100644 (file)
@@ -1,6 +1,8 @@
 package attributes
 
 import (
+       "strings"
+
        "github.com/gohugoio/hugo/markup/goldmark/goldmark_config"
        "github.com/gohugoio/hugo/markup/goldmark/internal/render"
        "github.com/yuin/goldmark"
@@ -181,12 +183,17 @@ func (a *transformer) generateAutoID(n ast.Node, reader text.Reader, pc parser.C
 }
 
 // Markdown settext headers can have multiple lines, use the last line for the ID.
-func textHeadingID(node *ast.Heading, reader text.Reader) []byte {
-       var line []byte
-       lastIndex := node.Lines().Len() - 1
-       if lastIndex > -1 {
-               lastLine := node.Lines().At(lastIndex)
-               line = lastLine.Value(reader.Source())
+func textHeadingID(n *ast.Heading, reader text.Reader) []byte {
+       text := render.TextPlain(n, reader.Source())
+       if n.Lines().Len() > 1 {
+
+               // For multiline headings, Goldmark's extension for headings returns the last line.
+               // We have a slightly different approach, but in most cases the end result should be the same.
+               // Instead of looking at the text segments in Lines (see #13405 for issues with that),
+               // we split the text above and use the last line.
+               parts := strings.Split(text, "\n")
+               text = parts[len(parts)-1]
        }
-       return line
+
+       return []byte(text)
 }
index fcce68ac2388274d9c83f9539825f82f840d9beb..90cf3d08419d91d55cd59bf05e3fa6dfab9c0584 100644 (file)
@@ -47,10 +47,12 @@ foo [something](/a/b/) bar
 Ā ā Ă ă Ą ą Ć ć Ĉ ĉ Ċ ċ Č č Ď
 : Testing accents.
 
-Mutiline set text header
+Multiline set text header
 Second line
 ---------------
 
+## Example [hyperlink](https://example.com/) in a header
+
 -- layouts/_default/single.html --
 {{ .Content }}|Identifiers: {{ .Fragments.Identifiers }}|
 `
@@ -68,7 +70,8 @@ Second line
                `<dt id="my-title-1">My Title</dt>`,
                `<dt id="term">良善天父</dt>`,
                `<dt id="a-a-a-a-a-a-c-c-c-c-c-c-c-c-d">Ā ā Ă ă Ą ą Ć ć Ĉ ĉ Ċ ċ Č č Ď</dt>`,
-               `<h2 id="second-line">Mutiline set text header`,
-               "|Identifiers: [a-a-a-a-a-a-c-c-c-c-c-c-c-c-d base-name base-name-1 foo-something-bar foobar my-title my-title-1 second-line term title-with-id title-with-id]|",
+               `<h2 id="second-line">`,
+               `<h2 id="example-hyperlink-in-a-header">`,
+               "|Identifiers: [a-a-a-a-a-a-c-c-c-c-c-c-c-c-d base-name base-name-1 example-hyperlink-in-a-header foo-something-bar foobar my-title my-title-1 second-line term title-with-id title-with-id]|",
        )
 }
index 469ea72e3cd2f54a742698d036a75a5dfaf5063d..27029b6704ed4d09605479fededde81f27145244 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2024 The Hugo Authors. All rights reserved.
+// Copyright 2025 The Hugo Authors. All rights reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import (
        "sync"
 
        bp "github.com/gohugoio/hugo/bufferpool"
+       east "github.com/yuin/goldmark-emoji/ast"
 
        htext "github.com/gohugoio/hugo/common/text"
        "github.com/gohugoio/hugo/tpl"
@@ -282,6 +283,7 @@ func textPlainTo(c ast.Node, source []byte, buf *bytes.Buffer) {
        if c == nil {
                return
        }
+
        switch c := c.(type) {
        case *ast.RawHTML:
                s := strings.TrimSpace(tpl.StripHTML(string(c.Segments.Value(source))))
@@ -290,6 +292,11 @@ func textPlainTo(c ast.Node, source []byte, buf *bytes.Buffer) {
                buf.Write(c.Value)
        case *ast.Text:
                buf.Write(c.Segment.Value(source))
+               if c.HardLineBreak() || c.SoftLineBreak() {
+                       buf.WriteByte('\n')
+               }
+       case *east.Emoji:
+               buf.WriteString(string(c.ShortName))
        default:
                textPlainTo(c.FirstChild(), source, buf)
        }
index 3b48dac6cfc398b967bea5aaa3c9b93fba814a57..7ce2e86643f33e5b95ba90032f61a344ca4cf34b 100644 (file)
@@ -239,12 +239,12 @@ title: p7 (emoji)
 
        // image
        b.AssertFileContent("public/p3/index.html", `
-<li><a href="#an-image-kittenajpg">An image <img src="a.jpg" alt="kitten" /></a></li>
+<li><a href="#an-image-kitten">An image <img src="a.jpg" alt="kitten" /></a></li>
 `)
 
        // raw html
        b.AssertFileContent("public/p4/index.html", `
-<li><a href="#some-spanrawspan-html">Some <span>raw</span> HTML</a></li>
+<li><a href="#some-raw-html">Some <span>raw</span> HTML</a></li>
 `)
 
        // typographer