summaryrefslogtreecommitdiffstats
path: root/markup
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2023-02-24 07:23:10 +0100
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2023-02-24 10:40:06 +0100
commit271318ad787ee2442c6d553edffaa29e1d9a4cf7 (patch)
tree4314daa1667ecb7badff421a5c19e51f5ea7bc4f /markup
parente442a63bb7659d95aec2d48bf954cd9d61163559 (diff)
Split parse and render for Goldmark
This also speeds up situations where you only need the fragments/toc and not the rendered content, e.g. Related with fragments type indexing: ```bash name old time/op new time/op delta RelatedSite-10 12.3ms ± 2% 10.7ms ± 1% -12.95% (p=0.029 n=4+4) name old alloc/op new alloc/op delta RelatedSite-10 38.6MB ± 0% 38.2MB ± 0% -1.08% (p=0.029 n=4+4) name old allocs/op new allocs/op delta RelatedSite-10 117k ± 0% 115k ± 0% -1.36% (p=0.029 n=4+4) ``` Fixes #10750
Diffstat (limited to 'markup')
-rw-r--r--markup/asciidocext/convert.go8
-rw-r--r--markup/converter/converter.go22
-rw-r--r--markup/goldmark/convert.go72
-rw-r--r--markup/goldmark/convert_test.go2
-rw-r--r--markup/org/convert.go2
-rw-r--r--markup/pandoc/convert.go2
-rw-r--r--markup/rst/convert.go2
7 files changed, 84 insertions, 26 deletions
diff --git a/markup/asciidocext/convert.go b/markup/asciidocext/convert.go
index c9524778f..c3bd90edd 100644
--- a/markup/asciidocext/convert.go
+++ b/markup/asciidocext/convert.go
@@ -52,7 +52,7 @@ func (p provider) New(cfg converter.ProviderConfig) (converter.Provider, error)
}
type asciidocResult struct {
- converter.Result
+ converter.ResultRender
toc *tableofcontents.Fragments
}
@@ -65,7 +65,7 @@ type asciidocConverter struct {
cfg converter.ProviderConfig
}
-func (a *asciidocConverter) Convert(ctx converter.RenderContext) (converter.Result, error) {
+func (a *asciidocConverter) Convert(ctx converter.RenderContext) (converter.ResultRender, error) {
b, err := a.getAsciidocContent(ctx.Src, a.ctx)
if err != nil {
return nil, err
@@ -75,8 +75,8 @@ func (a *asciidocConverter) Convert(ctx converter.RenderContext) (converter.Resu
return nil, err
}
return asciidocResult{
- Result: converter.Bytes(content),
- toc: toc,
+ ResultRender: converter.Bytes(content),
+ toc: toc,
}, nil
}
diff --git a/markup/converter/converter.go b/markup/converter/converter.go
index 7e5b56b07..e5a07f1a1 100644
--- a/markup/converter/converter.go
+++ b/markup/converter/converter.go
@@ -74,7 +74,7 @@ var NopConverter = new(nopConverter)
type nopConverter int
-func (nopConverter) Convert(ctx RenderContext) (Result, error) {
+func (nopConverter) Convert(ctx RenderContext) (ResultRender, error) {
return &bytes.Buffer{}, nil
}
@@ -85,15 +85,29 @@ func (nopConverter) Supports(feature identity.Identity) bool {
// Converter wraps the Convert method that converts some markup into
// another format, e.g. Markdown to HTML.
type Converter interface {
- Convert(ctx RenderContext) (Result, error)
+ Convert(ctx RenderContext) (ResultRender, error)
Supports(feature identity.Identity) bool
}
-// Result represents the minimum returned from Convert.
-type Result interface {
+// ParseRenderer is an optional interface.
+// The Goldmark converter implements this, and this allows us
+// to extract the ToC without having to render the content.
+type ParseRenderer interface {
+ Parse(RenderContext) (ResultParse, error)
+ Render(RenderContext, any) (ResultRender, error)
+}
+
+// ResultRender represents the minimum returned from Convert and Render.
+type ResultRender interface {
Bytes() []byte
}
+// ResultParse represents the minimum returned from Parse.
+type ResultParse interface {
+ Doc() any
+ TableOfContents() *tableofcontents.Fragments
+}
+
// DocumentInfo holds additional information provided by some converters.
type DocumentInfo interface {
AnchorSuffix() string
diff --git a/markup/goldmark/convert.go b/markup/goldmark/convert.go
index 6c1c7ad0a..3c8dbb299 100644
--- a/markup/goldmark/convert.go
+++ b/markup/goldmark/convert.go
@@ -18,6 +18,7 @@ import (
"bytes"
"github.com/gohugoio/hugo/identity"
+
"github.com/gohugoio/hugo/markup/goldmark/codeblocks"
"github.com/gohugoio/hugo/markup/goldmark/images"
"github.com/gohugoio/hugo/markup/goldmark/internal/extensions/attributes"
@@ -26,6 +27,7 @@ import (
"github.com/gohugoio/hugo/markup/converter"
"github.com/gohugoio/hugo/markup/tableofcontents"
"github.com/yuin/goldmark"
+ "github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer"
@@ -158,26 +160,41 @@ func newMarkdown(pcfg converter.ProviderConfig) goldmark.Markdown {
var _ identity.IdentitiesProvider = (*converterResult)(nil)
-type converterResult struct {
- converter.Result
+type parserResult struct {
+ doc any
toc *tableofcontents.Fragments
+}
+
+func (p parserResult) Doc() any {
+ return p.doc
+}
+
+func (p parserResult) TableOfContents() *tableofcontents.Fragments {
+ return p.toc
+}
+
+type renderResult struct {
+ converter.ResultRender
ids identity.Identities
}
-func (c converterResult) TableOfContents() *tableofcontents.Fragments {
- return c.toc
+func (r renderResult) GetIdentities() identity.Identities {
+ return r.ids
}
-func (c converterResult) GetIdentities() identity.Identities {
- return c.ids
+type converterResult struct {
+ converter.ResultRender
+ tableOfContentsProvider
+ identity.IdentitiesProvider
}
-var converterIdentity = identity.KeyValueIdentity{Key: "goldmark", Value: "converter"}
+type tableOfContentsProvider interface {
+ TableOfContents() *tableofcontents.Fragments
+}
-func (c *goldmarkConverter) Convert(ctx converter.RenderContext) (result converter.Result, err error) {
+var converterIdentity = identity.KeyValueIdentity{Key: "goldmark", Value: "converter"}
- buf := &render.BufWriter{Buffer: &bytes.Buffer{}}
- result = buf
+func (c *goldmarkConverter) Parse(ctx converter.RenderContext) (converter.ResultParse, error) {
pctx := c.newParserContext(ctx)
reader := text.NewReader(ctx.Src)
@@ -186,6 +203,16 @@ func (c *goldmarkConverter) Convert(ctx converter.RenderContext) (result convert
parser.WithContext(pctx),
)
+ return parserResult{
+ doc: doc,
+ toc: pctx.TableOfContents(),
+ }, nil
+
+}
+func (c *goldmarkConverter) Render(ctx converter.RenderContext, doc any) (converter.ResultRender, error) {
+ n := doc.(ast.Node)
+ buf := &render.BufWriter{Buffer: &bytes.Buffer{}}
+
rcx := &render.RenderContextDataHolder{
Rctx: ctx,
Dctx: c.ctx,
@@ -197,15 +224,32 @@ func (c *goldmarkConverter) Convert(ctx converter.RenderContext) (result convert
ContextData: rcx,
}
- if err := c.md.Renderer().Render(w, ctx.Src, doc); err != nil {
+ if err := c.md.Renderer().Render(w, ctx.Src, n); err != nil {
return nil, err
}
+ return renderResult{
+ ResultRender: buf,
+ ids: rcx.IDs.GetIdentities(),
+ }, nil
+
+}
+
+func (c *goldmarkConverter) Convert(ctx converter.RenderContext) (converter.ResultRender, error) {
+ parseResult, err := c.Parse(ctx)
+ if err != nil {
+ return nil, err
+ }
+ renderResult, err := c.Render(ctx, parseResult.Doc())
+ if err != nil {
+ return nil, err
+ }
return converterResult{
- Result: buf,
- ids: rcx.IDs.GetIdentities(),
- toc: pctx.TableOfContents(),
+ ResultRender: renderResult,
+ tableOfContentsProvider: parseResult,
+ IdentitiesProvider: renderResult.(identity.IdentitiesProvider),
}, nil
+
}
var featureSet = map[identity.Identity]bool{
diff --git a/markup/goldmark/convert_test.go b/markup/goldmark/convert_test.go
index cbc49d041..647ffce58 100644
--- a/markup/goldmark/convert_test.go
+++ b/markup/goldmark/convert_test.go
@@ -34,7 +34,7 @@ import (
qt "github.com/frankban/quicktest"
)
-func convert(c *qt.C, mconf markup_config.Config, content string) converter.Result {
+func convert(c *qt.C, mconf markup_config.Config, content string) converter.ResultRender {
p, err := Provider.New(
converter.ProviderConfig{
MarkupConfig: mconf,
diff --git a/markup/org/convert.go b/markup/org/convert.go
index 603ec8f19..a08453e94 100644
--- a/markup/org/convert.go
+++ b/markup/org/convert.go
@@ -43,7 +43,7 @@ type orgConverter struct {
cfg converter.ProviderConfig
}
-func (c *orgConverter) Convert(ctx converter.RenderContext) (converter.Result, error) {
+func (c *orgConverter) Convert(ctx converter.RenderContext) (converter.ResultRender, error) {
logger := c.cfg.Logger
config := org.New()
config.Log = logger.Warn()
diff --git a/markup/pandoc/convert.go b/markup/pandoc/convert.go
index ae90cf417..386a9ff26 100644
--- a/markup/pandoc/convert.go
+++ b/markup/pandoc/convert.go
@@ -43,7 +43,7 @@ type pandocConverter struct {
cfg converter.ProviderConfig
}
-func (c *pandocConverter) Convert(ctx converter.RenderContext) (converter.Result, error) {
+func (c *pandocConverter) Convert(ctx converter.RenderContext) (converter.ResultRender, error) {
b, err := c.getPandocContent(ctx.Src, c.ctx)
if err != nil {
return nil, err
diff --git a/markup/rst/convert.go b/markup/rst/convert.go
index b86b35f1b..59ce38408 100644
--- a/markup/rst/convert.go
+++ b/markup/rst/convert.go
@@ -47,7 +47,7 @@ type rstConverter struct {
cfg converter.ProviderConfig
}
-func (c *rstConverter) Convert(ctx converter.RenderContext) (converter.Result, error) {
+func (c *rstConverter) Convert(ctx converter.RenderContext) (converter.ResultRender, error) {
b, err := c.getRstContent(ctx.Src, c.ctx)
if err != nil {
return nil, err