Skip to content

Commit

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

Signed-off-by: Xavier Coulon <[email protected]>
  • Loading branch information
xcoulon committed Jun 26, 2022
1 parent 745e403 commit fe4500c
Show file tree
Hide file tree
Showing 42 changed files with 1,717 additions and 676 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
20 changes: 13 additions & 7 deletions pkg/renderer/sgml/cross_reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,18 @@ func (r *sgmlRenderer) renderInternalCrossReference(ctx *renderer.Context, xref
} else {
label = "[" + xrefID + "]"
}
err := r.internalCrossReference.Execute(result, struct {
tmpl, err := r.internalCrossReference()
if err != nil {
return "", errors.Wrap(err, "unable to load cross references template")
}
if err := tmpl.Execute(result, struct {
Href string
Label string
}{
Href: xrefID,
Label: label,
})
if err != nil {
return "", errors.Wrapf(err, "unable to render internal cross reference")
}); err != nil {
return "", errors.Wrap(err, "unable to render internal cross reference")
}
return result.String(), nil
}
Expand All @@ -82,14 +85,17 @@ func (r *sgmlRenderer) renderExternalCrossReference(ctx *renderer.Context, xref
default:
label = defaultXrefLabel(xref)
}
err = r.externalCrossReference.Execute(result, struct {
tmpl, err := r.externalCrossReference()
if err != nil {
return "", errors.Wrap(err, "unable to render load cross reference template")
}
if err := tmpl.Execute(result, struct {
Href string
Label string
}{
Href: getCrossReferenceLocation(xref),
Label: label,
})
if err != nil {
}); err != nil {
return "", errors.Wrap(err, "unable to render external cross reference")
}
return result.String(), nil
Expand Down
31 changes: 21 additions & 10 deletions pkg/renderer/sgml/delimited_block_admonition.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ func (r *sgmlRenderer) renderAdmonitionBlock(ctx *renderer.Context, b *types.Del
return "", errors.Wrap(err, "unable to render admonition block title")
}

err = r.admonitionBlock.Execute(result, struct {
tmpl, err := r.admonitionBlock()
if err != nil {
return "", errors.Wrap(err, "unable to load admonition block template")
}
if err := tmpl.Execute(result, struct {
Context *renderer.Context
ID string
Title string
Expand All @@ -50,8 +54,10 @@ func (r *sgmlRenderer) renderAdmonitionBlock(ctx *renderer.Context, b *types.Del
Title: title,
Icon: icon,
Content: content,
})
return result.String(), err
}); err != nil {
return "", errors.Wrap(err, "unable to render admonition block")
}
return result.String(), nil
}

func (r *sgmlRenderer) renderAdmonitionParagraph(ctx *renderer.Context, p *types.Paragraph) (string, error) {
Expand All @@ -62,7 +68,7 @@ func (r *sgmlRenderer) renderAdmonitionParagraph(ctx *renderer.Context, p *types
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 +81,18 @@ 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 "", errors.Wrap(err, "unable to render admonition paragraph roles")
}
title, err := r.renderElementTitle(ctx, p.Attributes)
if err != nil {
return "", errors.Wrap(err, "unable to render fenced block title")
return "", errors.Wrap(err, "unable to render admonition paragraph title")
}

err = r.admonitionParagraph.Execute(result, struct {
tmpl, err := r.admonitionParagraph()
if err != nil {
return "", errors.Wrap(err, "unable to load admonition paragraph template")
}
if err := tmpl.Execute(result, struct {
Context *renderer.Context
ID string
Title string
Expand All @@ -98,7 +108,8 @@ func (r *sgmlRenderer) renderAdmonitionParagraph(ctx *renderer.Context, p *types
Roles: roles,
Icon: icon,
Content: content,
})

return result.String(), err
}); err != nil {
return "", errors.Wrap(err, "unable to render admonition paragraph")
}
return result.String(), nil
}
39 changes: 28 additions & 11 deletions pkg/renderer/sgml/delimited_block_example.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ func (r *sgmlRenderer) renderExampleBlock(ctx *renderer.Context, b *types.Delimi
return "", errors.Wrap(err, "unable to render example block title")
}
caption.WriteString(c)
err = r.exampleBlock.Execute(result, struct {
tmpl, err := r.exampleBlock()
if err != nil {
return "", errors.Wrap(err, "unable to load example block template")
}
if err := tmpl.Execute(result, struct {
Context *renderer.Context
ID string
Title string
Expand All @@ -64,8 +68,10 @@ func (r *sgmlRenderer) renderExampleBlock(ctx *renderer.Context, b *types.Delimi
Roles: roles,
ExampleNumber: number,
Content: content,
})
return result.String(), err
}); err != nil {
return "", errors.Wrap(err, "unable to render example block")
}
return result.String(), nil
}

func (r *sgmlRenderer) renderExampleParagraph(ctx *renderer.Context, p *types.Paragraph) (string, error) {
Expand All @@ -83,7 +89,11 @@ 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 {
tmpl, err := r.exampleBlock()
if err != nil {
return "", errors.Wrap(err, "unable to load example paragraph template")
}
if err := tmpl.Execute(result, struct {
Context *renderer.Context
ID string
Title string
Expand All @@ -97,9 +107,10 @@ func (r *sgmlRenderer) renderExampleParagraph(ctx *renderer.Context, p *types.Pa
ID: r.renderElementID(p.Attributes),
Title: title,
Content: string(content) + "\n",
})

return result.String(), err
}); err != nil {
return "", errors.Wrap(err, "unable to render example paragraph")
}
return result.String(), nil
}

func (r *sgmlRenderer) renderLiteralParagraph(ctx *renderer.Context, p *types.Paragraph) (string, error) {
Expand All @@ -118,10 +129,14 @@ 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 {
tmpl, err := r.literalBlock()
if err != nil {
return "", errors.Wrap(err, "unable to load literal block template")
}
if err := tmpl.Execute(result, struct {
Context *renderer.Context
ID string
Title string
Expand All @@ -133,8 +148,10 @@ func (r *sgmlRenderer) renderLiteralParagraph(ctx *renderer.Context, p *types.Pa
Title: title,
Roles: roles,
Content: content,
})
return result.String(), err
}); err != nil {
return "", errors.Wrap(err, "unable to render literal block")
}
return result.String(), nil
}

// adjustHeadingSpaces removes the same number of heading spaces on each line, based on the
Expand Down
15 changes: 10 additions & 5 deletions pkg/renderer/sgml/delimited_block_fenced.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ 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 {
tmpl, err := r.fencedBlock()
if err != nil {
return "", errors.Wrap(err, "unable to load fenced block template")
}
if err := tmpl.Execute(result, struct {
Context *renderer.Context
ID string
Title string
Expand All @@ -41,6 +44,8 @@ func (r *sgmlRenderer) renderFencedBlock(ctx *renderer.Context, b *types.Delimit
Title: title,
Roles: roles,
Content: strings.Trim(content, "\n"),
})
return result.String(), err
}); err != nil {
return "", errors.Wrapf(err, "unable to render fenced block")
}
return result.String(), nil
}
26 changes: 19 additions & 7 deletions pkg/renderer/sgml/delimited_block_listing.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ func (r *sgmlRenderer) renderListingBlock(ctx *renderer.Context, b *types.Delimi
return "", errors.Wrap(err, "unable to render listing block title")
}

err = r.listingBlock.Execute(result, struct {
tmpl, err := r.listingBlock()
if err != nil {
return "", errors.Wrap(err, "unable to load listing block template")
}
if err := tmpl.Execute(result, struct {
Context *renderer.Context
ID string
Title string
Expand All @@ -43,8 +47,10 @@ func (r *sgmlRenderer) renderListingBlock(ctx *renderer.Context, b *types.Delimi
Title: title,
Roles: roles,
Content: strings.Trim(content, "\n"),
})
return result.String(), err
}); err != nil {
return "", errors.Wrapf(err, "unable to render listing block")
}
return result.String(), nil
}

func (r *sgmlRenderer) renderListingParagraph(ctx *renderer.Context, p *types.Paragraph) (string, error) {
Expand All @@ -59,10 +65,14 @@ 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 {
tmpl, err := r.listingBlock()
if err != nil {
return "", errors.Wrap(err, "unable to load listing paragraph template")
}
if err := tmpl.Execute(result, struct {
Context *renderer.Context
ID string
Title string
Expand All @@ -74,6 +84,8 @@ func (r *sgmlRenderer) renderListingParagraph(ctx *renderer.Context, p *types.Pa
Title: title,
Roles: roles,
Content: content,
})
return result.String(), err
}); err != nil {
return "", errors.Wrap(err, "unable to render listing paragraph")
}
return result.String(), nil
}
Loading

0 comments on commit fe4500c

Please sign in to comment.