link.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. package parser
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/yuin/goldmark/ast"
  6. "github.com/yuin/goldmark/text"
  7. "github.com/yuin/goldmark/util"
  8. )
  9. var linkLabelStateKey = NewContextKey()
  10. type linkLabelState struct {
  11. ast.BaseInline
  12. Segment text.Segment
  13. IsImage bool
  14. Prev *linkLabelState
  15. Next *linkLabelState
  16. First *linkLabelState
  17. Last *linkLabelState
  18. }
  19. func newLinkLabelState(segment text.Segment, isImage bool) *linkLabelState {
  20. return &linkLabelState{
  21. Segment: segment,
  22. IsImage: isImage,
  23. }
  24. }
  25. func (s *linkLabelState) Text(source []byte) []byte {
  26. return s.Segment.Value(source)
  27. }
  28. func (s *linkLabelState) Dump(source []byte, level int) {
  29. fmt.Printf("%slinkLabelState: \"%s\"\n", strings.Repeat(" ", level), s.Text(source))
  30. }
  31. var kindLinkLabelState = ast.NewNodeKind("LinkLabelState")
  32. func (s *linkLabelState) Kind() ast.NodeKind {
  33. return kindLinkLabelState
  34. }
  35. func linkLabelStateLength(v *linkLabelState) int {
  36. if v == nil || v.Last == nil || v.First == nil {
  37. return 0
  38. }
  39. return v.Last.Segment.Stop - v.First.Segment.Start
  40. }
  41. func pushLinkLabelState(pc Context, v *linkLabelState) {
  42. tlist := pc.Get(linkLabelStateKey)
  43. var list *linkLabelState
  44. if tlist == nil {
  45. list = v
  46. v.First = v
  47. v.Last = v
  48. pc.Set(linkLabelStateKey, list)
  49. } else {
  50. list = tlist.(*linkLabelState)
  51. l := list.Last
  52. list.Last = v
  53. l.Next = v
  54. v.Prev = l
  55. }
  56. }
  57. func removeLinkLabelState(pc Context, d *linkLabelState) {
  58. tlist := pc.Get(linkLabelStateKey)
  59. var list *linkLabelState
  60. if tlist == nil {
  61. return
  62. }
  63. list = tlist.(*linkLabelState)
  64. if d.Prev == nil {
  65. list = d.Next
  66. if list != nil {
  67. list.First = d
  68. list.Last = d.Last
  69. list.Prev = nil
  70. pc.Set(linkLabelStateKey, list)
  71. } else {
  72. pc.Set(linkLabelStateKey, nil)
  73. }
  74. } else {
  75. d.Prev.Next = d.Next
  76. if d.Next != nil {
  77. d.Next.Prev = d.Prev
  78. }
  79. }
  80. if list != nil && d.Next == nil {
  81. list.Last = d.Prev
  82. }
  83. d.Next = nil
  84. d.Prev = nil
  85. d.First = nil
  86. d.Last = nil
  87. }
  88. type linkParser struct {
  89. }
  90. var defaultLinkParser = &linkParser{}
  91. // NewLinkParser return a new InlineParser that parses links.
  92. func NewLinkParser() InlineParser {
  93. return defaultLinkParser
  94. }
  95. func (s *linkParser) Trigger() []byte {
  96. return []byte{'!', '[', ']'}
  97. }
  98. var linkBottom = NewContextKey()
  99. func (s *linkParser) Parse(parent ast.Node, block text.Reader, pc Context) ast.Node {
  100. line, segment := block.PeekLine()
  101. if line[0] == '!' {
  102. if len(line) > 1 && line[1] == '[' {
  103. block.Advance(1)
  104. pc.Set(linkBottom, pc.LastDelimiter())
  105. return processLinkLabelOpen(block, segment.Start+1, true, pc)
  106. }
  107. return nil
  108. }
  109. if line[0] == '[' {
  110. pc.Set(linkBottom, pc.LastDelimiter())
  111. return processLinkLabelOpen(block, segment.Start, false, pc)
  112. }
  113. // line[0] == ']'
  114. tlist := pc.Get(linkLabelStateKey)
  115. if tlist == nil {
  116. return nil
  117. }
  118. last := tlist.(*linkLabelState).Last
  119. if last == nil {
  120. return nil
  121. }
  122. block.Advance(1)
  123. removeLinkLabelState(pc, last)
  124. // CommonMark spec says:
  125. // > A link label can have at most 999 characters inside the square brackets.
  126. if linkLabelStateLength(tlist.(*linkLabelState)) > 998 {
  127. ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment)
  128. return nil
  129. }
  130. if !last.IsImage && s.containsLink(last) { // a link in a link text is not allowed
  131. ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment)
  132. return nil
  133. }
  134. c := block.Peek()
  135. l, pos := block.Position()
  136. var link *ast.Link
  137. var hasValue bool
  138. if c == '(' { // normal link
  139. link = s.parseLink(parent, last, block, pc)
  140. } else if c == '[' { // reference link
  141. link, hasValue = s.parseReferenceLink(parent, last, block, pc)
  142. if link == nil && hasValue {
  143. ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment)
  144. return nil
  145. }
  146. }
  147. if link == nil {
  148. // maybe shortcut reference link
  149. block.SetPosition(l, pos)
  150. ssegment := text.NewSegment(last.Segment.Stop, segment.Start)
  151. maybeReference := block.Value(ssegment)
  152. // CommonMark spec says:
  153. // > A link label can have at most 999 characters inside the square brackets.
  154. if len(maybeReference) > 999 {
  155. ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment)
  156. return nil
  157. }
  158. ref, ok := pc.Reference(util.ToLinkReference(maybeReference))
  159. if !ok {
  160. ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment)
  161. return nil
  162. }
  163. link = ast.NewLink()
  164. s.processLinkLabel(parent, link, last, pc)
  165. link.Title = ref.Title()
  166. link.Destination = ref.Destination()
  167. }
  168. if last.IsImage {
  169. last.Parent().RemoveChild(last.Parent(), last)
  170. return ast.NewImage(link)
  171. }
  172. last.Parent().RemoveChild(last.Parent(), last)
  173. return link
  174. }
  175. func (s *linkParser) containsLink(n ast.Node) bool {
  176. if n == nil {
  177. return false
  178. }
  179. for c := n; c != nil; c = c.NextSibling() {
  180. if _, ok := c.(*ast.Link); ok {
  181. return true
  182. }
  183. if s.containsLink(c.FirstChild()) {
  184. return true
  185. }
  186. }
  187. return false
  188. }
  189. func processLinkLabelOpen(block text.Reader, pos int, isImage bool, pc Context) *linkLabelState {
  190. start := pos
  191. if isImage {
  192. start--
  193. }
  194. state := newLinkLabelState(text.NewSegment(start, pos+1), isImage)
  195. pushLinkLabelState(pc, state)
  196. block.Advance(1)
  197. return state
  198. }
  199. func (s *linkParser) processLinkLabel(parent ast.Node, link *ast.Link, last *linkLabelState, pc Context) {
  200. var bottom ast.Node
  201. if v := pc.Get(linkBottom); v != nil {
  202. bottom = v.(ast.Node)
  203. }
  204. pc.Set(linkBottom, nil)
  205. ProcessDelimiters(bottom, pc)
  206. for c := last.NextSibling(); c != nil; {
  207. next := c.NextSibling()
  208. parent.RemoveChild(parent, c)
  209. link.AppendChild(link, c)
  210. c = next
  211. }
  212. }
  213. var linkFindClosureOptions text.FindClosureOptions = text.FindClosureOptions{
  214. Nesting: false,
  215. Newline: true,
  216. Advance: true,
  217. }
  218. func (s *linkParser) parseReferenceLink(parent ast.Node, last *linkLabelState,
  219. block text.Reader, pc Context) (*ast.Link, bool) {
  220. _, orgpos := block.Position()
  221. block.Advance(1) // skip '['
  222. segments, found := block.FindClosure('[', ']', linkFindClosureOptions)
  223. if !found {
  224. return nil, false
  225. }
  226. var maybeReference []byte
  227. if segments.Len() == 1 { // avoid allocate a new byte slice
  228. maybeReference = block.Value(segments.At(0))
  229. } else {
  230. maybeReference = []byte{}
  231. for i := 0; i < segments.Len(); i++ {
  232. s := segments.At(i)
  233. maybeReference = append(maybeReference, block.Value(s)...)
  234. }
  235. }
  236. if util.IsBlank(maybeReference) { // collapsed reference link
  237. s := text.NewSegment(last.Segment.Stop, orgpos.Start-1)
  238. maybeReference = block.Value(s)
  239. }
  240. // CommonMark spec says:
  241. // > A link label can have at most 999 characters inside the square brackets.
  242. if len(maybeReference) > 999 {
  243. return nil, true
  244. }
  245. ref, ok := pc.Reference(util.ToLinkReference(maybeReference))
  246. if !ok {
  247. return nil, true
  248. }
  249. link := ast.NewLink()
  250. s.processLinkLabel(parent, link, last, pc)
  251. link.Title = ref.Title()
  252. link.Destination = ref.Destination()
  253. return link, true
  254. }
  255. func (s *linkParser) parseLink(parent ast.Node, last *linkLabelState, block text.Reader, pc Context) *ast.Link {
  256. block.Advance(1) // skip '('
  257. block.SkipSpaces()
  258. var title []byte
  259. var destination []byte
  260. var ok bool
  261. if block.Peek() == ')' { // empty link like '[link]()'
  262. block.Advance(1)
  263. } else {
  264. destination, ok = parseLinkDestination(block)
  265. if !ok {
  266. return nil
  267. }
  268. block.SkipSpaces()
  269. if block.Peek() == ')' {
  270. block.Advance(1)
  271. } else {
  272. title, ok = parseLinkTitle(block)
  273. if !ok {
  274. return nil
  275. }
  276. block.SkipSpaces()
  277. if block.Peek() == ')' {
  278. block.Advance(1)
  279. } else {
  280. return nil
  281. }
  282. }
  283. }
  284. link := ast.NewLink()
  285. s.processLinkLabel(parent, link, last, pc)
  286. link.Destination = destination
  287. link.Title = title
  288. return link
  289. }
  290. func parseLinkDestination(block text.Reader) ([]byte, bool) {
  291. block.SkipSpaces()
  292. line, _ := block.PeekLine()
  293. if block.Peek() == '<' {
  294. i := 1
  295. for i < len(line) {
  296. c := line[i]
  297. if c == '\\' && i < len(line)-1 && util.IsPunct(line[i+1]) {
  298. i += 2
  299. continue
  300. } else if c == '>' {
  301. block.Advance(i + 1)
  302. return line[1:i], true
  303. }
  304. i++
  305. }
  306. return nil, false
  307. }
  308. opened := 0
  309. i := 0
  310. for i < len(line) {
  311. c := line[i]
  312. if c == '\\' && i < len(line)-1 && util.IsPunct(line[i+1]) {
  313. i += 2
  314. continue
  315. } else if c == '(' {
  316. opened++
  317. } else if c == ')' {
  318. opened--
  319. if opened < 0 {
  320. break
  321. }
  322. } else if util.IsSpace(c) {
  323. break
  324. }
  325. i++
  326. }
  327. block.Advance(i)
  328. return line[:i], len(line[:i]) != 0
  329. }
  330. func parseLinkTitle(block text.Reader) ([]byte, bool) {
  331. block.SkipSpaces()
  332. opener := block.Peek()
  333. if opener != '"' && opener != '\'' && opener != '(' {
  334. return nil, false
  335. }
  336. closer := opener
  337. if opener == '(' {
  338. closer = ')'
  339. }
  340. block.Advance(1)
  341. segments, found := block.FindClosure(opener, closer, linkFindClosureOptions)
  342. if found {
  343. if segments.Len() == 1 {
  344. return block.Value(segments.At(0)), true
  345. }
  346. var title []byte
  347. for i := 0; i < segments.Len(); i++ {
  348. s := segments.At(i)
  349. title = append(title, block.Value(s)...)
  350. }
  351. return title, true
  352. }
  353. return nil, false
  354. }
  355. func (s *linkParser) CloseBlock(parent ast.Node, block text.Reader, pc Context) {
  356. pc.Set(linkBottom, nil)
  357. tlist := pc.Get(linkLabelStateKey)
  358. if tlist == nil {
  359. return
  360. }
  361. for s := tlist.(*linkLabelState); s != nil; {
  362. next := s.Next
  363. removeLinkLabelState(pc, s)
  364. s.Parent().ReplaceChild(s.Parent(), s, ast.NewTextSegment(s.Segment))
  365. s = next
  366. }
  367. }