shithub: hugo

Download patch

ref: db4b7a5c6742c75f9cd9627d3b054d3a72802ec8
parent: 25114986086e5877a0b4108d8cf5e4e95f377241
author: Bjørn Erik Pedersen <[email protected]>
date: Sat Dec 16 13:56:58 EST 2017

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%
```

--- a/helpers/content.go
+++ b/helpers/content.go
@@ -41,7 +41,7 @@
 
 // ContentSpec provides functionality to render markdown content.
 type ContentSpec struct {
-	blackfriday                map[string]interface{}
+	BlackFriday                *BlackFriday
 	footnoteAnchorPrefix       string
 	footnoteReturnLinkContents string
 	// SummaryLength is the length of the summary that Hugo extracts from a content.
@@ -56,8 +56,9 @@
 // NewContentSpec returns a ContentSpec initialized
 // with the appropriate fields from the given config.Provider.
 func NewContentSpec(cfg config.Provider) (*ContentSpec, error) {
+	bf := newBlackfriday(cfg.GetStringMap("blackfriday"))
 	spec := &ContentSpec{
-		blackfriday:                cfg.GetStringMap("blackfriday"),
+		BlackFriday:                bf,
 		footnoteAnchorPrefix:       cfg.GetString("footnoteAnchorPrefix"),
 		footnoteReturnLinkContents: cfg.GetString("footnoteReturnLinkContents"),
 		summaryLength:              cfg.GetInt("summaryLength"),
@@ -93,8 +94,8 @@
 	return spec, nil
 }
 
-// Blackfriday holds configuration values for Blackfriday rendering.
-type Blackfriday struct {
+// BlackFriday holds configuration values for BlackFriday rendering.
+type BlackFriday struct {
 	Smartypants           bool
 	SmartypantsQuotesNBSP bool
 	AngledQuotes          bool
@@ -109,7 +110,7 @@
 }
 
 // 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{}{
 		"smartypants":           true,
 		"angledQuotes":          false,
@@ -130,13 +131,13 @@
 		siteConfig[k] = v
 	}
 
-	if c.blackfriday != nil {
-		for k, v := range c.blackfriday {
+	if config != nil {
+		for k, v := range config {
 			siteConfig[k] = v
 		}
 	}
 
-	combinedConfig := &Blackfriday{}
+	combinedConfig := &BlackFriday{}
 	if err := mapstructure.Decode(siteConfig, combinedConfig); err != nil {
 		jww.FATAL.Printf("Failed to get site rendering config\n%s", err.Error())
 	}
@@ -434,7 +435,7 @@
 	PageFmt      string
 	DocumentID   string
 	DocumentName string
-	Config       *Blackfriday
+	Config       *BlackFriday
 	RenderTOC    bool
 	Cfg          config.Provider
 }
--- a/helpers/content_renderer_test.go
+++ b/helpers/content_renderer_test.go
@@ -24,7 +24,7 @@
 
 // Renders a codeblock using Blackfriday
 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)
 
 	buf := &bytes.Buffer{}
@@ -34,7 +34,7 @@
 
 // Renders a codeblock using Mmark
 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)
 
 	buf := &bytes.Buffer{}
@@ -128,7 +128,7 @@
 <p>END</p>
 `},
 	} {
-		blackFridayConfig := c.NewBlackfriday()
+		blackFridayConfig := c.BlackFriday
 		blackFridayConfig.TaskLists = this.taskListEnabled
 		ctx := &RenderingContext{Content: []byte(this.markdown), PageFmt: "markdown", Config: blackFridayConfig}
 
--- a/helpers/content_test.go
+++ b/helpers/content_test.go
@@ -159,7 +159,7 @@
 
 func TestGetHTMLRendererFlags(t *testing.T) {
 	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)
 	flags := renderer.GetFlags()
 	if flags&blackfriday.HTML_USE_XHTML != blackfriday.HTML_USE_XHTML {
@@ -186,7 +186,7 @@
 		{blackfriday.HTML_SMARTYPANTS_LATEX_DASHES},
 	}
 	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.Fractions = true
 	ctx.Config.HrefTargetBlank = true
@@ -209,7 +209,7 @@
 
 func TestGetHTMLRendererAnchors(t *testing.T) {
 	c := newTestContentSpec()
-	ctx := &RenderingContext{Cfg: c.cfg, Config: c.NewBlackfriday()}
+	ctx := &RenderingContext{Cfg: c.cfg, Config: c.BlackFriday}
 	ctx.DocumentID = "testid"
 	ctx.Config.PlainIDAnchors = false
 
@@ -233,7 +233,7 @@
 
 func TestGetMmarkHTMLRenderer(t *testing.T) {
 	c := newTestContentSpec()
-	ctx := &RenderingContext{Cfg: c.cfg, Config: c.NewBlackfriday()}
+	ctx := &RenderingContext{Cfg: c.cfg, Config: c.BlackFriday}
 	ctx.DocumentID = "testid"
 	ctx.Config.PlainIDAnchors = false
 	actualRenderer := c.getMmarkHTMLRenderer(0, ctx)
@@ -257,7 +257,7 @@
 
 func TestGetMarkdownExtensionsMasksAreRemovedFromExtensions(t *testing.T) {
 	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.ExtensionsMask = []string{"noIntraEmphasis"}
 
@@ -272,7 +272,7 @@
 		testFlag int
 	}
 	c := newTestContentSpec()
-	ctx := &RenderingContext{Cfg: c.cfg, Config: c.NewBlackfriday()}
+	ctx := &RenderingContext{Cfg: c.cfg, Config: c.BlackFriday}
 	ctx.Config.Extensions = []string{""}
 	ctx.Config.ExtensionsMask = []string{""}
 	allExtensions := []data{
@@ -304,7 +304,7 @@
 
 func TestGetMarkdownExtensionsAddingFlagsThroughRenderingContext(t *testing.T) {
 	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.ExtensionsMask = []string{""}
 
@@ -316,7 +316,7 @@
 
 func TestGetMarkdownRenderer(t *testing.T) {
 	c := newTestContentSpec()
-	ctx := &RenderingContext{Cfg: c.cfg, Config: c.NewBlackfriday()}
+	ctx := &RenderingContext{Cfg: c.cfg, Config: c.BlackFriday}
 	ctx.Content = []byte("testContent")
 	actualRenderedMarkdown := c.markdownRender(ctx)
 	expectedRenderedMarkdown := []byte("<p>testContent</p>\n")
@@ -327,7 +327,7 @@
 
 func TestGetMarkdownRendererWithTOC(t *testing.T) {
 	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")
 	actualRenderedMarkdown := c.markdownRender(ctx)
 	expectedRenderedMarkdown := []byte("<nav>\n</nav>\n\n<p>testContent</p>\n")
@@ -342,7 +342,7 @@
 		testFlag int
 	}
 	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.ExtensionsMask = []string{""}
 	allExtensions := []data{
@@ -371,7 +371,7 @@
 
 func TestMmarkRender(t *testing.T) {
 	c := newTestContentSpec()
-	ctx := &RenderingContext{Cfg: c.cfg, Config: c.NewBlackfriday()}
+	ctx := &RenderingContext{Cfg: c.cfg, Config: c.BlackFriday}
 	ctx.Content = []byte("testContent")
 	actualRenderedMarkdown := c.mmarkRender(ctx)
 	expectedRenderedMarkdown := []byte("<p>testContent</p>\n")
--- a/hugolib/config.go
+++ b/hugolib/config.go
@@ -210,7 +210,7 @@
 	v.SetDefault("paginate", 10)
 	v.SetDefault("paginatePath", "page")
 	v.SetDefault("summaryLength", 70)
-	v.SetDefault("blackfriday", c.NewBlackfriday())
+	v.SetDefault("blackfriday", c.BlackFriday)
 	v.SetDefault("rSSUri", "index.xml")
 	v.SetDefault("rssLimit", -1)
 	v.SetDefault("sectionPagesMenu", "")
--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -168,7 +168,7 @@
 	plainWords []string
 
 	// rendering configuration
-	renderingConfig *helpers.Blackfriday
+	renderingConfig *helpers.BlackFriday
 
 	// menus
 	pageMenus PageMenus
@@ -700,17 +700,19 @@
 		Config: p.getRenderingConfig()})
 }
 
-func (p *Page) getRenderingConfig() *helpers.Blackfriday {
+func (p *Page) getRenderingConfig() *helpers.BlackFriday {
 	p.renderingConfigInit.Do(func() {
-		p.renderingConfig = p.s.ContentSpec.NewBlackfriday()
-
-		if p.Language() == nil {
-			panic(fmt.Sprintf("nil language for %s with source lang %s", p.BaseFileName(), p.lang))
-		}
-
 		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 {
+			panic(fmt.Sprintf("nil language for %s with source lang %s", p.BaseFileName(), p.lang))
 		}
 
 		pageParam := cast.ToStringMap(bfParam)
--- a/tpl/transform/transform.go
+++ b/tpl/transform/transform.go
@@ -98,7 +98,7 @@
 			Cfg:     ns.deps.Cfg,
 			Content: []byte(ss),
 			PageFmt: "markdown",
-			Config:  ns.deps.ContentSpec.NewBlackfriday(),
+			Config:  ns.deps.ContentSpec.BlackFriday,
 		},
 	)