Repository: gohugoio/hugo (language: go)

Issue:
Empty paragraphs added with .RenderShortcodes
Reference: <https://discourse.gohugo.io/t/52431>

The test below passes with v0.124.1, and fails with v0.125.0 and later.

```go
func TestFoo(t *testing.T) {
	t.Parallel()

	files := `
-- hugo.toml --
disableKinds = ['section','rss','sitemap','taxonomy','term']
-- layouts/_default/home.html --
{{ .Content }}
-- layouts/_default/single.html --
{{ .Content }}
-- layouts/shortcodes/include.html --
 {{ with site.GetPage (.Get 0) }}
  {{ .RenderShortcodes }}
{{ end }}
-- content/_index.md --
---
title: home
---

a

{{% include "/snippet" %}}

b

-- content/snippet.md --
---
title: snippet
build:
  render: never
  list: never
---

_emphasized_

`

	b := hugolib.Test(t, files)
	b.AssertFileContentEquals("public/index.html",
		"<p>a</p>\n<p><em>emphasized</em></p>\n<p>b</p>\n",
	)
}
```

got:

    "<p>a</p>\n<p></p>\n<p><em>emphasized</em>\n</p>\n<p>b</p>\n"
               -------                        --
want:

    "<p>a</p>\n<p><em>emphasized</em></p>\n<p>b</p>\n"


Discussion / hints:

Fix patch:
diff --git a/markup/goldmark/hugocontext/hugocontext.go b/markup/goldmark/hugocontext/hugocontext.go
index b1f149d0b86..601014b3705 100644
--- a/markup/goldmark/hugocontext/hugocontext.go
+++ b/markup/goldmark/hugocontext/hugocontext.go
@@ -242,6 +242,39 @@ func (r *hugoContextRenderer) handleHugoContext(w util.BufWriter, source []byte,
 	return ast.WalkContinue, nil
 }
 
+type hugoContextTransformer struct{}
+
+var _ parser.ASTTransformer = (*hugoContextTransformer)(nil)
+
+func (a *hugoContextTransformer) Transform(n *ast.Document, reader text.Reader, pc parser.Context) {
+	ast.Walk(n, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
+		s := ast.WalkContinue
+		if !entering || n.Kind() != kindHugoContext {
+			return s, nil
+		}
+
+		if p, ok := n.Parent().(*ast.Paragraph); ok {
+			if p.ChildCount() == 1 {
+				// Avoid empty paragraphs.
+				p.Parent().ReplaceChild(p.Parent(), p, n)
+			} else {
+				if t, ok := n.PreviousSibling().(*ast.Text); ok {
+					// Remove the newline produced by the Hugo context markers.
+					if t.SoftLineBreak() {
+						if t.Segment.Len() == 0 {
+							p.RemoveChild(p, t)
+						} else {
+							t.SetSoftLineBreak(false)
+						}
+					}
+				}
+			}
+		}
+
+		return s, nil
+	})
+}
+
 type hugoContextExtension struct {
 	logger loggers.Logger
 }
@@ -251,6 +284,7 @@ func (a *hugoContextExtension) Extend(m goldmark.Markdown) {
 		parser.WithInlineParsers(
 			util.Prioritized(&hugoContextParser{}, 50),
 		),
+		parser.WithASTTransformers(util.Prioritized(&hugoContextTransformer{}, 10)),
 	)
 
 	m.Renderer().AddOptions(


Test patch:
diff --git a/hugolib/rendershortcodes_test.go b/hugolib/rendershortcodes_test.go
index 0eebf46eb3e..d8b51d3ed47 100644
--- a/hugolib/rendershortcodes_test.go
+++ b/hugolib/rendershortcodes_test.go
@@ -434,16 +434,16 @@ code_p3
 	b := TestRunning(t, files, TestOptWarn())
 
 	b.AssertNoRenderShortcodesArtifacts()
-	b.AssertFileContentEquals("public/p1/index.html", "<p>Content p1 id-1000.</p>\n<code>code_p2</code><p>Foo.\n</p>\n<code>code_p3</code><p></p>\n<code>code_p1</code><code>code_p1_2</code><code>code_p1_3</code>")
+	b.AssertFileContentEquals("public/p1/index.html", "<p>Content p1 id-1000.</p>\n<code>code_p2</code><p>Foo.</p>\n<code>code_p3</code><code>code_p1</code><code>code_p1_2</code><code>code_p1_3</code>")
 	b.EditFileReplaceAll("content/p1.md", "id-1000.", "id-100.").Build()
 	b.AssertNoRenderShortcodesArtifacts()
-	b.AssertFileContentEquals("public/p1/index.html", "<p>Content p1 id-100.</p>\n<code>code_p2</code><p>Foo.\n</p>\n<code>code_p3</code><p></p>\n<code>code_p1</code><code>code_p1_2</code><code>code_p1_3</code>")
+	b.AssertFileContentEquals("public/p1/index.html", "<p>Content p1 id-100.</p>\n<code>code_p2</code><p>Foo.</p>\n<code>code_p3</code><code>code_p1</code><code>code_p1_2</code><code>code_p1_3</code>")
 	b.EditFileReplaceAll("content/p2.md", "code_p2", "codep2").Build()
 	b.AssertNoRenderShortcodesArtifacts()
-	b.AssertFileContentEquals("public/p1/index.html", "<p>Content p1 id-100.</p>\n<code>codep2</code><p>Foo.\n</p>\n<code>code_p3</code><p></p>\n<code>code_p1</code><code>code_p1_2</code><code>code_p1_3</code>")
+	b.AssertFileContentEquals("public/p1/index.html", "<p>Content p1 id-100.</p>\n<code>codep2</code><p>Foo.</p>\n<code>code_p3</code><code>code_p1</code><code>code_p1_2</code><code>code_p1_3</code>")
 	b.EditFileReplaceAll("content/p3.md", "code_p3", "code_p3_edited").Build()
 	b.AssertNoRenderShortcodesArtifacts()
-	b.AssertFileContentEquals("public/p1/index.html", "<p>Content p1 id-100.</p>\n<code>codep2</code><p>Foo.\n</p>\n<code>code_p3_edited</code><p></p>\n<code>code_p1</code><code>code_p1_2</code><code>code_p1_3</code>")
+	b.AssertFileContentEquals("public/p1/index.html", "<p>Content p1 id-100.</p>\n<code>codep2</code><p>Foo.</p>\n<code>code_p3_edited</code><code>code_p1</code><code>code_p1_2</code><code>code_p1_3</code>")
 }
 
 // Issue 13004.
