commit
bb07f152b5
|
@ -233,6 +233,13 @@ type Link struct {
|
|||
Footnote Node // If it's a footnote, this is a direct link to the footnote Node. Otherwise nil.
|
||||
}
|
||||
|
||||
// CrossReference is a reference node.
|
||||
type CrossReference struct {
|
||||
Container
|
||||
|
||||
Destination []byte // Destination is where the reference points to
|
||||
}
|
||||
|
||||
// Image represents markdown image node
|
||||
type Image struct {
|
||||
Container
|
||||
|
|
|
@ -879,6 +879,9 @@ func (r *Renderer) RenderNode(w io.Writer, node ast.Node, entering bool) ast.Wal
|
|||
r.outOneOfCr(w, entering, tag, "</aside>")
|
||||
case *ast.Link:
|
||||
r.link(w, node, entering)
|
||||
case *ast.CrossReference:
|
||||
link := &ast.Link{Destination: node.Destination}
|
||||
r.link(w, link, entering)
|
||||
case *ast.Image:
|
||||
if r.opts.Flags&SkipImages != 0 {
|
||||
return ast.SkipChildren
|
||||
|
|
|
@ -38,10 +38,11 @@ const (
|
|||
MathJax // Parse MathJax
|
||||
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
|
||||
MmarkMatters // Mmark document divisions
|
||||
MmarkCaptions // Allow Mmark captions under code and quote blocks be parsed.
|
||||
MmarkMatters // Mmark document divisions, see https://mmark.nl/syntax#document-matters
|
||||
MmarkReferenceIndex // Mmark cross references and indices. See https://mmark.nl/syntax#cross-references
|
||||
MmarkSpecialHeading // Allow Mmark special headings to be parsed. See mmark.nl/syntax
|
||||
|
||||
CommonExtensions Extensions = NoIntraEmphasis | Tables | FencedCode |
|
||||
Autolink | Strikethrough | SpaceHeadings | HeadingIDs |
|
||||
|
@ -146,6 +147,9 @@ func NewWithExtensions(extension Extensions) *Parser {
|
|||
p.inlineCallback['\\'] = escape
|
||||
p.inlineCallback['&'] = entity
|
||||
p.inlineCallback['!'] = maybeImage
|
||||
if p.extensions&MmarkReferenceIndex != 0 {
|
||||
p.inlineCallback['('] = maybeShortRefOrIndex
|
||||
}
|
||||
p.inlineCallback['^'] = maybeInlineFootnote
|
||||
if p.extensions&Autolink != 0 {
|
||||
p.inlineCallback['h'] = maybeAutoLink
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package parser
|
||||
|
||||
import "github.com/gomarkdown/markdown/ast"
|
||||
|
||||
// parse '(#r)', where r does not contain spaces and is an existing label. Or.
|
||||
// (!item) (!item, subitem), for an index, (!!item) signals primary.
|
||||
func maybeShortRefOrIndex(p *Parser, data []byte, offset int) (int, ast.Node) {
|
||||
if len(data[offset:]) < 4 {
|
||||
return 0, nil
|
||||
}
|
||||
// short ref first
|
||||
data = data[offset:]
|
||||
i := 1
|
||||
if data[i] != '#' {
|
||||
return 0, nil
|
||||
}
|
||||
i++
|
||||
Loop:
|
||||
for i < len(data) {
|
||||
c := data[i]
|
||||
switch {
|
||||
case c == ')':
|
||||
break Loop
|
||||
case !isAlnum(c):
|
||||
if c == '_' || c == '-' || c == ':' {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
i = 0
|
||||
break Loop
|
||||
}
|
||||
i++
|
||||
}
|
||||
// end not found or no valid syntax
|
||||
if i == 0 || data[i-1] != ')' {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
id := data[2:i]
|
||||
node := &ast.CrossReference{}
|
||||
node.Destination = id
|
||||
|
||||
return i, node
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package parser
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gomarkdown/markdown/ast"
|
||||
)
|
||||
|
||||
func TestCrossReference(t *testing.T) {
|
||||
p := New()
|
||||
|
||||
tests := []struct {
|
||||
data []byte
|
||||
r *ast.CrossReference
|
||||
fail bool
|
||||
}{
|
||||
// ok
|
||||
{
|
||||
data: []byte("(#yes)"),
|
||||
r: &ast.CrossReference{Destination: []byte("yes")},
|
||||
},
|
||||
// ok
|
||||
{
|
||||
data: []byte("(#y:es)"),
|
||||
r: &ast.CrossReference{Destination: []byte("y:es")},
|
||||
},
|
||||
// fails
|
||||
{data: []byte("(#y es)"), r: nil, fail: true},
|
||||
{data: []byte("(#yes"), r: nil, fail: true},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
_, n := maybeShortRefOrIndex(p, test.data, 0)
|
||||
if test.fail && n != nil {
|
||||
t.Errorf("test %d, should have failed to parse %s", i, test.data)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue