ref.go

 1package parser
 2
 3import (
 4	"bytes"
 5	"fmt"
 6
 7	"github.com/gomarkdown/markdown/ast"
 8)
 9
10// parse '(#r)', where r does not contain spaces. Or.
11// (!item) (!item, subitem), for an index, (!!item) signals primary.
12func maybeShortRefOrIndex(p *Parser, data []byte, offset int) (int, ast.Node) {
13	if len(data[offset:]) < 4 {
14		return 0, nil
15	}
16	// short ref first
17	data = data[offset:]
18	i := 1
19	switch data[i] {
20	case '#': // cross ref
21		i++
22	Loop:
23		for i < len(data) {
24			c := data[i]
25			switch {
26			case c == ')':
27				break Loop
28			case !isAlnum(c):
29				if c == '_' || c == '-' || c == ':' {
30					i++
31					continue
32				}
33				i = 0
34				break Loop
35			}
36			i++
37		}
38		if i >= len(data) {
39			return 0, nil
40		}
41		if data[i] != ')' {
42			return 0, nil
43		}
44
45		id := data[2:i]
46		node := &ast.CrossReference{}
47		node.Destination = id
48
49		return i + 1, node
50
51	case '!': // index
52		i++
53		start := i
54		i = skipUntilChar(data, start, ')')
55
56		// did we reach the end of the buffer without a closing marker?
57		if i >= len(data) {
58			return 0, nil
59		}
60
61		if len(data[start:i]) < 1 {
62			return 0, nil
63		}
64
65		idx := &ast.Index{}
66
67		idx.ID = fmt.Sprintf("idxref:%d", p.indexCnt)
68		p.indexCnt++
69
70		idx.Primary = data[start] == '!'
71		buf := data[start:i]
72
73		if idx.Primary {
74			buf = buf[1:]
75		}
76		items := bytes.Split(buf, []byte(","))
77		switch len(items) {
78		case 1:
79			idx.Item = bytes.TrimSpace(items[0])
80			return i + 1, idx
81		case 2:
82			idx.Item = bytes.TrimSpace(items[0])
83			idx.Subitem = bytes.TrimSpace(items[1])
84			return i + 1, idx
85		}
86	}
87
88	return 0, nil
89}