diff options
author | Joe Mooring <[email protected]> | 2024-12-09 10:58:52 -0800 |
---|---|---|
committer | Bjørn Erik Pedersen <[email protected]> | 2024-12-10 09:43:33 +0100 |
commit | 34373407b7778d66e2aaf009c6faeda5a1c2a866 (patch) | |
tree | e35fb4a2f4520e882d9bcfb399581ca698b5c522 | |
parent | 3afe91d4b1b069abbedd6a96ed755b1e12581dfe (diff) | |
download | hugo-34373407b7778d66e2aaf009c6faeda5a1c2a866.tar.gz hugo-34373407b7778d66e2aaf009c6faeda5a1c2a866.zip |
markup/goldmark: Fix blockquote render hook text parsing
Fixes #12913
Fixes #13119
-rw-r--r-- | markup/goldmark/blockquotes/blockquotes.go | 23 | ||||
-rw-r--r-- | markup/goldmark/blockquotes/blockquotes_integration_test.go | 126 |
2 files changed, 126 insertions, 23 deletions
diff --git a/markup/goldmark/blockquotes/blockquotes.go b/markup/goldmark/blockquotes/blockquotes.go index f9d518850..064200d5e 100644 --- a/markup/goldmark/blockquotes/blockquotes.go +++ b/markup/goldmark/blockquotes/blockquotes.go @@ -74,7 +74,7 @@ func (r *htmlRenderer) renderBlockquote(w util.BufWriter, src []byte, node ast.N ordinal := ctx.GetAndIncrementOrdinal(ast.KindBlockquote) typ := typeRegular - alert := resolveBlockQuoteAlert(string(text)) + alert := resolveBlockQuoteAlert(text) if alert.typ != "" { typ = typeAlert } @@ -85,10 +85,21 @@ func (r *htmlRenderer) renderBlockquote(w util.BufWriter, src []byte, node ast.N } if typ == typeAlert { - // Trim preamble: <p>[!NOTE]<br>\n but preserve leading paragraph. - // We could possibly complicate this by moving this to the parser, but - // keep it simple for now. - text = "<p>" + text[strings.Index(text, "\n")+1:] + // Parse the blockquote content to determine the alert text. The alert + // text begins after the first newline, but we need to add an opening p + // tag if the first line of the blockquote content does not have a + // closing p tag. At some point we might want to move this to the + // parser. + before, after, found := strings.Cut(strings.TrimSpace(text), "\n") + if found { + if strings.HasSuffix(before, "</p>") { + text = after + } else { + text = "<p>" + after + } + } else { + text = "" + } } bqctx := &blockquoteContext{ @@ -165,7 +176,7 @@ func resolveBlockQuoteAlert(s string) blockQuoteAlert { m := blockQuoteAlertRe.FindStringSubmatch(s) if len(m) == 4 { title := strings.TrimSpace(m[3]) - title = strings.TrimRight(title, "</p>") + title = strings.TrimSuffix(title, "</p>") return blockQuoteAlert{ typ: strings.ToLower(m[1]), sign: m[2], diff --git a/markup/goldmark/blockquotes/blockquotes_integration_test.go b/markup/goldmark/blockquotes/blockquotes_integration_test.go index 1f671df2b..93fe5b27d 100644 --- a/markup/goldmark/blockquotes/blockquotes_integration_test.go +++ b/markup/goldmark/blockquotes/blockquotes_integration_test.go @@ -48,10 +48,9 @@ Content: {{ .Content }} title: "p1" --- -> [!NOTE] +> [!NOTE] > This is a note with some whitespace after the alert type. - > [!TIP] > This is a tip. @@ -64,29 +63,26 @@ title: "p1" > This is a tip with attributes. {class="foo bar" id="baz"} -> [!NOTE] +> [!NOTE] > Note triggering showing the position. {showpos="true"} - -> [!nOtE] +> [!nOtE] > Mixed case alert type. - - ` b := hugolib.Test(t, files) b.AssertFileContentExact("public/p1/index.html", - "Blockquote Alert: |<p>This is a note with some whitespace after the alert type.</p>\n|alert|", + "Blockquote Alert: |<p>This is a note with some whitespace after the alert type.</p>|alert|", "Blockquote Alert: |<p>This is a tip.</p>", - "Blockquote Alert: |<p>This is a caution with some whitespace before the alert type.</p>\n|alert|", + "Blockquote Alert: |<p>This is a caution with some whitespace before the alert type.</p>|alert|", "Blockquote: |<p>A regular blockquote.</p>\n|regular|", - "Blockquote Alert Attributes: |<p>This is a tip with attributes.</p>\n|map[class:foo bar id:baz]|", - filepath.FromSlash("/content/p1.md:20:3"), - "Blockquote Alert Page: |<p>This is a tip with attributes.</p>\n|p1|p1|", + "Blockquote Alert Attributes: |<p>This is a tip with attributes.</p>|map[class:foo bar id:baz]|", + filepath.FromSlash("/content/p1.md:19:3"), + "Blockquote Alert Page: |<p>This is a tip with attributes.</p>|p1|p1|", // Issue 12767. - "Blockquote Alert: |<p>Mixed case alert type.</p>\n|alert", + "Blockquote Alert: |<p>Mixed case alert type.</p>|alert", ) } @@ -142,17 +138,113 @@ title: "Home" {{ .Content }} -- layouts/_default/_markup/render-blockquote.html -- AlertType: {{ .AlertType }}|AlertTitle: {{ .AlertTitle }}|AlertSign: {{ .AlertSign | safeHTML }}|Text: {{ .Text }}| - + ` b := hugolib.Test(t, files) b.AssertFileContentExact("public/index.html", "AlertType: tip|AlertTitle: Callouts can have custom titles|AlertSign: |", "AlertType: tip|AlertTitle: Title-only callout|AlertSign: |", - "AlertType: faq|AlertTitle: Foldable negated callout|AlertSign: -|Text: <p>Yes! In a foldable callout, the contents are hidden when the callout is collapsed</p>\n|", - "AlertType: faq|AlertTitle: Foldable callout|AlertSign: +|Text: <p>Yes! In a foldable callout, the contents are hidden when the callout is collapsed</p>\n|", - "AlertType: danger|AlertTitle: |AlertSign: |Text: <p>Do not approach or handle without protective gear.</p>\n|", + "AlertType: faq|AlertTitle: Foldable negated callout|AlertSign: -|Text: <p>Yes! In a foldable callout, the contents are hidden when the callout is collapsed</p>|", + "AlertType: faq|AlertTitle: Foldable callout|AlertSign: +|Text: <p>Yes! In a foldable callout, the contents are hidden when the callout is collapsed</p>|", + "AlertType: danger|AlertTitle: |AlertSign: |Text: <p>Do not approach or handle without protective gear.</p>|", "AlertTitle: Can callouts be nested?|", "AlertTitle: You can even use multiple layers of nesting.|", ) } + +// Issue 12913 +// Issue 13119 +func TestBlockquoteRenderHookTextParsing(t *testing.T) { + t.Parallel() + + files := ` +-- hugo.toml -- +disableKinds = ['page','rss','section','sitemap','taxonomy','term'] +-- layouts/index.html -- +{{ .Content }} +-- layouts/_default/_markup/render-blockquote.html -- +AlertType: {{ .AlertType }}|AlertTitle: {{ .AlertTitle }}|Text: {{ .Text }}| +-- content/_index.md -- +--- +title: home +--- + +> [!one] + +> [!two] title + +> [!three] +> line 1 + +> [!four] title +> line 1 + +> [!five] +> line 1 +> line 2 + +> [!six] title +> line 1 +> line 2 + +> [!seven] +> - list item + +> [!eight] title +> - list item + +> [!nine] +> line 1 +> - list item + +> [!ten] title +> line 1 +> - list item + +> [!eleven] +> line 1 +> - list item +> +> line 2 + +> [!twelve] title +> line 1 +> - list item +> +> line 2 + +> [!thirteen] +> ![alt](a.jpg) + +> [!fourteen] title +> ![alt](a.jpg) + +> [!fifteen] _title_ + +> [!sixteen] _title_ +> line one + +` + + b := hugolib.Test(t, files) + + b.AssertFileContent("public/index.html", + "AlertType: one|AlertTitle: |Text: |", + "AlertType: two|AlertTitle: title|Text: |", + "AlertType: three|AlertTitle: |Text: <p>line 1</p>|", + "AlertType: four|AlertTitle: title|Text: <p>line 1</p>|", + "AlertType: five|AlertTitle: |Text: <p>line 1\nline 2</p>|", + "AlertType: six|AlertTitle: title|Text: <p>line 1\nline 2</p>|", + "AlertType: seven|AlertTitle: |Text: <ul>\n<li>list item</li>\n</ul>|", + "AlertType: eight|AlertTitle: title|Text: <ul>\n<li>list item</li>\n</ul>|", + "AlertType: nine|AlertTitle: |Text: <p>line 1</p>\n<ul>\n<li>list item</li>\n</ul>|", + "AlertType: ten|AlertTitle: title|Text: <p>line 1</p>\n<ul>\n<li>list item</li>\n</ul>|", + "AlertType: eleven|AlertTitle: |Text: <p>line 1</p>\n<ul>\n<li>list item</li>\n</ul>\n<p>line 2</p>|", + "AlertType: twelve|AlertTitle: title|Text: <p>line 1</p>\n<ul>\n<li>list item</li>\n</ul>\n<p>line 2</p>|", + "AlertType: thirteen|AlertTitle: |Text: <p><img src=\"a.jpg\" alt=\"alt\"></p>|", + "AlertType: fourteen|AlertTitle: title|Text: <p><img src=\"a.jpg\" alt=\"alt\"></p>|", + "AlertType: fifteen|AlertTitle: <em>title</em>|Text: |", + "AlertType: sixteen|AlertTitle: <em>title</em>|Text: <p>line one</p>|", + ) +} |