summaryrefslogtreecommitdiffstats
path: root/mdit_py_plugins/colon_fence.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-29 04:29:52 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-29 04:29:52 +0000
commitfcb2f10732db61d216e2105c8154486f66b3e3ff (patch)
treeefda929db4b1543eecc583e3b7d9c0bad4cd86a6 /mdit_py_plugins/colon_fence.py
parentInitial commit. (diff)
downloadmdit-py-plugins-fcb2f10732db61d216e2105c8154486f66b3e3ff.tar.xz
mdit-py-plugins-fcb2f10732db61d216e2105c8154486f66b3e3ff.zip
Adding upstream version 0.3.3.upstream/0.3.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'mdit_py_plugins/colon_fence.py')
-rw-r--r--mdit_py_plugins/colon_fence.py132
1 files changed, 132 insertions, 0 deletions
diff --git a/mdit_py_plugins/colon_fence.py b/mdit_py_plugins/colon_fence.py
new file mode 100644
index 0000000..e2356ed
--- /dev/null
+++ b/mdit_py_plugins/colon_fence.py
@@ -0,0 +1,132 @@
+from markdown_it import MarkdownIt
+from markdown_it.common.utils import escapeHtml, unescapeAll
+from markdown_it.rules_block import StateBlock
+
+
+def colon_fence_plugin(md: MarkdownIt):
+ """This plugin directly mimics regular fences, but with `:` colons.
+
+ Example::
+
+ :::name
+ contained text
+ :::
+
+ """
+
+ md.block.ruler.before(
+ "fence",
+ "colon_fence",
+ _rule,
+ {"alt": ["paragraph", "reference", "blockquote", "list", "footnote_def"]},
+ )
+ md.add_render_rule("colon_fence", _render)
+
+
+def _rule(state: StateBlock, startLine: int, endLine: int, silent: bool):
+
+ haveEndMarker = False
+ pos = state.bMarks[startLine] + state.tShift[startLine]
+ maximum = state.eMarks[startLine]
+
+ # if it's indented more than 3 spaces, it should be a code block
+ if state.sCount[startLine] - state.blkIndent >= 4:
+ return False
+
+ if pos + 3 > maximum:
+ return False
+
+ marker = state.srcCharCode[pos]
+
+ # /* : */
+ if marker != 0x3A:
+ return False
+
+ # scan marker length
+ mem = pos
+ pos = state.skipChars(pos, marker)
+
+ length = pos - mem
+
+ if length < 3:
+ return False
+
+ markup = state.src[mem:pos]
+ params = state.src[pos:maximum]
+
+ # Since start is found, we can report success here in validation mode
+ if silent:
+ return True
+
+ # search end of block
+ nextLine = startLine
+
+ while True:
+ nextLine += 1
+ if nextLine >= endLine:
+ # unclosed block should be autoclosed by end of document.
+ # also block seems to be autoclosed by end of parent
+ break
+
+ pos = mem = state.bMarks[nextLine] + state.tShift[nextLine]
+ maximum = state.eMarks[nextLine]
+
+ if pos < maximum and state.sCount[nextLine] < state.blkIndent:
+ # non-empty line with negative indent should stop the list:
+ # - ```
+ # test
+ break
+
+ if state.srcCharCode[pos] != marker:
+ continue
+
+ if state.sCount[nextLine] - state.blkIndent >= 4:
+ # closing fence should be indented less than 4 spaces
+ continue
+
+ pos = state.skipChars(pos, marker)
+
+ # closing code fence must be at least as long as the opening one
+ if pos - mem < length:
+ continue
+
+ # make sure tail has spaces only
+ pos = state.skipSpaces(pos)
+
+ if pos < maximum:
+ continue
+
+ haveEndMarker = True
+ # found!
+ break
+
+ # If a fence has heading spaces, they should be removed from its inner block
+ length = state.sCount[startLine]
+
+ state.line = nextLine + (1 if haveEndMarker else 0)
+
+ token = state.push("colon_fence", "code", 0)
+ token.info = params
+ token.content = state.getLines(startLine + 1, nextLine, length, True)
+ token.markup = markup
+ token.map = [startLine, state.line]
+
+ return True
+
+
+def _render(self, tokens, idx, options, env):
+ token = tokens[idx]
+ info = unescapeAll(token.info).strip() if token.info else ""
+ content = escapeHtml(token.content)
+ block_name = ""
+
+ if info:
+ block_name = info.split()[0]
+
+ return (
+ "<pre><code"
+ + (f' class="block-{block_name}" ' if block_name else "")
+ + ">"
+ + content
+ + "</code></pre>\n"
+ )