mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
parent
f98e570b17
commit
5697348e17
4 changed files with 105 additions and 19 deletions
|
@ -94,7 +94,7 @@ func newMarkdown(pcfg converter.ProviderConfig) goldmark.Markdown {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
extensions = []goldmark.Extender{
|
extensions = []goldmark.Extender{
|
||||||
newLinks(),
|
newLinks(cfg),
|
||||||
newTocExtension(rendererOptions),
|
newTocExtension(rendererOptions),
|
||||||
}
|
}
|
||||||
parserOptions []parser.Option
|
parserOptions []parser.Option
|
||||||
|
|
|
@ -23,13 +23,14 @@ const (
|
||||||
// DefaultConfig holds the default Goldmark configuration.
|
// DefaultConfig holds the default Goldmark configuration.
|
||||||
var Default = Config{
|
var Default = Config{
|
||||||
Extensions: Extensions{
|
Extensions: Extensions{
|
||||||
Typographer: true,
|
Typographer: true,
|
||||||
Footnote: true,
|
Footnote: true,
|
||||||
DefinitionList: true,
|
DefinitionList: true,
|
||||||
Table: true,
|
Table: true,
|
||||||
Strikethrough: true,
|
Strikethrough: true,
|
||||||
Linkify: true,
|
Linkify: true,
|
||||||
TaskList: true,
|
LinkifyProtocol: "https",
|
||||||
|
TaskList: true,
|
||||||
},
|
},
|
||||||
Renderer: Renderer{
|
Renderer: Renderer{
|
||||||
Unsafe: false,
|
Unsafe: false,
|
||||||
|
@ -57,10 +58,11 @@ type Extensions struct {
|
||||||
DefinitionList bool
|
DefinitionList bool
|
||||||
|
|
||||||
// GitHub flavored markdown
|
// GitHub flavored markdown
|
||||||
Table bool
|
Table bool
|
||||||
Strikethrough bool
|
Strikethrough bool
|
||||||
Linkify bool
|
Linkify bool
|
||||||
TaskList bool
|
LinkifyProtocol string
|
||||||
|
TaskList bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Renderer struct {
|
type Renderer struct {
|
||||||
|
|
|
@ -423,3 +423,70 @@ title: "p1"
|
||||||
<img src="b.jpg" alt=""a"">
|
<img src="b.jpg" alt=""a"">
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLinkifyProtocol(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
runTest := func(protocol string, withHook bool) *hugolib.IntegrationTestBuilder {
|
||||||
|
|
||||||
|
files := `
|
||||||
|
-- config.toml --
|
||||||
|
[markup.goldmark]
|
||||||
|
[markup.goldmark.extensions]
|
||||||
|
linkify = true
|
||||||
|
linkifyProtocol = "PROTOCOL"
|
||||||
|
-- content/p1.md --
|
||||||
|
---
|
||||||
|
title: "p1"
|
||||||
|
---
|
||||||
|
Link no procol: www.example.org
|
||||||
|
Link http procol: http://www.example.org
|
||||||
|
Link https procol: https://www.example.org
|
||||||
|
|
||||||
|
-- layouts/_default/single.html --
|
||||||
|
{{ .Content }}
|
||||||
|
`
|
||||||
|
files = strings.ReplaceAll(files, "PROTOCOL", protocol)
|
||||||
|
|
||||||
|
if withHook {
|
||||||
|
files += `-- layouts/_default/_markup/render-link.html --
|
||||||
|
<a href="{{ .Destination | safeURL }}">{{ .Text | safeHTML }}</a>`
|
||||||
|
}
|
||||||
|
|
||||||
|
return hugolib.NewIntegrationTestBuilder(
|
||||||
|
hugolib.IntegrationTestConfig{
|
||||||
|
T: t,
|
||||||
|
TxtarString: files,
|
||||||
|
},
|
||||||
|
).Build()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, withHook := range []bool{false, true} {
|
||||||
|
|
||||||
|
b := runTest("https", withHook)
|
||||||
|
|
||||||
|
b.AssertFileContent("public/p1/index.html",
|
||||||
|
"Link no procol: <a href=\"https://www.example.org\">www.example.org</a>",
|
||||||
|
"Link http procol: <a href=\"http://www.example.org\">http://www.example.org</a>",
|
||||||
|
"Link https procol: <a href=\"https://www.example.org\">https://www.example.org</a></p>",
|
||||||
|
)
|
||||||
|
|
||||||
|
b = runTest("http", withHook)
|
||||||
|
|
||||||
|
b.AssertFileContent("public/p1/index.html",
|
||||||
|
"Link no procol: <a href=\"http://www.example.org\">www.example.org</a>",
|
||||||
|
"Link http procol: <a href=\"http://www.example.org\">http://www.example.org</a>",
|
||||||
|
"Link https procol: <a href=\"https://www.example.org\">https://www.example.org</a></p>",
|
||||||
|
)
|
||||||
|
|
||||||
|
b = runTest("gopher", withHook)
|
||||||
|
|
||||||
|
b.AssertFileContent("public/p1/index.html",
|
||||||
|
"Link no procol: <a href=\"gopher://www.example.org\">www.example.org</a>",
|
||||||
|
"Link http procol: <a href=\"http://www.example.org\">http://www.example.org</a>",
|
||||||
|
"Link https procol: <a href=\"https://www.example.org\">https://www.example.org</a></p>",
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gohugoio/hugo/markup/converter/hooks"
|
"github.com/gohugoio/hugo/markup/converter/hooks"
|
||||||
|
"github.com/gohugoio/hugo/markup/goldmark/goldmark_config"
|
||||||
"github.com/gohugoio/hugo/markup/goldmark/internal/render"
|
"github.com/gohugoio/hugo/markup/goldmark/internal/render"
|
||||||
"github.com/gohugoio/hugo/markup/internal/attributes"
|
"github.com/gohugoio/hugo/markup/internal/attributes"
|
||||||
|
|
||||||
|
@ -30,8 +31,9 @@ import (
|
||||||
|
|
||||||
var _ renderer.SetOptioner = (*hookedRenderer)(nil)
|
var _ renderer.SetOptioner = (*hookedRenderer)(nil)
|
||||||
|
|
||||||
func newLinkRenderer() renderer.NodeRenderer {
|
func newLinkRenderer(cfg goldmark_config.Config) renderer.NodeRenderer {
|
||||||
r := &hookedRenderer{
|
r := &hookedRenderer{
|
||||||
|
linkifyProtocol: []byte(cfg.Extensions.LinkifyProtocol),
|
||||||
Config: html.Config{
|
Config: html.Config{
|
||||||
Writer: html.DefaultWriter,
|
Writer: html.DefaultWriter,
|
||||||
},
|
},
|
||||||
|
@ -39,8 +41,8 @@ func newLinkRenderer() renderer.NodeRenderer {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLinks() goldmark.Extender {
|
func newLinks(cfg goldmark_config.Config) goldmark.Extender {
|
||||||
return &links{}
|
return &links{cfg: cfg}
|
||||||
}
|
}
|
||||||
|
|
||||||
type linkContext struct {
|
type linkContext struct {
|
||||||
|
@ -105,6 +107,7 @@ func (ctx headingContext) PlainText() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
type hookedRenderer struct {
|
type hookedRenderer struct {
|
||||||
|
linkifyProtocol []byte
|
||||||
html.Config
|
html.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +282,7 @@ func (r *hookedRenderer) renderAutoLink(w util.BufWriter, source []byte, node as
|
||||||
return r.renderAutoLinkDefault(w, source, node, entering)
|
return r.renderAutoLinkDefault(w, source, node, entering)
|
||||||
}
|
}
|
||||||
|
|
||||||
url := string(n.URL(source))
|
url := string(r.autoLinkURL(n, source))
|
||||||
label := string(n.Label(source))
|
label := string(n.Label(source))
|
||||||
if n.AutoLinkType == ast.AutoLinkEmail && !strings.HasPrefix(strings.ToLower(url), "mailto:") {
|
if n.AutoLinkType == ast.AutoLinkEmail && !strings.HasPrefix(strings.ToLower(url), "mailto:") {
|
||||||
url = "mailto:" + url
|
url = "mailto:" + url
|
||||||
|
@ -310,8 +313,9 @@ func (r *hookedRenderer) renderAutoLinkDefault(w util.BufWriter, source []byte,
|
||||||
if !entering {
|
if !entering {
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = w.WriteString(`<a href="`)
|
_, _ = w.WriteString(`<a href="`)
|
||||||
url := n.URL(source)
|
url := r.autoLinkURL(n, source)
|
||||||
label := n.Label(source)
|
label := n.Label(source)
|
||||||
if n.AutoLinkType == ast.AutoLinkEmail && !bytes.HasPrefix(bytes.ToLower(url), []byte("mailto:")) {
|
if n.AutoLinkType == ast.AutoLinkEmail && !bytes.HasPrefix(bytes.ToLower(url), []byte("mailto:")) {
|
||||||
_, _ = w.WriteString("mailto:")
|
_, _ = w.WriteString("mailto:")
|
||||||
|
@ -329,6 +333,17 @@ func (r *hookedRenderer) renderAutoLinkDefault(w util.BufWriter, source []byte,
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *hookedRenderer) autoLinkURL(n *ast.AutoLink, source []byte) []byte {
|
||||||
|
url := n.URL(source)
|
||||||
|
if len(n.Protocol) > 0 && !bytes.Equal(n.Protocol, r.linkifyProtocol) {
|
||||||
|
// The CommonMark spec says "http" is the correct protocol for links,
|
||||||
|
// but this doesn't make much sense (the fact that they should care about the rendered output).
|
||||||
|
// Note that n.Protocol is not set if protocol is provided by user.
|
||||||
|
url = append(r.linkifyProtocol, url[len(n.Protocol):]...)
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
func (r *hookedRenderer) renderHeading(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
|
func (r *hookedRenderer) renderHeading(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
|
||||||
n := node.(*ast.Heading)
|
n := node.(*ast.Heading)
|
||||||
var hr hooks.HeadingRenderer
|
var hr hooks.HeadingRenderer
|
||||||
|
@ -394,11 +409,13 @@ func (r *hookedRenderer) renderHeadingDefault(w util.BufWriter, source []byte, n
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type links struct{}
|
type links struct {
|
||||||
|
cfg goldmark_config.Config
|
||||||
|
}
|
||||||
|
|
||||||
// Extend implements goldmark.Extender.
|
// Extend implements goldmark.Extender.
|
||||||
func (e *links) Extend(m goldmark.Markdown) {
|
func (e *links) Extend(m goldmark.Markdown) {
|
||||||
m.Renderer().AddOptions(renderer.WithNodeRenderers(
|
m.Renderer().AddOptions(renderer.WithNodeRenderers(
|
||||||
util.Prioritized(newLinkRenderer(), 100),
|
util.Prioritized(newLinkRenderer(e.cfg), 100),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue