From 85535084dea4d3e3adf1ebd08ae57b39d76e1904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Sun, 22 Apr 2018 14:07:29 +0200 Subject: hugolib: Process and render shortcodes in their order of appearance Fixes #3359 --- hugolib/shortcode.go | 69 ++++++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 32 deletions(-) (limited to 'hugolib/shortcode.go') diff --git a/hugolib/shortcode.go b/hugolib/shortcode.go index df4acba5f..933bbe44e 100644 --- a/hugolib/shortcode.go +++ b/hugolib/shortcode.go @@ -180,11 +180,11 @@ type shortcodeHandler struct { p *PageWithoutContent // This is all shortcode rendering funcs for all potential output formats. - contentShortcodes map[scKey]func() (string, error) + contentShortcodes *orderedMap // This map contains the new or changed set of shortcodes that need // to be rendered for the current output format. - contentShortcodesDelta map[scKey]func() (string, error) + contentShortcodesDelta *orderedMap // This maps the shorcode placeholders with the rendered content. // We will do (potential) partial re-rendering per output format, @@ -192,7 +192,7 @@ type shortcodeHandler struct { renderedShortcodes map[string]string // Maps the shortcodeplaceholder with the actual shortcode. - shortcodes map[string]shortcode + shortcodes *orderedMap // All the shortcode names in this set. nameSet map[string]bool @@ -216,8 +216,8 @@ func (s *shortcodeHandler) createShortcodePlaceholder() string { func newShortcodeHandler(p *Page) *shortcodeHandler { return &shortcodeHandler{ p: p.withoutContent(), - contentShortcodes: make(map[scKey]func() (string, error)), - shortcodes: make(map[string]shortcode), + contentShortcodes: newOrderedMap(), + shortcodes: newOrderedMap(), nameSet: make(map[string]bool), renderedShortcodes: make(map[string]string), } @@ -259,7 +259,7 @@ const innerNewlineRegexp = "\n" const innerCleanupRegexp = `\A

(.*)

