ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/aya/vendor/github.com/russross/blackfriday/v2/node.go
Revision: 1.1
Committed: Mon Sep 30 00:42:06 2024 UTC (6 weeks, 4 days ago) by yakumo_izuru
Branch: MAIN
CVS Tags: HEAD
Log Message:
Mirrored from https://git.chaotic.ninja/git/yakumo_izuru/aya

File Contents

# User Rev Content
1 yakumo_izuru 1.1 package blackfriday
2    
3     import (
4     "bytes"
5     "fmt"
6     )
7    
8     // NodeType specifies a type of a single node of a syntax tree. Usually one
9     // node (and its type) corresponds to a single markdown feature, e.g. emphasis
10     // or code block.
11     type NodeType int
12    
13     // Constants for identifying different types of nodes. See NodeType.
14     const (
15     Document NodeType = iota
16     BlockQuote
17     List
18     Item
19     Paragraph
20     Heading
21     HorizontalRule
22     Emph
23     Strong
24     Del
25     Link
26     Image
27     Text
28     HTMLBlock
29     CodeBlock
30     Softbreak
31     Hardbreak
32     Code
33     HTMLSpan
34     Table
35     TableCell
36     TableHead
37     TableBody
38     TableRow
39     )
40    
41     var nodeTypeNames = []string{
42     Document: "Document",
43     BlockQuote: "BlockQuote",
44     List: "List",
45     Item: "Item",
46     Paragraph: "Paragraph",
47     Heading: "Heading",
48     HorizontalRule: "HorizontalRule",
49     Emph: "Emph",
50     Strong: "Strong",
51     Del: "Del",
52     Link: "Link",
53     Image: "Image",
54     Text: "Text",
55     HTMLBlock: "HTMLBlock",
56     CodeBlock: "CodeBlock",
57     Softbreak: "Softbreak",
58     Hardbreak: "Hardbreak",
59     Code: "Code",
60     HTMLSpan: "HTMLSpan",
61     Table: "Table",
62     TableCell: "TableCell",
63     TableHead: "TableHead",
64     TableBody: "TableBody",
65     TableRow: "TableRow",
66     }
67    
68     func (t NodeType) String() string {
69     return nodeTypeNames[t]
70     }
71    
72     // ListData contains fields relevant to a List and Item node type.
73     type ListData struct {
74     ListFlags ListType
75     Tight bool // Skip <p>s around list item data if true
76     BulletChar byte // '*', '+' or '-' in bullet lists
77     Delimiter byte // '.' or ')' after the number in ordered lists
78     RefLink []byte // If not nil, turns this list item into a footnote item and triggers different rendering
79     IsFootnotesList bool // This is a list of footnotes
80     }
81    
82     // LinkData contains fields relevant to a Link node type.
83     type LinkData struct {
84     Destination []byte // Destination is what goes into a href
85     Title []byte // Title is the tooltip thing that goes in a title attribute
86     NoteID int // NoteID contains a serial number of a footnote, zero if it's not a footnote
87     Footnote *Node // If it's a footnote, this is a direct link to the footnote Node. Otherwise nil.
88     }
89    
90     // CodeBlockData contains fields relevant to a CodeBlock node type.
91     type CodeBlockData struct {
92     IsFenced bool // Specifies whether it's a fenced code block or an indented one
93     Info []byte // This holds the info string
94     FenceChar byte
95     FenceLength int
96     FenceOffset int
97     }
98    
99     // TableCellData contains fields relevant to a TableCell node type.
100     type TableCellData struct {
101     IsHeader bool // This tells if it's under the header row
102     Align CellAlignFlags // This holds the value for align attribute
103     }
104    
105     // HeadingData contains fields relevant to a Heading node type.
106     type HeadingData struct {
107     Level int // This holds the heading level number
108     HeadingID string // This might hold heading ID, if present
109     IsTitleblock bool // Specifies whether it's a title block
110     }
111    
112     // Node is a single element in the abstract syntax tree of the parsed document.
113     // It holds connections to the structurally neighboring nodes and, for certain
114     // types of nodes, additional information that might be needed when rendering.
115     type Node struct {
116     Type NodeType // Determines the type of the node
117     Parent *Node // Points to the parent
118     FirstChild *Node // Points to the first child, if any
119     LastChild *Node // Points to the last child, if any
120     Prev *Node // Previous sibling; nil if it's the first child
121     Next *Node // Next sibling; nil if it's the last child
122    
123     Literal []byte // Text contents of the leaf nodes
124    
125     HeadingData // Populated if Type is Heading
126     ListData // Populated if Type is List
127     CodeBlockData // Populated if Type is CodeBlock
128     LinkData // Populated if Type is Link
129     TableCellData // Populated if Type is TableCell
130    
131     content []byte // Markdown content of the block nodes
132     open bool // Specifies an open block node that has not been finished to process yet
133     }
134    
135     // NewNode allocates a node of a specified type.
136     func NewNode(typ NodeType) *Node {
137     return &Node{
138     Type: typ,
139     open: true,
140     }
141     }
142    
143     func (n *Node) String() string {
144     ellipsis := ""
145     snippet := n.Literal
146     if len(snippet) > 16 {
147     snippet = snippet[:16]
148     ellipsis = "..."
149     }
150     return fmt.Sprintf("%s: '%s%s'", n.Type, snippet, ellipsis)
151     }
152    
153     // Unlink removes node 'n' from the tree.
154     // It panics if the node is nil.
155     func (n *Node) Unlink() {
156     if n.Prev != nil {
157     n.Prev.Next = n.Next
158     } else if n.Parent != nil {
159     n.Parent.FirstChild = n.Next
160     }
161     if n.Next != nil {
162     n.Next.Prev = n.Prev
163     } else if n.Parent != nil {
164     n.Parent.LastChild = n.Prev
165     }
166     n.Parent = nil
167     n.Next = nil
168     n.Prev = nil
169     }
170    
171     // AppendChild adds a node 'child' as a child of 'n'.
172     // It panics if either node is nil.
173     func (n *Node) AppendChild(child *Node) {
174     child.Unlink()
175     child.Parent = n
176     if n.LastChild != nil {
177     n.LastChild.Next = child
178     child.Prev = n.LastChild
179     n.LastChild = child
180     } else {
181     n.FirstChild = child
182     n.LastChild = child
183     }
184     }
185    
186     // InsertBefore inserts 'sibling' immediately before 'n'.
187     // It panics if either node is nil.
188     func (n *Node) InsertBefore(sibling *Node) {
189     sibling.Unlink()
190     sibling.Prev = n.Prev
191     if sibling.Prev != nil {
192     sibling.Prev.Next = sibling
193     }
194     sibling.Next = n
195     n.Prev = sibling
196     sibling.Parent = n.Parent
197     if sibling.Prev == nil {
198     sibling.Parent.FirstChild = sibling
199     }
200     }
201    
202     // IsContainer returns true if 'n' can contain children.
203     func (n *Node) IsContainer() bool {
204     switch n.Type {
205     case Document:
206     fallthrough
207     case BlockQuote:
208     fallthrough
209     case List:
210     fallthrough
211     case Item:
212     fallthrough
213     case Paragraph:
214     fallthrough
215     case Heading:
216     fallthrough
217     case Emph:
218     fallthrough
219     case Strong:
220     fallthrough
221     case Del:
222     fallthrough
223     case Link:
224     fallthrough
225     case Image:
226     fallthrough
227     case Table:
228     fallthrough
229     case TableHead:
230     fallthrough
231     case TableBody:
232     fallthrough
233     case TableRow:
234     fallthrough
235     case TableCell:
236     return true
237     default:
238     return false
239     }
240     }
241    
242     // IsLeaf returns true if 'n' is a leaf node.
243     func (n *Node) IsLeaf() bool {
244     return !n.IsContainer()
245     }
246    
247     func (n *Node) canContain(t NodeType) bool {
248     if n.Type == List {
249     return t == Item
250     }
251     if n.Type == Document || n.Type == BlockQuote || n.Type == Item {
252     return t != Item
253     }
254     if n.Type == Table {
255     return t == TableHead || t == TableBody
256     }
257     if n.Type == TableHead || n.Type == TableBody {
258     return t == TableRow
259     }
260     if n.Type == TableRow {
261     return t == TableCell
262     }
263     return false
264     }
265    
266     // WalkStatus allows NodeVisitor to have some control over the tree traversal.
267     // It is returned from NodeVisitor and different values allow Node.Walk to
268     // decide which node to go to next.
269     type WalkStatus int
270    
271     const (
272     // GoToNext is the default traversal of every node.
273     GoToNext WalkStatus = iota
274     // SkipChildren tells walker to skip all children of current node.
275     SkipChildren
276     // Terminate tells walker to terminate the traversal.
277     Terminate
278     )
279    
280     // NodeVisitor is a callback to be called when traversing the syntax tree.
281     // Called twice for every node: once with entering=true when the branch is
282     // first visited, then with entering=false after all the children are done.
283     type NodeVisitor func(node *Node, entering bool) WalkStatus
284    
285     // Walk is a convenience method that instantiates a walker and starts a
286     // traversal of subtree rooted at n.
287     func (n *Node) Walk(visitor NodeVisitor) {
288     w := newNodeWalker(n)
289     for w.current != nil {
290     status := visitor(w.current, w.entering)
291     switch status {
292     case GoToNext:
293     w.next()
294     case SkipChildren:
295     w.entering = false
296     w.next()
297     case Terminate:
298     return
299     }
300     }
301     }
302    
303     type nodeWalker struct {
304     current *Node
305     root *Node
306     entering bool
307     }
308    
309     func newNodeWalker(root *Node) *nodeWalker {
310     return &nodeWalker{
311     current: root,
312     root: root,
313     entering: true,
314     }
315     }
316    
317     func (nw *nodeWalker) next() {
318     if (!nw.current.IsContainer() || !nw.entering) && nw.current == nw.root {
319     nw.current = nil
320     return
321     }
322     if nw.entering && nw.current.IsContainer() {
323     if nw.current.FirstChild != nil {
324     nw.current = nw.current.FirstChild
325     nw.entering = true
326     } else {
327     nw.entering = false
328     }
329     } else if nw.current.Next == nil {
330     nw.current = nw.current.Parent
331     nw.entering = false
332     } else {
333     nw.current = nw.current.Next
334     nw.entering = true
335     }
336     }
337    
338     func dump(ast *Node) {
339     fmt.Println(dumpString(ast))
340     }
341    
342     func dumpR(ast *Node, depth int) string {
343     if ast == nil {
344     return ""
345     }
346     indent := bytes.Repeat([]byte("\t"), depth)
347     content := ast.Literal
348     if content == nil {
349     content = ast.content
350     }
351     result := fmt.Sprintf("%s%s(%q)\n", indent, ast.Type, content)
352     for n := ast.FirstChild; n != nil; n = n.Next {
353     result += dumpR(n, depth+1)
354     }
355     return result
356     }
357    
358     func dumpString(ast *Node) string {
359     return dumpR(ast, 0)
360     }