-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsubscript.go
128 lines (108 loc) · 3.3 KB
/
subscript.go
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package extension
import (
"github.com/bowman2001/goldmark-supersubscript/ast"
"github.com/yuin/goldmark"
gast "github.com/yuin/goldmark/ast"
"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"
)
type subscriptDelimiterProcessor struct {
}
func (p *subscriptDelimiterProcessor) IsDelimiter(b byte) bool {
return b == '~'
}
func (p *subscriptDelimiterProcessor) CanOpenCloser(opener, closer *parser.Delimiter) bool {
return opener.Char == closer.Char
}
func (p *subscriptDelimiterProcessor) OnMatch(consumes int) gast.Node {
return ast.NewSubscript()
}
var defaultSubscriptDelimiterProcessor = &subscriptDelimiterProcessor{}
type subscriptParser struct {
}
var defaultSubscriptParser = &subscriptParser{}
// NewSubscriptParser return a new InlineParser that parses
// subscript expressions.
func NewSubscriptParser() parser.InlineParser {
return defaultSubscriptParser
}
func (s *subscriptParser) Trigger() []byte {
return []byte{'~'}
}
func (s *subscriptParser) Parse(parent gast.Node, block text.Reader, pc parser.Context) gast.Node {
before := block.PrecendingCharacter()
line, segment := block.PeekLine()
node := parser.ScanDelimiter(line, before, 1, defaultSubscriptDelimiterProcessor)
if node == nil {
return nil
}
if node.CanOpen {
for i := 1; i < len(line); i++ {
c := line[i]
if c == line[0] {
break
}
if util.IsSpace(c) {
return nil
}
}
}
node.Segment = segment.WithStop(segment.Start + node.OriginalLength)
block.Advance(node.OriginalLength)
pc.PushDelimiter(node)
return node
}
func (s *subscriptParser) CloseBlock(parent gast.Node, pc parser.Context) {
// nothing to do
}
// SubscriptHTMLRenderer is a renderer.NodeRenderer implementation that
// renders Subscript nodes.
type SubscriptHTMLRenderer struct {
html.Config
}
// NewSubscriptHTMLRenderer returns a new SubscriptHTMLRenderer.
func NewSubscriptHTMLRenderer(opts ...html.Option) renderer.NodeRenderer {
r := &SubscriptHTMLRenderer{
Config: html.NewConfig(),
}
for _, opt := range opts {
opt.SetHTMLOption(&r.Config)
}
return r
}
// RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs.
func (r *SubscriptHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
reg.Register(ast.KindSubscript, r.renderSubscript)
}
// SubscriptAttributeFilter defines attribute names which dd elements can have.
var SubscriptAttributeFilter = html.GlobalAttributeFilter
func (r *SubscriptHTMLRenderer) renderSubscript(
w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) {
if entering {
if n.Attributes() != nil {
_, _ = w.WriteString("<sub")
html.RenderAttributes(w, n, SubscriptAttributeFilter)
_ = w.WriteByte('>')
} else {
_, _ = w.WriteString("<sub>")
}
} else {
_, _ = w.WriteString("</sub>")
}
return gast.WalkContinue, nil
}
type subscript struct {
}
// Subscript is an extension that allows you to use a subscript expression like 'x~0~'.
var Subscript = &subscript{}
func (e *subscript) Extend(m goldmark.Markdown) {
m.Parser().AddOptions(parser.WithInlineParsers(
util.Prioritized(NewSubscriptParser(), 600),
))
m.Renderer().AddOptions(renderer.WithNodeRenderers(
util.Prioritized(NewSubscriptHTMLRenderer(), 600),
))
}