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

Implement include_relative

This commit is contained in:
Oliver Steele 2017-07-04 17:13:47 -04:00
parent 197f6b0572
commit 956ca7bc3f
17 changed files with 105 additions and 43 deletions

View File

@ -45,7 +45,6 @@ gojekyll help build
- themes, page tags, excerpts, plugins (except for a few listed below), pagination, math, warning mode.
- Site variables: `pages`, `static_files`, `html_pages`, `html_files`, `documents`, and `tags`
- Jekyll filters: `group_by_exp`, `pop`, `shift`, `cgi_escape`, `uri_escape`, `scssify`, and `smartify`.
- Jekyll's `include_relative` tag
- The Go Liquid engine is also missing some tags and a few filters. See its [README](https://github.com/osteele/gojekyll/#status) for status.
- Data files must be YAML. CSV and JSON data files are not supported.
- `{% highlight %}` uses Pygments. There's no way to tell it to use Rouge. Also, I don't know what will happen if Pygments isn't installed.
@ -104,12 +103,11 @@ The cache is for calls to Pygments (via the `highlight` tag). For another site,
- [ ] Jekyll filters
- [ ] `group_by_exp` `pop` `shift` `cgi_escape` `uri_escape` `scssify` `smartify`
- [x] everything else
- [ ] Jekyll tags
- [x] Jekyll tags
- [x] `include`
- [ ] `include_relative`
- [x] `include_relative`
- [x] `link`
- [x] `post_url`
- [ ] `gist`
- [x] `highlight`
- [x] Includes
- [x] `include` parameters
@ -130,7 +128,7 @@ The cache is for calls to Pygments (via the `highlight` tag). For another site,
- [x] `build`
- [x] `--source`, `--destination`, `--drafts`, `--future`, `--unpublished`
- [ ] `--config`, `--baseurl`, `--lsi`, `--watch`, etc.
- [ ] won't implement: `--force-polling`, `--limit-posts`, `--incremental`, `JEKYLL_ENV=production`
- [ ] not planned: `--force-polling`, `--limit-posts`, `--incremental`, `JEKYLL_ENV=production`
- [x] `clean`
- [ ] `doctor`
- [x] `help`
@ -140,7 +138,7 @@ The cache is for calls to Pygments (via the `highlight` tag). For another site,
- [x] `serve`
- [x] `--open-uri`
- [ ] `--detach`, `--host`, `--port`, `--baseurl`
- [ ] won't implement: `--incremental`, `--ssl-*`
- [ ] not planned: `--incremental`, `--ssl`-*
- [ ] Windows
## Contributing

View File

@ -13,7 +13,7 @@ import (
"github.com/osteele/gojekyll/config"
"github.com/osteele/liquid"
"github.com/osteele/liquid/expressions"
"github.com/osteele/liquid/expression"
"github.com/osteele/liquid/generics"
"github.com/russross/blackfriday"
)
@ -214,7 +214,7 @@ func sortFilter(array []interface{}, key interface{}, nilFirst interface{}) []in
return out
}
func whereExpFilter(array []interface{}, name string, expr expressions.Closure) ([]interface{}, error) {
func whereExpFilter(array []interface{}, name string, expr expression.Closure) ([]interface{}, error) {
rt := reflect.ValueOf(array)
if rt.Kind() != reflect.Array && rt.Kind() != reflect.Slice {
return nil, nil

View File

@ -78,8 +78,8 @@ func (p *page) Write(rc RenderingContext, w io.Writer) error {
if err != nil {
return err
}
layout := templates.VariableMap(p.frontMatter).String("layout", "")
if layout != "" {
layout, ok := p.frontMatter["layout"].(string)
if ok && layout != "" {
b, err = rp.ApplyLayout(layout, b, p.TemplateContext(rc))
if err != nil {
return err

View File

@ -41,7 +41,12 @@ func (p *Pipeline) FindLayout(base string, fm *map[string]interface{}) (t liquid
if err != nil {
return
}
return p.liquidEngine.ParseTemplate(content)
t, err = p.liquidEngine.ParseTemplate(content)
if err != nil {
return nil, err
}
t.SetSourcePath(filename)
return
}
// LayoutsDir returns the path to the layouts directory.

View File

@ -73,8 +73,13 @@ func (p *Pipeline) Render(w io.Writer, b []byte, filename string, e map[string]i
return b, nil
}
func (p *Pipeline) renderTemplate(tpl []byte, b map[string]interface{}, filename string) ([]byte, error) {
out, err := p.liquidEngine.ParseAndRender(tpl, b)
func (p *Pipeline) renderTemplate(src []byte, b map[string]interface{}, filename string) ([]byte, error) {
tpl, err := p.liquidEngine.ParseTemplate(src)
if err != nil {
return nil, helpers.PathError(err, "Liquid Error", filename)
}
tpl.SetSourcePath(filename)
out, err := tpl.Render(b)
if err != nil {
return nil, helpers.PathError(err, "Liquid Error", filename)
}

View File

@ -5,7 +5,7 @@ import (
"strings"
"github.com/osteele/gojekyll/tags"
"github.com/osteele/liquid/chunks"
"github.com/osteele/liquid/render"
)
func init() {
@ -17,7 +17,7 @@ func init() {
const avatarTemplate = `<img class="avatar avatar-small" src="https://avatars3.githubusercontent.com/{user}?v=3&amp;s=40" alt="{user}" srcset="https://avatars3.githubusercontent.com/{user}?v=3&amp;s=40 1x, https://avatars3.githubusercontent.com/{user}?v=3&amp;s=80 2x, https://avatars3.githubusercontent.com/{user}?v=3&amp;s=120 3x, https://avatars3.githubusercontent.com/{user}?v=3&amp;s=160 4x" width="40" height="40" data-proofer-ignore="true" />`
func avatarTag(ctx chunks.RenderContext) (string, error) {
func avatarTag(ctx render.Context) (string, error) {
var (
user string
size interface{} = 40

View File

@ -4,7 +4,7 @@ import (
"fmt"
"github.com/osteele/gojekyll/tags"
"github.com/osteele/liquid/chunks"
"github.com/osteele/liquid/render"
)
func init() {
@ -14,7 +14,7 @@ func init() {
})
}
func gistTag(ctx chunks.RenderContext) (string, error) {
func gistTag(ctx render.Context) (string, error) {
argsline, err := ctx.ParseTagArgs()
if err != nil {
return "", err

View File

@ -9,7 +9,7 @@ import (
"fmt"
"github.com/osteele/liquid"
"github.com/osteele/liquid/chunks"
"github.com/osteele/liquid/render"
)
// PluginContext is the context for plugin initialization.
@ -22,7 +22,7 @@ type PluginContext interface {
func Install(name string, ctx PluginContext) bool {
p, found := plugins[name]
if p != nil {
if err := p(ctx, pluginHelper{name, ctx}); err != nil {
if err := p(ctx, pluginHelper{ctx, name}); err != nil {
panic(err)
}
}
@ -56,8 +56,8 @@ func init() {
}
type pluginHelper struct {
PluginContext
name string
ctx PluginContext
}
func (h pluginHelper) stubbed() {
@ -65,12 +65,12 @@ func (h pluginHelper) stubbed() {
}
func (h pluginHelper) tag(name string, r liquid.Renderer) {
h.ctx.TemplateEngine().RegisterTag(name, r)
h.TemplateEngine().RegisterTag(name, r)
}
func (h pluginHelper) makeUnimplementedTag() liquid.Renderer {
warned := false
return func(ctx chunks.RenderContext) (string, error) {
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(), h.name)
warned = true

View File

@ -46,13 +46,11 @@ func (s *Site) Clean(options BuildOptions) error {
// Build cleans the destination and create files in it.
// It attends to the global options.dry_run.
func (s *Site) Build(options BuildOptions) (int, error) {
count := 0
if err := s.prepareRendering(); err != nil {
return 0, err
}
if err := s.Clean(options); err != nil {
return 0, err
}
n, err := s.WritePages(options)
return count + n, err
return s.WritePages(options)
}

View File

@ -33,11 +33,8 @@ func (s *Site) WriteDocument(p pages.Document, w io.Writer) error {
// WritePages writes output files.
// It attends to options.dry_run.
func (s *Site) WritePages(options BuildOptions) (int, error) {
count := 0
var err error
func (s *Site) WritePages(options BuildOptions) (count int, err error) {
errs := make(chan error)
for _, p := range s.OutputPages() {
count++
go func(p pages.Document) {
@ -46,6 +43,7 @@ func (s *Site) WritePages(options BuildOptions) (int, error) {
}
for i := 0; i < count; i++ {
// might as well report the last error as the first
// TODO return an aggregate
if e := <-errs; e != nil {
err = e
}

View File

@ -7,10 +7,10 @@ import (
"os/exec"
"strings"
"github.com/osteele/liquid/chunks"
"github.com/osteele/liquid/render"
)
func highlightTag(ctx chunks.RenderContext) (string, error) {
func highlightTag(ctx render.Context) (string, error) {
args, err := ctx.ParseTagArgs()
if err != nil {
return "", err

View File

@ -2,12 +2,23 @@ package tags
import (
"fmt"
"path"
"path/filepath"
"github.com/osteele/liquid/chunks"
"github.com/osteele/liquid/render"
)
func (tc tagContext) includeTag(ctx chunks.RenderContext) (string, error) {
func (tc tagContext) includeTag(ctx render.Context) (string, error) {
return includeFromDir(ctx, filepath.Join(tc.config.Source, tc.config.IncludesDir))
}
func (tc tagContext) includeRelativeTag(ctx render.Context) (string, error) {
fmt.Println("include relative", ctx.SourceFile())
// TODO Note that you cannot use the ../ syntax
return includeFromDir(ctx, path.Dir(ctx.SourceFile()))
}
func includeFromDir(ctx render.Context, dirname string) (string, error) {
argsline, err := ctx.ParseTagArgs()
if err != nil {
return "", err
@ -23,8 +34,6 @@ func (tc tagContext) includeTag(ctx chunks.RenderContext) (string, error) {
if err != nil {
return "", err
}
filename := filepath.Join(tc.config.Source, tc.config.IncludesDir, args.Args[0])
ctx2 := ctx.Clone()
ctx2.UpdateBindings(map[string]interface{}{"include": include})
return ctx2.RenderFile(filename)
filename := filepath.Join(dirname, args.Args[0])
return ctx.RenderFile(filename, map[string]interface{}{"include": include})
}

46
tags/include_test.go Normal file
View File

@ -0,0 +1,46 @@
package tags
import (
"fmt"
"strings"
"testing"
"github.com/osteele/gojekyll/config"
"github.com/osteele/liquid"
"github.com/stretchr/testify/require"
)
func TestIncludeTag(t *testing.T) {
engine := liquid.NewEngine()
cfg := config.Default()
cfg.Source = "testdata"
AddJekyllTags(engine, cfg, func(s string) (string, bool) {
fmt.Println("ok")
if s == "_posts/2017-07-04-test.md" {
return "post.html", true
}
return "", false
})
bindings := map[string]interface{}{}
s, err := engine.ParseAndRenderString(`{% include include_target.html %}`, bindings)
require.NoError(t, err)
require.Equal(t, "include target", strings.TrimSpace(s))
// TODO {% include {{ page.my_variable }} %}
// TODO {% include note.html content="This is my sample note." %}
}
func TestIncludeRelativeTag(t *testing.T) {
engine := liquid.NewEngine()
cfg := config.Default()
AddJekyllTags(engine, cfg, func(s string) (string, bool) { return "", false })
bindings := map[string]interface{}{}
tpl, err := engine.ParseTemplate([]byte(`{% include_relative subdir/include_relative.html %}`))
require.NoError(t, err)
tpl.SetSourcePath("testdata/dir/include_relative_source.md")
s, err := tpl.Render(bindings)
require.NoError(t, err)
require.Equal(t, "include_relative target", strings.TrimSpace(string(s)))
}

View File

@ -4,7 +4,7 @@ import (
"fmt"
"regexp"
"github.com/osteele/liquid/chunks"
"github.com/osteele/liquid/render"
)
// TODO string escapes
@ -52,7 +52,7 @@ func ParseArgs(argsline string) (*ParsedArgs, error) {
}
// EvalOptions evaluates unquoted options.
func (r *ParsedArgs) EvalOptions(ctx chunks.RenderContext) (map[string]interface{}, error) {
func (r *ParsedArgs) EvalOptions(ctx render.Context) (map[string]interface{}, error) {
options := map[string]interface{}{}
for k, v := range r.Options {
if v.quoted {

View File

@ -6,7 +6,7 @@ import (
"github.com/osteele/gojekyll/config"
"github.com/osteele/liquid"
"github.com/osteele/liquid/chunks"
"github.com/osteele/liquid/render"
)
// A LinkTagHandler given an include tag file name returns a URL.
@ -17,6 +17,7 @@ func AddJekyllTags(e liquid.Engine, c config.Config, lh LinkTagHandler) {
tc := tagContext{c, lh}
e.RegisterBlock("highlight", highlightTag)
e.RegisterTag("include", tc.includeTag)
e.RegisterTag("include_relative", tc.includeRelativeTag)
e.RegisterTag("link", tc.linkTag)
e.RegisterTag("post_url", tc.postURLTag)
}
@ -31,7 +32,7 @@ type tagContext struct {
// time it's rendered, and otherwise does nothing.
func CreateUnimplementedTag() liquid.Renderer {
warned := false
return func(ctx chunks.RenderContext) (string, error) {
return func(ctx render.Context) (string, error) {
if !warned {
fmt.Printf("The %q tag has not been implemented. It is being ignored.\n", ctx.TagName())
warned = true
@ -40,7 +41,7 @@ func CreateUnimplementedTag() liquid.Renderer {
}
}
func (tc tagContext) linkTag(ctx chunks.RenderContext) (string, error) {
func (tc tagContext) linkTag(ctx render.Context) (string, error) {
filename := ctx.TagArgs()
url, found := tc.lh(filename)
if !found {
@ -49,7 +50,7 @@ func (tc tagContext) linkTag(ctx chunks.RenderContext) (string, error) {
return url, nil
}
func (tc tagContext) postURLTag(ctx chunks.RenderContext) (string, error) {
func (tc tagContext) postURLTag(ctx render.Context) (string, error) {
var (
filename = ctx.TagArgs()
found = false

View File

@ -0,0 +1 @@
include target

View File

@ -0,0 +1 @@
include_relative target