mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-14 20:37:55 -05:00
markup/goldmark: Add config options for the typographer extension
Note that the config per language part of this will be handled in #10602. Updates #9772
This commit is contained in:
parent
d01731d53c
commit
5596dc24a0
5 changed files with 139 additions and 12 deletions
|
@ -20,6 +20,7 @@ import (
|
|||
"github.com/gohugoio/hugo/identity"
|
||||
|
||||
"github.com/gohugoio/hugo/markup/goldmark/codeblocks"
|
||||
"github.com/gohugoio/hugo/markup/goldmark/goldmark_config"
|
||||
"github.com/gohugoio/hugo/markup/goldmark/images"
|
||||
"github.com/gohugoio/hugo/markup/goldmark/internal/extensions/attributes"
|
||||
"github.com/gohugoio/hugo/markup/goldmark/internal/render"
|
||||
|
@ -120,8 +121,11 @@ func newMarkdown(pcfg converter.ProviderConfig) goldmark.Markdown {
|
|||
extensions = append(extensions, extension.TaskList)
|
||||
}
|
||||
|
||||
if cfg.Extensions.Typographer {
|
||||
extensions = append(extensions, extension.Typographer)
|
||||
if !cfg.Extensions.Typographer.Disable {
|
||||
t := extension.NewTypographer(
|
||||
extension.WithTypographicSubstitutions(toTypographicPunctuationMap(cfg.Extensions.Typographer)),
|
||||
)
|
||||
extensions = append(extensions, t)
|
||||
}
|
||||
|
||||
if cfg.Extensions.DefinitionList {
|
||||
|
@ -278,3 +282,21 @@ func (p *parserContext) TableOfContents() *tableofcontents.Fragments {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Note: It's tempting to put this in the config package, but that doesn't work.
|
||||
// TODO(bep) create upstream issue.
|
||||
func toTypographicPunctuationMap(t goldmark_config.Typographer) map[extension.TypographicPunctuation][]byte {
|
||||
return map[extension.TypographicPunctuation][]byte{
|
||||
extension.LeftSingleQuote: []byte(t.LeftSingleQuote),
|
||||
extension.RightSingleQuote: []byte(t.RightSingleQuote),
|
||||
extension.LeftDoubleQuote: []byte(t.LeftDoubleQuote),
|
||||
extension.RightDoubleQuote: []byte(t.RightDoubleQuote),
|
||||
extension.EnDash: []byte(t.EnDash),
|
||||
extension.EmDash: []byte(t.EmDash),
|
||||
extension.Ellipsis: []byte(t.Ellipsis),
|
||||
extension.LeftAngleQuote: []byte(t.LeftAngleQuote),
|
||||
extension.RightAngleQuote: []byte(t.RightAngleQuote),
|
||||
extension.Apostrophe: []byte(t.Apostrophe),
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -499,3 +499,18 @@ LINE5
|
|||
c.Assert(result, qt.Contains, "<span class=\"ln\">2</span><span class=\"cl\">LINE2\n</span></span>")
|
||||
})
|
||||
}
|
||||
|
||||
func TestTypographerConfig(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
|
||||
content := `
|
||||
A "quote" and 'another quote' and a "quote with a 'nested' quote" and a 'quote with a "nested" quote' and an ellipsis...
|
||||
`
|
||||
mconf := markup_config.Default
|
||||
mconf.Goldmark.Extensions.Typographer.LeftDoubleQuote = "«"
|
||||
mconf.Goldmark.Extensions.Typographer.RightDoubleQuote = "»"
|
||||
b := convert(c, mconf, content)
|
||||
got := string(b.Bytes())
|
||||
|
||||
c.Assert(got, qt.Contains, "<p>A «quote» and ‘another quote’ and a «quote with a ’nested’ quote» and a ‘quote with a «nested» quote’ and an ellipsis…</p>\n")
|
||||
}
|
||||
|
|
|
@ -23,7 +23,19 @@ const (
|
|||
// DefaultConfig holds the default Goldmark configuration.
|
||||
var Default = Config{
|
||||
Extensions: Extensions{
|
||||
Typographer: true,
|
||||
Typographer: Typographer{
|
||||
Disable: false,
|
||||
LeftSingleQuote: "‘",
|
||||
RightSingleQuote: "’",
|
||||
LeftDoubleQuote: "“",
|
||||
RightDoubleQuote: "”",
|
||||
EnDash: "–",
|
||||
EmDash: "—",
|
||||
Ellipsis: "…",
|
||||
LeftAngleQuote: "«",
|
||||
RightAngleQuote: "»",
|
||||
Apostrophe: "’",
|
||||
},
|
||||
Footnote: true,
|
||||
DefinitionList: true,
|
||||
Table: true,
|
||||
|
@ -54,7 +66,7 @@ type Config struct {
|
|||
}
|
||||
|
||||
type Extensions struct {
|
||||
Typographer bool
|
||||
Typographer Typographer
|
||||
Footnote bool
|
||||
DefinitionList bool
|
||||
|
||||
|
@ -66,6 +78,33 @@ type Extensions struct {
|
|||
TaskList bool
|
||||
}
|
||||
|
||||
// Typographer holds typographer configuration.
|
||||
type Typographer struct {
|
||||
// Whether to disable typographer.
|
||||
Disable bool
|
||||
|
||||
// Value used for left single quote.
|
||||
LeftSingleQuote string
|
||||
// Value used for right single quote.
|
||||
RightSingleQuote string
|
||||
// Value used for left double quote.
|
||||
LeftDoubleQuote string
|
||||
// Value used for right double quote.
|
||||
RightDoubleQuote string
|
||||
// Value used for en dash.
|
||||
EnDash string
|
||||
// Value used for em dash.
|
||||
EmDash string
|
||||
// Value used for ellipsis.
|
||||
Ellipsis string
|
||||
// Value used for left angle quote.
|
||||
LeftAngleQuote string
|
||||
// Value used for right angle quote.
|
||||
RightAngleQuote string
|
||||
// Value used for apostrophe.
|
||||
Apostrophe string
|
||||
}
|
||||
|
||||
type Renderer struct {
|
||||
// Whether softline breaks should be rendered as '<br>'
|
||||
HardWraps bool
|
||||
|
|
|
@ -62,15 +62,32 @@ func Decode(cfg config.Provider) (conf Config, err error) {
|
|||
|
||||
func normalizeConfig(m map[string]any) {
|
||||
v, err := maps.GetNestedParam("goldmark.parser", ".", m)
|
||||
if err != nil {
|
||||
return
|
||||
if err == nil {
|
||||
vm := maps.ToStringMap(v)
|
||||
// Changed from a bool in 0.81.0
|
||||
if vv, found := vm["attribute"]; found {
|
||||
if vvb, ok := vv.(bool); ok {
|
||||
vm["attribute"] = goldmark_config.ParserAttribute{
|
||||
Title: vvb,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
vm := maps.ToStringMap(v)
|
||||
// Changed from a bool in 0.81.0
|
||||
if vv, found := vm["attribute"]; found {
|
||||
if vvb, ok := vv.(bool); ok {
|
||||
vm["attribute"] = goldmark_config.ParserAttribute{
|
||||
Title: vvb,
|
||||
|
||||
// Changed from a bool in 0.112.0.
|
||||
v, err = maps.GetNestedParam("goldmark.extensions", ".", m)
|
||||
if err == nil {
|
||||
vm := maps.ToStringMap(v)
|
||||
const typographerKey = "typographer"
|
||||
if vv, found := vm[typographerKey]; found {
|
||||
if vvb, ok := vv.(bool); ok {
|
||||
if !vvb {
|
||||
vm[typographerKey] = goldmark_config.Typographer{
|
||||
Disable: true,
|
||||
}
|
||||
} else {
|
||||
delete(vm, typographerKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,4 +52,38 @@ func TestConfig(t *testing.T) {
|
|||
c.Assert(conf.AsciidocExt.Extensions[0], qt.Equals, "asciidoctor-html5s")
|
||||
})
|
||||
|
||||
c.Run("Decode legacy typographer", func(c *qt.C) {
|
||||
c.Parallel()
|
||||
v := config.New()
|
||||
|
||||
// typographer was changed from a bool to a struct in 0.112.0.
|
||||
v.Set("markup", map[string]any{
|
||||
"goldmark": map[string]any{
|
||||
"extensions": map[string]any{
|
||||
"typographer": false,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
conf, err := Decode(v)
|
||||
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(conf.Goldmark.Extensions.Typographer.Disable, qt.Equals, true)
|
||||
|
||||
v.Set("markup", map[string]any{
|
||||
"goldmark": map[string]any{
|
||||
"extensions": map[string]any{
|
||||
"typographer": true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
conf, err = Decode(v)
|
||||
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(conf.Goldmark.Extensions.Typographer.Disable, qt.Equals, false)
|
||||
c.Assert(conf.Goldmark.Extensions.Typographer.Ellipsis, qt.Equals, "…")
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue