-
Notifications
You must be signed in to change notification settings - Fork 13
/
plugins.go
150 lines (126 loc) · 4.44 KB
/
plugins.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Package plugins holds emulated Jekyll plugins.
//
// Unlike Jekyll, these are baked into the executable -- both because package "plugin'
// works only on Linux (as of 2017.07); and because the gojekyll implementation is immature and any possible interfaces
// are far from baked.
package plugins
import (
"fmt"
"regexp"
"github.com/kyokomi/emoji"
"github.com/osteele/gojekyll/config"
"github.com/osteele/gojekyll/pages"
"github.com/osteele/gojekyll/utils"
"github.com/osteele/liquid"
)
// Plugin describes the hooks that a plugin can override.
type Plugin interface {
Initialize(Site) error
ConfigureTemplateEngine(*liquid.Engine) error
ModifySiteDrop(Site, map[string]interface{}) error
PostRead(Site) error
PostRender([]byte) []byte
}
// Site is the site interface that is available to a plugin.
type Site interface {
AddDocument(pages.Document, bool)
Config() *config.Config
TemplateEngine() *liquid.Engine
Pages() []pages.Page
}
// Lookup returns a plugin if it has been registered.
func Lookup(name string) (Plugin, bool) {
p, found := directory[name]
return p, found
}
// Install installs a registered plugin.
func Install(names []string, site Site) {
for _, name := range names {
if p, found := directory[name]; found {
if err := p.Initialize(site); err != nil {
panic(err)
}
} else {
fmt.Printf("warning: gojekyll does not emulate the %s plugin.\n", name)
}
}
}
// Embed plugin to implement defaults implementations of the Plugin interface.
//
// This is internal until better baked.
type plugin struct{}
func (p plugin) Initialize(Site) error { return nil }
func (p plugin) ConfigureTemplateEngine(*liquid.Engine) error { return nil }
func (p plugin) ModifySiteDrop(Site, map[string]interface{}) error { return nil }
func (p plugin) PostRead(Site) error { return nil }
func (p plugin) PostRender(b []byte) []byte { return b }
var directory = map[string]Plugin{}
// register installs a plugin in the plugin directory.
//
// This is internal until better baked.
func register(name string, p Plugin) {
directory[name] = p
}
// Add the built-in plugins defined in this file.
// More extensive plugins are defined and registered in own files.
func init() {
register("jemoji", jemojiPlugin{})
register("jekyll-mentions", jekyllMentionsPlugin{})
register("jekyll-optional-front-matter", jekyllOptionalFrontMatterPlugin{})
// Gojekyll behaves as though the following plugins are always loaded.
// Define them here so we don't see warnings that they aren't defined.
register("jekyll-live-reload", plugin{})
register("jekyll-sass-converter", plugin{})
}
// Some small plugins are below. More involved plugins are in separate files.
// jemojiPlugin emulates the jekyll-jemoji plugin.
type jemojiPlugin struct{ plugin }
func (p jemojiPlugin) PostRender(b []byte) []byte {
return utils.ApplyToHTMLText(b, func(s string) string {
s = emoji.Sprint(s)
return s
})
}
// jekyllMentionsPlugin emulates the jekyll-mentions plugin.
type jekyllMentionsPlugin struct{ plugin }
var mentionPattern = regexp.MustCompile(`@(\w+)`)
func (p jekyllMentionsPlugin) PostRender(b []byte) []byte {
return utils.ApplyToHTMLText(b, func(s string) string {
return mentionPattern.ReplaceAllString(s, `<a href="https://github.com/$1" class="user-mention">@$1</a>`)
})
}
// jekyllOptionalFrontMatterPlugin emulates the jekyll-optional-front-matter plugin.
type jekyllOptionalFrontMatterPlugin struct{ plugin }
var requireFrontMatterExclude = []string{
"README",
"LICENSE",
"LICENCE",
"COPYING",
"CODE_OF_CONDUCT",
"CONTRIBUTING",
"ISSUE_TEMPLATE",
"PULL_REQUEST_TEMPLATE",
}
func (p jekyllOptionalFrontMatterPlugin) Initialize(s Site) error {
m := map[string]bool{}
for _, k := range requireFrontMatterExclude {
m[k] = true
}
s.Config().RequireFrontMatter = false
s.Config().RequireFrontMatterExclude = m
return nil
}
// helpers
// func (p plugin) stubbed(name string) {
// fmt.Printf("warning: gojekyll does not emulate the %s plugin. Some tags have been stubbed to prevent errors.\n", name)
// }
// func (p plugin) makeUnimplementedTag(pluginName string) liquid.Renderer {
// warned := false
// return func(ctx render.Context) (string, error) {
// if !warned {
// fmt.Printf("The %q tag in the %q plugin has not been implemented.\n", ctx.TagName(), pluginName)
// warned = true
// }
// return fmt.Sprintf(`<!-- unimplemented tag: %q -->`, ctx.TagName()), nil
// }
// }