File: __init__.py

package info (click to toggle)
mdit-py-plugins 0.5.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 692 kB
  • sloc: python: 3,702; sh: 8; makefile: 7
file content (117 lines) | stat: -rw-r--r-- 3,059 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
"""
Markdown-it-py plugin to introduce <sub> markup using ~subscript~.

Ported from
https://github.com/markdown-it/markdown-it-sub/blob/master/index.mjs

Originally ported during implementation of https://github.com/hasgeek/funnel/blob/main/funnel/utils/markdown/mdit_plugins/sub_tag.py
"""

from __future__ import annotations

from collections.abc import Sequence
import re

from markdown_it import MarkdownIt
from markdown_it.renderer import RendererHTML
from markdown_it.rules_inline import StateInline
from markdown_it.token import Token
from markdown_it.utils import EnvType, OptionsDict

__all__ = ["sub_plugin"]

TILDE_CHAR = "~"

WHITESPACE_RE = re.compile(r"(^|[^\\])(\\\\)*\s")
UNESCAPE_RE = re.compile(r'\\([ \\!"#$%&\'()*+,.\/:;<=>?@[\]^_`{|}~-])')


def tokenize(state: StateInline, silent: bool) -> bool:
    """Parse a ~subscript~ token."""
    start = state.pos
    ch = state.src[start]
    maximum = state.posMax
    found = False

    # Don't run any pairs in validation mode
    if silent:
        return False

    if ch != TILDE_CHAR:
        return False

    if start + 2 >= maximum:
        return False

    state.pos = start + 1

    while state.pos < maximum:
        if state.src[state.pos] == TILDE_CHAR:
            found = True
            break
        state.md.inline.skipToken(state)

    if not found or start + 1 == state.pos:
        state.pos = start
        return False

    content = state.src[start + 1 : state.pos]

    # Don't allow unescaped spaces/newlines inside
    if WHITESPACE_RE.search(content) is not None:
        state.pos = start
        return False

    # Found a valid pair, so update posMax and pos
    state.posMax = state.pos
    state.pos = start + 1

    # Earlier we checked "not silent", but this implementation does not need it
    token = state.push("sub_open", "sub", 1)
    token.markup = TILDE_CHAR

    token = state.push("text", "", 0)
    token.content = UNESCAPE_RE.sub(r"\1", content)

    token = state.push("sub_close", "sub", -1)
    token.markup = TILDE_CHAR

    state.pos = state.posMax + 1
    state.posMax = maximum
    return True


def sub_open(
    renderer: RendererHTML,
    tokens: Sequence[Token],
    idx: int,
    options: OptionsDict,
    env: EnvType,
) -> str:
    """Render the opening tag for a ~subscript~ token."""
    return "<sub>"


def sub_close(
    renderer: RendererHTML,
    tokens: Sequence[Token],
    idx: int,
    options: OptionsDict,
    env: EnvType,
) -> str:
    """Render the closing tag for a ~subscript~ token."""
    return "</sub>"


def sub_plugin(md: MarkdownIt) -> None:
    """
    Markdown-it-py plugin to introduce <sub> markup using ~subscript~.

    Ported from
    https://github.com/markdown-it/markdown-it-sub/blob/master/index.mjs

    Originally ported during implementation of https://github.com/hasgeek/funnel/blob/main/funnel/utils/markdown/mdit_plugins/sub_tag.py
    """
    md.inline.ruler.after("emphasis", "sub", tokenize)
    md.add_render_rule("sub_open", sub_open)
    md.add_render_rule("sub_close", sub_close)