-
Notifications
You must be signed in to change notification settings - Fork 0
/
markdown_ex.go
115 lines (102 loc) · 2.98 KB
/
markdown_ex.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package markdown_ex
import (
"bytes"
"sync"
"text/template"
"github.com/alecthomas/chroma/v2/formatters/html"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
"github.com/caddyserver/caddy/v2/modules/caddyhttp/templates"
"github.com/ueffel/mdtohtml/tasklistitem"
"github.com/yuin/goldmark"
highlighting "github.com/yuin/goldmark-highlighting/v2"
"github.com/yuin/goldmark/extension"
"github.com/yuin/goldmark/parser"
gmhtml "github.com/yuin/goldmark/renderer/html"
"go.abhg.dev/goldmark/mermaid"
)
var bufPool = sync.Pool{New: func() any { return new(bytes.Buffer) }}
// MarkdownEx exposes the template function "markdown_ex" which uses a custom markdown renderer that
// includes
// - the html class "task-list-item" for item if a TaskList
// - support for mermaidJS syntax
type MarkdownEx struct {
md goldmark.Markdown
MermaidJS string `json:"mermaid_js"`
}
// CaddyModule returns the Caddy module information.
func (MarkdownEx) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "http.handlers.templates.functions.markdown_ex",
New: func() caddy.Module { return &MarkdownEx{} },
}
}
// CustomTemplateFunctions should return the mapping from custom function names to implementations.
// markdown_ex uses a custom markdown renderer that includes
// - the html class "task-list-item" for items of a TaskList
// - support for mermaidJS syntax
func (m *MarkdownEx) CustomTemplateFunctions() template.FuncMap {
return template.FuncMap{"markdown_ex": func(input any) (string, error) {
inputStr := caddy.ToString(input)
buf := bufPool.Get().(*bytes.Buffer)
defer bufPool.Put(buf)
buf.Reset()
err := m.md.Convert([]byte(inputStr), buf)
if err != nil {
return "", err
}
return buf.String(), nil
}}
}
func (m *MarkdownEx) Provision(ctx caddy.Context) error {
m.md = goldmark.New(
goldmark.WithExtensions(
extension.GFM,
extension.Footnote,
highlighting.NewHighlighting(
highlighting.WithFormatOptions(
html.WithClasses(true),
),
),
extension.Linkify,
extension.Strikethrough,
extension.TaskList,
tasklistitem.TaskListItemClass,
&mermaid.Extender{MermaidURL: m.MermaidJS},
),
goldmark.WithParserOptions(
parser.WithAutoHeadingID(),
),
goldmark.WithRendererOptions(
gmhtml.WithUnsafe(),
),
)
return nil
}
func (m *MarkdownEx) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
for d.Next() {
for nesting := d.Nesting(); d.NextBlock(nesting); {
switch d.Val() {
case "mermaid_js":
if !d.NextArg() {
return d.ArgErr()
}
m.MermaidJS = d.Val()
default:
return d.ArgErr()
}
}
}
return nil
}
// init registers the caddy module and the markdown_ex directive.
func init() {
caddy.RegisterModule(MarkdownEx{})
}
// Interface guards.
var (
_ caddy.Module = (*MarkdownEx)(nil)
_ templates.CustomFunctions = (*MarkdownEx)(nil)
_ caddyfile.Unmarshaler = (*MarkdownEx)(nil)
_ caddy.Provisioner = (*MarkdownEx)(nil)
)