markup/goldmark: Add removeSurroundingParagraph for Markdown images

* Removes any surrounding paragraph nodes
* And transfers any attributes from the surrounding paragraph down to the image node
* Adds IsBlock and Ordinal (zero based) field to the image context passed to the image render hooks

IsBlock is set to true if `wrapStandAloneImageWithinParagraph = false` and  the image's parent node has only one child.

Closes #8362
Fixes #10492
Fixes #10494
Fixes #10501
This commit is contained in:
Bjørn Erik Pedersen
2022-12-03 12:33:48 +01:00
parent 535ea8cc9b
commit 63126c6359
9 changed files with 469 additions and 24 deletions

View File

@@ -20,6 +20,7 @@ import (
"github.com/gohugoio/hugo/common/types/hstring"
"github.com/gohugoio/hugo/markup/converter/hooks"
"github.com/gohugoio/hugo/markup/goldmark/goldmark_config"
"github.com/gohugoio/hugo/markup/goldmark/images"
"github.com/gohugoio/hugo/markup/goldmark/internal/render"
"github.com/gohugoio/hugo/markup/internal/attributes"
@@ -52,16 +53,13 @@ type linkContext struct {
title string
text hstring.RenderedString
plainText string
*attributes.AttributesHolder
}
func (ctx linkContext) Destination() string {
return ctx.destination
}
func (ctx linkContext) Resolved() bool {
return false
}
func (ctx linkContext) Page() any {
return ctx.page
}
@@ -78,6 +76,20 @@ func (ctx linkContext) Title() string {
return ctx.title
}
type imageLinkContext struct {
linkContext
ordinal int
isBlock bool
}
func (ctx imageLinkContext) IsBlock() bool {
return ctx.isBlock
}
func (ctx imageLinkContext) Ordinal() int {
return ctx.ordinal
}
type headingContext struct {
page any
level int
@@ -151,14 +163,36 @@ func (r *hookedRenderer) renderImage(w util.BufWriter, source []byte, node ast.N
text := ctx.Buffer.Bytes()[pos:]
ctx.Buffer.Truncate(pos)
var (
isBlock bool
ordinal int
)
if b, ok := n.AttributeString(images.AttrIsBlock); ok && b.(bool) {
isBlock = true
}
if n, ok := n.AttributeString(images.AttrOrdinal); ok {
ordinal = n.(int)
}
// We use the attributes to signal from the parser whether the image is in
// a block context or not.
// We may find a better way to do that, but for now, we'll need to remove any
// internal attributes before rendering.
attrs := r.filterInternalAttributes(n.Attributes())
err := lr.RenderLink(
w,
linkContext{
page: ctx.DocumentContext().Document,
destination: string(n.Destination),
title: string(n.Title),
text: hstring.RenderedString(text),
plainText: string(n.Text(source)),
imageLinkContext{
linkContext: linkContext{
page: ctx.DocumentContext().Document,
destination: string(n.Destination),
title: string(n.Title),
text: hstring.RenderedString(text),
plainText: string(n.Text(source)),
AttributesHolder: attributes.New(attrs, attributes.AttributesOwnerGeneral),
},
ordinal: ordinal,
isBlock: isBlock,
},
)
@@ -167,6 +201,17 @@ func (r *hookedRenderer) renderImage(w util.BufWriter, source []byte, node ast.N
return ast.WalkContinue, err
}
func (r *hookedRenderer) filterInternalAttributes(attrs []ast.Attribute) []ast.Attribute {
n := 0
for _, x := range attrs {
if !bytes.HasPrefix(x.Name, []byte(internalAttrPrefix)) {
attrs[n] = x
n++
}
}
return attrs[:n]
}
// Fall back to the default Goldmark render funcs. Method below borrowed from:
// https://github.com/yuin/goldmark/blob/b611cd333a492416b56aa8d94b04a67bf0096ab2/renderer/html/html.go#L404
func (r *hookedRenderer) renderImageDefault(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
@@ -186,6 +231,10 @@ func (r *hookedRenderer) renderImageDefault(w util.BufWriter, source []byte, nod
r.Writer.Write(w, n.Title)
_ = w.WriteByte('"')
}
if n.Attributes() != nil {
attrs := r.filterInternalAttributes(n.Attributes())
attributes.RenderASTAttributes(w, attrs...)
}
if r.XHTML {
_, _ = w.WriteString(" />")
} else {
@@ -224,11 +273,12 @@ func (r *hookedRenderer) renderLink(w util.BufWriter, source []byte, node ast.No
err := lr.RenderLink(
w,
linkContext{
page: ctx.DocumentContext().Document,
destination: string(n.Destination),
title: string(n.Title),
text: hstring.RenderedString(text),
plainText: string(n.Text(source)),
page: ctx.DocumentContext().Document,
destination: string(n.Destination),
title: string(n.Title),
text: hstring.RenderedString(text),
plainText: string(n.Text(source)),
AttributesHolder: attributes.Empty,
},
)
@@ -292,10 +342,11 @@ func (r *hookedRenderer) renderAutoLink(w util.BufWriter, source []byte, node as
err := lr.RenderLink(
w,
linkContext{
page: ctx.DocumentContext().Document,
destination: url,
text: hstring.RenderedString(label),
plainText: label,
page: ctx.DocumentContext().Document,
destination: url,
text: hstring.RenderedString(label),
plainText: label,
AttributesHolder: attributes.Empty,
},
)