File: index.py

package info (click to toggle)
mdit-py-plugins 0.4.2-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 672 kB
  • sloc: python: 3,595; sh: 8; makefile: 7
file content (128 lines) | stat: -rw-r--r-- 3,360 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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
"""Process front matter."""

from markdown_it import MarkdownIt
from markdown_it.rules_block import StateBlock

from mdit_py_plugins.utils import is_code_block


def front_matter_plugin(md: MarkdownIt) -> None:
    """Plugin ported from
    `markdown-it-front-matter <https://github.com/ParkSB/markdown-it-front-matter>`__.

    It parses initial metadata, stored between opening/closing dashes:

    .. code-block:: md

        ---
        valid-front-matter: true
        ---

    """
    md.block.ruler.before(
        "table",
        "front_matter",
        _front_matter_rule,
        {"alt": ["paragraph", "reference", "blockquote", "list"]},
    )


def _front_matter_rule(
    state: StateBlock, startLine: int, endLine: int, silent: bool
) -> bool:
    marker_chr = "-"
    min_markers = 3

    auto_closed = False
    start = state.bMarks[startLine] + state.tShift[startLine]
    maximum = state.eMarks[startLine]
    src_len = len(state.src)

    # Check out the first character of the first line quickly,
    # this should filter out non-front matter
    if startLine != 0 or state.src[0] != marker_chr:
        return False

    # Check out the rest of the marker string
    # while pos <= 3
    pos = start + 1
    while pos <= maximum and pos < src_len:
        if state.src[pos] != marker_chr:
            break
        pos += 1

    marker_count = pos - start

    if marker_count < min_markers:
        return False

    # Since start is found, we can report success here in validation mode
    if silent:
        return True

    # Search for the end of the block
    nextLine = startLine

    while True:
        nextLine += 1
        if nextLine >= endLine:
            # unclosed block should be autoclosed by end of document.
            return False

        if state.src[start:maximum] == "...":
            break

        start = state.bMarks[nextLine] + state.tShift[nextLine]
        maximum = state.eMarks[nextLine]

        if start < maximum and state.sCount[nextLine] < state.blkIndent:
            # non-empty line with negative indent should stop the list:
            # - ```
            #  test
            break

        if state.src[start] != marker_chr:
            continue

        if is_code_block(state, nextLine):
            continue

        pos = start + 1
        while pos < maximum:
            if state.src[pos] != marker_chr:
                break
            pos += 1

        # closing code fence must be at least as long as the opening one
        if (pos - start) < marker_count:
            continue

        # make sure tail has spaces only
        pos = state.skipSpaces(pos)

        if pos < maximum:
            continue

        # found!
        auto_closed = True
        break

    old_parent = state.parentType
    old_line_max = state.lineMax
    state.parentType = "container"

    # this will prevent lazy continuations from ever going past our end marker
    state.lineMax = nextLine

    token = state.push("front_matter", "", 0)
    token.hidden = True
    token.markup = marker_chr * min_markers
    token.content = state.src[state.bMarks[startLine + 1] : state.eMarks[nextLine - 1]]
    token.block = True

    state.parentType = old_parent
    state.lineMax = old_line_max
    state.line = nextLine + (1 if auto_closed else 0)
    token.map = [startLine, state.line]

    return True