1
0
mirror of https://github.com/danog/gojekyll.git synced 2024-11-30 09:59:03 +01:00

Add a plugin emulation mechanism

This commit is contained in:
Oliver Steele 2017-06-30 12:53:34 -04:00
parent 564ada3cab
commit 7e50bb1de1
5 changed files with 111 additions and 6 deletions

View File

@ -23,6 +23,9 @@ type Config struct {
Exclude []string
MarkdownExt string `yaml:"markdown_ext"`
// Plugins
Plugins []string `yaml:"gems"` // TODO this differs from the Jekyll docs
// Serving
AbsoluteURL string `yaml:"url"`
BaseURL string
@ -78,6 +81,7 @@ func (c *Config) GetFrontMatterDefaults(relpath, typename string) (m templates.V
}
// From https://jekyllrb.com/docs/configuration/#default-configuration
// The following includes only those keys that are currently implemented.
const defaultSiteConfig = `
# Where things are
source: .
@ -97,6 +101,9 @@ encoding: "utf-8"
markdown_ext: "markdown,mkdown,mkdn,mkd,md"
strict_front_matter: false
# Plugins
plugins: []
# Outputting
permalink: date
paginate_path: /page:num

View File

@ -4,12 +4,14 @@ import (
"io"
"github.com/osteele/liquid"
"github.com/osteele/liquid/chunks"
)
// Engine is a configured liquid engine.
type Engine interface {
Parse([]byte) (liquid.Template, error)
ParseAndRender([]byte, map[string]interface{}) ([]byte, error)
DefineTag(string, func(string) (func(io.Writer, chunks.Context) error, error))
}
// Wrapper is a wrapper around the Liquid engine.
@ -35,6 +37,11 @@ func NewEngine() *Wrapper {
return e
}
// DefineTag is in the Engine interface.
func (e *Wrapper) DefineTag(name string, f func(string) (func(io.Writer, chunks.Context) error, error)) {
e.engine.DefineTag(name, f)
}
// LinkTagHandler sets the link tag handler.
func (e *Wrapper) LinkTagHandler(h LinkTagHandler) {
e.linkHandler = h

View File

@ -30,7 +30,6 @@ type Pipeline struct {
// PipelineOptions configures a pipeline.
type PipelineOptions struct {
SourceDir string
AbsoluteURL, BaseURL string
RelativeFilenameToURL liquid.LinkTagHandler
}
@ -44,6 +43,11 @@ func NewPipeline(c config.Config, options PipelineOptions) (*Pipeline, error) {
return &p, nil
}
// Engine returns the Liquid engine.
func (p *Pipeline) TemplateEngine() liquid.Engine {
return p.liquidEngine
}
// OutputExt returns the output extension.
func (p *Pipeline) OutputExt(pathname string) string {
return p.config.OutputExt(pathname)
@ -108,9 +112,9 @@ func (p *Pipeline) makeLiquidEngine() liquid.Engine {
_, err = w.Write(text)
return err
}
engine.AbsoluteURL = p.config.AbsoluteURL
engine.BaseURL = p.config.BaseURL
engine.IncludeHandler(includeHandler)
engine.LinkTagHandler(p.RelativeFilenameToURL)
engine.AbsoluteURL = p.AbsoluteURL
engine.BaseURL = p.BaseURL
return engine
}

74
plugins/plugins.go Normal file
View File

@ -0,0 +1,74 @@
package plugins
import (
"fmt"
"io"
"strings"
"github.com/osteele/gojekyll/liquid"
"github.com/osteele/liquid/chunks"
)
type PluginContext interface {
TemplateEngine() liquid.Engine
}
func Install(name string, ctx PluginContext) bool {
p, found := plugins[name]
if p != nil {
if err := p(ctx); err != nil {
panic(err)
}
}
return found
}
var plugins = map[string]func(PluginContext) error{}
func registerPlugin(name string, fn func(PluginContext) error) {
plugins[name] = fn
}
func warnUnimplemented(name string) {
fmt.Printf("warning: gojekyll does not emulate the %s plugin. Some tags have been stubbed to prevent errors.\n", name)
}
func emptyTag(lexer string) (func(io.Writer, chunks.Context) error, error) {
return func(w io.Writer, _ chunks.Context) error { return nil }, nil
}
func init() {
registerPlugin("jekyll-avatar", func(ctx PluginContext) error {
warnUnimplemented("jekyll-avatar")
ctx.TemplateEngine().DefineTag("avatar", avatarTag)
return nil
})
registerPlugin("jekyll-feed", func(ctx PluginContext) error {
warnUnimplemented("jekyll-feed")
ctx.TemplateEngine().DefineTag("feed_meta", emptyTag)
return nil
})
registerPlugin("jekyll-seo-tag", func(ctx PluginContext) error {
warnUnimplemented("jekyll-seo-tag")
ctx.TemplateEngine().DefineTag("seo", emptyTag)
return nil
})
// registerPlugin("jekyll-sitemap")
// registerPlugin("jemoji")
}
const avatarTemplate = `<img class="avatar avatar-small" src="https://avatars3.githubusercontent.com/{username}?v=3&amp;s=40" alt="{username}" srcset="https://avatars3.githubusercontent.com/{username}?v=3&amp;s=40 1x, https://avatars3.githubusercontent.com/{username}?v=3&amp;s=80 2x, https://avatars3.githubusercontent.com/{username}?v=3&amp;s=120 3x, https://avatars3.githubusercontent.com/{username}?v=3&amp;s=160 4x" width="40" height="40" />`
func avatarTag(filename string) (func(io.Writer, chunks.Context) error, error) {
username := "osteele" // TODO replace with real name
size := 40
return func(w io.Writer, _ chunks.Context) error {
s := strings.Replace(avatarTemplate, "40", fmt.Sprintf("%s", size), -1)
s = strings.Replace(s, "{username}", username, -1)
_, err := w.Write([]byte(s))
return err
}, nil
}

View File

@ -10,8 +10,10 @@ import (
"github.com/osteele/gojekyll/collections"
"github.com/osteele/gojekyll/config"
"github.com/osteele/gojekyll/helpers"
"github.com/osteele/gojekyll/liquid"
"github.com/osteele/gojekyll/pages"
"github.com/osteele/gojekyll/pipelines"
"github.com/osteele/gojekyll/plugins"
"github.com/osteele/gojekyll/templates"
)
@ -27,7 +29,7 @@ type Site struct {
config config.Config
data map[string]interface{}
pipeline pipelines.PipelineInterface
pipeline *pipelines.Pipeline
pages []pages.Document // all pages, output or not
preparedToRender bool
siteVariables templates.VariableMap
@ -128,15 +130,26 @@ func (s *Site) RenderingPipeline() pipelines.PipelineInterface {
return s.pipeline
}
type pluginContext struct {
engine liquid.Engine
}
// Engine is in the PluginContext interface.
func (c pluginContext) TemplateEngine() liquid.Engine { return c.engine }
// initializeRenderingPipeline initializes the rendering pipeline
func (s *Site) initializeRenderingPipeline() (err error) {
options := pipelines.PipelineOptions{
SourceDir: s.Source,
AbsoluteURL: s.config.AbsoluteURL,
BaseURL: s.config.BaseURL,
RelativeFilenameToURL: s.RelativeFilenameToURL,
}
s.pipeline, err = pipelines.NewPipeline(s.config, options)
ctx := pluginContext{s.pipeline.TemplateEngine()}
for _, name := range s.config.Plugins {
if !plugins.Install(name, ctx) {
fmt.Printf("warning: gojekyll does not emulate the %s plugin.\n", name)
}
}
return
}