From 19ea0eedcbca5189df9cf9f6ef658eade79abd79 Mon Sep 17 00:00:00 2001 From: Waylan Limberg Date: Mon, 12 May 2008 00:00:11 -0400 Subject: Added fenced_code extension and .gitignore file. --- .gitignore | 1 + mdx_fenced_code.py | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 .gitignore create mode 100644 mdx_fenced_code.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc 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'

A paragraph before a fenced code block:\\n

\\n
Fenced code block\\n
'
+
+Works with safe_mode also (we check this because we are using the HtmlStash):
+
+    >>> markdown.markdown(text, extensions=['fenced_code'], safe_mode='replace')
+    u'

A paragraph before a fenced code block:\\n

\\n
Fenced code block\\n
'
+    
+Include tilde's in a code block and wrap with blank lines:
+
+    >>> text = '''
+    ... ~~~~~~~~
+    ... 
+    ... ~~~~
+    ... 
+    ... ~~~~~~~~'''
+    >>> markdown.markdown(text, extensions=['fenced_code'])
+    u'
\\n~~~~\\n\\n
'
+
+Multiple blocks and language tags:
+
+    >>> text = '''
+    ... ~~~~
+    ... block one
+    ... ~~~~{.python}
+    ... 
+    ... ~~~~
+    ... 

block two

+ ... ~~~~{.html}''' + >>> markdown.markdown(text, extensions=['fenced_code']) + u'
block one\\n
\\n\\n
<p>block two</p>\\n
'
+
+"""
+
+import markdown, re
+
+# Global vars
+FENCED_BLOCK_RE = re.compile( \
+    r'(?P^~{3,})[ ]*\n(?P.*?)(?P=fence)[ ]*(\{\.(?P[a-zA-Z0-9_-]*)\})?[ ]*$', 
+    re.MULTILINE|re.DOTALL
+    )
+CODE_WRAP = '
%s
'
+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()
-- 
cgit v1.2.3