Skip to content

Commit 6a20d2b

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 0671ef5 commit 6a20d2b

File tree

4 files changed

+256
-23
lines changed

4 files changed

+256
-23
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

+6-2
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ import (
1818
"github.com/gohugoio/hugo/config"
1919
"github.com/gohugoio/hugo/docshelper"
2020
"github.com/gohugoio/hugo/markup/asciidocext/asciidocext_config"
21+
"github.com/gohugoio/hugo/markup/bibliography"
2122
"github.com/gohugoio/hugo/markup/blackfriday/blackfriday_config"
2223
"github.com/gohugoio/hugo/markup/goldmark/goldmark_config"
2324
"github.com/gohugoio/hugo/markup/highlight"
25+
"github.com/gohugoio/hugo/markup/pandoc/pandoc_config"
2426
"github.com/gohugoio/hugo/markup/tableofcontents"
2527
"github.com/gohugoio/hugo/parser"
2628
"github.com/mitchellh/mapstructure"
@@ -34,11 +36,12 @@ type Config struct {
3436

3537
Highlight highlight.Config
3638
TableOfContents tableofcontents.Config
39+
Bibliography bibliography.Config
3740

3841
// Content renderers
3942
Goldmark goldmark_config.Config
4043
BlackFriday blackfriday_config.Config
41-
44+
Pandoc pandoc_config.Config
4245
AsciidocExt asciidocext_config.Config
4346
}
4447

@@ -108,10 +111,11 @@ var Default = Config{
108111

109112
TableOfContents: tableofcontents.DefaultConfig,
110113
Highlight: highlight.DefaultConfig,
114+
Bibliography: bibliography.Default,
111115

112116
Goldmark: goldmark_config.Default,
113117
BlackFriday: blackfriday_config.Default,
114-
118+
Pandoc: pandoc_config.Default,
115119
AsciidocExt: asciidocext_config.Default,
116120
}
117121

Diff for: markup/pandoc/convert.go

+60-21
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"
25+
"github.com/gohugoio/hugo/markup/bibliography"
2126
"github.com/gohugoio/hugo/markup/internal"
27+
"github.com/gohugoio/hugo/markup/pandoc/pandoc_config"
2228

2329
"github.com/gohugoio/hugo/markup/converter"
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,54 +52,73 @@ 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.Result, error) {
47-
b, err := c.getPandocContent(ctx.Src, c.ctx)
48-
if err != nil {
49-
return nil, err
50-
}
51-
return converter.Bytes(b), nil
67+
return converter.Bytes(c.getPandocContent(ctx.Src)), nil
5268
}
5369

5470
func (c *pandocConverter) Supports(feature identity.Identity) bool {
5571
return false
5672
}
5773

