link.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  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, block text.Reader, pc Context) (*ast.Link, bool) {
  219. _, orgpos := block.Position()
  220. block.Advance(1) // skip '['
  221. segments, found := block.FindClosure('[', ']', linkFindClosureOptions)
  222. if !found {
  223. return nil, false
  224. }
  225. var maybeReference []byte
  226. if segments.Len() == 1 { // avoid allocate a new byte slice
  227. maybeReference = block.Value(segments.At(0))
  228. } else {
  229. maybeReference = []byte{}
  230. for i := 0; i < segments.Len(); i++ {
  231. s := segments.At(i)
  232. maybeReference = append(maybeReference, block.Value(s)...)
  233. }
  234. }
  235. if util.IsBlank(maybeReference) { // collapsed reference link
  236. s := text.NewSegment(last.Segment.Stop, orgpos.Start-1)
  237. maybeReference = block.Value(s)
  238. }
  239. // CommonMark spec says:
  240. // > A link label can have at most 999 characters inside the square brackets.
  241. if len(maybeReference) > 999 {
  242. return nil, true
  243. }
  244. ref, ok := pc.Reference(util.ToLinkReference(maybeReference))
  245. if !ok {
  246. return nil, true
  247. }
  248. link := ast.NewLink()
  249. s.processLinkLabel(parent, link, last, pc)
  250. link.Title = ref.Title()
  251. link.Destination = ref.Destination()
  252. return link, true
  253. }
  254. func (s *linkParser) parseLink(parent ast.Node, last *linkLabelState, block text.Reader, pc Context) *ast.Link {
  255. block.Advance(1) // skip '('
  256. block.SkipSpaces()
  257. var title []byte
  258. var destination []byte
  259. var ok bool
  260. if block.Peek() == ')' { // empty link like '[link]()'
  261. block.Advance(1)
  262. } else {
  263. destination, ok = parseLinkDestination(block)
  264. if !ok {
  265. return nil
  266. }
  267. block.SkipSpaces()
  268. if block.Peek() == ')' {
  269. block.Advance(1)
  270. } else {
  271. title, ok = parseLinkTitle(block)
  272. if !ok {
  273. return nil
  274. }
  275. block.SkipSpaces()
  276. if block.Peek() == ')' {
  277. block.Advance(1)
  278. } else {
  279. return nil
  280. }
  281. }
  282. }
  283. link := ast.NewLink()
  284. s.processLinkLabel(parent, link, last, pc)
  285. link.Destination = destination
  286. link.Title = title
  287. return link
  288. }
  289. func parseLinkDestination(block text.Reader) ([]byte, bool) {
  290. block.SkipSpaces()
  291. line, _ := block.PeekLine()
  292. if block.Peek() == '<' {
  293. i := 1
  294. for i < len(line) {
  295. c := line[i]
  296. if c == '\\' && i < len(line)-1 && util.IsPunct(line[i+1]) {
  297. i += 2
  298. continue
  299. } else if c == '>' {
  300. block.Advance(i + 1)
  301. return line[1:i], true
  302. }
  303. i++
  304. }
  305. return nil, false
  306. }
  307. opened := 0
  308. i := 0
  309. for i < len(line) {
  310. c := line[i]
  311. if c == '\\' && i < len(line)-1 && util.IsPunct(line[i+1]) {
  312. i += 2
  313. continue
  314. } else if c == '(' {
  315. opened++
  316. } else if c == ')' {
  317. opened--
  318. if opened < 0 {
  319. break
  320. }
  321. } else if util.IsSpace(c) {
  322. break
  323. }
  324. i++
  325. }
  326. block.Advance(i)
  327. return line[:i], len(line[:i]) != 0
  328. }
  329. func parseLinkTitle(block text.Reader) ([]byte, bool) {
  330. block.SkipSpaces()
  331. opener := block.Peek()
  332. if opener != '"' && opener != '\'' && opener != '(' {
  333. return nil, false
  334. }
  335. closer := opener
  336. if opener == '(' {
  337. closer = ')'
  338. }
  339. block.Advance(1)
  340. segments, found := block.FindClosure(opener, closer, linkFindClosureOptions)
  341. if found {
  342. if segments.Len() == 1 {
  343. return block.Value(segments.At(0)), true
  344. }
  345. var title []byte
  346. for i := 0; i < segments.Len(); i++ {
  347. s := segments.At(i)
  348. title = append(title, block.Value(s)...)
  349. }
  350. return title, true
  351. }
  352. return nil, false
  353. }
  354. func (s *linkParser) CloseBlock(parent ast.Node, block text.Reader, pc Context) {
  355. pc.Set(linkBottom, nil)
  356. tlist := pc.Get(linkLabelStateKey)
  357. if tlist == nil {
  358. return
  359. }
  360. for s := tlist.(*linkLabelState); s != nil; {
  361. next := s.Next
  362. removeLinkLabelState(pc, s)
  363. s.Parent().ReplaceChild(s.Parent(), s, ast.NewTextSegment(s.Segment))
  364. s = next
  365. }
  366. }