From 563a6302a0a27f1b8412d4ab621e336f83159727 Mon Sep 17 00:00:00 2001
From: Anthony Fok
Date: Fri, 30 Jan 2015 07:17:50 -0700
Subject: [PATCH] Very experimental support for mmark
Either name the content files as `*.mmark`,
or add `markup = "mmark"` in the front matter
of your `*.md` content files.
---
helpers/content.go | 73 +++++++++++++++++++++++++++++++++++++++++
helpers/general.go | 11 ++++---
helpers/general_test.go | 1 +
hugolib/handler_page.go | 28 ++++++++++++++++
4 files changed, 109 insertions(+), 4 deletions(-)
diff --git a/helpers/content.go b/helpers/content.go
index a5f2a560..0bb50f44 100644
--- a/helpers/content.go
+++ b/helpers/content.go
@@ -22,6 +22,7 @@ import (
"html/template"
"os/exec"
+ "github.com/miekg/mmark"
"github.com/russross/blackfriday"
bp "github.com/spf13/hugo/bufferpool"
jww "github.com/spf13/jwalterweatherman"
@@ -74,6 +75,19 @@ var blackfridayExtensionMap = map[string]int{
var stripHTMLReplacer = strings.NewReplacer("\n", " ", "
", "\n", "
", "\n", "
", "\n")
+var mmarkExtensionMap = map[string]int{
+ "tables": mmark.EXTENSION_TABLES,
+ "fencedCode": mmark.EXTENSION_FENCED_CODE,
+ "autolink": mmark.EXTENSION_AUTOLINK,
+ "laxHtmlBlocks": mmark.EXTENSION_LAX_HTML_BLOCKS,
+ "spaceHeaders": mmark.EXTENSION_SPACE_HEADERS,
+ "hardLineBreak": mmark.EXTENSION_HARD_LINE_BREAK,
+ "footnotes": mmark.EXTENSION_FOOTNOTES,
+ "noEmptyLineBeforeBlock": mmark.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK,
+ "headerIds": mmark.EXTENSION_HEADER_IDS,
+ "autoHeaderIds": mmark.EXTENSION_AUTO_HEADER_IDS,
+}
+
// StripHTML accepts a string, strips out all HTML tags and returns it.
func StripHTML(s string) string {
@@ -174,6 +188,61 @@ func markdownRenderWithTOC(ctx *RenderingContext) []byte {
getMarkdownExtensions(ctx))
}
+// mmark
+func GetMmarkHtmlRenderer(defaultFlags int, ctx *RenderingContext) mmark.Renderer {
+ renderParameters := mmark.HtmlRendererParameters{
+ FootnoteAnchorPrefix: viper.GetString("FootnoteAnchorPrefix"),
+ FootnoteReturnLinkContents: viper.GetString("FootnoteReturnLinkContents"),
+ }
+
+ b := len(ctx.DocumentID) != 0
+
+ if b && !ctx.getConfig().PlainIDAnchors {
+ renderParameters.FootnoteAnchorPrefix = ctx.DocumentID + ":" + renderParameters.FootnoteAnchorPrefix
+ // renderParameters.HeaderIDSuffix = ":" + ctx.DocumentId
+ }
+
+ htmlFlags := defaultFlags
+ htmlFlags |= mmark.HTML_FOOTNOTE_RETURN_LINKS
+
+ return mmark.HtmlRendererWithParameters(htmlFlags, "", "", renderParameters)
+}
+
+func GetMmarkExtensions(ctx RenderingContext) int {
+ flags := 0
+ flags |= mmark.EXTENSION_TABLES
+ flags |= mmark.EXTENSION_FENCED_CODE
+ flags |= mmark.EXTENSION_AUTOLINK
+ flags |= mmark.EXTENSION_SPACE_HEADERS
+ flags |= mmark.EXTENSION_CITATION
+ flags |= mmark.EXTENSION_TITLEBLOCK_TOML
+ flags |= mmark.EXTENSION_HEADER_IDS
+ flags |= mmark.EXTENSION_AUTO_HEADER_IDS
+ flags |= mmark.EXTENSION_UNIQUE_HEADER_IDS
+ flags |= mmark.EXTENSION_FOOTNOTES
+ flags |= mmark.EXTENSION_SHORT_REF
+ flags |= mmark.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK
+ flags |= mmark.EXTENSION_INCLUDE
+
+ for _, extension := range ctx.getConfig().Extensions {
+ if flag, ok := mmarkExtensionMap[extension]; ok {
+ flags |= flag
+ }
+ }
+ return flags
+}
+
+func MmarkRender(ctx *RenderingContext) []byte {
+ return mmark.Parse(ctx.Content, GetMmarkHtmlRenderer(0, ctx),
+ GetMmarkExtensions(*ctx)).Bytes()
+}
+
+func MmarkRenderWithTOC(ctx *RenderingContext) []byte {
+ return mmark.Parse(ctx.Content,
+ GetMmarkHtmlRenderer(0, ctx),
+ GetMmarkExtensions(*ctx)).Bytes()
+}
+
// ExtractTOC extracts Table of Contents from content.
func ExtractTOC(content []byte) (newcontent []byte, toc []byte) {
origContent := make([]byte, len(content))
@@ -238,6 +307,8 @@ func RenderBytesWithTOC(ctx *RenderingContext) []byte {
return markdownRenderWithTOC(ctx)
case "asciidoc":
return []byte(GetAsciidocContent(ctx.Content))
+ case "mmark":
+ return MmarkRenderWithTOC(ctx)
case "rst":
return []byte(GetRstContent(ctx.Content))
}
@@ -252,6 +323,8 @@ func RenderBytes(ctx *RenderingContext) []byte {
return markdownRender(ctx)
case "asciidoc":
return []byte(GetAsciidocContent(ctx.Content))
+ case "mmark":
+ return MmarkRender(ctx)
case "rst":
return []byte(GetRstContent(ctx.Content))
}
diff --git a/helpers/general.go b/helpers/general.go
index dc9029b0..97b1e7e8 100644
--- a/helpers/general.go
+++ b/helpers/general.go
@@ -19,16 +19,17 @@ import (
"encoding/hex"
"errors"
"fmt"
- "github.com/spf13/cast"
- bp "github.com/spf13/hugo/bufferpool"
- jww "github.com/spf13/jwalterweatherman"
- "github.com/spf13/viper"
"io"
"net"
"path/filepath"
"reflect"
"strings"
"sync"
+
+ "github.com/spf13/cast"
+ bp "github.com/spf13/hugo/bufferpool"
+ jww "github.com/spf13/jwalterweatherman"
+ "github.com/spf13/viper"
)
// Filepath separator defined by os.Separator.
@@ -66,6 +67,8 @@ func GuessType(in string) string {
return "markdown"
case "asciidoc", "adoc", "ad":
return "asciidoc"
+ case "mmark":
+ return "mmark"
case "rst":
return "rst"
case "html", "htm":
diff --git a/helpers/general_test.go b/helpers/general_test.go
index 144f7a31..0147822c 100644
--- a/helpers/general_test.go
+++ b/helpers/general_test.go
@@ -21,6 +21,7 @@ func TestGuessType(t *testing.T) {
{"adoc", "asciidoc"},
{"ad", "asciidoc"},
{"rst", "rst"},
+ {"mmark", "mmark"},
{"html", "html"},
{"htm", "html"},
{"excel", "unknown"},
diff --git a/hugolib/handler_page.go b/hugolib/handler_page.go
index a29b664e..24c81021 100644
--- a/hugolib/handler_page.go
+++ b/hugolib/handler_page.go
@@ -25,6 +25,7 @@ func init() {
RegisterHandler(new(htmlHandler))
RegisterHandler(new(asciidocHandler))
RegisterHandler(new(rstHandler))
+ RegisterHandler(new(mmarkHandler))
}
type basicPageHandler Handle
@@ -156,3 +157,30 @@ func (h rstHandler) PageConvert(p *Page, t tpl.Template) HandledResult {
return HandledResult{err: nil}
}
+
+type mmarkHandler struct {
+ basicPageHandler
+}
+
+func (h mmarkHandler) Extensions() []string { return []string{"mmark"} }
+func (h mmarkHandler) PageConvert(p *Page, t tpl.Template) HandledResult {
+ p.ProcessShortcodes(t)
+
+ tmpContent, tmpTableOfContents := helpers.ExtractTOC(p.renderContent(helpers.RemoveSummaryDivider(p.rawContent)))
+
+ if len(p.contentShortCodes) > 0 {
+ tmpContentWithTokensReplaced, err := replaceShortcodeTokens(tmpContent, shortcodePlaceholderPrefix, true, p.contentShortCodes)
+
+ if err != nil {
+ jww.FATAL.Printf("Fail to replace short code tokens in %s:\n%s", p.BaseFileName(), err.Error())
+ return HandledResult{err: err}
+ } else {
+ tmpContent = tmpContentWithTokensReplaced
+ }
+ }
+
+ p.Content = helpers.BytesToHTML(tmpContent)
+ p.TableOfContents = helpers.BytesToHTML(tmpTableOfContents)
+
+ return HandledResult{err: nil}
+}
--
2.30.2