Repository: gohugoio/hugo (language: go)

Issue:
Throw the "Raw HTML omitted" warning whenever Goldmark replaces raw HTML
This usage is somewhat common:

```text
column<br>one|column<br>two
:--|:--
a|b
```

Which obviously only works with this site configuration:

```text
[markup.goldmark.renderer]
unsafe = true
```

But when the above is `false` I expected to see the "Raw HTML omitted..." warning introduced in v0.137.0. 




Discussion / hints:
OK, I guess my expectations are wrong. It seems that this warning only applies to block level HTML elements. For example, this emits a warning:

```text
<div>one</div>
```

But this does not:

```text
<em>one</em>
```

It would nice if we emitted the warning whenever Goldmark replaces _any_ HTML with the `<!-- raw HTML omitted -->` comment. 

So, changing this to a proposal.

Reference: <https://discourse.gohugo.io/t/warnings-when-mixing-html-and-markdown/52280>

Fix patch:
diff --git a/commands/deploy.go b/commands/deploy.go
index f9c22be48f2..eb419dabaf8 100644
--- a/commands/deploy.go
+++ b/commands/deploy.go
@@ -20,7 +20,6 @@ import (
 	"context"
 
 	"github.com/gohugoio/hugo/deploy"
-	"github.com/gohugoio/hugo/deploy/deployconfig"
 
 	"github.com/bep/simplecobra"
 	"github.com/spf13/cobra"
@@ -47,17 +46,7 @@ documentation.
 			return deployer.Deploy(ctx)
 		},
 		withc: func(cmd *cobra.Command, r *rootCommand) {
-			cmd.ValidArgsFunction = cobra.NoFileCompletions
-			cmd.Flags().String("target", "", "target deployment from deployments section in config file; defaults to the first one")
-			_ = cmd.RegisterFlagCompletionFunc("target", cobra.NoFileCompletions)
-			cmd.Flags().Bool("confirm", false, "ask for confirmation before making changes to the target")
-			cmd.Flags().Bool("dryRun", false, "dry run")
-			cmd.Flags().Bool("force", false, "force upload of all files")
-			cmd.Flags().Bool("invalidateCDN", deployconfig.DefaultConfig.InvalidateCDN, "invalidate the CDN cache listed in the deployment target")
-			cmd.Flags().Int("maxDeletes", deployconfig.DefaultConfig.MaxDeletes, "maximum # of files to delete, or -1 to disable")
-			_ = cmd.RegisterFlagCompletionFunc("maxDeletes", cobra.NoFileCompletions)
-			cmd.Flags().Int("workers", deployconfig.DefaultConfig.Workers, "number of workers to transfer files. defaults to 10")
-			_ = cmd.RegisterFlagCompletionFunc("workers", cobra.NoFileCompletions)
+			applyDeployFlags(cmd, r)
 		},
 	}
 }
