1package parser
2
3import (
4 "bytes"
5
6 "github.com/gomarkdown/markdown/ast"
7)
8
9// sFigureLine checks if there's a figure line (e.g., !--- ) at the beginning of data,
10// and returns the end index if so, or 0 otherwise.
11func sFigureLine(data []byte, oldmarker string) (end int, marker string) {
12 i, size := 0, 0
13
14 n := len(data)
15 // skip up to three spaces
16 for i < n && i < 3 && data[i] == ' ' {
17 i++
18 }
19
20 // check for the marker characters: !
21 if i+1 >= n {
22 return 0, ""
23 }
24 if data[i] != '!' || data[i+1] != '-' {
25 return 0, ""
26 }
27 i++
28
29 c := data[i] // i.e. the -
30
31 // the whole line must be the same char or whitespace
32 for i < n && data[i] == c {
33 size++
34 i++
35 }
36
37 // the marker char must occur at least 3 times
38 if size < 3 {
39 return 0, ""
40 }
41 marker = string(data[i-size : i])
42
43 // if this is the end marker, it must match the beginning marker
44 if oldmarker != "" && marker != oldmarker {
45 return 0, ""
46 }
47
48 // there is no syntax modifier although it might be an idea to re-use this space for something?
49
50 i = skipChar(data, i, ' ')
51 if i >= n || data[i] != '\n' {
52 if i == n {
53 return i, marker
54 }
55 return 0, ""
56 }
57 return i + 1, marker // Take newline into account.
58}
59
60// figureBlock returns the end index if data contains a figure block at the beginning,
61// or 0 otherwise. It writes to out if doRender is true, otherwise it has no side effects.
62// If doRender is true, a final newline is mandatory to recognize the figure block.
63func (p *Parser) figureBlock(data []byte, doRender bool) int {
64 beg, marker := sFigureLine(data, "")
65 if beg == 0 || beg >= len(data) {
66 return 0
67 }
68
69 var raw bytes.Buffer
70
71 for {
72 // safe to assume beg < len(data)
73
74 // check for the end of the code block
75 figEnd, _ := sFigureLine(data[beg:], marker)
76 if figEnd != 0 {
77 beg += figEnd
78 break
79 }
80
81 // copy the current line
82 end := skipUntilChar(data, beg, '\n') + 1
83
84 // did we reach the end of the buffer without a closing marker?
85 if end >= len(data) {
86 return 0
87 }
88
89 // verbatim copy to the working buffer
90 if doRender {
91 raw.Write(data[beg:end])
92 }
93 beg = end
94 }
95
96 if !doRender {
97 return beg
98 }
99
100 figure := &ast.CaptionFigure{}
101 p.addBlock(figure)
102 p.block(raw.Bytes())
103
104 defer p.finalize(figure)
105
106 if captionContent, id, consumed := p.caption(data[beg:], []byte("Figure: ")); consumed > 0 {
107 caption := &ast.Caption{}
108 p.Inline(caption, captionContent)
109
110 figure.HeadingID = id
111
112 p.addChild(caption)
113
114 beg += consumed
115 }
116
117 p.finalize(figure)
118 return beg
119}