...
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(w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) {
89 if entering {
90 if n.Attributes() != nil {
91 _, _ = w.WriteString("<del")
92 html.RenderAttributes(w, n, StrikethroughAttributeFilter)
93 _ = w.WriteByte('>')
94 } else {
95 _, _ = w.WriteString("<del>")
96 }
97 } else {
98 _, _ = w.WriteString("</del>")
99 }
100 return gast.WalkContinue, nil
101 }
102
103 type strikethrough struct {
104 }
105
106
107 var Strikethrough = &strikethrough{}
108
109 func (e *strikethrough) Extend(m goldmark.Markdown) {
110 m.Parser().AddOptions(parser.WithInlineParsers(
111 util.Prioritized(NewStrikethroughParser(), 500),
112 ))
113 m.Renderer().AddOptions(renderer.WithNodeRenderers(
114 util.Prioritized(NewStrikethroughHTMLRenderer(), 500),
115 ))
116 }
117
View as plain text