Skip to content

Commit c9e6790

Browse files
committed
Add configuration options for pandoc
Current options are: markup: pandoc: filters: - list - of - filters extensions: - list - of - extensions extraArgs: - --extra-arguments - --one-per-line Generalize some Pandoc options. Support configuring a bibliography in markup config Anonymous Update [pandoc] Allow page parameters to override site parameters. This allows specifying things like this in the page frontmatter: --- title: Something bibliography: source: mybibliography.bib pandoc: filter: - make-diagrams.lua ... These options are local to the page. Specifying the same under `markup` in the site configuration applies those settings to all pages. Paths (filters, bibliography, citation style) are resolved relative to the page, site, and the `static` folder. [pandoc] Support metadata Support specifying Pandoc metadata in the site configuration and page configuration using the following syntax: Site (in `config.yaml`): ```yaml markup: pandoc: metadata: link-citations: true ``` Or in frontmatter: ```yaml --- pandoc: metadata: link-citations: true ... ``` [pandoc] Simplify path management. No need for any fancy path lookup gymnastics. `pandoc`'s `--resource-path` option does the legwork of locating resources on multiple directories. [pandoc] Don't use x != "" to denote failure.
1 parent 18ce854 commit c9e6790

File tree

4 files changed

+250
-16
lines changed

4 files changed

+250
-16
lines changed

Diff for: markup/bibliography/config.go

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2019 The Hugo Authors. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package bibliography
15+
16+
type Config struct {
17+
// File containing bibliography. E.g. 'my-doc.bibtex'. By default assumed
18+
// to be in BibTex format.
19+
Source string
20+
21+
// Path to .csl file describing citation file.
22+
CitationStyle string
23+
}
24+
25+
var Default Config

Diff for: markup/markup_config/config.go

+7
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ import (
1717
"github.com/gohugoio/hugo/common/maps"
1818
"github.com/gohugoio/hugo/config"
1919
"github.com/gohugoio/hugo/markup/asciidocext/asciidocext_config"
20+
"github.com/gohugoio/hugo/markup/bibliography"
2021
"github.com/gohugoio/hugo/markup/goldmark/goldmark_config"
2122
"github.com/gohugoio/hugo/markup/highlight"
23+
"github.com/gohugoio/hugo/markup/pandoc/pandoc_config"
2224
"github.com/gohugoio/hugo/markup/tableofcontents"
2325
"github.com/mitchellh/mapstructure"
2426
)
@@ -33,12 +35,16 @@ type Config struct {
3335

3436
// Table of contents configuration
3537
TableOfContents tableofcontents.Config
38+
Bibliography bibliography.Config
3639

3740
// Configuration for the Goldmark markdown engine.
3841
Goldmark goldmark_config.Config
3942

4043
// Configuration for the Asciidoc external markdown engine.
4144
AsciidocExt asciidocext_config.Config
45+
46+
// Configuration for Pandoc external markdown engine.
47+
Pandoc pandoc_config.Config
4248
}
4349

