WIP: Mmark: implement asides
This implements asides, blockquote like paragraph prexifed with `A>` instead of just a '>' Adds the extension MmarkAsides Signed-off-by: Miek Gieben <miek@miek.nl>
This commit is contained in:
parent
059798c247
commit
f1700b7c88
|
@ -129,6 +129,11 @@ type BlockQuote struct {
|
|||
Container
|
||||
}
|
||||
|
||||
// Aside represents an markdown aside node.
|
||||
type Aside struct {
|
||||
Container
|
||||
}
|
||||
|
||||
// List represents markdown list node
|
||||
type List struct {
|
||||
Container
|
||||
|
|
|
@ -536,7 +536,7 @@ func (r *Renderer) paragraphEnter(w io.Writer, para *ast.Paragraph) {
|
|||
prev := ast.GetPrevNode(para)
|
||||
if prev != nil {
|
||||
switch prev.(type) {
|
||||
case *ast.HTMLBlock, *ast.List, *ast.Paragraph, *ast.Heading, *ast.CodeBlock, *ast.BlockQuote, *ast.HorizontalRule:
|
||||
case *ast.HTMLBlock, *ast.List, *ast.Paragraph, *ast.Heading, *ast.CodeBlock, *ast.BlockQuote, *ast.Aside, *ast.HorizontalRule:
|
||||
r.cr(w)
|
||||
}
|
||||
}
|
||||
|
@ -546,6 +546,10 @@ func (r *Renderer) paragraphEnter(w io.Writer, para *ast.Paragraph) {
|
|||
if isParentBlockQuote {
|
||||
r.cr(w)
|
||||
}
|
||||
_, isParentAside := para.Parent.(*ast.Aside)
|
||||
if isParentAside {
|
||||
r.cr(w)
|
||||
}
|
||||
}
|
||||
|
||||
tag := tagWithAttributes("<p", blockAttrs(para))
|
||||
|
@ -689,7 +693,7 @@ func (r *Renderer) listExit(w io.Writer, list *ast.List) {
|
|||
if ast.GetNextNode(list) != nil {
|
||||
r.cr(w)
|
||||
}
|
||||
case *ast.Document, *ast.BlockQuote:
|
||||
case *ast.Document, *ast.BlockQuote, *ast.Aside:
|
||||
r.cr(w)
|
||||
}
|
||||
|
||||
|
@ -831,6 +835,9 @@ func (r *Renderer) RenderNode(w io.Writer, node ast.Node, entering bool) ast.Wal
|
|||
case *ast.BlockQuote:
|
||||
tag := tagWithAttributes("<blockquote", blockAttrs(node))
|
||||
r.outOneOfCr(w, entering, tag, "</blockquote>")
|
||||
case *ast.Aside:
|
||||
tag := tagWithAttributes("<aside", blockAttrs(node))
|
||||
r.outOneOfCr(w, entering, tag, "</aside>")
|
||||
case *ast.Link:
|
||||
r.link(w, node, entering)
|
||||
case *ast.Image:
|
||||
|
|
|
@ -21,14 +21,15 @@ func TestMmark(t *testing.T) {
|
|||
if len(testdata)%2 != 0 {
|
||||
t.Fatalf("odd test tuples: %d", len(testdata))
|
||||
}
|
||||
|
||||
ext := parser.CommonExtensions | parser.Attributes | parser.OrderedListStart | parser.MmarkSpecialHeading
|
||||
for i := 0; i < len(testdata); i += 2 {
|
||||
ext := parser.CommonExtensions | parser.Attributes | parser.OrderedListStart | parser.MmarkSpecialHeading
|
||||
parser := parser.NewWithExtensions(ext)
|
||||
p := parser.NewWithExtensions(ext)
|
||||
|
||||
input := testdata[i]
|
||||
want := testdata[i+1]
|
||||
|
||||
got := ToHTML([]byte(input), parser, nil)
|
||||
got := ToHTML([]byte(input), p, nil)
|
||||
|
||||
if bytes.Compare(got, want) != 0 {
|
||||
t.Errorf("want %s, got %s, for input %q", want, got, input)
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
package parser
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/gomarkdown/markdown/ast"
|
||||
)
|
||||
|
||||
// returns aisde prefix length
|
||||
func (p *Parser) asidePrefix(data []byte) int {
|
||||
i := 0
|
||||
n := len(data)
|
||||
for i < 3 && i < n && data[i] == ' ' {
|
||||
i++
|
||||
}
|
||||
if i+1 < n && data[i] == 'A' && data[i+1] == '>' {
|
||||
if i+2 < n && data[i+2] == ' ' {
|
||||
return i + 3
|
||||
}
|
||||
return i + 2
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// aside ends with at least one blank line
|
||||
// followed by something without a aside prefix
|
||||
func (p *Parser) terminateAside(data []byte, beg, end int) bool {
|
||||
if p.isEmpty(data[beg:]) <= 0 {
|
||||
return false
|
||||
}
|
||||
if end >= len(data) {
|
||||
return true
|
||||
}
|
||||
return p.asidePrefix(data[end:]) == 0 && p.isEmpty(data[end:]) == 0
|
||||
}
|
||||
|
||||
// parse a blockquote fragment
|
||||
func (p *Parser) aside(data []byte) int {
|
||||
block := p.addBlock(&ast.Aside{})
|
||||
var raw bytes.Buffer
|
||||
beg, end := 0, 0
|
||||
for beg < len(data) {
|
||||
end = beg
|
||||
// Step over whole lines, collecting them. While doing that, check for
|
||||
// fenced code and if one's found, incorporate it altogether,
|
||||
// irregardless of any contents inside it
|
||||
for end < len(data) && data[end] != '\n' {
|
||||
if p.extensions&FencedCode != 0 {
|
||||
if i := p.fencedCodeBlock(data[end:], false); i > 0 {
|
||||
// -1 to compensate for the extra end++ after the loop:
|
||||
end += i - 1
|
||||
break
|
||||
}
|
||||
}
|
||||
end++
|
||||
}
|
||||
end = skipCharN(data, end, '\n', 1)
|
||||
if pre := p.asidePrefix(data[beg:]); pre > 0 {
|
||||
// skip the prefix
|
||||
beg += pre
|
||||
} else if p.terminateAside(data, beg, end) {
|
||||
break
|
||||
}
|
||||
// this line is part of the aside
|
||||
raw.Write(data[beg:end])
|
||||
beg = end
|
||||
}
|
||||
p.block(raw.Bytes())
|
||||
p.finalize(block)
|
||||
return end
|
||||
}
|
|
@ -228,6 +228,17 @@ func (p *Parser) block(data []byte) {
|
|||
continue
|
||||
}
|
||||
|
||||
// aside:
|
||||
//
|
||||
// A> The proof is too large to fit
|
||||
// A> in the margin.
|
||||
if p.extensions|MmarkAsides != 0 {
|
||||
if p.asidePrefix(data) > 0 {
|
||||
data = data[p.aside(data):]
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// table:
|
||||
//
|
||||
// Name | Age | Phone
|
||||
|
|
|
@ -39,6 +39,7 @@ const (
|
|||
OrderedListStart // Keep track of the first number used when starting an ordered list.
|
||||
Attributes // Block Attributes
|
||||
MmarkSpecialHeading // Allow Mmark special headings to be parsed. See mmark.nl/syntax.
|
||||
MmarkAsides // Mmark asides paragraphs. See https://mmark.nl/syntax.
|
||||
|
||||
CommonExtensions Extensions = NoIntraEmphasis | Tables | FencedCode |
|
||||
Autolink | Strikethrough | SpaceHeadings | HeadingIDs |
|
||||
|
|
Loading…
Reference in New Issue