summaryrefslogtreecommitdiffstats
path: root/vendor/gitlab.com/golang-commonmark/markdown/markdown.go
blob: 1e37b3aee7d134de81679bc8945977243004419c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// Copyright 2015 The Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package markdown provides CommonMark-compliant markdown parser and renderer.
package markdown

import (
	"bytes"
	"io"
)

type Markdown struct {
	options
	Block         ParserBlock
	Inline        ParserInline
	renderOptions RenderOptions
}

type RenderOptions struct {
	LangPrefix string // CSS language class prefix for fenced blocks
	XHTML      bool   // render as XHTML instead of HTML
	Breaks     bool   // convert \n in paragraphs into <br>
	Nofollow   bool   // add rel="nofollow" to the links
}

type options struct {
	HTML        bool      // allow raw HTML in the markup
	Tables      bool      // GFM tables
	Linkify     bool      // autoconvert URL-like text to links
	Typographer bool      // enable some typographic replacements
	Quotes      [4]string // double/single quotes replacement pairs
	MaxNesting  int       // maximum nesting level
}

type Environment struct {
	References map[string]map[string]string
}

type CoreRule func(*StateCore)

var coreRules []CoreRule

func New(opts ...option) *Markdown {
	m := &Markdown{
		options: options{
			Tables:      true,
			Linkify:     true,
			Typographer: true,
			Quotes:      [4]string{"“", "”", "‘", "’"},
			MaxNesting:  20,
		},
		renderOptions: RenderOptions{LangPrefix: "language-"},
	}
	for _, opt := range opts {
		opt(m)
	}
	return m
}

func (m *Markdown) Parse(src []byte) []Token {
	if len(src) == 0 {
		return nil
	}

	s := &StateCore{
		Md:  m,
		Env: &Environment{},
	}
	s.Tokens = m.Block.Parse(src, m, s.Env)

	for _, r := range coreRules {
		r(s)
	}
	return s.Tokens
}

func (m *Markdown) Render(w io.Writer, src []byte) error {
	if len(src) == 0 {
		return nil
	}

	return NewRenderer(w).Render(m.Parse(src), m.renderOptions)
}

func (m *Markdown) RenderTokens(w io.Writer, tokens []Token) error {
	if len(tokens) == 0 {
		return nil
	}

	return NewRenderer(w).Render(tokens, m.renderOptions)
}

func (m *Markdown) RenderToString(src []byte) string {
	if len(src) == 0 {
		return ""
	}

	var buf bytes.Buffer
	NewRenderer(&buf).Render(m.Parse(src), m.renderOptions)
	return buf.String()
}

func (m *Markdown) RenderTokensToString(tokens []Token) string {
	if len(tokens) == 0 {
		return ""
	}

	var buf bytes.Buffer
	NewRenderer(&buf).Render(tokens, m.renderOptions)
	return buf.String()
}