From 9f09049f96b9b7ce5b63ac92c5f4289f7596c189 Mon Sep 17 00:00:00 2001 From: Xavier Coulon Date: Sun, 26 Jun 2022 15:23:30 +0200 Subject: [PATCH] refactor(renderer): lazy loading of templates (#1062) Fixes #1061 Signed-off-by: Xavier Coulon --- code-gen/renderer-templates/main.go | 89 ++ pkg/renderer/sgml/blank_line.go | 12 +- pkg/renderer/sgml/cross_reference.go | 16 +- .../sgml/delimited_block_admonition.go | 17 +- pkg/renderer/sgml/delimited_block_example.go | 18 +- pkg/renderer/sgml/delimited_block_fenced.go | 8 +- pkg/renderer/sgml/delimited_block_listing.go | 12 +- .../sgml/delimited_block_markdown_quote.go | 5 +- pkg/renderer/sgml/delimited_block_open.go | 7 +- .../sgml/delimited_block_passthrough.go | 5 +- pkg/renderer/sgml/delimited_block_quote.go | 14 +- pkg/renderer/sgml/delimited_block_sidebar.go | 8 +- pkg/renderer/sgml/delimited_block_source.go | 15 +- pkg/renderer/sgml/delimited_block_verse.go | 12 +- pkg/renderer/sgml/document_details.go | 106 +- pkg/renderer/sgml/element_id.go | 4 +- pkg/renderer/sgml/element_style.go | 4 +- pkg/renderer/sgml/footnote_reference.go | 68 +- pkg/renderer/sgml/html5/blank_line.go | 1 - pkg/renderer/sgml/html5/callout_list.go | 2 +- pkg/renderer/sgml/html5/footnote_reference.go | 2 +- pkg/renderer/sgml/html5/labeled_list.go | 6 +- pkg/renderer/sgml/html5/ordered_list.go | 2 +- pkg/renderer/sgml/html5/section.go | 2 +- pkg/renderer/sgml/html5/templates.go | 153 ++- pkg/renderer/sgml/html5/unordered_list.go | 2 +- pkg/renderer/sgml/icon.go | 31 +- pkg/renderer/sgml/image.go | 26 +- pkg/renderer/sgml/inline_button.go | 13 +- pkg/renderer/sgml/inline_menu.go | 10 +- pkg/renderer/sgml/link.go | 9 +- pkg/renderer/sgml/list.go | 115 +- pkg/renderer/sgml/literal_blocks.go | 7 +- pkg/renderer/sgml/paragraph.go | 33 +- pkg/renderer/sgml/passthrough.go | 4 +- pkg/renderer/sgml/preamble.go | 10 +- pkg/renderer/sgml/quoted_text.go | 31 +- pkg/renderer/sgml/renderer.go | 39 +- pkg/renderer/sgml/section.go | 21 +- pkg/renderer/sgml/sgml_renderer.go | 1026 ++++++++++++++--- pkg/renderer/sgml/table.go | 78 +- pkg/renderer/sgml/table_of_contents.go | 48 +- pkg/renderer/sgml/templates.go | 154 +-- pkg/renderer/sgml/xhtml5/blank_line.go | 1 - pkg/renderer/sgml/xhtml5/templates.go | 3 +- testsupport/html5_matcher.go | 6 +- 46 files changed, 1427 insertions(+), 828 deletions(-) create mode 100644 code-gen/renderer-templates/main.go diff --git a/code-gen/renderer-templates/main.go b/code-gen/renderer-templates/main.go new file mode 100644 index 00000000..c35cdda3 --- /dev/null +++ b/code-gen/renderer-templates/main.go @@ -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 +} diff --git a/pkg/renderer/sgml/blank_line.go b/pkg/renderer/sgml/blank_line.go index 42b32220..8dcd40bf 100644 --- a/pkg/renderer/sgml/blank_line.go +++ b/pkg/renderer/sgml/blank_line.go @@ -6,7 +6,11 @@ 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 @@ -14,7 +18,11 @@ func (r *sgmlRenderer) renderLineBreak() (string, error) { 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 diff --git a/pkg/renderer/sgml/cross_reference.go b/pkg/renderer/sgml/cross_reference.go index 76c3cf72..f6e1bd36 100644 --- a/pkg/renderer/sgml/cross_reference.go +++ b/pkg/renderer/sgml/cross_reference.go @@ -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 { @@ -54,22 +53,17 @@ 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) { @@ -77,22 +71,18 @@ func (r *sgmlRenderer) renderExternalCrossReference(ctx *renderer.Context, xref 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 { diff --git a/pkg/renderer/sgml/delimited_block_admonition.go b/pkg/renderer/sgml/delimited_block_admonition.go index 8039f117..c9431726 100644 --- a/pkg/renderer/sgml/delimited_block_admonition.go +++ b/pkg/renderer/sgml/delimited_block_admonition.go @@ -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 { @@ -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 @@ -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) @@ -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 @@ -99,6 +94,4 @@ func (r *sgmlRenderer) renderAdmonitionParagraph(ctx *renderer.Context, p *types Icon: icon, Content: content, }) - - return result.String(), err } diff --git a/pkg/renderer/sgml/delimited_block_example.go b/pkg/renderer/sgml/delimited_block_example.go index a204785c..2a583110 100644 --- a/pkg/renderer/sgml/delimited_block_example.go +++ b/pkg/renderer/sgml/delimited_block_example.go @@ -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) @@ -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 @@ -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") @@ -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 @@ -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) { @@ -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 @@ -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 diff --git a/pkg/renderer/sgml/delimited_block_fenced.go b/pkg/renderer/sgml/delimited_block_fenced.go index 5594f2d8..abcb5c04 100644 --- a/pkg/renderer/sgml/delimited_block_fenced.go +++ b/pkg/renderer/sgml/delimited_block_fenced.go @@ -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") @@ -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 @@ -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 } diff --git a/pkg/renderer/sgml/delimited_block_listing.go b/pkg/renderer/sgml/delimited_block_listing.go index e37be75a..b072eddc 100644 --- a/pkg/renderer/sgml/delimited_block_listing.go +++ b/pkg/renderer/sgml/delimited_block_listing.go @@ -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") @@ -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 @@ -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") @@ -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 @@ -75,5 +70,4 @@ func (r *sgmlRenderer) renderListingParagraph(ctx *renderer.Context, p *types.Pa Roles: roles, Content: content, }) - return result.String(), err } diff --git a/pkg/renderer/sgml/delimited_block_markdown_quote.go b/pkg/renderer/sgml/delimited_block_markdown_quote.go index 40c815e8..9435841e 100644 --- a/pkg/renderer/sgml/delimited_block_markdown_quote.go +++ b/pkg/renderer/sgml/delimited_block_markdown_quote.go @@ -9,7 +9,6 @@ import ( ) func (r *sgmlRenderer) renderMarkdownQuoteBlock(ctx *renderer.Context, b *types.DelimitedBlock) (string, error) { - result := &strings.Builder{} content, err := r.renderElements(ctx, b.Elements) if err != nil { return "", errors.Wrap(err, "unable to render markdown quote block content") @@ -26,8 +25,7 @@ func (r *sgmlRenderer) renderMarkdownQuoteBlock(ctx *renderer.Context, b *types. if err != nil { return "", errors.Wrap(err, "unable to render markdown quote block title") } - - err = r.markdownQuoteBlock.Execute(result, struct { + return r.execute(r.markdownQuoteBlock, struct { Context *renderer.Context ID string Title string @@ -42,5 +40,4 @@ func (r *sgmlRenderer) renderMarkdownQuoteBlock(ctx *renderer.Context, b *types. Attribution: attribution, Content: strings.Trim(content, "\n"), }) - return result.String(), err } diff --git a/pkg/renderer/sgml/delimited_block_open.go b/pkg/renderer/sgml/delimited_block_open.go index e321a5bf..ac09df46 100644 --- a/pkg/renderer/sgml/delimited_block_open.go +++ b/pkg/renderer/sgml/delimited_block_open.go @@ -1,15 +1,12 @@ package sgml import ( - "strings" - "github.com/bytesparadise/libasciidoc/pkg/renderer" "github.com/bytesparadise/libasciidoc/pkg/types" "github.com/pkg/errors" ) func (r *sgmlRenderer) renderOpenBlock(ctx *renderer.Context, b *types.DelimitedBlock) (string, error) { - result := &strings.Builder{} blocks := discardBlankLines(b.Elements) content, err := r.renderElements(ctx, blocks) if err != nil { @@ -23,8 +20,7 @@ func (r *sgmlRenderer) renderOpenBlock(ctx *renderer.Context, b *types.Delimited if err != nil { return "", errors.Wrap(err, "unable to render open block title") } - - err = r.openBlock.Execute(result, struct { + return r.execute(r.openBlock, struct { Context *renderer.Context ID string Title string @@ -37,5 +33,4 @@ func (r *sgmlRenderer) renderOpenBlock(ctx *renderer.Context, b *types.Delimited Roles: roles, Content: content, }) - return result.String(), err } diff --git a/pkg/renderer/sgml/delimited_block_passthrough.go b/pkg/renderer/sgml/delimited_block_passthrough.go index 9c4f6086..cb2e472a 100644 --- a/pkg/renderer/sgml/delimited_block_passthrough.go +++ b/pkg/renderer/sgml/delimited_block_passthrough.go @@ -9,8 +9,6 @@ import ( ) func (r *sgmlRenderer) renderPassthroughBlock(ctx *renderer.Context, b *types.DelimitedBlock) (string, error) { - result := &strings.Builder{} - // lines := discardEmptyLines(b.Lines) previousWithinDelimitedBlock := ctx.WithinDelimitedBlock defer func() { ctx.WithinDelimitedBlock = previousWithinDelimitedBlock @@ -24,7 +22,7 @@ func (r *sgmlRenderer) renderPassthroughBlock(ctx *renderer.Context, b *types.De if err != nil { return "", errors.Wrap(err, "unable to render passthrough block roles") } - err = r.passthroughBlock.Execute(result, struct { + return r.execute(r.passthroughBlock, struct { Context *renderer.Context ID string Roles string @@ -35,5 +33,4 @@ func (r *sgmlRenderer) renderPassthroughBlock(ctx *renderer.Context, b *types.De Roles: roles, Content: strings.Trim(content, "\n"), }) - return result.String(), err } diff --git a/pkg/renderer/sgml/delimited_block_quote.go b/pkg/renderer/sgml/delimited_block_quote.go index d35cbe07..79825e58 100644 --- a/pkg/renderer/sgml/delimited_block_quote.go +++ b/pkg/renderer/sgml/delimited_block_quote.go @@ -1,8 +1,6 @@ package sgml import ( - "strings" - "github.com/bytesparadise/libasciidoc/pkg/renderer" "github.com/bytesparadise/libasciidoc/pkg/types" "github.com/pkg/errors" @@ -10,7 +8,6 @@ import ( ) func (r *sgmlRenderer) renderQuoteBlock(ctx *renderer.Context, b *types.DelimitedBlock) (string, error) { - result := &strings.Builder{} content, err := r.renderElements(ctx, b.Elements) if err != nil { return "", errors.Wrap(err, "unable to render quote block content") @@ -27,8 +24,7 @@ func (r *sgmlRenderer) renderQuoteBlock(ctx *renderer.Context, b *types.Delimite if err != nil { return "", errors.Wrap(err, "unable to render quote block title") } - - err = r.quoteBlock.Execute(result, struct { + return r.execute(r.quoteBlock, struct { Context *renderer.Context ID string Title string @@ -43,13 +39,10 @@ func (r *sgmlRenderer) renderQuoteBlock(ctx *renderer.Context, b *types.Delimite Attribution: attribution, Content: content, }) - return result.String(), err } func (r *sgmlRenderer) renderQuoteParagraph(ctx *renderer.Context, p *types.Paragraph) (string, error) { log.Debug("rendering quote paragraph...") - result := &strings.Builder{} - content, err := r.renderParagraphElements(ctx, p) if err != nil { return "", errors.Wrap(err, "unable to render quote paragraph lines") @@ -62,8 +55,7 @@ func (r *sgmlRenderer) renderQuoteParagraph(ctx *renderer.Context, p *types.Para if err != nil { return "", errors.Wrap(err, "unable to render callout list roles") } - - err = r.quoteParagraph.Execute(result, struct { + return r.execute(r.quoteParagraph, struct { Context *renderer.Context ID string Title string @@ -76,6 +68,4 @@ func (r *sgmlRenderer) renderQuoteParagraph(ctx *renderer.Context, p *types.Para Attribution: attribution, Content: string(content), }) - - return result.String(), err } diff --git a/pkg/renderer/sgml/delimited_block_sidebar.go b/pkg/renderer/sgml/delimited_block_sidebar.go index ca5917b0..57efd71b 100644 --- a/pkg/renderer/sgml/delimited_block_sidebar.go +++ b/pkg/renderer/sgml/delimited_block_sidebar.go @@ -1,16 +1,12 @@ package sgml import ( - "strings" - "github.com/bytesparadise/libasciidoc/pkg/renderer" "github.com/bytesparadise/libasciidoc/pkg/types" "github.com/pkg/errors" ) func (r *sgmlRenderer) renderSidebarBlock(ctx *renderer.Context, b *types.DelimitedBlock) (string, error) { - result := &strings.Builder{} - blocks := discardBlankLines(b.Elements) content, err := r.renderElements(ctx, blocks) if err != nil { @@ -24,8 +20,7 @@ func (r *sgmlRenderer) renderSidebarBlock(ctx *renderer.Context, b *types.Delimi if err != nil { return "", errors.Wrap(err, "unable to render sidebar block title") } - - err = r.sidebarBlock.Execute(result, struct { + return r.execute(r.sidebarBlock, struct { Context *renderer.Context ID string Title string @@ -38,5 +33,4 @@ func (r *sgmlRenderer) renderSidebarBlock(ctx *renderer.Context, b *types.Delimi Roles: roles, Content: content, }) - return result.String(), err } diff --git a/pkg/renderer/sgml/delimited_block_source.go b/pkg/renderer/sgml/delimited_block_source.go index c499eeaf..ee6d99d7 100644 --- a/pkg/renderer/sgml/delimited_block_source.go +++ b/pkg/renderer/sgml/delimited_block_source.go @@ -1,7 +1,6 @@ package sgml import ( - "bytes" "fmt" "strings" @@ -39,9 +38,7 @@ func (r *sgmlRenderer) renderSourceBlock(ctx *renderer.Context, b *types.Delimit if err != nil { return "", errors.Wrap(err, "unable to render source block title") } - - result := &bytes.Buffer{} - err = r.sourceBlock.Execute(result, struct { + return r.execute(r.sourceBlock, struct { ID string Title string Roles string @@ -58,8 +55,6 @@ func (r *sgmlRenderer) renderSourceBlock(ctx *renderer.Context, b *types.Delimit Nowrap: nowrap, Content: strings.Trim(content, "\n"), }) - - return result.String(), err } func (r *sgmlRenderer) renderSourceParagraph(ctx *renderer.Context, p *types.Paragraph) (string, error) { @@ -180,9 +175,13 @@ func (r *sgmlRenderer) renderSourceLine(ctx *renderer.Context, line interface{}) func (r *sgmlRenderer) renderCalloutRef(co *types.Callout) (string, error) { result := &strings.Builder{} - err := r.calloutRef.Execute(result, co) + + tmpl, err := r.calloutRef() if err != nil { - return "", errors.Wrap(err, "unable to render callout number") + return "", errors.Wrap(err, "unable to load cross references template") + } + if err = tmpl.Execute(result, co); err != nil { + return "", errors.Wrap(err, "unable to render callout reference") } return result.String(), nil } diff --git a/pkg/renderer/sgml/delimited_block_verse.go b/pkg/renderer/sgml/delimited_block_verse.go index 91ac901c..5d9d093a 100644 --- a/pkg/renderer/sgml/delimited_block_verse.go +++ b/pkg/renderer/sgml/delimited_block_verse.go @@ -10,7 +10,6 @@ import ( ) func (r *sgmlRenderer) renderVerseBlock(ctx *renderer.Context, b *types.DelimitedBlock) (string, error) { - result := &strings.Builder{} roles, err := r.renderElementRoles(ctx, b.Attributes) if err != nil { return "", errors.Wrap(err, "unable to render verser block roles") @@ -32,8 +31,7 @@ func (r *sgmlRenderer) renderVerseBlock(ctx *renderer.Context, b *types.Delimite if err != nil { return "", errors.Wrap(err, "unable to render verse block title") } - - err = r.verseBlock.Execute(result, struct { + return r.execute(r.verseBlock, struct { Context *renderer.Context ID string Title string @@ -48,13 +46,10 @@ func (r *sgmlRenderer) renderVerseBlock(ctx *renderer.Context, b *types.Delimite Attribution: attribution, Content: strings.Trim(string(content), "\n"), }) - return result.String(), err } func (r *sgmlRenderer) renderVerseParagraph(ctx *renderer.Context, p *types.Paragraph) (string, error) { log.Debug("rendering verse paragraph...") - result := &strings.Builder{} - content, err := r.renderParagraphElements(ctx, p, withRenderer(r.renderPlainText)) if err != nil { return "", errors.Wrap(err, "unable to render verse paragraph lines") @@ -67,8 +62,7 @@ func (r *sgmlRenderer) renderVerseParagraph(ctx *renderer.Context, p *types.Para if err != nil { return "", errors.Wrap(err, "unable to render callout list roles") } - - err = r.verseParagraph.Execute(result, struct { + return r.execute(r.verseParagraph, struct { Context *renderer.Context ID string Title string @@ -81,6 +75,4 @@ func (r *sgmlRenderer) renderVerseParagraph(ctx *renderer.Context, p *types.Para Attribution: attribution, Content: string(content), }) - - return result.String(), err } diff --git a/pkg/renderer/sgml/document_details.go b/pkg/renderer/sgml/document_details.go index c8da37ba..8a51ea00 100644 --- a/pkg/renderer/sgml/document_details.go +++ b/pkg/renderer/sgml/document_details.go @@ -10,52 +10,54 @@ import ( "github.com/pkg/errors" ) -func (r *sgmlRenderer) renderDocumentDetails(ctx *renderer.Context) (*string, error) { - if ctx.Attributes.Has(types.AttrAuthors) { - authors, err := r.renderDocumentAuthorsDetails(ctx) - if err != nil { - return nil, errors.Wrap(err, "error while rendering the document details") - } - documentDetailsBuff := &bytes.Buffer{} - revLabel, _, err := ctx.Attributes.GetAsString(types.AttrVersionLabel) - if err != nil { - return nil, errors.Wrap(err, "error while rendering the document details") - } - revNumber, _, err := ctx.Attributes.GetAsString("revnumber") - if err != nil { - return nil, errors.Wrap(err, "error while rendering the document details") - } - revDate, _, err := ctx.Attributes.GetAsString("revdate") - if err != nil { - return nil, errors.Wrap(err, "error while rendering the document details") - } - revRemark, _, err := ctx.Attributes.GetAsString("revremark") - if err != nil { - return nil, errors.Wrap(err, "error while rendering the document details") - } - err = r.documentDetails.Execute(documentDetailsBuff, struct { - Authors string - RevLabel string - RevNumber string - RevDate string - RevRemark string - }{ - Authors: *authors, - RevLabel: revLabel, - RevNumber: revNumber, - RevDate: revDate, - RevRemark: revRemark, - }) - if err != nil { - return nil, errors.Wrap(err, "error while rendering the document details") - } - documentDetails := string(documentDetailsBuff.String()) - return &documentDetails, nil +func (r *sgmlRenderer) renderDocumentDetails(ctx *renderer.Context) (string, error) { + if !ctx.Attributes.Has(types.AttrAuthors) { + return "", nil + } + authors, err := r.renderDocumentAuthorsDetails(ctx) + if err != nil { + return "", errors.Wrap(err, "error while rendering the document details") + } + documentDetailsBuff := &bytes.Buffer{} + revLabel, _, err := ctx.Attributes.GetAsString(types.AttrVersionLabel) + if err != nil { + return "", errors.Wrap(err, "error while rendering the document details") } - return nil, nil + revNumber, _, err := ctx.Attributes.GetAsString("revnumber") + if err != nil { + return "", errors.Wrap(err, "error while rendering the document details") + } + revDate, _, err := ctx.Attributes.GetAsString("revdate") + if err != nil { + return "", errors.Wrap(err, "error while rendering the document details") + } + revRemark, _, err := ctx.Attributes.GetAsString("revremark") + if err != nil { + return "", errors.Wrap(err, "error while rendering the document details") + } + tmpl, err := r.documentDetails() + if err != nil { + return "", errors.Wrap(err, "unable to load document details template") + } + if err = tmpl.Execute(documentDetailsBuff, struct { + Authors string + RevLabel string + RevNumber string + RevDate string + RevRemark string + }{ + Authors: authors, + RevLabel: revLabel, + RevNumber: revNumber, + RevDate: revDate, + RevRemark: revRemark, + }); err != nil { + return "", errors.Wrap(err, "error while rendering the document details") + } + return documentDetailsBuff.String(), nil } -func (r *sgmlRenderer) renderDocumentAuthorsDetails(ctx *renderer.Context) (*string, error) { // TODO: use `types.DocumentAuthor` attribute in context +func (r *sgmlRenderer) renderDocumentAuthorsDetails(ctx *renderer.Context) (string, error) { // TODO: use `types.DocumentAuthor` attribute in context authorsDetailsBuff := &strings.Builder{} i := 1 for { @@ -73,16 +75,20 @@ func (r *sgmlRenderer) renderDocumentAuthorsDetails(ctx *renderer.Context) (*str } // having at least one author is the minimal requirement for document details if author, ok, err := ctx.Attributes.GetAsString(authorKey); err != nil { - return nil, errors.Wrap(err, "error while rendering the document details") + return "", errors.Wrap(err, "error while rendering the document authors") } else if ok { if i > 1 { authorsDetailsBuff.WriteString("\n") } email, _, err := ctx.Attributes.GetAsString(emailKey) if err != nil { - return nil, errors.Wrap(err, "error while rendering the document details") + return "", errors.Wrap(err, "error while rendering the document authors") + } + tmpl, err := r.documentAuthorDetails() + if err != nil { + return "", errors.Wrap(err, "unable to load document authors template") } - err = r.documentAuthorDetails.Execute(authorsDetailsBuff, struct { + if err := tmpl.Execute(authorsDetailsBuff, struct { Index string Name string Email string @@ -90,9 +96,8 @@ func (r *sgmlRenderer) renderDocumentAuthorsDetails(ctx *renderer.Context) (*str Index: index, Name: author, Email: email, - }) - if err != nil { - return nil, errors.Wrap(err, "error while rendering the document author") + }); err != nil { + return "", errors.Wrap(err, "error while rendering the document authors") } // if there were authors before, need to insert a `\n` i++ @@ -100,6 +105,5 @@ func (r *sgmlRenderer) renderDocumentAuthorsDetails(ctx *renderer.Context) (*str break } } - result := string(authorsDetailsBuff.String()) - return &result, nil + return authorsDetailsBuff.String(), nil } diff --git a/pkg/renderer/sgml/element_id.go b/pkg/renderer/sgml/element_id.go index 83ef473a..e93a6574 100644 --- a/pkg/renderer/sgml/element_id.go +++ b/pkg/renderer/sgml/element_id.go @@ -1,14 +1,14 @@ package sgml import ( - "text/template" + texttemplate "text/template" "github.com/bytesparadise/libasciidoc/pkg/types" ) func (r *sgmlRenderer) renderElementID(attrs types.Attributes) string { if id, ok := attrs[types.AttrID].(string); ok { - return string(template.HTMLEscapeString(id)) + return string(texttemplate.HTMLEscapeString(id)) } return "" } diff --git a/pkg/renderer/sgml/element_style.go b/pkg/renderer/sgml/element_style.go index bd8dbc2f..03683fa0 100644 --- a/pkg/renderer/sgml/element_style.go +++ b/pkg/renderer/sgml/element_style.go @@ -1,14 +1,14 @@ package sgml import ( - "text/template" + texttemplate "text/template" "github.com/bytesparadise/libasciidoc/pkg/types" ) func (r *sgmlRenderer) renderElementStyle(attrs types.Attributes) string { if id, ok := attrs[types.AttrStyle].(string); ok { - return string(template.HTMLEscapeString(id)) + return string(texttemplate.HTMLEscapeString(id)) } return "" } diff --git a/pkg/renderer/sgml/footnote_reference.go b/pkg/renderer/sgml/footnote_reference.go index a96004b9..79df67f2 100644 --- a/pkg/renderer/sgml/footnote_reference.go +++ b/pkg/renderer/sgml/footnote_reference.go @@ -2,7 +2,6 @@ package sgml import ( "fmt" - "io" "strings" "github.com/bytesparadise/libasciidoc/pkg/renderer" @@ -14,36 +13,45 @@ func (r *sgmlRenderer) renderFootnoteReference(note *types.FootnoteReference) (s result := &strings.Builder{} if note.ID != types.InvalidFootnoteReference && !note.Duplicate { // valid case for a footnote with content, with our without an explicit reference - err := r.footnote.Execute(result, struct { + tmpl, err := r.footnote() + if err != nil { + return "", errors.Wrap(err, "unable to load footnote template") + } + if err := tmpl.Execute(result, struct { ID int Ref string }{ ID: note.ID, Ref: note.Ref, - }) - if err != nil { + }); err != nil { return "", errors.Wrap(err, "unable to render footnote") } } else if note.Duplicate { // valid case for a footnote with content, with our without an explicit reference - err := r.footnoteRef.Execute(result, struct { + tmpl, err := r.footnoteRef() + if err != nil { + return "", errors.Wrap(err, "unable to load footnote template") + } + if err := tmpl.Execute(result, struct { ID int Ref string }{ ID: note.ID, Ref: note.Ref, - }) - if err != nil { + }); err != nil { return "", errors.Wrap(err, "unable to render footnote") } } else { // invalid footnote - err := r.invalidFootnote.Execute(result, struct { + tmpl, err := r.invalidFootnote() + if err != nil { + return "", errors.Wrap(err, "unable to load missing footnote template") + } + if err := tmpl.Execute(result, struct { Ref string }{ Ref: note.Ref, - }) - if err != nil { + }); err != nil { return "", errors.Wrap(err, "unable to render missing footnote") } } @@ -51,23 +59,17 @@ func (r *sgmlRenderer) renderFootnoteReference(note *types.FootnoteReference) (s } func (r *sgmlRenderer) renderFootnoteReferencePlainText(note *types.FootnoteReference) (string, error) { - result := &strings.Builder{} if note.ID != types.InvalidFootnoteReference { // valid case for a footnote with content, with our without an explicit reference - err := r.footnoteRefPlain.Execute(result, struct { + return r.execute(r.footnoteRefPlain, struct { ID int Class string }{ ID: note.ID, Class: "footnote", }) - if err != nil { - return "", errors.Wrap(err, "unable to render footnote") - } - } else { - return "", fmt.Errorf("unable to render missing footnote") } - return result.String(), nil + return "", fmt.Errorf("unable to render missing footnote") } func (r *sgmlRenderer) renderFootnotes(ctx *renderer.Context, notes []*types.Footnote) (string, error) { @@ -75,16 +77,15 @@ func (r *sgmlRenderer) renderFootnotes(ctx *renderer.Context, notes []*types.Foo if len(notes) == 0 { return "", nil } - result := &strings.Builder{} content := &strings.Builder{} - - for _, item := range notes { - if err := r.renderFootnoteItem(ctx, content, item); err != nil { - return "", errors.Wrap(err, "failed to render footnote item") + for _, note := range notes { + renderedNote, err := r.renderFootnoteElement(ctx, note) + if err != nil { + return "", errors.Wrap(err, "failed to render footnote element") } + content.WriteString(renderedNote) } - - err := r.footnotes.Execute(result, struct { + return r.execute(r.footnotes, struct { Context *renderer.Context Content string Footnotes []*types.Footnote @@ -93,30 +94,25 @@ func (r *sgmlRenderer) renderFootnotes(ctx *renderer.Context, notes []*types.Foo Content: content.String(), Footnotes: notes, }) - if err != nil { - return "", errors.Wrap(err, "failed to render footnotes") - } - return result.String(), nil } -func (r *sgmlRenderer) renderFootnoteItem(ctx *renderer.Context, w io.Writer, item *types.Footnote) error { - content, err := r.renderInlineElements(ctx, item.Elements) +func (r *sgmlRenderer) renderFootnoteElement(ctx *renderer.Context, note *types.Footnote) (string, error) { + content, err := r.renderInlineElements(ctx, note.Elements) if err != nil { - return errors.Wrapf(err, "unable to render foot note content") + return "", errors.Wrapf(err, "unable to render foot note content") } content = strings.TrimSpace(content) // Note: Asciidoctor will render the footnote content on a single line content = strings.ReplaceAll(content, "\n", " ") - err = r.footnoteItem.Execute(w, struct { + return r.execute(r.footnoteElement, struct { Context *renderer.Context ID int Ref string Content string }{ Context: ctx, - ID: item.ID, - Ref: item.Ref, + ID: note.ID, + Ref: note.Ref, Content: string(content), }) - return err } diff --git a/pkg/renderer/sgml/html5/blank_line.go b/pkg/renderer/sgml/html5/blank_line.go index f4e2e730..d48c6c89 100644 --- a/pkg/renderer/sgml/html5/blank_line.go +++ b/pkg/renderer/sgml/html5/blank_line.go @@ -2,5 +2,4 @@ package html5 const ( lineBreakTmpl = "
" - blankLineTmpl = "\n\n" ) diff --git a/pkg/renderer/sgml/html5/callout_list.go b/pkg/renderer/sgml/html5/callout_list.go index 16db2d40..8b8a9040 100644 --- a/pkg/renderer/sgml/html5/callout_list.go +++ b/pkg/renderer/sgml/html5/callout_list.go @@ -11,7 +11,7 @@ const ( "\n\n" // NB: The items are numbered sequentially. - calloutListItemTmpl = "
  • \n{{ .Content }}
  • \n" + calloutListElementTmpl = "
  • \n{{ .Content }}
  • \n" // This should probably have been a , but for compatibility we use calloutRefTmpl = "({{ .Ref }})" diff --git a/pkg/renderer/sgml/html5/footnote_reference.go b/pkg/renderer/sgml/html5/footnote_reference.go index 58e38e9b..5d2dc386 100644 --- a/pkg/renderer/sgml/html5/footnote_reference.go +++ b/pkg/renderer/sgml/html5/footnote_reference.go @@ -8,7 +8,7 @@ const ( footnotesTmpl = "
    \n
    \n{{ .Content }}
    \n" // arguably this should instead be an ordered list. - footnoteItemTmpl = "
    \n" + + footnoteElementTmpl = "
    \n" + "{{ .ID }}. {{ .Content }}\n" + "
    \n" ) diff --git a/pkg/renderer/sgml/html5/labeled_list.go b/pkg/renderer/sgml/html5/labeled_list.go index be309d20..cc030705 100644 --- a/pkg/renderer/sgml/html5/labeled_list.go +++ b/pkg/renderer/sgml/html5/labeled_list.go @@ -7,7 +7,7 @@ const ( "{{ if .Title }}
    {{ .Title }}
    \n{{ end }}" + "
    \n{{ .Content }}
    \n
    \n" - labeledListItemTmpl = "
    {{ .Term }}
    \n" + + labeledListElementTmpl = "
    {{ .Term }}
    \n" + "{{ if .Content }}
    \n{{ .Content }}
    \n{{ end }}" labeledListHorizontalTmpl = `\n{{ .Content }}\n\n" // Continuation items (multiple terms sharing a single definition) make this a bit more complex. - labeledListHorizontalItemTmpl = "{{ if not .Continuation }}\n" + + labeledListHorizontalElementTmpl = "{{ if not .Continuation }}\n" + "\n{{ else }}
    \n{{ end }}" + "{{ .Term }}\n" + "{{ if .Content }}\n\n{{ .Content }}\n\n{{ end }}" @@ -28,5 +28,5 @@ const ( "{{ if .Title }}
    {{ .Title }}
    \n{{ end }}" + "
      \n{{ .Content }}
    \n\n" - qAndAListItemTmpl = "
  • \n

    {{ .Term }}

    \n{{ .Content }}
  • \n" + qAndAListElementTmpl = "
  • \n

    {{ .Term }}

    \n{{ .Content }}
  • \n" ) diff --git a/pkg/renderer/sgml/html5/ordered_list.go b/pkg/renderer/sgml/html5/ordered_list.go index 4ceff2bf..dd24c671 100644 --- a/pkg/renderer/sgml/html5/ordered_list.go +++ b/pkg/renderer/sgml/html5/ordered_list.go @@ -13,5 +13,5 @@ const ( `{{ if .Reversed }} reversed{{ end }}` + ">\n{{ .Content }}\n\n" - orderedListItemTmpl = "
  • \n{{ .Content }}
  • \n" + orderedListElementTmpl = "
  • \n{{ .Content }}
  • \n" ) diff --git a/pkg/renderer/sgml/html5/section.go b/pkg/renderer/sgml/html5/section.go index 608241be..0fedff2a 100644 --- a/pkg/renderer/sgml/html5/section.go +++ b/pkg/renderer/sgml/html5/section.go @@ -7,6 +7,6 @@ const ( {{ end }}{{ .Content }}{{ if eq .Level 1 }} {{ end }} ` - sectionHeaderTmpl = `{{ if .Number }}{{ .Number }}. {{ end }}{{ .Content }} + sectionTitleTmpl = `{{ if .Number }}{{ .Number }}. {{ end }}{{ .Content }} ` ) diff --git a/pkg/renderer/sgml/html5/templates.go b/pkg/renderer/sgml/html5/templates.go index 506a0872..f2d72e31 100644 --- a/pkg/renderer/sgml/html5/templates.go +++ b/pkg/renderer/sgml/html5/templates.go @@ -9,83 +9,82 @@ import ( ) var templates = sgml.Templates{ - AdmonitionBlock: admonitionBlockTmpl, - AdmonitionParagraph: admonitionParagraphTmpl, - Article: articleTmpl, - ArticleHeader: articleHeaderTmpl, - BlankLine: blankLineTmpl, - BlockImage: blockImageTmpl, - BoldText: boldTextTmpl, - CalloutList: calloutListTmpl, - CalloutListItem: calloutListItemTmpl, - CalloutRef: calloutRefTmpl, - DocumentDetails: documentDetailsTmpl, - DocumentAuthorDetails: documentAuthorDetailsTmpl, - EmbeddedParagraph: embeddedParagraphTmpl, - ExternalCrossReference: externalCrossReferenceTmpl, - ExampleBlock: exampleBlockTmpl, - FencedBlock: fencedBlockTmpl, - Footnote: footnoteTmpl, - FootnoteItem: footnoteItemTmpl, - FootnoteRef: footnoteRefTmpl, - FootnoteRefPlain: footnoteRefPlainTmpl, - Footnotes: footnotesTmpl, - IconFont: iconFontTmpl, - IconImage: iconImageTmpl, - IconText: iconTextTmpl, - InlineButton: inlineButtonTmpl, - InlineIcon: inlineIconTmpl, - InlineImage: inlineImageTmpl, - InlineMenu: inlineMenuTmpl, - InternalCrossReference: internalCrossReferenceTmpl, - InvalidFootnote: invalidFootnoteTmpl, - ItalicText: italicTextTmpl, - LabeledList: labeledListTmpl, - LabeledListItem: labeledListItemTmpl, - LabeledListHorizontal: labeledListHorizontalTmpl, - LabeledListHorizontalItem: labeledListHorizontalItemTmpl, - LineBreak: lineBreakTmpl, - Link: linkTmpl, - ListingBlock: listingBlockTmpl, - LiteralBlock: literalBlockTmpl, - ManpageHeader: manpageHeaderTmpl, - ManpageNameParagraph: manpageNameParagraphTmpl, - MarkdownQuoteBlock: markdownQuoteBlockTmpl, - MarkedText: markedTextTmpl, - MonospaceText: monospaceTextTmpl, - OpenBlock: openBlockTmpl, - OrderedList: orderedListTmpl, - OrderedListElement: orderedListItemTmpl, - PassthroughBlock: passthroughBlock, - Paragraph: paragraphTmpl, - Preamble: preambleTmpl, - QAndAList: qAndAListTmpl, - QAndAListItem: qAndAListItemTmpl, - QuoteBlock: quoteBlockTmpl, - QuoteParagraph: quoteParagraphTmpl, - SectionContent: sectionContentTmpl, - SectionHeader: sectionHeaderTmpl, - SidebarBlock: sidebarBlockTmpl, - SourceBlock: sourceBlockTmpl, - SubscriptText: subscriptTextTmpl, - SuperscriptText: superscriptTextTmpl, - Table: tableTmpl, - TableBody: tableBodyTmpl, - TableCell: tableCellTmpl, - TableCellBlock: tableCellBlockTmpl, - TableHeader: tableHeaderTmpl, - TableHeaderCell: tableHeaderCellTmpl, - TableFooter: tableFooterTmpl, - TableFooterCell: tableFooterCellTmpl, - TableRow: tableRowTmpl, - ThematicBreak: thematicBreakTmpl, - TocRoot: tocRootTmpl, - TocEntry: tocEntryTmpl, - TocSection: tocSectionTmpl, - UnorderedList: unorderedListTmpl, - UnorderedListItem: unorderedListItemTmpl, - VerseBlock: verseBlockTmpl, - VerseParagraph: verseParagraphTmpl, + AdmonitionBlock: admonitionBlockTmpl, + AdmonitionParagraph: admonitionParagraphTmpl, + Article: articleTmpl, + ArticleHeader: articleHeaderTmpl, + BlockImage: blockImageTmpl, + BoldText: boldTextTmpl, + CalloutList: calloutListTmpl, + CalloutListElement: calloutListElementTmpl, + CalloutRef: calloutRefTmpl, + DocumentDetails: documentDetailsTmpl, + DocumentAuthorDetails: documentAuthorDetailsTmpl, + EmbeddedParagraph: embeddedParagraphTmpl, + ExternalCrossReference: externalCrossReferenceTmpl, + ExampleBlock: exampleBlockTmpl, + FencedBlock: fencedBlockTmpl, + Footnote: footnoteTmpl, + FootnoteElement: footnoteElementTmpl, + FootnoteRef: footnoteRefTmpl, + FootnoteRefPlain: footnoteRefPlainTmpl, + Footnotes: footnotesTmpl, + IconFont: iconFontTmpl, + IconImage: iconImageTmpl, + IconText: iconTextTmpl, + InlineButton: inlineButtonTmpl, + InlineIcon: inlineIconTmpl, + InlineImage: inlineImageTmpl, + InlineMenu: inlineMenuTmpl, + InternalCrossReference: internalCrossReferenceTmpl, + InvalidFootnote: invalidFootnoteTmpl, + ItalicText: italicTextTmpl, + LabeledList: labeledListTmpl, + LabeledListElement: labeledListElementTmpl, + LabeledListHorizontal: labeledListHorizontalTmpl, + LabeledListHorizontalElement: labeledListHorizontalElementTmpl, + LineBreak: lineBreakTmpl, + Link: linkTmpl, + ListingBlock: listingBlockTmpl, + LiteralBlock: literalBlockTmpl, + ManpageHeader: manpageHeaderTmpl, + ManpageNameParagraph: manpageNameParagraphTmpl, + MarkdownQuoteBlock: markdownQuoteBlockTmpl, + MarkedText: markedTextTmpl, + MonospaceText: monospaceTextTmpl, + OpenBlock: openBlockTmpl, + OrderedList: orderedListTmpl, + OrderedListElement: orderedListElementTmpl, + PassthroughBlock: passthroughBlock, + Paragraph: paragraphTmpl, + Preamble: preambleTmpl, + QAndAList: qAndAListTmpl, + QAndAListElement: qAndAListElementTmpl, + QuoteBlock: quoteBlockTmpl, + QuoteParagraph: quoteParagraphTmpl, + SectionContent: sectionContentTmpl, + SectionTitle: sectionTitleTmpl, + SidebarBlock: sidebarBlockTmpl, + SourceBlock: sourceBlockTmpl, + SubscriptText: subscriptTextTmpl, + SuperscriptText: superscriptTextTmpl, + Table: tableTmpl, + TableBody: tableBodyTmpl, + TableCell: tableCellTmpl, + TableCellBlock: tableCellBlockTmpl, + TableHeader: tableHeaderTmpl, + TableHeaderCell: tableHeaderCellTmpl, + TableFooter: tableFooterTmpl, + TableFooterCell: tableFooterCellTmpl, + TableRow: tableRowTmpl, + ThematicBreak: thematicBreakTmpl, + TocRoot: tocRootTmpl, + TocEntry: tocEntryTmpl, + TocSection: tocSectionTmpl, + UnorderedList: unorderedListTmpl, + UnorderedListElement: unorderedListElementTmpl, + VerseBlock: verseBlockTmpl, + VerseParagraph: verseParagraphTmpl, } var defaultRenderer sgml.Renderer diff --git a/pkg/renderer/sgml/html5/unordered_list.go b/pkg/renderer/sgml/html5/unordered_list.go index 12f4efba..73feabd4 100644 --- a/pkg/renderer/sgml/html5/unordered_list.go +++ b/pkg/renderer/sgml/html5/unordered_list.go @@ -10,5 +10,5 @@ const ( "\n" + "{{ .Content }}\n\n" - unorderedListItemTmpl = "
  • \n{{ .Content }}
  • \n" + unorderedListElementTmpl = "
  • \n{{ .Content }}
  • \n" ) diff --git a/pkg/renderer/sgml/icon.go b/pkg/renderer/sgml/icon.go index d0148a3d..aafbec0d 100644 --- a/pkg/renderer/sgml/icon.go +++ b/pkg/renderer/sgml/icon.go @@ -4,7 +4,7 @@ import ( fmt "fmt" "path" "strings" - text "text/template" + texttemplate "text/template" "github.com/bytesparadise/libasciidoc/pkg/renderer" "github.com/bytesparadise/libasciidoc/pkg/types" @@ -12,8 +12,6 @@ import ( ) func (r *sgmlRenderer) renderInlineIcon(ctx *renderer.Context, icon *types.Icon) (string, error) { - result := &strings.Builder{} - iconStr, err := r.renderIcon(ctx, types.Icon{ Class: icon.Class, Attributes: icon.Attributes, @@ -21,7 +19,7 @@ func (r *sgmlRenderer) renderInlineIcon(ctx *renderer.Context, icon *types.Icon) if err != nil { return "", err } - err = r.inlineIcon.Execute(result, struct { + return r.execute(r.inlineIcon, struct { Class string Role string Link string @@ -36,11 +34,6 @@ func (r *sgmlRenderer) renderInlineIcon(ctx *renderer.Context, icon *types.Icon) Window: icon.Attributes.GetAsStringWithDefault(types.AttrImageWindow, ""), Role: icon.Attributes.GetAsStringWithDefault(types.AttrRoles, ""), }) - - if err != nil { - return "", errors.Wrap(err, "unable to render inline image") - } - return result.String(), nil } var defaultIconClasses = map[string]string{ @@ -53,19 +46,23 @@ var defaultIconClasses = map[string]string{ func (r *sgmlRenderer) renderIcon(ctx *renderer.Context, icon types.Icon, admonition bool) (string, error) { icons := ctx.Attributes.GetAsStringWithDefault("icons", "text") - var template *text.Template + var tmpl *texttemplate.Template + var err error font := false switch icons { case "font": font = true - template = r.iconFont + tmpl, err = r.iconFont() case "text": - template = r.iconText + tmpl, err = r.iconText() case "image", "": - template = r.iconImage + tmpl, err = r.iconImage() default: return "", fmt.Errorf("unsupported icon type %s", icons) } + if err != nil { + return "", errors.Wrap(err, "unable to load icon template") + } title := "" alt := icon.Class @@ -88,7 +85,7 @@ func (r *sgmlRenderer) renderIcon(ctx *renderer.Context, icon types.Icon, admoni title = icon.Attributes.GetAsStringWithDefault(types.AttrTitle, "") } s := &strings.Builder{} - err := template.Execute(s, struct { + if err := tmpl.Execute(s, struct { Class string Alt string Title string @@ -114,8 +111,10 @@ func (r *sgmlRenderer) renderIcon(ctx *renderer.Context, icon types.Icon, admoni Window: icon.Attributes.GetAsStringWithDefault(types.AttrImageWindow, ""), Src: renderIconPath(ctx, icon.Class), Admonition: admonition, - }) - return string(s.String()), err + }); err != nil { + return "", errors.Wrap(err, "unable to render icon") + } + return string(s.String()), nil } func renderIconPath(ctx *renderer.Context, name string) string { diff --git a/pkg/renderer/sgml/image.go b/pkg/renderer/sgml/image.go index 5a961979..2eb26827 100644 --- a/pkg/renderer/sgml/image.go +++ b/pkg/renderer/sgml/image.go @@ -15,7 +15,6 @@ import ( ) func (r *sgmlRenderer) renderImageBlock(ctx *renderer.Context, img *types.ImageBlock) (string, error) { - result := &strings.Builder{} title, err := r.renderElementTitle(ctx, img.Attributes) if err != nil { return "", errors.Wrap(err, "unable to render image") @@ -57,7 +56,7 @@ func (r *sgmlRenderer) renderImageBlock(ctx *renderer.Context, img *types.ImageB if err != nil { return "", errors.Wrap(err, "unable to render image") } - err = r.blockImage.Execute(result, struct { + return r.execute(r.blockImage, struct { ID string Src string Title string @@ -80,31 +79,24 @@ func (r *sgmlRenderer) renderImageBlock(ctx *renderer.Context, img *types.ImageB Width: img.Attributes.GetAsStringWithDefault(types.AttrWidth, ""), Height: img.Attributes.GetAsStringWithDefault(types.AttrHeight, ""), }) - - if err != nil { - return "", errors.Wrap(err, "unable to render image") - } - return result.String(), nil } func (r *sgmlRenderer) renderInlineImage(ctx *renderer.Context, img *types.InlineImage) (string, error) { - result := &strings.Builder{} roles, err := r.renderImageRoles(ctx, img.Attributes) if err != nil { - return "", errors.Wrap(err, "unable to render image") + return "", errors.Wrap(err, "unable to render inline image") } href := img.Attributes.GetAsStringWithDefault(types.AttrInlineLink, "") src := r.getImageSrc(ctx, img.Location) alt, err := r.renderImageAlt(img.Attributes, src) if err != nil { - return "", errors.Wrap(err, "unable to render image") + return "", errors.Wrap(err, "unable to render inline image") } title, err := r.renderElementTitle(ctx, img.Attributes) if err != nil { - return "", errors.Wrap(err, "unable to render callout list roles") + return "", errors.Wrap(err, "unable to render inline image roles") } - - err = r.inlineImage.Execute(result, struct { + return r.execute(r.inlineImage, struct { Src string Roles string Title string @@ -121,14 +113,6 @@ func (r *sgmlRenderer) renderInlineImage(ctx *renderer.Context, img *types.Inlin Width: img.Attributes.GetAsStringWithDefault(types.AttrWidth, ""), Height: img.Attributes.GetAsStringWithDefault(types.AttrHeight, ""), }) - - if err != nil { - return "", errors.Wrap(err, "unable to render inline image") - } - if log.IsLevelEnabled(log.DebugLevel) { - log.Debugf("rendered inline image: %s", result.String()) - } - return result.String(), nil } func (r *sgmlRenderer) getImageSrc(ctx *renderer.Context, location *types.Location) string { diff --git a/pkg/renderer/sgml/inline_button.go b/pkg/renderer/sgml/inline_button.go index 7a37b329..cc6a677d 100644 --- a/pkg/renderer/sgml/inline_button.go +++ b/pkg/renderer/sgml/inline_button.go @@ -4,12 +4,17 @@ import ( "strings" "github.com/bytesparadise/libasciidoc/pkg/types" + "github.com/pkg/errors" ) func (r *sgmlRenderer) renderInlineButton(b *types.InlineButton) (string, error) { - buf := &strings.Builder{} - if err := r.inlineButton.Execute(buf, b.Attributes[types.AttrButtonLabel]); err != nil { - return "", err + result := &strings.Builder{} + tmpl, err := r.inlineButton() + if err != nil { + return "", errors.Wrap(err, "unable to load inline button template") } - return buf.String(), nil + if err = tmpl.Execute(result, b.Attributes[types.AttrButtonLabel]); err != nil { + return "", errors.Wrap(err, "unable to render inline button") + } + return result.String(), nil } diff --git a/pkg/renderer/sgml/inline_menu.go b/pkg/renderer/sgml/inline_menu.go index bb8d2e08..4998d540 100644 --- a/pkg/renderer/sgml/inline_menu.go +++ b/pkg/renderer/sgml/inline_menu.go @@ -1,19 +1,13 @@ package sgml import ( - "strings" - "github.com/bytesparadise/libasciidoc/pkg/types" ) func (r *sgmlRenderer) renderInlineMenu(m *types.InlineMenu) (string, error) { - buf := &strings.Builder{} - if err := r.inlineMenu.Execute(buf, struct { + return r.execute(r.inlineMenu, struct { Path []string }{ Path: m.Path, - }); err != nil { - return "", err - } - return buf.String(), nil + }) } diff --git a/pkg/renderer/sgml/link.go b/pkg/renderer/sgml/link.go index 59f1b661..f02274d5 100644 --- a/pkg/renderer/sgml/link.go +++ b/pkg/renderer/sgml/link.go @@ -7,11 +7,9 @@ import ( "github.com/bytesparadise/libasciidoc/pkg/renderer" "github.com/bytesparadise/libasciidoc/pkg/types" "github.com/pkg/errors" - log "github.com/sirupsen/logrus" ) func (r *sgmlRenderer) renderLink(ctx *renderer.Context, l *types.InlineLink) (string, error) { - result := &strings.Builder{} location := l.Location.ToString() text := "" class := "" @@ -43,7 +41,7 @@ func (r *sgmlRenderer) renderLink(ctx *renderer.Context, l *types.InlineLink) (s } target := l.Attributes.GetAsStringWithDefault(types.AttrInlineLinkTarget, "") noopener := target == "_blank" || l.Attributes.HasOption("noopener") - err = r.link.Execute(result, struct { + return r.execute(r.link, struct { ID string URL string Text string @@ -58,9 +56,4 @@ func (r *sgmlRenderer) renderLink(ctx *renderer.Context, l *types.InlineLink) (s Target: target, NoOpener: noopener, }) - if err != nil { - return "", errors.Wrap(err, "unable to render link") - } - log.Debugf("rendered link: %s", result.String()) - return result.String(), nil } diff --git a/pkg/renderer/sgml/list.go b/pkg/renderer/sgml/list.go index b6a43773..a9b69165 100644 --- a/pkg/renderer/sgml/list.go +++ b/pkg/renderer/sgml/list.go @@ -4,7 +4,7 @@ import ( "fmt" "io" "strings" - text "text/template" + texttemplate "text/template" "github.com/bytesparadise/libasciidoc/pkg/renderer" "github.com/bytesparadise/libasciidoc/pkg/types" @@ -30,7 +30,6 @@ func (r *sgmlRenderer) renderList(ctx *renderer.Context, l *types.List) (string, // Ordered Lists // ------------------------------------------------------- func (r *sgmlRenderer) renderOrderedList(ctx *renderer.Context, l *types.List) (string, error) { - result := &strings.Builder{} content := &strings.Builder{} for _, element := range l.Elements { @@ -54,7 +53,7 @@ func (r *sgmlRenderer) renderOrderedList(ctx *renderer.Context, l *types.List) ( if err != nil { return "", errors.Wrap(err, "unable to render callout list roles") } - err = r.orderedList.Execute(result, struct { + return r.execute(r.orderedList, struct { Context *renderer.Context ID string Title string @@ -64,7 +63,6 @@ func (r *sgmlRenderer) renderOrderedList(ctx *renderer.Context, l *types.List) ( Start string Content string Reversed bool - // Elements []types.ListElement }{ ID: r.renderElementID(l.Attributes), Title: title, @@ -72,14 +70,9 @@ func (r *sgmlRenderer) renderOrderedList(ctx *renderer.Context, l *types.List) ( Style: style, ListStyle: r.numberingType(style), Start: l.Attributes.GetAsStringWithDefault(types.AttrStart, ""), - Content: string(content.String()), + Content: content.String(), Reversed: l.Attributes.HasOption("reversed"), - // Elements: l.Elements, }) - if err != nil { - return "", errors.Wrap(err, "unable to render ordered list") - } - return result.String(), nil } func getNumberingStyle(l *types.List) (string, error) { @@ -114,15 +107,22 @@ func (r *sgmlRenderer) numberingType(style string) string { func (r *sgmlRenderer) renderOrderedListElement(ctx *renderer.Context, w io.Writer, element *types.OrderedListElement) error { content, err := r.renderListElements(ctx, element.GetElements()) if err != nil { - return errors.Wrap(err, "unable to render unordered list element content") + return errors.Wrap(err, "unable to render ordered list element content") } - return r.orderedListItem.Execute(w, struct { + tmpl, err := r.orderedListElement() + if err != nil { + return errors.Wrap(err, "unable to load ordered list element template") + } + if err = tmpl.Execute(w, struct { Context *renderer.Context Content string }{ Context: ctx, Content: string(content), - }) + }); err != nil { + return errors.Wrap(err, "unable to render ordered list element") + } + return nil } // ------------------------------------------------------- @@ -140,7 +140,6 @@ func (r *sgmlRenderer) renderUnorderedList(ctx *renderer.Context, l *types.List) checkList = true } } - result := &strings.Builder{} content := &strings.Builder{} for _, element := range l.Elements { @@ -156,9 +155,7 @@ func (r *sgmlRenderer) renderUnorderedList(ctx *renderer.Context, l *types.List) if err != nil { return "", errors.Wrap(err, "unable to render callout list roles") } - - // here we must preserve the HTML tags - err = r.unorderedList.Execute(result, struct { + return r.execute(r.unorderedList, struct { Context *renderer.Context ID string Title string @@ -173,27 +170,30 @@ func (r *sgmlRenderer) renderUnorderedList(ctx *renderer.Context, l *types.List) Title: title, Checklist: checkList, Items: l.Elements, - Content: string(content.String()), + Content: content.String(), Roles: roles, Style: r.renderElementStyle(l.Attributes), }) - if err != nil { - return "", errors.Wrap(err, "unable to render unordered list") - } - return result.String(), nil } func (r *sgmlRenderer) renderUnorderedListElement(ctx *renderer.Context, w io.Writer, element types.ListElement) error { content, err := r.renderListElements(ctx, element.GetElements()) if err != nil { return errors.Wrap(err, "unable to render unordered list element content") } - return r.unorderedListItem.Execute(w, struct { + tmpl, err := r.unorderedListElement() + if err != nil { + return errors.Wrap(err, "unable to load unordered list element template") + } + if err := tmpl.Execute(w, struct { Context *renderer.Context Content string }{ Context: ctx, Content: string(content), - }) + }); err != nil { + return errors.Wrap(err, "unable to render unordered list element") + } + return nil } // ------------------------------------------------------- @@ -225,8 +225,7 @@ func (r *sgmlRenderer) renderLabeledList(ctx *renderer.Context, l *types.List) ( return "", errors.Wrap(err, "unable to render labeled list roles") } result := &strings.Builder{} - // here we must preserve the HTML tags - err = tmpl.Execute(result, struct { + if err := tmpl.Execute(result, struct { Context *renderer.Context ID string Title string @@ -238,30 +237,53 @@ func (r *sgmlRenderer) renderLabeledList(ctx *renderer.Context, l *types.List) ( ID: r.renderElementID(l.Attributes), Title: title, Roles: roles, - Content: string(content.String()), + Content: content.String(), Items: l.Elements, - }) - if err != nil { + }); err != nil { return "", errors.Wrap(err, "unable to render labeled list") } return result.String(), nil } -func (r *sgmlRenderer) getLabeledListTmpl(l *types.List) (*text.Template, *text.Template, error) { +func (r *sgmlRenderer) getLabeledListTmpl(l *types.List) (*texttemplate.Template, *texttemplate.Template, error) { if layout, ok := l.Attributes[types.AttrStyle]; ok { switch layout { case "qanda": - return r.qAndAList, r.qAndAListItem, nil + listTmpl, err := r.qAndAList() + if err != nil { + return nil, nil, errors.Wrap(err, "unable to load q&A list template") + } + listElementTmpl, err := r.qAndAListElement() + if err != nil { + return nil, nil, errors.Wrap(err, "unable to load q&A list element template") + } + return listTmpl, listElementTmpl, nil case "horizontal": - return r.labeledListHorizontal, r.labeledListHorizontalItem, nil + listTmpl, err := r.labeledListHorizontal() + if err != nil { + return nil, nil, errors.Wrap(err, "unable to load horizontal list template") + } + listElementTmpl, err := r.labeledListHorizontalElement() + if err != nil { + return nil, nil, errors.Wrap(err, "unable to load horizontal list element template") + } + return listTmpl, listElementTmpl, nil default: return nil, nil, errors.Errorf("unsupported labeled list layout: %s", layout) } } - return r.labeledList, r.labeledListItem, nil + listTmpl, err := r.labeledList() + if err != nil { + return nil, nil, errors.Wrap(err, "unable to load labeled list template") + } + listElementTmpl, err := r.labeledListElement() + if err != nil { + return nil, nil, errors.Wrap(err, "unable to load labeld list element template") + } + return listTmpl, listElementTmpl, nil } -func (r *sgmlRenderer) renderLabeledListItem(ctx *renderer.Context, tmpl *text.Template, w io.Writer, continuation bool, element *types.LabeledListElement) (bool, error) { +func (r *sgmlRenderer) renderLabeledListItem(ctx *renderer.Context, tmpl *texttemplate.Template, w io.Writer, continuation bool, element *types.LabeledListElement) (bool, error) { term, err := r.renderInlineElements(ctx, element.Term) if err != nil { @@ -289,17 +311,17 @@ func (r *sgmlRenderer) renderLabeledListItem(ctx *renderer.Context, tmpl *text.T // Callout Lists // ------------------------------------------------------- func (r *sgmlRenderer) renderCalloutList(ctx *renderer.Context, l *types.List) (string, error) { - result := &strings.Builder{} content := &strings.Builder{} - for _, element := range l.Elements { e, ok := element.(*types.CalloutListElement) if !ok { return "", errors.Errorf("unable to render callout list element of type '%T'", element) } - if err := r.renderCalloutListItem(ctx, content, e); err != nil { + rendererElement, err := r.renderCalloutListElement(ctx, e) + if err != nil { return "", errors.Wrap(err, "unable to render callout list element") } + content.WriteString(rendererElement) } roles, err := r.renderElementRoles(ctx, l.Attributes) if err != nil { @@ -309,8 +331,7 @@ func (r *sgmlRenderer) renderCalloutList(ctx *renderer.Context, l *types.List) ( if err != nil { return "", errors.Wrap(err, "unable to render callout list roles") } - - err = r.calloutList.Execute(result, struct { + return r.execute(r.calloutList, struct { Context *renderer.Context ID string Title string @@ -322,21 +343,17 @@ func (r *sgmlRenderer) renderCalloutList(ctx *renderer.Context, l *types.List) ( ID: r.renderElementID(l.Attributes), Title: title, Roles: roles, - Content: string(content.String()), + Content: content.String(), Items: l.Elements, }) - if err != nil { - return "", errors.Wrap(err, "unable to render callout list") - } - return result.String(), nil } -func (r *sgmlRenderer) renderCalloutListItem(ctx *renderer.Context, w io.Writer, element *types.CalloutListElement) error { +func (r *sgmlRenderer) renderCalloutListElement(ctx *renderer.Context, element *types.CalloutListElement) (string, error) { content, err := r.renderListElements(ctx, element.Elements) if err != nil { - return errors.Wrap(err, "unable to render callout list element content") + return "", errors.Wrap(err, "unable to render callout list element content") } - err = r.calloutListItem.Execute(w, struct { + return r.execute(r.calloutListElement, struct { Context *renderer.Context Ref int Content string @@ -345,8 +362,4 @@ func (r *sgmlRenderer) renderCalloutListItem(ctx *renderer.Context, w io.Writer, Ref: element.Ref, Content: string(content), }) - if err != nil { - return errors.Wrap(err, "unable to render callout list") - } - return nil } diff --git a/pkg/renderer/sgml/literal_blocks.go b/pkg/renderer/sgml/literal_blocks.go index 95ef3755..624e9470 100644 --- a/pkg/renderer/sgml/literal_blocks.go +++ b/pkg/renderer/sgml/literal_blocks.go @@ -24,8 +24,7 @@ func (r *sgmlRenderer) renderLiteralBlock(ctx *renderer.Context, b *types.Delimi return "", errors.Wrap(err, "unable to render literal block title") } - result := &strings.Builder{} - err = r.literalBlock.Execute(result, struct { + return r.execute(r.literalBlock, struct { Context *renderer.Context ID string Title string @@ -38,8 +37,4 @@ func (r *sgmlRenderer) renderLiteralBlock(ctx *renderer.Context, b *types.Delimi Roles: roles, Content: strings.Trim(content, "\n"), }) - if err != nil { - return "", errors.Wrap(err, "unable to render literal block") - } - return result.String(), nil } diff --git a/pkg/renderer/sgml/paragraph.go b/pkg/renderer/sgml/paragraph.go index 78a55d54..2a5bd501 100644 --- a/pkg/renderer/sgml/paragraph.go +++ b/pkg/renderer/sgml/paragraph.go @@ -53,8 +53,7 @@ func (r *sgmlRenderer) renderRegularParagraph(ctx *renderer.Context, p *types.Pa if err != nil { return "", errors.Wrap(err, "unable to render paragraph roles") } - result := &strings.Builder{} - err = r.paragraph.Execute(result, struct { + return r.execute(r.paragraph, struct { Context *renderer.Context ID string Roles string @@ -67,42 +66,29 @@ func (r *sgmlRenderer) renderRegularParagraph(ctx *renderer.Context, p *types.Pa Roles: roles, Content: strings.Trim(string(content), "\n"), }) - if err != nil { - return "", errors.Wrap(err, "unable to render paragraph") - } - return result.String(), nil - } func (r *sgmlRenderer) renderManpageNameParagraph(ctx *renderer.Context, p *types.Paragraph) (string, error) { log.Debug("rendering name section paragraph in manpage...") - result := &strings.Builder{} - content, err := r.renderElements(ctx, p.Elements) if err != nil { - return "", errors.Wrap(err, "unable to render quote paragraph lines") + return "", errors.Wrap(err, "unable to render manpage 'NAME' paragraph content") } - - err = r.manpageNameParagraph.Execute(result, struct { + return r.execute(r.manpageNameParagraph, struct { Context *renderer.Context Content string }{ Context: ctx, Content: string(content), }) - return result.String(), err } func (r *sgmlRenderer) renderEmbeddedParagraph(ctx *renderer.Context, p *types.Paragraph, class string) (string, error) { - log.Debug("rendering paragraph within a delimited block or a list") - result := &strings.Builder{} - content, err := r.renderElements(ctx, p.Elements) if err != nil { - return "", errors.Wrap(err, "unable to render delimited block paragraph content") + return "", errors.Wrap(err, "unable to render embedded paragraph content") } - - err = r.embeddedParagraph.Execute(result, struct { + return r.execute(r.embeddedParagraph, struct { Context *renderer.Context CheckStyle string Class string @@ -113,7 +99,6 @@ func (r *sgmlRenderer) renderEmbeddedParagraph(ctx *renderer.Context, p *types.P CheckStyle: renderCheckStyle(p.Attributes[types.AttrCheckStyle]), Content: trimSpaces(content), }) - return result.String(), err } // trimSpaces removes heading and trailing spaces on each line of the given content @@ -210,8 +195,12 @@ func (r *sgmlRenderer) renderParagraphElements(ctx *renderer.Context, p *types.P result := buf.String() if lr.hardBreaks { // TODO: move within the call to `render`? linebreak := &strings.Builder{} - if err := r.lineBreak.Execute(linebreak, nil); err != nil { - return "", err + tmpl, err := r.lineBreak() + if err != nil { + return "", errors.Wrap(err, "unable to load line break template") + } + if err := tmpl.Execute(linebreak, nil); err != nil { + return "", errors.Wrap(err, "unable to render line break") } result = strings.ReplaceAll(result, "\n", linebreak.String()+"\n") } diff --git a/pkg/renderer/sgml/passthrough.go b/pkg/renderer/sgml/passthrough.go index cba482e7..1d0b98c7 100644 --- a/pkg/renderer/sgml/passthrough.go +++ b/pkg/renderer/sgml/passthrough.go @@ -1,7 +1,7 @@ package sgml import ( - "html/template" + htmltemplate "html/template" "strings" "github.com/bytesparadise/libasciidoc/pkg/renderer" @@ -26,7 +26,7 @@ func (r *sgmlRenderer) renderInlinePassthrough(ctx *renderer.Context, p *types.I case types.SinglePlusPassthrough: // rendered passthrough content is in an HTML-escaped form buf := &strings.Builder{} - template.HTMLEscape(buf, []byte(renderedContent)) + htmltemplate.HTMLEscape(buf, []byte(renderedContent)) return buf.String(), nil default: return renderedContent, nil diff --git a/pkg/renderer/sgml/preamble.go b/pkg/renderer/sgml/preamble.go index e8c3867a..561dbe52 100644 --- a/pkg/renderer/sgml/preamble.go +++ b/pkg/renderer/sgml/preamble.go @@ -1,8 +1,6 @@ package sgml import ( - "strings" - "github.com/bytesparadise/libasciidoc/pkg/renderer" "github.com/bytesparadise/libasciidoc/pkg/types" "github.com/pkg/errors" @@ -10,7 +8,6 @@ import ( func (r *sgmlRenderer) renderPreamble(ctx *renderer.Context, p *types.Preamble) (string, error) { // log.Debugf("rendering preamble...") - result := &strings.Builder{} // the
    wrapper is only necessary // if the document has a section 0 @@ -22,7 +19,7 @@ func (r *sgmlRenderer) renderPreamble(ctx *renderer.Context, p *types.Preamble) if err != nil { return "", errors.Wrap(err, "error rendering preamble elements") } - err = r.preamble.Execute(result, struct { + return r.execute(r.preamble, struct { Context *renderer.Context Wrapper bool Content string @@ -33,9 +30,4 @@ func (r *sgmlRenderer) renderPreamble(ctx *renderer.Context, p *types.Preamble) Content: string(content), ToC: string(toc), }) - if err != nil { - return "", errors.Wrap(err, "error while rendering preamble") - } - // log.Debugf("rendered preamble: %s", result.Bytes()) - return result.String(), nil } diff --git a/pkg/renderer/sgml/quoted_text.go b/pkg/renderer/sgml/quoted_text.go index f269a0d8..5f5ae9d3 100644 --- a/pkg/renderer/sgml/quoted_text.go +++ b/pkg/renderer/sgml/quoted_text.go @@ -2,7 +2,7 @@ package sgml import ( "strings" - text "text/template" + texttemplate "text/template" "github.com/bytesparadise/libasciidoc/pkg/renderer" "github.com/bytesparadise/libasciidoc/pkg/types" @@ -23,29 +23,32 @@ func (r *sgmlRenderer) renderQuotedText(ctx *renderer.Context, t *types.QuotedTe return "", errors.Wrapf(err, "unable to render text quote") } } - var tmpl *text.Template + roles, err := r.renderElementRoles(ctx, t.Attributes) + if err != nil { + return "", errors.Wrap(err, "unable to render quoted text roles") + } + var tmpl *texttemplate.Template switch t.Kind { case types.SingleQuoteBold, types.DoubleQuoteBold: - tmpl = r.boldText + tmpl, err = r.boldText() case types.SingleQuoteItalic, types.DoubleQuoteItalic: - tmpl = r.italicText + tmpl, err = r.italicText() case types.SingleQuoteMarked, types.DoubleQuoteMarked: - tmpl = r.markedText + tmpl, err = r.markedText() case types.SingleQuoteMonospace, types.DoubleQuoteMonospace: - tmpl = r.monospaceText + tmpl, err = r.monospaceText() case types.SingleQuoteSubscript: - tmpl = r.subscriptText + tmpl, err = r.subscriptText() case types.SingleQuoteSuperscript: - tmpl = r.superscriptText + tmpl, err = r.superscriptText() default: return "", errors.Errorf("unsupported quoted text kind: '%v'", t.Kind) } - roles, err := r.renderElementRoles(ctx, t.Attributes) if err != nil { - return "", errors.Wrap(err, "unable to render quoted text roles") + return "", errors.Wrap(err, "unable to load quoted text template") } result := &strings.Builder{} - err = tmpl.Execute(result, struct { + if err := tmpl.Execute(result, struct { ID string Roles string Attributes types.Attributes @@ -55,10 +58,8 @@ func (r *sgmlRenderer) renderQuotedText(ctx *renderer.Context, t *types.QuotedTe ID: r.renderElementID(t.Attributes), Roles: roles, Content: string(elementsBuffer.String()), - }) - if err != nil { - return "", errors.Wrap(err, "unable to render monospaced quote") + }); err != nil { + return "", errors.Wrap(err, "unable to render quoted text") } - // log.Debugf("rendered bold quote: %s", result.Bytes()) return result.String(), nil } diff --git a/pkg/renderer/sgml/renderer.go b/pkg/renderer/sgml/renderer.go index 120a9de0..373e0a09 100644 --- a/pkg/renderer/sgml/renderer.go +++ b/pkg/renderer/sgml/renderer.go @@ -4,7 +4,7 @@ import ( "fmt" "io" "strings" - text "text/template" + texttemplate "text/template" "github.com/bytesparadise/libasciidoc/pkg/configuration" "github.com/bytesparadise/libasciidoc/pkg/renderer" @@ -32,7 +32,7 @@ func NewRenderer(t Templates) Renderer { r := &sgmlRenderer{ templates: t, // Establish some default function handlers. - functions: text.FuncMap{ + functions: texttemplate.FuncMap{ "escape": EscapeString, "halign": halign, "valign": valign, @@ -121,7 +121,7 @@ func (r *sgmlRenderer) Templates() Templates { return r.templates } -func (r *sgmlRenderer) newTemplate(name string, tmpl string, err error) (*text.Template, error) { +func (r *sgmlRenderer) newTemplate(name string, tmpl string, err error) (*texttemplate.Template, error) { // NB: if the data is missing below, it will be an empty string. if err != nil { return nil, err @@ -129,7 +129,7 @@ func (r *sgmlRenderer) newTemplate(name string, tmpl string, err error) (*text.T if len(tmpl) == 0 { return nil, fmt.Errorf("empty template for '%s'", name) } - t := text.New(name) + t := texttemplate.New(name) t.Funcs(r.functions) if t, err = t.Parse(tmpl); err != nil { log.Errorf("failed to initialize the '%s' template: %v", name, err) @@ -148,11 +148,6 @@ func (r *sgmlRenderer) Render(ctx *renderer.Context, doc *types.Document, output var metadata types.Metadata // arguably this should be a time.Time for use in Go metadata.LastUpdated = ctx.Config.LastUpdated.Format(configuration.LastUpdatedFormat) - err := r.prepareTemplates() - if err != nil { - return metadata, err - } - renderedTitle, exists, err := r.renderDocumentTitle(ctx, doc) if err != nil { return metadata, errors.Wrapf(err, "unable to render full document") @@ -191,7 +186,11 @@ func (r *sgmlRenderer) Render(ctx *renderer.Context, doc *types.Document, output } if ctx.Config.WrapInHTMLBodyElement { log.Debugf("Rendering full document...") - err = r.article.Execute(output, struct { + tmpl, err := r.article() + if err != nil { + return metadata, errors.Wrapf(err, "unable to render full document") + } + err = tmpl.Execute(output, struct { Doctype string Generator string Description string @@ -355,18 +354,13 @@ func (r *sgmlRenderer) renderDocumentHeader(ctx *renderer.Context, header *types if err != nil { return "", err } - output := &strings.Builder{} - err = r.articleHeader.Execute(output, struct { + return r.execute(r.articleHeader, struct { Header string - Details *string // TODO: convert to string (no need to be a pointer) + Details string }{ Header: renderedHeader, Details: documentDetails, }) - if err != nil { - return "", err - } - return output.String(), nil } func (r *sgmlRenderer) renderDocumentHeaderTitle(ctx *renderer.Context, header *types.DocumentHeader) (string, error) { @@ -396,7 +390,11 @@ func (r *sgmlRenderer) renderManpageHeader(ctx *renderer.Context, header *types. return "", err } output := &strings.Builder{} - err = r.manpageHeader.Execute(output, struct { + tmpl, err := r.manpageHeader() + if err != nil { + return "", errors.Wrap(err, "unable to load manpage header template") + } + if err = tmpl.Execute(output, struct { Header string Name string Content string @@ -406,9 +404,8 @@ func (r *sgmlRenderer) renderManpageHeader(ctx *renderer.Context, header *types. Name: renderedName, Content: string(renderedContent), IncludeH1: len(renderedHeader) > 0, - }) - if err != nil { - return "", err + }); err != nil { + return "", errors.Wrap(err, "unable to render manpage header") } return output.String(), nil } diff --git a/pkg/renderer/sgml/section.go b/pkg/renderer/sgml/section.go index fa52b0cf..0a45c365 100644 --- a/pkg/renderer/sgml/section.go +++ b/pkg/renderer/sgml/section.go @@ -25,9 +25,7 @@ func (r *sgmlRenderer) renderSection(ctx *renderer.Context, s *types.Section) (s if err != nil { return "", errors.Wrap(err, "unable to render section roles") } - - result := &strings.Builder{} - err = r.sectionContent.Execute(result, struct { + return r.execute(r.sectionContent, struct { Context *renderer.Context Header string Content string @@ -44,30 +42,24 @@ func (r *sgmlRenderer) renderSection(ctx *renderer.Context, s *types.Section) (s Roles: roles, Content: string(content), }) - if err != nil { - return "", errors.Wrap(err, "error while rendering section") - } - // log.Debugf("rendered section: %s", result.Bytes()) - return result.String(), nil } func (r *sgmlRenderer) renderSectionTitle(ctx *renderer.Context, s *types.Section) (string, error) { - result := &strings.Builder{} renderedContent, err := r.renderInlineElements(ctx, s.Title) if err != nil { - return "", errors.Wrap(err, "error while rendering sectionTitle content") + return "", errors.Wrap(err, "error while rendering section title") } renderedContentStr := strings.TrimSpace(renderedContent) var number string if ctx.SectionNumbering != nil { id, err := s.GetID() if err != nil { - return "", errors.Wrap(err, "error while rendering sectionTitle content") + return "", errors.Wrap(err, "error while rendering section title") } log.Debugf("number for section '%s': '%s'", id, number) number = ctx.SectionNumbering[id] } - err = r.sectionTitle.Execute(result, struct { + return r.execute(r.sectionTitle, struct { Level int LevelPlusOne int ID string @@ -80,9 +72,4 @@ func (r *sgmlRenderer) renderSectionTitle(ctx *renderer.Context, s *types.Sectio Number: number, Content: renderedContentStr, }) - if err != nil { - return "", errors.Wrapf(err, "error while rendering sectionTitle") - } - // log.Debugf("rendered sectionTitle: %s", result.Bytes()) - return string(result.String()), nil } diff --git a/pkg/renderer/sgml/sgml_renderer.go b/pkg/renderer/sgml/sgml_renderer.go index 54a4e0b6..922a3f45 100644 --- a/pkg/renderer/sgml/sgml_renderer.go +++ b/pkg/renderer/sgml/sgml_renderer.go @@ -1,177 +1,865 @@ package sgml import ( + "strings" "sync" - text "text/template" + texttemplate "text/template" + + "github.com/pkg/errors" ) -// sgmlRenderer a generic renderer for all SGML backends type sgmlRenderer struct { - functions text.FuncMap - templates Templates - prepareOnce sync.Once - - // Processed templates - admonitionBlock *text.Template - admonitionParagraph *text.Template - article *text.Template - articleHeader *text.Template - blankLine *text.Template - blockImage *text.Template - boldText *text.Template - calloutList *text.Template - calloutListItem *text.Template - calloutRef *text.Template - embeddedParagraph *text.Template - documentDetails *text.Template - documentAuthorDetails *text.Template - externalCrossReference *text.Template - exampleBlock *text.Template - fencedBlock *text.Template - footnote *text.Template - footnoteItem *text.Template - footnoteRef *text.Template - footnoteRefPlain *text.Template - footnotes *text.Template - iconFont *text.Template - iconImage *text.Template - iconText *text.Template - inlineButton *text.Template - inlineIcon *text.Template - inlineImage *text.Template - inlineMenu *text.Template - internalCrossReference *text.Template - invalidFootnote *text.Template - italicText *text.Template - labeledList *text.Template - labeledListItem *text.Template - labeledListHorizontal *text.Template - labeledListHorizontalItem *text.Template - lineBreak *text.Template - link *text.Template - listingBlock *text.Template - literalBlock *text.Template - manpageHeader *text.Template - manpageNameParagraph *text.Template - markdownQuoteBlock *text.Template - markedText *text.Template - monospaceText *text.Template - openBlock *text.Template - orderedList *text.Template - orderedListItem *text.Template - paragraph *text.Template - passthroughBlock *text.Template - preamble *text.Template - qAndAList *text.Template - qAndAListItem *text.Template - quoteBlock *text.Template - quoteParagraph *text.Template - sectionContent *text.Template - sectionTitle *text.Template - sidebarBlock *text.Template - sourceBlock *text.Template - subscriptText *text.Template - superscriptText *text.Template - table *text.Template - tableBody *text.Template - tableCell *text.Template - tableCellBlock *text.Template - tableHeader *text.Template - tableHeaderCell *text.Template - tableFooter *text.Template - tableFooterCell *text.Template - tableRow *text.Template - thematicBreak *text.Template - tocEntry *text.Template - tocRoot *text.Template - tocSection *text.Template - unorderedList *text.Template - unorderedListItem *text.Template - verseBlock *text.Template - verseParagraph *text.Template -} - -func (r *sgmlRenderer) prepareTemplates() error { - tmpls := r.templates - var err error - r.prepareOnce.Do(func() { - r.admonitionBlock, err = r.newTemplate("admonition-block", tmpls.AdmonitionBlock, err) - r.admonitionParagraph, err = r.newTemplate("admonition-paragraph", tmpls.AdmonitionParagraph, err) - r.article, err = r.newTemplate("article", tmpls.Article, err) - r.articleHeader, err = r.newTemplate("article-header", tmpls.ArticleHeader, err) - r.blankLine, err = r.newTemplate("blank-line", tmpls.BlankLine, err) - r.blockImage, err = r.newTemplate("block-image", tmpls.BlockImage, err) - r.boldText, err = r.newTemplate("bold-text", tmpls.BoldText, err) - r.calloutList, err = r.newTemplate("callout-list", tmpls.CalloutList, err) - r.calloutListItem, err = r.newTemplate("callout-list-item", tmpls.CalloutListItem, err) - r.calloutRef, err = r.newTemplate("callout-ref", tmpls.CalloutRef, err) - r.documentDetails, err = r.newTemplate("document-details", tmpls.DocumentDetails, err) - r.documentAuthorDetails, err = r.newTemplate("document-author-details", tmpls.DocumentAuthorDetails, err) - r.embeddedParagraph, err = r.newTemplate("embedded-paragraph", tmpls.EmbeddedParagraph, err) - r.exampleBlock, err = r.newTemplate("example-block", tmpls.ExampleBlock, err) - r.externalCrossReference, err = r.newTemplate("external-xref", tmpls.ExternalCrossReference, err) - r.fencedBlock, err = r.newTemplate("fenced-block", tmpls.FencedBlock, err) - r.footnote, err = r.newTemplate("footnote", tmpls.Footnote, err) - r.footnoteItem, err = r.newTemplate("footnote-item", tmpls.FootnoteItem, err) - r.footnoteRef, err = r.newTemplate("footnote-ref", tmpls.FootnoteRef, err) - r.footnoteRefPlain, err = r.newTemplate("footnote-ref-plain", tmpls.FootnoteRefPlain, err) - r.footnotes, err = r.newTemplate("footnotes", tmpls.Footnotes, err) - r.iconFont, err = r.newTemplate("icon-font", tmpls.IconFont, err) - r.iconImage, err = r.newTemplate("icon-image", tmpls.IconImage, err) - r.iconText, err = r.newTemplate("icon-text", tmpls.IconText, err) - r.inlineButton, err = r.newTemplate("inline-button", tmpls.InlineButton, err) - r.inlineIcon, err = r.newTemplate("inline-icon", tmpls.InlineIcon, err) - r.inlineImage, err = r.newTemplate("inline-image", tmpls.InlineImage, err) - r.inlineMenu, err = r.newTemplate("inline-menu", tmpls.InlineMenu, err) - r.internalCrossReference, err = r.newTemplate("internal-xref", tmpls.InternalCrossReference, err) - r.invalidFootnote, err = r.newTemplate("invalid-footnote", tmpls.InvalidFootnote, err) - r.italicText, err = r.newTemplate("italic-text", tmpls.ItalicText, err) - r.labeledList, err = r.newTemplate("labeled-list", tmpls.LabeledList, err) - r.labeledListItem, err = r.newTemplate("labeled-list-item", tmpls.LabeledListItem, err) - r.labeledListHorizontal, err = r.newTemplate("labeled-list-horizontal", tmpls.LabeledListHorizontal, err) - r.labeledListHorizontalItem, err = r.newTemplate("labeled-list-horizontal-item", tmpls.LabeledListHorizontalItem, err) - r.lineBreak, err = r.newTemplate("line-break", tmpls.LineBreak, err) - r.link, err = r.newTemplate("link", tmpls.Link, err) - r.listingBlock, err = r.newTemplate("listing", tmpls.ListingBlock, err) - r.literalBlock, err = r.newTemplate("literal-block", tmpls.LiteralBlock, err) - r.manpageHeader, err = r.newTemplate("manpage-header", tmpls.ManpageHeader, err) - r.manpageNameParagraph, err = r.newTemplate("manpage-name-paragraph", tmpls.ManpageNameParagraph, err) - r.markdownQuoteBlock, err = r.newTemplate("markdown-quote-block", tmpls.MarkdownQuoteBlock, err) - r.markedText, err = r.newTemplate("marked-text", tmpls.MarkedText, err) - r.monospaceText, err = r.newTemplate("monospace-text", tmpls.MonospaceText, err) - r.openBlock, err = r.newTemplate("open-block", tmpls.OpenBlock, err) - r.orderedList, err = r.newTemplate("ordered-list", tmpls.OrderedList, err) - r.orderedListItem, err = r.newTemplate("ordered-list-item", tmpls.OrderedListElement, err) - r.paragraph, err = r.newTemplate("paragraph", tmpls.Paragraph, err) - r.passthroughBlock, err = r.newTemplate("passthrough", tmpls.PassthroughBlock, err) - r.preamble, err = r.newTemplate("preamble", tmpls.Preamble, err) - r.qAndAList, err = r.newTemplate("qanda-list", tmpls.QAndAList, err) - r.qAndAListItem, err = r.newTemplate("qanda-list-item", tmpls.QAndAListItem, err) - r.quoteBlock, err = r.newTemplate("quote-block", tmpls.QuoteBlock, err) - r.quoteParagraph, err = r.newTemplate("quote-paragraph", tmpls.QuoteParagraph, err) - r.sectionContent, err = r.newTemplate("section-content", tmpls.SectionContent, err) - r.sectionTitle, err = r.newTemplate("section-header", tmpls.SectionHeader, err) - r.sidebarBlock, err = r.newTemplate("sidebar-block", tmpls.SidebarBlock, err) - r.sourceBlock, err = r.newTemplate("source-block", tmpls.SourceBlock, err) - r.subscriptText, err = r.newTemplate("subscript", tmpls.SubscriptText, err) - r.superscriptText, err = r.newTemplate("superscript", tmpls.SuperscriptText, err) - r.table, err = r.newTemplate("table", tmpls.Table, err) - r.tableBody, err = r.newTemplate("table-body", tmpls.TableBody, err) - r.tableCell, err = r.newTemplate("table-cell", tmpls.TableCell, err) - r.tableCellBlock, err = r.newTemplate("table-cell-block", tmpls.TableCellBlock, err) - r.tableHeader, err = r.newTemplate("table-header", tmpls.TableHeader, err) - r.tableHeaderCell, err = r.newTemplate("table-header-cell", tmpls.TableHeaderCell, err) - r.tableFooter, err = r.newTemplate("table-header", tmpls.TableFooter, err) - r.tableFooterCell, err = r.newTemplate("table-header-cell", tmpls.TableFooterCell, err) - r.tableRow, err = r.newTemplate("table-row", tmpls.TableRow, err) - r.thematicBreak, err = r.newTemplate("thematic-break", tmpls.ThematicBreak, err) - r.tocEntry, err = r.newTemplate("toc-entry", tmpls.TocEntry, err) - r.tocRoot, err = r.newTemplate("toc-root", tmpls.TocRoot, err) - r.tocSection, err = r.newTemplate("toc-section", tmpls.TocSection, err) - r.unorderedList, err = r.newTemplate("unordered-list", tmpls.UnorderedList, err) - r.unorderedListItem, err = r.newTemplate("unordered-list-item", tmpls.UnorderedListItem, err) - r.verseBlock, err = r.newTemplate("verse", tmpls.VerseBlock, err) - r.verseParagraph, err = r.newTemplate("verse-paragraph", tmpls.VerseParagraph, err) - }) - return err + templates Templates + functions texttemplate.FuncMap + + admonitionBlockOnce sync.Once + admonitionBlockTmpl *texttemplate.Template + + admonitionParagraphOnce sync.Once + admonitionParagraphTmpl *texttemplate.Template + + articleOnce sync.Once + articleTmpl *texttemplate.Template + + articleHeaderOnce sync.Once + articleHeaderTmpl *texttemplate.Template + + blockImageOnce sync.Once + blockImageTmpl *texttemplate.Template + + boldTextOnce sync.Once + boldTextTmpl *texttemplate.Template + + calloutListOnce sync.Once + calloutListTmpl *texttemplate.Template + + calloutListElementOnce sync.Once + calloutListElementTmpl *texttemplate.Template + + calloutRefOnce sync.Once + calloutRefTmpl *texttemplate.Template + + embeddedParagraphOnce sync.Once + embeddedParagraphTmpl *texttemplate.Template + + documentDetailsOnce sync.Once + documentDetailsTmpl *texttemplate.Template + + documentAuthorDetailsOnce sync.Once + documentAuthorDetailsTmpl *texttemplate.Template + + exampleBlockOnce sync.Once + exampleBlockTmpl *texttemplate.Template + + externalCrossReferenceOnce sync.Once + externalCrossReferenceTmpl *texttemplate.Template + + fencedBlockOnce sync.Once + fencedBlockTmpl *texttemplate.Template + + footnoteOnce sync.Once + footnoteTmpl *texttemplate.Template + + footnoteElementOnce sync.Once + footnoteElementTmpl *texttemplate.Template + + footnoteRefOnce sync.Once + footnoteRefTmpl *texttemplate.Template + + footnoteRefPlainOnce sync.Once + footnoteRefPlainTmpl *texttemplate.Template + + footnotesOnce sync.Once + footnotesTmpl *texttemplate.Template + + iconFontOnce sync.Once + iconFontTmpl *texttemplate.Template + + iconImageOnce sync.Once + iconImageTmpl *texttemplate.Template + + iconTextOnce sync.Once + iconTextTmpl *texttemplate.Template + + inlineButtonOnce sync.Once + inlineButtonTmpl *texttemplate.Template + + inlineIconOnce sync.Once + inlineIconTmpl *texttemplate.Template + + inlineImageOnce sync.Once + inlineImageTmpl *texttemplate.Template + + inlineMenuOnce sync.Once + inlineMenuTmpl *texttemplate.Template + + internalCrossReferenceOnce sync.Once + internalCrossReferenceTmpl *texttemplate.Template + + invalidFootnoteOnce sync.Once + invalidFootnoteTmpl *texttemplate.Template + + italicTextOnce sync.Once + italicTextTmpl *texttemplate.Template + + labeledListOnce sync.Once + labeledListTmpl *texttemplate.Template + + labeledListElementOnce sync.Once + labeledListElementTmpl *texttemplate.Template + + labeledListHorizontalOnce sync.Once + labeledListHorizontalTmpl *texttemplate.Template + + labeledListHorizontalElementOnce sync.Once + labeledListHorizontalElementTmpl *texttemplate.Template + + lineBreakOnce sync.Once + lineBreakTmpl *texttemplate.Template + + linkOnce sync.Once + linkTmpl *texttemplate.Template + + listingBlockOnce sync.Once + listingBlockTmpl *texttemplate.Template + + literalBlockOnce sync.Once + literalBlockTmpl *texttemplate.Template + + manpageHeaderOnce sync.Once + manpageHeaderTmpl *texttemplate.Template + + manpageNameParagraphOnce sync.Once + manpageNameParagraphTmpl *texttemplate.Template + + markdownQuoteBlockOnce sync.Once + markdownQuoteBlockTmpl *texttemplate.Template + + markedTextOnce sync.Once + markedTextTmpl *texttemplate.Template + + monospaceTextOnce sync.Once + monospaceTextTmpl *texttemplate.Template + + openBlockOnce sync.Once + openBlockTmpl *texttemplate.Template + + orderedListOnce sync.Once + orderedListTmpl *texttemplate.Template + + orderedListElementOnce sync.Once + orderedListElementTmpl *texttemplate.Template + + paragraphOnce sync.Once + paragraphTmpl *texttemplate.Template + + passthroughBlockOnce sync.Once + passthroughBlockTmpl *texttemplate.Template + + preambleOnce sync.Once + preambleTmpl *texttemplate.Template + + qAndAListOnce sync.Once + qAndAListTmpl *texttemplate.Template + + qAndAListElementOnce sync.Once + qAndAListElementTmpl *texttemplate.Template + + quoteBlockOnce sync.Once + quoteBlockTmpl *texttemplate.Template + + quoteParagraphOnce sync.Once + quoteParagraphTmpl *texttemplate.Template + + sectionContentOnce sync.Once + sectionContentTmpl *texttemplate.Template + + sectionTitleOnce sync.Once + sectionTitleTmpl *texttemplate.Template + + sidebarBlockOnce sync.Once + sidebarBlockTmpl *texttemplate.Template + + sourceBlockOnce sync.Once + sourceBlockTmpl *texttemplate.Template + + subscriptTextOnce sync.Once + subscriptTextTmpl *texttemplate.Template + + superscriptTextOnce sync.Once + superscriptTextTmpl *texttemplate.Template + + tableOnce sync.Once + tableTmpl *texttemplate.Template + + tableBodyOnce sync.Once + tableBodyTmpl *texttemplate.Template + + tableCellOnce sync.Once + tableCellTmpl *texttemplate.Template + + tableCellBlockOnce sync.Once + tableCellBlockTmpl *texttemplate.Template + + tableHeaderOnce sync.Once + tableHeaderTmpl *texttemplate.Template + + tableHeaderCellOnce sync.Once + tableHeaderCellTmpl *texttemplate.Template + + tableFooterOnce sync.Once + tableFooterTmpl *texttemplate.Template + + tableFooterCellOnce sync.Once + tableFooterCellTmpl *texttemplate.Template + + tableRowOnce sync.Once + tableRowTmpl *texttemplate.Template + + thematicBreakOnce sync.Once + thematicBreakTmpl *texttemplate.Template + + tocEntryOnce sync.Once + tocEntryTmpl *texttemplate.Template + + tocRootOnce sync.Once + tocRootTmpl *texttemplate.Template + + tocSectionOnce sync.Once + tocSectionTmpl *texttemplate.Template + + unorderedListOnce sync.Once + unorderedListTmpl *texttemplate.Template + + unorderedListElementOnce sync.Once + unorderedListElementTmpl *texttemplate.Template + + verseBlockOnce sync.Once + verseBlockTmpl *texttemplate.Template + + verseParagraphOnce sync.Once + verseParagraphTmpl *texttemplate.Template +} + +type template func() (*texttemplate.Template, error) + +func (s *sgmlRenderer) execute(loadTmpl template, data interface{}) (string, error) { + tmpl, err := loadTmpl() + result := &strings.Builder{} + if err != nil { + return "", errors.Wrap(err, "unable to load template") + } + if err := tmpl.Execute(result, data); err != nil { + return "", err + } + return result.String(), nil + +} + +func (r *sgmlRenderer) admonitionBlock() (*texttemplate.Template, error) { + var err error + r.admonitionBlockOnce.Do(func() { + r.admonitionBlockTmpl, err = r.newTemplate("AdmonitionBlock", r.templates.AdmonitionBlock, err) + }) + return r.admonitionBlockTmpl, err +} + +func (r *sgmlRenderer) admonitionParagraph() (*texttemplate.Template, error) { + var err error + r.admonitionParagraphOnce.Do(func() { + r.admonitionParagraphTmpl, err = r.newTemplate("AdmonitionParagraph", r.templates.AdmonitionParagraph, err) + }) + return r.admonitionParagraphTmpl, err +} + +func (r *sgmlRenderer) article() (*texttemplate.Template, error) { + var err error + r.articleOnce.Do(func() { + r.articleTmpl, err = r.newTemplate("Article", r.templates.Article, err) + }) + return r.articleTmpl, err +} + +func (r *sgmlRenderer) articleHeader() (*texttemplate.Template, error) { + var err error + r.articleHeaderOnce.Do(func() { + r.articleHeaderTmpl, err = r.newTemplate("ArticleHeader", r.templates.ArticleHeader, err) + }) + return r.articleHeaderTmpl, err +} + +func (r *sgmlRenderer) blockImage() (*texttemplate.Template, error) { + var err error + r.blockImageOnce.Do(func() { + r.blockImageTmpl, err = r.newTemplate("BlockImage", r.templates.BlockImage, err) + }) + return r.blockImageTmpl, err +} + +func (r *sgmlRenderer) boldText() (*texttemplate.Template, error) { + var err error + r.boldTextOnce.Do(func() { + r.boldTextTmpl, err = r.newTemplate("BoldText", r.templates.BoldText, err) + }) + return r.boldTextTmpl, err +} + +func (r *sgmlRenderer) calloutList() (*texttemplate.Template, error) { + var err error + r.calloutListOnce.Do(func() { + r.calloutListTmpl, err = r.newTemplate("CalloutList", r.templates.CalloutList, err) + }) + return r.calloutListTmpl, err +} + +func (r *sgmlRenderer) calloutListElement() (*texttemplate.Template, error) { + var err error + r.calloutListElementOnce.Do(func() { + r.calloutListElementTmpl, err = r.newTemplate("CalloutListElement", r.templates.CalloutListElement, err) + }) + return r.calloutListElementTmpl, err +} + +func (r *sgmlRenderer) calloutRef() (*texttemplate.Template, error) { + var err error + r.calloutRefOnce.Do(func() { + r.calloutRefTmpl, err = r.newTemplate("CalloutRef", r.templates.CalloutRef, err) + }) + return r.calloutRefTmpl, err +} + +func (r *sgmlRenderer) embeddedParagraph() (*texttemplate.Template, error) { + var err error + r.embeddedParagraphOnce.Do(func() { + r.embeddedParagraphTmpl, err = r.newTemplate("EmbeddedParagraph", r.templates.EmbeddedParagraph, err) + }) + return r.embeddedParagraphTmpl, err +} + +func (r *sgmlRenderer) documentDetails() (*texttemplate.Template, error) { + var err error + r.documentDetailsOnce.Do(func() { + r.documentDetailsTmpl, err = r.newTemplate("DocumentDetails", r.templates.DocumentDetails, err) + }) + return r.documentDetailsTmpl, err +} + +func (r *sgmlRenderer) documentAuthorDetails() (*texttemplate.Template, error) { + var err error + r.documentAuthorDetailsOnce.Do(func() { + r.documentAuthorDetailsTmpl, err = r.newTemplate("DocumentAuthorDetails", r.templates.DocumentAuthorDetails, err) + }) + return r.documentAuthorDetailsTmpl, err +} + +func (r *sgmlRenderer) exampleBlock() (*texttemplate.Template, error) { + var err error + r.exampleBlockOnce.Do(func() { + r.exampleBlockTmpl, err = r.newTemplate("ExampleBlock", r.templates.ExampleBlock, err) + }) + return r.exampleBlockTmpl, err +} + +func (r *sgmlRenderer) externalCrossReference() (*texttemplate.Template, error) { + var err error + r.externalCrossReferenceOnce.Do(func() { + r.externalCrossReferenceTmpl, err = r.newTemplate("ExternalCrossReference", r.templates.ExternalCrossReference, err) + }) + return r.externalCrossReferenceTmpl, err +} + +func (r *sgmlRenderer) fencedBlock() (*texttemplate.Template, error) { + var err error + r.fencedBlockOnce.Do(func() { + r.fencedBlockTmpl, err = r.newTemplate("FencedBlock", r.templates.FencedBlock, err) + }) + return r.fencedBlockTmpl, err +} + +func (r *sgmlRenderer) footnote() (*texttemplate.Template, error) { + var err error + r.footnoteOnce.Do(func() { + r.footnoteTmpl, err = r.newTemplate("Footnote", r.templates.Footnote, err) + }) + return r.footnoteTmpl, err +} + +func (r *sgmlRenderer) footnoteElement() (*texttemplate.Template, error) { + var err error + r.footnoteElementOnce.Do(func() { + r.footnoteElementTmpl, err = r.newTemplate("FootnoteElement", r.templates.FootnoteElement, err) + }) + return r.footnoteElementTmpl, err +} + +func (r *sgmlRenderer) footnoteRef() (*texttemplate.Template, error) { + var err error + r.footnoteRefOnce.Do(func() { + r.footnoteRefTmpl, err = r.newTemplate("FootnoteRef", r.templates.FootnoteRef, err) + }) + return r.footnoteRefTmpl, err +} + +func (r *sgmlRenderer) footnoteRefPlain() (*texttemplate.Template, error) { + var err error + r.footnoteRefPlainOnce.Do(func() { + r.footnoteRefPlainTmpl, err = r.newTemplate("FootnoteRefPlain", r.templates.FootnoteRefPlain, err) + }) + return r.footnoteRefPlainTmpl, err +} + +func (r *sgmlRenderer) footnotes() (*texttemplate.Template, error) { + var err error + r.footnotesOnce.Do(func() { + r.footnotesTmpl, err = r.newTemplate("Footnotes", r.templates.Footnotes, err) + }) + return r.footnotesTmpl, err +} + +func (r *sgmlRenderer) iconFont() (*texttemplate.Template, error) { + var err error + r.iconFontOnce.Do(func() { + r.iconFontTmpl, err = r.newTemplate("IconFont", r.templates.IconFont, err) + }) + return r.iconFontTmpl, err +} + +func (r *sgmlRenderer) iconImage() (*texttemplate.Template, error) { + var err error + r.iconImageOnce.Do(func() { + r.iconImageTmpl, err = r.newTemplate("IconImage", r.templates.IconImage, err) + }) + return r.iconImageTmpl, err +} + +func (r *sgmlRenderer) iconText() (*texttemplate.Template, error) { + var err error + r.iconTextOnce.Do(func() { + r.iconTextTmpl, err = r.newTemplate("IconText", r.templates.IconText, err) + }) + return r.iconTextTmpl, err +} + +func (r *sgmlRenderer) inlineButton() (*texttemplate.Template, error) { + var err error + r.inlineButtonOnce.Do(func() { + r.inlineButtonTmpl, err = r.newTemplate("InlineButton", r.templates.InlineButton, err) + }) + return r.inlineButtonTmpl, err +} + +func (r *sgmlRenderer) inlineIcon() (*texttemplate.Template, error) { + var err error + r.inlineIconOnce.Do(func() { + r.inlineIconTmpl, err = r.newTemplate("InlineIcon", r.templates.InlineIcon, err) + }) + return r.inlineIconTmpl, err +} + +func (r *sgmlRenderer) inlineImage() (*texttemplate.Template, error) { + var err error + r.inlineImageOnce.Do(func() { + r.inlineImageTmpl, err = r.newTemplate("InlineImage", r.templates.InlineImage, err) + }) + return r.inlineImageTmpl, err +} + +func (r *sgmlRenderer) inlineMenu() (*texttemplate.Template, error) { + var err error + r.inlineMenuOnce.Do(func() { + r.inlineMenuTmpl, err = r.newTemplate("InlineMenu", r.templates.InlineMenu, err) + }) + return r.inlineMenuTmpl, err +} + +func (r *sgmlRenderer) internalCrossReference() (*texttemplate.Template, error) { + var err error + r.internalCrossReferenceOnce.Do(func() { + r.internalCrossReferenceTmpl, err = r.newTemplate("InternalCrossReference", r.templates.InternalCrossReference, err) + }) + return r.internalCrossReferenceTmpl, err +} + +func (r *sgmlRenderer) invalidFootnote() (*texttemplate.Template, error) { + var err error + r.invalidFootnoteOnce.Do(func() { + r.invalidFootnoteTmpl, err = r.newTemplate("InvalidFootnote", r.templates.InvalidFootnote, err) + }) + return r.invalidFootnoteTmpl, err +} + +func (r *sgmlRenderer) italicText() (*texttemplate.Template, error) { + var err error + r.italicTextOnce.Do(func() { + r.italicTextTmpl, err = r.newTemplate("ItalicText", r.templates.ItalicText, err) + }) + return r.italicTextTmpl, err +} + +func (r *sgmlRenderer) labeledList() (*texttemplate.Template, error) { + var err error + r.labeledListOnce.Do(func() { + r.labeledListTmpl, err = r.newTemplate("LabeledList", r.templates.LabeledList, err) + }) + return r.labeledListTmpl, err +} + +func (r *sgmlRenderer) labeledListElement() (*texttemplate.Template, error) { + var err error + r.labeledListElementOnce.Do(func() { + r.labeledListElementTmpl, err = r.newTemplate("LabeledListElement", r.templates.LabeledListElement, err) + }) + return r.labeledListElementTmpl, err +} + +func (r *sgmlRenderer) labeledListHorizontal() (*texttemplate.Template, error) { + var err error + r.labeledListHorizontalOnce.Do(func() { + r.labeledListHorizontalTmpl, err = r.newTemplate("LabeledListHorizontal", r.templates.LabeledListHorizontal, err) + }) + return r.labeledListHorizontalTmpl, err +} + +func (r *sgmlRenderer) labeledListHorizontalElement() (*texttemplate.Template, error) { + var err error + r.labeledListHorizontalElementOnce.Do(func() { + r.labeledListHorizontalElementTmpl, err = r.newTemplate("LabeledListHorizontalElement", r.templates.LabeledListHorizontalElement, err) + }) + return r.labeledListHorizontalElementTmpl, err +} + +func (r *sgmlRenderer) lineBreak() (*texttemplate.Template, error) { + var err error + r.lineBreakOnce.Do(func() { + r.lineBreakTmpl, err = r.newTemplate("LineBreak", r.templates.LineBreak, err) + }) + return r.lineBreakTmpl, err +} + +func (r *sgmlRenderer) link() (*texttemplate.Template, error) { + var err error + r.linkOnce.Do(func() { + r.linkTmpl, err = r.newTemplate("Link", r.templates.Link, err) + }) + return r.linkTmpl, err +} + +func (r *sgmlRenderer) listingBlock() (*texttemplate.Template, error) { + var err error + r.listingBlockOnce.Do(func() { + r.listingBlockTmpl, err = r.newTemplate("ListingBlock", r.templates.ListingBlock, err) + }) + return r.listingBlockTmpl, err +} + +func (r *sgmlRenderer) literalBlock() (*texttemplate.Template, error) { + var err error + r.literalBlockOnce.Do(func() { + r.literalBlockTmpl, err = r.newTemplate("LiteralBlock", r.templates.LiteralBlock, err) + }) + return r.literalBlockTmpl, err +} + +func (r *sgmlRenderer) manpageHeader() (*texttemplate.Template, error) { + var err error + r.manpageHeaderOnce.Do(func() { + r.manpageHeaderTmpl, err = r.newTemplate("ManpageHeader", r.templates.ManpageHeader, err) + }) + return r.manpageHeaderTmpl, err +} + +func (r *sgmlRenderer) manpageNameParagraph() (*texttemplate.Template, error) { + var err error + r.manpageNameParagraphOnce.Do(func() { + r.manpageNameParagraphTmpl, err = r.newTemplate("ManpageNameParagraph", r.templates.ManpageNameParagraph, err) + }) + return r.manpageNameParagraphTmpl, err +} + +func (r *sgmlRenderer) markdownQuoteBlock() (*texttemplate.Template, error) { + var err error + r.markdownQuoteBlockOnce.Do(func() { + r.markdownQuoteBlockTmpl, err = r.newTemplate("MarkdownQuoteBlock", r.templates.MarkdownQuoteBlock, err) + }) + return r.markdownQuoteBlockTmpl, err +} + +func (r *sgmlRenderer) markedText() (*texttemplate.Template, error) { + var err error + r.markedTextOnce.Do(func() { + r.markedTextTmpl, err = r.newTemplate("MarkedText", r.templates.MarkedText, err) + }) + return r.markedTextTmpl, err +} + +func (r *sgmlRenderer) monospaceText() (*texttemplate.Template, error) { + var err error + r.monospaceTextOnce.Do(func() { + r.monospaceTextTmpl, err = r.newTemplate("MonospaceText", r.templates.MonospaceText, err) + }) + return r.monospaceTextTmpl, err +} + +func (r *sgmlRenderer) openBlock() (*texttemplate.Template, error) { + var err error + r.openBlockOnce.Do(func() { + r.openBlockTmpl, err = r.newTemplate("OpenBlock", r.templates.OpenBlock, err) + }) + return r.openBlockTmpl, err +} + +func (r *sgmlRenderer) orderedList() (*texttemplate.Template, error) { + var err error + r.orderedListOnce.Do(func() { + r.orderedListTmpl, err = r.newTemplate("OrderedList", r.templates.OrderedList, err) + }) + return r.orderedListTmpl, err +} + +func (r *sgmlRenderer) orderedListElement() (*texttemplate.Template, error) { + var err error + r.orderedListElementOnce.Do(func() { + r.orderedListElementTmpl, err = r.newTemplate("OrderedListElement", r.templates.OrderedListElement, err) + }) + return r.orderedListElementTmpl, err +} + +func (r *sgmlRenderer) paragraph() (*texttemplate.Template, error) { + var err error + r.paragraphOnce.Do(func() { + r.paragraphTmpl, err = r.newTemplate("Paragraph", r.templates.Paragraph, err) + }) + return r.paragraphTmpl, err +} + +func (r *sgmlRenderer) passthroughBlock() (*texttemplate.Template, error) { + var err error + r.passthroughBlockOnce.Do(func() { + r.passthroughBlockTmpl, err = r.newTemplate("PassthroughBlock", r.templates.PassthroughBlock, err) + }) + return r.passthroughBlockTmpl, err +} + +func (r *sgmlRenderer) preamble() (*texttemplate.Template, error) { + var err error + r.preambleOnce.Do(func() { + r.preambleTmpl, err = r.newTemplate("Preamble", r.templates.Preamble, err) + }) + return r.preambleTmpl, err +} + +func (r *sgmlRenderer) qAndAList() (*texttemplate.Template, error) { + var err error + r.qAndAListOnce.Do(func() { + r.qAndAListTmpl, err = r.newTemplate("QAndAList", r.templates.QAndAList, err) + }) + return r.qAndAListTmpl, err +} + +func (r *sgmlRenderer) qAndAListElement() (*texttemplate.Template, error) { + var err error + r.qAndAListElementOnce.Do(func() { + r.qAndAListElementTmpl, err = r.newTemplate("QAndAListElement", r.templates.QAndAListElement, err) + }) + return r.qAndAListElementTmpl, err +} + +func (r *sgmlRenderer) quoteBlock() (*texttemplate.Template, error) { + var err error + r.quoteBlockOnce.Do(func() { + r.quoteBlockTmpl, err = r.newTemplate("QuoteBlock", r.templates.QuoteBlock, err) + }) + return r.quoteBlockTmpl, err +} + +func (r *sgmlRenderer) quoteParagraph() (*texttemplate.Template, error) { + var err error + r.quoteParagraphOnce.Do(func() { + r.quoteParagraphTmpl, err = r.newTemplate("QuoteParagraph", r.templates.QuoteParagraph, err) + }) + return r.quoteParagraphTmpl, err +} + +func (r *sgmlRenderer) sectionContent() (*texttemplate.Template, error) { + var err error + r.sectionContentOnce.Do(func() { + r.sectionContentTmpl, err = r.newTemplate("SectionContent", r.templates.SectionContent, err) + }) + return r.sectionContentTmpl, err +} + +func (r *sgmlRenderer) sectionTitle() (*texttemplate.Template, error) { + var err error + r.sectionTitleOnce.Do(func() { + r.sectionTitleTmpl, err = r.newTemplate("SectionTitle", r.templates.SectionTitle, err) + }) + return r.sectionTitleTmpl, err +} + +func (r *sgmlRenderer) sidebarBlock() (*texttemplate.Template, error) { + var err error + r.sidebarBlockOnce.Do(func() { + r.sidebarBlockTmpl, err = r.newTemplate("SidebarBlock", r.templates.SidebarBlock, err) + }) + return r.sidebarBlockTmpl, err +} + +func (r *sgmlRenderer) sourceBlock() (*texttemplate.Template, error) { + var err error + r.sourceBlockOnce.Do(func() { + r.sourceBlockTmpl, err = r.newTemplate("SourceBlock", r.templates.SourceBlock, err) + }) + return r.sourceBlockTmpl, err +} + +func (r *sgmlRenderer) subscriptText() (*texttemplate.Template, error) { + var err error + r.subscriptTextOnce.Do(func() { + r.subscriptTextTmpl, err = r.newTemplate("SubscriptText", r.templates.SubscriptText, err) + }) + return r.subscriptTextTmpl, err +} + +func (r *sgmlRenderer) superscriptText() (*texttemplate.Template, error) { + var err error + r.superscriptTextOnce.Do(func() { + r.superscriptTextTmpl, err = r.newTemplate("SuperscriptText", r.templates.SuperscriptText, err) + }) + return r.superscriptTextTmpl, err +} + +func (r *sgmlRenderer) table() (*texttemplate.Template, error) { + var err error + r.tableOnce.Do(func() { + r.tableTmpl, err = r.newTemplate("Table", r.templates.Table, err) + }) + return r.tableTmpl, err +} + +func (r *sgmlRenderer) tableBody() (*texttemplate.Template, error) { + var err error + r.tableBodyOnce.Do(func() { + r.tableBodyTmpl, err = r.newTemplate("TableBody", r.templates.TableBody, err) + }) + return r.tableBodyTmpl, err +} + +func (r *sgmlRenderer) tableCell() (*texttemplate.Template, error) { + var err error + r.tableCellOnce.Do(func() { + r.tableCellTmpl, err = r.newTemplate("TableCell", r.templates.TableCell, err) + }) + return r.tableCellTmpl, err +} + +func (r *sgmlRenderer) tableCellBlock() (*texttemplate.Template, error) { + var err error + r.tableCellBlockOnce.Do(func() { + r.tableCellBlockTmpl, err = r.newTemplate("TableCellBlock", r.templates.TableCellBlock, err) + }) + return r.tableCellBlockTmpl, err +} + +func (r *sgmlRenderer) tableHeader() (*texttemplate.Template, error) { + var err error + r.tableHeaderOnce.Do(func() { + r.tableHeaderTmpl, err = r.newTemplate("TableHeader", r.templates.TableHeader, err) + }) + return r.tableHeaderTmpl, err +} + +func (r *sgmlRenderer) tableHeaderCell() (*texttemplate.Template, error) { + var err error + r.tableHeaderCellOnce.Do(func() { + r.tableHeaderCellTmpl, err = r.newTemplate("TableHeaderCell", r.templates.TableHeaderCell, err) + }) + return r.tableHeaderCellTmpl, err +} + +func (r *sgmlRenderer) tableFooter() (*texttemplate.Template, error) { + var err error + r.tableFooterOnce.Do(func() { + r.tableFooterTmpl, err = r.newTemplate("TableFooter", r.templates.TableFooter, err) + }) + return r.tableFooterTmpl, err +} + +func (r *sgmlRenderer) tableFooterCell() (*texttemplate.Template, error) { + var err error + r.tableFooterCellOnce.Do(func() { + r.tableFooterCellTmpl, err = r.newTemplate("TableFooterCell", r.templates.TableFooterCell, err) + }) + return r.tableFooterCellTmpl, err +} + +func (r *sgmlRenderer) tableRow() (*texttemplate.Template, error) { + var err error + r.tableRowOnce.Do(func() { + r.tableRowTmpl, err = r.newTemplate("TableRow", r.templates.TableRow, err) + }) + return r.tableRowTmpl, err +} + +func (r *sgmlRenderer) thematicBreak() (*texttemplate.Template, error) { + var err error + r.thematicBreakOnce.Do(func() { + r.thematicBreakTmpl, err = r.newTemplate("ThematicBreak", r.templates.ThematicBreak, err) + }) + return r.thematicBreakTmpl, err +} + +func (r *sgmlRenderer) tocEntry() (*texttemplate.Template, error) { + var err error + r.tocEntryOnce.Do(func() { + r.tocEntryTmpl, err = r.newTemplate("TocEntry", r.templates.TocEntry, err) + }) + return r.tocEntryTmpl, err +} + +func (r *sgmlRenderer) tocRoot() (*texttemplate.Template, error) { + var err error + r.tocRootOnce.Do(func() { + r.tocRootTmpl, err = r.newTemplate("TocRoot", r.templates.TocRoot, err) + }) + return r.tocRootTmpl, err +} + +func (r *sgmlRenderer) tocSection() (*texttemplate.Template, error) { + var err error + r.tocSectionOnce.Do(func() { + r.tocSectionTmpl, err = r.newTemplate("TocSection", r.templates.TocSection, err) + }) + return r.tocSectionTmpl, err +} + +func (r *sgmlRenderer) unorderedList() (*texttemplate.Template, error) { + var err error + r.unorderedListOnce.Do(func() { + r.unorderedListTmpl, err = r.newTemplate("UnorderedList", r.templates.UnorderedList, err) + }) + return r.unorderedListTmpl, err +} + +func (r *sgmlRenderer) unorderedListElement() (*texttemplate.Template, error) { + var err error + r.unorderedListElementOnce.Do(func() { + r.unorderedListElementTmpl, err = r.newTemplate("UnorderedListElement", r.templates.UnorderedListElement, err) + }) + return r.unorderedListElementTmpl, err +} + +func (r *sgmlRenderer) verseBlock() (*texttemplate.Template, error) { + var err error + r.verseBlockOnce.Do(func() { + r.verseBlockTmpl, err = r.newTemplate("VerseBlock", r.templates.VerseBlock, err) + }) + return r.verseBlockTmpl, err +} + +func (r *sgmlRenderer) verseParagraph() (*texttemplate.Template, error) { + var err error + r.verseParagraphOnce.Do(func() { + r.verseParagraphTmpl, err = r.newTemplate("VerseParagraph", r.templates.VerseParagraph, err) + }) + return r.verseParagraphTmpl, err } diff --git a/pkg/renderer/sgml/table.go b/pkg/renderer/sgml/table.go index caf7e573..7eb7e017 100644 --- a/pkg/renderer/sgml/table.go +++ b/pkg/renderer/sgml/table.go @@ -4,7 +4,6 @@ import ( "fmt" "strconv" "strings" - "text/template" "github.com/bytesparadise/libasciidoc/pkg/renderer" "github.com/bytesparadise/libasciidoc/pkg/types" @@ -13,9 +12,7 @@ import ( ) func (r *sgmlRenderer) renderTable(ctx *renderer.Context, t *types.Table) (string, error) { - result := &strings.Builder{} caption := &strings.Builder{} - number := 0 fit := "stretch" frame := t.Attributes.GetAsStringWithDefault(types.AttrFrame, "all") @@ -92,7 +89,7 @@ func (r *sgmlRenderer) renderTable(ctx *renderer.Context, t *types.Table) (strin if err != nil { return "", errors.Wrap(err, "unable to render table title") } - err = r.table.Execute(result, struct { + return r.execute(r.table, struct { Context *renderer.Context ID string Title string @@ -127,17 +124,12 @@ func (r *sgmlRenderer) renderTable(ctx *renderer.Context, t *types.Table) (strin Body: body, Footer: footer, }) - if err != nil { - return "", errors.Wrap(err, "failed to render table") - } - return result.String(), nil } func (r *sgmlRenderer) renderTableHeader(ctx *renderer.Context, h *types.TableRow, cols []*types.TableColumn) (string, error) { if h == nil { return "", nil } - result := &strings.Builder{} content := &strings.Builder{} col := 0 for _, cell := range h.Cells { @@ -148,12 +140,11 @@ func (r *sgmlRenderer) renderTableHeader(ctx *renderer.Context, h *types.TableRo } content.WriteString(c) } - err := r.tableHeader.Execute(result, struct { + return r.execute(r.tableHeader, struct { Content string }{ Content: content.String(), }) - return result.String(), err } func (r *sgmlRenderer) renderTableHeaderCell(ctx *renderer.Context, c *types.TableCell, col *types.TableColumn) (string, error) { @@ -164,8 +155,7 @@ func (r *sgmlRenderer) renderTableHeaderCell(ctx *renderer.Context, c *types.Tab if err != nil { return "", errors.Wrap(err, "unable to render header cell") } - result := &strings.Builder{} - if err := r.tableHeaderCell.Execute(result, struct { + return r.execute(r.tableHeaderCell, struct { HAlign types.HAlign VAlign types.VAlign Content string @@ -173,10 +163,7 @@ func (r *sgmlRenderer) renderTableHeaderCell(ctx *renderer.Context, c *types.Tab HAlign: col.HAlign, VAlign: col.VAlign, Content: content, - }); err != nil { - return "", errors.Wrap(err, "unable to render header cell") - } - return result.String(), nil + }) } } return "", fmt.Errorf("invalid header content (expected a single paragraph)") @@ -186,18 +173,17 @@ func (r *sgmlRenderer) renderTableFooter(ctx *renderer.Context, f *types.TableRo if f == nil { return "", nil } - result := &strings.Builder{} content := &strings.Builder{} col := 0 for _, cell := range f.Cells { c, err := r.renderTableFooterCell(ctx, cell, cols[col%len(cols)]) col++ if err != nil { - return "", errors.Wrap(err, "unable to render header") + return "", errors.Wrap(err, "unable to render footer") } content.WriteString(c) } - err := r.tableFooter.Execute(result, struct { + return r.execute(r.tableFooter, struct { Context *renderer.Context Content string Cells []*types.TableCell @@ -206,7 +192,6 @@ func (r *sgmlRenderer) renderTableFooter(ctx *renderer.Context, f *types.TableRo Content: content.String(), Cells: f.Cells, }) - return result.String(), err } func (r *sgmlRenderer) renderTableFooterCell(ctx *renderer.Context, c *types.TableCell, col *types.TableColumn) (string, error) { @@ -215,10 +200,9 @@ func (r *sgmlRenderer) renderTableFooterCell(ctx *renderer.Context, c *types.Tab if p, ok := c.Elements[0].(*types.Paragraph); ok { content, err := r.renderInlineElements(ctx, p.Elements) if err != nil { - return "", errors.Wrap(err, "unable to render header cell") + return "", errors.Wrap(err, "unable to render footer cell") } - result := &strings.Builder{} - if err := r.tableFooterCell.Execute(result, struct { + return r.execute(r.tableFooterCell, struct { HAlign types.HAlign VAlign types.VAlign Content string @@ -226,22 +210,13 @@ func (r *sgmlRenderer) renderTableFooterCell(ctx *renderer.Context, c *types.Tab HAlign: col.HAlign, VAlign: col.VAlign, Content: content, - }); err != nil { - return "", errors.Wrap(err, "unable to render footer cell") - } - return result.String(), nil + }) } } return "", fmt.Errorf("invalid footer content (expected a single paragraph)") } func (r *sgmlRenderer) renderTableBody(ctx *renderer.Context, rows []*types.TableRow, columns []*types.TableColumn) (string, error) { - // if log.IsLevelEnabled(log.DebugLevel) { - // log.Debug("rendering table body") - // log.Debugf("columns:\n%s", spew.Sdump(columns)) - // log.Debugf("rows:\n%s", spew.Sdump(rows)) - // } - result := &strings.Builder{} content := &strings.Builder{} for _, row := range rows { c, err := r.renderTableRow(ctx, row, columns) @@ -250,7 +225,7 @@ func (r *sgmlRenderer) renderTableBody(ctx *renderer.Context, rows []*types.Tabl } content.WriteString(c) } - err := r.tableBody.Execute(result, struct { + return r.execute(r.tableBody, struct { Context *renderer.Context Content string Rows []*types.TableRow @@ -261,20 +236,18 @@ func (r *sgmlRenderer) renderTableBody(ctx *renderer.Context, rows []*types.Tabl Rows: rows, Columns: columns, }) - return result.String(), err } func (r *sgmlRenderer) renderTableRow(ctx *renderer.Context, l *types.TableRow, cols []*types.TableColumn) (string, error) { - result := &strings.Builder{} content := &strings.Builder{} for i, cell := range l.Cells { - c, err := r.renderTableCell(ctx, r.tableCell, cell, cols[i]) + c, err := r.renderTableCell(ctx, cell, cols[i]) if err != nil { return "", errors.Wrap(err, "unable to render row") } content.WriteString(c) } - err := r.tableRow.Execute(result, struct { + return r.execute(r.tableRow, struct { Context *renderer.Context Content string Cells []*types.TableCell @@ -283,12 +256,9 @@ func (r *sgmlRenderer) renderTableRow(ctx *renderer.Context, l *types.TableRow, Content: content.String(), Cells: l.Cells, }) - return result.String(), err } -func (r *sgmlRenderer) renderTableCell(ctx *renderer.Context, tmpl *template.Template, cell *types.TableCell, col *types.TableColumn) (string, error) { - result := &strings.Builder{} - // custom rendering of cell elements +func (r *sgmlRenderer) renderTableCell(ctx *renderer.Context, cell *types.TableCell, col *types.TableColumn) (string, error) { buff := &strings.Builder{} for _, element := range cell.Elements { renderedElement, err := r.renderTableCellBlock(ctx, element) @@ -297,10 +267,7 @@ func (r *sgmlRenderer) renderTableCell(ctx *renderer.Context, tmpl *template.Tem } buff.WriteString(renderedElement) } - // if log.IsLevelEnabled(log.DebugLevel) { - // log.Debugf("rendering cell with content '%s' and def %s", content, spew.Sdump(col)) - // } - err := tmpl.Execute(result, struct { + return r.execute(r.tableCell, struct { Context *renderer.Context Content string Cell *types.TableCell @@ -313,14 +280,12 @@ func (r *sgmlRenderer) renderTableCell(ctx *renderer.Context, tmpl *template.Tem HAlign: col.HAlign, VAlign: col.VAlign, }) - return result.String(), err } func (r *sgmlRenderer) renderTableCellBlock(ctx *renderer.Context, element interface{}) (string, error) { switch e := element.(type) { case *types.Paragraph: log.Debug("rendering paragraph within table cell") - result := &strings.Builder{} content, err := r.renderElements(ctx, e.Elements) if err != nil { return "", errors.Wrap(err, "unable to render table cell paragraph content") @@ -329,7 +294,7 @@ func (r *sgmlRenderer) renderTableCellBlock(ctx *renderer.Context, element inter if err != nil { return "", errors.Wrap(err, "unable to render table cell paragraph content") } - if err = r.embeddedParagraph.Execute(result, struct { + result, err := r.execute(r.embeddedParagraph, struct { Context *renderer.Context ID string // TODO: not used in template? Title string // TODO: not used in template? @@ -343,24 +308,21 @@ func (r *sgmlRenderer) renderTableCellBlock(ctx *renderer.Context, element inter Class: "tableblock", CheckStyle: renderCheckStyle(e.Attributes[types.AttrCheckStyle]), Content: string(content), - }); err != nil { + }) + if err != nil { return "", errors.Wrap(err, "unable to render table cell paragraph content") } - return strings.TrimSuffix(result.String(), "\n"), err + return strings.TrimSuffix(result, "\n"), nil default: // Note: Asciidoctor wraps the `
    ` elements within a `
    `, which we also do here for the sake of compatibility renderedElement, err := r.renderElement(ctx, e) if err != nil { return "", errors.Wrap(err, "unable to render table cell") } - result := &strings.Builder{} - if err := r.tableCellBlock.Execute(result, struct { + return r.execute(r.tableCellBlock, struct { Content string }{ Content: renderedElement, - }); err != nil { - return "", errors.Wrap(err, "unable to render cell block") - } - return result.String(), nil + }) } } diff --git a/pkg/renderer/sgml/table_of_contents.go b/pkg/renderer/sgml/table_of_contents.go index 4e4f33fd..86ac4fdc 100644 --- a/pkg/renderer/sgml/table_of_contents.go +++ b/pkg/renderer/sgml/table_of_contents.go @@ -15,13 +15,13 @@ func (r *sgmlRenderer) prerenderTableOfContents(ctx *renderer.Context, toc *type } // if log.IsLevelEnabled(log.DebugLevel) { - // log.Debugf("pre-rendering ToC: %s", spew.Sdump(toc)) + // log.Debugf("pre-rendering table of contents: %s", spew.Sdump(toc)) // } if err := r.prerenderTableOfContentsSections(ctx, toc.Sections); err != nil { return errors.Wrap(err, "error while rendering table of contents") } // if log.IsLevelEnabled(log.DebugLevel) { - // log.Debugf("pre-rendered ToC: %s", spew.Sdump(toc)) + // log.Debugf("pre-rendered table of contents: %s", spew.Sdump(toc)) // } return nil } @@ -29,27 +29,27 @@ func (r *sgmlRenderer) prerenderTableOfContents(ctx *renderer.Context, toc *type func (r *sgmlRenderer) prerenderTableOfContentsSections(ctx *renderer.Context, sections []*types.ToCSection) error { for _, entry := range sections { if err := r.prerenderTableOfContentsEntry(ctx, entry); err != nil { - return errors.Wrap(err, "unable to render ToC section") + return errors.Wrap(err, "unable to render table of contents section") } } - // log.Debugf("retrieved sections for ToC: %+v", sections) + // log.Debugf("retrieved sections for table of contents: %+v", sections) return nil } func (r *sgmlRenderer) prerenderTableOfContentsEntry(ctx *renderer.Context, entry *types.ToCSection) error { if err := r.prerenderTableOfContentsSections(ctx, entry.Children); err != nil { - return errors.Wrap(err, "unable to render ToC entry children") + return errors.Wrap(err, "unable to render table of contents entry children") } if ctx.SectionNumbering != nil { entry.Number = ctx.SectionNumbering[entry.ID] } s, found := ctx.ElementReferences[entry.ID] if !found { - return errors.New("unable to render ToC entry title (missing element reference") + return errors.New("unable to render table of contents entry title (missing element reference") } title, err := r.renderPlainText(ctx, s) if err != nil { - return errors.Wrap(err, "unable to render ToC entry title (missing element reference") + return errors.Wrap(err, "unable to render table of contents entry title (missing element reference") } entry.Title = title return nil @@ -66,7 +66,7 @@ func (r *sgmlRenderer) renderTableOfContents(ctx *renderer.Context, toc *types.T } // if log.IsLevelEnabled(log.DebugLevel) { - // log.Debugf("rendering ToC %s", spew.Sdump(toc)) + // log.Debugf("rendering table of contents %s", spew.Sdump(toc)) // } renderedSections, err := r.renderTableOfContentsSections(ctx, toc.Sections) if err != nil { @@ -76,19 +76,13 @@ func (r *sgmlRenderer) renderTableOfContents(ctx *renderer.Context, toc *types.T // nothing to render (document has no section) return "", nil } - result := &strings.Builder{} - err = r.tocRoot.Execute(result, struct { + return r.execute(r.tocRoot, struct { Title string Sections string }{ Title: title, Sections: renderedSections, }) - if err != nil { - return "", errors.Wrap(err, "error while rendering table of contents") - } - // log.Debugf("rendered ToC: %s", result.Bytes()) - return result.String(), nil } func (r *sgmlRenderer) renderTableOfContentsTitle(ctx *renderer.Context) (string, error) { @@ -112,41 +106,29 @@ func (r *sgmlRenderer) renderTableOfContentsSections(ctx *renderer.Context, sect if len(sections) == 0 { return "", nil } - // if log.IsLevelEnabled(log.DebugLevel) { - // log.Debugf("rendering sections (in toc): '%s'", spew.Sdump(sections)) - // } - - resultBuf := &strings.Builder{} contents := &strings.Builder{} for _, entry := range sections { buf, err := r.renderTableOfContentsEntry(ctx, entry) if err != nil { - return "", errors.Wrap(err, "unable to render ToC section") + return "", errors.Wrap(err, "unable to render table of contents section") } contents.WriteString(buf) } - - err := r.tocSection.Execute(resultBuf, struct { + return r.execute(r.tocSection, struct { Level int Content string }{ Level: sections[0].Level, Content: contents.String(), }) - if err != nil { - return "", errors.Wrap(err, "failed to render document ToC") - } - // log.Debugf("retrieved sections for ToC: %+v", sections) - return resultBuf.String(), nil } func (r *sgmlRenderer) renderTableOfContentsEntry(ctx *renderer.Context, entry *types.ToCSection) (string, error) { content, err := r.renderTableOfContentsSections(ctx, entry.Children) if err != nil { - return "", errors.Wrap(err, "unable to render ToC entry children") + return "", errors.Wrap(err, "unable to render table of contents entry children") } - resultBuf := &strings.Builder{} - err = r.tocEntry.Execute(resultBuf, struct { + return r.execute(r.tocEntry, struct { Number string ID string Title string @@ -157,8 +139,4 @@ func (r *sgmlRenderer) renderTableOfContentsEntry(ctx *renderer.Context, entry * Title: entry.Title, Content: content, }) - if err != nil { - return "", errors.Wrap(err, "failed to render document ToC") - } - return resultBuf.String(), nil } diff --git a/pkg/renderer/sgml/templates.go b/pkg/renderer/sgml/templates.go index 9b4fa84e..3ffc277a 100644 --- a/pkg/renderer/sgml/templates.go +++ b/pkg/renderer/sgml/templates.go @@ -1,82 +1,82 @@ package sgml // Templates represents all the templates we use. +// go:generate type Templates struct { - AdmonitionBlock string - AdmonitionParagraph string - Article string - ArticleHeader string - BlankLine string - BlockImage string - BoldText string - CalloutList string - CalloutListItem string - CalloutRef string - EmbeddedParagraph string - DocumentDetails string - DocumentAuthorDetails string - ExampleBlock string - ExternalCrossReference string - FencedBlock string - Footnote string - FootnoteItem string - FootnoteRef string - FootnoteRefPlain string - Footnotes string - IconFont string - IconImage string - IconText string - InlineButton string - InlineIcon string - InlineImage string - InlineMenu string - InternalCrossReference string - InvalidFootnote string - ItalicText string - LabeledList string - LabeledListItem string - LabeledListHorizontal string - LabeledListHorizontalItem string - LineBreak string - Link string - ListingBlock string - LiteralBlock string - ManpageHeader string - ManpageNameParagraph string - MarkdownQuoteBlock string - MarkedText string - MonospaceText string - OpenBlock string - OrderedList string - OrderedListElement string - Paragraph string - PassthroughBlock string - Preamble string - QAndAList string - QAndAListItem string - QuoteBlock string - QuoteParagraph string - SectionContent string - SectionHeader string - SidebarBlock string - SourceBlock string - SubscriptText string - SuperscriptText string - Table string - TableBody string - TableCell string - TableCellBlock string - TableHeader string - TableHeaderCell string - TableFooter string - TableFooterCell string - TableRow string - ThematicBreak string - TocEntry string - TocRoot string - TocSection string - UnorderedList string - UnorderedListItem string - VerseBlock string - VerseParagraph string + AdmonitionBlock string + AdmonitionParagraph string + Article string + ArticleHeader string + BlockImage string + BoldText string + CalloutList string + CalloutListElement string + CalloutRef string + EmbeddedParagraph string + DocumentDetails string + DocumentAuthorDetails string + ExampleBlock string + ExternalCrossReference string + FencedBlock string + Footnote string + FootnoteElement string + FootnoteRef string + FootnoteRefPlain string + Footnotes string + IconFont string + IconImage string + IconText string + InlineButton string + InlineIcon string + InlineImage string + InlineMenu string + InternalCrossReference string + InvalidFootnote string + ItalicText string + LabeledList string + LabeledListElement string + LabeledListHorizontal string + LabeledListHorizontalElement string + LineBreak string + Link string + ListingBlock string + LiteralBlock string + ManpageHeader string + ManpageNameParagraph string + MarkdownQuoteBlock string + MarkedText string + MonospaceText string + OpenBlock string + OrderedList string + OrderedListElement string + Paragraph string + PassthroughBlock string + Preamble string + QAndAList string + QAndAListElement string + QuoteBlock string + QuoteParagraph string + SectionContent string + SectionTitle string + SidebarBlock string + SourceBlock string + SubscriptText string + SuperscriptText string + Table string + TableBody string + TableCell string + TableCellBlock string + TableHeader string + TableHeaderCell string + TableFooter string + TableFooterCell string + TableRow string + ThematicBreak string + TocEntry string + TocRoot string + TocSection string + UnorderedList string + UnorderedListElement string + VerseBlock string + VerseParagraph string } diff --git a/pkg/renderer/sgml/xhtml5/blank_line.go b/pkg/renderer/sgml/xhtml5/blank_line.go index 577d1756..edd5519d 100644 --- a/pkg/renderer/sgml/xhtml5/blank_line.go +++ b/pkg/renderer/sgml/xhtml5/blank_line.go @@ -2,5 +2,4 @@ package xhtml5 const ( lineBreakTmpl = "
    " - blankLineTmpl = "\n\n" ) diff --git a/pkg/renderer/sgml/xhtml5/templates.go b/pkg/renderer/sgml/xhtml5/templates.go index 3bfe6f04..cb5eb373 100644 --- a/pkg/renderer/sgml/xhtml5/templates.go +++ b/pkg/renderer/sgml/xhtml5/templates.go @@ -18,7 +18,6 @@ func init() { // XHTML5 overrides of HTML5. templates.Article = articleTmpl - templates.BlankLine = blankLineTmpl templates.BlockImage = blockImageTmpl templates.LineBreak = lineBreakTmpl templates.DocumentAuthorDetails = documentAuthorDetailsTmpl @@ -26,7 +25,7 @@ func init() { templates.Footnotes = footnotesTmpl templates.IconImage = iconImageTmpl templates.InlineImage = inlineImageTmpl - templates.LabeledListHorizontalItem = labeledListHorizontalItemTmpl + templates.LabeledListHorizontalElement = labeledListHorizontalItemTmpl templates.Table = tableTmpl templates.ThematicBreak = thematicBreakTmpl templates.QuoteBlock = quoteBlockTmpl diff --git a/testsupport/html5_matcher.go b/testsupport/html5_matcher.go index abdad136..bd3e5c75 100644 --- a/testsupport/html5_matcher.go +++ b/testsupport/html5_matcher.go @@ -4,7 +4,7 @@ import ( "bytes" "fmt" "io/ioutil" - "text/template" + texttemplate "text/template" "github.com/google/go-cmp/cmp" . "github.com/onsi/ginkgo/v2" @@ -117,7 +117,7 @@ func (m *htmlTemplateMatcher) Match(actual interface{}) (success bool, err error if _, ok := actual.(string); !ok { return false, errors.Errorf("MatchHTMLTemplate matcher expects a string (actual: %T)", actual) } - expectedTmpl, err := template.New("test").Parse(string(m.expectedTmpl)) + expectedTmpl, err := texttemplate.New("test").Parse(string(m.expectedTmpl)) if err != nil { return false, err } @@ -171,7 +171,7 @@ func (m *htmlTemplateFileMatcher) Match(actual interface{}) (success bool, err e return false, err } expected = bytes.ReplaceAll(expected, []byte{'\r'}, []byte{}) - expectedTmpl, err := template.New("test").Parse(string(expected)) + expectedTmpl, err := texttemplate.New("test").Parse(string(expected)) if err != nil { return false, err }