Skip to content

Commit

Permalink
markup: Handle attribute lists in code fences
Browse files Browse the repository at this point in the history
Fixes #8278
  • Loading branch information
bep committed Feb 24, 2021
1 parent cd0c5d7 commit aed7df6
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 6 deletions.
24 changes: 23 additions & 1 deletion markup/goldmark/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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
}

Expand Down
19 changes: 19 additions & 0 deletions markup/goldmark/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
41 changes: 36 additions & 5 deletions markup/goldmark/render_hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
package goldmark

import (
"bytes"
"sync"

"github.com/spf13/cast"

"github.com/gohugoio/hugo/markup/converter/hooks"

"github.com/yuin/goldmark"
Expand Down Expand Up @@ -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('"')
}
}
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit aed7df6

Please # to comment.