summaryrefslogtreecommitdiff
path: root/src/mistune/directives/_base.py
blob: ad326c6b3afb7c6bff8b92b9a4c5890fc49ec647 (plain) (blame)
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()