about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/markdown/extensions/admonition.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/markdown/extensions/admonition.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/markdown/extensions/admonition.py')
-rw-r--r--.venv/lib/python3.12/site-packages/markdown/extensions/admonition.py183
1 files changed, 183 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/markdown/extensions/admonition.py b/.venv/lib/python3.12/site-packages/markdown/extensions/admonition.py
new file mode 100644
index 00000000..01c2316d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/markdown/extensions/admonition.py
@@ -0,0 +1,183 @@
+# Admonition extension for Python-Markdown
+# ========================================
+
+# Adds rST-style admonitions. Inspired by [rST][] feature with the same name.
+
+# [rST]: http://docutils.sourceforge.net/docs/ref/rst/directives.html#specific-admonitions
+
+# See https://Python-Markdown.github.io/extensions/admonition
+# for documentation.
+
+# Original code Copyright [Tiago Serafim](https://www.tiagoserafim.com/).
+
+# All changes Copyright The Python Markdown Project
+
+# License: [BSD](https://opensource.org/licenses/bsd-license.php)
+
+
+"""
+Adds rST-style admonitions. Inspired by [rST][] feature with the same name.
+
+[rST]: http://docutils.sourceforge.net/docs/ref/rst/directives.html#specific-admonitions
+
+See the [documentation](https://Python-Markdown.github.io/extensions/admonition)
+for details.
+"""
+
+from __future__ import annotations
+
+from . import Extension
+from ..blockprocessors import BlockProcessor
+import xml.etree.ElementTree as etree
+import re
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:  # pragma: no cover
+    from markdown import blockparser
+
+
+class AdmonitionExtension(Extension):
+    """ Admonition extension for Python-Markdown. """
+
+    def extendMarkdown(self, md):
+        """ Add Admonition to Markdown instance. """
+        md.registerExtension(self)
+
+        md.parser.blockprocessors.register(AdmonitionProcessor(md.parser), 'admonition', 105)
+
+
+class AdmonitionProcessor(BlockProcessor):
+
+    CLASSNAME = 'admonition'
+    CLASSNAME_TITLE = 'admonition-title'
+    RE = re.compile(r'(?:^|\n)!!! ?([\w\-]+(?: +[\w\-]+)*)(?: +"(.*?)")? *(?:\n|$)')
+    RE_SPACES = re.compile('  +')
+
+    def __init__(self, parser: blockparser.BlockParser):
+        """Initialization."""
+
+        super().__init__(parser)
+
+        self.current_sibling: etree.Element | None = None
+        self.content_indent = 0
+
+    def parse_content(self, parent: etree.Element, block: str) -> tuple[etree.Element | None, str, str]:
+        """Get sibling admonition.
+
+        Retrieve the appropriate sibling element. This can get tricky when
+        dealing with lists.
+
+        """
+
+        old_block = block
+        the_rest = ''
+
+        # We already acquired the block via test
+        if self.current_sibling is not None:
+            sibling = self.current_sibling
+            block, the_rest = self.detab(block, self.content_indent)
+            self.current_sibling = None
+            self.content_indent = 0
+            return sibling, block, the_rest
+
+        sibling = self.lastChild(parent)
+
+        if sibling is None or sibling.tag != 'div' or sibling.get('class', '').find(self.CLASSNAME) == -1:
+            sibling = None
+        else:
+            # If the last child is a list and the content is sufficiently indented
+            # to be under it, then the content's sibling is in the list.
+            last_child = self.lastChild(sibling)
+            indent = 0
+            while last_child is not None:
+                if (
+                    sibling is not None and block.startswith(' ' * self.tab_length * 2) and
+                    last_child is not None and last_child.tag in ('ul', 'ol', 'dl')
+                ):
+
+                    # The expectation is that we'll find an `<li>` or `<dt>`.
+                    # We should get its last child as well.
+                    sibling = self.lastChild(last_child)
+                    last_child = self.lastChild(sibling) if sibling is not None else None
+
+                    # Context has been lost at this point, so we must adjust the
+                    # text's indentation level so it will be evaluated correctly
+                    # under the list.
+                    block = block[self.tab_length:]
+                    indent += self.tab_length
+                else:
+                    last_child = None
+
+            if not block.startswith(' ' * self.tab_length):
+                sibling = None
+
+            if sibling is not None:
+                indent += self.tab_length
+                block, the_rest = self.detab(old_block, indent)
+                self.current_sibling = sibling
+                self.content_indent = indent
+
+        return sibling, block, the_rest
+
+    def test(self, parent: etree.Element, block: str) -> bool:
+
+        if self.RE.search(block):
+            return True
+        else:
+            return self.parse_content(parent, block)[0] is not None
+
+    def run(self, parent: etree.Element, blocks: list[str]) -> None:
+        block = blocks.pop(0)
+        m = self.RE.search(block)
+
+        if m:
+            if m.start() > 0:
+                self.parser.parseBlocks(parent, [block[:m.start()]])
+            block = block[m.end():]  # removes the first line
+            block, theRest = self.detab(block)
+        else:
+            sibling, block, theRest = self.parse_content(parent, block)
+
+        if m:
+            klass, title = self.get_class_and_title(m)
+            div = etree.SubElement(parent, 'div')
+            div.set('class', '{} {}'.format(self.CLASSNAME, klass))
+            if title:
+                p = etree.SubElement(div, 'p')
+                p.text = title
+                p.set('class', self.CLASSNAME_TITLE)
+        else:
+            # Sibling is a list item, but we need to wrap it's content should be wrapped in <p>
+            if sibling.tag in ('li', 'dd') and sibling.text:
+                text = sibling.text
+                sibling.text = ''
+                p = etree.SubElement(sibling, 'p')
+                p.text = text
+
+            div = sibling
+
+        self.parser.parseChunk(div, block)
+
+        if theRest:
+            # This block contained unindented line(s) after the first indented
+            # line. Insert these lines as the first block of the master blocks
+            # list for future processing.
+            blocks.insert(0, theRest)
+
+    def get_class_and_title(self, match: re.Match[str]) -> tuple[str, str | None]:
+        klass, title = match.group(1).lower(), match.group(2)
+        klass = self.RE_SPACES.sub(' ', klass)
+        if title is None:
+            # no title was provided, use the capitalized class name as title
+            # e.g.: `!!! note` will render
+            # `<p class="admonition-title">Note</p>`
+            title = klass.split(' ', 1)[0].capitalize()
+        elif title == '':
+            # an explicit blank title should not be rendered
+            # e.g.: `!!! warning ""` will *not* render `p` with a title
+            title = None
+        return klass, title
+
+
+def makeExtension(**kwargs):  # pragma: no cover
+    return AdmonitionExtension(**kwargs)