This extends the page grouping in Hugo with a template function that allows for ad-hoc grouping.
A made-up example:
```
{{ $cool := where .Site.RegularPages "Params.cool" true | group "cool" }}
{{ $blue := where .Site.RegularPages "Params.blue" true | group "blue" }}
{{ $paginator := .Paginate (slice $cool $blue) }}
```
Closes#4865
This also adjusts the pagination logic to allow for these new collections.
Note that we will follow up with a template function named `group` that will be the end user API. The `.Group` method on `Page` should be considered as internal.
Updates #4865
Doing so was probably a mistake. This may be a breaking change for some people,
but it's easy to restore the previous behaviour in the layouts.
Fixes#5172
This commit also removes the deprecated `Suffix` from MediaType. Now use `Suffixes` and put the MIME type suffix in the type, e.g. `application/svg+xml`.
Fixes#5093
Before this commit, the live reload logic in `hugo server` got confused when you dropped a new bundle into the project while the server was running. The workaround was to restart the server.
This commit fixes the "live reload bundle detection" in server mode, and also makes sure that the bundle headers are always processed first.
Fixes#5075
Currently it makes no practical difference, but this is more a protection if we in the future creates index from the content related fields. That will not work from a shortcode.
See #5071
Yesterday's commit was a little too agressive.
This commit makes sure that the duplication of resources to public/en etc. is only performed in multihost mode.
See #5058
In Hugo 0.46 we made the output of what you get from resources.Get and similar static, i.e. language agnostic. This makes total sense, as it is wasteful and time-consuming to do SASS/SCSS/PostCSS processing for lots of languages when the output is lots of duplicates with different filenames.
But since we now output the result once only, this had a negative side effect for multihost setups: We publish the resource once only to the root folder (i.e. not to the language "domain folder").
This commit removes the language code from the processed image keys. This creates less duplication in the file cache, but it means that you should do a `hugo --gc` to clean up stale files.
Fixes#5058
Hugo Pipes added minification support for resources fetched via ´resources.Get` and similar.
This also adds support for minification of the final output for supported output formats: HTML, XML, SVG, CSS, JavaScript, JSON.
To enable, run Hugo with the `--minify` flag:
```bash
hugo --minify
```
This commit is also a major spring cleaning of the `transform` package to allow the new minification step fit into that processing chain.
Fixes#1251
Before this commit, only SASS/SCSS components imported from main.scss at first level can be overwritten by homonymous files in projects or over-preceding theme components.
This commit fixes that by implementing a custom import resolver which will be tried first. This resolver will make sure that the project/theme hierarchy is always respected.
Fixes#5008
In Hugo 0.44 we simplified the `.Site.GetPage` API and added code to handle the old-style syntax in most cases.
This logic did not handle the lookup of the home page via `.Site.GetPage "section" ""` and similar. This commit fixes that.
Fixes#4989
If a content file contains shortcode(s), we have logic in place to re-render it per output format.
We also have logic in place that avoids making a copy of the content used for this process if we don't need it.
This was before this commit limited to server mode and if the page should be output to multiple formats.
But there is a third case: If a site (language) borrows and renders `.Content` from another language. This would, before this commit, behave oddly for content with shortcodes.
Fixes#4986
Two new settings:
* refLinksErrorLevel: ERROR (default) or WARNING. ERROR will fail the build.
* refLinksNotFoundURL: Used as a placeholder when page references cannot be found.
Fixes#4964
This commit is a follow up to a recent overhaul of the GetPage/ref/relref implemenation.
The most important change in this commit is the update to `.Site.GetPage`:
* To reduce the amount of breakage in the wild to its minimum, I have reworked .Site.GetPage with some rules:
* We cannot support more than 2 arguments, i.e. .Site.GetPage "page" "posts" "mypage.md" will now throw an error. I think this is the most uncommon syntax and should be OK. It is an easy fix to change the above to .Site.GetPage "/posts/mypage.md" or similar.
* .Site.GetPage "home", .Site.GetPage "home" "" and .Site.GetPage "home" "/" will give you the home page. This means that if you have page in root with the name home.md you need to do .Site.GetPage "/home.md" or similar
This commit also fixes some multilingual issues, most notable it is now possible to do cross-language ref/relref lookups by prepending the language code to the path, e.g. `/jp/posts/mypage.md`.
This commit also reverts the site building tests related to this to "Hugo 0.44 state", to get better control of the changes made.
Closes#4147Closes#4727Closes#4728Closes#4728Closes#4726Closes#4652
This commit unifies the core internal page index for all page kinds.
This enables the `ref` and `relref` shortcodes to support all pages kinds, and adds a new page-relative `.GetPage` method with simplified signature.
See #4147
See #4727
See #4728
See #4728
See #4726
See #4652
When the 'allThemes' configuration setting is read, it will panic if
there are no themes. This was a regression introduced in Hugo 0.42.
Also updated a unit test to check for this.
Fixes#4851
Multihost is where each language has its own `baseURL`. In this configuration, static files from the theme was not picked up.
This was a regression in Hugo `0.42`. This commit also adds proper tests for this, so that does not happen again.
Fixes#4929
Before this commit, `Suffix` on `MediaType` was used both to set a custom file suffix and as a way to augment the mediatype definition (what you see after the "+", e.g. "image/svg+xml").
This had its limitations. For one, it was only possible with one file extension per MIME type.
Now you can specify multiple file suffixes using "suffixes", but you need to specify the full MIME type
identifier:
[mediaTypes]
[mediaTypes."image/svg+xml"]
suffixes = ["svg", "abc ]
In most cases, it will be enough to just change:
[mediaTypes]
[mediaTypes."my/custom-mediatype"]
suffix = "txt"
To:
[mediaTypes]
[mediaTypes."my/custom-mediatype"]
suffixes = ["txt"]
Hugo will still respect values set in "suffix" if no value for "suffixes" is provided, but this will be removed in a future release.
Note that you can still get the Media Type's suffix from a template: {{ $mediaType.Suffix }}. But this will now map to the MIME type filename.
Fixes#4920
This is a recent regression in Hugo, where we have started to produce `/page/30/index.json` when the main output format (usually `HTML`) is set up with pagination.
For JSON this is potentially lot of superflous work and hurts performance.
This commit reinstates the earlier behaviour: We only create paginators if in use in the main output format.
And add a test for it to prevent this from happening again.
Fixes#4890
Before this commit, you would have to use page bundles to do image processing etc. in Hugo.
This commit adds
* A new `/assets` top-level project or theme dir (configurable via `assetDir`)
* A new template func, `resources.Get` which can be used to "get a resource" that can be further processed.
This means that you can now do this in your templates (or shortcodes):
```bash
{{ $sunset := (resources.Get "images/sunset.jpg").Fill "300x200" }}
```
This also adds a new `extended` build tag that enables powerful SCSS/SASS support with source maps. To compile this from source, you will also need a C compiler installed:
```
HUGO_BUILD_TAGS=extended mage install
```
Note that you can use output of the SCSS processing later in a non-SCSSS-enabled Hugo.
The `SCSS` processor is a _Resource transformation step_ and it can be chained with the many others in a pipeline:
```bash
{{ $css := resources.Get "styles.scss" | resources.ToCSS | resources.PostCSS | resources.Minify | resources.Fingerprint }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Digest }}" media="screen">
```
The transformation funcs above have aliases, so it can be shortened to:
```bash
{{ $css := resources.Get "styles.scss" | toCSS | postCSS | minify | fingerprint }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Digest }}" media="screen">
```
A quick tip would be to avoid the fingerprinting part, and possibly also the not-superfast `postCSS` when you're doing development, as it allows Hugo to be smarter about the rebuilding.
Documentation will follow, but have a look at the demo repo in https://github.com/bep/hugo-sass-test
New functions to create `Resource` objects:
* `resources.Get` (see above)
* `resources.FromString`: Create a Resource from a string.
New `Resource` transformation funcs:
* `resources.ToCSS`: Compile `SCSS` or `SASS` into `CSS`.
* `resources.PostCSS`: Process your CSS with PostCSS. Config file support (project or theme or passed as an option).
* `resources.Minify`: Currently supports `css`, `js`, `json`, `html`, `svg`, `xml`.
* `resources.Fingerprint`: Creates a fingerprinted version of the given Resource with Subresource Integrity..
* `resources.Concat`: Concatenates a list of Resource objects. Think of this as a poor man's bundler.
* `resources.ExecuteAsTemplate`: Parses and executes the given Resource and data context (e.g. .Site) as a Go template.
Fixes#4381Fixes#4903Fixes#4858
This should allow for less duplication of templates. Before this commit it was possible to override the content page of a given page/section, but only one page at a time.
Full "template sets" can now be inherited by setting `type: blog` etc. in the section content page's front matter, and that type will be considered when looking for layouts for all pages in that section.
For nested sections, it will use consider both `type` set in the current section first, then `type` set in the first section below home, e.g. `/docs`.
This commit also adds a new Page method: `FirstSection`. This navigates up to the first section below home (e.g. `/docs`). For the home page it will return itself.
Fixes#4891
In Hugo 0.42, this could lead to errors of type `runtime error: invalid memory address or nil pointer dereference` in some rare situations.
Note that this was also an issue before 0.42, but the symptom was then potentially stale list content on rebuilds on content changes.
This commit also improves the above error message.
Fixes#4845
This commit adds support for theme composition and inheritance in Hugo.
With this, it helps thinking about a theme as a set of ordered components:
```toml
theme = ["my-shortcodes", "base-theme", "hyde"]
```
The theme definition example above in `config.toml` creates a theme with the 3 components with presedence from left to right.
So, Hugo will, for any given file, data entry etc., look first in the project, and then in `my-shortcode`, `base-theme` and lastly `hyde`.
Hugo uses two different algorithms to merge the filesystems, depending on the file type:
* For `i18n` and `data` files, Hugo merges deeply using the translation id and data key inside the files.
* For `static`, `layouts` (templates) and `archetypes` files, these are merged on file level. So the left-most file will be chosen.
The name used in the `theme` definition above must match a folder in `/your-site/themes`, e.g. `/your-site/themes/my-shortcodes`. There are plans to improve on this and get a URL scheme so this can be resolved automatically.
Also note that a component that is part of a theme can have its own configuration file, e.g. `config.toml`. There are currently some restrictions to what a theme component can configure:
* `params` (global and per language)
* `menu` (global and per language)
* `outputformats` and `mediatypes`
The same rules apply here: The left-most param/menu etc. with the same ID will win. There are some hidden and experimental namespace support in the above, which we will work to improve in the future, but theme authors are encouraged to create their own namespaces to avoid naming conflicts.
A final note: Themes/components can also have a `theme` definition in their `config.toml` and similar, which is the "inheritance" part of this commit's title. This is currently not supported by the Hugo theme site. We will have to wait for some "auto dependency" feature to be implemented for that to happen, but this can be a powerful feature if you want to create your own theme-variant based on others.
Fixes#4460Fixes#4450
So that a timeout warning does appear if it does happen
especially on a slow machine with soft floating-point CPU.
Special thanks to @bep for the solution.
See #4672
Sets Page.markup earlier (as early as possible, when the page is
loaded). Sets it once and only once, removing many redundant calls
to determineMarkupType().
This kills a sleeping bug that was avoided by the parts of the
code depending on this value making those redundant calls.
There have been one report of a site with truncated `.Content` after the Hugo `0.40.1` release.
This commit fixes this so that race should not be possible anymore. It also adds a stress test with focus on content rendering and multiple output formats.
Fixes#4706
Having them in separate files should make maintainance easier.
When adding new or making changes to the templates:
```bash
mage generate
```
This will get the Go code in sync.
Fixes#4457
This bug was introduced in Hugo 0.40. It is when you use the `<!--more-->` summary marker.
Note that this affects the word stats only. The related `PlainWords`, `Plain`, `Content` all return correct values.
Fixes#4675Fixes#4682
This is a follow-up to #4632. There were some assumptions in that implementation that did not hold water in all situations.
This commit simplifies the content lazy initalization making it more robust.
Fixes#4664
I eturn either:
1. leaf
2. branch
3. empty string
The above sits well with constructs like:
```
{{ with .BundleType }}
// Now we know it is a bundle
{{ end }}
```
Fixes#4662
The count starts at 0 relative to the shortcode's parent: Either the page or the surrounding shortcode.
Access it in a shortcode like this:
```bash
Ordinal is {{ .Ordinal }}
```
Note that this is a shared ordinal for all shortcodes in the relevant context, so, as an example, you have this in a content page:
```markdown
This is a shortcode:
{{< hello >}}
This is another shortcode:
{{< hugo >}}
The `.Ordinal` you get in the two shortcodes above is 0 and 1.
```
See #3359
In most cases we could delay the content init until rendering time, but there could be use cases where the templates would depend on state set in the shortcodes (.Page.Scratch.Set), so we need to do this early.
See #4632
This resolves some surprising behaviour when reading other pages' content from shortcodes. Before this commit, that behaviour was undefined. Note that this has never been an issue from regular templates.
It will still not be possible to get **the current shortcode's page's rendered content**. That would have impressed Einstein.
The new and well defined rules are:
* `.Page.Content` from a shortcode will be empty. The related `.Page.Truncated` `.Page.Summary`, `.Page.WordCount`, `.Page.ReadingTime`, `.Page.Plain` and `.Page.PlainWords` will also have empty values.
* For _other pages_ (retrieved via `.Page.Site.GetPage`, `.Site.Pages` etc.) the `.Content` is there to use as you please as long as you don't have infinite content recursion in your shortcode/content setup. See below.
* `.Page.TableOfContents` is good to go (but does not support shortcodes in headlines; this is unchanged)
If you get into a situation of infinite recursion, the `.Content` will be empty. Run `hugo -v` for more information.
Fixes#4632Fixes#4653Fixes#4655
For the content from other pages in shortcodes there are some chicken and
egg dependencies that is hard to get around. But we can improve on this by preparing the pages in a certain order:
1. The headless bundles goes first. These are page typically page and image collections..
2. Leaf bundles
3. Regular single pages
4. Branch bundles
Fixes#4632
Put guards around TestPageBundlerCaptureSymlinks and
TestPageBundlerSiteWitSymbolicLinksInContent so that they aren't
run on Windows (they both use symbolic links and the Go library
implementation requires administrator mode on Windows).
A sample config:
```toml
defaultContentLanguage = "en"
defaultContentLanguageInSubdir = true
[Languages]
[Languages.en]
weight = 10
title = "In English"
languageName = "English"
contentDir = "content/english"
[Languages.nn]
weight = 20
title = "På Norsk"
languageName = "Norsk"
contentDir = "content/norwegian"
```
The value of `contentDir` can be any valid path, even absolute path references. The only restriction is that the content dirs cannot overlap.
The content files will be assigned a language by
1. The placement: `content/norwegian/post/my-post.md` will be read as Norwegian content.
2. The filename: `content/english/post/my-post.nn.md` will be read as Norwegian even if it lives in the English content folder.
The content directories will be merged into a big virtual filesystem with one simple rule: The most specific language file will win.
This means that if both `content/norwegian/post/my-post.md` and `content/english/post/my-post.nn.md` exists, they will be considered duplicates and the version inside `content/norwegian` will win.
Note that translations will be automatically assigned by Hugo by the content file's relative placement, so `content/norwegian/post/my-post.md` will be a translation of `content/english/post/my-post.md`.
If this does not work for you, you can connect the translations together by setting a `translationKey` in the content files' front matter.
Fixes#4523Fixes#4552Fixes#4553
This allows a `config.toml` (or `yaml`, ´yml`, or `json`) in the theme to set:
1) `params` (but cannot override params in project. Will also get its own "namespace", i.e. `{{ .Site.Params.mytheme.my_param }}` will be the same as `{{ .Site.Params.my_param }}` providing that the main project does not define a param with that key.
2) `menu` -- but cannot redefine/add menus in the project. Must create its own menus with its own identifiers.
3) `languages` -- only `params` and `menu`. Same rules as above.
4) **new** `outputFormats`
5) **new** `mediaTypes`
This should help with the "theme portability" issue and people having to copy and paste lots of setting into their projects.
Fixes#4490
These were written as a development aid in some kind of structural change at some point.
They served their purpose then, but these are tests covered elsewhere and is deleted to reduce maintainance.
The reported test covrage is not reduced because of this.
As an example:
```html
{{ $pages := .Site.RegularPages | lang.Merge $frSite.RegularPages | lang.Merge $enSite.RegularPages }}
```
Will "fill in the gaps" in the current site with, from left to right, content from the French site, and lastly the English.
Fixes#4463
This commit makes it possible to extract the date from the content filename. Also, the filenames in these cases will make for very poor permalinks, so we will also use the remaining part as the page `slug` if that value is not set in front matter.
This should make it easier to move content from Jekyll to Hugo.
To enable, put this in your `config.toml`:
```toml
[frontmatter]
date = [":filename", ":default"]
```
This commit is also a spring cleaning of how the different dates are configured in Hugo. Hugo will check for dates following the configuration from left to right, starting with `:filename` etc.
So, if you want to use the `file modification time`, this can be a good configuration:
```toml
[frontmatter]
date = [ "date",":fileModTime", ":default"]
lastmod = ["lastmod" ,":fileModTime", ":default"]
```
The current `:default` values for the different dates are
```toml
[frontmatter]
date = ["date","publishDate", "lastmod"]
lastmod = ["lastmod", "date","publishDate"]
publishDate = ["publishDate", "date"]
expiryDate = ["expiryDate"]
```
The above will now be the same as:
```toml
[frontmatter]
date = [":default"]
lastmod = [":default"]
publishDate = [":default"]
expiryDate = [":default"]
```
Note:
* We have some built-in aliases to the above: lastmod => modified, publishDate => pubdate, published and expiryDate => unpublishdate.
* If you want a new configuration for, say, `date`, you can provide only that line, and the rest will be preserved.
* All the keywords to the right that does not start with a ":" maps to front matter parameters, and can be any date param (e.g. `myCustomDateParam`).
* The keywords to the left are the **4 predefined dates in Hugo**, i.e. they are constant values.
* The current "special date handlers" are `:fileModTime` and `:filename`. We will soon add `:git` to that list.
Fixes#285Closes#3310Closes#3762Closes#4340
Site.assembleSections logic assumes that the the home page would always be the first in the Site's list of pages. This is not in fact guaranteed to be true. When it is not, the method can fail to set the parent for some or all root-level pages.
Fixes#4447
This means that you can do something ala:
```html
{{ if ge .Hugo.Version "0.36" }}Reasonable new Hugo version!{{ end }}
```
The intented use is feature toggling, but please note that it will take some time and Hugo versions until this can be trusted. It does not work in older Hugo versions.
Fixes#4443
The same code now cycles through equivalent JSON, YAML and TOML data sets,
verifying output both proper and identical. Coverage increased by applying
previous tests for one format to the others.
More DRY. Added tests for numeric and bool value types.
Also:
- Remove unnecessary space from `figure` tag if no class is specified.
- Update related tests.
- Add test cases for the changes made to the figure shortcode.
- Document the newly added target and rel parameters
- Add more detail to the documentation of all figure shortcode parameters.
Add an additional test to "Variant 4, theme, use site base" to also test
for the index.html base (from by testing of #3505). Also add a "name"
field to the test cases to make it easier to know which test is failing
versus just getting a slice index.
* Adds retro-coverage for #4361
* Verifies open issues #4138, #3890, #4366, 4083
* Removes test reliance on the very code it is testing (hugo/parser package).
Expected results are now all built manually / are more precise.
Tests can run against different versions (no linkage errs)
This fixes some issues with language params handling by separating params from configuration values per language.
This means that you can now do this:
```toml
[languages]
[languages.en]
languageName = "English"
weight = 1
title = "My Cool Site"
[languages.en.params]
myParam = "Hi!"
```
This is not a breaking change, but the above is a less suprising way of configuring custom params.
It also fixes some hard-to-debug corner-cases in multilingual sites.
Fixes#4356Fixes#4352
This commit adds a new config setting:
```toml
disableLanguages = ["fr"]
```
If this is a multilingual site:
* No site for the French language will be created
* French content pages will be ignored/not read
* The French language configuration (menus etc.) will also be ignored
This makes it possible to start translating new languages and turn it on when you're happy etc.
Fixes#4297Fixed#4329
* Page without front matter now treated same as a page with empty front matter.
* Test cases added to cover this and repro issue #4320.
* Type safety of front matter code improved.
Fixes#4320
Now, even for nun-bundles it is possible to do lookup without path or extension.
So, given `blog/my-blog-post.en.md` these lookups will succeed:
* `blog/my-blog-post.en.md`
* `blog/my-blog-post`
* `my-blog-post.en.md`
* `my-blog-post`
See #4312
See https://github.com/gohugoio/hugoDocs/issues/307
Given a bundle in `blog/my-bundle/index.en.md` all of these will now worK:
* `blog/my-bundle/index.en.md`
* `blog/my-bundle/index`
* `blog/my-bundle`
* `my-bundle`
The last one is potentially ambigous.
Fixes#4312
This commit adds support for `headless bundles` for the `index` bundle type.
So:
```toml
headless = true
```
In front matter means that
* It will have no `Permalink` and no rendered HTML in /public
* It will not be part of `.Site.RegularPages` etc.
But you can get it by:
* `.Site.GetPage ...`
The use cases are many:
* Shared media galleries
* Reusable page content "snippets"
* ...
Fixes#4311
You can still use the full path with extensions, but to get the current language version:
* If the content file lives in `/content/blog/mypost.en.md`
* Use `.Site.GetPage "page" "blog/mypost"`
Fixes#4285
This commit expands the Resource interface with 3 new methods:
* Name
* Title
* Params
All of these can be set in the Page front matter. `Name` will get its default value from the base filename, and is the value used in the ByPrefix and GetByPrefix lookup methods.
Fixes#4244
This commit also has some other nice side-effects:
* The layout logic is unified for all page types, which should make it less surprising
* Page.Render now supports all types
* The legacy "indexes" type is removed from the template lookup order. This is an undocumented type from early Hugo days. This means that having a template in, say, `/layouts/indexes/list.html` will no longer work.
* The theme override logic is improved. As an example, an `index.html` in theme will now wn over a `_default/list.html` in the project, which most will expect.
Fixes#3005Fixes#3245
* We match by path vs taxonomy to determine if we have a content page for that taxonomy
* The taxonomy name is (if `preserveTaxonomyNames` is not set) normalized to `maxmustermann` while you have the disk folder called `MaxMustermann`.
* This isn't a new issue, but I suspect most people will just name the folder `authors/maxmustermann` and it will just work.
* The inconsistent behaviour you see here is that you will end up with two pages with the same target filename, so it is a little random who will win.
This fixes that by also normalizing the taxonomy path when doing the comparison.
Fixes#4238
We still do lowering of the param strings in some internal use of this, but the exported `GetParam` method is changed to a more sensible default.
This was used for the `disqus_title` etc. in the internal Disqus template, which was obviously not right.
If you really want to lowercase your params, do it with `.GetParam "myparam" | lower` or similar.
Fixes#4187
This commit is not the smallest in Hugo's history.
Some hightlights include:
* Page bundles (for complete articles, keeping images and content together etc.).
* Bundled images can be processed in as many versions/sizes as you need with the three methods `Resize`, `Fill` and `Fit`.
* Processed images are cached inside `resources/_gen/images` (default) in your project.
* Symbolic links (both files and dirs) are now allowed anywhere inside /content
* A new table based build summary
* The "Total in nn ms" now reports the total including the handling of the files inside /static. So if it now reports more than you're used to, it is just **more real** and probably faster than before (see below).
A site building benchmark run compared to `v0.31.1` shows that this should be slightly faster and use less memory:
```bash
▶ ./benchSite.sh "TOML,num_langs=.*,num_root_sections=5,num_pages=(500|1000),tags_per_page=5,shortcodes,render"
benchmark old ns/op new ns/op delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 101785785 78067944 -23.30%
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 185481057 149159919 -19.58%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 103149918 85679409 -16.94%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 203515478 169208775 -16.86%
benchmark old allocs new allocs delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 532464 391539 -26.47%
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 1056549 772702 -26.87%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 555974 406630 -26.86%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 1086545 789922 -27.30%
benchmark old bytes new bytes delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 53243246 43598155 -18.12%
BenchmarkSiteBuilding/TOML,num_langs=1,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 105811617 86087116 -18.64%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=500,tags_per_page=5,shortcodes,render-4 54558852 44545097 -18.35%
BenchmarkSiteBuilding/TOML,num_langs=3,num_root_sections=5,num_pages=1000,tags_per_page=5,shortcodes,render-4 106903858 86978413 -18.64%
```
Fixes#3651Closes#3158Fixes#1014Closes#2021Fixes#1240
Updates #3757
This is in heavy use in rendering, so this makes a difference:
```bash
benchmark old ns/op new ns/op delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_pages=500,tags_per_page=5,shortcodes,render-4 124551144 107743429 -13.49%
benchmark old allocs new allocs delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_pages=500,tags_per_page=5,shortcodes,render-4 528684 435118 -17.70%
benchmark old bytes new bytes delta
BenchmarkSiteBuilding/TOML,num_langs=1,num_pages=500,tags_per_page=5,shortcodes,render-4 53306848 45147832 -15.31%
```
It was clever, but storing the items in a slice is faster -- and it gives room to more goroutines in other places.
```bash
benchmark old ns/op new ns/op delta
BenchmarkShortcodeLexer-4 180173 79614 -55.81%
benchmark old allocs new allocs delta
BenchmarkShortcodeLexer-4 309 328 +6.15%
benchmark old bytes new bytes delta
BenchmarkShortcodeLexer-4 35456 47008 +32.58%
```