diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2022-02-17 13:04:00 +0100 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2022-02-24 18:59:50 +0100 |
commit | 08fdca9d9365eaf1e496a12e2af5e18617bd0e66 (patch) | |
tree | 6c6942d1b74a4160d93a997860bafd52b92025f5 /markup/goldmark/convert.go | |
parent | 2c20f5bc00b604e72b3b7e401fbdbf9447fe3470 (diff) |
Add Markdown diagrams and render hooks for code blocks
You can now create custom hook templates for code blocks, either one for all (`render-codeblock.html`) or for a given code language (e.g. `render-codeblock-go.html`).
We also used this new hook to add support for diagrams in Hugo:
* Goat (Go ASCII Tool) is built-in and enabled by default; just create a fenced code block with the language `goat` and start draw your Ascii diagrams.
* Another popular alternative for diagrams in Markdown, Mermaid (supported by GitHub), can also be implemented with a simple template. See the Hugo documentation for more information.
Updates #7765
Closes #9538
Fixes #9553
Fixes #8520
Fixes #6702
Fixes #9558
Diffstat (limited to 'markup/goldmark/convert.go')
-rw-r--r-- | markup/goldmark/convert.go | 146 |
1 files changed, 12 insertions, 134 deletions
diff --git a/markup/goldmark/convert.go b/markup/goldmark/convert.go index c547fe1e0..4c1641a0b 100644 --- a/markup/goldmark/convert.go +++ b/markup/goldmark/convert.go @@ -17,12 +17,12 @@ package goldmark import ( "bytes" "fmt" - "math/bits" "path/filepath" "runtime/debug" + "github.com/gohugoio/hugo/markup/goldmark/codeblocks" "github.com/gohugoio/hugo/markup/goldmark/internal/extensions/attributes" - "github.com/yuin/goldmark/ast" + "github.com/gohugoio/hugo/markup/goldmark/internal/render" "github.com/gohugoio/hugo/identity" @@ -32,16 +32,13 @@ import ( "github.com/gohugoio/hugo/hugofs" "github.com/gohugoio/hugo/markup/converter" - "github.com/gohugoio/hugo/markup/highlight" "github.com/gohugoio/hugo/markup/tableofcontents" "github.com/yuin/goldmark" - hl "github.com/yuin/goldmark-highlighting" "github.com/yuin/goldmark/extension" "github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/renderer" "github.com/yuin/goldmark/renderer/html" "github.com/yuin/goldmark/text" - "github.com/yuin/goldmark/util" ) // Provider is the package entry point. @@ -104,7 +101,7 @@ func newMarkdown(pcfg converter.ProviderConfig) goldmark.Markdown { ) if mcfg.Highlight.CodeFences { - extensions = append(extensions, newHighlighting(mcfg.Highlight)) + extensions = append(extensions, codeblocks.New()) } if cfg.Extensions.Table { @@ -178,65 +175,6 @@ func (c converterResult) GetIdentities() identity.Identities { return c.ids } -type bufWriter struct { - *bytes.Buffer -} - -const maxInt = 1<<(bits.UintSize-1) - 1 - -func (b *bufWriter) Available() int { - return maxInt -} - -func (b *bufWriter) Buffered() int { - return b.Len() -} - -func (b *bufWriter) Flush() error { - return nil -} - -type renderContext struct { - *bufWriter - positions []int - renderContextData -} - -func (ctx *renderContext) pushPos(n int) { - ctx.positions = append(ctx.positions, n) -} - -func (ctx *renderContext) popPos() int { - i := len(ctx.positions) - 1 - p := ctx.positions[i] - ctx.positions = ctx.positions[:i] - return p -} - -type renderContextData interface { - RenderContext() converter.RenderContext - DocumentContext() converter.DocumentContext - AddIdentity(id identity.Provider) -} - -type renderContextDataHolder struct { - rctx converter.RenderContext - dctx converter.DocumentContext - ids identity.Manager -} - -func (ctx *renderContextDataHolder) RenderContext() converter.RenderContext { - return ctx.rctx -} - -func (ctx *renderContextDataHolder) DocumentContext() converter.DocumentContext { - return ctx.dctx -} - -func (ctx *renderContextDataHolder) AddIdentity(id identity.Provider) { - ctx.ids.Add(id) -} - var converterIdentity = identity.KeyValueIdentity{Key: "goldmark", Value: "converter"} func (c *goldmarkConverter) Convert(ctx converter.RenderContext) (result converter.Result, err error) { @@ -251,7 +189,7 @@ func (c *goldmarkConverter) Convert(ctx converter.RenderContext) (result convert } }() - buf := &bufWriter{Buffer: &bytes.Buffer{}} + buf := &render.BufWriter{Buffer: &bytes.Buffer{}} result = buf pctx := c.newParserContext(ctx) reader := text.NewReader(ctx.Src) @@ -261,15 +199,15 @@ func (c *goldmarkConverter) Convert(ctx converter.RenderContext) (result convert parser.WithContext(pctx), ) - rcx := &renderContextDataHolder{ - rctx: ctx, - dctx: c.ctx, - ids: identity.NewManager(converterIdentity), + rcx := &render.RenderContextDataHolder{ + Rctx: ctx, + Dctx: c.ctx, + IDs: identity.NewManager(converterIdentity), } - w := &renderContext{ - bufWriter: buf, - renderContextData: rcx, + w := &render.Context{ + BufWriter: buf, + ContextData: rcx, } if err := c.md.Renderer().Render(w, ctx.Src, doc); err != nil { @@ -278,7 +216,7 @@ func (c *goldmarkConverter) Convert(ctx converter.RenderContext) (result convert return converterResult{ Result: buf, - ids: rcx.ids.GetIdentities(), + ids: rcx.IDs.GetIdentities(), toc: pctx.TableOfContents(), }, nil } @@ -309,63 +247,3 @@ func (p *parserContext) TableOfContents() tableofcontents.Root { } return tableofcontents.Root{} } - -func newHighlighting(cfg highlight.Config) goldmark.Extender { - return hl.NewHighlighting( - hl.WithStyle(cfg.Style), - hl.WithGuessLanguage(cfg.GuessSyntax), - hl.WithCodeBlockOptions(highlight.GetCodeBlockOptions()), - hl.WithFormatOptions( - cfg.ToHTMLOptions()..., - ), - - hl.WithWrapperRenderer(func(w util.BufWriter, ctx hl.CodeBlockContext, entering bool) { - var language string - if l, hasLang := ctx.Language(); hasLang { - language = string(l) - } - - if ctx.Highlighted() { - if entering { - writeDivStart(w, ctx) - } else { - writeDivEnd(w) - } - } else { - if entering { - highlight.WritePreStart(w, language, "") - } else { - highlight.WritePreEnd(w) - } - } - }), - ) -} - -func writeDivStart(w util.BufWriter, ctx hl.CodeBlockContext) { - w.WriteString(`<div class="highlight`) - - var attributes []ast.Attribute - if ctx.Attributes() != nil { - attributes = ctx.Attributes().All() - } - - if attributes != nil { - class, found := ctx.Attributes().GetString("class") - if found { - w.WriteString(" ") - w.Write(util.EscapeHTML(class.([]byte))) - - } - _, _ = w.WriteString("\"") - renderAttributes(w, true, attributes...) - } else { - _, _ = w.WriteString("\"") - } - - w.WriteString(">") -} - -func writeDivEnd(w util.BufWriter) { - w.WriteString("</div>") -} |