mdrender

package
v0.0.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 2, 2024 License: MIT Imports: 6 Imported by: 0

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var DefaultWriter = NewWriter()

DefaultWriter is a default instance of the Writer.

Functions

func NewRenderer

func NewRenderer(opts ...Option) renderer.NodeRenderer

NewRenderer returns a new Renderer with given options.

Example
package main

import (
	"bytes"
	"fmt"
	"strings"

	"github.com/yuin/goldmark"
	"github.com/yuin/goldmark/ast"
	"github.com/yuin/goldmark/parser"
	"github.com/yuin/goldmark/text"
	"go.abhg.dev/goldmark/hashtag"

	"github.com/will-wow/larkdown"
	"github.com/will-wow/larkdown/gmast"
	"github.com/will-wow/larkdown/match"
	"github.com/will-wow/larkdown/mdfront"
	"github.com/will-wow/larkdown/mdrender"
	"github.com/will-wow/larkdown/query"
)

var postMarkdown = `# Markdown in Go

## Tags

#markdown #golang

In this essay I will explain...
`

type PostData struct {
	Slug string `yaml:"slug"`
}

// Matcher for a line of #tags under the heading ## Tags
var tagsQuery = []match.Node{
	match.Branch{Level: 2, Name: []byte("tags"), CaseInsensitive: true},
	match.NodeOfKind{Kind: ast.KindParagraph},
}

var titleQuery = []match.Node{match.Heading{Level: 1}}

func main() {
	source := []byte(postMarkdown)
	// Preprocess the markdown into goldmark AST
	md := goldmark.New(
		goldmark.WithExtensions(
			// Parse hashtags to they can be matched against.
			&hashtag.Extender{Variant: hashtag.ObsidianVariant},
			// Support frontmatter rendering.
			// This does nothing on its own, but sets up a place to render frontmatter to.
			&mdfront.Extender{},
		),
	)

	// Set up context for the metadata
	context := parser.NewContext()
	// Parse the markdown into an AST, with context
	doc := md.Parser().Parse(text.NewReader(source), parser.WithContext(context))

	// ====
	// Get the tags from the file
	// ====

	// Find the tags header to append to
	tagsLine, err := query.QueryOne(doc, source, tagsQuery)
	if err != nil {
		panic(fmt.Errorf("error finding tags heading: %w", err))
	}

	// ====
	// Edit the AST to add a new tag
	// ====

	// Create a new tag
	space, source := gmast.NewSpace(source)
	hashtag, source := gmast.NewHashtag("testing", source)

	// Append the new tag to the tags line
	gmast.AppendChild(tagsLine,
		space,
		hashtag,
	)

	// ====
	// Add a slug to the post's frontmatter.
	// ====

	// Find the title header to use as a slug
	// In practice, you might want to also pull this frontmatter out of an existing document
	// using goldmark-meta or goldmark-frontmatter.
	title, err := larkdown.Find(doc, source, titleQuery, larkdown.DecodeText)
	if err != nil {
		panic(fmt.Errorf("error finding title: %w", err))
	}

	// Slugify the title
	slug := strings.ReplaceAll(strings.ToLower(title), " ", "-")

	// Set up a struct to render the frontmatter
	data := &PostData{Slug: slug}

	// ====
	// Use larkdown renderer to render back to markdown
	// ====
	var newMarkdown bytes.Buffer
	// Here we set up the renderer outside the goldmark.New call, so you can use the normal
	// goldmark HTML renderer, and also render back to markdown.
	err = larkdown.NewNodeRenderer(
		// Pass the metaData to the renderer to render back to markdown
		mdrender.WithFrontmatter(data),
	).Render(&newMarkdown, source, doc)
	if err != nil {
		panic(fmt.Errorf("error rendering Markdown: %w", err))
	}

	// ====
	// Also render to HTML
	// ====
	var html bytes.Buffer
	err = md.Renderer().Render(&html, source, doc)
	if err != nil {
		panic(fmt.Errorf("error rendering HTML: %w", err))
	}

	// The new #testing tag is after the #golang tag in the HTML output
	fmt.Println("HTML:")
	fmt.Println(html.String())

	// The new #testing tag is after the #golang tag in the markdown
	fmt.Println("Markdown:")
	fmt.Println(newMarkdown.String())

}
Output:

HTML:
<h1>Markdown in Go</h1>
<h2>Tags</h2>
<p><span class="hashtag">#markdown</span> <span class="hashtag">#golang</span> <span class="hashtag">#testing</span></p>
<p>In this essay I will explain...</p>

Markdown:
---
slug: markdown-in-go
---

# Markdown in Go

## Tags

#markdown #golang #testing

In this essay I will explain...

func WithWriter

func WithWriter(writer Writer) interface {
	renderer.Option
	Option
}

WithWriter is a functional option that allow you to set the given writer to the renderer.

Types

type Config

type Config struct {
	Writer      Writer // Writer is a writer used to write textual contents.
	Frontmatter any    // Frontmatter is a frontmatter struct to be rendered to yaml.
}

A Config struct has configuration for the markdown renderer.

func NewConfig

func NewConfig() Config

NewConfig returns a new Config with defaults.

func (*Config) SetOption

func (c *Config) SetOption(name renderer.OptionName, value interface{})

SetOption implements renderer.NodeRenderer.SetOption.

type Option

type Option interface {
	SetMarkdownOption(*Config)
}

An Option interface sets options for HTML based renderers.

func WithFrontmatter

func WithFrontmatter(data any) Option

WithFrontmatter records a frontmatter struct for repopulating the frontmatter.

type Renderer

type Renderer struct {
	Config
}

A Renderer struct is an implementation of renderer.NodeRenderer that renders nodes as Markdown.

func (*Renderer) RegisterFuncs

func (r *Renderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer)

RegisterFuncs implements NodeRenderer.RegisterFuncs .

type Writer

type Writer interface {
	// Write writes the given source to writer with resolving references and unescaping
	// backslash escaped characters.
	Write(writer util.BufWriter, source []byte)
}

A Writer interface writes textual contents to a writer.

func NewWriter

func NewWriter() Writer

NewWriter returns a new Writer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL