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)
|