gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

inline.go (12686B)


      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 // A BaseInline struct implements the Node interface partialliy.
     12 type BaseInline struct {
     13 	BaseNode
     14 }
     15 
     16 // Type implements Node.Type
     17 func (b *BaseInline) Type() NodeType {
     18 	return TypeInline
     19 }
     20 
     21 // IsRaw implements Node.IsRaw
     22 func (b *BaseInline) IsRaw() bool {
     23 	return false
     24 }
     25 
     26 // HasBlankPreviousLines implements Node.HasBlankPreviousLines.
     27 func (b *BaseInline) HasBlankPreviousLines() bool {
     28 	panic("can not call with inline nodes.")
     29 }
     30 
     31 // SetBlankPreviousLines implements Node.SetBlankPreviousLines.
     32 func (b *BaseInline) SetBlankPreviousLines(v bool) {
     33 	panic("can not call with inline nodes.")
     34 }
     35 
     36 // Lines implements Node.Lines
     37 func (b *BaseInline) Lines() *textm.Segments {
     38 	panic("can not call with inline nodes.")
     39 }
     40 
     41 // SetLines implements Node.SetLines
     42 func (b *BaseInline) SetLines(v *textm.Segments) {
     43 	panic("can not call with inline nodes.")
     44 }
     45 
     46 // A Text struct represents a textual content of the Markdown text.
     47 type Text struct {
     48 	BaseInline
     49 	// Segment is a position in a source text.
     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 // Inline implements Inline.Inline.
     80 func (n *Text) Inline() {
     81 }
     82 
     83 // SoftLineBreak returns true if this node ends with a new line,
     84 // otherwise false.
     85 func (n *Text) SoftLineBreak() bool {
     86 	return n.flags&textSoftLineBreak != 0
     87 }
     88 
     89 // SetSoftLineBreak sets whether this node ends with a new line.
     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 // IsRaw returns true if this text should be rendered without unescaping
     99 // back slash escapes and resolving references.
    100 func (n *Text) IsRaw() bool {
    101 	return n.flags&textRaw != 0
    102 }
    103 
    104 // SetRaw sets whether this text should be rendered as raw contents.
    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 // HardLineBreak returns true if this node ends with a hard line break.
    114 // See https://spec.commonmark.org/0.30/#hard-line-breaks for details.
    115 func (n *Text) HardLineBreak() bool {
    116 	return n.flags&textHardLineBreak != 0
    117 }
    118 
    119 // SetHardLineBreak sets whether this node ends with a hard line break.
    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 // Merge merges a Node n into this node.
    129 // Merge returns true if the given node has been merged, otherwise false.
    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 // Text implements Node.Text.
    145 func (n *Text) Text(source []byte) []byte {
    146 	return n.Segment.Value(source)
    147 }
    148 
    149 // Dump implements Node.Dump.
    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 // KindText is a NodeKind of the Text node.
    159 var KindText = NewNodeKind("Text")
    160 
    161 // Kind implements Node.Kind.
    162 func (n *Text) Kind() NodeKind {
    163 	return KindText
    164 }
    165 
    166 // NewText returns a new Text node.
    167 func NewText() *Text {
    168 	return &Text{
    169 		BaseInline: BaseInline{},
    170 	}
    171 }
    172 
    173 // NewTextSegment returns a new Text node with the given source position.
    174 func NewTextSegment(v textm.Segment) *Text {
    175 	return &Text{
    176 		BaseInline: BaseInline{},
    177 		Segment:    v,
    178 	}
    179 }
    180 
    181 // NewRawTextSegment returns a new Text node with the given source position.
    182 // The new node should be rendered as raw contents.
    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 // MergeOrAppendTextSegment merges a given s into the last child of the parent if
    193 // it can be merged, otherwise creates a new Text node and appends it to after current
    194 // last child.
    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 // MergeOrReplaceTextSegment merges a given s into a previous sibling of the node n
    206 // if a previous sibling of the node n is *Text, otherwise replaces Node n with s.
    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 // A String struct is a textual content that has a concrete value
    218 type String struct {
    219 	BaseInline
    220 
    221 	Value []byte
    222 	flags uint8
    223 }
    224 
    225 // Inline implements Inline.Inline.
    226 func (n *String) Inline() {
    227 }
    228 
    229 // IsRaw returns true if this text should be rendered without unescaping
    230 // back slash escapes and resolving references.
    231 func (n *String) IsRaw() bool {
    232 	return n.flags&textRaw != 0
    233 }
    234 
    235 // SetRaw sets whether this text should be rendered as raw contents.
    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 // IsCode returns true if this text should be rendered without any
    245 // modifications.
    246 func (n *String) IsCode() bool {
    247 	return n.flags&textCode != 0
    248 }
    249 
    250 // SetCode sets whether this text should be rendered without any modifications.
    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 // Text implements Node.Text.
    260 func (n *String) Text(source []byte) []byte {
    261 	return n.Value
    262 }
    263 
    264 // Dump implements Node.Dump.
    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 // KindString is a NodeKind of the String node.
    274 var KindString = NewNodeKind("String")
    275 
    276 // Kind implements Node.Kind.
    277 func (n *String) Kind() NodeKind {
    278 	return KindString
    279 }
    280 
    281 // NewString returns a new String node.
    282 func NewString(v []byte) *String {
    283 	return &String{
    284 		Value: v,
    285 	}
    286 }
    287 
    288 // A CodeSpan struct represents a code span of Markdown text.
    289 type CodeSpan struct {
    290 	BaseInline
    291 }
    292 
    293 // Inline implements Inline.Inline .
    294 func (n *CodeSpan) Inline() {
    295 }
    296 
    297 // IsBlank returns true if this node consists of spaces, otherwise false.
    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 // Dump implements Node.Dump
    309 func (n *CodeSpan) Dump(source []byte, level int) {
    310 	DumpHelper(n, source, level, nil, nil)
    311 }
    312 
    313 // KindCodeSpan is a NodeKind of the CodeSpan node.
    314 var KindCodeSpan = NewNodeKind("CodeSpan")
    315 
    316 // Kind implements Node.Kind.
    317 func (n *CodeSpan) Kind() NodeKind {
    318 	return KindCodeSpan
    319 }
    320 
    321 // NewCodeSpan returns a new CodeSpan node.
    322 func NewCodeSpan() *CodeSpan {
    323 	return &CodeSpan{
    324 		BaseInline: BaseInline{},
    325 	}
    326 }
    327 
    328 // An Emphasis struct represents an emphasis of Markdown text.
    329 type Emphasis struct {
    330 	BaseInline
    331 
    332 	// Level is a level of the emphasis.
    333 	Level int
    334 }
    335 
    336 // Dump implements Node.Dump.
    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 // KindEmphasis is a NodeKind of the Emphasis node.
    345 var KindEmphasis = NewNodeKind("Emphasis")
    346 
    347 // Kind implements Node.Kind.
    348 func (n *Emphasis) Kind() NodeKind {
    349 	return KindEmphasis
    350 }
    351 
    352 // NewEmphasis returns a new Emphasis node with the given level.
    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 	// Destination is a destination(URL) of this link.
    364 	Destination []byte
    365 
    366 	// Title is a title of this link.
    367 	Title []byte
    368 }
    369 
    370 // Inline implements Inline.Inline.
    371 func (n *baseLink) Inline() {
    372 }
    373 
    374 // A Link struct represents a link of the Markdown text.
    375 type Link struct {
    376 	baseLink
    377 }
    378 
    379 // Dump implements Node.Dump.
    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 // KindLink is a NodeKind of the Link node.
    388 var KindLink = NewNodeKind("Link")
    389 
    390 // Kind implements Node.Kind.
    391 func (n *Link) Kind() NodeKind {
    392 	return KindLink
    393 }
    394 
    395 // NewLink returns a new Link node.
    396 func NewLink() *Link {
    397 	c := &Link{
    398 		baseLink: baseLink{
    399 			BaseInline: BaseInline{},
    400 		},
    401 	}
    402 	return c
    403 }
    404 
    405 // An Image struct represents an image of the Markdown text.
    406 type Image struct {
    407 	baseLink
    408 }
    409 
    410 // Dump implements Node.Dump.
    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 // KindImage is a NodeKind of the Image node.
    419 var KindImage = NewNodeKind("Image")
    420 
    421 // Kind implements Node.Kind.
    422 func (n *Image) Kind() NodeKind {
    423 	return KindImage
    424 }
    425 
    426 // NewImage returns a new Image node.
    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 // AutoLinkType defines kind of auto links.
    446 type AutoLinkType int
    447 
    448 const (
    449 	// AutoLinkEmail indicates that an autolink is an email address.
    450 	AutoLinkEmail AutoLinkType = iota + 1
    451 	// AutoLinkURL indicates that an autolink is a generic URL.
    452 	AutoLinkURL
    453 )
    454 
    455 // An AutoLink struct represents an autolink of the Markdown text.
    456 type AutoLink struct {
    457 	BaseInline
    458 	// Type is a type of this autolink.
    459 	AutoLinkType AutoLinkType
    460 
    461 	// Protocol specified a protocol of the link.
    462 	Protocol []byte
    463 
    464 	value *Text
    465 }
    466 
    467 // Inline implements Inline.Inline.
    468 func (n *AutoLink) Inline() {}
    469 
    470 // Dump implements Node.Dump
    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 // KindAutoLink is a NodeKind of the AutoLink node.
    480 var KindAutoLink = NewNodeKind("AutoLink")
    481 
    482 // Kind implements Node.Kind.
    483 func (n *AutoLink) Kind() NodeKind {
    484 	return KindAutoLink
    485 }
    486 
    487 // URL returns an url of this node.
    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 // Label returns a label of this node.
    501 func (n *AutoLink) Label(source []byte) []byte {
    502 	return n.value.Text(source)
    503 }
    504 
    505 // NewAutoLink returns a new AutoLink node.
    506 func NewAutoLink(typ AutoLinkType, value *Text) *AutoLink {
    507 	return &AutoLink{
    508 		BaseInline:   BaseInline{},
    509 		value:        value,
    510 		AutoLinkType: typ,
    511 	}
    512 }
    513 
    514 // A RawHTML struct represents an inline raw HTML of the Markdown text.
    515 type RawHTML struct {
    516 	BaseInline
    517 	Segments *textm.Segments
    518 }
    519 
    520 // Inline implements Inline.Inline.
    521 func (n *RawHTML) Inline() {}
    522 
    523 // Dump implements Node.Dump.
    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 // KindRawHTML is a NodeKind of the RawHTML node.
    536 var KindRawHTML = NewNodeKind("RawHTML")
    537 
    538 // Kind implements Node.Kind.
    539 func (n *RawHTML) Kind() NodeKind {
    540 	return KindRawHTML
    541 }
    542 
    543 // NewRawHTML returns a new RawHTML node.
    544 func NewRawHTML() *RawHTML {
    545 	return &RawHTML{
    546 		Segments: textm.NewSegments(),
    547 	}
    548 }