Merge pull request #31 from mmarkdown/ref

Mmark: corss references
This commit is contained in:
Miek Gieben 2018-08-03 08:36:24 +01:00 committed by GitHub
commit bb07f152b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 98 additions and 2 deletions

View File

@ -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

View File

@ -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

View File

@ -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

44
parser/ref.go Normal file
View File

@ -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
}

38
parser/ref_test.go Normal file
View File

@ -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)
}
}
}