@@ -475,8 +475,55 @@ This is some **markup**.
 `
 	b := TestRunning(t, files)
 	b.AssertNoRenderShortcodesArtifacts()
-	b.AssertFileContentEquals("public/first/p1/index.html", "<h2 id=\"p1-h1\">p1-h1</h2>\n<p></p>\n<h3 id=\"p2-h1\">p2-h1</h3>\n<p>This is some <strong>markup</strong>.\n</p>\n")
+	b.AssertFileContentEquals("public/first/p1/index.html", "<h2 id=\"p1-h1\">p1-h1</h2>\n<h3 id=\"p2-h1\">p2-h1</h3>\n<p>This is some <strong>markup</strong>.</p>\n")
 	b.EditFileReplaceAll("content/second/p2.md", "p2-h1", "p2-h1-edited").Build()
 	b.AssertNoRenderShortcodesArtifacts()
-	b.AssertFileContentEquals("public/first/p1/index.html", "<h2 id=\"p1-h1\">p1-h1</h2>\n<p></p>\n<h3 id=\"p2-h1-edited\">p2-h1-edited</h3>\n<p>This is some <strong>markup</strong>.\n</p>\n")
+	b.AssertFileContentEquals("public/first/p1/index.html", "<h2 id=\"p1-h1\">p1-h1</h2>\n<h3 id=\"p2-h1-edited\">p2-h1-edited</h3>\n<p>This is some <strong>markup</strong>.</p>\n")
+}
+
+// Issue 13051.
+func TestRenderShortcodesEmptyParagraph(t *testing.T) {
+	t.Parallel()
+
+	files := `
+-- hugo.toml --
+disableKinds = ['section','rss','sitemap','taxonomy','term']
+-- layouts/_default/home.html --
+{{ .Content }}
+-- layouts/_default/single.html --
+{{ .Content }}
+-- layouts/shortcodes/include.html --
+ {{ with site.GetPage (.Get 0) }}
+  {{ .RenderShortcodes }}
+{{ end }}
+-- content/_index.md --
+---
+title: home
+---
+
+a
+
+{{% include "/snippet" %}}
+
+b
+
+-- content/snippet.md --
+---
+title: snippet
+build:
+  render: never
+  list: never
+---
+
+_emphasized_
+
+not emphasized
+
+`
+
+	b := Test(t, files)
+	b.AssertNoRenderShortcodesArtifacts()
+	b.AssertFileContentEquals("public/index.html",
+		"<p>a</p>\n<p><em>emphasized</em></p>\n<p>not emphasized</p>\n<p>b</p>\n",
+	)
 }
diff --git a/markup/goldmark/goldmark_integration_test.go b/markup/goldmark/goldmark_integration_test.go
index 794f34150a4..591226dc2fe 100644
--- a/markup/goldmark/goldmark_integration_test.go
+++ b/markup/goldmark/goldmark_integration_test.go
@@ -575,7 +575,7 @@ sc3_begin|{{ .Inner }}|sc3_end
 		// Issue #7332
 		"<span>:x:\n</span>",
 		// Issue #11587
-		"<p>&#x2714;&#xfe0f;\n</p>",
+		"<p>&#x2714;&#xfe0f;</p>",
 		// Should not be converted to emoji
 		"sc1_begin|:smiley:|sc1_end",
 		// Should be converted to emoji