ref.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. package parser
  2. import (
  3. "bytes"
  4. "fmt"
  5. "github.com/gomarkdown/markdown/ast"
  6. )
  7. // parse '(#r, text)', where r does not contain spaces, but text may (similar to a citation). Or. (!item) (!item,
  8. // subitem), for an index, (!!item) signals primary.
  9. func maybeShortRefOrIndex(p *Parser, data []byte, offset int) (int, ast.Node) {
  10. if len(data[offset:]) < 4 {
  11. return 0, nil
  12. }
  13. // short ref first
  14. data = data[offset:]
  15. i := 1
  16. switch data[i] {
  17. case '#': // cross ref
  18. i++
  19. Loop:
  20. for i < len(data) {
  21. c := data[i]
  22. switch {
  23. case c == ')':
  24. break Loop
  25. case !IsAlnum(c):
  26. if c == '_' || c == '-' || c == ':' || c == ' ' || c == ',' {
  27. i++
  28. continue
  29. }
  30. i = 0
  31. break Loop
  32. }
  33. i++
  34. }
  35. if i >= len(data) {
  36. return 0, nil
  37. }
  38. if data[i] != ')' {
  39. return 0, nil
  40. }
  41. id := data[2:i]
  42. node := &ast.CrossReference{}
  43. node.Destination = id
  44. if c := bytes.Index(id, []byte(",")); c > 0 {
  45. idpart := id[:c]
  46. suff := id[c+1:]
  47. suff = bytes.TrimSpace(suff)
  48. node.Destination = idpart
  49. node.Suffix = suff
  50. }
  51. if bytes.Index(node.Destination, []byte(" ")) > 0 {
  52. // no spaces allowed in id
  53. return 0, nil
  54. }
  55. if bytes.Index(node.Destination, []byte(",")) > 0 {
  56. // nor comma
  57. return 0, nil
  58. }
  59. return i + 1, node
  60. case '!': // index
  61. i++
  62. start := i
  63. i = skipUntilChar(data, start, ')')
  64. // did we reach the end of the buffer without a closing marker?
  65. if i >= len(data) {
  66. return 0, nil
  67. }
  68. if len(data[start:i]) < 1 {
  69. return 0, nil
  70. }
  71. idx := &ast.Index{}
  72. idx.ID = fmt.Sprintf("idxref:%d", p.indexCnt)
  73. p.indexCnt++
  74. idx.Primary = data[start] == '!'
  75. buf := data[start:i]
  76. if idx.Primary {
  77. buf = buf[1:]
  78. }
  79. items := bytes.Split(buf, []byte(","))
  80. switch len(items) {
  81. case 1:
  82. idx.Item = bytes.TrimSpace(items[0])
  83. return i + 1, idx
  84. case 2:
  85. idx.Item = bytes.TrimSpace(items[0])
  86. idx.Subitem = bytes.TrimSpace(items[1])
  87. return i + 1, idx
  88. }
  89. }
  90. return 0, nil
  91. }