markup/goldmark: Improve attributes vs options

Fixes #9571
This commit is contained in:
Bjørn Erik Pedersen 2022-02-26 17:24:10 +01:00
parent 928a896962
commit 579ff9b652
6 changed files with 41 additions and 19 deletions

View file

@ -1798,6 +1798,10 @@ func (hr hookRendererTemplate) ResolvePosition(ctx interface{}) text.Position {
return hr.resolvePosition(ctx) return hr.resolvePosition(ctx)
} }
func (hr hookRendererTemplate) IsDefaultCodeBlockRenderer() bool {
return false
}
func (s *Site) renderForTemplate(name, outputFormat string, d interface{}, w io.Writer, templ tpl.Template) (err error) { func (s *Site) renderForTemplate(name, outputFormat string, d interface{}, w io.Writer, templ tpl.Template) (err error) {
if templ == nil { if templ == nil {
s.logMissingLayout(name, "", "", outputFormat) s.logMissingLayout(name, "", "", outputFormat)

View file

@ -90,11 +90,11 @@ type HeadingRenderer interface {
identity.Provider identity.Provider
} }
// ElementPositionRevolver provides a way to resolve the start Position // ElementPositionResolver provides a way to resolve the start Position
// of a markdown element in the original source document. // of a markdown element in the original source document.
// This may be both slow and aproximate, so should only be // This may be both slow and aproximate, so should only be
// used for error logging. // used for error logging.
type ElementPositionRevolver interface { type ElementPositionResolver interface {
ResolvePosition(ctx interface{}) text.Position ResolvePosition(ctx interface{}) text.Position
} }

View file

@ -14,6 +14,7 @@
package codeblocks_test package codeblocks_test
import ( import (
"strings"
"testing" "testing"
"github.com/gohugoio/hugo/hugolib" "github.com/gohugoio/hugo/hugolib"
@ -176,7 +177,7 @@ Position: {{ .Position | safeHTML }}
} }
// Issue 9571 // Issue 9571
func TestOptionsNonChroma(t *testing.T) { func TestAttributesChroma(t *testing.T) {
t.Parallel() t.Parallel()
files := ` files := `
@ -188,23 +189,27 @@ title: "p1"
## Code ## Code
§§§bash {style=monokai} §§§LANGUAGE {style=monokai}
echo "p1"; echo "p1";
§§§ §§§
-- layouts/_default/single.html -- -- layouts/_default/single.html --
{{ .Content }} {{ .Content }}
-- layouts/_default/_markup/render-codeblock.html -- -- layouts/_default/_markup/render-codeblock.html --
Style: {{ .Attributes }}| Attributes: {{ .Attributes }}|Options: {{ .Options }}|
` `
testLanguage := func(language, expect string) {
b := hugolib.NewIntegrationTestBuilder( b := hugolib.NewIntegrationTestBuilder(
hugolib.IntegrationTestConfig{ hugolib.IntegrationTestConfig{
T: t, T: t,
TxtarString: files, TxtarString: strings.ReplaceAll(files, "LANGUAGE", language),
}, },
).Build() ).Build()
b.AssertFileContent("public/p1/index.html", "asdfadf") b.AssertFileContent("public/p1/index.html", expect)
}
testLanguage("bash", "Attributes: map[]|Options: map[style:monokai]|")
testLanguage("hugo", "Attributes: map[style:monokai]|Options: map[]|")
} }

View file

@ -18,7 +18,7 @@ import (
"fmt" "fmt"
"sync" "sync"
"github.com/gohugoio/hugo/common/herrors" "github.com/alecthomas/chroma/lexers"
htext "github.com/gohugoio/hugo/common/text" htext "github.com/gohugoio/hugo/common/text"
"github.com/gohugoio/hugo/markup/converter/hooks" "github.com/gohugoio/hugo/markup/converter/hooks"
"github.com/gohugoio/hugo/markup/goldmark/internal/render" "github.com/gohugoio/hugo/markup/goldmark/internal/render"
@ -61,8 +61,6 @@ func (r *htmlRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
} }
func (r *htmlRenderer) renderCodeBlock(w util.BufWriter, src []byte, node ast.Node, entering bool) (ast.WalkStatus, error) { func (r *htmlRenderer) renderCodeBlock(w util.BufWriter, src []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
defer herrors.Recover()
ctx := w.(*render.Context) ctx := w.(*render.Context)
if entering { if entering {
@ -92,17 +90,26 @@ func (r *htmlRenderer) renderCodeBlock(w util.BufWriter, src []byte, node ast.No
if n.b.Info != nil { if n.b.Info != nil {
info = n.b.Info.Segment.Value(src) info = n.b.Info.Segment.Value(src)
} }
attrtp := attributes.AttributesOwnerCodeBlockCustom
if isd, ok := renderer.(hooks.IsDefaultCodeBlockRendererProvider); (ok && isd.IsDefaultCodeBlockRenderer()) || lexers.Get(lang) != nil {
// We say that this is a Chroma code block if it's the default code block renderer
// or if the language is supported by Chroma.
attrtp = attributes.AttributesOwnerCodeBlockChroma
}
// IsDefaultCodeBlockRendererProvider
attrs := getAttributes(n.b, info) attrs := getAttributes(n.b, info)
cbctx := &codeBlockContext{ cbctx := &codeBlockContext{
page: ctx.DocumentContext().Document, page: ctx.DocumentContext().Document,
lang: lang, lang: lang,
code: s, code: s,
ordinal: ordinal, ordinal: ordinal,
AttributesHolder: attributes.New(attrs, attributes.AttributesOwnerCodeBlock), AttributesHolder: attributes.New(attrs, attrtp),
} }
cbctx.createPos = func() htext.Position { cbctx.createPos = func() htext.Position {
if resolver, ok := renderer.(hooks.ElementPositionRevolver); ok { if resolver, ok := renderer.(hooks.ElementPositionResolver); ok {
return resolver.ResolvePosition(cbctx) return resolver.ResolvePosition(cbctx)
} }
return htext.Position{ return htext.Position{

View file

@ -61,6 +61,7 @@ type Highlighter interface {
Highlight(code, lang string, opts interface{}) (string, error) Highlight(code, lang string, opts interface{}) (string, error)
HighlightCodeBlock(ctx hooks.CodeblockContext, opts interface{}) (HightlightResult, error) HighlightCodeBlock(ctx hooks.CodeblockContext, opts interface{}) (HightlightResult, error)
hooks.CodeBlockRenderer hooks.CodeBlockRenderer
hooks.IsDefaultCodeBlockRendererProvider
} }
type chromaHighlighter struct { type chromaHighlighter struct {
@ -129,6 +130,10 @@ func (h chromaHighlighter) RenderCodeblock(w hugio.FlexiWriter, ctx hooks.Codebl
return highlight(w, code, ctx.Lang(), attributes, cfg) return highlight(w, code, ctx.Lang(), attributes, cfg)
} }
func (h chromaHighlighter) IsDefaultCodeBlockRenderer() bool {
return true
}
var id = identity.NewPathIdentity("chroma", "highlight") var id = identity.NewPathIdentity("chroma", "highlight")
func (h chromaHighlighter) GetIdentity() identity.Identity { func (h chromaHighlighter) GetIdentity() identity.Identity {

View file

@ -50,7 +50,8 @@ type AttributesOwnerType int
const ( const (
AttributesOwnerGeneral AttributesOwnerType = iota AttributesOwnerGeneral AttributesOwnerType = iota
AttributesOwnerCodeBlock AttributesOwnerCodeBlockChroma
AttributesOwnerCodeBlockCustom
) )
func New(astAttributes []ast.Attribute, ownerType AttributesOwnerType) *AttributesHolder { func New(astAttributes []ast.Attribute, ownerType AttributesOwnerType) *AttributesHolder {
@ -99,7 +100,7 @@ func New(astAttributes []ast.Attribute, ownerType AttributesOwnerType) *Attribut
panic(fmt.Sprintf("not implemented: %T", vvv)) panic(fmt.Sprintf("not implemented: %T", vvv))
} }
if ownerType == AttributesOwnerCodeBlock && chromaHightlightProcessingAttributes[nameLower] { if ownerType == AttributesOwnerCodeBlockChroma && chromaHightlightProcessingAttributes[nameLower] {
attr := Attribute{Name: string(v.Name), Value: vv} attr := Attribute{Name: string(v.Name), Value: vv}
opts = append(opts, attr) opts = append(opts, attr)
} else { } else {