Reuse the BlackFriday instance when possible

This is in heavy use in rendering, so this makes a difference:

```bash
benchmark                                                                                    old ns/op     new ns/op     delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_pages=500,tags_per_page=5,shortcodes,render-4     124551144     107743429     -13.49%

benchmark                                                                                    old allocs     new allocs     delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_pages=500,tags_per_page=5,shortcodes,render-4     528684         435118         -17.70%

benchmark                                                                                    old bytes     new bytes     delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_pages=500,tags_per_page=5,shortcodes,render-4     53306848      45147832      -15.31%
```
This commit is contained in:
Bjørn Erik Pedersen 2017-12-16 18:56:58 +01:00
parent 2511498608
commit db4b7a5c67
6 changed files with 36 additions and 33 deletions

View file

@ -41,7 +41,7 @@ var SummaryDivider = []byte("<!--more-->")
// ContentSpec provides functionality to render markdown content. // ContentSpec provides functionality to render markdown content.
type ContentSpec struct { type ContentSpec struct {
blackfriday map[string]interface{} BlackFriday *BlackFriday
footnoteAnchorPrefix string footnoteAnchorPrefix string
footnoteReturnLinkContents string footnoteReturnLinkContents string
// SummaryLength is the length of the summary that Hugo extracts from a content. // SummaryLength is the length of the summary that Hugo extracts from a content.
@ -56,8 +56,9 @@ type ContentSpec struct {
// NewContentSpec returns a ContentSpec initialized // NewContentSpec returns a ContentSpec initialized
// with the appropriate fields from the given config.Provider. // with the appropriate fields from the given config.Provider.
func NewContentSpec(cfg config.Provider) (*ContentSpec, error) { func NewContentSpec(cfg config.Provider) (*ContentSpec, error) {
bf := newBlackfriday(cfg.GetStringMap("blackfriday"))
spec := &ContentSpec{ spec := &ContentSpec{
blackfriday: cfg.GetStringMap("blackfriday"), BlackFriday: bf,
footnoteAnchorPrefix: cfg.GetString("footnoteAnchorPrefix"), footnoteAnchorPrefix: cfg.GetString("footnoteAnchorPrefix"),
footnoteReturnLinkContents: cfg.GetString("footnoteReturnLinkContents"), footnoteReturnLinkContents: cfg.GetString("footnoteReturnLinkContents"),
summaryLength: cfg.GetInt("summaryLength"), summaryLength: cfg.GetInt("summaryLength"),
@ -93,8 +94,8 @@ func NewContentSpec(cfg config.Provider) (*ContentSpec, error) {
return spec, nil return spec, nil
} }
// Blackfriday holds configuration values for Blackfriday rendering. // BlackFriday holds configuration values for BlackFriday rendering.
type Blackfriday struct { type BlackFriday struct {
Smartypants bool Smartypants bool
SmartypantsQuotesNBSP bool SmartypantsQuotesNBSP bool
AngledQuotes bool AngledQuotes bool
@ -109,7 +110,7 @@ type Blackfriday struct {
} }
// NewBlackfriday creates a new Blackfriday filled with site config or some sane defaults. // NewBlackfriday creates a new Blackfriday filled with site config or some sane defaults.
func (c ContentSpec) NewBlackfriday() *Blackfriday { func newBlackfriday(config map[string]interface{}) *BlackFriday {
defaultParam := map[string]interface{}{ defaultParam := map[string]interface{}{
"smartypants": true, "smartypants": true,
"angledQuotes": false, "angledQuotes": false,
@ -130,13 +131,13 @@ func (c ContentSpec) NewBlackfriday() *Blackfriday {
siteConfig[k] = v siteConfig[k] = v
} }
if c.blackfriday != nil { if config != nil {
for k, v := range c.blackfriday { for k, v := range config {
siteConfig[k] = v siteConfig[k] = v
} }
} }
combinedConfig := &Blackfriday{} combinedConfig := &BlackFriday{}
if err := mapstructure.Decode(siteConfig, combinedConfig); err != nil { if err := mapstructure.Decode(siteConfig, combinedConfig); err != nil {
jww.FATAL.Printf("Failed to get site rendering config\n%s", err.Error()) jww.FATAL.Printf("Failed to get site rendering config\n%s", err.Error())
} }
@ -434,7 +435,7 @@ type RenderingContext struct {
PageFmt string PageFmt string
DocumentID string DocumentID string
DocumentName string DocumentName string
Config *Blackfriday Config *BlackFriday
RenderTOC bool RenderTOC bool
Cfg config.Provider Cfg config.Provider
} }

View file

@ -24,7 +24,7 @@ import (
// Renders a codeblock using Blackfriday // Renders a codeblock using Blackfriday
func (c ContentSpec) render(input string) string { func (c ContentSpec) render(input string) string {
ctx := &RenderingContext{Cfg: c.cfg, Config: c.NewBlackfriday()} ctx := &RenderingContext{Cfg: c.cfg, Config: c.BlackFriday}
render := c.getHTMLRenderer(0, ctx) render := c.getHTMLRenderer(0, ctx)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
@ -34,7 +34,7 @@ func (c ContentSpec) render(input string) string {
// Renders a codeblock using Mmark // Renders a codeblock using Mmark
func (c ContentSpec) renderWithMmark(input string) string { func (c ContentSpec) renderWithMmark(input string) string {
ctx := &RenderingContext{Cfg: c.cfg, Config: c.NewBlackfriday()} ctx := &RenderingContext{Cfg: c.cfg, Config: c.BlackFriday}
render := c.getMmarkHTMLRenderer(0, ctx) render := c.getMmarkHTMLRenderer(0, ctx)
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
@ -128,7 +128,7 @@ END`, true, `<ul class="task-list">
<p>END</p> <p>END</p>
`}, `},
} { } {
blackFridayConfig := c.NewBlackfriday() blackFridayConfig := c.BlackFriday
blackFridayConfig.TaskLists = this.taskListEnabled blackFridayConfig.TaskLists = this.taskListEnabled
ctx := &RenderingContext{Content: []byte(this.markdown), PageFmt: "markdown", Config: blackFridayConfig} ctx := &RenderingContext{Content: []byte(this.markdown), PageFmt: "markdown", Config: blackFridayConfig}

View file

@ -159,7 +159,7 @@ func TestTruncateWordsByRune(t *testing.T) {
func TestGetHTMLRendererFlags(t *testing.T) { func TestGetHTMLRendererFlags(t *testing.T) {
c := newTestContentSpec() c := newTestContentSpec()
ctx := &RenderingContext{Cfg: c.cfg, Config: c.NewBlackfriday()} ctx := &RenderingContext{Cfg: c.cfg, Config: c.BlackFriday}
renderer := c.getHTMLRenderer(blackfriday.HTML_USE_XHTML, ctx) renderer := c.getHTMLRenderer(blackfriday.HTML_USE_XHTML, ctx)
flags := renderer.GetFlags() flags := renderer.GetFlags()
if flags&blackfriday.HTML_USE_XHTML != blackfriday.HTML_USE_XHTML { if flags&blackfriday.HTML_USE_XHTML != blackfriday.HTML_USE_XHTML {
@ -186,7 +186,7 @@ func TestGetHTMLRendererAllFlags(t *testing.T) {
{blackfriday.HTML_SMARTYPANTS_LATEX_DASHES}, {blackfriday.HTML_SMARTYPANTS_LATEX_DASHES},
} }
defaultFlags := blackfriday.HTML_USE_XHTML defaultFlags := blackfriday.HTML_USE_XHTML
ctx := &RenderingContext{Cfg: c.cfg, Config: c.NewBlackfriday()} ctx := &RenderingContext{Cfg: c.cfg, Config: c.BlackFriday}
ctx.Config.AngledQuotes = true ctx.Config.AngledQuotes = true
ctx.Config.Fractions = true ctx.Config.Fractions = true
ctx.Config.HrefTargetBlank = true ctx.Config.HrefTargetBlank = true
@ -209,7 +209,7 @@ func TestGetHTMLRendererAllFlags(t *testing.T) {
func TestGetHTMLRendererAnchors(t *testing.T) { func TestGetHTMLRendererAnchors(t *testing.T) {
c := newTestContentSpec() c := newTestContentSpec()
ctx := &RenderingContext{Cfg: c.cfg, Config: c.NewBlackfriday()} ctx := &RenderingContext{Cfg: c.cfg, Config: c.BlackFriday}
ctx.DocumentID = "testid" ctx.DocumentID = "testid"
ctx.Config.PlainIDAnchors = false ctx.Config.PlainIDAnchors = false
@ -233,7 +233,7 @@ func TestGetHTMLRendererAnchors(t *testing.T) {
func TestGetMmarkHTMLRenderer(t *testing.T) { func TestGetMmarkHTMLRenderer(t *testing.T) {
c := newTestContentSpec() c := newTestContentSpec()
ctx := &RenderingContext{Cfg: c.cfg, Config: c.NewBlackfriday()} ctx := &RenderingContext{Cfg: c.cfg, Config: c.BlackFriday}
ctx.DocumentID = "testid" ctx.DocumentID = "testid"
ctx.Config.PlainIDAnchors = false ctx.Config.PlainIDAnchors = false
actualRenderer := c.getMmarkHTMLRenderer(0, ctx) actualRenderer := c.getMmarkHTMLRenderer(0, ctx)
@ -257,7 +257,7 @@ func TestGetMmarkHTMLRenderer(t *testing.T) {
func TestGetMarkdownExtensionsMasksAreRemovedFromExtensions(t *testing.T) { func TestGetMarkdownExtensionsMasksAreRemovedFromExtensions(t *testing.T) {
c := newTestContentSpec() c := newTestContentSpec()
ctx := &RenderingContext{Cfg: c.cfg, Config: c.NewBlackfriday()} ctx := &RenderingContext{Cfg: c.cfg, Config: c.BlackFriday}
ctx.Config.Extensions = []string{"headerId"} ctx.Config.Extensions = []string{"headerId"}
ctx.Config.ExtensionsMask = []string{"noIntraEmphasis"} ctx.Config.ExtensionsMask = []string{"noIntraEmphasis"}
@ -272,7 +272,7 @@ func TestGetMarkdownExtensionsByDefaultAllExtensionsAreEnabled(t *testing.T) {
testFlag int testFlag int
} }
c := newTestContentSpec() c := newTestContentSpec()
ctx := &RenderingContext{Cfg: c.cfg, Config: c.NewBlackfriday()} ctx := &RenderingContext{Cfg: c.cfg, Config: c.BlackFriday}
ctx.Config.Extensions = []string{""} ctx.Config.Extensions = []string{""}
ctx.Config.ExtensionsMask = []string{""} ctx.Config.ExtensionsMask = []string{""}
allExtensions := []data{ allExtensions := []data{
@ -304,7 +304,7 @@ func TestGetMarkdownExtensionsByDefaultAllExtensionsAreEnabled(t *testing.T) {
func TestGetMarkdownExtensionsAddingFlagsThroughRenderingContext(t *testing.T) { func TestGetMarkdownExtensionsAddingFlagsThroughRenderingContext(t *testing.T) {
c := newTestContentSpec() c := newTestContentSpec()
ctx := &RenderingContext{Cfg: c.cfg, Config: c.NewBlackfriday()} ctx := &RenderingContext{Cfg: c.cfg, Config: c.BlackFriday}
ctx.Config.Extensions = []string{"definitionLists"} ctx.Config.Extensions = []string{"definitionLists"}
ctx.Config.ExtensionsMask = []string{""} ctx.Config.ExtensionsMask = []string{""}
@ -316,7 +316,7 @@ func TestGetMarkdownExtensionsAddingFlagsThroughRenderingContext(t *testing.T) {
func TestGetMarkdownRenderer(t *testing.T) { func TestGetMarkdownRenderer(t *testing.T) {
c := newTestContentSpec() c := newTestContentSpec()
ctx := &RenderingContext{Cfg: c.cfg, Config: c.NewBlackfriday()} ctx := &RenderingContext{Cfg: c.cfg, Config: c.BlackFriday}
ctx.Content = []byte("testContent") ctx.Content = []byte("testContent")
actualRenderedMarkdown := c.markdownRender(ctx) actualRenderedMarkdown := c.markdownRender(ctx)
expectedRenderedMarkdown := []byte("<p>testContent</p>\n") expectedRenderedMarkdown := []byte("<p>testContent</p>\n")
@ -327,7 +327,7 @@ func TestGetMarkdownRenderer(t *testing.T) {
func TestGetMarkdownRendererWithTOC(t *testing.T) { func TestGetMarkdownRendererWithTOC(t *testing.T) {
c := newTestContentSpec() c := newTestContentSpec()
ctx := &RenderingContext{RenderTOC: true, Cfg: c.cfg, Config: c.NewBlackfriday()} ctx := &RenderingContext{RenderTOC: true, Cfg: c.cfg, Config: c.BlackFriday}
ctx.Content = []byte("testContent") ctx.Content = []byte("testContent")
actualRenderedMarkdown := c.markdownRender(ctx) actualRenderedMarkdown := c.markdownRender(ctx)
expectedRenderedMarkdown := []byte("<nav>\n</nav>\n\n<p>testContent</p>\n") expectedRenderedMarkdown := []byte("<nav>\n</nav>\n\n<p>testContent</p>\n")
@ -342,7 +342,7 @@ func TestGetMmarkExtensions(t *testing.T) {
testFlag int testFlag int
} }
c := newTestContentSpec() c := newTestContentSpec()
ctx := &RenderingContext{Cfg: c.cfg, Config: c.NewBlackfriday()} ctx := &RenderingContext{Cfg: c.cfg, Config: c.BlackFriday}
ctx.Config.Extensions = []string{"tables"} ctx.Config.Extensions = []string{"tables"}
ctx.Config.ExtensionsMask = []string{""} ctx.Config.ExtensionsMask = []string{""}
allExtensions := []data{ allExtensions := []data{
@ -371,7 +371,7 @@ func TestGetMmarkExtensions(t *testing.T) {
func TestMmarkRender(t *testing.T) { func TestMmarkRender(t *testing.T) {
c := newTestContentSpec() c := newTestContentSpec()
ctx := &RenderingContext{Cfg: c.cfg, Config: c.NewBlackfriday()} ctx := &RenderingContext{Cfg: c.cfg, Config: c.BlackFriday}
ctx.Content = []byte("testContent") ctx.Content = []byte("testContent")
actualRenderedMarkdown := c.mmarkRender(ctx) actualRenderedMarkdown := c.mmarkRender(ctx)
expectedRenderedMarkdown := []byte("<p>testContent</p>\n") expectedRenderedMarkdown := []byte("<p>testContent</p>\n")

View file

@ -210,7 +210,7 @@ func loadDefaultSettingsFor(v *viper.Viper) error {
v.SetDefault("paginate", 10) v.SetDefault("paginate", 10)
v.SetDefault("paginatePath", "page") v.SetDefault("paginatePath", "page")
v.SetDefault("summaryLength", 70) v.SetDefault("summaryLength", 70)
v.SetDefault("blackfriday", c.NewBlackfriday()) v.SetDefault("blackfriday", c.BlackFriday)
v.SetDefault("rSSUri", "index.xml") v.SetDefault("rSSUri", "index.xml")
v.SetDefault("rssLimit", -1) v.SetDefault("rssLimit", -1)
v.SetDefault("sectionPagesMenu", "") v.SetDefault("sectionPagesMenu", "")

View file

@ -168,7 +168,7 @@ type Page struct {
plainWords []string plainWords []string
// rendering configuration // rendering configuration
renderingConfig *helpers.Blackfriday renderingConfig *helpers.BlackFriday
// menus // menus
pageMenus PageMenus pageMenus PageMenus
@ -700,19 +700,21 @@ func (p *Page) renderContent(content []byte) []byte {
Config: p.getRenderingConfig()}) Config: p.getRenderingConfig()})
} }
func (p *Page) getRenderingConfig() *helpers.Blackfriday { func (p *Page) getRenderingConfig() *helpers.BlackFriday {
p.renderingConfigInit.Do(func() { p.renderingConfigInit.Do(func() {
p.renderingConfig = p.s.ContentSpec.NewBlackfriday() bfParam := p.GetParam("blackfriday")
if bfParam == nil {
p.renderingConfig = p.s.ContentSpec.BlackFriday
return
}
// Create a copy so we can modify it.
bf := *p.s.ContentSpec.BlackFriday
p.renderingConfig = &bf
if p.Language() == nil { if p.Language() == nil {
panic(fmt.Sprintf("nil language for %s with source lang %s", p.BaseFileName(), p.lang)) panic(fmt.Sprintf("nil language for %s with source lang %s", p.BaseFileName(), p.lang))
} }
bfParam := p.GetParam("blackfriday")
if bfParam == nil {
return
}
pageParam := cast.ToStringMap(bfParam) pageParam := cast.ToStringMap(bfParam)
if err := mapstructure.Decode(pageParam, &p.renderingConfig); err != nil { if err := mapstructure.Decode(pageParam, &p.renderingConfig); err != nil {
p.s.Log.FATAL.Printf("Failed to get rendering config for %s:\n%s", p.BaseFileName(), err.Error()) p.s.Log.FATAL.Printf("Failed to get rendering config for %s:\n%s", p.BaseFileName(), err.Error())

View file

@ -98,7 +98,7 @@ func (ns *Namespace) Markdownify(s interface{}) (template.HTML, error) {
Cfg: ns.deps.Cfg, Cfg: ns.deps.Cfg,
Content: []byte(ss), Content: []byte(ss),
PageFmt: "markdown", PageFmt: "markdown",
Config: ns.deps.ContentSpec.NewBlackfriday(), Config: ns.deps.ContentSpec.BlackFriday,
}, },
) )