inline.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  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 ||
  115. source[n.Segment.Stop-1] == '\n' || t.IsRaw() != n.IsRaw() {
  116. return false
  117. }
  118. n.Segment.Stop = t.Segment.Stop
  119. n.SetSoftLineBreak(t.SoftLineBreak())
  120. n.SetHardLineBreak(t.HardLineBreak())
  121. return true
  122. }
  123. // Text implements Node.Text.
  124. func (n *Text) Text(source []byte) []byte {
  125. return n.Segment.Value(source)
  126. }
  127. // Dump implements Node.Dump.
  128. func (n *Text) Dump(source []byte, level int) {
  129. fs := textFlagsString(n.flags)
  130. if len(fs) != 0 {
  131. fs = "(" + fs + ")"
  132. }
  133. fmt.Printf("%sText%s: \"%s\"\n", strings.Repeat(" ", level), fs, strings.TrimRight(string(n.Text(source)), "\n"))
  134. }
  135. // KindText is a NodeKind of the Text node.
  136. var KindText = NewNodeKind("Text")
  137. // Kind implements Node.Kind.
  138. func (n *Text) Kind() NodeKind {
  139. return KindText
  140. }
  141. // NewText returns a new Text node.
  142. func NewText() *Text {
  143. return &Text{
  144. BaseInline: BaseInline{},
  145. }
  146. }
  147. // NewTextSegment returns a new Text node with the given source position.
  148. func NewTextSegment(v textm.Segment) *Text {
  149. return &Text{
  150. BaseInline: BaseInline{},
  151. Segment: v,
  152. }
  153. }
  154. // NewRawTextSegment returns a new Text node with the given source position.
  155. // The new node should be rendered as raw contents.
  156. func NewRawTextSegment(v textm.Segment) *Text {
  157. t := &Text{
  158. BaseInline: BaseInline{},
  159. Segment: v,
  160. }
  161. t.SetRaw(true)
  162. return t
  163. }
  164. // MergeOrAppendTextSegment merges a given s into the last child of the parent if
  165. // it can be merged, otherwise creates a new Text node and appends it to after current
  166. // last child.
  167. func MergeOrAppendTextSegment(parent Node, s textm.Segment) {
  168. last := parent.LastChild()
  169. t, ok := last.(*Text)
  170. if ok && t.Segment.Stop == s.Start && !t.SoftLineBreak() {
  171. t.Segment = t.Segment.WithStop(s.Stop)
  172. } else {
  173. parent.AppendChild(parent, NewTextSegment(s))
  174. }
  175. }
  176. // MergeOrReplaceTextSegment merges a given s into a previous sibling of the node n
  177. // if a previous sibling of the node n is *Text, otherwise replaces Node n with s.
  178. func MergeOrReplaceTextSegment(parent Node, n Node, s textm.Segment) {
  179. prev := n.PreviousSibling()
  180. if t, ok := prev.(*Text); ok && t.Segment.Stop == s.Start && !t.SoftLineBreak() {
  181. t.Segment = t.Segment.WithStop(s.Stop)
  182. parent.RemoveChild(parent, n)
  183. } else {
  184. parent.ReplaceChild(parent, n, NewTextSegment(s))
  185. }
  186. }
  187. // A String struct is a textual content that has a concrete value.
  188. type String struct {
  189. BaseInline
  190. Value []byte
  191. flags uint8
  192. }
  193. // Inline implements Inline.Inline.
  194. func (n *String) Inline() {
  195. }
  196. // IsRaw returns true if this text should be rendered without unescaping
  197. // back slash escapes and resolving references.
  198. func (n *String) IsRaw() bool {
  199. return n.flags&textRaw != 0
  200. }
  201. // SetRaw sets whether this text should be rendered as raw contents.
  202. func (n *String) SetRaw(v bool) {
  203. if v {
  204. n.flags |= textRaw
  205. } else {
  206. n.flags = n.flags &^ textRaw
  207. }
  208. }
  209. // IsCode returns true if this text should be rendered without any
  210. // modifications.
  211. func (n *String) IsCode() bool {
  212. return n.flags&textCode != 0
  213. }
  214. // SetCode sets whether this text should be rendered without any modifications.
  215. func (n *String) SetCode(v bool) {
  216. if v {
  217. n.flags |= textCode
  218. } else {
  219. n.flags = n.flags &^ textCode
  220. }
  221. }
  222. // Text implements Node.Text.
  223. func (n *String) Text(source []byte) []byte {
  224. return n.Value
  225. }
  226. // Dump implements Node.Dump.
  227. func (n *String) Dump(source []byte, level int) {
  228. fs := textFlagsString(n.flags)
  229. if len(fs) != 0 {
  230. fs = "(" + fs + ")"
  231. }
  232. fmt.Printf("%sString%s: \"%s\"\n", strings.Repeat(" ", level), fs, strings.TrimRight(string(n.Value), "\n"))
  233. }
  234. // KindString is a NodeKind of the String node.
  235. var KindString = NewNodeKind("String")
  236. // Kind implements Node.Kind.
  237. func (n *String) Kind() NodeKind {
  238. return KindString
  239. }
  240. // NewString returns a new String node.
  241. func NewString(v []byte) *String {
  242. return &String{
  243. Value: v,
  244. }
  245. }
  246. // A CodeSpan struct represents a code span of Markdown text.
  247. type CodeSpan struct {
  248. BaseInline
  249. }
  250. // Inline implements Inline.Inline .
  251. func (n *CodeSpan) Inline() {
  252. }
  253. // IsBlank returns true if this node consists of spaces, otherwise false.
  254. func (n *CodeSpan) IsBlank(source []byte) bool {
  255. for c := n.FirstChild(); c != nil; c = c.NextSibling() {
  256. text := c.(*Text).Segment
  257. if !util.IsBlank(text.Value(source)) {
  258. return false
  259. }
  260. }
  261. return true
  262. }
  263. // Dump implements Node.Dump.
  264. func (n *CodeSpan) Dump(source []byte, level int) {
  265. DumpHelper(n, source, level, nil, nil)
  266. }
  267. // KindCodeSpan is a NodeKind of the CodeSpan node.
  268. var KindCodeSpan = NewNodeKind("CodeSpan")
  269. // Kind implements Node.Kind.
  270. func (n *CodeSpan) Kind() NodeKind {
  271. return KindCodeSpan
  272. }
  273. // NewCodeSpan returns a new CodeSpan node.
  274. func NewCodeSpan() *CodeSpan {
  275. return &CodeSpan{
  276. BaseInline: BaseInline{},
  277. }
  278. }
  279. // An Emphasis struct represents an emphasis of Markdown text.
  280. type Emphasis struct {
  281. BaseInline
  282. // Level is a level of the emphasis.
  283. Level int
  284. }
  285. // Dump implements Node.Dump.
  286. func (n *Emphasis) Dump(source []byte, level int) {
  287. m := map[string]string{
  288. "Level": fmt.Sprintf("%v", n.Level),
  289. }
  290. DumpHelper(n, source, level, m, nil)
  291. }
  292. // KindEmphasis is a NodeKind of the Emphasis node.
  293. var KindEmphasis = NewNodeKind("Emphasis")
  294. // Kind implements Node.Kind.
  295. func (n *Emphasis) Kind() NodeKind {
  296. return KindEmphasis
  297. }
  298. // NewEmphasis returns a new Emphasis node with the given level.
  299. func NewEmphasis(level int) *Emphasis {
  300. return &Emphasis{
  301. BaseInline: BaseInline{},
  302. Level: level,
  303. }
  304. }
  305. type baseLink struct {
  306. BaseInline
  307. // Destination is a destination(URL) of this link.
  308. Destination []byte
  309. // Title is a title of this link.
  310. Title []byte
  311. }
  312. // Inline implements Inline.Inline.
  313. func (n *baseLink) Inline() {
  314. }
  315. // A Link struct represents a link of the Markdown text.
  316. type Link struct {
  317. baseLink
  318. }
  319. // Dump implements Node.Dump.
  320. func (n *Link) Dump(source []byte, level int) {
  321. m := map[string]string{}
  322. m["Destination"] = string(n.Destination)
  323. m["Title"] = string(n.Title)
  324. DumpHelper(n, source, level, m, nil)
  325. }
  326. // KindLink is a NodeKind of the Link node.
  327. var KindLink = NewNodeKind("Link")
  328. // Kind implements Node.Kind.
  329. func (n *Link) Kind() NodeKind {
  330. return KindLink
  331. }
  332. // NewLink returns a new Link node.
  333. func NewLink() *Link {
  334. c := &Link{
  335. baseLink: baseLink{
  336. BaseInline: BaseInline{},
  337. },
  338. }
  339. return c
  340. }
  341. // An Image struct represents an image of the Markdown text.
  342. type Image struct {
  343. baseLink
  344. }
  345. // Dump implements Node.Dump.
  346. func (n *Image) Dump(source []byte, level int) {
  347. m := map[string]string{}
  348. m["Destination"] = string(n.Destination)
  349. m["Title"] = string(n.Title)
  350. DumpHelper(n, source, level, m, nil)
  351. }
  352. // KindImage is a NodeKind of the Image node.
  353. var KindImage = NewNodeKind("Image")
  354. // Kind implements Node.Kind.
  355. func (n *Image) Kind() NodeKind {
  356. return KindImage
  357. }
  358. // NewImage returns a new Image node.
  359. func NewImage(link *Link) *Image {
  360. c := &Image{
  361. baseLink: baseLink{
  362. BaseInline: BaseInline{},
  363. },
  364. }
  365. c.Destination = link.Destination
  366. c.Title = link.Title
  367. for n := link.FirstChild(); n != nil; {
  368. next := n.NextSibling()
  369. link.RemoveChild(link, n)
  370. c.AppendChild(c, n)
  371. n = next
  372. }
  373. return c
  374. }
  375. // AutoLinkType defines kind of auto links.
  376. type AutoLinkType int
  377. const (
  378. // AutoLinkEmail indicates that an autolink is an email address.
  379. AutoLinkEmail AutoLinkType = iota + 1
  380. // AutoLinkURL indicates that an autolink is a generic URL.
  381. AutoLinkURL
  382. )
  383. // An AutoLink struct represents an autolink of the Markdown text.
  384. type AutoLink struct {
  385. BaseInline
  386. // Type is a type of this autolink.
  387. AutoLinkType AutoLinkType
  388. // Protocol specified a protocol of the link.
  389. Protocol []byte
  390. value *Text
  391. }
  392. // Inline implements Inline.Inline.
  393. func (n *AutoLink) Inline() {}
  394. // Dump implements Node.Dump.
  395. func (n *AutoLink) Dump(source []byte, level int) {
  396. segment := n.value.Segment
  397. m := map[string]string{
  398. "Value": string(segment.Value(source)),
  399. }
  400. DumpHelper(n, source, level, m, nil)
  401. }
  402. // KindAutoLink is a NodeKind of the AutoLink node.
  403. var KindAutoLink = NewNodeKind("AutoLink")
  404. // Kind implements Node.Kind.
  405. func (n *AutoLink) Kind() NodeKind {
  406. return KindAutoLink
  407. }
  408. // URL returns an url of this node.
  409. func (n *AutoLink) URL(source []byte) []byte {
  410. if n.Protocol != nil {
  411. s := n.value.Segment
  412. ret := make([]byte, 0, len(n.Protocol)+s.Len()+3)
  413. ret = append(ret, n.Protocol...)
  414. ret = append(ret, ':', '/', '/')
  415. ret = append(ret, n.value.Text(source)...)
  416. return ret
  417. }
  418. return n.value.Text(source)
  419. }
  420. // Label returns a label of this node.
  421. func (n *AutoLink) Label(source []byte) []byte {
  422. return n.value.Text(source)
  423. }
  424. // NewAutoLink returns a new AutoLink node.
  425. func NewAutoLink(typ AutoLinkType, value *Text) *AutoLink {
  426. return &AutoLink{
  427. BaseInline: BaseInline{},
  428. value: value,
  429. AutoLinkType: typ,
  430. }
  431. }
  432. // A RawHTML struct represents an inline raw HTML of the Markdown text.
  433. type RawHTML struct {
  434. BaseInline
  435. Segments *textm.Segments
  436. }
  437. // Inline implements Inline.Inline.
  438. func (n *RawHTML) Inline() {}
  439. // Dump implements Node.Dump.
  440. func (n *RawHTML) Dump(source []byte, level int) {
  441. m := map[string]string{}
  442. t := []string{}
  443. for i := 0; i < n.Segments.Len(); i++ {
  444. segment := n.Segments.At(i)
  445. t = append(t, string(segment.Value(source)))
  446. }
  447. m["RawText"] = strings.Join(t, "")
  448. DumpHelper(n, source, level, m, nil)
  449. }
  450. // KindRawHTML is a NodeKind of the RawHTML node.
  451. var KindRawHTML = NewNodeKind("RawHTML")
  452. // Kind implements Node.Kind.
  453. func (n *RawHTML) Kind() NodeKind {
  454. return KindRawHTML
  455. }
  456. // NewRawHTML returns a new RawHTML node.
  457. func NewRawHTML() *RawHTML {
  458. return &RawHTML{
  459. Segments: textm.NewSegments(),
  460. }
  461. }