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
|
from markdown_it import MarkdownIt
from markdown_it.rules_block import StateBlock
from markdown_it.rules_inline import StateInline
from mdit_py_plugins.utils import is_code_block
def substitution_plugin(
md: MarkdownIt, start_delimiter: str = "{", end_delimiter: str = "}"
) -> None:
"""A plugin to create substitution tokens.
These, token should be handled by the renderer.
Example::
{{ block }}
a {{ inline }} b
"""
def _substitution_inline(state: StateInline, silent: bool) -> bool:
try:
if (
state.src[state.pos] != start_delimiter
or state.src[state.pos + 1] != start_delimiter
):
return False
except IndexError:
return False
pos = state.pos + 2
found_closing = False
while True:
try:
end = state.src.index(end_delimiter, pos)
except ValueError:
return False
try:
if state.src[end + 1] == end_delimiter:
found_closing = True
break
except IndexError:
return False
pos = end + 2
if not found_closing:
return False
text = state.src[state.pos + 2 : end].strip()
state.pos = end + 2
if silent:
return True
token = state.push("substitution_inline", "span", 0)
token.block = False
token.content = text
token.attrSet("class", "substitution")
token.attrSet("text", text)
token.markup = f"{start_delimiter}{end_delimiter}"
return True
def _substitution_block(
state: StateBlock, startLine: int, endLine: int, silent: bool
) -> bool:
if is_code_block(state, startLine):
return False
startPos = state.bMarks[startLine] + state.tShift[startLine]
end = state.eMarks[startLine]
lineText = state.src[startPos:end].strip()
try:
if (
lineText[0] != start_delimiter
or lineText[1] != start_delimiter
or lineText[-1] != end_delimiter
or lineText[-2] != end_delimiter
or len(lineText) < 5
):
return False
except IndexError:
return False
text = lineText[2:-2].strip()
# special case if multiple on same line, e.g. {{a}}{{b}}
if (end_delimiter * 2) in text:
return False
state.line = startLine + 1
if silent:
return True
token = state.push("substitution_block", "div", 0)
token.block = True
token.content = text
token.attrSet("class", "substitution")
token.attrSet("text", text)
token.markup = f"{start_delimiter}{end_delimiter}"
token.map = [startLine, state.line]
return True
md.block.ruler.before("fence", "substitution_block", _substitution_block)
md.inline.ruler.before("escape", "substitution_inline", _substitution_inline)
|