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
117
118
119
120
121
|
import re
class DirectiveParser:
name = 'directive'
@staticmethod
def parse_type(m: re.Match):
raise NotImplementedError()
@staticmethod
def parse_title(m: re.Match):
raise NotImplementedError()
@staticmethod
def parse_content(m: re.Match):
raise NotImplementedError()
@classmethod
def parse_tokens(cls, block, text, state):
if state.depth() >= block.max_nested_level - 1 and cls.name in block.rules:
rules = list(block.rules)
rules.remove(cls.name)
else:
rules = block.rules
child = state.child_state(text)
block.parse(child, rules)
return child.tokens
@staticmethod
def parse_options(m: re.Match):
text = m.group('options')
if not text.strip():
return []
options = []
for line in re.split(r'\n+', text):
line = line.strip()[1:]
if not line:
continue
i = line.find(':')
k = line[:i]
v = line[i + 1:].strip()
options.append((k, v))
return options
class BaseDirective:
parser = DirectiveParser
directive_pattern = None
def __init__(self, plugins):
self._methods = {}
self.__plugins = plugins
def register(self, name, fn):
self._methods[name] = fn
def parse_method(self, block, m, state):
_type = self.parser.parse_type(m)
method = self._methods.get(_type)
if method:
try:
token = method(block, m, state)
except ValueError as e:
token = {'type': 'block_error', 'raw': str(e)}
else:
text = m.group(0)
token = {
'type': 'block_error',
'raw': text,
}
if isinstance(token, list):
for tok in token:
state.append_token(tok)
else:
state.append_token(token)
return token
def parse_directive(self, block, m, state):
raise NotImplementedError()
def register_block_parser(self, md, before=None):
md.block.register(
self.parser.name,
self.directive_pattern,
self.parse_directive,
before=before,
)
def __call__(self, md):
for plugin in self.__plugins:
plugin.parser = self.parser
plugin(self, md)
class DirectivePlugin:
def __init__(self):
self.parser = None
def parse_options(self, m: re.Match):
return self.parser.parse_options(m)
def parse_type(self, m: re.Match):
return self.parser.parse_type(m)
def parse_title(self, m: re.Match):
return self.parser.parse_title(m)
def parse_content(self, m: re.Match):
return self.parser.parse_content(m)
def parse_tokens(self, block, text, state):
return self.parser.parse_tokens(block, text, state)
def parse(self, block, m, state):
raise NotImplementedError()
def __call__(self, md):
raise NotImplementedError()
|