2019-01-02 06:33:26 -05:00
|
|
|
// Copyright 2019 The Hugo Authors. All rights reserved.
|
2013-07-04 11:32:55 -04:00
|
|
|
//
|
2015-11-23 22:16:36 -05:00
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
2013-07-04 11:32:55 -04:00
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
2015-11-23 22:16:36 -05:00
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
2013-07-04 11:32:55 -04:00
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package hugolib
|
|
|
|
|
|
|
|
import (
|
2015-06-21 07:08:30 -04:00
|
|
|
"bytes"
|
2023-02-11 10:20:24 -05:00
|
|
|
"context"
|
2023-10-25 05:31:01 -04:00
|
|
|
"errors"
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
"fmt"
|
2020-12-02 07:23:25 -05:00
|
|
|
"html/template"
|
|
|
|
"path"
|
|
|
|
"reflect"
|
|
|
|
"regexp"
|
|
|
|
"sort"
|
2019-01-02 06:33:26 -05:00
|
|
|
"strconv"
|
2020-12-02 07:23:25 -05:00
|
|
|
"strings"
|
|
|
|
"sync"
|
2019-01-02 06:33:26 -05:00
|
|
|
|
2018-11-26 05:01:27 -05:00
|
|
|
"github.com/gohugoio/hugo/common/herrors"
|
2018-10-21 06:20:21 -04:00
|
|
|
|
2018-10-17 06:57:09 -04:00
|
|
|
"github.com/gohugoio/hugo/parser/pageparser"
|
2019-01-02 06:33:26 -05:00
|
|
|
"github.com/gohugoio/hugo/resources/page"
|
2018-10-17 06:57:09 -04:00
|
|
|
|
2018-07-06 08:12:10 -04:00
|
|
|
"github.com/gohugoio/hugo/common/maps"
|
2018-11-01 06:28:30 -04:00
|
|
|
"github.com/gohugoio/hugo/common/text"
|
|
|
|
"github.com/gohugoio/hugo/common/urls"
|
2017-06-13 12:42:45 -04:00
|
|
|
"github.com/gohugoio/hugo/output"
|
2017-05-06 14:15:28 -04:00
|
|
|
|
2017-06-13 12:42:45 -04:00
|
|
|
bp "github.com/gohugoio/hugo/bufferpool"
|
|
|
|
"github.com/gohugoio/hugo/tpl"
|
2014-03-31 13:23:34 -04:00
|
|
|
)
|
2013-07-04 11:32:55 -04:00
|
|
|
|
2018-11-01 06:28:30 -04:00
|
|
|
var (
|
|
|
|
_ urls.RefLinker = (*ShortcodeWithPage)(nil)
|
2019-01-02 06:33:26 -05:00
|
|
|
_ pageWrapper = (*ShortcodeWithPage)(nil)
|
2018-11-01 06:28:30 -04:00
|
|
|
_ text.Positioner = (*ShortcodeWithPage)(nil)
|
|
|
|
)
|
|
|
|
|
2016-03-24 09:11:04 -04:00
|
|
|
// ShortcodeWithPage is the "." context in a shortcode template.
|
2013-07-04 11:32:55 -04:00
|
|
|
type ShortcodeWithPage struct {
|
2022-03-17 17:03:27 -04:00
|
|
|
Params any
|
2015-11-20 19:59:54 -05:00
|
|
|
Inner template.HTML
|
2019-01-02 06:33:26 -05:00
|
|
|
Page page.Page
|
2016-03-08 14:56:24 -05:00
|
|
|
Parent *ShortcodeWithPage
|
2018-12-21 03:51:15 -05:00
|
|
|
Name string
|
2015-11-20 19:59:54 -05:00
|
|
|
IsNamedParams bool
|
2018-04-23 02:09:56 -04:00
|
|
|
|
2018-05-27 15:34:05 -04:00
|
|
|
// Zero-based ordinal in relation to its parent. If the parent is the page itself,
|
|
|
|
// this ordinal will represent the position of this shortcode in the page content.
|
2018-04-23 02:09:56 -04:00
|
|
|
Ordinal int
|
|
|
|
|
2022-05-30 14:42:46 -04:00
|
|
|
// Indentation before the opening shortcode in the source.
|
|
|
|
indentation string
|
|
|
|
|
|
|
|
innerDeindentInit sync.Once
|
|
|
|
innerDeindent template.HTML
|
|
|
|
|
2018-11-01 05:39:44 -04:00
|
|
|
// pos is the position in bytes in the source file. Used for error logging.
|
|
|
|
posInit sync.Once
|
|
|
|
posOffset int
|
2018-11-01 06:28:30 -04:00
|
|
|
pos text.Position
|
2018-11-01 05:39:44 -04:00
|
|
|
|
2018-07-06 08:12:10 -04:00
|
|
|
scratch *maps.Scratch
|
2013-07-04 11:32:55 -04:00
|
|
|
}
|
|
|
|
|
2022-05-30 14:42:46 -04:00
|
|
|
// InnerDeindent returns the (potentially de-indented) inner content of the shortcode.
|
|
|
|
func (scp *ShortcodeWithPage) InnerDeindent() template.HTML {
|
|
|
|
if scp.indentation == "" {
|
|
|
|
return scp.Inner
|
|
|
|
}
|
|
|
|
scp.innerDeindentInit.Do(func() {
|
|
|
|
b := bp.GetBuffer()
|
|
|
|
text.VisitLinesAfter(string(scp.Inner), func(s string) {
|
|
|
|
if strings.HasPrefix(s, scp.indentation) {
|
|
|
|
b.WriteString(strings.TrimPrefix(s, scp.indentation))
|
|
|
|
} else {
|
|
|
|
b.WriteString(s)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
scp.innerDeindent = template.HTML(b.String())
|
|
|
|
bp.PutBuffer(b)
|
|
|
|
})
|
|
|
|
|
|
|
|
return scp.innerDeindent
|
|
|
|
}
|
|
|
|
|
2018-11-01 05:39:44 -04:00
|
|
|
// Position returns this shortcode's detailed position. Note that this information
|
|
|
|
// may be expensive to calculate, so only use this in error situations.
|
2018-11-01 06:28:30 -04:00
|
|
|
func (scp *ShortcodeWithPage) Position() text.Position {
|
2018-11-01 05:39:44 -04:00
|
|
|
scp.posInit.Do(func() {
|
2019-01-02 06:33:26 -05:00
|
|
|
if p, ok := mustUnwrapPage(scp.Page).(pageContext); ok {
|
|
|
|
scp.pos = p.posOffset(scp.posOffset)
|
|
|
|
}
|
2018-11-01 05:39:44 -04:00
|
|
|
})
|
|
|
|
return scp.pos
|
|
|
|
}
|
|
|
|
|
2016-03-24 09:11:04 -04:00
|
|
|
// Site returns information about the current site.
|
2019-01-02 06:33:26 -05:00
|
|
|
func (scp *ShortcodeWithPage) Site() page.Site {
|
|
|
|
return scp.Page.Site()
|
2016-03-14 09:10:15 -04:00
|
|
|
}
|
|
|
|
|
2018-11-01 06:28:30 -04:00
|
|
|
// Ref is a shortcut to the Ref method on Page. It passes itself as a context
|
|
|
|
// to get better error messages.
|
2022-03-17 17:03:27 -04:00
|
|
|
func (scp *ShortcodeWithPage) Ref(args map[string]any) (string, error) {
|
2019-01-02 06:33:26 -05:00
|
|
|
return scp.Page.RefFrom(args, scp)
|
Provide (relative) reference funcs & shortcodes.
- `.Ref` and `.RelRef` take a reference (the logical filename for a
page, including extension and/or a document fragment ID) and return
a permalink (or relative permalink) to the referenced document.
- If the reference is a page name (such as `about.md`), the page
will be discovered and the permalink will be returned: `/about/`
- If the reference is a page name with a fragment (such as
`about.md#who`), the page will be discovered and used to add the
`page.UniqueID()` to the resulting fragment and permalink:
`/about/#who:deadbeef`.
- If the reference is a fragment and `.*Ref` has been called from
a `Node` or `SiteInfo`, it will be returned as is: `#who`.
- If the reference is a fragment and `.*Ref` has been called from
a `Page`, it will be returned with the page’s unique ID:
`#who:deadbeef`.
- `.*Ref` can be called from either `Node`, `SiteInfo` (e.g.,
`Node.Site`), `Page` objects, or `ShortcodeWithPage` objects in
templates.
- `.*Ref` cannot be used in content, so two shortcodes have been
created to provide the functionality to content: `ref` and `relref`.
These are intended to be used within markup, like `[Who]({{% ref
about.md#who %}})` or `<a href="{{% ref about.md#who %}}">Who</a>`.
- There are also `ref` and `relref` template functions (used to create
the shortcodes) that expect a `Page` or `Node` object and the
reference string (e.g., `{{ relref . "about.md" }}` or `{{
"about.md" | ref . }}`). It actually looks for `.*Ref` as defined on
`Node` or `Page` objects.
- Shortcode handling had to use a *differently unique* wrapper in
`createShortcodePlaceholder` because of the way that the `ref` and
`relref` are intended to be used in content.
2014-11-24 01:15:34 -05:00
|
|
|
}
|
|
|
|
|
2018-11-01 06:28:30 -04:00
|
|
|
// RelRef is a shortcut to the RelRef method on Page. It passes itself as a context
|
|
|
|
// to get better error messages.
|
2022-03-17 17:03:27 -04:00
|
|
|
func (scp *ShortcodeWithPage) RelRef(args map[string]any) (string, error) {
|
2019-01-02 06:33:26 -05:00
|
|
|
return scp.Page.RelRefFrom(args, scp)
|
Provide (relative) reference funcs & shortcodes.
- `.Ref` and `.RelRef` take a reference (the logical filename for a
page, including extension and/or a document fragment ID) and return
a permalink (or relative permalink) to the referenced document.
- If the reference is a page name (such as `about.md`), the page
will be discovered and the permalink will be returned: `/about/`
- If the reference is a page name with a fragment (such as
`about.md#who`), the page will be discovered and used to add the
`page.UniqueID()` to the resulting fragment and permalink:
`/about/#who:deadbeef`.
- If the reference is a fragment and `.*Ref` has been called from
a `Node` or `SiteInfo`, it will be returned as is: `#who`.
- If the reference is a fragment and `.*Ref` has been called from
a `Page`, it will be returned with the page’s unique ID:
`#who:deadbeef`.
- `.*Ref` can be called from either `Node`, `SiteInfo` (e.g.,
`Node.Site`), `Page` objects, or `ShortcodeWithPage` objects in
templates.
- `.*Ref` cannot be used in content, so two shortcodes have been
created to provide the functionality to content: `ref` and `relref`.
These are intended to be used within markup, like `[Who]({{% ref
about.md#who %}})` or `<a href="{{% ref about.md#who %}}">Who</a>`.
- There are also `ref` and `relref` template functions (used to create
the shortcodes) that expect a `Page` or `Node` object and the
reference string (e.g., `{{ relref . "about.md" }}` or `{{
"about.md" | ref . }}`). It actually looks for `.*Ref` as defined on
`Node` or `Page` objects.
- Shortcode handling had to use a *differently unique* wrapper in
`createShortcodePlaceholder` because of the way that the `ref` and
`relref` are intended to be used in content.
2014-11-24 01:15:34 -05:00
|
|
|
}
|
|
|
|
|
2016-03-24 09:11:04 -04:00
|
|
|
// Scratch returns a scratch-pad scoped for this shortcode. This can be used
|
|
|
|
// as a temporary storage for variables, counters etc.
|
2018-07-06 08:12:10 -04:00
|
|
|
func (scp *ShortcodeWithPage) Scratch() *maps.Scratch {
|
2016-03-21 06:10:57 -04:00
|
|
|
if scp.scratch == nil {
|
2018-07-06 08:12:10 -04:00
|
|
|
scp.scratch = maps.NewScratch()
|
2016-03-21 06:10:57 -04:00
|
|
|
}
|
|
|
|
return scp.scratch
|
2015-04-19 08:50:24 -04:00
|
|
|
}
|
|
|
|
|
2016-03-24 09:11:04 -04:00
|
|
|
// Get is a convenience method to look up shortcode parameters by its key.
|
2022-03-17 17:03:27 -04:00
|
|
|
func (scp *ShortcodeWithPage) Get(key any) any {
|
2016-07-21 11:18:55 -04:00
|
|
|
if scp.Params == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2014-02-25 23:57:31 -05:00
|
|
|
if reflect.ValueOf(scp.Params).Len() == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var x reflect.Value
|
|
|
|
|
|
|
|
switch key.(type) {
|
|
|
|
case int64, int32, int16, int8, int:
|
|
|
|
if reflect.TypeOf(scp.Params).Kind() == reflect.Map {
|
2018-05-21 11:47:52 -04:00
|
|
|
// We treat this as a non error, so people can do similar to
|
|
|
|
// {{ $myParam := .Get "myParam" | default .Get 0 }}
|
|
|
|
// Without having to do additional checks.
|
|
|
|
return nil
|
2014-02-25 23:57:31 -05:00
|
|
|
} else if reflect.TypeOf(scp.Params).Kind() == reflect.Slice {
|
2015-08-07 13:21:26 -04:00
|
|
|
idx := int(reflect.ValueOf(key).Int())
|
|
|
|
ln := reflect.ValueOf(scp.Params).Len()
|
|
|
|
if idx > ln-1 {
|
2018-04-17 05:24:03 -04:00
|
|
|
return ""
|
2015-08-07 13:21:26 -04:00
|
|
|
}
|
|
|
|
x = reflect.ValueOf(scp.Params).Index(idx)
|
2014-02-25 23:57:31 -05:00
|
|
|
}
|
|
|
|
case string:
|
|
|
|
if reflect.TypeOf(scp.Params).Kind() == reflect.Map {
|
|
|
|
x = reflect.ValueOf(scp.Params).MapIndex(reflect.ValueOf(key))
|
|
|
|
if !x.IsValid() {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
} else if reflect.TypeOf(scp.Params).Kind() == reflect.Slice {
|
2018-05-21 11:47:52 -04:00
|
|
|
// We treat this as a non error, so people can do similar to
|
|
|
|
// {{ $myParam := .Get "myParam" | default .Get 0 }}
|
|
|
|
// Without having to do additional checks.
|
|
|
|
return nil
|
2014-02-25 23:57:31 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-29 08:51:51 -04:00
|
|
|
return x.Interface()
|
2014-02-25 23:57:31 -05:00
|
|
|
}
|
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
func (scp *ShortcodeWithPage) page() page.Page {
|
|
|
|
return scp.Page
|
2018-11-01 06:28:30 -04:00
|
|
|
}
|
|
|
|
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
// Note - this value must not contain any markup syntax
|
2019-01-02 06:33:26 -05:00
|
|
|
const shortcodePlaceholderPrefix = "HAHAHUGOSHORTCODE"
|
|
|
|
|
2023-08-01 12:12:36 -04:00
|
|
|
func createShortcodePlaceholder(sid string, id, ordinal int) string {
|
|
|
|
return shortcodePlaceholderPrefix + strconv.Itoa(id) + sid + strconv.Itoa(ordinal) + "HBHB"
|
2019-01-02 06:33:26 -05:00
|
|
|
}
|
2013-07-04 11:32:55 -04:00
|
|
|
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
type shortcode struct {
|
2018-11-26 05:01:27 -05:00
|
|
|
name string
|
2022-03-17 17:03:27 -04:00
|
|
|
isInline bool // inline shortcode. Any inner will be a Go template.
|
|
|
|
isClosing bool // whether a closing tag was provided
|
|
|
|
inner []any // string or nested shortcode
|
|
|
|
params any // map or array
|
2018-11-26 05:01:27 -05:00
|
|
|
ordinal int
|
|
|
|
err error
|
2019-01-02 06:33:26 -05:00
|
|
|
|
2022-05-28 07:18:50 -04:00
|
|
|
indentation string // indentation from source.
|
|
|
|
|
2020-07-03 12:02:32 -04:00
|
|
|
info tpl.Info // One of the output formats (arbitrary)
|
|
|
|
templs []tpl.Template // All output formats
|
2019-01-02 06:33:26 -05:00
|
|
|
|
|
|
|
// If set, the rendered shortcode is sent as part of the surrounding content
|
2022-05-28 05:01:47 -04:00
|
|
|
// to Goldmark and similar.
|
2019-01-02 06:33:26 -05:00
|
|
|
// Before Hug0 0.55 we didn't send any shortcode output to the markup
|
|
|
|
// renderer, and this flag told Hugo to process the {{ .Inner }} content
|
|
|
|
// separately.
|
|
|
|
// The old behaviour can be had by starting your shortcode template with:
|
|
|
|
// {{ $_hugo_config := `{ "version": 1 }`}}
|
|
|
|
doMarkup bool
|
|
|
|
|
2022-05-28 05:01:47 -04:00
|
|
|
// the placeholder in the source when passed to Goldmark etc.
|
2019-01-02 06:33:26 -05:00
|
|
|
// This also identifies the rendered shortcode.
|
|
|
|
placeholder string
|
|
|
|
|
|
|
|
pos int // the position in bytes in the source file
|
|
|
|
length int // the length in bytes in the source file
|
2013-07-04 11:32:55 -04:00
|
|
|
}
|
|
|
|
|
2019-04-24 08:05:37 -04:00
|
|
|
func (s shortcode) insertPlaceholder() bool {
|
2019-12-28 06:07:23 -05:00
|
|
|
return !s.doMarkup || s.configVersion() == 1
|
|
|
|
}
|
|
|
|
|
2023-02-23 02:08:17 -05:00
|
|
|
func (s shortcode) needsInner() bool {
|
|
|
|
return s.info != nil && s.info.ParseInfo().IsInner
|
|
|
|
}
|
|
|
|
|
2019-12-28 06:07:23 -05:00
|
|
|
func (s shortcode) configVersion() int {
|
|
|
|
if s.info == nil {
|
|
|
|
// Not set for inline shortcodes.
|
|
|
|
return 2
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.info.ParseInfo().Config.Version
|
2019-04-24 08:05:37 -04:00
|
|
|
}
|
|
|
|
|
Move the emoji parsing to pageparser
This avoids double parsing the page content when `enableEmoji=true`.
This commit also adds some general improvements to the parser, making it in general much faster:
```bash
benchmark old ns/op new ns/op delta
BenchmarkShortcodeLexer-4 90258 101730 +12.71%
BenchmarkParse-4 148940 15037 -89.90%
benchmark old allocs new allocs delta
BenchmarkShortcodeLexer-4 456 700 +53.51%
BenchmarkParse-4 28 33 +17.86%
benchmark old bytes new bytes delta
BenchmarkShortcodeLexer-4 69875 81014 +15.94%
BenchmarkParse-4 8128 8304 +2.17%
```
Running some site benchmarks with Emoji support turned on:
```bash
benchmark old ns/op new ns/op delta
BenchmarkSiteBuilding/TOML,num_langs=3,num_pages=5000,tags_per_page=5,shortcodes,render-4 924556797 818115620 -11.51%
benchmark old allocs new allocs delta
BenchmarkSiteBuilding/TOML,num_langs=3,num_pages=5000,tags_per_page=5,shortcodes,render-4 4112613 4133787 +0.51%
benchmark old bytes new bytes delta
BenchmarkSiteBuilding/TOML,num_langs=3,num_pages=5000,tags_per_page=5,shortcodes,render-4 426982864 424363832 -0.61%
```
Fixes #5534
2018-12-17 15:03:23 -05:00
|
|
|
func (s shortcode) innerString() string {
|
|
|
|
var sb strings.Builder
|
|
|
|
|
|
|
|
for _, inner := range s.inner {
|
|
|
|
sb.WriteString(inner.(string))
|
|
|
|
}
|
|
|
|
|
|
|
|
return sb.String()
|
|
|
|
}
|
|
|
|
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
func (sc shortcode) String() string {
|
|
|
|
// for testing (mostly), so any change here will break tests!
|
2022-03-17 17:03:27 -04:00
|
|
|
var params any
|
2014-11-18 04:20:52 -05:00
|
|
|
switch v := sc.params.(type) {
|
2022-03-17 17:03:27 -04:00
|
|
|
case map[string]any:
|
2014-11-18 04:20:52 -05:00
|
|
|
// sort the keys so test assertions won't fail
|
|
|
|
var keys []string
|
|
|
|
for k := range v {
|
|
|
|
keys = append(keys, k)
|
|
|
|
}
|
|
|
|
sort.Strings(keys)
|
2022-03-17 17:03:27 -04:00
|
|
|
tmp := make(map[string]any)
|
2014-11-18 04:20:52 -05:00
|
|
|
|
2019-09-29 08:51:51 -04:00
|
|
|
for _, k := range keys {
|
|
|
|
tmp[k] = v[k]
|
2014-11-18 04:20:52 -05:00
|
|
|
}
|
|
|
|
params = tmp
|
|
|
|
|
|
|
|
default:
|
|
|
|
// use it as is
|
|
|
|
params = sc.params
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Sprintf("%s(%q, %t){%s}", sc.name, params, sc.doMarkup, sc.inner)
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
}
|
2013-12-06 23:14:54 -05:00
|
|
|
|
2017-03-10 14:54:50 -05:00
|
|
|
type shortcodeHandler struct {
|
2019-01-02 06:33:26 -05:00
|
|
|
p *pageState
|
2017-05-06 14:15:28 -04:00
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
s *Site
|
2017-05-06 14:15:28 -04:00
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
// Ordered list of shortcodes for a page.
|
|
|
|
shortcodes []*shortcode
|
2017-03-10 14:54:50 -05:00
|
|
|
|
|
|
|
// All the shortcode names in this set.
|
2022-05-29 10:41:57 -04:00
|
|
|
nameSet map[string]bool
|
|
|
|
nameSetMu sync.RWMutex
|
2018-04-19 12:06:40 -04:00
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
// Configuration
|
2018-11-26 05:01:27 -05:00
|
|
|
enableInlineShortcodes bool
|
2018-04-19 12:06:40 -04:00
|
|
|
}
|
|
|
|
|
2022-05-29 10:41:57 -04:00
|
|
|
func newShortcodeHandler(p *pageState, s *Site) *shortcodeHandler {
|
2019-01-02 06:33:26 -05:00
|
|
|
sh := &shortcodeHandler{
|
|
|
|
p: p,
|
|
|
|
s: s,
|
2021-12-12 06:11:11 -05:00
|
|
|
enableInlineShortcodes: s.ExecHelper.Sec().EnableInlineShortcodes,
|
2019-01-02 06:33:26 -05:00
|
|
|
shortcodes: make([]*shortcode, 0, 4),
|
2018-11-26 05:01:27 -05:00
|
|
|
nameSet: make(map[string]bool),
|
2014-06-26 16:47:51 -04:00
|
|
|
}
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
return sh
|
2017-03-10 14:54:50 -05:00
|
|
|
}
|
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
const (
|
|
|
|
innerNewlineRegexp = "\n"
|
|
|
|
innerCleanupRegexp = `\A<p>(.*)</p>\n\z`
|
|
|
|
innerCleanupExpand = "$1"
|
|
|
|
)
|
2014-02-25 23:57:31 -05:00
|
|
|
|
2023-02-11 10:20:24 -05:00
|
|
|
func prepareShortcode(
|
|
|
|
ctx context.Context,
|
2019-01-02 06:33:26 -05:00
|
|
|
level int,
|
|
|
|
s *Site,
|
|
|
|
tplVariants tpl.TemplateVariants,
|
2018-04-22 08:07:29 -04:00
|
|
|
sc *shortcode,
|
2017-05-06 14:15:28 -04:00
|
|
|
parent *ShortcodeWithPage,
|
2023-10-25 05:31:01 -04:00
|
|
|
p *pageState,
|
|
|
|
) (shortcodeRenderer, error) {
|
2023-02-11 10:20:24 -05:00
|
|
|
toParseErr := func(err error) error {
|
|
|
|
return p.parseError(fmt.Errorf("failed to render shortcode %q: %w", sc.name, err), p.source.parsed.Input(), sc.pos)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allow the caller to delay the rendering of the shortcode if needed.
|
|
|
|
var fn shortcodeRenderFunc = func(ctx context.Context) ([]byte, bool, error) {
|
|
|
|
r, err := doRenderShortcode(ctx, level, s, tplVariants, sc, parent, p)
|
|
|
|
if err != nil {
|
|
|
|
return nil, false, toParseErr(err)
|
|
|
|
}
|
|
|
|
b, hasVariants, err := r.renderShortcode(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, false, toParseErr(err)
|
|
|
|
}
|
|
|
|
return b, hasVariants, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return fn, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func doRenderShortcode(
|
|
|
|
ctx context.Context,
|
|
|
|
level int,
|
|
|
|
s *Site,
|
|
|
|
tplVariants tpl.TemplateVariants,
|
|
|
|
sc *shortcode,
|
|
|
|
parent *ShortcodeWithPage,
|
2023-10-25 05:31:01 -04:00
|
|
|
p *pageState,
|
|
|
|
) (shortcodeRenderer, error) {
|
2018-11-26 05:01:27 -05:00
|
|
|
var tmpl tpl.Template
|
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
// Tracks whether this shortcode or any of its children has template variations
|
|
|
|
// in other languages or output formats. We are currently only interested in
|
|
|
|
// the output formats, so we may get some false positives -- we
|
|
|
|
// should improve on that.
|
|
|
|
var hasVariants bool
|
|
|
|
|
2018-11-26 05:01:27 -05:00
|
|
|
if sc.isInline {
|
2021-12-12 06:11:11 -05:00
|
|
|
if !p.s.ExecHelper.Sec().EnableInlineShortcodes {
|
2023-02-11 10:20:24 -05:00
|
|
|
return zeroShortcode, nil
|
2019-01-31 05:53:21 -05:00
|
|
|
}
|
2019-01-02 06:33:26 -05:00
|
|
|
templName := path.Join("_inline_shortcode", p.File().Path(), sc.name)
|
2018-11-26 05:01:27 -05:00
|
|
|
if sc.isClosing {
|
Move the emoji parsing to pageparser
This avoids double parsing the page content when `enableEmoji=true`.
This commit also adds some general improvements to the parser, making it in general much faster:
```bash
benchmark old ns/op new ns/op delta
BenchmarkShortcodeLexer-4 90258 101730 +12.71%
BenchmarkParse-4 148940 15037 -89.90%
benchmark old allocs new allocs delta
BenchmarkShortcodeLexer-4 456 700 +53.51%
BenchmarkParse-4 28 33 +17.86%
benchmark old bytes new bytes delta
BenchmarkShortcodeLexer-4 69875 81014 +15.94%
BenchmarkParse-4 8128 8304 +2.17%
```
Running some site benchmarks with Emoji support turned on:
```bash
benchmark old ns/op new ns/op delta
BenchmarkSiteBuilding/TOML,num_langs=3,num_pages=5000,tags_per_page=5,shortcodes,render-4 924556797 818115620 -11.51%
benchmark old allocs new allocs delta
BenchmarkSiteBuilding/TOML,num_langs=3,num_pages=5000,tags_per_page=5,shortcodes,render-4 4112613 4133787 +0.51%
benchmark old bytes new bytes delta
BenchmarkSiteBuilding/TOML,num_langs=3,num_pages=5000,tags_per_page=5,shortcodes,render-4 426982864 424363832 -0.61%
```
Fixes #5534
2018-12-17 15:03:23 -05:00
|
|
|
templStr := sc.innerString()
|
2018-11-26 05:01:27 -05:00
|
|
|
|
|
|
|
var err error
|
2020-01-15 09:59:56 -05:00
|
|
|
tmpl, err = s.TextTmpl().Parse(templName, templStr)
|
2018-11-26 05:01:27 -05:00
|
|
|
if err != nil {
|
2022-05-15 05:40:34 -04:00
|
|
|
fe := herrors.NewFileErrorFromName(err, p.File().Filename())
|
2022-05-02 10:07:52 -04:00
|
|
|
pos := fe.Position()
|
|
|
|
pos.LineNumber += p.posOffset(sc.pos).LineNumber
|
|
|
|
fe = fe.UpdatePosition(pos)
|
2023-02-11 10:20:24 -05:00
|
|
|
return zeroShortcode, p.wrapError(fe)
|
2018-11-26 05:01:27 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Re-use of shortcode defined earlier in the same page.
|
|
|
|
var found bool
|
2020-01-15 09:59:56 -05:00
|
|
|
tmpl, found = s.TextTmpl().Lookup(templName)
|
2018-11-26 05:01:27 -05:00
|
|
|
if !found {
|
2023-02-11 10:20:24 -05:00
|
|
|
return zeroShortcode, fmt.Errorf("no earlier definition of shortcode %q found", sc.name)
|
2018-11-26 05:01:27 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2019-01-02 06:33:26 -05:00
|
|
|
var found, more bool
|
2020-01-15 09:59:56 -05:00
|
|
|
tmpl, found, more = s.Tmpl().LookupVariant(sc.name, tplVariants)
|
2019-01-02 06:33:26 -05:00
|
|
|
if !found {
|
2020-10-21 05:17:48 -04:00
|
|
|
s.Log.Errorf("Unable to locate template for shortcode %q in page %q", sc.name, p.File().Path())
|
2023-02-11 10:20:24 -05:00
|
|
|
return zeroShortcode, nil
|
2019-01-02 06:33:26 -05:00
|
|
|
}
|
|
|
|
hasVariants = hasVariants || more
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
}
|
2014-02-25 23:57:31 -05:00
|
|
|
|
2022-05-30 14:42:46 -04:00
|
|
|
data := &ShortcodeWithPage{Ordinal: sc.ordinal, posOffset: sc.pos, indentation: sc.indentation, Params: sc.params, Page: newPageForShortcode(p), Parent: parent, Name: sc.name}
|
2015-11-20 19:59:54 -05:00
|
|
|
if sc.params != nil {
|
|
|
|
data.IsNamedParams = reflect.TypeOf(sc.params).Kind() == reflect.Map
|
|
|
|
}
|
|
|
|
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
if len(sc.inner) > 0 {
|
|
|
|
var inner string
|
|
|
|
for _, innerData := range sc.inner {
|
2019-01-02 06:33:26 -05:00
|
|
|
switch innerData := innerData.(type) {
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
case string:
|
2019-01-02 06:33:26 -05:00
|
|
|
inner += innerData
|
2018-04-22 08:07:29 -04:00
|
|
|
case *shortcode:
|
2023-02-11 10:20:24 -05:00
|
|
|
s, err := prepareShortcode(ctx, level+1, s, tplVariants, innerData, data, p)
|
2018-10-03 08:58:09 -04:00
|
|
|
if err != nil {
|
2023-02-11 10:20:24 -05:00
|
|
|
return zeroShortcode, err
|
2018-10-03 08:58:09 -04:00
|
|
|
}
|
2023-02-11 10:20:24 -05:00
|
|
|
ss, more, err := s.renderShortcodeString(ctx)
|
2019-01-02 06:33:26 -05:00
|
|
|
hasVariants = hasVariants || more
|
2023-02-11 10:20:24 -05:00
|
|
|
if err != nil {
|
|
|
|
return zeroShortcode, err
|
|
|
|
}
|
|
|
|
inner += ss
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
default:
|
2020-10-21 05:17:48 -04:00
|
|
|
s.Log.Errorf("Illegal state on shortcode rendering of %q in page %q. Illegal type in inner data: %s ",
|
2019-01-02 06:33:26 -05:00
|
|
|
sc.name, p.File().Path(), reflect.TypeOf(innerData))
|
2023-02-11 10:20:24 -05:00
|
|
|
return zeroShortcode, nil
|
2014-02-25 23:57:31 -05:00
|
|
|
}
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
}
|
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
// Pre Hugo 0.55 this was the behaviour even for the outer-most
|
|
|
|
// shortcode.
|
2019-12-28 06:07:23 -05:00
|
|
|
if sc.doMarkup && (level > 0 || sc.configVersion() == 1) {
|
2019-08-16 09:55:03 -04:00
|
|
|
var err error
|
2023-02-24 01:23:10 -05:00
|
|
|
b, err := p.pageOutput.contentRenderer.ParseAndRenderContent(ctx, []byte(inner), false)
|
2019-08-16 09:55:03 -04:00
|
|
|
if err != nil {
|
2023-02-11 10:20:24 -05:00
|
|
|
return zeroShortcode, err
|
2019-08-16 09:55:03 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
newInner := b.Bytes()
|
Provide (relative) reference funcs & shortcodes.
- `.Ref` and `.RelRef` take a reference (the logical filename for a
page, including extension and/or a document fragment ID) and return
a permalink (or relative permalink) to the referenced document.
- If the reference is a page name (such as `about.md`), the page
will be discovered and the permalink will be returned: `/about/`
- If the reference is a page name with a fragment (such as
`about.md#who`), the page will be discovered and used to add the
`page.UniqueID()` to the resulting fragment and permalink:
`/about/#who:deadbeef`.
- If the reference is a fragment and `.*Ref` has been called from
a `Node` or `SiteInfo`, it will be returned as is: `#who`.
- If the reference is a fragment and `.*Ref` has been called from
a `Page`, it will be returned with the page’s unique ID:
`#who:deadbeef`.
- `.*Ref` can be called from either `Node`, `SiteInfo` (e.g.,
`Node.Site`), `Page` objects, or `ShortcodeWithPage` objects in
templates.
- `.*Ref` cannot be used in content, so two shortcodes have been
created to provide the functionality to content: `ref` and `relref`.
These are intended to be used within markup, like `[Who]({{% ref
about.md#who %}})` or `<a href="{{% ref about.md#who %}}">Who</a>`.
- There are also `ref` and `relref` template functions (used to create
the shortcodes) that expect a `Page` or `Node` object and the
reference string (e.g., `{{ relref . "about.md" }}` or `{{
"about.md" | ref . }}`). It actually looks for `.*Ref` as defined on
`Node` or `Page` objects.
- Shortcode handling had to use a *differently unique* wrapper in
`createShortcodePlaceholder` because of the way that the `ref` and
`relref` are intended to be used in content.
2014-11-24 01:15:34 -05:00
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
// If the type is “” (unknown) or “markdown”, we assume the markdown
|
Provide (relative) reference funcs & shortcodes.
- `.Ref` and `.RelRef` take a reference (the logical filename for a
page, including extension and/or a document fragment ID) and return
a permalink (or relative permalink) to the referenced document.
- If the reference is a page name (such as `about.md`), the page
will be discovered and the permalink will be returned: `/about/`
- If the reference is a page name with a fragment (such as
`about.md#who`), the page will be discovered and used to add the
`page.UniqueID()` to the resulting fragment and permalink:
`/about/#who:deadbeef`.
- If the reference is a fragment and `.*Ref` has been called from
a `Node` or `SiteInfo`, it will be returned as is: `#who`.
- If the reference is a fragment and `.*Ref` has been called from
a `Page`, it will be returned with the page’s unique ID:
`#who:deadbeef`.
- `.*Ref` can be called from either `Node`, `SiteInfo` (e.g.,
`Node.Site`), `Page` objects, or `ShortcodeWithPage` objects in
templates.
- `.*Ref` cannot be used in content, so two shortcodes have been
created to provide the functionality to content: `ref` and `relref`.
These are intended to be used within markup, like `[Who]({{% ref
about.md#who %}})` or `<a href="{{% ref about.md#who %}}">Who</a>`.
- There are also `ref` and `relref` template functions (used to create
the shortcodes) that expect a `Page` or `Node` object and the
reference string (e.g., `{{ relref . "about.md" }}` or `{{
"about.md" | ref . }}`). It actually looks for `.*Ref` as defined on
`Node` or `Page` objects.
- Shortcode handling had to use a *differently unique* wrapper in
`createShortcodePlaceholder` because of the way that the `ref` and
`relref` are intended to be used in content.
2014-11-24 01:15:34 -05:00
|
|
|
// generation has been performed. Given the input: `a line`, markdown
|
|
|
|
// specifies the HTML `<p>a line</p>\n`. When dealing with documents as a
|
|
|
|
// whole, this is OK. When dealing with an `{{ .Inner }}` block in Hugo,
|
|
|
|
// this is not so good. This code does two things:
|
|
|
|
//
|
|
|
|
// 1. Check to see if inner has a newline in it. If so, the Inner data is
|
|
|
|
// unchanged.
|
|
|
|
// 2 If inner does not have a newline, strip the wrapping <p> block and
|
2019-01-02 06:33:26 -05:00
|
|
|
// the newline.
|
|
|
|
switch p.m.markup {
|
|
|
|
case "", "markdown":
|
Provide (relative) reference funcs & shortcodes.
- `.Ref` and `.RelRef` take a reference (the logical filename for a
page, including extension and/or a document fragment ID) and return
a permalink (or relative permalink) to the referenced document.
- If the reference is a page name (such as `about.md`), the page
will be discovered and the permalink will be returned: `/about/`
- If the reference is a page name with a fragment (such as
`about.md#who`), the page will be discovered and used to add the
`page.UniqueID()` to the resulting fragment and permalink:
`/about/#who:deadbeef`.
- If the reference is a fragment and `.*Ref` has been called from
a `Node` or `SiteInfo`, it will be returned as is: `#who`.
- If the reference is a fragment and `.*Ref` has been called from
a `Page`, it will be returned with the page’s unique ID:
`#who:deadbeef`.
- `.*Ref` can be called from either `Node`, `SiteInfo` (e.g.,
`Node.Site`), `Page` objects, or `ShortcodeWithPage` objects in
templates.
- `.*Ref` cannot be used in content, so two shortcodes have been
created to provide the functionality to content: `ref` and `relref`.
These are intended to be used within markup, like `[Who]({{% ref
about.md#who %}})` or `<a href="{{% ref about.md#who %}}">Who</a>`.
- There are also `ref` and `relref` template functions (used to create
the shortcodes) that expect a `Page` or `Node` object and the
reference string (e.g., `{{ relref . "about.md" }}` or `{{
"about.md" | ref . }}`). It actually looks for `.*Ref` as defined on
`Node` or `Page` objects.
- Shortcode handling had to use a *differently unique* wrapper in
`createShortcodePlaceholder` because of the way that the `ref` and
`relref` are intended to be used in content.
2014-11-24 01:15:34 -05:00
|
|
|
if match, _ := regexp.MatchString(innerNewlineRegexp, inner); !match {
|
|
|
|
cleaner, err := regexp.Compile(innerCleanupRegexp)
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
newInner = cleaner.ReplaceAll(newInner, []byte(innerCleanupExpand))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-06 14:15:28 -04:00
|
|
|
// TODO(bep) we may have plain text inner templates.
|
Provide (relative) reference funcs & shortcodes.
- `.Ref` and `.RelRef` take a reference (the logical filename for a
page, including extension and/or a document fragment ID) and return
a permalink (or relative permalink) to the referenced document.
- If the reference is a page name (such as `about.md`), the page
will be discovered and the permalink will be returned: `/about/`
- If the reference is a page name with a fragment (such as
`about.md#who`), the page will be discovered and used to add the
`page.UniqueID()` to the resulting fragment and permalink:
`/about/#who:deadbeef`.
- If the reference is a fragment and `.*Ref` has been called from
a `Node` or `SiteInfo`, it will be returned as is: `#who`.
- If the reference is a fragment and `.*Ref` has been called from
a `Page`, it will be returned with the page’s unique ID:
`#who:deadbeef`.
- `.*Ref` can be called from either `Node`, `SiteInfo` (e.g.,
`Node.Site`), `Page` objects, or `ShortcodeWithPage` objects in
templates.
- `.*Ref` cannot be used in content, so two shortcodes have been
created to provide the functionality to content: `ref` and `relref`.
These are intended to be used within markup, like `[Who]({{% ref
about.md#who %}})` or `<a href="{{% ref about.md#who %}}">Who</a>`.
- There are also `ref` and `relref` template functions (used to create
the shortcodes) that expect a `Page` or `Node` object and the
reference string (e.g., `{{ relref . "about.md" }}` or `{{
"about.md" | ref . }}`). It actually looks for `.*Ref` as defined on
`Node` or `Page` objects.
- Shortcode handling had to use a *differently unique* wrapper in
`createShortcodePlaceholder` because of the way that the `ref` and
`relref` are intended to be used in content.
2014-11-24 01:15:34 -05:00
|
|
|
data.Inner = template.HTML(newInner)
|
2014-02-25 23:57:31 -05:00
|
|
|
} else {
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
data.Inner = template.HTML(inner)
|
2014-02-25 23:57:31 -05:00
|
|
|
}
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
|
2014-02-25 23:57:31 -05:00
|
|
|
}
|
|
|
|
|
2023-02-11 10:20:24 -05:00
|
|
|
result, err := renderShortcodeWithPage(ctx, s.Tmpl(), tmpl, data)
|
2018-11-26 05:01:27 -05:00
|
|
|
|
|
|
|
if err != nil && sc.isInline {
|
2022-05-15 05:40:34 -04:00
|
|
|
fe := herrors.NewFileErrorFromName(err, p.File().Filename())
|
2022-05-02 10:07:52 -04:00
|
|
|
pos := fe.Position()
|
|
|
|
pos.LineNumber += p.posOffset(sc.pos).LineNumber
|
|
|
|
fe = fe.UpdatePosition(pos)
|
2023-02-11 10:20:24 -05:00
|
|
|
return zeroShortcode, fe
|
2018-04-23 23:57:33 -04:00
|
|
|
}
|
2017-05-06 14:15:28 -04:00
|
|
|
|
2022-05-28 07:18:50 -04:00
|
|
|
if len(sc.inner) == 0 && len(sc.indentation) > 0 {
|
|
|
|
b := bp.GetBuffer()
|
|
|
|
i := 0
|
|
|
|
text.VisitLinesAfter(result, func(line string) {
|
|
|
|
// The first line is correctly indented.
|
|
|
|
if i > 0 {
|
|
|
|
b.WriteString(sc.indentation)
|
|
|
|
}
|
|
|
|
i++
|
|
|
|
b.WriteString(line)
|
|
|
|
})
|
|
|
|
|
|
|
|
result = b.String()
|
|
|
|
bp.PutBuffer(b)
|
|
|
|
}
|
|
|
|
|
2023-02-11 10:20:24 -05:00
|
|
|
return prerenderedShortcode{s: result, hasVariants: hasVariants}, err
|
2016-03-17 10:51:52 -04:00
|
|
|
}
|
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
func (s *shortcodeHandler) hasShortcodes() bool {
|
2020-03-09 07:04:33 -04:00
|
|
|
return s != nil && len(s.shortcodes) > 0
|
2018-04-23 23:57:33 -04:00
|
|
|
}
|
|
|
|
|
2022-05-29 10:41:57 -04:00
|
|
|
func (s *shortcodeHandler) addName(name string) {
|
|
|
|
s.nameSetMu.Lock()
|
|
|
|
defer s.nameSetMu.Unlock()
|
|
|
|
s.nameSet[name] = true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *shortcodeHandler) transferNames(in *shortcodeHandler) {
|
|
|
|
s.nameSetMu.Lock()
|
|
|
|
defer s.nameSetMu.Unlock()
|
|
|
|
for k := range in.nameSet {
|
|
|
|
s.nameSet[k] = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *shortcodeHandler) hasName(name string) bool {
|
|
|
|
s.nameSetMu.RLock()
|
|
|
|
defer s.nameSetMu.RUnlock()
|
|
|
|
_, ok := s.nameSet[name]
|
|
|
|
return ok
|
|
|
|
}
|
|
|
|
|
2023-02-11 10:20:24 -05:00
|
|
|
func (s *shortcodeHandler) prepareShortcodesForPage(ctx context.Context, p *pageState, f output.Format) (map[string]shortcodeRenderer, error) {
|
|
|
|
rendered := make(map[string]shortcodeRenderer)
|
2017-05-06 14:15:28 -04:00
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
tplVariants := tpl.TemplateVariants{
|
|
|
|
Language: p.Language().Lang,
|
|
|
|
OutputFormat: f,
|
2017-05-06 14:15:28 -04:00
|
|
|
}
|
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
for _, v := range s.shortcodes {
|
2023-02-11 10:20:24 -05:00
|
|
|
s, err := prepareShortcode(ctx, 0, s.s, tplVariants, v, nil, p)
|
2016-08-01 17:04:44 -04:00
|
|
|
if err != nil {
|
2023-02-11 10:20:24 -05:00
|
|
|
return nil, err
|
2016-08-01 17:04:44 -04:00
|
|
|
}
|
2019-01-02 06:33:26 -05:00
|
|
|
rendered[v.placeholder] = s
|
2017-05-06 14:15:28 -04:00
|
|
|
|
2016-08-01 17:04:44 -04:00
|
|
|
}
|
|
|
|
|
2023-02-11 10:20:24 -05:00
|
|
|
return rendered, nil
|
2016-08-01 17:04:44 -04:00
|
|
|
}
|
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
func (s *shortcodeHandler) parseError(err error, input []byte, pos int) error {
|
|
|
|
if s.p != nil {
|
|
|
|
return s.p.parseError(err, input, pos)
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
}
|
2019-01-02 06:33:26 -05:00
|
|
|
return err
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// pageTokens state:
|
|
|
|
// - before: positioned just before the shortcode start
|
|
|
|
// - after: shortcode(s) consumed (plural when they are nested)
|
2022-07-07 10:11:47 -04:00
|
|
|
func (s *shortcodeHandler) extractShortcode(ordinal, level int, source []byte, pt *pageparser.Iterator) (*shortcode, error) {
|
2019-01-02 06:33:26 -05:00
|
|
|
if s == nil {
|
|
|
|
panic("handler nil")
|
|
|
|
}
|
2018-04-23 02:09:56 -04:00
|
|
|
sc := &shortcode{ordinal: ordinal}
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
|
2022-05-28 07:18:50 -04:00
|
|
|
// Back up one to identify any indentation.
|
|
|
|
if pt.Pos() > 0 {
|
|
|
|
pt.Backup()
|
|
|
|
item := pt.Next()
|
|
|
|
if item.IsIndentation() {
|
2022-07-07 10:11:47 -04:00
|
|
|
sc.indentation = item.ValStr(source)
|
2022-05-28 07:18:50 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-02 07:23:25 -05:00
|
|
|
cnt := 0
|
|
|
|
nestedOrdinal := 0
|
|
|
|
nextLevel := level + 1
|
2023-02-23 02:08:17 -05:00
|
|
|
closed := false
|
2022-05-02 10:07:52 -04:00
|
|
|
const errorPrefix = "failed to extract shortcode"
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
|
|
|
|
Loop:
|
|
|
|
for {
|
2018-10-17 06:57:09 -04:00
|
|
|
currItem := pt.Next()
|
|
|
|
switch {
|
|
|
|
case currItem.IsLeftShortcodeDelim():
|
|
|
|
next := pt.Peek()
|
2021-05-24 08:59:02 -04:00
|
|
|
if next.IsRightShortcodeDelim() {
|
|
|
|
// no name: {{< >}} or {{% %}}
|
|
|
|
return sc, errors.New("shortcode has no name")
|
|
|
|
}
|
2018-10-17 06:57:09 -04:00
|
|
|
if next.IsShortcodeClose() {
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
continue
|
2014-01-29 17:50:31 -05:00
|
|
|
}
|
|
|
|
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
if cnt > 0 {
|
|
|
|
// nested shortcode; append it to inner content
|
2018-10-18 04:21:23 -04:00
|
|
|
pt.Backup()
|
2022-07-07 10:11:47 -04:00
|
|
|
nested, err := s.extractShortcode(nestedOrdinal, nextLevel, source, pt)
|
2018-04-23 02:09:56 -04:00
|
|
|
nestedOrdinal++
|
2019-08-19 10:26:53 -04:00
|
|
|
if nested != nil && nested.name != "" {
|
2022-05-29 10:41:57 -04:00
|
|
|
s.addName(nested.name)
|
2017-03-10 14:54:50 -05:00
|
|
|
}
|
2019-08-19 10:26:53 -04:00
|
|
|
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
if err == nil {
|
|
|
|
sc.inner = append(sc.inner, nested)
|
|
|
|
} else {
|
|
|
|
return sc, err
|
|
|
|
}
|
|
|
|
|
2014-01-29 17:50:31 -05:00
|
|
|
} else {
|
2018-10-17 06:57:09 -04:00
|
|
|
sc.doMarkup = currItem.IsShortcodeMarkupDelimiter()
|
2014-01-29 17:50:31 -05:00
|
|
|
}
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
|
|
|
|
cnt++
|
|
|
|
|
2018-10-17 06:57:09 -04:00
|
|
|
case currItem.IsRightShortcodeDelim():
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
// we trust the template on this:
|
|
|
|
// if there's no inner, we're done
|
2020-06-14 12:16:45 -04:00
|
|
|
if !sc.isInline {
|
|
|
|
if !sc.info.ParseInfo().IsInner {
|
|
|
|
return sc, nil
|
|
|
|
}
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
}
|
|
|
|
|
2018-10-17 06:57:09 -04:00
|
|
|
case currItem.IsShortcodeClose():
|
2023-02-23 02:08:17 -05:00
|
|
|
closed = true
|
2018-10-17 06:57:09 -04:00
|
|
|
next := pt.Peek()
|
2020-06-14 12:16:45 -04:00
|
|
|
if !sc.isInline {
|
2023-02-23 02:08:17 -05:00
|
|
|
if !sc.needsInner() {
|
2020-06-14 12:16:45 -04:00
|
|
|
if next.IsError() {
|
|
|
|
// return that error, more specific
|
|
|
|
continue
|
|
|
|
}
|
2023-02-23 02:38:51 -05:00
|
|
|
return nil, fmt.Errorf("%s: shortcode %q does not evaluate .Inner or .InnerDeindent, yet a closing tag was provided", errorPrefix, next.ValStr(source))
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
}
|
|
|
|
}
|
2018-10-17 06:57:09 -04:00
|
|
|
if next.IsRightShortcodeDelim() {
|
2015-03-02 15:23:16 -05:00
|
|
|
// self-closing
|
2018-10-17 06:57:09 -04:00
|
|
|
pt.Consume(1)
|
2015-03-02 15:23:16 -05:00
|
|
|
} else {
|
2018-11-26 05:01:27 -05:00
|
|
|
sc.isClosing = true
|
2018-10-17 06:57:09 -04:00
|
|
|
pt.Consume(2)
|
2015-03-02 15:23:16 -05:00
|
|
|
}
|
|
|
|
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
return sc, nil
|
2018-10-17 06:57:09 -04:00
|
|
|
case currItem.IsText():
|
2022-07-07 10:11:47 -04:00
|
|
|
sc.inner = append(sc.inner, currItem.ValStr(source))
|
2018-10-17 06:57:09 -04:00
|
|
|
case currItem.IsShortcodeName():
|
2019-01-02 06:33:26 -05:00
|
|
|
|
2022-07-07 10:11:47 -04:00
|
|
|
sc.name = currItem.ValStr(source)
|
2019-01-02 06:33:26 -05:00
|
|
|
|
2020-07-03 12:02:32 -04:00
|
|
|
// Used to check if the template expects inner content.
|
|
|
|
templs := s.s.Tmpl().LookupVariants(sc.name)
|
|
|
|
if templs == nil {
|
2022-05-02 10:07:52 -04:00
|
|
|
return nil, fmt.Errorf("%s: template for shortcode %q not found", errorPrefix, sc.name)
|
2015-11-15 14:53:12 -05:00
|
|
|
}
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
|
2020-07-03 12:02:32 -04:00
|
|
|
sc.info = templs[0].(tpl.Info)
|
|
|
|
sc.templs = templs
|
2018-11-26 05:01:27 -05:00
|
|
|
case currItem.IsInlineShortcodeName():
|
2022-07-07 10:11:47 -04:00
|
|
|
sc.name = currItem.ValStr(source)
|
2018-11-26 05:01:27 -05:00
|
|
|
sc.isInline = true
|
2018-10-17 06:57:09 -04:00
|
|
|
case currItem.IsShortcodeParam():
|
|
|
|
if !pt.IsValueNext() {
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
continue
|
2018-10-17 06:57:09 -04:00
|
|
|
} else if pt.Peek().IsShortcodeParamVal() {
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
// named params
|
|
|
|
if sc.params == nil {
|
2022-03-17 17:03:27 -04:00
|
|
|
params := make(map[string]any)
|
2022-07-07 10:11:47 -04:00
|
|
|
params[currItem.ValStr(source)] = pt.Next().ValTyped(source)
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
sc.params = params
|
2014-01-29 17:50:31 -05:00
|
|
|
} else {
|
2022-03-17 17:03:27 -04:00
|
|
|
if params, ok := sc.params.(map[string]any); ok {
|
2022-07-07 10:11:47 -04:00
|
|
|
params[currItem.ValStr(source)] = pt.Next().ValTyped(source)
|
2015-08-07 14:08:23 -04:00
|
|
|
} else {
|
2022-09-01 03:26:27 -04:00
|
|
|
return sc, fmt.Errorf("%s: invalid state: invalid param type %T for shortcode %q, expected a map", errorPrefix, params, sc.name)
|
2015-08-07 14:08:23 -04:00
|
|
|
}
|
2014-01-29 17:50:31 -05:00
|
|
|
}
|
|
|
|
} else {
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
// positional params
|
|
|
|
if sc.params == nil {
|
2022-03-17 17:03:27 -04:00
|
|
|
var params []any
|
2022-07-07 10:11:47 -04:00
|
|
|
params = append(params, currItem.ValTyped(source))
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
sc.params = params
|
2014-01-29 17:50:31 -05:00
|
|
|
} else {
|
2022-03-17 17:03:27 -04:00
|
|
|
if params, ok := sc.params.([]any); ok {
|
2022-07-07 10:11:47 -04:00
|
|
|
params = append(params, currItem.ValTyped(source))
|
2015-08-07 14:08:23 -04:00
|
|
|
sc.params = params
|
|
|
|
} else {
|
2022-09-01 03:26:27 -04:00
|
|
|
return sc, fmt.Errorf("%s: invalid state: invalid param type %T for shortcode %q, expected a slice", errorPrefix, params, sc.name)
|
2015-08-07 14:08:23 -04:00
|
|
|
}
|
2014-01-29 17:50:31 -05:00
|
|
|
}
|
|
|
|
}
|
2018-10-17 06:57:09 -04:00
|
|
|
case currItem.IsDone():
|
2023-02-23 02:08:17 -05:00
|
|
|
if !currItem.IsError() {
|
|
|
|
if !closed && sc.needsInner() {
|
2023-03-10 12:41:17 -05:00
|
|
|
return sc, fmt.Errorf("%s: shortcode %q must be closed or self-closed", errorPrefix, sc.name)
|
2023-02-23 02:08:17 -05:00
|
|
|
}
|
|
|
|
}
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
// handled by caller
|
2018-10-17 06:57:09 -04:00
|
|
|
pt.Backup()
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
break Loop
|
|
|
|
|
2014-01-29 17:50:31 -05:00
|
|
|
}
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
}
|
|
|
|
return sc, nil
|
|
|
|
}
|
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
// Replace prefixed shortcode tokens with the real content.
|
2015-10-20 14:35:12 -04:00
|
|
|
// Note: This function will rewrite the input slice.
|
2023-02-11 10:20:24 -05:00
|
|
|
func expandShortcodeTokens(
|
|
|
|
ctx context.Context,
|
|
|
|
source []byte,
|
|
|
|
tokenHandler func(ctx context.Context, token string) ([]byte, error),
|
|
|
|
) ([]byte, error) {
|
2015-06-21 07:08:30 -04:00
|
|
|
start := 0
|
|
|
|
|
2019-01-02 06:33:26 -05:00
|
|
|
pre := []byte(shortcodePlaceholderPrefix)
|
2016-09-08 15:23:01 -04:00
|
|
|
post := []byte("HBHB")
|
2015-06-21 07:08:30 -04:00
|
|
|
pStart := []byte("<p>")
|
|
|
|
pEnd := []byte("</p>")
|
|
|
|
|
|
|
|
k := bytes.Index(source[start:], pre)
|
|
|
|
|
|
|
|
for k != -1 {
|
|
|
|
j := start + k
|
|
|
|
postIdx := bytes.Index(source[j:], post)
|
|
|
|
if postIdx < 0 {
|
|
|
|
// this should never happen, but let the caller decide to panic or not
|
|
|
|
return nil, errors.New("illegal state in content; shortcode token missing end delim")
|
|
|
|
}
|
|
|
|
|
|
|
|
end := j + postIdx + 4
|
2023-02-11 10:20:24 -05:00
|
|
|
key := string(source[j:end])
|
|
|
|
newVal, err := tokenHandler(ctx, key)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-06-21 07:08:30 -04:00
|
|
|
|
|
|
|
// Issue #1148: Check for wrapping p-tags <p>
|
|
|
|
if j >= 3 && bytes.Equal(source[j-3:j], pStart) {
|
2018-08-16 20:17:27 -04:00
|
|
|
if (k+4) < len(source) && bytes.Equal(source[end:end+4], pEnd) {
|
2015-06-21 07:08:30 -04:00
|
|
|
j -= 3
|
|
|
|
end += 4
|
2015-01-28 22:11:41 -05:00
|
|
|
}
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
}
|
Provide (relative) reference funcs & shortcodes.
- `.Ref` and `.RelRef` take a reference (the logical filename for a
page, including extension and/or a document fragment ID) and return
a permalink (or relative permalink) to the referenced document.
- If the reference is a page name (such as `about.md`), the page
will be discovered and the permalink will be returned: `/about/`
- If the reference is a page name with a fragment (such as
`about.md#who`), the page will be discovered and used to add the
`page.UniqueID()` to the resulting fragment and permalink:
`/about/#who:deadbeef`.
- If the reference is a fragment and `.*Ref` has been called from
a `Node` or `SiteInfo`, it will be returned as is: `#who`.
- If the reference is a fragment and `.*Ref` has been called from
a `Page`, it will be returned with the page’s unique ID:
`#who:deadbeef`.
- `.*Ref` can be called from either `Node`, `SiteInfo` (e.g.,
`Node.Site`), `Page` objects, or `ShortcodeWithPage` objects in
templates.
- `.*Ref` cannot be used in content, so two shortcodes have been
created to provide the functionality to content: `ref` and `relref`.
These are intended to be used within markup, like `[Who]({{% ref
about.md#who %}})` or `<a href="{{% ref about.md#who %}}">Who</a>`.
- There are also `ref` and `relref` template functions (used to create
the shortcodes) that expect a `Page` or `Node` object and the
reference string (e.g., `{{ relref . "about.md" }}` or `{{
"about.md" | ref . }}`). It actually looks for `.*Ref` as defined on
`Node` or `Page` objects.
- Shortcode handling had to use a *differently unique* wrapper in
`createShortcodePlaceholder` because of the way that the `ref` and
`relref` are intended to be used in content.
2014-11-24 01:15:34 -05:00
|
|
|
|
2015-10-20 14:35:12 -04:00
|
|
|
// This and other cool slice tricks: https://github.com/golang/go/wiki/SliceTricks
|
|
|
|
source = append(source[:j], append(newVal, source[end:]...)...)
|
2016-02-25 15:31:22 -05:00
|
|
|
start = j
|
2015-06-21 07:08:30 -04:00
|
|
|
k = bytes.Index(source[start:], pre)
|
2015-06-22 13:40:12 -04:00
|
|
|
|
2015-10-20 14:35:12 -04:00
|
|
|
}
|
2015-06-22 13:40:12 -04:00
|
|
|
|
2015-10-20 14:35:12 -04:00
|
|
|
return source, nil
|
Shortcode rewrite, take 2
This commit contains a restructuring and partial rewrite of the shortcode handling.
Prior to this commit rendering of the page content was mingled with handling of the shortcodes. This led to several oddities.
The new flow is:
1. Shortcodes are extracted from page and replaced with placeholders.
2. Shortcodes are processed and rendered
3. Page is processed
4. The placeholders are replaced with the rendered shortcodes
The handling of summaries is also made simpler by this.
This commit also introduces some other chenges:
1. distinction between shortcodes that need further processing and those who do not:
* `{{< >}}`: Typically raw HTML. Will not be processed.
* `{{% %}}`: Will be processed by the page's markup engine (Markdown or (infuture) Asciidoctor)
The above also involves a new shortcode-parser, with lexical scanning inspired by Rob Pike's talk called "Lexical Scanning in Go",
which should be easier to understand, give better error messages and perform better.
2. If you want to exclude a shortcode from being processed (for documentation etc.), the inner part of the shorcode must be commented out, i.e. `{{%/* movie 47238zzb */%}}`. See the updated shortcode section in the documentation for further examples.
The new parser supports nested shortcodes. This isn't new, but has two related design choices worth mentioning:
* The shortcodes will be rendered individually, so If both `{{< >}}` and `{{% %}}` are used in the nested hierarchy, one will be passed through the page's markdown processor, the other not.
* To avoid potential costly overhead of always looking far ahead for a possible closing tag, this implementation looks at the template itself, and is branded as a container with inner content if it contains a reference to `.Inner`
Fixes #565
Fixes #480
Fixes #461
And probably some others.
2014-10-27 16:48:30 -04:00
|
|
|
}
|
2013-07-04 11:32:55 -04:00
|
|
|
|
2023-02-11 10:20:24 -05:00
|
|
|
func renderShortcodeWithPage(ctx context.Context, h tpl.TemplateHandler, tmpl tpl.Template, data *ShortcodeWithPage) (string, error) {
|
2015-01-30 14:19:46 -05:00
|
|
|
buffer := bp.GetBuffer()
|
|
|
|
defer bp.PutBuffer(buffer)
|
|
|
|
|
2023-02-11 10:20:24 -05:00
|
|
|
err := h.ExecuteWithContext(ctx, tmpl, buffer, data)
|
2014-01-29 17:50:31 -05:00
|
|
|
if err != nil {
|
2022-05-02 10:07:52 -04:00
|
|
|
return "", fmt.Errorf("failed to process shortcode: %w", err)
|
2014-01-29 17:50:31 -05:00
|
|
|
}
|
2018-10-03 08:58:09 -04:00
|
|
|
return buffer.String(), nil
|
2013-07-04 11:32:55 -04:00
|
|
|
}
|