gtsocial-umbx

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

block.go (11848B)


      1 package ast
      2 
      3 import (
      4 	"fmt"
      5 	"strings"
      6 
      7 	textm "github.com/yuin/goldmark/text"
      8 )
      9 
     10 // A BaseBlock struct implements the Node interface partialliy.
     11 type BaseBlock struct {
     12 	BaseNode
     13 	blankPreviousLines bool
     14 	lines              *textm.Segments
     15 }
     16 
     17 // Type implements Node.Type
     18 func (b *BaseBlock) Type() NodeType {
     19 	return TypeBlock
     20 }
     21 
     22 // IsRaw implements Node.IsRaw
     23 func (b *BaseBlock) IsRaw() bool {
     24 	return false
     25 }
     26 
     27 // HasBlankPreviousLines implements Node.HasBlankPreviousLines.
     28 func (b *BaseBlock) HasBlankPreviousLines() bool {
     29 	return b.blankPreviousLines
     30 }
     31 
     32 // SetBlankPreviousLines implements Node.SetBlankPreviousLines.
     33 func (b *BaseBlock) SetBlankPreviousLines(v bool) {
     34 	b.blankPreviousLines = v
     35 }
     36 
     37 // Lines implements Node.Lines
     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 // SetLines implements Node.SetLines
     46 func (b *BaseBlock) SetLines(v *textm.Segments) {
     47 	b.lines = v
     48 }
     49 
     50 // A Document struct is a root node of Markdown text.
     51 type Document struct {
     52 	BaseBlock
     53 
     54 	meta map[string]interface{}
     55 }
     56 
     57 // KindDocument is a NodeKind of the Document node.
     58 var KindDocument = NewNodeKind("Document")
     59 
     60 // Dump implements Node.Dump .
     61 func (n *Document) Dump(source []byte, level int) {
     62 	DumpHelper(n, source, level, nil, nil)
     63 }
     64 
     65 // Type implements Node.Type .
     66 func (n *Document) Type() NodeType {
     67 	return TypeDocument
     68 }
     69 
     70 // Kind implements Node.Kind.
     71 func (n *Document) Kind() NodeKind {
     72 	return KindDocument
     73 }
     74 
     75 // OwnerDocument implements Node.OwnerDocument
     76 func (n *Document) OwnerDocument() *Document {
     77 	return n
     78 }
     79 
     80 // Meta returns metadata of this document.
     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 // SetMeta sets given metadata to this document.
     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 // AddMeta adds given metadata to this document.
     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 // NewDocument returns a new Document node.
    107 func NewDocument() *Document {
    108 	return &Document{
    109 		BaseBlock: BaseBlock{},
    110 		meta:      nil,
    111 	}
    112 }
    113 
    114 // A TextBlock struct is a node whose lines
    115 // should be rendered without any containers.
    116 type TextBlock struct {
    117 	BaseBlock
    118 }
    119 
    120 // Dump implements Node.Dump .
    121 func (n *TextBlock) Dump(source []byte, level int) {
    122 	DumpHelper(n, source, level, nil, nil)
    123 }
    124 
    125 // KindTextBlock is a NodeKind of the TextBlock node.
    126 var KindTextBlock = NewNodeKind("TextBlock")
    127 
    128 // Kind implements Node.Kind.
    129 func (n *TextBlock) Kind() NodeKind {
    130 	return KindTextBlock
    131 }
    132 
    133 // NewTextBlock returns a new TextBlock node.
    134 func NewTextBlock() *TextBlock {
    135 	return &TextBlock{
    136 		BaseBlock: BaseBlock{},
    137 	}
    138 }
    139 
    140 // A Paragraph struct represents a paragraph of Markdown text.
    141 type Paragraph struct {
    142 	BaseBlock
    143 }
    144 
    145 // Dump implements Node.Dump .
    146 func (n *Paragraph) Dump(source []byte, level int) {
    147 	DumpHelper(n, source, level, nil, nil)
    148 }
    149 
    150 // KindParagraph is a NodeKind of the Paragraph node.
    151 var KindParagraph = NewNodeKind("Paragraph")
    152 
    153 // Kind implements Node.Kind.
    154 func (n *Paragraph) Kind() NodeKind {
    155 	return KindParagraph
    156 }
    157 
    158 // NewParagraph returns a new Paragraph node.
    159 func NewParagraph() *Paragraph {
    160 	return &Paragraph{
    161 		BaseBlock: BaseBlock{},
    162 	}
    163 }
    164 
    165 // IsParagraph returns true if the given node implements the Paragraph interface,
    166 // otherwise false.
    167 func IsParagraph(node Node) bool {
    168 	_, ok := node.(*Paragraph)
    169 	return ok
    170 }
    171 
    172 // A Heading struct represents headings like SetextHeading and ATXHeading.
    173 type Heading struct {
    174 	BaseBlock
    175 	// Level returns a level of this heading.
    176 	// This value is between 1 and 6.
    177 	Level int
    178 }
    179 
    180 // Dump implements Node.Dump .
    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 // KindHeading is a NodeKind of the Heading node.
    189 var KindHeading = NewNodeKind("Heading")
    190 
    191 // Kind implements Node.Kind.
    192 func (n *Heading) Kind() NodeKind {
    193 	return KindHeading
    194 }
    195 
    196 // NewHeading returns a new Heading node.
    197 func NewHeading(level int) *Heading {
    198 	return &Heading{
    199 		BaseBlock: BaseBlock{},
    200 		Level:     level,
    201 	}
    202 }
    203 
    204 // A ThematicBreak struct represents a thematic break of Markdown text.
    205 type ThematicBreak struct {
    206 	BaseBlock
    207 }
    208 
    209 // Dump implements Node.Dump .
    210 func (n *ThematicBreak) Dump(source []byte, level int) {
    211 	DumpHelper(n, source, level, nil, nil)
    212 }
    213 
    214 // KindThematicBreak is a NodeKind of the ThematicBreak node.
    215 var KindThematicBreak = NewNodeKind("ThematicBreak")
    216 
    217 // Kind implements Node.Kind.
    218 func (n *ThematicBreak) Kind() NodeKind {
    219 	return KindThematicBreak
    220 }
    221 
    222 // NewThematicBreak returns a new ThematicBreak node.
    223 func NewThematicBreak() *ThematicBreak {
    224 	return &ThematicBreak{
    225 		BaseBlock: BaseBlock{},
    226 	}
    227 }
    228 
    229 // A CodeBlock interface represents an indented code block of Markdown text.
    230 type CodeBlock struct {
    231 	BaseBlock
    232 }
    233 
    234 // IsRaw implements Node.IsRaw.
    235 func (n *CodeBlock) IsRaw() bool {
    236 	return true
    237 }
    238 
    239 // Dump implements Node.Dump .
    240 func (n *CodeBlock) Dump(source []byte, level int) {
    241 	DumpHelper(n, source, level, nil, nil)
    242 }
    243 
    244 // KindCodeBlock is a NodeKind of the CodeBlock node.
    245 var KindCodeBlock = NewNodeKind("CodeBlock")
    246 
    247 // Kind implements Node.Kind.
    248 func (n *CodeBlock) Kind() NodeKind {
    249 	return KindCodeBlock
    250 }
    251 
    252 // NewCodeBlock returns a new CodeBlock node.
    253 func NewCodeBlock() *CodeBlock {
    254 	return &CodeBlock{
    255 		BaseBlock: BaseBlock{},
    256 	}
    257 }
    258 
    259 // A FencedCodeBlock struct represents a fenced code block of Markdown text.
    260 type FencedCodeBlock struct {
    261 	BaseBlock
    262 	// Info returns a info text of this fenced code block.
    263 	Info *Text
    264 
    265 	language []byte
    266 }
    267 
    268 // Language returns an language in an info string.
    269 // Language returns nil if this node does not have an info string.
    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 // IsRaw implements Node.IsRaw.
    286 func (n *FencedCodeBlock) IsRaw() bool {
    287 	return true
    288 }
    289 
    290 // Dump implements Node.Dump .
    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 // KindFencedCodeBlock is a NodeKind of the FencedCodeBlock node.
    300 var KindFencedCodeBlock = NewNodeKind("FencedCodeBlock")
    301 
    302 // Kind implements Node.Kind.
    303 func (n *FencedCodeBlock) Kind() NodeKind {
    304 	return KindFencedCodeBlock
    305 }
    306 
    307 // NewFencedCodeBlock return a new FencedCodeBlock node.
    308 func NewFencedCodeBlock(info *Text) *FencedCodeBlock {
    309 	return &FencedCodeBlock{
    310 		BaseBlock: BaseBlock{},
    311 		Info:      info,
    312 	}
    313 }
    314 
    315 // A Blockquote struct represents an blockquote block of Markdown text.
    316 type Blockquote struct {
    317 	BaseBlock
    318 }
    319 
    320 // Dump implements Node.Dump .
    321 func (n *Blockquote) Dump(source []byte, level int) {
    322 	DumpHelper(n, source, level, nil, nil)
    323 }
    324 
    325 // KindBlockquote is a NodeKind of the Blockquote node.
    326 var KindBlockquote = NewNodeKind("Blockquote")
    327 
    328 // Kind implements Node.Kind.
    329 func (n *Blockquote) Kind() NodeKind {
    330 	return KindBlockquote
    331 }
    332 
    333 // NewBlockquote returns a new Blockquote node.
    334 func NewBlockquote() *Blockquote {
    335 	return &Blockquote{
    336 		BaseBlock: BaseBlock{},
    337 	}
    338 }
    339 
    340 // A List struct represents a list of Markdown text.
    341 type List struct {
    342 	BaseBlock
    343 
    344 	// Marker is a marker character like '-', '+', ')' and '.'.
    345 	Marker byte
    346 
    347 	// IsTight is a true if this list is a 'tight' list.
    348 	// See https://spec.commonmark.org/0.30/#loose for details.
    349 	IsTight bool
    350 
    351 	// Start is an initial number of this ordered list.
    352 	// If this list is not an ordered list, Start is 0.
    353 	Start int
    354 }
    355 
    356 // IsOrdered returns true if this list is an ordered list, otherwise false.
    357 func (l *List) IsOrdered() bool {
    358 	return l.Marker == '.' || l.Marker == ')'
    359 }
    360 
    361 // CanContinue returns true if this list can continue with
    362 // the given mark and a list type, otherwise false.
    363 func (l *List) CanContinue(marker byte, isOrdered bool) bool {
    364 	return marker == l.Marker && isOrdered == l.IsOrdered()
    365 }
    366 
    367 // Dump implements Node.Dump.
    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 // KindList is a NodeKind of the List node.
    381 var KindList = NewNodeKind("List")
    382 
    383 // Kind implements Node.Kind.
    384 func (l *List) Kind() NodeKind {
    385 	return KindList
    386 }
    387 
    388 // NewList returns a new List node.
    389 func NewList(marker byte) *List {
    390 	return &List{
    391 		BaseBlock: BaseBlock{},
    392 		Marker:    marker,
    393 		IsTight:   true,
    394 	}
    395 }
    396 
    397 // A ListItem struct represents a list item of Markdown text.
    398 type ListItem struct {
    399 	BaseBlock
    400 
    401 	// Offset is an offset position of this item.
    402 	Offset int
    403 }
    404 
    405 // Dump implements Node.Dump.
    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 // KindListItem is a NodeKind of the ListItem node.
    414 var KindListItem = NewNodeKind("ListItem")
    415 
    416 // Kind implements Node.Kind.
    417 func (n *ListItem) Kind() NodeKind {
    418 	return KindListItem
    419 }
    420 
    421 // NewListItem returns a new ListItem node.
    422 func NewListItem(offset int) *ListItem {
    423 	return &ListItem{
    424 		BaseBlock: BaseBlock{},
    425 		Offset:    offset,
    426 	}
    427 }
    428 
    429 // HTMLBlockType represents kinds of an html blocks.
    430 // See https://spec.commonmark.org/0.30/#html-blocks
    431 type HTMLBlockType int
    432 
    433 const (
    434 	// HTMLBlockType1 represents type 1 html blocks
    435 	HTMLBlockType1 HTMLBlockType = iota + 1
    436 	// HTMLBlockType2 represents type 2 html blocks
    437 	HTMLBlockType2
    438 	// HTMLBlockType3 represents type 3 html blocks
    439 	HTMLBlockType3
    440 	// HTMLBlockType4 represents type 4 html blocks
    441 	HTMLBlockType4
    442 	// HTMLBlockType5 represents type 5 html blocks
    443 	HTMLBlockType5
    444 	// HTMLBlockType6 represents type 6 html blocks
    445 	HTMLBlockType6
    446 	// HTMLBlockType7 represents type 7 html blocks
    447 	HTMLBlockType7
    448 )
    449 
    450 // An HTMLBlock struct represents an html block of Markdown text.
    451 type HTMLBlock struct {
    452 	BaseBlock
    453 
    454 	// Type is a type of this html block.
    455 	HTMLBlockType HTMLBlockType
    456 
    457 	// ClosureLine is a line that closes this html block.
    458 	ClosureLine textm.Segment
    459 }
    460 
    461 // IsRaw implements Node.IsRaw.
    462 func (n *HTMLBlock) IsRaw() bool {
    463 	return true
    464 }
    465 
    466 // HasClosure returns true if this html block has a closure line,
    467 // otherwise false.
    468 func (n *HTMLBlock) HasClosure() bool {
    469 	return n.ClosureLine.Start >= 0
    470 }
    471 
    472 // Dump implements Node.Dump.
    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 // KindHTMLBlock is a NodeKind of the HTMLBlock node.
    494 var KindHTMLBlock = NewNodeKind("HTMLBlock")
    495 
    496 // Kind implements Node.Kind.
    497 func (n *HTMLBlock) Kind() NodeKind {
    498 	return KindHTMLBlock
    499 }
    500 
    501 // NewHTMLBlock returns a new HTMLBlock node.
    502 func NewHTMLBlock(typ HTMLBlockType) *HTMLBlock {
    503 	return &HTMLBlock{
    504 		BaseBlock:     BaseBlock{},
    505 		HTMLBlockType: typ,
    506 		ClosureLine:   textm.NewSegment(-1, -1),
    507 	}
    508 }