1 package ast
2
3 import (
4 "fmt"
5 "strings"
6
7 textm "github.com/yuin/goldmark/text"
8 )
9
10
11 type BaseBlock struct {
12 BaseNode
13 blankPreviousLines bool
14 lines *textm.Segments
15 }
16
17
18 func (b *BaseBlock) Type() NodeType {
19 return TypeBlock
20 }
21
22
23 func (b *BaseBlock) IsRaw() bool {
24 return false
25 }
26
27
28 func (b *BaseBlock) HasBlankPreviousLines() bool {
29 return b.blankPreviousLines
30 }
31
32
33 func (b *BaseBlock) SetBlankPreviousLines(v bool) {
34 b.blankPreviousLines = v
35 }
36
37
38 func (b *BaseBlock) Lines() *textm.Segments {
39 if b.lines == nil {
40 b.lines = textm.NewSegments()
41 }
42 return b.lines
43 }
44
45
46 func (b *BaseBlock) SetLines(v *textm.Segments) {
47 b.lines = v
48 }
49
50
51 type Document struct {
52 BaseBlock
53
54 meta map[string]interface{}
55 }
56
57
58 var KindDocument = NewNodeKind("Document")
59
60
61 func (n *Document) Dump(source []byte, level int) {
62 DumpHelper(n, source, level, nil, nil)
63 }
64
65
66 func (n *Document) Type() NodeType {
67 return TypeDocument
68 }
69
70
71 func (n *Document) Kind() NodeKind {
72 return KindDocument
73 }
74
75
76 func (n *Document) OwnerDocument() *Document {
77 return n
78 }
79
80
81 func (n *Document) Meta() map[string]interface{} {
82 if n.meta == nil {
83 n.meta = map[string]interface{}{}
84 }
85 return n.meta
86 }
87
88
89 func (n *Document) SetMeta(meta map[string]interface{}) {
90 if n.meta == nil {
91 n.meta = map[string]interface{}{}
92 }
93 for k, v := range meta {
94 n.meta[k] = v
95 }
96 }
97
98
99 func (n *Document) AddMeta(key string, value interface{}) {
100 if n.meta == nil {
101 n.meta = map[string]interface{}{}
102 }
103 n.meta[key] = value
104 }
105
106
107 func NewDocument() *Document {
108 return &Document{
109 BaseBlock: BaseBlock{},
110 meta: nil,
111 }
112 }
113
114
115
116 type TextBlock struct {
117 BaseBlock
118 }
119
120
121 func (n *TextBlock) Dump(source []byte, level int) {
122 DumpHelper(n, source, level, nil, nil)
123 }
124
125
126 var KindTextBlock = NewNodeKind("TextBlock")
127
128
129 func (n *TextBlock) Kind() NodeKind {
130 return KindTextBlock
131 }
132
133
134 func NewTextBlock() *TextBlock {
135 return &TextBlock{
136 BaseBlock: BaseBlock{},
137 }
138 }
139
140
141 type Paragraph struct {
142 BaseBlock
143 }
144
145
146 func (n *Paragraph) Dump(source []byte, level int) {
147 DumpHelper(n, source, level, nil, nil)
148 }
149
150
151 var KindParagraph = NewNodeKind("Paragraph")
152
153
154 func (n *Paragraph) Kind() NodeKind {
155 return KindParagraph
156 }
157
158
159 func NewParagraph() *Paragraph {
160 return &Paragraph{
161 BaseBlock: BaseBlock{},
162 }
163 }
164
165
166
167 func IsParagraph(node Node) bool {
168 _, ok := node.(*Paragraph)
169 return ok
170 }
171
172
173 type Heading struct {
174 BaseBlock
175
176
177 Level int
178 }
179
180
181 func (n *Heading) Dump(source []byte, level int) {
182 m := map[string]string{
183 "Level": fmt.Sprintf("%d", n.Level),
184 }
185 DumpHelper(n, source, level, m, nil)
186 }
187
188
189 var KindHeading = NewNodeKind("Heading")
190
191
192 func (n *Heading) Kind() NodeKind {
193 return KindHeading
194 }
195
196
197 func NewHeading(level int) *Heading {
198 return &Heading{
199 BaseBlock: BaseBlock{},
200 Level: level,
201 }
202 }
203
204
205 type ThematicBreak struct {
206 BaseBlock
207 }
208
209
210 func (n *ThematicBreak) Dump(source []byte, level int) {
211 DumpHelper(n, source, level, nil, nil)
212 }
213
214
215 var KindThematicBreak = NewNodeKind("ThematicBreak")
216
217
218 func (n *ThematicBreak) Kind() NodeKind {
219 return KindThematicBreak
220 }
221
222
223 func NewThematicBreak() *ThematicBreak {
224 return &ThematicBreak{
225 BaseBlock: BaseBlock{},
226 }
227 }
228
229
230 type CodeBlock struct {
231 BaseBlock
232 }
233
234
235 func (n *CodeBlock) IsRaw() bool {
236 return true
237 }
238
239
240 func (n *CodeBlock) Dump(source []byte, level int) {
241 DumpHelper(n, source, level, nil, nil)
242 }
243
244
245 var KindCodeBlock = NewNodeKind("CodeBlock")
246
247
248 func (n *CodeBlock) Kind() NodeKind {
249 return KindCodeBlock
250 }
251
252
253 func NewCodeBlock() *CodeBlock {
254 return &CodeBlock{
255 BaseBlock: BaseBlock{},
256 }
257 }
258
259
260 type FencedCodeBlock struct {
261 BaseBlock
262
263 Info *Text
264
265 language []byte
266 }
267
268
269
270 func (n *FencedCodeBlock) Language(source []byte) []byte {
271 if n.language == nil && n.Info != nil {
272 segment := n.Info.Segment
273 info := segment.Value(source)
274 i := 0
275 for ; i < len(info); i++ {
276 if info[i] == ' ' {
277 break
278 }
279 }
280 n.language = info[:i]
281 }
282 return n.language
283 }
284
285
286 func (n *FencedCodeBlock) IsRaw() bool {
287 return true
288 }
289
290
291 func (n *FencedCodeBlock) Dump(source []byte, level int) {
292 m := map[string]string{}
293 if n.Info != nil {
294 m["Info"] = fmt.Sprintf("\"%s\"", n.Info.Text(source))
295 }
296 DumpHelper(n, source, level, m, nil)
297 }
298
299
300 var KindFencedCodeBlock = NewNodeKind("FencedCodeBlock")
301
302
303 func (n *FencedCodeBlock) Kind() NodeKind {
304 return KindFencedCodeBlock
305 }
306
307
308 func NewFencedCodeBlock(info *Text) *FencedCodeBlock {
309 return &FencedCodeBlock{
310 BaseBlock: BaseBlock{},
311 Info: info,
312 }
313 }
314
315
316 type Blockquote struct {
317 BaseBlock
318 }
319
320
321 func (n *Blockquote) Dump(source []byte, level int) {
322 DumpHelper(n, source, level, nil, nil)
323 }
324
325
326 var KindBlockquote = NewNodeKind("Blockquote")
327
328
329 func (n *Blockquote) Kind() NodeKind {
330 return KindBlockquote
331 }
332
333
334 func NewBlockquote() *Blockquote {
335 return &Blockquote{
336 BaseBlock: BaseBlock{},
337 }
338 }
339
340
341 type List struct {
342 BaseBlock
343
344
345 Marker byte
346
347
348
349 IsTight bool
350
351
352
353 Start int
354 }
355
356
357 func (l *List) IsOrdered() bool {
358 return l.Marker == '.' || l.Marker == ')'
359 }
360
361
362
363 func (l *List) CanContinue(marker byte, isOrdered bool) bool {
364 return marker == l.Marker && isOrdered == l.IsOrdered()
365 }
366
367
368 func (l *List) Dump(source []byte, level int) {
369 m := map[string]string{
370 "Ordered": fmt.Sprintf("%v", l.IsOrdered()),
371 "Marker": fmt.Sprintf("%c", l.Marker),
372 "Tight": fmt.Sprintf("%v", l.IsTight),
373 }
374 if l.IsOrdered() {
375 m["Start"] = fmt.Sprintf("%d", l.Start)
376 }
377 DumpHelper(l, source, level, m, nil)
378 }
379
380
381 var KindList = NewNodeKind("List")
382
383
384 func (l *List) Kind() NodeKind {
385 return KindList
386 }
387
388
389 func NewList(marker byte) *List {
390 return &List{
391 BaseBlock: BaseBlock{},
392 Marker: marker,
393 IsTight: true,
394 }
395 }
396
397
398 type ListItem struct {
399 BaseBlock
400
401
402 Offset int
403 }
404
405
406 func (n *ListItem) Dump(source []byte, level int) {
407 m := map[string]string{
408 "Offset": fmt.Sprintf("%d", n.Offset),
409 }
410 DumpHelper(n, source, level, m, nil)
411 }
412
413
414 var KindListItem = NewNodeKind("ListItem")
415
416
417 func (n *ListItem) Kind() NodeKind {
418 return KindListItem
419 }
420
421
422 func NewListItem(offset int) *ListItem {
423 return &ListItem{
424 BaseBlock: BaseBlock{},
425 Offset: offset,
426 }
427 }
428
429
430
431 type HTMLBlockType int
432
433 const (
434
435 HTMLBlockType1 HTMLBlockType = iota + 1
436
437 HTMLBlockType2
438
439 HTMLBlockType3
440
441 HTMLBlockType4
442
443 HTMLBlockType5
444
445 HTMLBlockType6
446
447 HTMLBlockType7
448 )
449
450
451 type HTMLBlock struct {
452 BaseBlock
453
454
455 HTMLBlockType HTMLBlockType
456
457
458 ClosureLine textm.Segment
459 }
460
461
462 func (n *HTMLBlock) IsRaw() bool {
463 return true
464 }
465
466
467
468 func (n *HTMLBlock) HasClosure() bool {
469 return n.ClosureLine.Start >= 0
470 }
471
472
473 func (n *HTMLBlock) Dump(source []byte, level int) {
474 indent := strings.Repeat(" ", level)
475 fmt.Printf("%s%s {\n", indent, "HTMLBlock")
476 indent2 := strings.Repeat(" ", level+1)
477 fmt.Printf("%sRawText: \"", indent2)
478 for i := 0; i < n.Lines().Len(); i++ {
479 s := n.Lines().At(i)
480 fmt.Print(string(source[s.Start:s.Stop]))
481 }
482 fmt.Printf("\"\n")
483 for c := n.FirstChild(); c != nil; c = c.NextSibling() {
484 c.Dump(source, level+1)
485 }
486 if n.HasClosure() {
487 cl := n.ClosureLine
488 fmt.Printf("%sClosure: \"%s\"\n", indent2, string(cl.Value(source)))
489 }
490 fmt.Printf("%s}\n", indent)
491 }
492
493
494 var KindHTMLBlock = NewNodeKind("HTMLBlock")
495
496
497 func (n *HTMLBlock) Kind() NodeKind {
498 return KindHTMLBlock
499 }
500
501
502 func NewHTMLBlock(typ HTMLBlockType) *HTMLBlock {
503 return &HTMLBlock{
504 BaseBlock: BaseBlock{},
505 HTMLBlockType: typ,
506 ClosureLine: textm.NewSegment(-1, -1),
507 }
508 }
509
View as plain text