diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2021-02-23 18:04:05 +0100 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2021-02-24 11:16:06 +0100 |
commit | aed7df62a811b07b73ec5cbbf03e69e4bbf00919 (patch) | |
tree | 6099181308f9f6fe5126a3eac85a73ff601df52e | |
parent | cd0c5d7ef32cbd570af00c50ce760452381df64e (diff) |
markup: Handle attribute lists in code fences
Fixes #8278
-rw-r--r-- | markup/goldmark/convert.go | 24 | ||||
-rw-r--r-- | markup/goldmark/convert_test.go | 19 | ||||
-rw-r--r-- | markup/goldmark/render_hooks.go | 41 |
3 files changed, 78 insertions, 6 deletions
diff --git a/markup/goldmark/convert.go b/markup/goldmark/convert.go index 629e2b15a..639fddace 100644 --- 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 index d35d4d1fd..c7367dd01 100644 --- 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 index 6bedc897e..41db4011b 100644 --- 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 { |