5874
// 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) {
75+
func (c *pandocConverter) getPandocContent(src []byte) []byte {
6076
logger := c.cfg.Logger
61-
binaryName := getPandocBinaryName()
62-
if binaryName == "" {
77+
pandocPath, pandocFound := getPandocBinaryName()
78+
if !pandocFound {
6379
logger.Println("pandoc not found in $PATH: Please install.\n",
6480
" Leaving pandoc content unrendered.")
65-
return src, nil
81+
return src
6682
}
67-
args := []string{"--mathjax"}
68-
return internal.ExternallyRenderContent(c.cfg, ctx, src, binaryName, args)
83+
84+
var pandocConfig pandoc_config.Config = c.cfg.MarkupConfig.Pandoc
85+
var bibConfig bibliography.Config = c.cfg.MarkupConfig.Bibliography
86+
87+
if pageParameters, ok := c.docCtx.Document.(paramer); ok {
88+
if bibParam, err := pageParameters.Param("bibliography"); err == nil {
89+
mapstructure.WeakDecode(bibParam, &bibConfig)
90+
}
91+
92+
if pandocParam, err := pageParameters.Param("pandoc"); err == nil {
93+
mapstructure.WeakDecode(pandocParam, &pandocConfig)
94+
}
95+
}
96+
97+
arguments := pandocConfig.AsPandocArguments()
98+
99+
if bibConfig.Source != "" {
100+
arguments = append(arguments, "--citeproc", "--bibliography", bibConfig.Source)
101+
if bibConfig.CitationStyle != "" {
102+
arguments = append(arguments, "--csl", bibConfig.CitationStyle)
103+
}
104+
}
105+
106+
resourcePath := strings.Join([]string{path.Dir(c.docCtx.Filename), "static", "."}, ":")
107+
arguments = append(arguments, "--resource-path", resourcePath)
108+
109+
renderedContent, _ := internal.ExternallyRenderContent(c.cfg, c.docCtx, src, pandocPath, arguments)
110+
return renderedContent
69111
}
70112

71113
const pandocBinary = "pandoc"
72114

73-
func getPandocBinaryName() string {
74-
if hexec.InPath(pandocBinary) {
75-
return pandocBinary
76-
}
77-
return ""
115+
func getPandocBinaryName() (string, bool) {
116+
return pandocBinary, hexec.InPath(pandocBinary)
78117
}
79118

80119
// Supports returns whether Pandoc is installed on this computer.
81120
func Supports() bool {
82-
hasBin := getPandocBinaryName() != ""
121+
_, hasBin := getPandocBinaryName()
83122
if htesting.SupportsAll() {
84123
if !hasBin {
85124
panic("pandoc not installed")

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

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
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+
var Default = Config{
73+
InputFormat:"markdown",
74+
UseLegacyHtml:false,
75+
UseMathjax:true
76+
}
77+
78+
func (c *Config) getInputArg() string {
79+
var b strings.Builder
80+
b.WriteString("--from=")
81+
if len(c.InputFormat) > 0 {
82+
b.WriteString(c.InputFormat)
83+
} else {
84+
b.WriteString("markdown")
85+
}
86+
87+
for _, extension := range c.InputExtensions {
88+
b.WriteString("+")
89+
b.WriteString(extension)
90+
}
91+
return b.String()
92+
}
93+
94+
func (c *Config) getOutputArg() string {
95+
var b strings.Builder
96+
b.WriteString("--to=")
97+
if c.UseLegacyHtml {
98+
b.WriteString("html")
99+
} else {
100+
b.WriteString("html5")
101+
}
102+
103+
for _, extension := range c.OutputExtensions {
104+
b.WriteString("+")
105+
b.WriteString(extension)
106+
}
107+
return b.String()
108+
}
109+
110+
func (c *Config) getMathRenderingArg() string {
111+
switch {
112+
case c.UseMathml:
113+
return "--mathml"
114+
case c.UseWebtex:
115+
return "--webtex"
116+
case c.UseKatex:
117+
return "--katex"
118+
default:
119+
return "--mathjax"
120+
}
121+
}
122+
123+
func (c *Config) getMetadataArgs() []string {
124+
var args []string
125+
for k, iv := range c.Metadata {
126+
var v string
127+
if sv, ok := iv.(string); ok {
128+
v = sv
129+
} else if sv, ok := iv.(fmt.Stringer); ok {
130+
v = sv.String()
131+
} else {
132+
v = fmt.Sprintf("%v", iv)
133+
}
134+
args = append(args, fmt.Sprintf("-M%s=%s", k, v))
135+
}
136+
return args
137+
}
138+
139+
func (c *Config) getFilterArgs() []string {
140+
var args []string
141+
for _, filterPath := range c.Filters {
142+
if strings.HasPrefix(filterPath, "lua:") || strings.HasSuffix(filterPath, ".lua") {
143+
args = append(args, fmt.Sprintf("--lua-filter=%s", strings.TrimPrefix(filterPath, "lua:")))
144+
} else {
145+
args = append(args, fmt.Sprintf("--filter=%s", filterPath))
146+
}
147+
}
148+
return args
149+
}
150+
151+
// AsPandocArguments returns a list of strings that can be used as arguments to
152+
// a "pandoc" invocation. All the settings contained in Config are represented
153+
// in the returned list of arguments.
154+
func (c *Config) AsPandocArguments() []string {
155+
args := []string{
156+
c.getInputArg(),
157+
c.getOutputArg(),
158+
c.getMathRenderingArg()}
159+
160+
args = append(args, c.getMetadataArgs()...)
161+
args = append(args, c.getFilterArgs()...)
162+
args = append(args, c.ExtraArgs...)
163+
164+
return args
165+
}

0 commit comments

Comments
 (0)