1 package ast
2
3 import (
4 "fmt"
5 "strings"
6
7 textm "github.com/yuin/goldmark/text"
8 "github.com/yuin/goldmark/util"
9 )
10
11
12 type BaseInline struct {
13 BaseNode
14 }
15
16
17 func (b *BaseInline) Type() NodeType {
18 return TypeInline
19 }
20
21
22 func (b *BaseInline) IsRaw() bool {
23 return false
24 }
25
26
27 func (b *BaseInline) HasBlankPreviousLines() bool {
28 panic("can not call with inline nodes.")
29 }
30
31
32 func (b *BaseInline) SetBlankPreviousLines(v bool) {
33 panic("can not call with inline nodes.")
34 }
35
36
37 func (b *BaseInline) Lines() *textm.Segments {
38 panic("can not call with inline nodes.")
39 }
40
41
42 func (b *BaseInline) SetLines(v *textm.Segments) {
43 panic("can not call with inline nodes.")
44 }
45
46
47 type Text struct {
48 BaseInline
49
50 Segment textm.Segment
51
52 flags uint8
53 }
54
55 const (
56 textSoftLineBreak = 1 << iota
57 textHardLineBreak
58 textRaw
59 textCode
60 )
61
62 func textFlagsString(flags uint8) string {
63 buf := []string{}
64 if flags&textSoftLineBreak != 0 {
65 buf = append(buf, "SoftLineBreak")
66 }
67 if flags&textHardLineBreak != 0 {
68 buf = append(buf, "HardLineBreak")
69 }
70 if flags&textRaw != 0 {
71 buf = append(buf, "Raw")
72 }
73 if flags&textCode != 0 {
74 buf = append(buf, "Code")
75 }
76 return strings.Join(buf, ", ")
77 }
78
79
80 func (n *Text) Inline() {
81 }
82
83
84
85 func (n *Text) SoftLineBreak() bool {
86 return n.flags&textSoftLineBreak != 0
87 }
88
89
90 func (n *Text) SetSoftLineBreak(v bool) {
91 if v {
92 n.flags |= textSoftLineBreak
93 } else {
94 n.flags = n.flags &^ textSoftLineBreak
95 }
96 }
97
98
99
100 func (n *Text) IsRaw() bool {
101 return n.flags&textRaw != 0
102 }
103
104
105 func (n *Text) SetRaw(v bool) {
106 if v {
107 n.flags |= textRaw
108 } else {
109 n.flags = n.flags &^ textRaw
110 }
111 }
112
113
114
115 func (n *Text) HardLineBreak() bool {
116 return n.flags&textHardLineBreak != 0
117 }
118
119
120 func (n *Text) SetHardLineBreak(v bool) {
121 if v {
122 n.flags |= textHardLineBreak
123 } else {
124 n.flags = n.flags &^ textHardLineBreak
125 }
126 }
127
128
129
130 func (n *Text) Merge(node Node, source []byte) bool {
131 t, ok := node.(*Text)
132 if !ok {
133 return false
134 }
135 if n.Segment.Stop != t.Segment.Start || t.Segment.Padding != 0 ||
136 source[n.Segment.Stop-1] == '\n' || t.IsRaw() != n.IsRaw() {
137 return false
138 }
139 n.Segment.Stop = t.Segment.Stop
140 n.SetSoftLineBreak(t.SoftLineBreak())
141 n.SetHardLineBreak(t.HardLineBreak())
142 return true
143 }
144
145
146 func (n *Text) Text(source []byte) []byte {
147 return n.Segment.Value(source)
148 }
149
150
151 func (n *Text) Dump(source []byte, level int) {
152 fs := textFlagsString(n.flags)
153 if len(fs) != 0 {
154 fs = "(" + fs + ")"
155 }
156 fmt.Printf("%sText%s: \"%s\"\n", strings.Repeat(" ", level), fs, strings.TrimRight(string(n.Text(source)), "\n"))
157 }
158
159
160 var KindText = NewNodeKind("Text")
161
162
163 func (n *Text) Kind() NodeKind {
164 return KindText
165 }
166
167
168 func NewText() *Text {
169 return &Text{
170 BaseInline: BaseInline{},
171 }
172 }
173
174
175 func NewTextSegment(v textm.Segment) *Text {
176 return &Text{
177 BaseInline: BaseInline{},
178 Segment: v,
179 }
180 }
181
182
183
184 func NewRawTextSegment(v textm.Segment) *Text {
185 t := &Text{
186 BaseInline: BaseInline{},
187 Segment: v,
188 }
189 t.SetRaw(true)
190 return t
191 }
192
193
194
195
196 func MergeOrAppendTextSegment(parent Node, s textm.Segment) {
197 last := parent.LastChild()
198 t, ok := last.(*Text)
199 if ok && t.Segment.Stop == s.Start && !t.SoftLineBreak() {
200 t.Segment = t.Segment.WithStop(s.Stop)
201 } else {
202 parent.AppendChild(parent, NewTextSegment(s))
203 }
204 }
205
206
207
208 func MergeOrReplaceTextSegment(parent Node, n Node, s textm.Segment) {
209 prev := n.PreviousSibling()
210 if t, ok := prev.(*Text); ok && t.Segment.Stop == s.Start && !t.SoftLineBreak() {
211 t.Segment = t.Segment.WithStop(s.Stop)
212 parent.RemoveChild(parent, n)
213 } else {
214 parent.ReplaceChild(parent, n, NewTextSegment(s))
215 }
216 }
217
218
219 type String struct {
220 BaseInline
221
222 Value []byte
223 flags uint8
224 }
225
226
227 func (n *String) Inline() {
228 }
229
230
231
232 func (n *String) IsRaw() bool {
233 return n.flags&textRaw != 0
234 }
235
236
237 func (n *String) SetRaw(v bool) {
238 if v {
239 n.flags |= textRaw
240 } else {
241 n.flags = n.flags &^ textRaw
242 }
243 }
244
245
246
247 func (n *String) IsCode() bool {
248 return n.flags&textCode != 0
249 }
250
251
252 func (n *String) SetCode(v bool) {
253 if v {
254 n.flags |= textCode
255 } else {
256 n.flags = n.flags &^ textCode
257 }
258 }
259
260
261 func (n *String) Text(source []byte) []byte {
262 return n.Value
263 }
264
265
266 func (n *String) Dump(source []byte, level int) {
267 fs := textFlagsString(n.flags)
268 if len(fs) != 0 {
269 fs = "(" + fs + ")"
270 }
271 fmt.Printf("%sString%s: \"%s\"\n", strings.Repeat(" ", level), fs, strings.TrimRight(string(n.Value), "\n"))
272 }
273
274
275 var KindString = NewNodeKind("String")
276
277
278 func (n *String) Kind() NodeKind {
279 return KindString
280 }
281
282
283 func NewString(v []byte) *String {
284 return &String{
285 Value: v,
286 }
287 }
288
289
290 type CodeSpan struct {
291 BaseInline
292 }
293
294
295 func (n *CodeSpan) Inline() {
296 }
297
298
299 func (n *CodeSpan) IsBlank(source []byte) bool {
300 for c := n.FirstChild(); c != nil; c = c.NextSibling() {
301 text := c.(*Text).Segment
302 if !util.IsBlank(text.Value(source)) {
303 return false
304 }
305 }
306 return true
307 }
308
309
310 func (n *CodeSpan) Dump(source []byte, level int) {
311 DumpHelper(n, source, level, nil, nil)
312 }
313
314
315 var KindCodeSpan = NewNodeKind("CodeSpan")
316
317
318 func (n *CodeSpan) Kind() NodeKind {
319 return KindCodeSpan
320 }
321
322
323 func NewCodeSpan() *CodeSpan {
324 return &CodeSpan{
325 BaseInline: BaseInline{},
326 }
327 }
328
329
330 type Emphasis struct {
331 BaseInline
332
333
334 Level int
335 }
336
337
338 func (n *Emphasis) Dump(source []byte, level int) {
339 m := map[string]string{
340 "Level": fmt.Sprintf("%v", n.Level),
341 }
342 DumpHelper(n, source, level, m, nil)
343 }
344
345
346 var KindEmphasis = NewNodeKind("Emphasis")
347
348
349 func (n *Emphasis) Kind() NodeKind {
350 return KindEmphasis
351 }
352
353
354 func NewEmphasis(level int) *Emphasis {
355 return &Emphasis{
356 BaseInline: BaseInline{},
357 Level: level,
358 }
359 }
360
361 type baseLink struct {
362 BaseInline
363
364
365 Destination []byte
366
367
368 Title []byte
369 }
370
371
372 func (n *baseLink) Inline() {
373 }
374
375
376 type Link struct {
377 baseLink
378 }
379
380
381 func (n *Link) Dump(source []byte, level int) {
382 m := map[string]string{}
383 m["Destination"] = string(n.Destination)
384 m["Title"] = string(n.Title)
385 DumpHelper(n, source, level, m, nil)
386 }
387
388
389 var KindLink = NewNodeKind("Link")
390
391
392 func (n *Link) Kind() NodeKind {
393 return KindLink
394 }
395
396
397 func NewLink() *Link {
398 c := &Link{
399 baseLink: baseLink{
400 BaseInline: BaseInline{},
401 },
402 }
403 return c
404 }
405
406
407 type Image struct {
408 baseLink
409 }
410
411
412 func (n *Image) Dump(source []byte, level int) {
413 m := map[string]string{}
414 m["Destination"] = string(n.Destination)
415 m["Title"] = string(n.Title)
416 DumpHelper(n, source, level, m, nil)
417 }
418
419
420 var KindImage = NewNodeKind("Image")
421
422
423 func (n *Image) Kind() NodeKind {
424 return KindImage
425 }
426
427
428 func NewImage(link *Link) *Image {
429 c := &Image{
430 baseLink: baseLink{
431 BaseInline: BaseInline{},
432 },
433 }
434 c.Destination = link.Destination
435 c.Title = link.Title
436 for n := link.FirstChild(); n != nil; {
437 next := n.NextSibling()
438 link.RemoveChild(link, n)
439 c.AppendChild(c, n)
440 n = next
441 }
442
443 return c
444 }
445
446
447 type AutoLinkType int
448
449 const (
450
451 AutoLinkEmail AutoLinkType = iota + 1
452
453 AutoLinkURL
454 )
455
456
457 type AutoLink struct {
458 BaseInline
459
460 AutoLinkType AutoLinkType
461
462
463 Protocol []byte
464
465 value *Text
466 }
467
468
469 func (n *AutoLink) Inline() {}
470
471
472 func (n *AutoLink) Dump(source []byte, level int) {
473 segment := n.value.Segment
474 m := map[string]string{
475 "Value": string(segment.Value(source)),
476 }
477 DumpHelper(n, source, level, m, nil)
478 }
479
480
481 var KindAutoLink = NewNodeKind("AutoLink")
482
483
484 func (n *AutoLink) Kind() NodeKind {
485 return KindAutoLink
486 }
487
488
489 func (n *AutoLink) URL(source []byte) []byte {
490 if n.Protocol != nil {
491 s := n.value.Segment
492 ret := make([]byte, 0, len(n.Protocol)+s.Len()+3)
493 ret = append(ret, n.Protocol...)
494 ret = append(ret, ':', '/', '/')
495 ret = append(ret, n.value.Text(source)...)
496 return ret
497 }
498 return n.value.Text(source)
499 }
500
501
502 func (n *AutoLink) Label(source []byte) []byte {
503 return n.value.Text(source)
504 }
505
506
507 func NewAutoLink(typ AutoLinkType, value *Text) *AutoLink {
508 return &AutoLink{
509 BaseInline: BaseInline{},
510 value: value,
511 AutoLinkType: typ,
512 }
513 }
514
515
516 type RawHTML struct {
517 BaseInline
518 Segments *textm.Segments
519 }
520
521
522 func (n *RawHTML) Inline() {}
523
524
525 func (n *RawHTML) Dump(source []byte, level int) {
526 m := map[string]string{}
527 t := []string{}
528 for i := 0; i < n.Segments.Len(); i++ {
529 segment := n.Segments.At(i)
530 t = append(t, string(segment.Value(source)))
531 }
532 m["RawText"] = strings.Join(t, "")
533 DumpHelper(n, source, level, m, nil)
534 }
535
536
537 var KindRawHTML = NewNodeKind("RawHTML")
538
539
540 func (n *RawHTML) Kind() NodeKind {
541 return KindRawHTML
542 }
543
544
545 func NewRawHTML() *RawHTML {
546 return &RawHTML{
547 Segments: textm.NewSegments(),
548 }
549 }
550
View as plain text