diff options
Diffstat (limited to 'mdx_fenced_code.py')
-rw-r--r-- | mdx_fenced_code.py | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/mdx_fenced_code.py b/mdx_fenced_code.py new file mode 100644 index 0000000..4b0e406 --- /dev/null +++ b/mdx_fenced_code.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python + +""" +Fenced Code Extension for Python Markdown +========================================= + +This extension adds Fenced Code Blocks to Python-Markdown. + + >>> import markdown + >>> text = ''' + ... A paragraph before a fenced code block: + ... + ... ~~~ + ... Fenced code block + ... ~~~ + ... ''' + >>> html = markdown.markdown(text, extensions=['fenced_code']) + >>> html + u'<p>A paragraph before a fenced code block:\\n</p>\\n<pre><code>Fenced code block\\n<code><pre>' + +Works with safe_mode also (we check this because we are using the HtmlStash): + + >>> markdown.markdown(text, extensions=['fenced_code'], safe_mode='replace') + u'<p>A paragraph before a fenced code block:\\n</p>\\n<pre><code>Fenced code block\\n<code><pre>' + +Include tilde's in a code block and wrap with blank lines: + + >>> text = ''' + ... ~~~~~~~~ + ... + ... ~~~~ + ... + ... ~~~~~~~~''' + >>> markdown.markdown(text, extensions=['fenced_code']) + u'<pre><code>\\n~~~~\\n\\n<code><pre>' + +Multiple blocks and language tags: + + >>> text = ''' + ... ~~~~ + ... block one + ... ~~~~{.python} + ... + ... ~~~~ + ... <p>block two</p> + ... ~~~~{.html}''' + >>> markdown.markdown(text, extensions=['fenced_code']) + u'<pre><code class="python">block one\\n<code><pre>\\n\\n<pre><code class="html"><p>block two</p>\\n<code><pre>' + +""" + +import markdown, re + +# Global vars +FENCED_BLOCK_RE = re.compile( \ + r'(?P<fence>^~{3,})[ ]*\n(?P<code>.*?)(?P=fence)[ ]*(\{\.(?P<lang>[a-zA-Z0-9_-]*)\})?[ ]*$', + re.MULTILINE|re.DOTALL + ) +CODE_WRAP = '<pre><code%s>%s<code><pre>' +LANG_TAG = ' class="%s"' + + +class FencedCodeExtension(markdown.Extension): + + def extendMarkdown(self, md, md_globals): + """ Add FencedBlockPreprocessor to the Markdown instance. """ + + FENCED_BLOCK_PREPROCESSOR = FencedBlockPreprocessor() + FENCED_BLOCK_PREPROCESSOR.md = md + md.textPreprocessors.insert(0, FENCED_BLOCK_PREPROCESSOR) + + +class FencedBlockPreprocessor(markdown.TextPreprocessor): + + def run(self, text): + """ Match and store Fenced Code Blocks in the HtmlStash. """ + while 1: + m = FENCED_BLOCK_RE.search(text) + if m: + lang = '' + if m.group('lang'): + lang = LANG_TAG % m.group('lang') + code = CODE_WRAP % (lang, self._escape(m.group('code'))) + placeholder = self.md.htmlStash.store(code, safe=True) + text = '%s\n%s\n%s'% (text[:m.start()], placeholder, text[m.end():]) + else: + break + return text + + def _escape(self, txt): + """ basic html escaping """ + txt = txt.replace('&', '&') + txt = txt.replace('<', '<') + txt = txt.replace('>', '>') + txt = txt.replace('"', '"') + return txt + + +def makeExtension(configs=None): + return FencedCodeExtension() + + +if __name__ == "__main__": + import doctest + doctest.testmod() |