caption.go

 1package parser
 2
 3import (
 4	"bytes"
 5)
 6
 7// caption checks for a caption, it returns the caption data and a potential "headingID".
 8func (p *Parser) caption(data, caption []byte) ([]byte, string, int) {
 9	if !bytes.HasPrefix(data, caption) {
10		return nil, "", 0
11	}
12	j := len(caption)
13	data = data[j:]
14	end := p.linesUntilEmpty(data)
15
16	data = data[:end]
17
18	id, start := captionID(data)
19	if id != "" {
20		return data[:start], id, end + j
21	}
22
23	return data, "", end + j
24}
25
26// linesUntilEmpty scans lines up to the first empty line.
27func (p *Parser) linesUntilEmpty(data []byte) int {
28	line, i := 0, 0
29
30	for line < len(data) {
31		i++
32
33		// find the end of this line
34		for i < len(data) && data[i-1] != '\n' {
35			i++
36		}
37
38		if p.isEmpty(data[line:i]) == 0 {
39			line = i
40			continue
41		}
42
43		break
44	}
45	return i
46}
47
48// captionID checks if the caption *ends* in {#....}. If so the text after {# is taken to be
49// the ID/anchor of the entire figure block.
50func captionID(data []byte) (string, int) {
51	end := len(data)
52
53	j, k := 0, 0
54	// find start/end of heading id
55	for j = 0; j < end-1 && (data[j] != '{' || data[j+1] != '#'); j++ {
56	}
57	for k = j + 1; k < end && data[k] != '}'; k++ {
58	}
59	// remains must be whitespace.
60	for l := k + 1; l < end; l++ {
61		if !isSpace(data[l]) {
62			return "", 0
63		}
64	}
65
66	if j > 0 && k > 0 && j+2 < k {
67		return string(data[j+2 : k]), j
68	}
69	return "", 0
70}