commit 6f7bf3f2d7eda178d0dba4a6bf3dfa50229df7ae
parent 9e904d756be02ca30e4cd9abb1eae8ba01f9c8af
Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Date: Mon, 30 May 2022 20:42:46 +0200
Fix indentation in highlight shortcode
This commit adds a new `.InnerDeindent` method to the shortcode context, which is `.Inner` with any
indendation removed. This is then used in the built-in `highlight` shortcode to prevent the extra
whitespace getting hightlighted.
Fixes #4717
Diffstat:
5 files changed, 79 insertions(+), 4 deletions(-)
diff --git a/docs/content/en/variables/shortcodes.md b/docs/content/en/variables/shortcodes.md
@@ -45,4 +45,8 @@ toc: false
[markdownshortcode]: /content-management/shortcodes/#shortcodes-with-markdown
[shortcodes]: /templates/shortcode-templates/
+.InnerDeindent {{< new-in "0.100.0" >}}
+: Gets the `.Inner` with any indentation removed. This is what's used in the built-in `{{</* highlight */>}}` shortcode.
+
+
diff --git a/hugolib/shortcode.go b/hugolib/shortcode.go
@@ -62,6 +62,12 @@ type ShortcodeWithPage struct {
// this ordinal will represent the position of this shortcode in the page content.
Ordinal int
+ // Indentation before the opening shortcode in the source.
+ indentation string
+
+ innerDeindentInit sync.Once
+ innerDeindent template.HTML
+
// pos is the position in bytes in the source file. Used for error logging.
posInit sync.Once
posOffset int
@@ -70,6 +76,27 @@ type ShortcodeWithPage struct {
scratch *maps.Scratch
}
+// InnerDeindent returns the (potentially de-indented) inner content of the shortcode.
+func (scp *ShortcodeWithPage) InnerDeindent() template.HTML {
+ if scp.indentation == "" {
+ return scp.Inner
+ }
+ scp.innerDeindentInit.Do(func() {
+ b := bp.GetBuffer()
+ text.VisitLinesAfter(string(scp.Inner), func(s string) {
+ if strings.HasPrefix(s, scp.indentation) {
+ b.WriteString(strings.TrimPrefix(s, scp.indentation))
+ } else {
+ b.WriteString(s)
+ }
+ })
+ scp.innerDeindent = template.HTML(b.String())
+ bp.PutBuffer(b)
+ })
+
+ return scp.innerDeindent
+}
+
// Position returns this shortcode's detailed position. Note that this information
// may be expensive to calculate, so only use this in error situations.
func (scp *ShortcodeWithPage) Position() text.Position {
@@ -326,7 +353,7 @@ func renderShortcode(
hasVariants = hasVariants || more
}
- data := &ShortcodeWithPage{Ordinal: sc.ordinal, posOffset: sc.pos, Params: sc.params, Page: newPageForShortcode(p), Parent: parent, Name: sc.name}
+ data := &ShortcodeWithPage{Ordinal: sc.ordinal, posOffset: sc.pos, indentation: sc.indentation, Params: sc.params, Page: newPageForShortcode(p), Parent: parent, Name: sc.name}
if sc.params != nil {
data.IsNamedParams = reflect.TypeOf(sc.params).Kind() == reflect.Map
}
diff --git a/hugolib/shortcode_test.go b/hugolib/shortcode_test.go
@@ -1009,3 +1009,47 @@ echo "foo";
b.AssertFileContent("public/p1/index.html", "<pre><code>echo "foo";\n</code></pre>")
}
+
+func TestShortcodeHighlightDeindent(t *testing.T) {
+ t.Parallel()
+
+ files := `
+-- config.toml --
+[markup]
+[markup.highlight]
+codeFences = true
+noClasses = false
+-- content/p1.md --
+---
+title: "p1"
+---
+
+## Indent 5 Spaces
+
+ {{< highlight bash >}}
+ line 1;
+ line 2;
+ line 3;
+ {{< /highlight >}}
+
+-- layouts/_default/single.html --
+{{ .Content }}
+`
+
+ b := NewIntegrationTestBuilder(
+ IntegrationTestConfig{
+ T: t,
+ TxtarString: files,
+ Running: true,
+ },
+ ).Build()
+
+ b.AssertFileContent("public/p1/index.html", `
+<pre><code> <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">line 1<span class="p">;</span>
+</span></span><span class="line"><span class="cl">line 2<span class="p">;</span>
+</span></span><span class="line"><span class="cl">line 3<span class="p">;</span></span></span></code></pre></div>
+</code></pre>
+
+ `)
+
+}
diff --git a/tpl/tplimpl/embedded/templates/shortcodes/highlight.html b/tpl/tplimpl/embedded/templates/shortcodes/highlight.html
@@ -1 +1 @@
-{{ if len .Params | eq 2 }}{{ highlight (trim .Inner "\n\r") (.Get 0) (.Get 1) }}{{ else }}{{ highlight (trim .Inner "\n\r") (.Get 0) "" }}{{ end }}-
\ No newline at end of file
+{{ if len .Params | eq 2 }}{{ highlight (trim .InnerDeindent "\n\r") (.Get 0) (.Get 1) }}{{ else }}{{ highlight (trim .InnerDeindent "\n\r") (.Get 0) "" }}{{ end }}+
\ No newline at end of file
diff --git a/tpl/tplimpl/template_ast_transformers.go b/tpl/tplimpl/template_ast_transformers.go
@@ -272,7 +272,7 @@ func (c *templateContext) collectInner(n *parse.CommandNode) {
idents = nt.Ident
}
- if c.hasIdent(idents, "Inner") {
+ if c.hasIdent(idents, "Inner") || c.hasIdent(idents, "InnerDeindent") {
c.t.parseInfo.IsInner = true
break
}