...

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 ||
   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  // Text implements Node.Text.
   146  func (n *Text) Text(source []byte) []byte {
   147  	return n.Segment.Value(source)
   148  }
   149  
   150  // Dump implements Node.Dump.
   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  // KindText is a NodeKind of the Text node.
   160  var KindText = NewNodeKind("Text")
   161  
   162  // Kind implements Node.Kind.
   163  func (n *Text) Kind() NodeKind {
   164  	return KindText
   165  }
   166  
   167  // NewText returns a new Text node.
   168  func NewText() *Text {
   169  	return &Text{
   170  		BaseInline: BaseInline{},
   171  	}
   172  }
   173  
   174  // NewTextSegment returns a new Text node with the given source position.
   175  func NewTextSegment(v textm.Segment) *Text {
   176  	return &Text{
   177  		BaseInline: BaseInline{},
   178  		Segment:    v,
   179  	}
   180  }
   181  
   182  // NewRawTextSegment returns a new Text node with the given source position.
   183  // The new node should be rendered as raw contents.
   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  // MergeOrAppendTextSegment merges a given s into the last child of the parent if
   194  // it can be merged, otherwise creates a new Text node and appends it to after current
   195  // last child.
   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  // MergeOrReplaceTextSegment merges a given s into a previous sibling of the node n
   207  // if a previous sibling of the node n is *Text, otherwise replaces Node n with s.
   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  // A String struct is a textual content that has a concrete value.
   219  type String struct {
   220  	BaseInline
   221  
   222  	Value []byte
   223  	flags uint8
   224  }
   225  
   226  // Inline implements Inline.Inline.
   227  func (n *String) Inline() {
   228  }
   229  
   230  // IsRaw returns true if this text should be rendered without unescaping
   231  // back slash escapes and resolving references.
   232  func (n *String) IsRaw() bool {
   233  	return n.flags&textRaw != 0
   234  }
   235  
   236  // SetRaw sets whether this text should be rendered as raw contents.
   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  // IsCode returns true if this text should be rendered without any
   246  // modifications.
   247  func (n *String) IsCode() bool {
   248  	return n.flags&textCode != 0
   249  }
   250  
   251  // SetCode sets whether this text should be rendered without any modifications.
   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  // Text implements Node.Text.
   261  func (n *String) Text(source []byte) []byte {
   262  	return n.Value
   263  }
   264  
   265  // Dump implements Node.Dump.
   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  // KindString is a NodeKind of the String node.
   275  var KindString = NewNodeKind("String")
   276  
   277  // Kind implements Node.Kind.
   278  func (n *String) Kind() NodeKind {
   279  	return KindString
   280  }
   281  
   282  // NewString returns a new String node.
   283  func NewString(v []byte) *String {
   284  	return &String{
   285  		Value: v,
   286  	}
   287  }
   288  
   289  // A CodeSpan struct represents a code span of Markdown text.
   290  type CodeSpan struct {
   291  	BaseInline
   292  }
   293  
   294  // Inline implements Inline.Inline .
   295  func (n *CodeSpan) Inline() {
   296  }
   297  
   298  // IsBlank returns true if this node consists of spaces, otherwise false.
   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  // Dump implements Node.Dump.
   310  func (n *CodeSpan) Dump(source []byte, level int) {
   311  	DumpHelper(n, source, level, nil, nil)
   312  }
   313  
   314  // KindCodeSpan is a NodeKind of the CodeSpan node.
   315  var KindCodeSpan = NewNodeKind("CodeSpan")
   316  
   317  // Kind implements Node.Kind.
   318  func (n *CodeSpan) Kind() NodeKind {
   319  	return KindCodeSpan
   320  }
   321  
   322  // NewCodeSpan returns a new CodeSpan node.
   323  func NewCodeSpan() *CodeSpan {
   324  	return &CodeSpan{
   325  		BaseInline: BaseInline{},
   326  	}
   327  }
   328  
   329  // An Emphasis struct represents an emphasis of Markdown text.
   330  type Emphasis struct {
   331  	BaseInline
   332  
   333  	// Level is a level of the emphasis.
   334  	Level int
   335  }
   336  
   337  // Dump implements Node.Dump.
   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  // KindEmphasis is a NodeKind of the Emphasis node.
   346  var KindEmphasis = NewNodeKind("Emphasis")
   347  
   348  // Kind implements Node.Kind.
   349  func (n *Emphasis) Kind() NodeKind {
   350  	return KindEmphasis
   351  }
   352  
   353  // NewEmphasis returns a new Emphasis node with the given level.
   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  	// Destination is a destination(URL) of this link.
   365  	Destination []byte
   366  
   367  	// Title is a title of this link.
   368  	Title []byte
   369  }
   370  
   371  // Inline implements Inline.Inline.
   372  func (n *baseLink) Inline() {
   373  }
   374  
   375  // A Link struct represents a link of the Markdown text.
   376  type Link struct {
   377  	baseLink
   378  }
   379  
   380  // Dump implements Node.Dump.
   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  // KindLink is a NodeKind of the Link node.
   389  var KindLink = NewNodeKind("Link")
   390  
   391  // Kind implements Node.Kind.
   392  func (n *Link) Kind() NodeKind {
   393  	return KindLink
   394  }
   395  
   396  // NewLink returns a new Link node.
   397  func NewLink() *Link {
   398  	c := &Link{
   399  		baseLink: baseLink{
   400  			BaseInline: BaseInline{},
   401  		},
   402  	}
   403  	return c
   404  }
   405  
   406  // An Image struct represents an image of the Markdown text.
   407  type Image struct {
   408  	baseLink
   409  }
   410  
   411  // Dump implements Node.Dump.
   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  // KindImage is a NodeKind of the Image node.
   420  var KindImage = NewNodeKind("Image")
   421  
   422  // Kind implements Node.Kind.
   423  func (n *Image) Kind() NodeKind {
   424  	return KindImage
   425  }
   426  
   427  // NewImage returns a new Image node.
   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  // AutoLinkType defines kind of auto links.
   447  type AutoLinkType int
   448  
   449  const (
   450  	// AutoLinkEmail indicates that an autolink is an email address.
   451  	AutoLinkEmail AutoLinkType = iota + 1
   452  	// AutoLinkURL indicates that an autolink is a generic URL.
   453  	AutoLinkURL
   454  )
   455  
   456  // An AutoLink struct represents an autolink of the Markdown text.
   457  type AutoLink struct {
   458  	BaseInline
   459  	// Type is a type of this autolink.
   460  	AutoLinkType AutoLinkType
   461  
   462  	// Protocol specified a protocol of the link.
   463  	Protocol []byte
   464  
   465  	value *Text
   466  }
   467  
   468  // Inline implements Inline.Inline.
   469  func (n *AutoLink) Inline() {}
   470  
   471  // Dump implements Node.Dump.
   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  // KindAutoLink is a NodeKind of the AutoLink node.
   481  var KindAutoLink = NewNodeKind("AutoLink")
   482  
   483  // Kind implements Node.Kind.
   484  func (n *AutoLink) Kind() NodeKind {
   485  	return KindAutoLink
   486  }
   487  
   488  // URL returns an url of this node.
   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  // Label returns a label of this node.
   502  func (n *AutoLink) Label(source []byte) []byte {
   503  	return n.value.Text(source)
   504  }
   505  
   506  // NewAutoLink returns a new AutoLink node.
   507  func NewAutoLink(typ AutoLinkType, value *Text) *AutoLink {
   508  	return &AutoLink{
   509  		BaseInline:   BaseInline{},
   510  		value:        value,
   511  		AutoLinkType: typ,
   512  	}
   513  }
   514  
   515  // A RawHTML struct represents an inline raw HTML of the Markdown text.
   516  type RawHTML struct {
   517  	BaseInline
   518  	Segments *textm.Segments
   519  }
   520  
   521  // Inline implements Inline.Inline.
   522  func (n *RawHTML) Inline() {}
   523  
   524  // Dump implements Node.Dump.
   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  // KindRawHTML is a NodeKind of the RawHTML node.
   537  var KindRawHTML = NewNodeKind("RawHTML")
   538  
   539  // Kind implements Node.Kind.
   540  func (n *RawHTML) Kind() NodeKind {
   541  	return KindRawHTML
   542  }
   543  
   544  // NewRawHTML returns a new RawHTML node.
   545  func NewRawHTML() *RawHTML {
   546  	return &RawHTML{
   547  		Segments: textm.NewSegments(),
   548  	}
   549  }
   550  

View as plain text