1package ast
2
3// ListType contains bitwise or'ed flags for list and list item objects.
4type ListType int
5
6// These are the possible flag values for the ListItem renderer.
7// Multiple flag values may be ORed together.
8// These are mostly of interest if you are writing a new output format.
9const (
10 ListTypeOrdered ListType = 1 << iota
11 ListTypeDefinition
12 ListTypeTerm
13
14 ListItemContainsBlock
15 ListItemBeginningOfList // TODO: figure out if this is of any use now
16 ListItemEndOfList
17)
18
19// CellAlignFlags holds a type of alignment in a table cell.
20type CellAlignFlags int
21
22// These are the possible flag values for the table cell renderer.
23// Only a single one of these values will be used; they are not ORed together.
24// These are mostly of interest if you are writing a new output format.
25const (
26 TableAlignmentLeft CellAlignFlags = 1 << iota
27 TableAlignmentRight
28 TableAlignmentCenter = (TableAlignmentLeft | TableAlignmentRight)
29)
30
31func (a CellAlignFlags) String() string {
32 switch a {
33 case TableAlignmentLeft:
34 return "left"
35 case TableAlignmentRight:
36 return "right"
37 case TableAlignmentCenter:
38 return "center"
39 default:
40 return ""
41 }
42}
43
44// DocumentMatters holds the type of a {front,main,back}matter in the document
45type DocumentMatters int
46
47// These are all possible Document divisions.
48const (
49 DocumentMatterNone DocumentMatters = iota
50 DocumentMatterFront
51 DocumentMatterMain
52 DocumentMatterBack
53)
54
55// CitationTypes holds the type of a citation, informative, normative or suppressed
56type CitationTypes int
57
58const (
59 CitationTypeNone CitationTypes = iota
60 CitationTypeSuppressed
61 CitationTypeInformative
62 CitationTypeNormative
63)
64
65// Node defines an ast node
66type Node interface {
67 AsContainer() *Container
68 AsLeaf() *Leaf
69 GetParent() Node
70 SetParent(newParent Node)
71 GetChildren() []Node
72 SetChildren(newChildren []Node)
73}
74
75// Container is a type of node that can contain children
76type Container struct {
77 Parent Node
78 Children []Node
79
80 Literal []byte // Text contents of the leaf nodes
81 Content []byte // Markdown content of the block nodes
82
83 *Attribute // Block level attribute
84}
85
86// AsContainer returns itself as *Container
87func (c *Container) AsContainer() *Container {
88 return c
89}
90
91// AsLeaf returns nil
92func (c *Container) AsLeaf() *Leaf {
93 return nil
94}
95
96// GetParent returns parent node
97func (c *Container) GetParent() Node {
98 return c.Parent
99}
100
101// SetParent sets the parent node
102func (c *Container) SetParent(newParent Node) {
103 c.Parent = newParent
104}
105
106// GetChildren returns children nodes
107func (c *Container) GetChildren() []Node {
108 return c.Children
109}
110
111// SetChildren sets children node
112func (c *Container) SetChildren(newChildren []Node) {
113 c.Children = newChildren
114}
115
116// Leaf is a type of node that cannot have children
117type Leaf struct {
118 Parent Node
119
120 Literal []byte // Text contents of the leaf nodes
121 Content []byte // Markdown content of the block nodes
122
123 *Attribute // Block level attribute
124}
125
126// AsContainer returns nil
127func (l *Leaf) AsContainer() *Container {
128 return nil
129}
130
131// AsLeaf returns itself as *Leaf
132func (l *Leaf) AsLeaf() *Leaf {
133 return l
134}
135
136// GetParent returns parent node
137func (l *Leaf) GetParent() Node {
138 return l.Parent
139}
140
141// SetParent sets the parent nodd
142func (l *Leaf) SetParent(newParent Node) {
143 l.Parent = newParent
144}
145
146// GetChildren returns nil because Leaf cannot have children
147func (l *Leaf) GetChildren() []Node {
148 return nil
149}
150
151// SetChildren will panic becuase Leaf cannot have children
152func (l *Leaf) SetChildren(newChildren []Node) {
153 panic("leaf node cannot have children")
154}
155
156// Document represents markdown document node, a root of ast
157type Document struct {
158 Container
159}
160
161// DocumentMatter represents markdown node that signals a document
162// division: frontmatter, mainmatter or backmatter.
163type DocumentMatter struct {
164 Container
165
166 Matter DocumentMatters
167}
168
169// BlockQuote represents markdown block quote node
170type BlockQuote struct {
171 Container
172}
173
174// Aside represents an markdown aside node.
175type Aside struct {
176 Container
177}
178
179// List represents markdown list node
180type List struct {
181 Container
182
183 ListFlags ListType
184 Tight bool // Skip <p>s around list item data if true
185 BulletChar byte // '*', '+' or '-' in bullet lists
186 Delimiter byte // '.' or ')' after the number in ordered lists
187 Start int // for ordered lists this indicates the starting number if > 0
188 RefLink []byte // If not nil, turns this list item into a footnote item and triggers different rendering
189 IsFootnotesList bool // This is a list of footnotes
190}
191
192// ListItem represents markdown list item node
193type ListItem struct {
194 Container
195
196 ListFlags ListType
197 Tight bool // Skip <p>s around list item data if true
198 BulletChar byte // '*', '+' or '-' in bullet lists
199 Delimiter byte // '.' or ')' after the number in ordered lists
200 RefLink []byte // If not nil, turns this list item into a footnote item and triggers different rendering
201 IsFootnotesList bool // This is a list of footnotes
202}
203
204// Paragraph represents markdown paragraph node
205type Paragraph struct {
206 Container
207}
208
209// Math represents markdown MathAjax inline node
210type Math struct {
211 Leaf
212}
213
214// MathBlock represents markdown MathAjax block node
215type MathBlock struct {
216 Container
217}
218
219// Heading represents markdown heading node
220type Heading struct {
221 Container
222
223 Level int // This holds the heading level number
224 HeadingID string // This might hold heading ID, if present
225 IsTitleblock bool // Specifies whether it's a title block
226 IsSpecial bool // We are a special heading (starts with .#)
227}
228
229// HorizontalRule represents markdown horizontal rule node
230type HorizontalRule struct {
231 Leaf
232}
233
234// Emph represents markdown emphasis node
235type Emph struct {
236 Container
237}
238
239// Strong represents markdown strong node
240type Strong struct {
241 Container
242}
243
244// Del represents markdown del node
245type Del struct {
246 Container
247}
248
249// Link represents markdown link node
250type Link struct {
251 Container
252
253 Destination []byte // Destination is what goes into a href
254 Title []byte // Title is the tooltip thing that goes in a title attribute
255 NoteID int // NoteID contains a serial number of a footnote, zero if it's not a footnote
256 Footnote Node // If it's a footnote, this is a direct link to the footnote Node. Otherwise nil.
257 DeferredID []byte // If a deferred link this holds the original ID.
258}
259
260// CrossReference is a reference node.
261type CrossReference struct {
262 Container
263
264 Destination []byte // Destination is where the reference points to
265}
266
267// Citation is a citation node.
268type Citation struct {
269 Leaf
270
271 Destination [][]byte // Destination is where the citation points to. Multiple ones are allowed.
272 Type []CitationTypes // 1:1 mapping of destination and citation type
273 Suffix [][]byte // Potential citation suffix, i.e. [@!RFC1035, p. 144]
274}
275
276// Image represents markdown image node
277type Image struct {
278 Container
279
280 Destination []byte // Destination is what goes into a href
281 Title []byte // Title is the tooltip thing that goes in a title attribute
282}
283
284// Text represents markdown text node
285type Text struct {
286 Leaf
287}
288
289// HTMLBlock represents markdown html node
290type HTMLBlock struct {
291 Leaf
292}
293
294// CodeBlock represents markdown code block node
295type CodeBlock struct {
296 Leaf
297
298 IsFenced bool // Specifies whether it's a fenced code block or an indented one
299 Info []byte // This holds the info string
300 FenceChar byte
301 FenceLength int
302 FenceOffset int
303}
304
305// Softbreak represents markdown softbreak node
306// Note: not used currently
307type Softbreak struct {
308 Leaf
309}
310
311// Hardbreak represents markdown hard break node
312type Hardbreak struct {
313 Leaf
314}
315
316// NonBlockingSpace represents markdown non-blocking space node
317type NonBlockingSpace struct {
318 Leaf
319}
320
321// Code represents markdown code node
322type Code struct {
323 Leaf
324}
325
326// HTMLSpan represents markdown html span node
327type HTMLSpan struct {
328 Leaf
329}
330
331// Table represents markdown table node
332type Table struct {
333 Container
334}
335
336// TableCell represents markdown table cell node
337type TableCell struct {
338 Container
339
340 IsHeader bool // This tells if it's under the header row
341 Align CellAlignFlags // This holds the value for align attribute
342}
343
344// TableHeader represents markdown table head node
345type TableHeader struct {
346 Container
347}
348
349// TableBody represents markdown table body node
350type TableBody struct {
351 Container
352}
353
354// TableRow represents markdown table row node
355type TableRow struct {
356 Container
357}
358
359// TableFooter represents markdown table foot node
360type TableFooter struct {
361 Container
362}
363
364// Caption represents a figure, code or quote caption
365type Caption struct {
366 Container
367}
368
369// CaptionFigure is a node (blockquote or codeblock) that has a caption
370type CaptionFigure struct {
371 Container
372
373 HeadingID string // This might hold heading ID, if present
374}
375
376// Callout is a node that can exist both in text (where it is an actual node) and in a code block.
377type Callout struct {
378 Leaf
379
380 ID []byte // number of this callout
381}
382
383// Index is a node that contains an Index item and an optional, subitem.
384type Index struct {
385 Leaf
386
387 Primary bool
388 Item []byte
389 Subitem []byte
390 ID string // ID of the index
391}
392
393// Subscript is a subscript node
394type Subscript struct {
395 Leaf
396}
397
398// Subscript is a superscript node
399type Superscript struct {
400 Leaf
401}
402
403// Footnotes is a node that contains all footnotes
404type Footnotes struct {
405 Container
406}
407
408func removeNodeFromArray(a []Node, node Node) []Node {
409 n := len(a)
410 for i := 0; i < n; i++ {
411 if a[i] == node {
412 return append(a[:i], a[i+1:]...)
413 }
414 }
415 return nil
416}
417
418// AppendChild appends child to children of parent
419// It panics if either node is nil.
420func AppendChild(parent Node, child Node) {
421 RemoveFromTree(child)
422 child.SetParent(parent)
423 newChildren := append(parent.GetChildren(), child)
424 parent.SetChildren(newChildren)
425}
426
427// RemoveFromTree removes this node from tree
428func RemoveFromTree(n Node) {
429 if n.GetParent() == nil {
430 return
431 }
432 // important: don't clear n.Children if n has no parent
433 // we're called from AppendChild and that might happen on a node
434 // that accumulated Children but hasn't been inserted into the tree
435 n.SetChildren(nil)
436 p := n.GetParent()
437 newChildren := removeNodeFromArray(p.GetChildren(), n)
438 if newChildren != nil {
439 p.SetChildren(newChildren)
440 }
441}
442
443// GetLastChild returns last child of node n
444// It's implemented as stand-alone function to keep Node interface small
445func GetLastChild(n Node) Node {
446 a := n.GetChildren()
447 if len(a) > 0 {
448 return a[len(a)-1]
449 }
450 return nil
451}
452
453// GetFirstChild returns first child of node n
454// It's implemented as stand-alone function to keep Node interface small
455func GetFirstChild(n Node) Node {
456 a := n.GetChildren()
457 if len(a) > 0 {
458 return a[0]
459 }
460 return nil
461}
462
463// GetNextNode returns next sibling of node n (node after n)
464// We can't make it part of Container or Leaf because we loose Node identity
465func GetNextNode(n Node) Node {
466 parent := n.GetParent()
467 if parent == nil {
468 return nil
469 }
470 a := parent.GetChildren()
471 len := len(a) - 1
472 for i := 0; i < len; i++ {
473 if a[i] == n {
474 return a[i+1]
475 }
476 }
477 return nil
478}
479
480// GetPrevNode returns previous sibling of node n (node before n)
481// We can't make it part of Container or Leaf because we loose Node identity
482func GetPrevNode(n Node) Node {
483 parent := n.GetParent()
484 if parent == nil {
485 return nil
486 }
487 a := parent.GetChildren()
488 len := len(a)
489 for i := 1; i < len; i++ {
490 if a[i] == n {
491 return a[i-1]
492 }
493 }
494 return nil
495}
496
497// WalkStatus allows NodeVisitor to have some control over the tree traversal.
498// It is returned from NodeVisitor and different values allow Node.Walk to
499// decide which node to go to next.
500type WalkStatus int
501
502const (
503 // GoToNext is the default traversal of every node.
504 GoToNext WalkStatus = iota
505 // SkipChildren tells walker to skip all children of current node.
506 SkipChildren
507 // Terminate tells walker to terminate the traversal.
508 Terminate
509)
510
511// NodeVisitor is a callback to be called when traversing the syntax tree.
512// Called twice for every node: once with entering=true when the branch is
513// first visited, then with entering=false after all the children are done.
514type NodeVisitor interface {
515 Visit(node Node, entering bool) WalkStatus
516}
517
518// NodeVisitorFunc casts a function to match NodeVisitor interface
519type NodeVisitorFunc func(node Node, entering bool) WalkStatus
520
521// Walk traverses tree recursively
522func Walk(n Node, visitor NodeVisitor) WalkStatus {
523 isContainer := n.AsContainer() != nil
524 status := visitor.Visit(n, true) // entering
525 if status == Terminate {
526 // even if terminating, close container node
527 if isContainer {
528 visitor.Visit(n, false)
529 }
530 return status
531 }
532 if isContainer && status != SkipChildren {
533 children := n.GetChildren()
534 for _, n := range children {
535 status = Walk(n, visitor)
536 if status == Terminate {
537 return status
538 }
539 }
540 }
541 if isContainer {
542 status = visitor.Visit(n, false) // exiting
543 if status == Terminate {
544 return status
545 }
546 }
547 return GoToNext
548}
549
550// Visit calls visitor function
551func (f NodeVisitorFunc) Visit(node Node, entering bool) WalkStatus {
552 return f(node, entering)
553}
554
555// WalkFunc is like Walk but accepts just a callback function
556func WalkFunc(n Node, f NodeVisitorFunc) {
557 visitor := NodeVisitorFunc(f)
558 Walk(n, visitor)
559}