Repository: gohugoio/hugo (language: go)

Issue:
plaintext blocks after goat block are turned into goat blocks in v1.146
<!--
Please do not use the issue queue for questions or troubleshooting. Unless you are certain that your issue is a software defect, use the forum:

https://discourse.gohugo.io
-->

<!-- Please answer these questions before submitting your issue. Thanks! -->

Here's the repro case: https://github.com/jakebailey/hugo-goat-bug

````md
+++
date = '2025-04-11T09:06:44-07:00'
title = 'goat bug example'
+++

```goat
+---------------+
| Hello, world! |
+---------------+
```

```
This is just another code block!
```

{{< details summary="Expand me" >}}

```
This info is collapsed by default!
```

{{< /details >}}

Now, something else:

```go
package main
```

```
This is just another code block!
```

{{< details summary="Expand me" >}}

```
This info is collapsed by default!
```

{{< /details >}}
````

In 0.145, things work as expected; goat only runs on the goat blocks. But in 0.146, the goat block appears to apply to all of the other blocks too!

- Before: https://github.com/jakebailey/hugo-goat-bug/blob/7f744a768a0a15652fec4aa0ec85f4df9246ce6e/public-v0.145/posts/bug/index.html#L185
- After: https://github.com/jakebailey/hugo-goat-bug/blob/7f744a768a0a15652fec4aa0ec85f4df9246ce6e/public-v0.146/posts/bug/index.html#L312

This also bisects to #13541.

### What version of Hugo are you using (`hugo version`)?

<pre>
$ hugo version
hugo v0.146.1+extended linux/amd64 BuildDate=unknown
</pre>

### Does this issue reproduce with the latest release?
Yes


Discussion / hints:

