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