1
0
mirror of https://github.com/danog/gojekyll.git synced 2024-11-26 23:14:40 +01:00

Implement markdown=1

This commit is contained in:
Oliver Steele 2017-08-11 17:16:49 -04:00
parent 63ca72592e
commit 440104d56e
3 changed files with 110 additions and 4 deletions

View File

@ -1,6 +1,13 @@
package pipelines
import "github.com/russross/blackfriday"
import (
"bytes"
"io"
"regexp"
"github.com/russross/blackfriday"
"golang.org/x/net/html"
)
const blackfridayFlags = 0 |
blackfriday.HTML_USE_XHTML |
@ -22,8 +29,88 @@ const blackfridayExtensions = 0 |
// added relative to commonExtensions
blackfriday.EXTENSION_AUTO_HEADER_IDS
func markdownRenderer(input []byte) []byte {
func renderMarkdown(md []byte) []byte {
renderer := blackfriday.HtmlRenderer(blackfridayFlags, "", "")
return blackfriday.MarkdownOptions(input, renderer, blackfriday.Options{
html := blackfriday.MarkdownOptions(md, renderer, blackfriday.Options{
Extensions: blackfridayExtensions})
html, err := renderInnerMarkdown(html)
if err != nil {
panic(err)
}
return html
}
var markdownAttrRE = regexp.MustCompile(`\s*markdown\s*=\s*("1"|'1'|1)\s*`)
func renderInnerMarkdown(b []byte) ([]byte, error) {
z := html.NewTokenizer(bytes.NewReader(b))
buf := new(bytes.Buffer)
outer:
for {
tt := z.Next()
switch tt {
case html.ErrorToken:
if z.Err() == io.EOF {
break outer
}
return nil, z.Err()
case html.StartTagToken:
if hasAttr(z) {
tag := markdownAttrRE.ReplaceAll(z.Raw(), []byte(" "))
tag = bytes.Replace(tag, []byte(" >"), []byte(">"), 1)
_, err := buf.Write(tag)
if err != nil {
return nil, err
}
if err := processInnerMarkdown(buf, z); err != nil {
return nil, err
}
// the above leaves z set to the end token
}
}
_, err := buf.Write(z.Raw())
if err != nil {
return nil, err
}
}
return buf.Bytes(), nil
}
func hasAttr(z *html.Tokenizer) bool {
for {
k, v, more := z.TagAttr()
switch {
case string(k) == "markdown" && string(v) == "1":
return true
case !more:
return false
}
}
}
func processInnerMarkdown(w io.Writer, z *html.Tokenizer) error {
buf := new(bytes.Buffer)
depth := 1
loop:
for {
tt := z.Next()
switch tt {
case html.ErrorToken:
return z.Err()
case html.StartTagToken:
depth++
case html.EndTagToken:
depth--
if depth == 0 {
break loop
}
}
_, err := buf.Write(z.Raw())
if err != nil {
panic(err)
}
}
html := renderMarkdown(buf.Bytes())
_, err := w.Write(html)
return err
}

View File

@ -0,0 +1,19 @@
package pipelines
import (
"testing"
"github.com/stretchr/testify/require"
)
func renderMarkdownString(s string) string {
return string(renderMarkdown([]byte(s)))
}
func TestRenderMarkdown(t *testing.T) {
require.Equal(t, "<p><em>b</em></p>\n", renderMarkdownString("*b*"))
require.Equal(t, "<div>*b*</div>\n", renderMarkdownString("<div>*b*</div>"))
require.Equal(t, "<div a=1><p><em>b</em></p>\n</div>\n", renderMarkdownString(`<div a=1 markdown="1">*b*</div>`))
require.Equal(t, "<div a=1><p><em>b</em></p>\n</div>\n", renderMarkdownString(`<div a=1 markdown='1'>*b*</div>`))
require.Equal(t, "<div a=1><p><em>b</em></p>\n</div>\n", renderMarkdownString(`<div a=1 markdown=1>*b*</div>`))
}

View File

@ -70,7 +70,7 @@ func (p *Pipeline) Render(w io.Writer, src []byte, vars liquid.Bindings, filenam
return err
}
if p.cfg.IsMarkdown(filename) {
src = markdownRenderer(src)
src = renderMarkdown(src)
}
_, err = w.Write(src)
return err