Skip to content

Commit

Permalink
refactor(renderer): Use string instead of []byte internally (#625)
Browse files Browse the repository at this point in the history
This uses strings.Builder to get more efficiency and reduce
copies, but more importantly it gets rid of the need to pipe
output through printf "%s" in templates, which makes them
cleaner and nicer to work with.

Fixes #619
  • Loading branch information
gdamore authored Jun 20, 2020
1 parent 07252b5 commit 8955d3d
Show file tree
Hide file tree
Showing 38 changed files with 355 additions and 366 deletions.
20 changes: 10 additions & 10 deletions pkg/renderer/sgml/blank_line.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
package sgml

import (
"bytes"
"strings"

"github.com/bytesparadise/libasciidoc/pkg/types"

log "github.com/sirupsen/logrus"
)

func (r *sgmlRenderer) renderBlankLine(ctx *Context, _ types.BlankLine) ([]byte, error) {
func (r *sgmlRenderer) renderBlankLine(ctx *Context, _ types.BlankLine) (string, error) {
if ctx.IncludeBlankLine {
buf := &bytes.Buffer{}
buf := &strings.Builder{}
if err := r.blankLine.Execute(buf, nil); err != nil {
return nil, err
return "", err
}
log.Debug("rendering blank line")
return buf.Bytes(), nil
return buf.String(), nil
}
return []byte{}, nil
return "", nil
}

func (r *sgmlRenderer) renderLineBreak() ([]byte, error) {
buf := &bytes.Buffer{}
func (r *sgmlRenderer) renderLineBreak() (string, error) {
buf := &strings.Builder{}
if err := r.lineBreak.Execute(buf, nil); err != nil {
return nil, err
return "", err
}
return buf.Bytes(), nil
return buf.String(), nil
}
10 changes: 5 additions & 5 deletions pkg/renderer/sgml/callout_list.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package sgml

import (
"bytes"
"strings"

"github.com/bytesparadise/libasciidoc/pkg/renderer"
"github.com/bytesparadise/libasciidoc/pkg/types"
"github.com/pkg/errors"
)

func (r *sgmlRenderer) renderCalloutList(ctx *renderer.Context, l types.CalloutList) ([]byte, error) {
result := &bytes.Buffer{}
func (r *sgmlRenderer) renderCalloutList(ctx *renderer.Context, l types.CalloutList) (string, error) {
result := &strings.Builder{}
err := r.calloutList.Execute(result, ContextualPipeline{
Context: ctx,
Data: struct {
Expand All @@ -25,7 +25,7 @@ func (r *sgmlRenderer) renderCalloutList(ctx *renderer.Context, l types.CalloutL
},
})
if err != nil {
return nil, errors.Wrapf(err, "unable to render callout list")
return "", errors.Wrap(err, "unable to render callout list")
}
return result.Bytes(), nil
return result.String(), nil
}
28 changes: 14 additions & 14 deletions pkg/renderer/sgml/cross_reference.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
package sgml

import (
"bytes"
"path/filepath"
"strings"

"github.com/bytesparadise/libasciidoc/pkg/renderer"
"github.com/bytesparadise/libasciidoc/pkg/types"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)

func (r *sgmlRenderer) renderInternalCrossReference(ctx *renderer.Context, xref types.InternalCrossReference) ([]byte, error) {
func (r *sgmlRenderer) renderInternalCrossReference(ctx *renderer.Context, xref types.InternalCrossReference) (string, error) {
log.Debugf("rendering cross reference with ID: %s", xref.ID)
result := &bytes.Buffer{}
result := &strings.Builder{}
var label string
if xref.Label != "" {
label = xref.Label
} else if target, found := ctx.ElementReferences[xref.ID]; found {
if t, ok := target.([]interface{}); ok {
renderedContent, err := r.renderElement(ctx, t)
if err != nil {
return nil, errors.Wrapf(err, "error while rendering internal cross reference")
return "", errors.Wrap(err, "error while rendering internal cross reference")
}
label = string(renderedContent)
label = renderedContent
} else {
return nil, errors.Errorf("unable to process internal cross reference to element of type %T", target)
return "", errors.Errorf("unable to process internal cross reference to element of type %T", target)
}
} else {
label = "[" + xref.ID + "]"
Expand All @@ -37,29 +37,29 @@ func (r *sgmlRenderer) renderInternalCrossReference(ctx *renderer.Context, xref
Label: label,
})
if err != nil {
return nil, errors.Wrapf(err, "unable to render internal cross reference")
return "", errors.Wrapf(err, "unable to render internal cross reference")
}
return result.Bytes(), nil
return result.String(), nil
}

func (r *sgmlRenderer) renderExternalCrossReference(ctx *renderer.Context, xref types.ExternalCrossReference) ([]byte, error) {
func (r *sgmlRenderer) renderExternalCrossReference(ctx *renderer.Context, xref types.ExternalCrossReference) (string, error) {
log.Debugf("rendering cross reference with ID: %s", xref.Location)
result := &bytes.Buffer{}
result := &strings.Builder{}
label, err := r.renderInlineElements(ctx, xref.Label)
if err != nil {
return nil, errors.Wrapf(err, "unable to render external cross reference")
return "", errors.Wrap(err, "unable to render external cross reference")
}
err = r.externalCrossReference.Execute(result, struct {
Href string
Label string
}{
Href: getCrossReferenceLocation(xref),
Label: string(label),
Label: label,
})
if err != nil {
return nil, errors.Wrapf(err, "unable to render external cross reference")
return "", errors.Wrap(err, "unable to render external cross reference")
}
return result.Bytes(), nil
return result.String(), nil
}

func getCrossReferenceLocation(xref types.ExternalCrossReference) string {
Expand Down
75 changes: 38 additions & 37 deletions pkg/renderer/sgml/delimited_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package sgml
import (
"bytes"
"strconv"
"strings"

"github.com/alecthomas/chroma"
"github.com/alecthomas/chroma/formatters/html"
Expand All @@ -14,7 +15,7 @@ import (
log "github.com/sirupsen/logrus"
)

func (r *sgmlRenderer) renderDelimitedBlock(ctx *renderer.Context, b types.DelimitedBlock) ([]byte, error) {
func (r *sgmlRenderer) renderDelimitedBlock(ctx *renderer.Context, b types.DelimitedBlock) (string, error) {
log.Debugf("rendering delimited block of kind '%v'", b.Attributes[types.AttrKind])
var err error
kind := b.Kind
Expand All @@ -36,11 +37,11 @@ func (r *sgmlRenderer) renderDelimitedBlock(ctx *renderer.Context, b types.Delim
case types.Passthrough:
return r.renderPassthrough(ctx, b)
default:
return nil, errors.Wrapf(err, "unable to render delimited block")
return "", errors.Wrap(err, "unable to render delimited block")
}
}

func (r *sgmlRenderer) renderFencedBlock(ctx *renderer.Context, b types.DelimitedBlock) ([]byte, error) {
func (r *sgmlRenderer) renderFencedBlock(ctx *renderer.Context, b types.DelimitedBlock) (string, error) {
previousWithinDelimitedBlock := ctx.WithinDelimitedBlock
previousIncludeBlankLine := ctx.IncludeBlankLine
defer func() {
Expand All @@ -49,7 +50,7 @@ func (r *sgmlRenderer) renderFencedBlock(ctx *renderer.Context, b types.Delimite
}()
ctx.WithinDelimitedBlock = true
ctx.IncludeBlankLine = true
result := &bytes.Buffer{}
result := &strings.Builder{}
err := r.fencedBlock.Execute(result, ContextualPipeline{
Context: ctx,
Data: struct {
Expand All @@ -62,10 +63,10 @@ func (r *sgmlRenderer) renderFencedBlock(ctx *renderer.Context, b types.Delimite
Elements: discardTrailingBlankLines(b.Elements),
},
})
return result.Bytes(), err
return result.String(), err
}

func (r *sgmlRenderer) renderListingBlock(ctx *renderer.Context, b types.DelimitedBlock) ([]byte, error) {
func (r *sgmlRenderer) renderListingBlock(ctx *renderer.Context, b types.DelimitedBlock) (string, error) {
previousWithinDelimitedBlock := ctx.WithinDelimitedBlock
previousIncludeBlankLine := ctx.IncludeBlankLine
defer func() {
Expand All @@ -74,7 +75,7 @@ func (r *sgmlRenderer) renderListingBlock(ctx *renderer.Context, b types.Delimit
}()
ctx.WithinDelimitedBlock = true
ctx.IncludeBlankLine = true
result := &bytes.Buffer{}
result := &strings.Builder{}
err := r.listingBlock.Execute(result, ContextualPipeline{
Context: ctx,
Data: struct {
Expand All @@ -87,10 +88,10 @@ func (r *sgmlRenderer) renderListingBlock(ctx *renderer.Context, b types.Delimit
Elements: discardTrailingBlankLines(b.Elements),
},
})
return result.Bytes(), err
return result.String(), err
}

func (r *sgmlRenderer) renderSourceBlock(ctx *renderer.Context, b types.DelimitedBlock) ([]byte, error) {
func (r *sgmlRenderer) renderSourceBlock(ctx *renderer.Context, b types.DelimitedBlock) (string, error) {
previousWithinDelimitedBlock := ctx.WithinDelimitedBlock
previousIncludeBlankLine := ctx.IncludeBlankLine
defer func() {
Expand All @@ -100,7 +101,7 @@ func (r *sgmlRenderer) renderSourceBlock(ctx *renderer.Context, b types.Delimite
ctx.WithinDelimitedBlock = true
ctx.IncludeBlankLine = true
// first, render the content
contentBuf := &bytes.Buffer{}
contentBuf := &strings.Builder{}
err := r.sourceBlockContent.Execute(contentBuf, ContextualPipeline{
Context: ctx,
Data: struct {
Expand All @@ -109,15 +110,15 @@ func (r *sgmlRenderer) renderSourceBlock(ctx *renderer.Context, b types.Delimite
Elements: discardTrailingBlankLines(b.Elements),
}})
if err != nil {
return []byte{}, err
return "", err
}
content := contentBuf.String()

highlighter, _ := ctx.Attributes.GetAsString(types.AttrSyntaxHighlighter)
language, found := b.Attributes.GetAsString(types.AttrLanguage)
if found && highlighter == "pygments" {
// using github.com/alecthomas/chroma to highlight the content
contentBuf = &bytes.Buffer{}
contentBuf = &strings.Builder{}
lexer := lexers.Get(language)
lexer = chroma.Coalesce(lexer)
style := styles.Fallback
Expand All @@ -126,7 +127,7 @@ func (r *sgmlRenderer) renderSourceBlock(ctx *renderer.Context, b types.Delimite
}
iterator, err := lexer.Tokenise(nil, content)
if err != nil {
return []byte{}, err
return "", err
}
options := []html.Option{
html.ClassPrefix("tok-"),
Expand All @@ -144,7 +145,7 @@ func (r *sgmlRenderer) renderSourceBlock(ctx *renderer.Context, b types.Delimite
}
err = html.New(options...).Format(contentBuf, style, iterator)
if err != nil {
return []byte{}, err
return "", err
}
content = contentBuf.String()
}
Expand All @@ -163,15 +164,15 @@ func (r *sgmlRenderer) renderSourceBlock(ctx *renderer.Context, b types.Delimite
Language: language,
Content: content,
})
return result.Bytes(), err
return result.String(), err
}

func (r *sgmlRenderer) renderExampleBlock(ctx *renderer.Context, b types.DelimitedBlock) ([]byte, error) {
result := &bytes.Buffer{}
func (r *sgmlRenderer) renderExampleBlock(ctx *renderer.Context, b types.DelimitedBlock) (string, error) {
result := &strings.Builder{}
if k, ok := b.Attributes[types.AttrAdmonitionKind].(types.AdmonitionKind); ok {
icon, err := r.renderIcon(ctx, types.Icon{Class: string(k)}, true)
if err != nil {
return nil, err
return "", err
}
err = r.admonitionBlock.Execute(result, ContextualPipeline{
Context: ctx,
Expand All @@ -189,7 +190,7 @@ func (r *sgmlRenderer) renderExampleBlock(ctx *renderer.Context, b types.Delimit
Elements: discardTrailingBlankLines(b.Elements),
},
})
return result.Bytes(), err
return result.String(), err
}
// default, example block
var title string
Expand All @@ -208,11 +209,11 @@ func (r *sgmlRenderer) renderExampleBlock(ctx *renderer.Context, b types.Delimit
Elements: discardTrailingBlankLines(b.Elements),
},
})
return result.Bytes(), err
return result.String(), err
}

func (r *sgmlRenderer) renderQuoteBlock(ctx *renderer.Context, b types.DelimitedBlock) ([]byte, error) {
result := &bytes.Buffer{}
func (r *sgmlRenderer) renderQuoteBlock(ctx *renderer.Context, b types.DelimitedBlock) (string, error) {
result := &strings.Builder{}
err := r.quoteBlock.Execute(result, ContextualPipeline{
Context: ctx,
Data: struct {
Expand All @@ -227,11 +228,11 @@ func (r *sgmlRenderer) renderQuoteBlock(ctx *renderer.Context, b types.Delimited
Elements: b.Elements,
},
})
return result.Bytes(), err
return result.String(), err
}

func (r *sgmlRenderer) renderVerseBlock(ctx *renderer.Context, b types.DelimitedBlock) ([]byte, error) {
result := &bytes.Buffer{}
func (r *sgmlRenderer) renderVerseBlock(ctx *renderer.Context, b types.DelimitedBlock) (string, error) {
result := &strings.Builder{}
err := r.verseBlock.Execute(result, ContextualPipeline{
Context: ctx,
Data: struct {
Expand All @@ -246,10 +247,10 @@ func (r *sgmlRenderer) renderVerseBlock(ctx *renderer.Context, b types.Delimited
Elements: discardTrailingBlankLines(b.Elements),
},
})
return result.Bytes(), err
return result.String(), err
}

func (r *sgmlRenderer) renderVerseBlockElement(ctx *renderer.Context, element interface{}) ([]byte, error) {
func (r *sgmlRenderer) renderVerseBlockElement(ctx *renderer.Context, element interface{}) (string, error) {
previousIncludeBlankLine := ctx.IncludeBlankLine
defer func() {
ctx.IncludeBlankLine = previousIncludeBlankLine
Expand All @@ -261,13 +262,13 @@ func (r *sgmlRenderer) renderVerseBlockElement(ctx *renderer.Context, element in
case types.BlankLine:
return r.renderBlankLine(ctx, e)
default:
return nil, errors.Errorf("unexpected type of element to include in verse block: %T", element)
return "", errors.Errorf("unexpected type of element to include in verse block: %T", element)
}
}

func (r *sgmlRenderer) renderVerseBlockParagraph(ctx *renderer.Context, p types.Paragraph) ([]byte, error) {
func (r *sgmlRenderer) renderVerseBlockParagraph(ctx *renderer.Context, p types.Paragraph) (string, error) {
log.Debugf("rendering paragraph with %d line(s) within a delimited block or a list", len(p.Lines))
result := &bytes.Buffer{}
result := &strings.Builder{}
err := r.verseBlockParagraph.Execute(result, ContextualPipeline{
Context: ctx,
Data: struct {
Expand All @@ -276,11 +277,11 @@ func (r *sgmlRenderer) renderVerseBlockParagraph(ctx *renderer.Context, p types.
Lines: p.Lines,
},
})
return result.Bytes(), err
return result.String(), err
}

func (r *sgmlRenderer) renderSidebarBlock(ctx *renderer.Context, b types.DelimitedBlock) ([]byte, error) {
result := &bytes.Buffer{}
func (r *sgmlRenderer) renderSidebarBlock(ctx *renderer.Context, b types.DelimitedBlock) (string, error) {
result := &strings.Builder{}
err := r.sidebarBlock.Execute(result, ContextualPipeline{
Context: ctx,
Data: struct {
Expand All @@ -293,11 +294,11 @@ func (r *sgmlRenderer) renderSidebarBlock(ctx *renderer.Context, b types.Delimit
Elements: discardTrailingBlankLines(b.Elements),
},
})
return result.Bytes(), err
return result.String(), err
}

func (r *sgmlRenderer) renderPassthrough(ctx *renderer.Context, b types.DelimitedBlock) ([]byte, error) {
result := &bytes.Buffer{}
func (r *sgmlRenderer) renderPassthrough(ctx *renderer.Context, b types.DelimitedBlock) (string, error) {
result := &strings.Builder{}
err := r.passthroughBlock.Execute(result, ContextualPipeline{
Context: ctx,
Data: struct {
Expand All @@ -308,7 +309,7 @@ func (r *sgmlRenderer) renderPassthrough(ctx *renderer.Context, b types.Delimite
Elements: discardTrailingBlankLines(b.Elements),
},
})
return result.Bytes(), err
return result.String(), err
}

func discardTrailingBlankLines(elements []interface{}) []interface{} {
Expand Down
Loading

0 comments on commit 8955d3d

Please sign in to comment.