inline.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. package ast
  2. import (
  3. "fmt"
  4. "strings"
  5. textm "github.com/yuin/goldmark/text"
  6. "github.com/yuin/goldmark/util"
  7. )
  8. // A BaseInline struct implements the Node interface partialliy.
  9. type BaseInline struct {
  10. BaseNode
  11. }
  12. // Type implements Node.Type
  13. func (b *BaseInline) Type() NodeType {
  14. return TypeInline
  15. }
  16. // IsRaw implements Node.IsRaw
  17. func (b *BaseInline) IsRaw() bool {
  18. return false
  19. }
  20. // HasBlankPreviousLines implements Node.HasBlankPreviousLines.
  21. func (b *BaseInline) HasBlankPreviousLines() bool {
  22. panic("can not call with inline nodes.")
  23. }
  24. // SetBlankPreviousLines implements Node.SetBlankPreviousLines.
  25. func (b *BaseInline) SetBlankPreviousLines(v bool) {
  26. panic("can not call with inline nodes.")
  27. }
  28. // Lines implements Node.Lines
  29. func (b *BaseInline) Lines() *textm.Segments {
  30. panic("can not call with inline nodes.")
  31. }
  32. // SetLines implements Node.SetLines
  33. func (b *BaseInline) SetLines(v *textm.Segments) {
  34. panic("can not call with inline nodes.")
  35. }
  36. // A Text struct represents a textual content of the Markdown text.
  37. type Text struct {
  38. BaseInline
  39. // Segment is a position in a source text.
  40. Segment textm.Segment
  41. flags uint8
  42. }
  43. const (
  44. textSoftLineBreak = 1 << iota
  45. textHardLineBreak
  46. textRaw
  47. textCode
  48. )
  49. func textFlagsString(flags uint8) string {
  50. buf := []string{}
  51. if flags&textSoftLineBreak != 0 {
  52. buf = append(buf, "SoftLineBreak")
  53. }
  54. if flags&textHardLineBreak != 0 {
  55. buf = append(buf, "HardLineBreak")
  56. }
  57. if flags&textRaw != 0 {
  58. buf = append(buf, "Raw")
  59. }
  60. if flags&textCode != 0 {
  61. buf = append(buf, "Code")
  62. }
  63. return strings.Join(buf, ", ")
  64. }
  65. // Inline implements Inline.Inline.
  66. func (n *Text) Inline() {
  67. }
  68. // SoftLineBreak returns true if this node ends with a new line,
  69. // otherwise false.
  70. func (n *Text) SoftLineBreak() bool {
  71. return n.flags&textSoftLineBreak != 0
  72. }
  73. // SetSoftLineBreak sets whether this node ends with a new line.
  74. func (n *Text) SetSoftLineBreak(v bool) {
  75. if v {
  76. n.flags |= textSoftLineBreak
  77. } else {
  78. n.flags = n.flags &^ textSoftLineBreak
  79. }
  80. }
  81. // IsRaw returns true if this text should be rendered without unescaping
  82. // back slash escapes and resolving references.
  83. func (n *Text) IsRaw() bool {
  84. return n.flags&textRaw != 0
  85. }
  86. // SetRaw sets whether this text should be rendered as raw contents.
  87. func (n *Text) SetRaw(v bool) {
  88. if v {
  89. n.flags |= textRaw
  90. } else {
  91. n.flags = n.flags &^ textRaw
  92. }
  93. }
  94. // HardLineBreak returns true if this node ends with a hard line break.
  95. // See https://spec.commonmark.org/0.30/#hard-line-breaks for details.
  96. func (n *Text) HardLineBreak() bool {
  97. return n.flags&textHardLineBreak != 0
  98. }
  99. // SetHardLineBreak sets whether this node ends with a hard line break.
  100. func (n *Text) SetHardLineBreak(v bool) {
  101. if v {
  102. n.flags |= textHardLineBreak
  103. } else {
  104. n.flags = n.flags &^ textHardLineBreak
  105. }
  106. }
  107. // Merge merges a Node n into this node.
  108. // Merge returns true if the given node has been merged, otherwise false.
  109. func (n *Text) Merge(node Node, source []byte) bool {
  110. t, ok := node.(*Text)
  111. if !ok {
  112. return false
  113. }
  114. if n.Segment.Stop != t.Segment.Start || t.Segment.Padding != 0 || source[n.Segment.Stop-1] == '\n' || t.IsRaw() != n.IsRaw() {
  115. return false
  116. }
  117. n.Segment.Stop = t.Segment.Stop
  118. n.SetSoftLineBreak(t.SoftLineBreak())
  119. n.SetHardLineBreak(t.HardLineBreak())
  120. return true
  121. }
  122. // Text implements Node.Text.
  123. func (n *Text) Text(source []byte) []byte {
  124. return n.Segment.Value(source)
  125. }
  126. // Dump implements Node.Dump.
  127. func (n *Text) Dump(source []byte, level int) {
  128. fs := textFlagsString(n.flags)
  129. if len(fs) != 0 {
  130. fs = "(" + fs + ")"
  131. }
  132. fmt.Printf("%sText%s: \"%s\"\n", strings.Repeat(" ", level), fs, strings.TrimRight(string(n.Text(source)), "\n"))
  133. }
  134. // KindText is a NodeKind of the Text node.
  135. var KindText = NewNodeKind("Text")
  136. // Kind implements Node.Kind.
  137. func (n *Text) Kind() NodeKind {
  138. return KindText
  139. }
  140. // NewText returns a new Text node.
  141. func NewText() *Text {
  142. return &Text{
  143. BaseInline: BaseInline{},
  144. }
  145. }
  146. // NewTextSegment returns a new Text node with the given source position.
  147. func NewTextSegment(v textm.Segment) *Text {
  148. return &Text{
  149. BaseInline: BaseInline{},
  150. Segment: v,
  151. }
  152. }
  153. // NewRawTextSegment returns a new Text node with the given source position.
  154. // The new node should be rendered as raw contents.
  155. func NewRawTextSegment(v textm.Segment) *Text {
  156. t := &Text{
  157. BaseInline: BaseInline{},
  158. Segment: v,
  159. }
  160. t.SetRaw(true)
  161. return t
  162. }
  163. // MergeOrAppendTextSegment merges a given s into the last child of the parent if
  164. // it can be merged, otherwise creates a new Text node and appends it to after current
  165. // last child.
  166. func MergeOrAppendTextSegment(parent Node, s textm.Segment) {
  167. last := parent.LastChild()
  168. t, ok := last.(*Text)
  169. if ok && t.Segment.Stop == s.Start && !t.SoftLineBreak() {
  170. t.Segment = t.Segment.WithStop(s.Stop)
  171. } else {
  172. parent.AppendChild(parent, NewTextSegment(s))
  173. }
  174. }
  175. // MergeOrReplaceTextSegment merges a given s into a previous sibling of the node n
  176. // if a previous sibling of the node n is *Text, otherwise replaces Node n with s.
  177. func MergeOrReplaceTextSegment(parent Node, n Node, s textm.Segment) {
  178. prev := n.PreviousSibling()
  179. if t, ok := prev.(*Text); ok && t.Segment.Stop == s.Start && !t.SoftLineBreak() {
  180. t.Segment = t.Segment.WithStop(s.Stop)
  181. parent.RemoveChild(parent, n)
  182. } else {
  183. parent.ReplaceChild(parent, n, NewTextSegment(s))
  184. }
  185. }
  186. // A String struct is a textual content that has a concrete value
  187. type String struct {
  188. BaseInline
  189. Value []byte
  190. flags uint8
  191. }
  192. // Inline implements Inline.Inline.
  193. func (n *String) Inline() {
  194. }
  195. // IsRaw returns true if this text should be rendered without unescaping
  196. // back slash escapes and resolving references.
  197. func (n *String) IsRaw() bool {
  198. return n.flags&textRaw != 0
  199. }
  200. // SetRaw sets whether this text should be rendered as raw contents.
  201. func (n *String) SetRaw(v bool) {
  202. if v {
  203. n.flags |= textRaw
  204. } else {
  205. n.flags = n.flags &^ textRaw
  206. }
  207. }
  208. // IsCode returns true if this text should be rendered without any
  209. // modifications.
  210. func (n *String) IsCode() bool {
  211. return n.flags&textCode != 0
  212. }
  213. // SetCode sets whether this text should be rendered without any modifications.
  214. func (n *String) SetCode(v bool) {
  215. if v {
  216. n.flags |= textCode
  217. } else {
  218. n.flags = n.flags &^ textCode
  219. }
  220. }
  221. // Text implements Node.Text.
  222. func (n *String) Text(source []byte) []byte {
  223. return n.Value
  224. }
  225. // Dump implements Node.Dump.
  226. func (n *String) Dump(source []byte, level int) {
  227. fs := textFlagsString(n.flags)
  228. if len(fs) != 0 {
  229. fs = "(" + fs + ")"
  230. }
  231. fmt.Printf("%sString%s: \"%s\"\n", strings.Repeat(" ", level), fs, strings.TrimRight(string(n.Value), "\n"))
  232. }
  233. // KindString is a NodeKind of the String node.
  234. var KindString = NewNodeKind("String")
  235. // Kind implements Node.Kind.
  236. func (n *String) Kind() NodeKind {
  237. return KindString
  238. }
  239. // NewString returns a new String node.
  240. func NewString(v []byte) *String {
  241. return &String{
  242. Value: v,
  243. }
  244. }
  245. // A CodeSpan struct represents a code span of Markdown text.
  246. type CodeSpan struct {
  247. BaseInline
  248. }
  249. // Inline implements Inline.Inline .
  250. func (n *CodeSpan) Inline() {
  251. }
  252. // IsBlank returns true if this node consists of spaces, otherwise false.
  253. func (n *CodeSpan) IsBlank(source []byte) bool {
  254. for c := n.FirstChild(); c != nil; c = c.NextSibling() {
  255. text := c.(*Text).Segment
  256. if !util.IsBlank(text.Value(source)) {
  257. return false
  258. }
  259. }
  260. return true
  261. }
  262. // Dump implements Node.Dump
  263. func (n *CodeSpan) Dump(source []byte, level int) {
  264. DumpHelper(n, source, level, nil, nil)
  265. }
  266. // KindCodeSpan is a NodeKind of the CodeSpan node.
  267. var KindCodeSpan = NewNodeKind("CodeSpan")
  268. // Kind implements Node.Kind.
  269. func (n *CodeSpan) Kind() NodeKind {
  270. return KindCodeSpan
  271. }
  272. // NewCodeSpan returns a new CodeSpan node.
  273. func NewCodeSpan() *CodeSpan {
  274. return &CodeSpan{
  275. BaseInline: BaseInline{},
  276. }
  277. }
  278. // An Emphasis struct represents an emphasis of Markdown text.
  279. type Emphasis struct {
  280. BaseInline
  281. // Level is a level of the emphasis.
  282. Level int
  283. }
  284. // Dump implements Node.Dump.
  285. func (n *Emphasis) Dump(source []byte, level int) {
  286. m := map[string]string{
  287. "Level": fmt.Sprintf("%v", n.Level),
  288. }
  289. DumpHelper(n, source, level, m, nil)
  290. }
  291. // KindEmphasis is a NodeKind of the Emphasis node.
  292. var KindEmphasis = NewNodeKind("Emphasis")
  293. // Kind implements Node.Kind.
  294. func (n *Emphasis) Kind() NodeKind {
  295. return KindEmphasis
  296. }
  297. // NewEmphasis returns a new Emphasis node with the given level.
  298. func NewEmphasis(level int) *Emphasis {
  299. return &Emphasis{
  300. BaseInline: BaseInline{},
  301. Level: level,
  302. }
  303. }
  304. type baseLink struct {
  305. BaseInline
  306. // Destination is a destination(URL) of this link.
  307. Destination []byte
  308. // Title is a title of this link.
  309. Title []byte
  310. }
  311. // Inline implements Inline.Inline.
  312. func (n *baseLink) Inline() {
  313. }
  314. // A Link struct represents a link of the Markdown text.
  315. type Link struct {
  316. baseLink
  317. }
  318. // Dump implements Node.Dump.
  319. func (n *Link) Dump(source []byte, level int) {
  320. m := map[string]string{}
  321. m["Destination"] = string(n.Destination)
  322. m["Title"] = string(n.Title)
  323. DumpHelper(n, source, level, m, nil)
  324. }
  325. // KindLink is a NodeKind of the Link node.
  326. var KindLink = NewNodeKind("Link")
  327. // Kind implements Node.Kind.
  328. func (n *Link) Kind() NodeKind {
  329. return KindLink
  330. }
  331. // NewLink returns a new Link node.
  332. func NewLink() *Link {
  333. c := &Link{
  334. baseLink: baseLink{
  335. BaseInline: BaseInline{},
  336. },
  337. }
  338. return c
  339. }
  340. // An Image struct represents an image of the Markdown text.
  341. type Image struct {
  342. baseLink
  343. }
  344. // Dump implements Node.Dump.
  345. func (n *Image) Dump(source []byte, level int) {
  346. m := map[string]string{}
  347. m["Destination"] = string(n.Destination)
  348. m["Title"] = string(n.Title)
  349. DumpHelper(n, source, level, m, nil)
  350. }
  351. // KindImage is a NodeKind of the Image node.
  352. var KindImage = NewNodeKind("Image")
  353. // Kind implements Node.Kind.
  354. func (n *Image) Kind() NodeKind {
  355. return KindImage
  356. }
  357. // NewImage returns a new Image node.
  358. func NewImage(link *Link) *Image {
  359. c := &Image{
  360. baseLink: baseLink{
  361. BaseInline: BaseInline{},
  362. },
  363. }
  364. c.Destination = link.Destination
  365. c.Title = link.Title
  366. for n := link.FirstChild(); n != nil; {
  367. next := n.NextSibling()
  368. link.RemoveChild(link, n)
  369. c.AppendChild(c, n)
  370. n = next
  371. }
  372. return c
  373. }
  374. // AutoLinkType defines kind of auto links.
  375. type AutoLinkType int
  376. const (
  377. // AutoLinkEmail indicates that an autolink is an email address.
  378. AutoLinkEmail AutoLinkType = iota + 1
  379. // AutoLinkURL indicates that an autolink is a generic URL.
  380. AutoLinkURL
  381. )
  382. // An AutoLink struct represents an autolink of the Markdown text.
  383. type AutoLink struct {
  384. BaseInline
  385. // Type is a type of this autolink.
  386. AutoLinkType AutoLinkType
  387. // Protocol specified a protocol of the link.
  388. Protocol []byte
  389. value *Text
  390. }
  391. // Inline implements Inline.Inline.
  392. func (n *AutoLink) Inline() {}
  393. // Dump implements Node.Dump
  394. func (n *AutoLink) Dump(source []byte, level int) {
  395. segment := n.value.Segment
  396. m := map[string]string{
  397. "Value": string(segment.Value(source)),
  398. }
  399. DumpHelper(n, source, level, m, nil)
  400. }
  401. // KindAutoLink is a NodeKind of the AutoLink node.
  402. var KindAutoLink = NewNodeKind("AutoLink")
  403. // Kind implements Node.Kind.
  404. func (n *AutoLink) Kind() NodeKind {
  405. return KindAutoLink
  406. }
  407. // URL returns an url of this node.
  408. func (n *AutoLink) URL(source []byte) []byte {
  409. if n.Protocol != nil {
  410. s := n.value.Segment
  411. ret := make([]byte, 0, len(n.Protocol)+s.Len()+3)
  412. ret = append(ret, n.Protocol...)
  413. ret = append(ret, ':', '/', '/')
  414. ret = append(ret, n.value.Text(source)...)
  415. return ret
  416. }
  417. return n.value.Text(source)
  418. }
  419. // Label returns a label of this node.
  420. func (n *AutoLink) Label(source []byte) []byte {
  421. return n.value.Text(source)
  422. }
  423. // NewAutoLink returns a new AutoLink node.
  424. func NewAutoLink(typ AutoLinkType, value *Text) *AutoLink {
  425. return &AutoLink{
  426. BaseInline: BaseInline{},
  427. value: value,
  428. AutoLinkType: typ,
  429. }
  430. }
  431. // A RawHTML struct represents an inline raw HTML of the Markdown text.
  432. type RawHTML struct {
  433. BaseInline
  434. Segments *textm.Segments
  435. }
  436. // Inline implements Inline.Inline.
  437. func (n *RawHTML) Inline() {}
  438. // Dump implements Node.Dump.
  439. func (n *RawHTML) Dump(source []byte, level int) {
  440. m := map[string]string{}
  441. t := []string{}
  442. for i := 0; i < n.Segments.Len(); i++ {
  443. segment := n.Segments.At(i)
  444. t = append(t, string(segment.Value(source)))
  445. }
  446. m["RawText"] = strings.Join(t, "")
  447. DumpHelper(n, source, level, m, nil)
  448. }
  449. // KindRawHTML is a NodeKind of the RawHTML node.
  450. var KindRawHTML = NewNodeKind("RawHTML")
  451. // Kind implements Node.Kind.
  452. func (n *RawHTML) Kind() NodeKind {
  453. return KindRawHTML
  454. }
  455. // NewRawHTML returns a new RawHTML node.
  456. func NewRawHTML() *RawHTML {
  457. return &RawHTML{
  458. Segments: textm.NewSegments(),
  459. }
  460. }