4450
func Decode(cfg config.Provider) (conf Config, err error) {
@@ -102,6 +108,7 @@ var Default = Config{
102108

103109
TableOfContents: tableofcontents.DefaultConfig,
104110
Highlight: highlight.DefaultConfig,
111+
Bibliography: bibliography.Default,
105112

106113
Goldmark: goldmark_config.Default,
107114
AsciidocExt: asciidocext_config.Default,

Diff for: markup/pandoc/convert.go

+59-16
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,34 @@
1515
package pandoc
1616

1717
import (
18+
"strings"
19+
1820
"github.com/gohugoio/hugo/common/hexec"
1921
"github.com/gohugoio/hugo/htesting"
22+
"github.com/mitchellh/mapstructure"
23+
2024
"github.com/gohugoio/hugo/identity"
2125

26+
"github.com/gohugoio/hugo/markup/bibliography"
2227
"github.com/gohugoio/hugo/markup/converter"
2328
"github.com/gohugoio/hugo/markup/internal"
29+
"github.com/gohugoio/hugo/markup/pandoc/pandoc_config"
30+
31+
"path"
2432
)
2533

34+
type paramer interface {
35+
Param(interface{}) (interface{}, error)
36+
}
37+
38+
type searchPaths struct {
39+
Paths []string
40+
}
41+
42+
func (s *searchPaths) AsResourcePath() string {
43+
return strings.Join(s.Paths, ":")
44+
}
45+
2646
// Provider is the package entry point.
2747
var Provider converter.ProviderProvider = provider{}
2848

@@ -32,15 +52,15 @@ type provider struct {
3252
func (p provider) New(cfg converter.ProviderConfig) (converter.Provider, error) {
3353
return converter.NewProvider("pandoc", func(ctx converter.DocumentContext) (converter.Converter, error) {
3454
return &pandocConverter{
35-
ctx: ctx,
36-
cfg: cfg,
55+
docCtx: ctx,
56+
cfg: cfg,
3757
}, nil
3858
}), nil
3959
}
4060

4161
type pandocConverter struct {
42-
ctx converter.DocumentContext
43-
cfg converter.ProviderConfig
62+
docCtx converter.DocumentContext
63+
cfg converter.ProviderConfig
4464
}
4565

4666
func (c *pandocConverter) Convert(ctx converter.RenderContext) (converter.ResultRender, error) {
@@ -56,30 +76,53 @@ func (c *pandocConverter) Supports(feature identity.Identity) bool {
5676
}
5777

5878
// getPandocContent calls pandoc as an external helper to convert pandoc markdown to HTML.
59-
func (c *pandocConverter) getPandocContent(src []byte, ctx converter.DocumentContext) ([]byte, error) {
79+
func (c *pandocConverter) getPandocContent(src []byte) []byte {
6080
logger := c.cfg.Logger
61-
binaryName := getPandocBinaryName()
62-
if binaryName == "" {
81+
pandocPath, pandocFound := getPandocBinaryName()
82+
if !pandocFound {
6383
logger.Println("pandoc not found in $PATH: Please install.\n",
6484
" Leaving pandoc content unrendered.")
65-
return src, nil
85+
return src
86+
}
87+
88+
var pandocConfig pandoc_config.Config = c.cfg.MarkupConfig.Pandoc
89+
var bibConfig bibliography.Config = c.cfg.MarkupConfig.Bibliography
90+
91+
if pageParameters, ok := c.docCtx.Document.(paramer); ok {
92+
if bibParam, err := pageParameters.Param("bibliography"); err == nil {
93+
mapstructure.WeakDecode(bibParam, &bibConfig)
94+
}
95+
96+
if pandocParam, err := pageParameters.Param("pandoc"); err == nil {
97+
mapstructure.WeakDecode(pandocParam, &pandocConfig)
98+
}
6699
}
67-
args := []string{"--mathjax"}
68-
return internal.ExternallyRenderContent(c.cfg, ctx, src, binaryName, args)
100+
101+
arguments := pandocConfig.AsPandocArguments()
102+
103+
if bibConfig.Source != "" {
104+
arguments = append(arguments, "--citeproc", "--bibliography", bibConfig.Source)
105+
if bibConfig.CitationStyle != "" {
106+
arguments = append(arguments, "--csl", bibConfig.CitationStyle)
107+
}
108+
}
109+
110+
resourcePath := strings.Join([]string{path.Dir(c.docCtx.Filename), "static", "."}, ":")
111+
arguments = append(arguments, "--resource-path", resourcePath)
112+
113+
renderedContent, _ := internal.ExternallyRenderContent(c.cfg, c.docCtx, src, pandocPath, arguments)
114+
return renderedContent
69115
}
70116

71117
const pandocBinary = "pandoc"
72118

73-
func getPandocBinaryName() string {
74-
if hexec.InPath(pandocBinary) {
75-
return pandocBinary
76-
}
77-
return ""
119+
func getPandocBinaryName() (string, bool) {
120+
return pandocBinary, hexec.InPath(pandocBinary)
78121
}
79122

80123
// Supports returns whether Pandoc is installed on this computer.
81124
func Supports() bool {
82-
hasBin := getPandocBinaryName() != ""
125+
_, hasBin := getPandocBinaryName()
83126
if htesting.SupportsAll() {
84127
if !hasBin {
85128
panic("pandoc not installed")

Diff for: markup/pandoc/pandoc_config/pandoc.go

+159
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package pandoc_config
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
)
7+
8+
// Config contains configuration settings for Pandoc.
9+
type Config struct {
10+
// Input format. Use the 'Extensions' field to specify extensions thereof.
11+
// Only specify the bare format here. Defaults to 'markdown' if empty. Invoke
12+
// "pandoc --list-input-formats" to see the list of supported input formats
13+
// including various Markdown dialects.
14+
InputFormat string
15+
16+
// If true, the output format is HTML (i.e. "--to=html"). Otherwise the output
17+
// format is HTML5 (i.e. "--to=html5").
18+
UseLegacyHtml bool
19+
20+
// Equivalent to specifying "--mathjax". For compatibility, this option is
21+
// always true if none of the other math options are used.
22+
// See https://pandoc.org/MANUAL.html#math-rendering-in-html
23+
UseMathjax bool
24+
25+
// Equivalent to specifying "--mathml".
26+
// See https://pandoc.org/MANUAL.html#math-rendering-in-html
27+
UseMathml bool
28+
29+
// Equivalent to specifying "--webtex".
30+
// See https://pandoc.org/MANUAL.html#math-rendering-in-html. Uses the default
31+
// Webtex rendering URL.
32+
UseWebtex bool
33+
34+
// Equivalent to specifying "--katex".
35+
// See https://pandoc.org/MANUAL.html#math-rendering-in-html
36+
UseKatex bool
37+
38+
// List of filters to use. These translate to '--filter=' or '--lua-filter'
39+
// arguments to the pandoc invocation. The order of elements in `Filters`
40+
// is preserved when constructing the `pandoc` commandline.
41+
//
42+
// Use the prefix 'lua:' or the suffix '.lua' to indicate Lua filters.
43+
Filters []string
44+
45+
// List of Pandoc Markdown extensions to use. No need to include default
46+
// extensions. Specifying ["foo", "bar"] is equivalent to specifying
47+
// --from=markdown+foo+bar on the pandoc commandline.
48+
Extensions []string
49+
50+
// List of input format extensions to use. Specifying ["foo", "bar"] is
51+
// equivalent to specifying --from=markdown+foo+bar on the pandoc commandline
52+
// assuming InputFormat is "markdown".
53+
InputExtensions []string
54+
55+
// List of output format extensions to use. Specifying ["foo", "bar"] is
56+
// equivalent to specifying --to=html5+foo+bar on the pandoc commandline,
57+
// assuming UseLegacyHTML is false. Invoke "pandoc --list-extensions=html5" to
58+
// or "pandoc --list-extensions=html5" to see the list of extensions that can
59+
// be specified here.
60+
OutputExtensions []string
61+
62+
// Metadata. The dictionary keys and values are handled in the obvious way.
63+
Metadata map[string]interface{}
64+
65+
// Extra commandline options passed to the pandoc invocation. These options
66+
// are appended to the commandline after the format and filter options.
67+
// Arguments are passed in literally. Hence must have the "--" or "-" prefix
68+
// where applicable.
69+
ExtraArgs []string
70+
}
71+
72+
func (c *Config) getInputArg() string {
73+
var b strings.Builder
74+
b.WriteString("--from=")
75+
if len(c.InputFormat) > 0 {
76+
b.WriteString(c.InputFormat)
77+
} else {
78+
b.WriteString("markdown")
79+
}
80+
81+
for _, extension := range c.InputExtensions {
82+
b.WriteString("+")
83+
b.WriteString(extension)
84+
}
85+
return b.String()
86+
}
87+
88+
func (c *Config) getOutputArg() string {
89+
var b strings.Builder
90+
b.WriteString("--to=")
91+
if c.UseLegacyHtml {
92+
b.WriteString("html")
93+
} else {
94+
b.WriteString("html5")
95+
}
96+
97+
for _, extension := range c.OutputExtensions {
98+
b.WriteString("+")
99+
b.WriteString(extension)
100+
}
101+
return b.String()
102+
}
103+
104+
func (c *Config) getMathRenderingArg() string {
105+
switch {
106+
case c.UseMathml:
107+
return "--mathml"
108+
case c.UseWebtex:
109+
return "--webtex"
110+
case c.UseKatex:
111+
return "--katex"
112+
default:
113+
return "--mathjax"
114+
}
115+
}
116+
117+
func (c *Config) getMetadataArgs() []string {
118+
var args []string
119+
for k, iv := range c.Metadata {
120+
var v string
121+
if sv, ok := iv.(string); ok {
122+
v = sv
123+
} else if sv, ok := iv.(fmt.Stringer); ok {
124+
v = sv.String()
125+
} else {
126+
v = fmt.Sprintf("%v", iv)
127+
}
128+
args = append(args, fmt.Sprintf("-M%s=%s", k, v))
129+
}
130+
return args
131+
}
132+
133+
func (c *Config) getFilterArgs() []string {
134+
var args []string
135+
for _, filterPath := range c.Filters {
136+
if strings.HasPrefix(filterPath, "lua:") || strings.HasSuffix(filterPath, ".lua") {
137+
args = append(args, fmt.Sprintf("--lua-filter=%s", strings.TrimPrefix(filterPath, "lua:")))
138+
} else {
139+
args = append(args, fmt.Sprintf("--filter=%s", filterPath))
140+
}
141+
}
142+
return args
143+
}
144+
145+
// AsPandocArguments returns a list of strings that can be used as arguments to
146+
// a "pandoc" invocation. All the settings contained in Config are represented
147+
// in the returned list of arguments.
148+
func (c *Config) AsPandocArguments() []string {
149+
args := []string{
150+
c.getInputArg(),
151+
c.getOutputArg(),
152+
c.getMathRenderingArg()}
153+
154+
args = append(args, c.getMetadataArgs()...)
155+
args = append(args, c.getFilterArgs()...)
156+
args = append(args, c.ExtraArgs...)
157+
158+
return args
159+
}

0 commit comments

Comments
 (0)