diff --git a/commands/deploy_flags.go b/commands/deploy_flags.go
new file mode 100644
index 00000000000..d4326547ab3
--- /dev/null
+++ b/commands/deploy_flags.go
@@ -0,0 +1,33 @@
+// Copyright 2024 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.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package commands
+
+import (
+	"github.com/gohugoio/hugo/deploy/deployconfig"
+	"github.com/spf13/cobra"
+)
+
+func applyDeployFlags(cmd *cobra.Command, r *rootCommand) {
+	cmd.ValidArgsFunction = cobra.NoFileCompletions
+	cmd.Flags().String("target", "", "target deployment from deployments section in config file; defaults to the first one")
+	_ = cmd.RegisterFlagCompletionFunc("target", cobra.NoFileCompletions)
+	cmd.Flags().Bool("confirm", false, "ask for confirmation before making changes to the target")
+	cmd.Flags().Bool("dryRun", false, "dry run")
+	cmd.Flags().Bool("force", false, "force upload of all files")
+	cmd.Flags().Bool("invalidateCDN", deployconfig.DefaultConfig.InvalidateCDN, "invalidate the CDN cache listed in the deployment target")
+	cmd.Flags().Int("maxDeletes", deployconfig.DefaultConfig.MaxDeletes, "maximum # of files to delete, or -1 to disable")
+	_ = cmd.RegisterFlagCompletionFunc("maxDeletes", cobra.NoFileCompletions)
+	cmd.Flags().Int("workers", deployconfig.DefaultConfig.Workers, "number of workers to transfer files. defaults to 10")
+	_ = cmd.RegisterFlagCompletionFunc("workers", cobra.NoFileCompletions)
+}
diff --git a/commands/deploy_off.go b/commands/deploy_off.go
index 7eb6429c513..32a08da2eca 100644
--- a/commands/deploy_off.go
+++ b/commands/deploy_off.go
@@ -44,6 +44,7 @@ func newDeployCommand() simplecobra.Commander {
 			return errors.New("deploy not supported in this version of Hugo; install a release with 'withdeploy' in the archive filename or build yourself with the 'withdeploy' build tag. Also see https://github.com/gohugoio/hugo/pull/12995")
 		},
 		withc: func(cmd *cobra.Command, r *rootCommand) {
+			applyDeployFlags(cmd, r)
 			cmd.Hidden = true
 		},
 	}
