package main import ( "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" ) // A Strikethrough struct represents a strikethrough of GFM text. type AstMark struct { gast.BaseInline } // Dump implements Node.Dump. func (n *AstMark) Dump(source []byte, level int) { gast.DumpHelper(n, source, level, nil, nil) } // KindStrikethrough is a NodeKind of the AstMark node. var KindMark = gast.NewNodeKind("AstMark") // Kind implements Node.Kind. func (n *AstMark) Kind() gast.NodeKind { return KindMark } // NewStrikethrough returns a new AstMark node. func NewAstMark() *AstMark { return &AstMark{} } type markDelimiterProcessor struct { } func (p *markDelimiterProcessor) IsDelimiter(b byte) bool { return b == '=' } func (p *markDelimiterProcessor) CanOpenCloser(opener, closer *parser.Delimiter) bool { return opener.Char == closer.Char } func (p *markDelimiterProcessor) OnMatch(consumes int) gast.Node { return NewAstMark() } var defaultMarkDelimiterProcessor = &markDelimiterProcessor{} type markParser struct { } var defaultMarkParser = &markParser{} // NewMarkParser return a new InlineParser that parses // strikethrough expressions. func NewMarkParser() parser.InlineParser { return defaultMarkParser } func (s *markParser) Trigger() []byte { return []byte{'='} } func (s *markParser) Parse(parent gast.Node, block text.Reader, pc parser.Context) gast.Node { before := block.PrecendingCharacter() line, segment := block.PeekLine() node := parser.ScanDelimiter(line, before, 2, defaultMarkDelimiterProcessor) if node == nil { return nil } node.Segment = segment.WithStop(segment.Start + node.OriginalLength) block.Advance(node.OriginalLength) pc.PushDelimiter(node) return node } func (s *markParser) CloseBlock(parent gast.Node, pc parser.Context) { // nothing to do } // MarkHTMLRenderer is a renderer.NodeRenderer implementation that // renders Mark nodes. type MarkHTMLRenderer struct { html.Config } // NewMarkHTMLRenderer returns a new MarkHTMLRenderer. func NewMarkHTMLRenderer(opts ...html.Option) renderer.NodeRenderer { r := &MarkHTMLRenderer{ Config: html.NewConfig(), } for _, opt := range opts { opt.SetHTMLOption(&r.Config) } return r } // RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs. func (r *MarkHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) { reg.Register(KindMark, r.renderMark) } // MarkAttributeFilter defines attribute names which dd elements can have. var MarkAttributeFilter = html.GlobalAttributeFilter func (r *MarkHTMLRenderer) renderMark(w util.BufWriter, source []byte, n gast.Node, entering bool) (gast.WalkStatus, error) { if entering { if n.Attributes() != nil { _, _ = w.WriteString("') } else { _, _ = w.WriteString("") } } else { _, _ = w.WriteString("") } return gast.WalkContinue, nil } type mark struct { } // Mark is an extension that allow you to use strikethrough expression like '==text==' . var Mark = &mark{} func (e *mark) Extend(m goldmark.Markdown) { m.Parser().AddOptions(parser.WithInlineParsers( util.Prioritized(NewMarkParser(), 500), )) m.Renderer().AddOptions(renderer.WithNodeRenderers( util.Prioritized(NewMarkHTMLRenderer(), 500), )) }