123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581 |
- package ast
- // An attribute can be attached to block elements. They are specified as
- // {#id .classs key="value"} where quotes for values are mandatory, multiple
- // key/value pairs are separated by whitespace.
- type Attribute struct {
- ID []byte
- Classes [][]byte
- Attrs map[string][]byte
- }
- // ListType contains bitwise or'ed flags for list and list item objects.
- type ListType int
- // These are the possible flag values for the ListItem renderer.
- // Multiple flag values may be ORed together.
- // These are mostly of interest if you are writing a new output format.
- const (
- ListTypeOrdered ListType = 1 << iota
- ListTypeDefinition
- ListTypeTerm
- ListItemContainsBlock
- ListItemBeginningOfList // TODO: figure out if this is of any use now
- ListItemEndOfList
- )
- // CellAlignFlags holds a type of alignment in a table cell.
- type CellAlignFlags int
- // These are the possible flag values for the table cell renderer.
- // Only a single one of these values will be used; they are not ORed together.
- // These are mostly of interest if you are writing a new output format.
- const (
- TableAlignmentLeft CellAlignFlags = 1 << iota
- TableAlignmentRight
- TableAlignmentCenter = (TableAlignmentLeft | TableAlignmentRight)
- )
- func (a CellAlignFlags) String() string {
- switch a {
- case TableAlignmentLeft:
- return "left"
- case TableAlignmentRight:
- return "right"
- case TableAlignmentCenter:
- return "center"
- default:
- return ""
- }
- }
- // DocumentMatters holds the type of a {front,main,back}matter in the document
- type DocumentMatters int
- // These are all possible Document divisions.
- const (
- DocumentMatterNone DocumentMatters = iota
- DocumentMatterFront
- DocumentMatterMain
- DocumentMatterBack
- )
- // CitationTypes holds the type of a citation, informative, normative or suppressed
- type CitationTypes int
- const (
- CitationTypeNone CitationTypes = iota
- CitationTypeSuppressed
- CitationTypeInformative
- CitationTypeNormative
- )
- // Node defines an ast node
- type Node interface {
- AsContainer() *Container
- AsLeaf() *Leaf
- GetParent() Node
- SetParent(newParent Node)
- GetChildren() []Node
- SetChildren(newChildren []Node)
- }
- // Container is a type of node that can contain children
- type Container struct {
- Parent Node
- Children []Node
- Literal []byte // Text contents of the leaf nodes
- Content []byte // Markdown content of the block nodes
- *Attribute // Block level attribute
- }
- // return true if can contain children of a given node type
- // used by custom nodes to over-ride logic in canNodeContain
- type CanContain interface {
- CanContain(Node) bool
- }
- // AsContainer returns itself as *Container
- func (c *Container) AsContainer() *Container {
- return c
- }
- // AsLeaf returns nil
- func (c *Container) AsLeaf() *Leaf {
- return nil
- }
- // GetParent returns parent node
- func (c *Container) GetParent() Node {
- return c.Parent
- }
- // SetParent sets the parent node
- func (c *Container) SetParent(newParent Node) {
- c.Parent = newParent
- }
- // GetChildren returns children nodes
- func (c *Container) GetChildren() []Node {
- return c.Children
- }
- // SetChildren sets children node
- func (c *Container) SetChildren(newChildren []Node) {
- c.Children = newChildren
- }
- // Leaf is a type of node that cannot have children
- type Leaf struct {
- Parent Node
- Literal []byte // Text contents of the leaf nodes
- Content []byte // Markdown content of the block nodes
- *Attribute // Block level attribute
- }
- // AsContainer returns nil
- func (l *Leaf) AsContainer() *Container {
- return nil
- }
- // AsLeaf returns itself as *Leaf
- func (l *Leaf) AsLeaf() *Leaf {
- return l
- }
- // GetParent returns parent node
- func (l *Leaf) GetParent() Node {
- return l.Parent
- }
- // SetParent sets the parent nodd
- func (l *Leaf) SetParent(newParent Node) {
- l.Parent = newParent
- }
- // GetChildren returns nil because Leaf cannot have children
- func (l *Leaf) GetChildren() []Node {
- return nil
- }
- // SetChildren will panic if trying to set non-empty children
- // because Leaf cannot have children
- func (l *Leaf) SetChildren(newChildren []Node) {
- if len(newChildren) != 0 {
- panic("leaf node cannot have children")
- }
- }
- // Document represents markdown document node, a root of ast
- type Document struct {
- Container
- }
- // DocumentMatter represents markdown node that signals a document
- // division: frontmatter, mainmatter or backmatter.
- type DocumentMatter struct {
- Container
- Matter DocumentMatters
- }
- // BlockQuote represents markdown block quote node
- type BlockQuote struct {
- Container
- }
- // Aside represents an markdown aside node.
- type Aside struct {
- Container
- }
- // List represents markdown list node
- type List struct {
- Container
- ListFlags ListType
- Tight bool // Skip <p>s around list item data if true
- BulletChar byte // '*', '+' or '-' in bullet lists
- Delimiter byte // '.' or ')' after the number in ordered lists
- Start int // for ordered lists this indicates the starting number if > 0
- RefLink []byte // If not nil, turns this list item into a footnote item and triggers different rendering
- IsFootnotesList bool // This is a list of footnotes
- }
- // ListItem represents markdown list item node
- type ListItem struct {
- Container
- ListFlags ListType
- Tight bool // Skip <p>s around list item data if true
- BulletChar byte // '*', '+' or '-' in bullet lists
- Delimiter byte // '.' or ')' after the number in ordered lists
- RefLink []byte // If not nil, turns this list item into a footnote item and triggers different rendering
- IsFootnotesList bool // This is a list of footnotes
- }
- // Paragraph represents markdown paragraph node
- type Paragraph struct {
- Container
- }
- // Math represents markdown MathAjax inline node
- type Math struct {
- Leaf
- }
- // MathBlock represents markdown MathAjax block node
- type MathBlock struct {
- Container
- }
- // Heading represents markdown heading node
- type Heading struct {
- Container
- Level int // This holds the heading level number
- HeadingID string // This might hold heading ID, if present
- IsTitleblock bool // Specifies whether it's a title block
- IsSpecial bool // We are a special heading (starts with .#)
- }
- // HorizontalRule represents markdown horizontal rule node
- type HorizontalRule struct {
- Leaf
- }
- // Emph represents markdown emphasis node
- type Emph struct {
- Container
- }
- // Strong represents markdown strong node
- type Strong struct {
- Container
- }
- // Del represents markdown del node
- type Del struct {
- Container
- }
- // Link represents markdown link node
- type Link struct {
- Container
- Destination []byte // Destination is what goes into a href
- Title []byte // Title is the tooltip thing that goes in a title attribute
- NoteID int // NoteID contains a serial number of a footnote, zero if it's not a footnote
- Footnote Node // If it's a footnote, this is a direct link to the footnote Node. Otherwise nil.
- DeferredID []byte // If a deferred link this holds the original ID.
- AdditionalAttributes []string // Defines additional attributes to use during rendering.
- }
- // CrossReference is a reference node.
- type CrossReference struct {
- Container
- Destination []byte // Destination is where the reference points to
- Suffix []byte // Potential citation suffix, i.e. (#myid, text)
- }
- // Citation is a citation node.
- type Citation struct {
- Leaf
- Destination [][]byte // Destination is where the citation points to. Multiple ones are allowed.
- Type []CitationTypes // 1:1 mapping of destination and citation type
- Suffix [][]byte // Potential citation suffix, i.e. [@!RFC1035, p. 144]
- }
- // Image represents markdown image node
- type Image struct {
- Container
- Destination []byte // Destination is what goes into a href
- Title []byte // Title is the tooltip thing that goes in a title attribute
- }
- // Text represents markdown text node
- type Text struct {
- Leaf
- }
- // HTMLBlock represents markdown html node
- type HTMLBlock struct {
- Leaf
- }
- // CodeBlock represents markdown code block node
- type CodeBlock struct {
- Leaf
- IsFenced bool // Specifies whether it's a fenced code block or an indented one
- Info []byte // This holds the info string
- FenceChar byte
- FenceLength int
- FenceOffset int
- }
- // Softbreak represents markdown softbreak node
- // Note: not used currently
- type Softbreak struct {
- Leaf
- }
- // Hardbreak represents markdown hard break node
- type Hardbreak struct {
- Leaf
- }
- // NonBlockingSpace represents markdown non-blocking space node
- type NonBlockingSpace struct {
- Leaf
- }
- // Code represents markdown code node
- type Code struct {
- Leaf
- }
- // HTMLSpan represents markdown html span node
- type HTMLSpan struct {
- Leaf
- }
- // Table represents markdown table node
- type Table struct {
- Container
- }
- // TableCell represents markdown table cell node
- type TableCell struct {
- Container
- IsHeader bool // This tells if it's under the header row
- Align CellAlignFlags // This holds the value for align attribute
- ColSpan int // How many columns to span
- }
- // TableHeader represents markdown table head node
- type TableHeader struct {
- Container
- }
- // TableBody represents markdown table body node
- type TableBody struct {
- Container
- }
- // TableRow represents markdown table row node
- type TableRow struct {
- Container
- }
- // TableFooter represents markdown table foot node
- type TableFooter struct {
- Container
- }
- // Caption represents a figure, code or quote caption
- type Caption struct {
- Container
- }
- // CaptionFigure is a node (blockquote or codeblock) that has a caption
- type CaptionFigure struct {
- Container
- HeadingID string // This might hold heading ID, if present
- }
- // Callout is a node that can exist both in text (where it is an actual node) and in a code block.
- type Callout struct {
- Leaf
- ID []byte // number of this callout
- }
- // Index is a node that contains an Index item and an optional, subitem.
- type Index struct {
- Leaf
- Primary bool
- Item []byte
- Subitem []byte
- ID string // ID of the index
- }
- // Subscript is a subscript node
- type Subscript struct {
- Leaf
- }
- // Subscript is a superscript node
- type Superscript struct {
- Leaf
- }
- // Footnotes is a node that contains all footnotes
- type Footnotes struct {
- Container
- }
- func removeNodeFromArray(a []Node, node Node) []Node {
- n := len(a)
- for i := 0; i < n; i++ {
- if a[i] == node {
- return append(a[:i], a[i+1:]...)
- }
- }
- return nil
- }
- // AppendChild appends child to children of parent
- // It panics if either node is nil.
- func AppendChild(parent Node, child Node) {
- RemoveFromTree(child)
- child.SetParent(parent)
- newChildren := append(parent.GetChildren(), child)
- parent.SetChildren(newChildren)
- }
- // RemoveFromTree removes this node from tree
- func RemoveFromTree(n Node) {
- if n.GetParent() == nil {
- return
- }
- // important: don't clear n.Children if n has no parent
- // we're called from AppendChild and that might happen on a node
- // that accumulated Children but hasn't been inserted into the tree
- n.SetChildren(nil)
- p := n.GetParent()
- newChildren := removeNodeFromArray(p.GetChildren(), n)
- if newChildren != nil {
- p.SetChildren(newChildren)
- }
- }
- // GetLastChild returns last child of node n
- // It's implemented as stand-alone function to keep Node interface small
- func GetLastChild(n Node) Node {
- a := n.GetChildren()
- if len(a) > 0 {
- return a[len(a)-1]
- }
- return nil
- }
- // GetFirstChild returns first child of node n
- // It's implemented as stand-alone function to keep Node interface small
- func GetFirstChild(n Node) Node {
- a := n.GetChildren()
- if len(a) > 0 {
- return a[0]
- }
- return nil
- }
- // GetNextNode returns next sibling of node n (node after n)
- // We can't make it part of Container or Leaf because we loose Node identity
- func GetNextNode(n Node) Node {
- parent := n.GetParent()
- if parent == nil {
- return nil
- }
- a := parent.GetChildren()
- len := len(a) - 1
- for i := 0; i < len; i++ {
- if a[i] == n {
- return a[i+1]
- }
- }
- return nil
- }
- // GetPrevNode returns previous sibling of node n (node before n)
- // We can't make it part of Container or Leaf because we loose Node identity
- func GetPrevNode(n Node) Node {
- parent := n.GetParent()
- if parent == nil {
- return nil
- }
- a := parent.GetChildren()
- len := len(a)
- for i := 1; i < len; i++ {
- if a[i] == n {
- return a[i-1]
- }
- }
- return nil
- }
- // WalkStatus allows NodeVisitor to have some control over the tree traversal.
- // It is returned from NodeVisitor and different values allow Node.Walk to
- // decide which node to go to next.
- type WalkStatus int
- const (
- // GoToNext is the default traversal of every node.
- GoToNext WalkStatus = iota
- // SkipChildren tells walker to skip all children of current node.
- SkipChildren
- // Terminate tells walker to terminate the traversal.
- Terminate
- )
- // NodeVisitor is a callback to be called when traversing the syntax tree.
- // Called twice for every node: once with entering=true when the branch is
- // first visited, then with entering=false after all the children are done.
- type NodeVisitor interface {
- Visit(node Node, entering bool) WalkStatus
- }
- // NodeVisitorFunc casts a function to match NodeVisitor interface
- type NodeVisitorFunc func(node Node, entering bool) WalkStatus
- // Walk traverses tree recursively
- func Walk(n Node, visitor NodeVisitor) WalkStatus {
- isContainer := n.AsContainer() != nil
- status := visitor.Visit(n, true) // entering
- if status == Terminate {
- // even if terminating, close container node
- if isContainer {
- visitor.Visit(n, false)
- }
- return status
- }
- if isContainer && status != SkipChildren {
- children := n.GetChildren()
- for _, n := range children {
- status = Walk(n, visitor)
- if status == Terminate {
- return status
- }
- }
- }
- if isContainer {
- status = visitor.Visit(n, false) // exiting
- if status == Terminate {
- return status
- }
- }
- return GoToNext
- }
- // Visit calls visitor function
- func (f NodeVisitorFunc) Visit(node Node, entering bool) WalkStatus {
- return f(node, entering)
- }
- // WalkFunc is like Walk but accepts just a callback function
- func WalkFunc(n Node, f NodeVisitorFunc) {
- visitor := NodeVisitorFunc(f)
- Walk(n, visitor)
- }
|