...
1 package extension
2
3 import (
4 "github.com/yuin/goldmark"
5 gast "github.com/yuin/goldmark/ast"
6 "github.com/yuin/goldmark/extension/ast"
7 "github.com/yuin/goldmark/parser"
8 "github.com/yuin/goldmark/renderer"
9 "github.com/yuin/goldmark/renderer/html"
10 "github.com/yuin/goldmark/text"
11 "github.com/yuin/goldmark/util"
12 )
13
14 type strikethroughDelimiterProcessor struct {
15 }
16
17 func (p *strikethroughDelimiterProcessor) IsDelimiter(b byte) bool {
18 return b == '~'
19 }
20
21 func (p *strikethroughDelimiterProcessor) CanOpenCloser(opener, closer *parser.Delimiter) bool {
22 return opener.Char == closer.Char
23 }
24
25 func (p *strikethroughDelimiterProcessor) OnMatch(consumes int) gast.Node {
26 return ast.NewStrikethrough()
27 }
28
29 var defaultStrikethroughDelimiterProcessor = &strikethroughDelimiterProcessor{}
30
31 type strikethroughParser struct {
32 }
33
34 var defaultStrikethroughParser = &strikethroughParser{}
35
36
37
38 func NewStrikethroughParser() parser.InlineParser {
39 return defaultStrikethroughParser
40 }
41
42 func (s *strikethroughParser) Trigger() []byte {
43 return []byte{'~'}
44 }
45
46 func (s *strikethroughParser) Parse(parent gast.Node, block text.Reader, pc parser.Context) gast.Node {
47 before := block.PrecendingCharacter()
48 line, segment := block.PeekLine()
49 node := parser.ScanDelimiter(line, before, 2, defaultStrikethroughDelimiterProcessor)
50 if node == nil {
51 return nil
52 }
53 node.Segment = segment.WithStop(segment.Start + node.OriginalLength)
54 block.Advance(node.OriginalLength)
55 pc.PushDelimiter(node)
56 return node
57 }
58
59 func (s *strikethroughParser) CloseBlock(parent gast.Node, pc parser.Context) {
60
61 }
62
63
64
65 type StrikethroughHTMLRenderer struct {
66 html.Config
67 }
68
69
70 func NewStrikethroughHTMLRenderer(opts ...html.Option) renderer.NodeRenderer {
71 r := &StrikethroughHTMLRenderer{
72 Config: html.NewConfig(),
73 }
74 for _, opt := range opts {
75 opt.SetHTMLOption(&r.Config)
76 }
77 return r
78 }
79
80
81 func (r *StrikethroughHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
82 reg.Register(ast.KindStrikethrough, r.renderStrikethrough)
83 }
84
85
86 var StrikethroughAttributeFilter = html.GlobalAttributeFilter
87
88 func (r *StrikethroughHTMLRenderer) renderStrikethrough(
89 w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) {
90 if entering {
91 if n.Attributes() != nil {
92 _, _ = w.WriteString("<del")
93 html.RenderAttributes(w, n, StrikethroughAttributeFilter)
94 _ = w.WriteByte('>')
95 } else {
96 _, _ = w.WriteString("<del>")
97 }
98 } else {
99 _, _ = w.WriteString("</del>")
100 }
101 return gast.WalkContinue, nil
102 }
103
104 type strikethrough struct {
105 }
106
107
108 var Strikethrough = &strikethrough{}
109
110 func (e *strikethrough) Extend(m goldmark.Markdown) {
111 m.Parser().AddOptions(parser.WithInlineParsers(
112 util.Prioritized(NewStrikethroughParser(), 500),
113 ))
114 m.Renderer().AddOptions(renderer.WithNodeRenderers(
115 util.Prioritized(NewStrikethroughHTMLRenderer(), 500),
116 ))
117 }
118
View as plain text