summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/gomarkdown/markdown/parser/ref.go
blob: c1e053417bc31261ed81a5c65503bbf8e3acdc0a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package parser

import (
	"bytes"
	"fmt"

	"github.com/gomarkdown/markdown/ast"
)

// parse '(#r, text)', where r does not contain spaces, but text may (similar to a citation). 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
	switch data[i] {
	case '#': // cross ref
		i++
	Loop:
		for i < len(data) {
			c := data[i]
			switch {
			case c == ')':
				break Loop
			case !IsAlnum(c):
				if c == '_' || c == '-' || c == ':' || c == ' ' || c == ',' {
					i++
					continue
				}
				i = 0
				break Loop
			}
			i++
		}
		if i >= len(data) {
			return 0, nil
		}
		if data[i] != ')' {
			return 0, nil
		}

		id := data[2:i]
		node := &ast.CrossReference{}
		node.Destination = id
		if c := bytes.Index(id, []byte(",")); c > 0 {
			idpart := id[:c]
			suff := id[c+1:]
			suff = bytes.TrimSpace(suff)
			node.Destination = idpart
			node.Suffix = suff
		}
		if bytes.Index(node.Destination, []byte(" ")) > 0 {
			// no spaces allowed in id
			return 0, nil
		}
		if bytes.Index(node.Destination, []byte(",")) > 0 {
			// nor comma
			return 0, nil
		}

		return i + 1, 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.ID = fmt.Sprintf("idxref:%d", p.indexCnt)
		p.indexCnt++

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

	return 0, nil
}