hugo

Unnamed repository; edit this file 'description' to name the repository.

git clone git://git.shimmy1996.com/hugo.git
commit aed7df62a811b07b73ec5cbbf03e69e4bbf00919
parent cd0c5d7ef32cbd570af00c50ce760452381df64e
Author: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Date:   Tue, 23 Feb 2021 18:04:05 +0100

markup: Handle attribute lists in code fences

Fixes #8278

Diffstat:
Mmarkup/goldmark/convert.go | 24+++++++++++++++++++++++-
Mmarkup/goldmark/convert_test.go | 19+++++++++++++++++++
Mmarkup/goldmark/render_hooks.go | 41++++++++++++++++++++++++++++++++++++-----
3 files changed, 78 insertions(+), 6 deletions(-)
diff --git a/markup/goldmark/convert.go b/markup/goldmark/convert.go
@@ -22,6 +22,7 @@ import (
 	"runtime/debug"
 
 	"github.com/gohugoio/hugo/markup/goldmark/internal/extensions/attributes"
+	"github.com/yuin/goldmark/ast"
 
 	"github.com/gohugoio/hugo/identity"
 
@@ -321,7 +322,28 @@ func newHighlighting(cfg highlight.Config) goldmark.Extender {
 					highlight.WriteCodeTag(w, language)
 					return
 				}
-				w.WriteString(`<div class="highlight">`)
+
+				w.WriteString(`<div class="highlight`)
+
+				var attributes []ast.Attribute
+				if ctx.Attributes() != nil {
+					attributes = ctx.Attributes().All()
+				}
+
+				if attributes != nil {
+					class, found := ctx.Attributes().GetString("class")
+					if found {
+						w.WriteString(" ")
+						w.Write(util.EscapeHTML(class.([]byte)))
+
+					}
+					_, _ = w.WriteString("\"")
+					renderAttributes(w, true, attributes...)
+				} else {
+					_, _ = w.WriteString("\"")
+				}
+
+				w.WriteString(">")
 				return
 			}
 
diff --git a/markup/goldmark/convert_test.go b/markup/goldmark/convert_test.go
@@ -226,6 +226,25 @@ func TestConvertAttributes(t *testing.T) {
 			"> foo\n> bar\n{#id .className attrName=attrValue class=\"class1 class2\"}\n",
 			"<blockquote id=\"id\" class=\"className class1 class2\"><p>foo\nbar</p>\n</blockquote>\n",
 		},
+		/*{
+			// TODO(bep) this needs an upstream fix, see https://github.com/yuin/goldmark/issues/195
+			"Code block, CodeFences=false",
+			func(conf *markup_config.Config) {
+				withBlockAttributes(conf)
+				conf.Highlight.CodeFences = false
+			},
+			"```bash\necho 'foo';\n```\n{.myclass}",
+			"TODO",
+		},*/
+		{
+			"Code block, CodeFences=true",
+			func(conf *markup_config.Config) {
+				withBlockAttributes(conf)
+				conf.Highlight.CodeFences = true
+			},
+			"```bash\necho 'foo';\n````\n{.myclass id=\"myid\"}",
+			"<div class=\"highlight myclass\" id=\"myid\"><pre style",
+		},
 		{
 			"Paragraph",
 			withBlockAttributes,
diff --git a/markup/goldmark/render_hooks.go b/markup/goldmark/render_hooks.go
@@ -14,8 +14,11 @@
 package goldmark
 
 import (
+	"bytes"
 	"sync"
 
+	"github.com/spf13/cast"
+
 	"github.com/gohugoio/hugo/markup/converter/hooks"
 
 	"github.com/yuin/goldmark"
@@ -135,13 +138,41 @@ func (r *hookedRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) 
 	reg.Register(ast.KindHeading, r.renderHeading)
 }
 
-// https://github.com/yuin/goldmark/blob/b611cd333a492416b56aa8d94b04a67bf0096ab2/renderer/html/html.go#L404
-func (r *hookedRenderer) RenderAttributes(w util.BufWriter, node ast.Node) {
-	for _, attr := range node.Attributes() {
+func (r *hookedRenderer) renderAttributesForNode(w util.BufWriter, node ast.Node) {
+	renderAttributes(w, false, node.Attributes()...)
+}
+
+var (
+
+	// Attributes with special meaning that does not make sense to render in HTML.
+	attributeExcludes = map[string]bool{
+		"linenos":     true,
+		"hl_lines":    true,
+		"linenostart": true,
+	}
+)
+
+func renderAttributes(w util.BufWriter, skipClass bool, attributes ...ast.Attribute) {
+	for _, attr := range attributes {
+		if skipClass && bytes.Equal(attr.Name, []byte("class")) {
+			continue
+		}
+
+		if attributeExcludes[string(attr.Name)] {
+			continue
+		}
+
 		_, _ = w.WriteString(" ")
 		_, _ = w.Write(attr.Name)
 		_, _ = w.WriteString(`="`)
-		_, _ = w.Write(util.EscapeHTML(attr.Value.([]byte)))
+
+		switch v := attr.Value.(type) {
+		case []byte:
+			_, _ = w.Write(util.EscapeHTML(v))
+		default:
+			w.WriteString(cast.ToString(v))
+		}
+
 		_ = w.WriteByte('"')
 	}
 }
@@ -282,7 +313,7 @@ func (r *hookedRenderer) renderDefaultHeading(w util.BufWriter, source []byte, n
 		_, _ = w.WriteString("<h")
 		_ = w.WriteByte("0123456"[n.Level])
 		if n.Attributes() != nil {
-			r.RenderAttributes(w, node)
+			r.renderAttributesForNode(w, node)
 		}
 		_ = w.WriteByte('>')
 	} else {