attribute.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. package parser
  2. import (
  3. "bytes"
  4. "github.com/gomarkdown/markdown/ast"
  5. )
  6. // attribute parses a (potential) block attribute and adds it to p.
  7. func (p *Parser) attribute(data []byte) []byte {
  8. if len(data) < 3 {
  9. return data
  10. }
  11. i := 0
  12. if data[i] != '{' {
  13. return data
  14. }
  15. i++
  16. // last character must be a } otherwise it's not an attribute
  17. end := skipUntilChar(data, i, '\n')
  18. if data[end-1] != '}' {
  19. return data
  20. }
  21. i = skipSpace(data, i)
  22. b := &ast.Attribute{Attrs: make(map[string][]byte)}
  23. esc := false
  24. quote := false
  25. trail := 0
  26. Loop:
  27. for ; i < len(data); i++ {
  28. switch data[i] {
  29. case ' ', '\t', '\f', '\v':
  30. if quote {
  31. continue
  32. }
  33. chunk := data[trail+1 : i]
  34. if len(chunk) == 0 {
  35. trail = i
  36. continue
  37. }
  38. switch {
  39. case chunk[0] == '.':
  40. b.Classes = append(b.Classes, chunk[1:])
  41. case chunk[0] == '#':
  42. b.ID = chunk[1:]
  43. default:
  44. k, v := keyValue(chunk)
  45. if k != nil && v != nil {
  46. b.Attrs[string(k)] = v
  47. } else {
  48. // this is illegal in an attribute
  49. return data
  50. }
  51. }
  52. trail = i
  53. case '"':
  54. if esc {
  55. esc = !esc
  56. continue
  57. }
  58. quote = !quote
  59. case '\\':
  60. esc = !esc
  61. case '}':
  62. if esc {
  63. esc = !esc
  64. continue
  65. }
  66. chunk := data[trail+1 : i]
  67. if len(chunk) == 0 {
  68. return data
  69. }
  70. switch {
  71. case chunk[0] == '.':
  72. b.Classes = append(b.Classes, chunk[1:])
  73. case chunk[0] == '#':
  74. b.ID = chunk[1:]
  75. default:
  76. k, v := keyValue(chunk)
  77. if k != nil && v != nil {
  78. b.Attrs[string(k)] = v
  79. } else {
  80. return data
  81. }
  82. }
  83. i++
  84. break Loop
  85. default:
  86. esc = false
  87. }
  88. }
  89. p.attr = b
  90. return data[i:]
  91. }
  92. // key="value" quotes are mandatory.
  93. func keyValue(data []byte) ([]byte, []byte) {
  94. chunk := bytes.SplitN(data, []byte{'='}, 2)
  95. if len(chunk) != 2 {
  96. return nil, nil
  97. }
  98. key := chunk[0]
  99. value := chunk[1]
  100. if len(value) < 3 || len(key) == 0 {
  101. return nil, nil
  102. }
  103. if value[0] != '"' || value[len(value)-1] != '"' {
  104. return key, nil
  105. }
  106. return key, value[1 : len(value)-1]
  107. }