diff --git a/common/hugo/vars_withdeploy.go b/common/hugo/vars_withdeploy.go
new file mode 100644
index 00000000000..88ce9a1cdbe
--- /dev/null
+++ b/common/hugo/vars_withdeploy.go
@@ -0,0 +1,19 @@
+// Copyright 2024 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.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//go:build withdeploy
+// +build withdeploy
+
+package hugo
+
+var IsWithdeploy = true
diff --git a/common/hugo/vars_withdeploy_off.go b/common/hugo/vars_withdeploy_off.go
new file mode 100644
index 00000000000..93556802702
--- /dev/null
+++ b/common/hugo/vars_withdeploy_off.go
@@ -0,0 +1,19 @@
+// Copyright 2024 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.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//go:build !withdeploy
+// +build !withdeploy
+
+package hugo
+
+var IsWithdeploy = false
diff --git a/common/hugo/version.go b/common/hugo/version.go
index 6cabfdbb964..cf598884069 100644
--- a/common/hugo/version.go
+++ b/common/hugo/version.go
@@ -152,6 +152,9 @@ func BuildVersionString() string {
 	if IsExtended {
 		version += "+extended"
 	}
+	if IsWithdeploy {
+		version += "+withdeploy"
+	}
 
 	osArch := bi.GoOS + "/" + bi.GoArch
 
diff --git a/hugoreleaser.toml b/hugoreleaser.toml
index 8c369373981..2cb8e3665ee 100644
--- a/hugoreleaser.toml
+++ b/hugoreleaser.toml
@@ -185,6 +185,25 @@ archive_alias_replacements = { "linux-amd64.tar.gz" = "Linux-64bit.tar.gz" }
         [[builds.os.archs]]
             goarch = "amd64"
 
+[[builds]]
+    path = "container1/windows/extended-withdeploy"
+
+    [builds.build_settings]
+        flags = ["-buildmode", "exe", "-tags", "extended,withdeploy"]
+        env = [
+            "CGO_ENABLED=1",
+            "CC=x86_64-w64-mingw32-gcc",
+            "CXX=x86_64-w64-mingw32-g++",
+        ]
+        ldflags = "-s -w -X github.com/gohugoio/hugo/common/hugo.vendorInfo=gohugoio -extldflags '-static'"
+
+    [[builds.os]]
+        goos = "windows"
+        [builds.os.build_settings]
+            binary = "hugo.exe"
+        [[builds.os.archs]]
+            goarch = "amd64"
+
 [[archives]]
     paths = ["builds/container1/unix/regular/**"]
 [[archives]]
@@ -212,6 +231,13 @@ archive_alias_replacements = { "linux-amd64.tar.gz" = "Linux-64bit.tar.gz" }
         [archives.archive_settings.type]
             format    = "zip"
             extension = ".zip"
+[[archives]]
+    paths = ["builds/**/windows/extended-withdeploy/**"]
+    [archives.archive_settings]
+        name_template = "{{ .Project }}_extended_withdeploy_{{ .Tag | trimPrefix `v` }}_{{ .Goos }}-{{ .Goarch }}"
+        [archives.archive_settings.type]
+            format    = "zip"
+            extension = ".zip"
 [[archives]]
     paths = ["builds/**/regular/linux/{arm64,amd64}"]
     [archives.archive_settings]
diff --git a/markup/goldmark/hugocontext/hugocontext.go b/markup/goldmark/hugocontext/hugocontext.go
index 4971456be42..a10e095efb9 100644
--- a/markup/goldmark/hugocontext/hugocontext.go
+++ b/markup/goldmark/hugocontext/hugocontext.go
@@ -145,6 +145,7 @@ func (r *hugoContextRenderer) SetOption(name renderer.OptionName, value any) {
 
 func (r *hugoContextRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
 	reg.Register(kindHugoContext, r.handleHugoContext)
+	reg.Register(ast.KindRawHTML, r.renderRawHTML)
 	reg.Register(ast.KindHTMLBlock, r.renderHTMLBlock)
 }
 
@@ -155,16 +156,25 @@ func (r *hugoContextRenderer) stripHugoCtx(b []byte) ([]byte, bool) {
 	return hugoCtxRe.ReplaceAll(b, nil), true
 }
 
+func (r *hugoContextRenderer) logRawHTMLEmittedWarn(w util.BufWriter) {
+	r.logger.Warnidf(constants.WarnGoldmarkRawHTML, "Raw HTML omitted from %q; see https://gohugo.io/getting-started/configuration-markup/#rendererunsafe", r.getPage(w))
+}
+
+func (r *hugoContextRenderer) getPage(w util.BufWriter) any {
+	var p any
+	ctx, ok := w.(*render.Context)
+	if ok {
+		p, _ = render.GetPageAndPageInner(ctx)
+	}
+	return p
+}
+
+// HTML rendering based on Goldmark implementation.
 func (r *hugoContextRenderer) renderHTMLBlock(
 	w util.BufWriter, source []byte, node ast.Node, entering bool,
 ) (ast.WalkStatus, error) {
 	n := node.(*ast.HTMLBlock)
 	if entering {
-		var p any
-		ctx, ok := w.(*render.Context)
-		if ok {
-			p, _ = render.GetPageAndPageInner(ctx)
-		}
 		if r.Unsafe {
 			l := n.Lines().Len()
 			for i := 0; i < l; i++ {
@@ -173,12 +183,12 @@ func (r *hugoContextRenderer) renderHTMLBlock(
 				var stripped bool
 				linev, stripped = r.stripHugoCtx(linev)
 				if stripped {
-					r.logger.Warnidf(constants.WarnRenderShortcodesInHTML, ".RenderShortcodes detected inside HTML block in %q; this may not be what you intended, see https://gohugo.io/methods/page/rendershortcodes/#limitations", p)
+					r.logger.Warnidf(constants.WarnRenderShortcodesInHTML, ".RenderShortcodes detected inside HTML block in %q; this may not be what you intended, see https://gohugo.io/methods/page/rendershortcodes/#limitations", r.getPage(w))
 				}
 				r.Writer.SecureWrite(w, linev)
 			}
 		} else {
-			r.logger.Warnidf(constants.WarnGoldmarkRawHTML, "Raw HTML omitted from %q; see https://gohugo.io/getting-started/configuration-markup/#rendererunsafe", p)
+			r.logRawHTMLEmittedWarn(w)
 			_, _ = w.WriteString("<!-- raw HTML omitted -->\n")
 		}
 	} else {
@@ -194,6 +204,26 @@ func (r *hugoContextRenderer) renderHTMLBlock(
 	return ast.WalkContinue, nil
 }
 
+func (r *hugoContextRenderer) renderRawHTML(
+	w util.BufWriter, source []byte, node ast.Node, entering bool,
+) (ast.WalkStatus, error) {
+	if !entering {
+		return ast.WalkSkipChildren, nil
+	}
+	if r.Unsafe {
+		n := node.(*ast.RawHTML)
+		l := n.Segments.Len()
+		for i := 0; i < l; i++ {
+			segment := n.Segments.At(i)
+			_, _ = w.Write(segment.Value(source))
+		}
+		return ast.WalkSkipChildren, nil
+	}
+	r.logRawHTMLEmittedWarn(w)
+	_, _ = w.WriteString("<!-- raw HTML omitted -->")
+	return ast.WalkSkipChildren, nil
+}
+
 func (r *hugoContextRenderer) handleHugoContext(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
 	if !entering {
 		return ast.WalkContinue, nil


Test patch:
diff --git a/main_withdeploy_off_test.go b/main_withdeploy_off_test.go
new file mode 100644
index 00000000000..490ccd69360
--- /dev/null
+++ b/main_withdeploy_off_test.go
@@ -0,0 +1,29 @@
+// Copyright 2024 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.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//go:build !withdeploy
+// +build !withdeploy
+
+package main
+
+import (
+	"testing"
+
+	"github.com/rogpeppe/go-internal/testscript"
+)
+
+func TestWithdeploy(t *testing.T) {
+	p := commonTestScriptsParam
+	p.Dir = "testscripts/withdeploy-off"
+	testscript.Run(t, p)
+}
diff --git a/markup/goldmark/goldmark_integration_test.go b/markup/goldmark/goldmark_integration_test.go
index 8b7cc5a5432..82579069bb2 100644
--- a/markup/goldmark/goldmark_integration_test.go
+++ b/markup/goldmark/goldmark_integration_test.go
@@ -804,7 +804,7 @@ H~2~0
 }
 
 // Issue 12997.
-func TestGoldmarkRawHTMLWarning(t *testing.T) {
+func TestGoldmarkRawHTMLWarningBlocks(t *testing.T) {
 	files := `
 -- hugo.toml --
 disableKinds = ['home','rss','section','sitemap','taxonomy','term']
@@ -827,3 +827,27 @@ title: "p1"
 	b.AssertFileContent("public/p1/index.html", "! <!-- raw HTML omitted -->")
 	b.AssertLogContains("! WARN")
 }
+
+func TestGoldmarkRawHTMLWarningInline(t *testing.T) {
+	files := `
+-- hugo.toml --
+disableKinds = ['home','rss','section','sitemap','taxonomy','term']
+markup.goldmark.renderer.unsafe = false
+-- content/p1.md --
+---
+title: "p1"
+---
+<em>raw HTML</em>
+-- layouts/_default/single.html --
+{{ .Content }}
+`
+
+	b := hugolib.Test(t, files, hugolib.TestOptWarn())
+
+	b.AssertFileContent("public/p1/index.html", "<!-- raw HTML omitted -->")
+	b.AssertLogContains("WARN  Raw HTML omitted from \"/content/p1.md\"; see https://gohugo.io/getting-started/configuration-markup/#rendererunsafe\nYou can suppress this warning by adding the following to your site configuration:\nignoreLogs = ['warning-goldmark-raw-html']")
+
+	b = hugolib.Test(t, strings.ReplaceAll(files, "markup.goldmark.renderer.unsafe = false", "markup.goldmark.renderer.unsafe = true"), hugolib.TestOptWarn())
+	b.AssertFileContent("public/p1/index.html", "! <!-- raw HTML omitted -->")
+	b.AssertLogContains("! WARN")
+}
diff --git a/testscripts/withdeploy-off/deploy_off.txt b/testscripts/withdeploy-off/deploy_off.txt
new file mode 100644
index 00000000000..5e6c65d2717
--- /dev/null
+++ b/testscripts/withdeploy-off/deploy_off.txt
@@ -0,0 +1,3 @@
+! hugo deploy --force
+# Issue 13012
+stderr 'deploy not supported in this version of Hugo'
\ No newline at end of file