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 || source[n.Segment.Stop-1] == '\n' || t.IsRaw() != n.IsRaw() {
136 return false
137 }
138 n.Segment.Stop = t.Segment.Stop
139 n.SetSoftLineBreak(t.SoftLineBreak())
140 n.SetHardLineBreak(t.HardLineBreak())
141 return true
142 }
143
144
145 func (n *Text) Text(source []byte) []byte {
146 return n.Segment.Value(source)
147 }
148
149
150 func (n *Text) Dump(source []byte, level int) {
151 fs := textFlagsString(n.flags)
152 if len(fs) != 0 {
153 fs = "(" + fs + ")"
154 }
155 fmt.Printf("%sText%s: \"%s\"\n", strings.Repeat(" ", level), fs, strings.TrimRight(string(n.Text(source)), "\n"))
156 }
157
158
159 var KindText = NewNodeKind("Text")
160
161
162 func (n *Text) Kind() NodeKind {
163 return KindText
164 }
165
166
167 func NewText() *Text {
168 return &Text{
169 BaseInline: BaseInline{},
170 }
171 }
172
173
174 func NewTextSegment(v textm.Segment) *Text {
175 return &Text{
176 BaseInline: BaseInline{},
177 Segment: v,
178 }
179 }
180
181
182
183 func NewRawTextSegment(v textm.Segment) *Text {
184 t := &Text{
185 BaseInline: BaseInline{},
186 Segment: v,
187 }
188 t.SetRaw(true)
189 return t
190 }
191
192
193
194
195 func MergeOrAppendTextSegment(parent Node, s textm.Segment) {
196 last := parent.LastChild()
197 t, ok := last.(*Text)
198 if ok && t.Segment.Stop == s.Start && !t.SoftLineBreak() {
199 t.Segment = t.Segment.WithStop(s.Stop)
200 } else {
201 parent.AppendChild(parent, NewTextSegment(s))
202 }
203 }
204
205
206
207 func MergeOrReplaceTextSegment(parent Node, n Node, s textm.Segment) {
208 prev := n.PreviousSibling()
209 if t, ok := prev.(*Text); ok && t.Segment.Stop == s.Start && !t.SoftLineBreak() {
210 t.Segment = t.Segment.WithStop(s.Stop)
211 parent.RemoveChild(parent, n)
212 } else {
213 parent.ReplaceChild(parent, n, NewTextSegment(s))
214 }
215 }
216
217
218 type String struct {
219 BaseInline
220
221 Value []byte
222 flags uint8
223 }
224
225
226 func (n *String) Inline() {
227 }
228
229
230
231 func (n *String) IsRaw() bool {
232 return n.flags&textRaw != 0
233 }
234
235
236 func (n *String) SetRaw(v bool) {
237 if v {
238 n.flags |= textRaw
239 } else {
240 n.flags = n.flags &^ textRaw
241 }
242 }
243
244
245
246 func (n *String) IsCode() bool {
247 return n.flags&textCode != 0
248 }
249
250
251 func (n *String) SetCode(v bool) {
252 if v {
253 n.flags |= textCode
254 } else {
255 n.flags = n.flags &^ textCode
256 }
257 }
258
259
260 func (n *String) Text(source []byte) []byte {
261 return n.Value
262 }
263
264
265 func (n *String) Dump(source []byte, level int) {
266 fs := textFlagsString(n.flags)
267 if len(fs) != 0 {
268 fs = "(" + fs + ")"
269 }
270 fmt.Printf("%sString%s: \"%s\"\n", strings.Repeat(" ", level), fs, strings.TrimRight(string(n.Value), "\n"))
271 }
272
273
274 var KindString = NewNodeKind("String")
275
276
277 func (n *String) Kind() NodeKind {
278 return KindString
279 }
280
281
282 func NewString(v []byte) *String {
283 return &String{
284 Value: v,
285 }
286 }
287
288
289 type CodeSpan struct {
290 BaseInline
291 }
292
293
294 func (n *CodeSpan) Inline() {
295 }
296
297
298 func (n *CodeSpan) IsBlank(source []byte) bool {
299 for c := n.FirstChild(); c != nil; c = c.NextSibling() {
300 text := c.(*Text).Segment
301 if !util.IsBlank(text.Value(source)) {
302 return false
303 }
304 }
305 return true
306 }
307
308
309 func (n *CodeSpan) Dump(source []byte, level int) {
310 DumpHelper(n, source, level, nil, nil)
311 }
312
313
314 var KindCodeSpan = NewNodeKind("CodeSpan")
315
316
317 func (n *CodeSpan) Kind() NodeKind {
318 return KindCodeSpan
319 }
320
321
322 func NewCodeSpan() *CodeSpan {
323 return &CodeSpan{
324 BaseInline: BaseInline{},
325 }
326 }
327
328
329 type Emphasis struct {
330 BaseInline
331
332
333 Level int
334 }
335
336
337 func (n *Emphasis) Dump(source []byte, level int) {
338 m := map[string]string{
339 "Level": fmt.Sprintf("%v", n.Level),
340 }
341 DumpHelper(n, source, level, m, nil)
342 }
343
344
345 var KindEmphasis = NewNodeKind("Emphasis")
346
347
348 func (n *Emphasis) Kind() NodeKind {
349 return KindEmphasis
350 }
351
352
353 func NewEmphasis(level int) *Emphasis {
354 return &Emphasis{
355 BaseInline: BaseInline{},
356 Level: level,
357 }
358 }
359
360 type baseLink struct {
361 BaseInline
362
363
364 Destination []byte
365
366
367 Title []byte
368 }
369
370
371 func (n *baseLink) Inline() {
372 }
373
374
375 type Link struct {
376 baseLink
377 }
378
379
380 func (n *Link) Dump(source []byte, level int) {
381 m := map[string]string{}
382 m["Destination"] = string(n.Destination)
383 m["Title"] = string(n.Title)
384 DumpHelper(n, source, level, m, nil)
385 }
386
387
388 var KindLink = NewNodeKind("Link")
389
390
391 func (n *Link) Kind() NodeKind {
392 return KindLink
393 }
394
395
396 func NewLink() *Link {
397 c := &Link{
398 baseLink: baseLink{
399 BaseInline: BaseInline{},
400 },
401 }
402 return c
403 }
404
405
406 type Image struct {
407 baseLink
408 }
409
410
411 func (n *Image) Dump(source []byte, level int) {
412 m := map[string]string{}
413 m["Destination"] = string(n.Destination)
414 m["Title"] = string(n.Title)
415 DumpHelper(n, source, level, m, nil)
416 }
417
418
419 var KindImage = NewNodeKind("Image")
420
421
422 func (n *Image) Kind() NodeKind {
423 return KindImage
424 }
425
426
427 func NewImage(link *Link) *Image {
428 c := &Image{
429 baseLink: baseLink{
430 BaseInline: BaseInline{},
431 },
432 }
433 c.Destination = link.Destination
434 c.Title = link.Title
435 for n := link.FirstChild(); n != nil; {
436 next := n.NextSibling()
437 link.RemoveChild(link, n)
438 c.AppendChild(c, n)
439 n = next
440 }
441
442 return c
443 }
444
445
446 type AutoLinkType int
447
448 const (
449
450 AutoLinkEmail AutoLinkType = iota + 1
451
452 AutoLinkURL
453 )
454
455
456 type AutoLink struct {
457 BaseInline
458
459 AutoLinkType AutoLinkType
460
461
462 Protocol []byte
463
464 value *Text
465 }
466
467
468 func (n *AutoLink) Inline() {}
469
470
471 func (n *AutoLink) Dump(source []byte, level int) {
472 segment := n.value.Segment
473 m := map[string]string{
474 "Value": string(segment.Value(source)),
475 }
476 DumpHelper(n, source, level, m, nil)
477 }
478
479
480 var KindAutoLink = NewNodeKind("AutoLink")
481
482
483 func (n *AutoLink) Kind() NodeKind {
484 return KindAutoLink
485 }
486
487
488 func (n *AutoLink) URL(source []byte) []byte {
489 if n.Protocol != nil {
490 s := n.value.Segment
491 ret := make([]byte, 0, len(n.Protocol)+s.Len()+3)
492 ret = append(ret, n.Protocol...)
493 ret = append(ret, ':', '/', '/')
494 ret = append(ret, n.value.Text(source)...)
495 return ret
496 }
497 return n.value.Text(source)
498 }
499
500
501 func (n *AutoLink) Label(source []byte) []byte {
502 return n.value.Text(source)
503 }
504
505
506 func NewAutoLink(typ AutoLinkType, value *Text) *AutoLink {
507 return &AutoLink{
508 BaseInline: BaseInline{},
509 value: value,
510 AutoLinkType: typ,
511 }
512 }
513
514
515 type RawHTML struct {
516 BaseInline
517 Segments *textm.Segments
518 }
519
520
521 func (n *RawHTML) Inline() {}
522
523
524 func (n *RawHTML) Dump(source []byte, level int) {
525 m := map[string]string{}
526 t := []string{}
527 for i := 0; i < n.Segments.Len(); i++ {
528 segment := n.Segments.At(i)
529 t = append(t, string(segment.Value(source)))
530 }
531 m["RawText"] = strings.Join(t, "")
532 DumpHelper(n, source, level, m, nil)
533 }
534
535
536 var KindRawHTML = NewNodeKind("RawHTML")
537
538
539 func (n *RawHTML) Kind() NodeKind {
540 return KindRawHTML
541 }
542
543
544 func NewRawHTML() *RawHTML {
545 return &RawHTML{
546 Segments: textm.NewSegments(),
547 }
548 }
549
View as plain text