-
-
Save tomcam/a1c8fbe27a335164add3bc2b1d92b204 to your computer and use it in GitHub Desktop.
Goldmark demo with App object Markdown to HTML conversion, code highlighting, YAML support, simple template support
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// g.5: | |
// Demonstrates | |
// 1. The goldmark Markdown to HTML converter using an App object | |
// 2. Code highlighting. | |
// 3. Extracting YAML front matter | |
// 4. Executing a template to replace front matter metadata with its evaluated result | |
// Displays results to standard output | |
// $ mkdir ~/g | |
// $ cd ~/g | |
// $ go mod init example.com/g # example.com is OK to use in this quick & dirty example | |
// $ go fmt | |
// $ go mod tidy | |
// $ go run g.go | |
// $ go run g.go > foobar.html | |
// $ open foobar.html | |
package main | |
import ( | |
"bytes" | |
"fmt" | |
"github.com/yuin/goldmark" | |
"github.com/yuin/goldmark-highlighting" | |
"github.com/yuin/goldmark-meta" | |
"github.com/yuin/goldmark/extension" | |
"github.com/yuin/goldmark/parser" | |
"github.com/yuin/goldmark/renderer" | |
"github.com/yuin/goldmark/renderer/html" | |
"os" | |
"text/template" | |
) | |
const frontMatter1 = `--- | |
Title: goldmark-meta | |
Theme: wide | |
Summary: Add YAML metadata to the document | |
Tags: | |
- markdown | |
- goldmark | |
--- | |
## Title? | |
{{ .Title }} | |
` | |
const codeFence1 = "# Example with code fence and code highlighting:\n" + | |
"hello, world.\n\nCode fence example:\n" + | |
"```js\n" + | |
"console.log('hi')\n" + | |
"```\n" + ` | |
` | |
const template1 = ` | |
## Add template: | |
This is template1 | |
Title: {{ .Title }} | |
` | |
type App struct { | |
mdParser goldmark.Markdown | |
mdParserCtx parser.Context | |
// YAML front matter | |
metaData map[string]interface{} | |
} | |
// newGoldmark returns the a goldmark object with a parser and renderer. | |
func (app *App) newGoldmark() goldmark.Markdown { | |
exts := []goldmark.Extender{ | |
meta.New( | |
meta.WithStoresInDocument(), | |
), | |
// Support GitHub tables & other extensions | |
extension.Table, | |
extension.GFM, | |
extension.DefinitionList, | |
extension.Footnote, | |
highlighting.NewHighlighting( | |
highlighting.WithStyle("github"), | |
highlighting.WithFormatOptions()), | |
} | |
parserOpts := []parser.Option{ | |
parser.WithAttribute(), | |
parser.WithAutoHeadingID()} | |
renderOpts := []renderer.Option{ | |
// WithUnsafe is required for HTML templates to work properly | |
html.WithUnsafe(), | |
html.WithXHTML(), | |
} | |
return goldmark.New( | |
goldmark.WithExtensions(exts...), | |
goldmark.WithParserOptions(parserOpts...), | |
goldmark.WithRendererOptions(renderOpts...), | |
) | |
} | |
func NewApp() *App { | |
app := App{} | |
app.mdParser = app.newGoldmark() | |
app.mdParserCtx = parser.NewContext() | |
return &app | |
} | |
// mdYAMLtoHTML converts a Markdown document with optional | |
// YAML front matter to HTML. YAML is written to app.metaData | |
// Returns a byte slice containing the HTML source. | |
// Pre: parser.NewContext() has already been called on app.parserCtx | |
func (app *App) mdYAMLtoHTML(source []byte) ([]byte, error) { | |
var buf bytes.Buffer | |
// Convert Markdown source to HTML and deposit in buf.Bytes(). | |
if err := app.mdParser.Convert(source, &buf, parser.WithContext(app.mdParserCtx)); err != nil { | |
return []byte{}, err | |
} | |
// Obtain YAML front matter from document. | |
app.metaData = meta.Get(app.mdParserCtx) | |
return buf.Bytes(), nil | |
} | |
// mdtoHTML converts a Markdown document to HTML. | |
// YAML front matter should not be present. | |
// Returns a byte slice containing the HTML source. | |
// Pre: parser.NewContext() has already been called on app.parserCtx | |
func (app *App) mdToHTML(source []byte) ([]byte, error) { | |
var buf bytes.Buffer | |
// Convert Markdown source to HTML and deposit in buf.Bytes(). | |
if err := app.mdParser.Convert(source, &buf, parser.WithContext(app.mdParserCtx)); err != nil { | |
return []byte{}, err | |
} | |
return buf.Bytes(), nil | |
} | |
func (app *App) doTemplate(templateName string, source string /* funcMap template.FuncMap */) string { | |
if templateName == "" { | |
templateName = "Metabuzz" | |
} | |
tmpl, err := template.New(templateName).Parse(source) | |
if err != nil { | |
quit(err, 1) | |
} | |
//err = tmpl.Execute(os.Stdout, app.metaData) | |
buf := new(bytes.Buffer) | |
err = tmpl.Execute(buf, app.metaData) | |
if err != nil { | |
quit(err, 1) | |
} | |
return buf.String() | |
} | |
func main() { | |
var app = NewApp() | |
app.mdParserCtx = parser.NewContext() | |
var b []byte | |
var err error | |
// Do a simple markdown > HTML conversion | |
// without front matter being parsed | |
source := []byte(frontMatter1 + codeFence1) | |
if b, err = app.mdToHTML(source); err != nil { | |
quit(err, 1) | |
} else { | |
fmt.Println("\nmdToHTML() results:\n" + string(b)) | |
//fmt.Printf("Raw YAML:\n%+v", app.metaData) | |
} | |
// Convert Markdown to HTML and parse front matter. | |
source = []byte(frontMatter1 + codeFence1) | |
if b, err = app.mdYAMLtoHTML(source); err != nil { | |
quit(err, 1) | |
} else { | |
fmt.Println("\nmdYAMLtoHTML() results:\n" + string(b)) | |
//fmt.Printf("\nRaw YAML:\n%+v\n", app.metaData) | |
} | |
source = []byte(frontMatter1 + codeFence1 + template1) | |
if b, err = app.mdYAMLtoHTML(source); err != nil { | |
quit(err, 1) | |
} | |
t := app.doTemplate("METABUZZ", string(b)) | |
fmt.Println(t) | |
} | |
func quit(err error, exitCode int) { | |
if err != nil { | |
fmt.Println(err) | |
} | |
os.Exit(exitCode) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
updated