...

Source file src/github.com/yuin/goldmark/ast/inline.go

Documentation: github.com/yuin/goldmark/ast

     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  }
   549  

View as plain text