summaryrefslogtreecommitdiffstats
path: root/markup/mmark
diff options
context:
space:
mode:
Diffstat (limited to 'markup/mmark')
-rw-r--r--markup/mmark/convert.go143
-rw-r--r--markup/mmark/convert_test.go77
-rw-r--r--markup/mmark/renderer.go44
3 files changed, 264 insertions, 0 deletions
diff --git a/markup/mmark/convert.go b/markup/mmark/convert.go
new file mode 100644
index 000000000..a0da346c1
--- /dev/null
+++ b/markup/mmark/convert.go
@@ -0,0 +1,143 @@
+// Copyright 2019 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Package mmark converts Markdown to HTML using MMark v1.
+package mmark
+
+import (
+ "github.com/gohugoio/hugo/markup/internal"
+
+ "github.com/gohugoio/hugo/markup/converter"
+ "github.com/miekg/mmark"
+)
+
+// Provider is the package entry point.
+var Provider converter.NewProvider = provider{}
+
+type provider struct {
+}
+
+func (p provider) New(cfg converter.ProviderConfig) (converter.Provider, error) {
+ defaultBlackFriday, err := internal.NewBlackfriday(cfg)
+ if err != nil {
+ return nil, err
+ }
+
+ defaultExtensions := getMmarkExtensions(defaultBlackFriday)
+
+ var n converter.NewConverter = func(ctx converter.DocumentContext) (converter.Converter, error) {
+ b := defaultBlackFriday
+ extensions := defaultExtensions
+
+ if ctx.ConfigOverrides != nil {
+ var err error
+ b, err = internal.UpdateBlackFriday(b, ctx.ConfigOverrides)
+ if err != nil {
+ return nil, err
+ }
+ extensions = getMmarkExtensions(b)
+ }
+
+ return &mmarkConverter{
+ ctx: ctx,
+ b: b,
+ extensions: extensions,
+ cfg: cfg,
+ }, nil
+ }
+
+ return n, nil
+
+}
+
+type mmarkConverter struct {
+ ctx converter.DocumentContext
+ extensions int
+ b *internal.BlackFriday
+ cfg converter.ProviderConfig
+}
+
+func (c *mmarkConverter) Convert(ctx converter.RenderContext) (converter.Result, error) {
+ r := getHTMLRenderer(c.ctx, c.b, c.cfg)
+ return mmark.Parse(ctx.Src, r, c.extensions), nil
+}
+
+func getHTMLRenderer(
+ ctx converter.DocumentContext,
+ cfg *internal.BlackFriday,
+ pcfg converter.ProviderConfig) mmark.Renderer {
+
+ var (
+ flags int
+ documentID string
+ )
+
+ documentID = ctx.DocumentID
+
+ renderParameters := mmark.HtmlRendererParameters{
+ FootnoteAnchorPrefix: cfg.FootnoteAnchorPrefix,
+ FootnoteReturnLinkContents: cfg.FootnoteReturnLinkContents,
+ }
+
+ if documentID != "" && !cfg.PlainIDAnchors {
+ renderParameters.FootnoteAnchorPrefix = documentID + ":" + renderParameters.FootnoteAnchorPrefix
+ }
+
+ htmlFlags := flags
+ htmlFlags |= mmark.HTML_FOOTNOTE_RETURN_LINKS
+
+ return &mmarkRenderer{
+ Config: cfg,
+ Cfg: pcfg.Cfg,
+ highlight: pcfg.Highlight,
+ Renderer: mmark.HtmlRendererWithParameters(htmlFlags, "", "", renderParameters),
+ }
+
+}
+
+func getMmarkExtensions(cfg *internal.BlackFriday) 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 cfg.Extensions {
+ if flag, ok := mmarkExtensionMap[extension]; ok {
+ flags |= flag
+ }
+ }
+ return flags
+}
+
+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,
+}
diff --git a/markup/mmark/convert_test.go b/markup/mmark/convert_test.go
new file mode 100644
index 000000000..d015ee94c
--- /dev/null
+++ b/markup/mmark/convert_test.go
@@ -0,0 +1,77 @@
+// Copyright 2019 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package mmark
+
+import (
+ "testing"
+
+ "github.com/spf13/viper"
+
+ "github.com/gohugoio/hugo/common/loggers"
+
+ "github.com/miekg/mmark"
+
+ "github.com/gohugoio/hugo/markup/internal"
+
+ "github.com/gohugoio/hugo/markup/converter"
+
+ qt "github.com/frankban/quicktest"
+)
+
+func TestGetMmarkExtensions(t *testing.T) {
+ c := qt.New(t)
+ b, err := internal.NewBlackfriday(converter.ProviderConfig{Cfg: viper.New()})
+ c.Assert(err, qt.IsNil)
+
+ //TODO: This is doing the same just with different marks...
+ type data struct {
+ testFlag int
+ }
+
+ b.Extensions = []string{"tables"}
+ b.ExtensionsMask = []string{""}
+ allExtensions := []data{
+ {mmark.EXTENSION_TABLES},
+ {mmark.EXTENSION_FENCED_CODE},
+ {mmark.EXTENSION_AUTOLINK},
+ {mmark.EXTENSION_SPACE_HEADERS},
+ {mmark.EXTENSION_CITATION},
+ {mmark.EXTENSION_TITLEBLOCK_TOML},
+ {mmark.EXTENSION_HEADER_IDS},
+ {mmark.EXTENSION_AUTO_HEADER_IDS},
+ {mmark.EXTENSION_UNIQUE_HEADER_IDS},
+ {mmark.EXTENSION_FOOTNOTES},
+ {mmark.EXTENSION_SHORT_REF},
+ {mmark.EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK},
+ {mmark.EXTENSION_INCLUDE},
+ }
+
+ actualFlags := getMmarkExtensions(b)
+ for _, e := range allExtensions {
+ if actualFlags&e.testFlag != e.testFlag {
+ t.Errorf("Flag %v was not found in the list of extensions.", e)
+ }
+ }
+}
+
+func TestConvert(t *testing.T) {
+ c := qt.New(t)
+ p, err := Provider.New(converter.ProviderConfig{Cfg: viper.New(), Logger: loggers.NewErrorLogger()})
+ c.Assert(err, qt.IsNil)
+ conv, err := p.New(converter.DocumentContext{})
+ c.Assert(err, qt.IsNil)
+ b, err := conv.Convert(converter.RenderContext{Src: []byte("testContent")})
+ c.Assert(err, qt.IsNil)
+ c.Assert(string(b.Bytes()), qt.Equals, "<p>testContent</p>\n")
+}
diff --git a/markup/mmark/renderer.go b/markup/mmark/renderer.go
new file mode 100644
index 000000000..07fe71c95
--- /dev/null
+++ b/markup/mmark/renderer.go
@@ -0,0 +1,44 @@
+// Copyright 2019 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package mmark
+
+import (
+ "bytes"
+ "strings"
+
+ "github.com/miekg/mmark"
+
+ "github.com/gohugoio/hugo/config"
+ "github.com/gohugoio/hugo/markup/internal"
+)
+
+// hugoHTMLRenderer wraps a blackfriday.Renderer, typically a blackfriday.Html
+// adding some custom behaviour.
+type mmarkRenderer struct {
+ Cfg config.Provider
+ Config *internal.BlackFriday
+ highlight func(code, lang, optsStr string) (string, error)
+ mmark.Renderer
+}
+
+// BlockCode renders a given text as a block of code.
+func (r *mmarkRenderer) BlockCode(out *bytes.Buffer, text []byte, lang string, caption []byte, subfigure bool, callouts bool) {
+ if r.Cfg.GetBool("pygmentsCodeFences") && (lang != "" || r.Cfg.GetBool("pygmentsCodeFencesGuessSyntax")) {
+ str := strings.Trim(string(text), "\n\r")
+ highlighted, _ := r.highlight(str, lang, "")
+ out.WriteString(highlighted)
+ } else {
+ r.Renderer.BlockCode(out, text, lang, caption, subfigure, callouts)
+ }
+}