Merge pull request #55 from mmarkdown/index-example-list

parser: allow indices
This commit is contained in:
Miek Gieben 2018-08-13 20:35:28 +01:00 committed by GitHub
commit f5568e358d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 147 additions and 29 deletions

View File

@ -366,6 +366,15 @@ type Callout struct {
ID []byte // number of this callout
}
// Index is a node that contains an Index item and an optional, subitem.
type Index struct {
Leaf
Primary bool
Item []byte
Subitem []byte
}
func removeNodeFromArray(a []Node, node Node) []Node {
n := len(a)
for i := 0; i < n; i++ {

View File

@ -869,6 +869,10 @@ func (r *Renderer) callout(w io.Writer, node *ast.Callout) {
r.outs(w, "</span>")
}
func (r *Renderer) index(w io.Writer, node *ast.Index) {
// there is no in-text representation.
}
// RenderNode renders a markdown node to HTML
func (r *Renderer) RenderNode(w io.Writer, node ast.Node, entering bool) ast.WalkStatus {
if r.opts.RenderNodeHook != nil {
@ -957,6 +961,8 @@ func (r *Renderer) RenderNode(w io.Writer, node ast.Node, entering bool) ast.Wal
r.matter(w, node, entering)
case *ast.Callout:
r.callout(w, node)
case *ast.Index:
r.index(w, node)
default:
panic(fmt.Sprintf("Unknown node %T", node))
}

View File

@ -1,8 +1,12 @@
package parser
import "github.com/gomarkdown/markdown/ast"
import (
"bytes"
// parse '(#r)', where r does not contain spaces and is an existing label. Or.
"github.com/gomarkdown/markdown/ast"
)
// parse '(#r)', where r does not contain spaces. 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 {
@ -11,34 +15,67 @@ func maybeShortRefOrIndex(p *Parser, data []byte, offset int) (int, ast.Node) {
// 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
}
switch data[i] {
case '#': // cross ref
i++
}
// end not found or no valid syntax
if i == 0 || data[i-1] != ')' {
return 0, nil
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
case '!': // index
i++
start := i
i = skipUntilChar(data, start, ')')
// did we reach the end of the buffer without a closing marker?
if i >= len(data) {
return 0, nil
}
if len(data[start:i]) < 1 {
return 0, nil
}
idx := &ast.Index{}
idx.Primary = data[start] == '!'
buf := data[start:i]
if idx.Primary {
buf = buf[1:]
}
items := bytes.Split(buf, []byte(","))
switch len(items) {
case 1:
idx.Item = bytes.TrimSpace(items[0])
return i + 1, idx
case 2:
idx.Item = bytes.TrimSpace(items[0])
idx.Subitem = bytes.TrimSpace(items[1])
return i + 1, idx
}
}
id := data[2:i]
node := &ast.CrossReference{}
node.Destination = id
return i, node
return 0, nil
}

View File

@ -36,3 +36,58 @@ func TestCrossReference(t *testing.T) {
}
}
}
func TestIndex(t *testing.T) {
p := New()
tests := []struct {
data []byte
i *ast.Index
fail bool
}{
// ok
{
data: []byte("(!yes)"),
i: &ast.Index{Item: []byte("yes")},
},
{
data: []byte("(!y:es)"),
i: &ast.Index{Item: []byte("y:es")},
},
{
data: []byte("(!yes, no)"),
i: &ast.Index{Item: []byte("yes"), Subitem: []byte("no")},
},
{
data: []byte("(! yes , no )"),
i: &ast.Index{Item: []byte("yes"), Subitem: []byte("no")},
},
// fails
{data: []byte("(!yes"), fail: true},
{data: []byte("(_yes"), 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)
continue
}
if test.fail && n == nil {
// ok
continue
}
idx := n.(*ast.Index)
if string(test.i.Item) != string(idx.Item) {
t.Errorf("test %d, got item %s, wanted %s", i, idx.Item, test.i.Item)
}
if string(test.i.Subitem) != string(idx.Subitem) {
t.Errorf("test %d, got item %s, wanted %s", i, idx.Subitem, test.i.Subitem)
}
if test.i.Primary != idx.Primary {
t.Errorf("test %d, got item %t, wanted %t", i, idx.Primary, test.i.Primary)
}
}
}

11
testdata/mmark.test vendored
View File

@ -79,3 +79,14 @@ code
---
<pre><code class="myclass1 myclass2">code
</code></pre>
---
# Index
(!myitem, subitem)
(!!item)
(!!item, subtitem )
---
<h1>Index</h1>
<p>
</p>