diff --git a/markdown.go b/markdown.go index 5e681fd..d50ede5 100644 --- a/markdown.go +++ b/markdown.go @@ -3,21 +3,12 @@ package main import ( "bytes" - "gitlab.com/golang-commonmark/markdown" - "github.com/yuin/goldmark" "github.com/yuin/goldmark/extension" "github.com/yuin/goldmark/renderer/html" -) -func renderMarkdown(pageText string) string { - md := markdown.New( - markdown.HTML(true), - markdown.XHTMLOutput(true), - ) - pageText = md.RenderToString([]byte(pageText)) - return pageText -} + "p83.nl/go/wiki/markdown" +) func renderMarkdown2(pageText string) string { md := goldmark.New( @@ -28,6 +19,8 @@ func renderMarkdown2(pageText string) string { ), ) + markdown.Mark.Extend(md) + var buf bytes.Buffer if err := md.Convert([]byte(pageText), &buf); err != nil { panic(err) diff --git a/markdown/mark.go b/markdown/mark.go new file mode 100644 index 0000000..ae333b1 --- /dev/null +++ b/markdown/mark.go @@ -0,0 +1,138 @@ +package markdown + +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), + )) +}