mirror of
https://github.com/gohugoio/hugo.git
synced 2025-04-26 21:51:02 +03:00
Merge 861f9d5b7c
into a88b488181
This commit is contained in:
commit
45bbac2744
5 changed files with 210 additions and 6 deletions
50
docs/content/en/content-management/bibliography.md
Normal file
50
docs/content/en/content-management/bibliography.md
Normal file
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
title: Bibliographies in Markdown
|
||||
linkTitle: Bibliography
|
||||
description: Include citations and a bibliography in Markdown using LaTeX markup.
|
||||
categories: [content management]
|
||||
keywords: [latex,pandoc,citation,reference,bibliography]
|
||||
menu:
|
||||
docs:
|
||||
parent: content-management
|
||||
weight: 320
|
||||
weight: 320
|
||||
toc: true
|
||||
---
|
||||
|
||||
{{< new-in 0.144.0 />}}
|
||||
|
||||
## Citations and Bibliographies
|
||||
|
||||
[Pandoc](https://pandoc.org) is a universal document converter and can be used to convert markdown files.
|
||||
|
||||
With **Pandoc >= 2.11**, you can use [citations](https://pandoc.org/MANUAL.html#extension-citations).
|
||||
One way is to employ [BibTeX files](https://en.wikibooks.org/wiki/LaTeX/Bibliography_Management#BibTeX) to cite:
|
||||
|
||||
```
|
||||
---
|
||||
title: Citation document
|
||||
---
|
||||
---
|
||||
bibliography: assets/bibliography.bib
|
||||
...
|
||||
This is a citation: @Doe2022
|
||||
```
|
||||
|
||||
Note that Hugo will **not** pass its metadata YAML block to Pandoc; however, it will pass the **second** meta data block, denoted with `---` and `...` to Pandoc.
|
||||
Thus, all Pandoc-specific settings should go there.
|
||||
|
||||
You can also add all elements from a bibliography file (without citing them explicitly) using:
|
||||
|
||||
```
|
||||
---
|
||||
title: My Publications
|
||||
---
|
||||
---
|
||||
bibliography: assets/bibliography.bib
|
||||
nocite: |
|
||||
@*
|
||||
...
|
||||
```
|
||||
|
||||
It is also possible to provide a custom [CSL style](https://citationstyles.org/authors/) by passing `csl: path-to-style.csl` as a Pandoc option.
|
|
@ -105,6 +105,12 @@ Hugo passes these CLI flags when calling the Pandoc executable:
|
|||
--mathjax
|
||||
```
|
||||
|
||||
If your Pandoc has version 2.11 or later, it also passes this CLI flag:
|
||||
|
||||
```text
|
||||
--citeproc
|
||||
```
|
||||
|
||||
[Pandoc]: https://pandoc.org/
|
||||
|
||||
### reStructuredText
|
||||
|
|
|
@ -15,10 +15,12 @@
|
|||
package pandoc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sync"
|
||||
|
||||
"github.com/gohugoio/hugo/common/hexec"
|
||||
"github.com/gohugoio/hugo/htesting"
|
||||
"github.com/gohugoio/hugo/identity"
|
||||
|
||||
"github.com/gohugoio/hugo/markup/converter"
|
||||
"github.com/gohugoio/hugo/markup/internal"
|
||||
)
|
||||
|
@ -64,6 +66,9 @@ func (c *pandocConverter) getPandocContent(src []byte, ctx converter.DocumentCon
|
|||
return src, nil
|
||||
}
|
||||
args := []string{"--mathjax"}
|
||||
if supportsCitations(c.cfg) {
|
||||
args = append(args[:], "--citeproc")
|
||||
}
|
||||
return internal.ExternallyRenderContent(c.cfg, ctx, src, binaryName, args)
|
||||
}
|
||||
|
||||
|
@ -76,6 +81,45 @@ func getPandocBinaryName() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
var pandocSupportsCiteprocOnce sync.Once
|
||||
var pandocSupportsCiteproc bool
|
||||
|
||||
// getPandocSupportsCiteproc runs a dump-args to determine if pandoc knows the --citeproc argument
|
||||
func getPandocSupportsCiteproc(cfg converter.ProviderConfig) (bool, error) {
|
||||
var err error
|
||||
|
||||
pandocSupportsCiteprocOnce.Do(func() {
|
||||
argsv := []any{"--dump-args", "--citeproc"}
|
||||
|
||||
var out bytes.Buffer
|
||||
argsv = append(argsv, hexec.WithStdout(&out))
|
||||
|
||||
cmd, err := cfg.Exec.New(pandocBinary, argsv...)
|
||||
if err != nil {
|
||||
pandocSupportsCiteproc = false
|
||||
return
|
||||
}
|
||||
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
pandocSupportsCiteproc = false
|
||||
return
|
||||
}
|
||||
pandocSupportsCiteproc = true
|
||||
})
|
||||
|
||||
return pandocSupportsCiteproc, err
|
||||
}
|
||||
|
||||
// supportsCitations returns true if citeproc is available
|
||||
func supportsCitations(cfg converter.ProviderConfig) bool {
|
||||
if Supports() {
|
||||
supportsCiteproc, err := getPandocSupportsCiteproc(cfg)
|
||||
return supportsCiteproc && err == nil
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Supports returns whether Pandoc is installed on this computer.
|
||||
func Supports() bool {
|
||||
hasBin := getPandocBinaryName() != ""
|
||||
|
|
|
@ -25,7 +25,7 @@ import (
|
|||
qt "github.com/frankban/quicktest"
|
||||
)
|
||||
|
||||
func TestConvert(t *testing.T) {
|
||||
func setupTestConverter(t *testing.T) (*qt.C, converter.Converter, converter.ProviderConfig) {
|
||||
if !Supports() {
|
||||
t.Skip("pandoc not installed")
|
||||
}
|
||||
|
@ -34,11 +34,109 @@ func TestConvert(t *testing.T) {
|
|||
var err error
|
||||
sc.Exec.Allow, err = security.NewWhitelist("pandoc")
|
||||
c.Assert(err, qt.IsNil)
|
||||
p, err := Provider.New(converter.ProviderConfig{Exec: hexec.New(sc, "", loggers.NewDefault()), Logger: loggers.NewDefault()})
|
||||
cfg := converter.ProviderConfig{Exec: hexec.New(sc, "", loggers.NewDefault()), Logger: loggers.NewDefault()}
|
||||
p, err := Provider.New(cfg)
|
||||
c.Assert(err, qt.IsNil)
|
||||
conv, err := p.New(converter.DocumentContext{})
|
||||
c.Assert(err, qt.IsNil)
|
||||
b, err := conv.Convert(converter.RenderContext{Src: []byte("testContent")})
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(string(b.Bytes()), qt.Equals, "<p>testContent</p>\n")
|
||||
return c, conv, cfg
|
||||
}
|
||||
|
||||
func TestConvert(t *testing.T) {
|
||||
c, conv, _ := setupTestConverter(t)
|
||||
output, err := conv.Convert(converter.RenderContext{Src: []byte("testContent")})
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(string(output.Bytes()), qt.Equals, "<p>testContent</p>\n")
|
||||
}
|
||||
|
||||
func runCiteprocTest(t *testing.T, content string, expectContained []string, expectNotContained []string) {
|
||||
c, conv, cfg := setupTestConverter(t)
|
||||
if !supportsCitations(cfg) {
|
||||
t.Skip("pandoc does not support citations")
|
||||
}
|
||||
output, err := conv.Convert(converter.RenderContext{Src: []byte(content)})
|
||||
c.Assert(err, qt.IsNil)
|
||||
for _, expected := range expectContained {
|
||||
c.Assert(string(output.Bytes()), qt.Contains, expected)
|
||||
}
|
||||
for _, notExpected := range expectNotContained {
|
||||
c.Assert(string(output.Bytes()), qt.Not(qt.Contains), notExpected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPandocSupportsCiteprocCallTwice(t *testing.T) {
|
||||
c, _, cfg := setupTestConverter(t)
|
||||
|
||||
supports1, err1 := getPandocSupportsCiteproc(cfg)
|
||||
supports2, err2 := getPandocSupportsCiteproc(cfg)
|
||||
c.Assert(supports1, qt.Equals, supports2)
|
||||
c.Assert(err1, qt.IsNil)
|
||||
c.Assert(err2, qt.IsNil)
|
||||
}
|
||||
|
||||
func TestCiteprocWithHugoMeta(t *testing.T) {
|
||||
content := `
|
||||
---
|
||||
title: Test
|
||||
published: 2022-05-30
|
||||
---
|
||||
testContent
|
||||
`
|
||||
expected := []string{"testContent"}
|
||||
unexpected := []string{"Doe", "Mustermann", "2022", "Treatise"}
|
||||
runCiteprocTest(t, content, expected, unexpected)
|
||||
}
|
||||
|
||||
func TestCiteprocWithPandocMeta(t *testing.T) {
|
||||
content := `
|
||||
---
|
||||
---
|
||||
---
|
||||
...
|
||||
testContent
|
||||
`
|
||||
expected := []string{"testContent"}
|
||||
unexpected := []string{"Doe", "Mustermann", "2022", "Treatise"}
|
||||
runCiteprocTest(t, content, expected, unexpected)
|
||||
}
|
||||
|
||||
func TestCiteprocWithBibliography(t *testing.T) {
|
||||
content := `
|
||||
---
|
||||
---
|
||||
---
|
||||
bibliography: testdata/bibliography.bib
|
||||
...
|
||||
testContent
|
||||
`
|
||||
expected := []string{"testContent"}
|
||||
unexpected := []string{"Doe", "Mustermann", "2022", "Treatise"}
|
||||
runCiteprocTest(t, content, expected, unexpected)
|
||||
}
|
||||
|
||||
func TestCiteprocWithExplicitCitation(t *testing.T) {
|
||||
content := `
|
||||
---
|
||||
---
|
||||
---
|
||||
bibliography: testdata/bibliography.bib
|
||||
...
|
||||
@Doe2022
|
||||
`
|
||||
expected := []string{"Doe", "Mustermann", "2022", "Treatise"}
|
||||
runCiteprocTest(t, content, expected, []string{})
|
||||
}
|
||||
|
||||
func TestCiteprocWithNocite(t *testing.T) {
|
||||
content := `
|
||||
---
|
||||
---
|
||||
---
|
||||
bibliography: testdata/bibliography.bib
|
||||
nocite: |
|
||||
@*
|
||||
...
|
||||
`
|
||||
expected := []string{"Doe", "Mustermann", "2022", "Treatise"}
|
||||
runCiteprocTest(t, content, expected, []string{})
|
||||
}
|
||||
|
|
6
markup/pandoc/testdata/bibliography.bib
vendored
Normal file
6
markup/pandoc/testdata/bibliography.bib
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
@article{Doe2022,
|
||||
author = "Jane Doe and Max Mustermann",
|
||||
title = "A Treatise on Hugo Tests",
|
||||
journal = "Hugo Websites",
|
||||
year = "2022",
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue