Skip to content

Commit

Permalink
refactor(renderer): lazy loading of templates (#1062)
Browse files Browse the repository at this point in the history
Fixes #1061

Signed-off-by: Xavier Coulon <[email protected]>
  • Loading branch information
xcoulon authored Jun 26, 2022
1 parent 745e403 commit 9f09049
Show file tree
Hide file tree
Showing 46 changed files with 1,427 additions and 828 deletions.
89 changes: 89 additions & 0 deletions code-gen/renderer-templates/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package main

import (
"bytes"
"fmt"
"go/ast"
"go/parser"
"go/token"
"log"
"text/template"
"unicode"
)

const (
sgmlRenderer = `package sgml
import (
"sync"
text "text/template"
)
type sgmlRenderer struct {
templates Templates
functions text.FuncMap
{{ range $i, $tmpl := . }}
{{ once $tmpl}} sync.Once
{{ tmpl $tmpl}} *text.Template
{{ end }}
}
{{ range $i, $tmpl := . }}
func (r *sgmlRenderer) {{ func $tmpl }} (*text.Template, error) {
var err error
r.{{ once $tmpl }}.Do(func() {
r.{{ tmpl $tmpl }}, err = r.newTemplate("{{ $tmpl }}", r.templates.{{ $tmpl }}, err)
})
return r.{{ tmpl $tmpl }}, err
}
{{ end }}
`
)

func main() {
// read the content of pkg/renderer/sgml/templates.go
fs := token.NewFileSet()
f, err := parser.ParseFile(fs, "pkg/renderer/sgml/templates.go", nil, parser.AllErrors)
if err != nil {
log.Fatal(err)
}
v := &visitor{
fields: []string{},
}
ast.Walk(v, f)
tmpl, err := template.New("templates").Funcs(template.FuncMap{
"once": func(s string) string {
return string(unicode.ToLower(rune(s[0]))) + s[1:] + "Once"
},
"func": func(s string) string {
return string(unicode.ToLower(rune(s[0]))) + s[1:] + "()"
},
"tmpl": func(s string) string {
return string(unicode.ToLower(rune(s[0]))) + s[1:] + "Tmpl"
},
}).Parse(sgmlRenderer)
if err != nil {
log.Fatal(err)
}
// fmt.Printf("templates: %v\n", v.fields)
result := &bytes.Buffer{}
if err := tmpl.Execute(result, v.fields); err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", result.String())
}

type visitor struct {
fields []string
}

func (v *visitor) Visit(n ast.Node) ast.Visitor {
if n == nil {
return nil
}
if f, ok := n.(*ast.Field); ok {
v.fields = append(v.fields, f.Names[0].Name)
}
return v
}
12 changes: 10 additions & 2 deletions pkg/renderer/sgml/blank_line.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,23 @@ import (

func (r *sgmlRenderer) renderLineBreak() (string, error) {
buf := &strings.Builder{}
if err := r.lineBreak.Execute(buf, nil); err != nil {
tmpl, err := r.lineBreak()
if err != nil {
return "", err
}
if err := tmpl.Execute(buf, nil); err != nil {
return "", err
}
return buf.String(), nil
}

func (r *sgmlRenderer) renderThematicBreak() (string, error) {
buf := &strings.Builder{}
if err := r.thematicBreak.Execute(buf, nil); err != nil {
tmpl, err := r.thematicBreak()
if err != nil {
return "", err
}
if err := tmpl.Execute(buf, nil); err != nil {
return "", err
}
return buf.String(), nil
Expand Down
16 changes: 3 additions & 13 deletions pkg/renderer/sgml/cross_reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ func (r *sgmlRenderer) renderInternalCrossReference(ctx *renderer.Context, xref
if log.IsLevelEnabled(log.DebugLevel) {
log.Debugf("rendering cross reference with ID: %s", spew.Sdump(xref.ID))
}
result := &strings.Builder{}
var label string
xrefID, ok := xref.ID.(string)
if !ok {
Expand Down Expand Up @@ -54,45 +53,36 @@ func (r *sgmlRenderer) renderInternalCrossReference(ctx *renderer.Context, xref
} else {
label = "[" + xrefID + "]"
}
err := r.internalCrossReference.Execute(result, struct {
return r.execute(r.internalCrossReference, struct {
Href string
Label string
}{
Href: xrefID,
Label: label,
})
if err != nil {
return "", errors.Wrapf(err, "unable to render internal cross reference")
}
return result.String(), nil
}

func (r *sgmlRenderer) renderExternalCrossReference(ctx *renderer.Context, xref *types.ExternalCrossReference) (string, error) {
// log.Debugf("rendering cross reference with ID: %s", xref.Location)
result := &strings.Builder{}
var label string
var err error
switch l := xref.Attributes[types.AttrXRefLabel].(type) {
case string:
label = l
case []interface{}:
if label, err = r.renderInlineElements(ctx, l); err != nil {
return "", errors.Wrap(err, "unable to render external cross reference")
return "", err
}
default:
label = defaultXrefLabel(xref)
}
err = r.externalCrossReference.Execute(result, struct {
return r.execute(r.externalCrossReference, struct {
Href string
Label string
}{
Href: getCrossReferenceLocation(xref),
Label: label,
})
if err != nil {
return "", errors.Wrap(err, "unable to render external cross reference")
}
return result.String(), nil
}

func defaultXrefLabel(xref *types.ExternalCrossReference) string {
Expand Down
17 changes: 5 additions & 12 deletions pkg/renderer/sgml/delimited_block_admonition.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ func (r *sgmlRenderer) renderAdmonitionBlock(ctx *renderer.Context, b *types.Del
if err != nil {
return "", err
}
result := &strings.Builder{}
blocks := discardBlankLines(b.Elements)
content, err := r.renderElements(ctx, blocks)
if err != nil {
Expand All @@ -33,8 +32,7 @@ func (r *sgmlRenderer) renderAdmonitionBlock(ctx *renderer.Context, b *types.Del
if err != nil {
return "", errors.Wrap(err, "unable to render admonition block title")
}

err = r.admonitionBlock.Execute(result, struct {
return r.execute(r.admonitionBlock, struct {
Context *renderer.Context
ID string
Title string
Expand All @@ -51,18 +49,16 @@ func (r *sgmlRenderer) renderAdmonitionBlock(ctx *renderer.Context, b *types.Del
Icon: icon,
Content: content,
})
return result.String(), err
}

func (r *sgmlRenderer) renderAdmonitionParagraph(ctx *renderer.Context, p *types.Paragraph) (string, error) {
log.Debug("rendering admonition paragraph...")
result := &strings.Builder{}
kind, ok, err := p.Attributes.GetAsString(types.AttrStyle)
if err != nil {
return "", err
}
if !ok {
return "", errors.Errorf("failed to render admonition with unknown kind: %T", p.Attributes[types.AttrStyle])
return "", errors.Errorf("failed to render admonition paragraph with unknown kind: %T", p.Attributes[types.AttrStyle])
}
kind = strings.ToLower(kind)
icon, err := r.renderIcon(ctx, types.Icon{Class: kind, Attributes: p.Attributes}, true)
Expand All @@ -75,14 +71,13 @@ func (r *sgmlRenderer) renderAdmonitionParagraph(ctx *renderer.Context, p *types
}
roles, err := r.renderElementRoles(ctx, p.Attributes)
if err != nil {
return "", errors.Wrap(err, "unable to render fenced block roles")
return "", err
}
title, err := r.renderElementTitle(ctx, p.Attributes)
if err != nil {
return "", errors.Wrap(err, "unable to render fenced block title")
return "", err
}

err = r.admonitionParagraph.Execute(result, struct {
return r.execute(r.admonitionParagraph, struct {
Context *renderer.Context
ID string
Title string
Expand All @@ -99,6 +94,4 @@ func (r *sgmlRenderer) renderAdmonitionParagraph(ctx *renderer.Context, p *types
Icon: icon,
Content: content,
})

return result.String(), err
}
18 changes: 5 additions & 13 deletions pkg/renderer/sgml/delimited_block_example.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ import (
)

func (r *sgmlRenderer) renderExampleBlock(ctx *renderer.Context, b *types.DelimitedBlock) (string, error) {
result := &strings.Builder{}
caption := &strings.Builder{}

// default, example block
number := 0
content, err := r.renderElements(ctx, b.Elements)
Expand Down Expand Up @@ -47,8 +44,9 @@ func (r *sgmlRenderer) renderExampleBlock(ctx *renderer.Context, b *types.Delimi
if err != nil {
return "", errors.Wrap(err, "unable to render example block title")
}
caption := &strings.Builder{}
caption.WriteString(c)
err = r.exampleBlock.Execute(result, struct {
return r.execute(r.exampleBlock, struct {
Context *renderer.Context
ID string
Title string
Expand All @@ -65,12 +63,10 @@ func (r *sgmlRenderer) renderExampleBlock(ctx *renderer.Context, b *types.Delimi
ExampleNumber: number,
Content: content,
})
return result.String(), err
}

func (r *sgmlRenderer) renderExampleParagraph(ctx *renderer.Context, p *types.Paragraph) (string, error) {
log.Debug("rendering example paragraph...")
result := &strings.Builder{}
content, err := r.renderElements(ctx, p.Elements)
if err != nil {
return "", errors.Wrap(err, "unable to render example paragraph content")
Expand All @@ -83,7 +79,7 @@ func (r *sgmlRenderer) renderExampleParagraph(ctx *renderer.Context, p *types.Pa
if err != nil {
return "", errors.Wrap(err, "unable to render example paragraph title")
}
err = r.exampleBlock.Execute(result, struct {
return r.execute(r.exampleBlock, struct {
Context *renderer.Context
ID string
Title string
Expand All @@ -98,8 +94,6 @@ func (r *sgmlRenderer) renderExampleParagraph(ctx *renderer.Context, p *types.Pa
Title: title,
Content: string(content) + "\n",
})

return result.String(), err
}

func (r *sgmlRenderer) renderLiteralParagraph(ctx *renderer.Context, p *types.Paragraph) (string, error) {
Expand All @@ -118,10 +112,9 @@ func (r *sgmlRenderer) renderLiteralParagraph(ctx *renderer.Context, p *types.Pa
}
title, err := r.renderElementTitle(ctx, p.Attributes)
if err != nil {
return "", errors.Wrap(err, "unable to render callout list roles")
return "", errors.Wrap(err, "unable to render literal block roles")
}
result := &strings.Builder{}
err = r.literalBlock.Execute(result, struct {
return r.execute(r.literalBlock, struct {
Context *renderer.Context
ID string
Title string
Expand All @@ -134,7 +127,6 @@ func (r *sgmlRenderer) renderLiteralParagraph(ctx *renderer.Context, p *types.Pa
Roles: roles,
Content: content,
})
return result.String(), err
}

// adjustHeadingSpaces removes the same number of heading spaces on each line, based on the
Expand Down
8 changes: 2 additions & 6 deletions pkg/renderer/sgml/delimited_block_fenced.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ func (r *sgmlRenderer) renderFencedBlock(ctx *renderer.Context, b *types.Delimit
ctx.WithinDelimitedBlock = previousWithinDelimitedBlock
}()
ctx.WithinDelimitedBlock = true
result := &strings.Builder{}
// lines := discardEmptyLines(b.Elements)
content, err := r.renderElements(ctx, b.Elements)
if err != nil {
return "", errors.Wrap(err, "unable to render fenced block content")
Expand All @@ -26,10 +24,9 @@ func (r *sgmlRenderer) renderFencedBlock(ctx *renderer.Context, b *types.Delimit
}
title, err := r.renderElementTitle(ctx, b.Attributes)
if err != nil {
return "", errors.Wrap(err, "unable to render callout list roles")
return "", errors.Wrap(err, "unable to render fenced block roles")
}

err = r.fencedBlock.Execute(result, struct {
return r.execute(r.fencedBlock, struct {
Context *renderer.Context
ID string
Title string
Expand All @@ -42,5 +39,4 @@ func (r *sgmlRenderer) renderFencedBlock(ctx *renderer.Context, b *types.Delimit
Roles: roles,
Content: strings.Trim(content, "\n"),
})
return result.String(), err
}
12 changes: 3 additions & 9 deletions pkg/renderer/sgml/delimited_block_listing.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ func (r *sgmlRenderer) renderListingBlock(ctx *renderer.Context, b *types.Delimi
ctx.WithinDelimitedBlock = previousWithinDelimitedBlock
}()
ctx.WithinDelimitedBlock = true
result := &strings.Builder{}
content, err := r.renderElements(ctx, b.Elements)
if err != nil {
return "", errors.Wrap(err, "unable to render listing block content")
Expand All @@ -30,8 +29,7 @@ func (r *sgmlRenderer) renderListingBlock(ctx *renderer.Context, b *types.Delimi
if err != nil {
return "", errors.Wrap(err, "unable to render listing block title")
}

err = r.listingBlock.Execute(result, struct {
return r.execute(r.listingBlock, struct {
Context *renderer.Context
ID string
Title string
Expand All @@ -44,11 +42,9 @@ func (r *sgmlRenderer) renderListingBlock(ctx *renderer.Context, b *types.Delimi
Roles: roles,
Content: strings.Trim(content, "\n"),
})
return result.String(), err
}

func (r *sgmlRenderer) renderListingParagraph(ctx *renderer.Context, p *types.Paragraph) (string, error) {
result := &strings.Builder{}
content, err := r.renderElements(ctx, p.Elements)
if err != nil {
return "", errors.Wrap(err, "unable to render listing block content")
Expand All @@ -59,10 +55,9 @@ func (r *sgmlRenderer) renderListingParagraph(ctx *renderer.Context, p *types.Pa
}
title, err := r.renderElementTitle(ctx, p.Attributes)
if err != nil {
return "", errors.Wrap(err, "unable to render callout list roles")
return "", errors.Wrap(err, "unable to render listing paragraph roles")
}

err = r.listingBlock.Execute(result, struct {
return r.execute(r.listingBlock, struct {
Context *renderer.Context
ID string
Title string
Expand All @@ -75,5 +70,4 @@ func (r *sgmlRenderer) renderListingParagraph(ctx *renderer.Context, p *types.Pa
Roles: roles,
Content: content,
})
return result.String(), err
}
Loading

0 comments on commit 9f09049

Please sign in to comment.