File: parse.py

package info (click to toggle)
sphinx-mdinclude 0.6.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 380 kB
  • sloc: python: 1,242; makefile: 53; sh: 8
file content (97 lines) | stat: -rw-r--r-- 3,473 bytes parent folder | download
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
from typing import Any, Dict, Match, Tuple

from mistune import BlockParser, InlineParser
from mistune.core import BlockState, InlineState
from mistune.helpers import HTML_ATTRIBUTES, HTML_TAGNAME


State = Dict[str, Any]
Token = Dict[str, Any]
Element = Tuple[str, ...]


class RestBlockParser(BlockParser):
    SPECIFICATION = BlockParser.SPECIFICATION.copy()
    SPECIFICATION.update(
        {
            "directive": r"(?ms:^(?P<directive_1> *\.\..*?)\n(?=\S))",
            "oneline_directive": r"(?ms:^(?P<directive_2> *\.\..*?)$)",
            "rest_code_block": r"(?m:^::\s*$)",
        }
    )

    DEFAULT_RULES = BlockParser.DEFAULT_RULES + (  # type: ignore[has-type]
        "directive",
        "oneline_directive",
        "rest_code_block",
    )

    def parse_directive(self, m: Match[str], state: BlockState) -> int:
        state.append_token({"type": "directive", "raw": m.group("directive_1")})
        return m.end()

    def parse_oneline_directive(self, m: Match[str], state: BlockState) -> int:
        # reuse directive output
        state.append_token({"type": "directive", "raw": m.group("directive_2")})
        # $ does not count '\n'
        return m.end() + 1

    def parse_rest_code_block(self, m: Match[str], state: BlockState) -> int:
        state.append_token({"type": "rest_code_block", "text": ""})
        # $ does not count '\n'
        return m.end() + 1


class RestInlineParser(InlineParser):
    # make inline_html span open/contents/close instead of just a single tag
    INLINE_HTML = (
        r"(?<!\\)<" + HTML_TAGNAME + HTML_ATTRIBUTES + r"\s*>"  # open tag
        r"(.*)"
        r"(?<!\\)</" + HTML_TAGNAME + r"\s*>|"  # close tag
        r"(?<!\\)<" + HTML_TAGNAME + HTML_ATTRIBUTES + r"\s*/>|"  # open/close tag
        r"(?<!\\)<\?[\s\S]+?\?>|"
        r"(?<!\\)<![A-Z][\s\S]+?>|"  # doctype
        r"(?<!\\)<!\[CDATA[\s\S]+?\]\]>"  # cdata
    )

    SPECIFICATION = InlineParser.SPECIFICATION.copy()
    SPECIFICATION.update(
        {
            "inline_html": INLINE_HTML,
            "inline_math": r"`\$(?P<math_1>.*?)\$`",
            "rest_role": r":.*?:`.*?`|`[^`]+`:.*?:",
            "rest_link": r"`[^`]*?`_",
            "eol_literal_marker": r"(?P<eol_space>\s+)?::\s*$",
        }
    )

    # Order is important: need these rules to be checked before the
    # default rules
    DEFAULT_RULES = (
        "inline_math",
        "rest_role",
        "rest_link",
        "eol_literal_marker",
    ) + InlineParser.DEFAULT_RULES  # type: ignore[has-type]

    def parse_rest_role(self, m: Match[str], state: InlineState) -> int:
        """Pass through rest role."""
        state.append_token({"type": "rest_role", "raw": m.group(0)})
        return m.end()

    def parse_rest_link(self, m: Match[str], state: InlineState) -> int:
        """Pass through rest link."""
        state.append_token({"type": "rest_link", "raw": m.group(0)})
        return m.end()

    def parse_inline_math(self, m: Match[str], state: InlineState) -> int:
        """Pass through inline math."""
        state.append_token({"type": "inline_math", "raw": m.group("math_1")})
        return m.end()

    def parse_eol_literal_marker(self, m: Match[str], state: InlineState) -> int:
        """Pass through rest link."""
        marker = ":" if m.group("eol_space") is None else ""
        state.append_token({"type": "eol_literal_marker", "raw": marker})
        # $ does not count '\n'
        return m.end() + 1