package markup
import (
"bytes"
"regexp"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
)
// fossilBlockTag is what fossil's markdown takes as the start of an HTML
// block: <html>, <pre> or <script>, a comment, or <hr> (block_tags and
// parse_htmlblock in src/markdown.c).
var fossilBlockTag = regexp.MustCompile(`(?i)^ {0,3}<(?:(?:html|pre|script)[\s>]|!--|hr[\s/>])`)
// fossilHTMLBlocks is goldmark's HTML block parser, narrowed to the
// blocks fossil's markdown has. Any other tag — a <table>, a <div> — is
// inline HTML in a paragraph there, so the markdown between the tags is
// rendered: a forum post laying a formula out in a table writes `x` in
// its cells and means code. CommonMark makes such a tag a raw block,
// and the post showed its backticks. And as in fossil, only a blank
// line, a heading, a rule or a list item ends a paragraph, never a tag.
type fossilHTMLBlocks struct{ parser.BlockParser }
func (p fossilHTMLBlocks) Open(parent ast.Node, reader text.Reader, pc parser.Context) (ast.Node, parser.State) {
line, _ := reader.PeekLine()
if !fossilBlockTag.Match(bytes.TrimRight(line, "\r\n")) {
return nil, parser.NoChildren
}
return p.BlockParser.Open(parent, reader, pc)
}
func (fossilHTMLBlocks) CanInterruptParagraph() bool { return false }
// fossilParser is goldmark's default parser with fossil's HTML blocks.
func fossilParser() goldmark.Option {
blocks := parser.DefaultBlockParsers()
for i, b := range blocks {
if b.Priority == 900 { // NewHTMLBlockParser, per DefaultBlockParsers
blocks[i] = util.Prioritized(fossilHTMLBlocks{parser.NewHTMLBlockParser()}, 900)
}
}
return goldmark.WithParser(parser.NewParser(parser.WithBlockParsers(blocks...),
parser.WithInlineParsers(parser.DefaultInlineParsers()...),
parser.WithParagraphTransformers(parser.DefaultParagraphTransformers()...)))
}