diff --git a/common/text/transform.go b/common/text/transform.go index f59577803..66a67d8bc 100644 --- a/common/text/transform.go +++ b/common/text/transform.go @@ -14,6 +14,7 @@ package text import ( + "strings" "sync" "unicode" @@ -45,3 +46,18 @@ func RemoveAccentsString(s string) string { accentTransformerPool.Put(t) return s } + +// Chomp removes trailing newline characters from s. +func Chomp(s string) string { + return strings.TrimRightFunc(s, func(r rune) bool { + return r == '\n' || r == '\r' + }) +} + +// Puts adds a trailing \n none found. +func Puts(s string) string { + if s == "" || s[len(s)-1] == '\n' { + return s + } + return s + "\n" +} diff --git a/common/text/transform_test.go b/common/text/transform_test.go index 08265f976..992dd524c 100644 --- a/common/text/transform_test.go +++ b/common/text/transform_test.go @@ -26,3 +26,18 @@ func TestRemoveAccents(t *testing.T) { c.Assert(string(RemoveAccents([]byte("Hugo Rocks!"))), qt.Equals, "Hugo Rocks!") c.Assert(string(RemoveAccentsString("Resumé")), qt.Equals, "Resume") } + +func TestChomp(t *testing.T) { + c := qt.New(t) + + c.Assert(Chomp("\nA\n"), qt.Equals, "\nA") + c.Assert(Chomp("A\r\n"), qt.Equals, "A") +} + +func TestPuts(t *testing.T) { + c := qt.New(t) + + c.Assert(Puts("A"), qt.Equals, "A\n") + c.Assert(Puts("\nA\n"), qt.Equals, "\nA\n") + c.Assert(Puts(""), qt.Equals, "") +} diff --git a/hugolib/integrationtest_builder.go b/hugolib/integrationtest_builder.go index ed68783a1..b7b43624f 100644 --- a/hugolib/integrationtest_builder.go +++ b/hugolib/integrationtest_builder.go @@ -28,6 +28,9 @@ import ( ) func NewIntegrationTestBuilder(conf IntegrationTestConfig) *IntegrationTestBuilder { + // Code fences. + conf.TxtarString = strings.ReplaceAll(conf.TxtarString, "§§§", "```") + data := txtar.Parse([]byte(conf.TxtarString)) c, ok := conf.T.(*qt.C) diff --git a/markup/goldmark/codeblocks/integration_test.go b/markup/goldmark/codeblocks/integration_test.go index d662b3911..0c9039cec 100644 --- a/markup/goldmark/codeblocks/integration_test.go +++ b/markup/goldmark/codeblocks/integration_test.go @@ -113,3 +113,34 @@ Go Language: golang| "
32echo "l1";\n33",
)
}
+
+func TestCodeChomp(t *testing.T) {
+ t.Parallel()
+
+ files := `
+-- config.toml --
+-- content/p1.md --
+---
+title: "p1"
+---
+
+§§§bash
+echo "p1";
+§§§
+-- layouts/_default/single.html --
+{{ .Content }}
+-- layouts/_default/_markup/render-codeblock.html --
+|{{ .Code | safeHTML }}|
+
+`
+
+ b := hugolib.NewIntegrationTestBuilder(
+ hugolib.IntegrationTestConfig{
+ T: t,
+ TxtarString: files,
+ NeedsOsFS: false,
+ },
+ ).Build()
+
+ b.AssertFileContent("public/p1/index.html", "|echo \"p1\";|")
+}
diff --git a/markup/goldmark/codeblocks/render.go b/markup/goldmark/codeblocks/render.go
index b598763d3..6cc43128b 100644
--- a/markup/goldmark/codeblocks/render.go
+++ b/markup/goldmark/codeblocks/render.go
@@ -17,6 +17,7 @@ import (
"bytes"
"fmt"
+ htext "github.com/gohugoio/hugo/common/text"
"github.com/gohugoio/hugo/markup/converter/hooks"
"github.com/gohugoio/hugo/markup/goldmark/internal/render"
"github.com/gohugoio/hugo/markup/internal/attributes"
@@ -75,7 +76,8 @@ func (r *htmlRenderer) renderCodeBlock(w util.BufWriter, src []byte, node ast.No
line := n.b.Lines().At(i)
buff.Write(line.Value(src))
}
- text := buff.String()
+
+ text := htext.Chomp(buff.String())
var info []byte
if n.b.Info != nil {
diff --git a/markup/highlight/highlight.go b/markup/highlight/highlight.go
index 6013ba1c8..156007d0a 100644
--- a/markup/highlight/highlight.go
+++ b/markup/highlight/highlight.go
@@ -25,6 +25,7 @@ import (
"github.com/alecthomas/chroma/lexers"
"github.com/alecthomas/chroma/styles"
"github.com/gohugoio/hugo/common/hugio"
+ "github.com/gohugoio/hugo/common/text"
"github.com/gohugoio/hugo/identity"
"github.com/gohugoio/hugo/markup/converter/hooks"
"github.com/gohugoio/hugo/markup/internal/attributes"
@@ -123,7 +124,9 @@ func (h chromaHighlighter) RenderCodeblock(w hugio.FlexiWriter, ctx hooks.Codebl
return err
}
- return highlight(w, ctx.Code(), ctx.Lang(), attributes, cfg)
+ code := text.Puts(ctx.Code())
+
+ return highlight(w, code, ctx.Lang(), attributes, cfg)
}
var id = identity.NewPathIdentity("chroma", "highlight")
diff --git a/tpl/strings/strings.go b/tpl/strings/strings.go
index ac2defed5..2575b2fee 100644
--- a/tpl/strings/strings.go
+++ b/tpl/strings/strings.go
@@ -21,6 +21,7 @@ import (
"strings"
"unicode/utf8"
+ "github.com/gohugoio/hugo/common/text"
"github.com/gohugoio/hugo/deps"
"github.com/gohugoio/hugo/helpers"
@@ -119,7 +120,7 @@ func (ns *Namespace) Chomp(s interface{}) (interface{}, error) {
return "", err
}
- res := strings.TrimRight(ss, "\r\n")
+ res := text.Chomp(ss)
switch s.(type) {
case template.HTML:
return template.HTML(res), nil