Fix patch:
diff --git a/tpl/tplimpl/templatedescriptor.go b/tpl/tplimpl/templatedescriptor.go
index fc757126f86..f8cf0287090 100644
--- a/tpl/tplimpl/templatedescriptor.go
+++ b/tpl/tplimpl/templatedescriptor.go
@@ -60,12 +60,13 @@ type descriptorHandler struct {
 
 // Note that this in this setup is usually a descriptor constructed from a page,
 // so we want to find the best match for that page.
-func (s descriptorHandler) compareDescriptors(category Category, this, other TemplateDescriptor) weight {
+func (s descriptorHandler) compareDescriptors(category Category, isEmbedded bool, this, other TemplateDescriptor) weight {
 	if this.LayoutMustMatch && this.Layout != other.Layout {
 		return weightNoMatch
 	}
 
-	w := this.doCompare(category, other)
+	w := this.doCompare(category, isEmbedded, other)
+
 	if w.w1 <= 0 {
 		if category == CategoryMarkup && (this.Variant1 == other.Variant1) && (this.Variant2 == other.Variant2 || this.Variant2 != "" && other.Variant2 == "") {
 			// See issue 13242.
@@ -82,7 +83,7 @@ func (s descriptorHandler) compareDescriptors(category Category, this, other Tem
 }
 
 //lint:ignore ST1006 this vs other makes it easier to reason about.
-func (this TemplateDescriptor) doCompare(category Category, other TemplateDescriptor) weight {
+func (this TemplateDescriptor) doCompare(category Category, isEmbedded bool, other TemplateDescriptor) weight {
 	w := weightNoMatch
 
 	// HTML in plain text is OK, but not the other way around.
@@ -135,9 +136,15 @@ func (this TemplateDescriptor) doCompare(category Category, other TemplateDescri
 		return w
 	}
 
-	// If both are set and different, no match.
-	if other.Variant2 != "" && this.Variant2 != "" && other.Variant2 != this.Variant2 {
-		return w
+	if isEmbedded {
+		if other.Variant2 != "" && other.Variant2 != this.Variant2 {
+			return w
+		}
+	} else {
+		// If both are set and different, no match.
+		if other.Variant2 != "" && this.Variant2 != "" && other.Variant2 != this.Variant2 {
+			return w
+		}
 	}
 
 	const (


Test patch:
diff --git a/tpl/tplimpl/templatedescriptor_test.go b/tpl/tplimpl/templatedescriptor_test.go
index 76201287d46..6fb8c219515 100644
--- a/tpl/tplimpl/templatedescriptor_test.go
+++ b/tpl/tplimpl/templatedescriptor_test.go
@@ -20,14 +20,14 @@ func TestTemplateDescriptorCompare(t *testing.T) {
 
 	less := func(category Category, this, other1, other2 TemplateDescriptor) {
 		c.Helper()
-		result1 := dh.compareDescriptors(category, this, other1)
-		result2 := dh.compareDescriptors(category, this, other2)
+		result1 := dh.compareDescriptors(category, false, this, other1)
+		result2 := dh.compareDescriptors(category, false, this, other2)
 		c.Assert(result1.w1 < result2.w1, qt.IsTrue, qt.Commentf("%d < %d", result1, result2))
 	}
 
 	check := func(category Category, this, other TemplateDescriptor, less bool) {
 		c.Helper()
-		result := dh.compareDescriptors(category, this, other)
+		result := dh.compareDescriptors(category, false, this, other)
 		if less {
 			c.Assert(result.w1 < 0, qt.IsTrue, qt.Commentf("%d", result))
 		} else {
@@ -98,7 +98,7 @@ func BenchmarkCompareDescriptors(b *testing.B) {
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
 		for _, pair := range pairs {
-			_ = dh.compareDescriptors(CategoryLayout, pair.d1, pair.d2)
+			_ = dh.compareDescriptors(CategoryLayout, false, pair.d1, pair.d2)
 		}
 	}
 }
diff --git a/tpl/tplimpl/templatestore.go b/tpl/tplimpl/templatestore.go
index 8fe89586d02..6ef03053178 100644
--- a/tpl/tplimpl/templatestore.go
+++ b/tpl/tplimpl/templatestore.go
@@ -311,7 +311,7 @@ func (ti *TemplInfo) findBestMatchBaseof(s *TemplateStore, d1 TemplateDescriptor
 		distance := slashCountK1 - slashCountK2
 
 		for d2, vv := range v {
-			weight := s.dh.compareDescriptors(CategoryBaseof, d1, d2)
+			weight := s.dh.compareDescriptors(CategoryBaseof, false, d1, d2)
 			weight.distance = distance
 			if best.isBetter(weight, vv.Template) {
 				best.updateValues(weight, k2, d2, vv.Template)
@@ -447,7 +447,7 @@ func (s *TemplateStore) FindAllBaseTemplateCandidates(overlayKey string, desc Te
 				continue
 			}
 
-			if vv.D.isKindInLayout(desc.Layout) && s.dh.compareDescriptors(CategoryBaseof, descBaseof, vv.D).w1 > 0 {
+			if vv.D.isKindInLayout(desc.Layout) && s.dh.compareDescriptors(CategoryBaseof, false, descBaseof, vv.D).w1 > 0 {
 				result = append(result, keyTemplateInfo{Key: k, Info: vv})
 			}
 		}
@@ -584,7 +584,7 @@ func (s *TemplateStore) LookupShortcode(q TemplateQuery) *TemplInfo {
 				continue
 			}
 
-			weight := s.dh.compareDescriptors(q.Category, q.Desc, k)
+			weight := s.dh.compareDescriptors(q.Category, vv.subCategory == SubCategoryEmbedded, q.Desc, k)
 			weight.distance = distance
 			if best.isBetter(weight, vv) {
 				best.updateValues(weight, k2, k, vv)
@@ -737,7 +737,7 @@ func (s *TemplateStore) findBestMatchGet(key string, category Category, consider
 			continue
 		}
 
-		weight := s.dh.compareDescriptors(category, desc, k.d)
+		weight := s.dh.compareDescriptors(category, vv.subCategory == SubCategoryEmbedded, desc, k.d)
 		if best.isBetter(weight, vv) {
 			best.updateValues(weight, key, k.d, vv)
 		}
@@ -758,7 +758,7 @@ func (s *TemplateStore) findBestMatchWalkPath(q TemplateQuery, k1 string, slashC
 				continue
 			}
 
-			weight := s.dh.compareDescriptors(q.Category, q.Desc, k.d)
+			weight := s.dh.compareDescriptors(q.Category, vv.subCategory == SubCategoryEmbedded, q.Desc, k.d)
 
 			weight.distance = distance
 			isBetter := best.isBetter(weight, vv)
diff --git a/tpl/tplimpl/templatestore_integration_test.go b/tpl/tplimpl/templatestore_integration_test.go
index 74abe58d0fd..618c173fc76 100644
--- a/tpl/tplimpl/templatestore_integration_test.go
+++ b/tpl/tplimpl/templatestore_integration_test.go
@@ -826,6 +826,31 @@ func TestPartialHTML(t *testing.T) {
 	b.AssertFileContent("public/index.html", "<link rel=\"stylesheet\" href=\"/css/style.css\">")
 }
 
+// Issue #13593.
+func TestNoGoat(t *testing.T) {
+	t.Parallel()
+
+	files := `
+-- hugo.toml --
+-- content/_index.md --
+---
+title: "Home"
+---
+
+§§§
+printf "Hello, world!"
+§§§
+
+-- layouts/all.html --
+{{ .Content }}
+
+`
+
+	b := hugolib.Test(t, files)
+
+	b.AssertFileContent("public/index.html", "Hello, world!")
+}
+
 // Issue #13515
 func TestPrintPathWarningOnDotRemoval(t *testing.T) {
 	t.Parallel()