summaryrefslogtreecommitdiffstats
path: root/hugolib/shortcode.go
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2017-03-10 20:54:50 +0100
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2017-03-11 20:21:06 +0100
commit2f2ea42c091931fe4735e0ca7b37dc05cb8c044b (patch)
treeca1d5fa25acf4d955936c2f9f3f8536edca4176a /hugolib/shortcode.go
parent5f443bd45bd63c10796fc340985fddf218c7ef0d (diff)
hugolib: Fix reloading corner cases for shortcodes
This commit fixes two different, but related issues: 1) Live-reload when a new shortcode was defined in the content file before the shortcode itself was created. 2) Live-reload when a newly defined shortcode changed its "inner content" status. This commit also improves the shortcode related error messages to include the full path to the content file in question. Fixes #3156
Diffstat (limited to 'hugolib/shortcode.go')
-rw-r--r--hugolib/shortcode.go83
1 files changed, 56 insertions, 27 deletions
diff --git a/hugolib/shortcode.go b/hugolib/shortcode.go
index 823989f7d..d165c778b 100644
--- a/hugolib/shortcode.go
+++ b/hugolib/shortcode.go
@@ -149,6 +149,26 @@ func (sc shortcode) String() string {
return fmt.Sprintf("%s(%q, %t){%s}", sc.name, params, sc.doMarkup, sc.inner)
}
+type shortcodeHandler struct {
+ // Maps the shortcodeplaceholder with the shortcode rendering func.
+ contentShortCodes map[string]func() (string, error)
+
+ // Maps the shortcodeplaceholder with the actual shortcode.
+ shortcodes map[string]shortcode
+
+ // All the shortcode names in this set.
+ nameSet map[string]bool
+}
+
+func newShortcodeHandler() *shortcodeHandler {
+ return &shortcodeHandler{
+ contentShortCodes: make(map[string]func() (string, error)),
+ shortcodes: make(map[string]shortcode),
+ nameSet: make(map[string]bool),
+ }
+}
+
+// TODO(bep) make it non-global
var isInnerShortcodeCache = struct {
sync.RWMutex
m map[string]bool
@@ -177,6 +197,12 @@ func isInnerShortcode(t *template.Template) (bool, error) {
return match, nil
}
+func clearIsInnerShortcodeCache() {
+ isInnerShortcodeCache.Lock()
+ defer isInnerShortcodeCache.Unlock()
+ isInnerShortcodeCache.m = make(map[string]bool)
+}
+
func createShortcodePlaceholder(id int) string {
return fmt.Sprintf("HAHA%s-%dHBHB", shortcodePlaceholderPrefix, id)
}
@@ -189,7 +215,7 @@ func renderShortcode(sc shortcode, parent *ShortcodeWithPage, p *Page) string {
tmpl := getShortcodeTemplate(sc.name, p.s.Tmpl)
if tmpl == nil {
- p.s.Log.ERROR.Printf("Unable to locate template for shortcode '%s' in page %s", sc.name, p.BaseFileName())
+ p.s.Log.ERROR.Printf("Unable to locate template for shortcode '%s' in page %q", sc.name, p.Path())
return ""
}
@@ -207,8 +233,8 @@ func renderShortcode(sc shortcode, parent *ShortcodeWithPage, p *Page) string {
case shortcode:
inner += renderShortcode(innerData.(shortcode), data, p)
default:
- p.s.Log.ERROR.Printf("Illegal state on shortcode rendering of '%s' in page %s. Illegal type in inner data: %s ",
- sc.name, p.BaseFileName(), reflect.TypeOf(innerData))
+ p.s.Log.ERROR.Printf("Illegal state on shortcode rendering of %q in page %q. Illegal type in inner data: %s ",
+ sc.name, p.Path(), reflect.TypeOf(innerData))
return ""
}
}
@@ -255,22 +281,17 @@ func renderShortcode(sc shortcode, parent *ShortcodeWithPage, p *Page) string {
return renderShortcodeWithPage(tmpl, data)
}
-func extractAndRenderShortcodes(stringToParse string, p *Page) (string, map[string]func() (string, error), error) {
-
- content, shortcodes, err := extractShortcodes(stringToParse, p)
+func (s *shortcodeHandler) extractAndRenderShortcodes(stringToParse string, p *Page) (string, error) {
+ content, err := s.extractShortcodes(stringToParse, p)
if err != nil {
// try to render what we have whilst logging the error
p.s.Log.ERROR.Println(err.Error())
}
- // Save for reuse
- // TODO(bep) refactor this
- p.shortcodes = shortcodes
-
- renderedShortcodes := renderShortcodes(shortcodes, p)
+ s.contentShortCodes = renderShortcodes(s.shortcodes, p)
- return content, renderedShortcodes, err
+ return content, err
}
@@ -311,7 +332,7 @@ var errShortCodeIllegalState = errors.New("Illegal shortcode state")
// pageTokens state:
// - before: positioned just before the shortcode start
// - after: shortcode(s) consumed (plural when they are nested)
-func extractShortcode(pt *pageTokens, p *Page) (shortcode, error) {
+func (s *shortcodeHandler) extractShortcode(pt *pageTokens, p *Page) (shortcode, error) {
sc := shortcode{}
var isInner = false
@@ -332,7 +353,10 @@ Loop:
if cnt > 0 {
// nested shortcode; append it to inner content
pt.backup3(currItem, next)
- nested, err := extractShortcode(pt, p)
+ nested, err := s.extractShortcode(pt, p)
+ if nested.name != "" {
+ s.nameSet[nested.name] = true
+ }
if err == nil {
sc.inner = append(sc.inner, nested)
} else {
@@ -374,15 +398,16 @@ Loop:
case tScName:
sc.name = currItem.val
tmpl := getShortcodeTemplate(sc.name, p.s.Tmpl)
-
+ {
+ }
if tmpl == nil {
- return sc, fmt.Errorf("Unable to locate template for shortcode '%s' in page %s", sc.name, p.BaseFileName())
+ return sc, fmt.Errorf("Unable to locate template for shortcode %q in page %q", sc.name, p.Path())
}
var err error
isInner, err = isInnerShortcode(tmpl)
if err != nil {
- return sc, fmt.Errorf("Failed to handle template for shortcode '%s' for page '%s': %s", sc.name, p.BaseFileName(), err)
+ return sc, fmt.Errorf("Failed to handle template for shortcode %q for page %q: %s", sc.name, p.Path(), err)
}
case tScParam:
@@ -429,15 +454,13 @@ Loop:
return sc, nil
}
-func extractShortcodes(stringToParse string, p *Page) (string, map[string]shortcode, error) {
-
- shortCodes := make(map[string]shortcode)
+func (s *shortcodeHandler) extractShortcodes(stringToParse string, p *Page) (string, error) {
startIdx := strings.Index(stringToParse, "{{")
// short cut for docs with no shortcodes
if startIdx < 0 {
- return stringToParse, shortCodes, nil
+ return stringToParse, nil
}
// the parser takes a string;
@@ -455,7 +478,6 @@ func extractShortcodes(stringToParse string, p *Page) (string, map[string]shortc
// … it's safe to keep some "global" state
var currItem item
var currShortcode shortcode
- var err error
Loop:
for {
@@ -467,8 +489,15 @@ Loop:
case tLeftDelimScWithMarkup, tLeftDelimScNoMarkup:
// let extractShortcode handle left delim (will do so recursively)
pt.backup()
- if currShortcode, err = extractShortcode(pt, p); err != nil {
- return result.String(), shortCodes, err
+
+ currShortcode, err := s.extractShortcode(pt, p)
+
+ if currShortcode.name != "" {
+ s.nameSet[currShortcode.name] = true
+ }
+
+ if err != nil {
+ return result.String(), err
}
if currShortcode.params == nil {
@@ -477,7 +506,7 @@ Loop:
placeHolder := createShortcodePlaceholder(id)
result.WriteString(placeHolder)
- shortCodes[placeHolder] = currShortcode
+ s.shortcodes[placeHolder] = currShortcode
id++
case tEOF:
break Loop
@@ -485,11 +514,11 @@ Loop:
err := fmt.Errorf("%s:%d: %s",
p.FullFilePath(), (p.lineNumRawContentStart() + pt.lexer.lineNum() - 1), currItem)
currShortcode.err = err
- return result.String(), shortCodes, err
+ return result.String(), err
}
}
- return result.String(), shortCodes, nil
+ return result.String(), nil
}