\n\z` const innerCleanupExpand = "$1" -func prepareShortcodeForPage(placeholder string, sc shortcode, parent *ShortcodeWithPage, p *PageWithoutContent) map[scKey]func() (string, error) { +func prepareShortcodeForPage(placeholder string, sc *shortcode, parent *ShortcodeWithPage, p *PageWithoutContent) map[scKey]func() (string, error) { m := make(map[scKey]func() (string, error)) lang := p.Lang() @@ -277,7 +277,7 @@ func prepareShortcodeForPage(placeholder string, sc shortcode, parent *Shortcode func renderShortcode( tmplKey scKey, - sc shortcode, + sc *shortcode, parent *ShortcodeWithPage, p *PageWithoutContent) string { @@ -298,8 +298,8 @@ func renderShortcode( switch innerData.(type) { case string: inner += innerData.(string) - case shortcode: - inner += renderShortcode(tmplKey, innerData.(shortcode), data, p) + case *shortcode: + inner += renderShortcode(tmplKey, innerData.(*shortcode), data, p) default: 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)) @@ -363,48 +363,51 @@ func (s *shortcodeHandler) updateDelta() bool { contentShortcodes := s.contentShortcodesForOutputFormat(s.p.s.rc.Format) - if s.contentShortcodesDelta == nil || len(s.contentShortcodesDelta) == 0 { + if s.contentShortcodesDelta == nil || s.contentShortcodesDelta.Len() == 0 { s.contentShortcodesDelta = contentShortcodes return true } - delta := make(map[scKey]func() (string, error)) + delta := newOrderedMap() - for k, v := range contentShortcodes { - if _, found := s.contentShortcodesDelta[k]; !found { - delta[k] = v + for _, k := range contentShortcodes.Keys() { + if !s.contentShortcodesDelta.Contains(k) { + v, _ := contentShortcodes.Get(k) + delta.Add(k, v) } } s.contentShortcodesDelta = delta - return len(delta) > 0 + return delta.Len() > 0 } -func (s *shortcodeHandler) contentShortcodesForOutputFormat(f output.Format) map[scKey]func() (string, error) { - contentShortcodesForOuputFormat := make(map[scKey]func() (string, error)) +func (s *shortcodeHandler) contentShortcodesForOutputFormat(f output.Format) *orderedMap { + contentShortcodesForOuputFormat := newOrderedMap() lang := s.p.Lang() - for shortcodePlaceholder := range s.shortcodes { + for _, key := range s.shortcodes.Keys() { + shortcodePlaceholder := key.(string) + // shortcodePlaceholder := s.shortcodes.getShortcode(key) key := newScKeyFromLangAndOutputFormat(lang, f, shortcodePlaceholder) - renderFn, found := s.contentShortcodes[key] + renderFn, found := s.contentShortcodes.Get(key) if !found { key.OutputFormat = "" - renderFn, found = s.contentShortcodes[key] + renderFn, found = s.contentShortcodes.Get(key) } // Fall back to HTML if !found && key.Suffix != "html" { key.Suffix = "html" - renderFn, found = s.contentShortcodes[key] + renderFn, found = s.contentShortcodes.Get(key) } if !found { panic(fmt.Sprintf("Shortcode %q could not be found", shortcodePlaceholder)) } - contentShortcodesForOuputFormat[newScKeyFromLangAndOutputFormat(lang, f, shortcodePlaceholder)] = renderFn + contentShortcodesForOuputFormat.Add(newScKeyFromLangAndOutputFormat(lang, f, shortcodePlaceholder), renderFn) } return contentShortcodesForOuputFormat @@ -412,27 +415,29 @@ func (s *shortcodeHandler) contentShortcodesForOutputFormat(f output.Format) map func (s *shortcodeHandler) executeShortcodesForDelta(p *PageWithoutContent) error { - for k, render := range s.contentShortcodesDelta { + for _, k := range s.contentShortcodesDelta.Keys() { + render := s.contentShortcodesDelta.getShortcodeRenderer(k) renderedShortcode, err := render() if err != nil { return fmt.Errorf("Failed to execute shortcode in page %q: %s", p.Path(), err) } - s.renderedShortcodes[k.ShortcodePlaceholder] = renderedShortcode + s.renderedShortcodes[k.(scKey).ShortcodePlaceholder] = renderedShortcode } return nil } -func createShortcodeRenderers(shortcodes map[string]shortcode, p *PageWithoutContent) map[scKey]func() (string, error) { +func createShortcodeRenderers(shortcodes *orderedMap, p *PageWithoutContent) *orderedMap { - shortcodeRenderers := make(map[scKey]func() (string, error)) + shortcodeRenderers := newOrderedMap() - for k, v := range shortcodes { - prepared := prepareShortcodeForPage(k, v, nil, p) + for _, k := range shortcodes.Keys() { + v := shortcodes.getShortcode(k) + prepared := prepareShortcodeForPage(k.(string), v, nil, p) for kk, vv := range prepared { - shortcodeRenderers[kk] = vv + shortcodeRenderers.Add(kk, vv) } } @@ -444,8 +449,8 @@ 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 (s *shortcodeHandler) extractShortcode(pt *pageTokens, p *PageWithoutContent) (shortcode, error) { - sc := shortcode{} +func (s *shortcodeHandler) extractShortcode(pt *pageTokens, p *PageWithoutContent) (*shortcode, error) { + sc := &shortcode{} var isInner = false var currItem item @@ -616,7 +621,7 @@ Loop: placeHolder := s.createShortcodePlaceholder() result.WriteString(placeHolder) - s.shortcodes[placeHolder] = currShortcode + s.shortcodes.Add(placeHolder, currShortcode) case tEOF: break Loop case tError: -- cgit v1.2.3