Index: third_party/markdown/extensions/fenced_code.py |
diff --git a/third_party/markdown/extensions/fenced_code.py b/third_party/markdown/extensions/fenced_code.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b9f0c2f2914124321060f51e129a41c7e0e8126f |
--- /dev/null |
+++ b/third_party/markdown/extensions/fenced_code.py |
@@ -0,0 +1,193 @@ |
+# markdown is released under the BSD license |
+# Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later) |
+# Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) |
+# Copyright 2004 Manfred Stienstra (the original version) |
+# |
+# All rights reserved. |
+# |
+# Redistribution and use in source and binary forms, with or without |
+# modification, are permitted provided that the following conditions are met: |
+# |
+# * Redistributions of source code must retain the above copyright |
+# notice, this list of conditions and the following disclaimer. |
+# * Redistributions in binary form must reproduce the above copyright |
+# notice, this list of conditions and the following disclaimer in the |
+# documentation and/or other materials provided with the distribution. |
+# * Neither the name of the <organization> nor the |
+# names of its contributors may be used to endorse or promote products |
+# derived from this software without specific prior written permission. |
+# |
+# THIS SOFTWARE IS PROVIDED BY THE PYTHON MARKDOWN PROJECT ''AS IS'' AND ANY |
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
+# DISCLAIMED. IN NO EVENT SHALL ANY CONTRIBUTORS TO THE PYTHON MARKDOWN PROJECT |
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
+# POSSIBILITY OF SUCH DAMAGE. |
+ |
+ |
+""" |
+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']) |
+ >>> print html |
+ <p>A paragraph before a fenced code block:</p> |
+ <pre><code>Fenced code block |
+ </code></pre> |
+ |
+Works with safe_mode also (we check this because we are using the HtmlStash): |
+ |
+ >>> print markdown.markdown(text, extensions=['fenced_code'], safe_mode='replace') |
+ <p>A paragraph before a fenced code block:</p> |
+ <pre><code>Fenced code block |
+ </code></pre> |
+ |
+Include tilde's in a code block and wrap with blank lines: |
+ |
+ >>> text = ''' |
+ ... ~~~~~~~~ |
+ ... |
+ ... ~~~~ |
+ ... ~~~~~~~~''' |
+ >>> print markdown.markdown(text, extensions=['fenced_code']) |
+ <pre><code> |
+ ~~~~ |
+ </code></pre> |
+ |
+Language tags: |
+ |
+ >>> text = ''' |
+ ... ~~~~{.python} |
+ ... # Some python code |
+ ... ~~~~''' |
+ >>> print markdown.markdown(text, extensions=['fenced_code']) |
+ <pre><code class="python"># Some python code |
+ </code></pre> |
+ |
+Optionally backticks instead of tildes as per how github's code block markdown is identified: |
+ |
+ >>> text = ''' |
+ ... ````` |
+ ... # Arbitrary code |
+ ... ~~~~~ # these tildes will not close the block |
+ ... `````''' |
+ >>> print markdown.markdown(text, extensions=['fenced_code']) |
+ <pre><code># Arbitrary code |
+ ~~~~~ # these tildes will not close the block |
+ </code></pre> |
+ |
+Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/). |
+ |
+Project website: <http://packages.python.org/Markdown/extensions/fenced_code_blocks.html> |
+Contact: markdown@freewisdom.org |
+ |
+License: BSD (see ../docs/LICENSE for details) |
+ |
+Dependencies: |
+* [Python 2.4+](http://python.org) |
+* [Markdown 2.0+](http://packages.python.org/Markdown/) |
+* [Pygments (optional)](http://pygments.org) |
+ |
+""" |
+ |
+from __future__ import absolute_import |
+from __future__ import unicode_literals |
+from . import Extension |
+from ..preprocessors import Preprocessor |
+from .codehilite import CodeHilite, CodeHiliteExtension |
+import re |
+ |
+# Global vars |
+FENCED_BLOCK_RE = re.compile( \ |
+ r'(?P<fence>^(?:~{3,}|`{3,}))[ ]*(\{?\.?(?P<lang>[a-zA-Z0-9_+-]*)\}?)?[ ]*\n(?P<code>.*?)(?<=\n)(?P=fence)[ ]*$', |
+ re.MULTILINE|re.DOTALL |
+ ) |
+CODE_WRAP = '<pre><code%s>%s</code></pre>' |
+LANG_TAG = ' class="%s"' |
+ |
+class FencedCodeExtension(Extension): |
+ |
+ def extendMarkdown(self, md, md_globals): |
+ """ Add FencedBlockPreprocessor to the Markdown instance. """ |
+ md.registerExtension(self) |
+ |
+ md.preprocessors.add('fenced_code_block', |
+ FencedBlockPreprocessor(md), |
+ ">normalize_whitespace") |
+ |
+ |
+class FencedBlockPreprocessor(Preprocessor): |
+ |
+ def __init__(self, md): |
+ super(FencedBlockPreprocessor, self).__init__(md) |
+ |
+ self.checked_for_codehilite = False |
+ self.codehilite_conf = {} |
+ |
+ def run(self, lines): |
+ """ Match and store Fenced Code Blocks in the HtmlStash. """ |
+ |
+ # Check for code hilite extension |
+ if not self.checked_for_codehilite: |
+ for ext in self.markdown.registeredExtensions: |
+ if isinstance(ext, CodeHiliteExtension): |
+ self.codehilite_conf = ext.config |
+ break |
+ |
+ self.checked_for_codehilite = True |
+ |
+ text = "\n".join(lines) |
+ while 1: |
+ m = FENCED_BLOCK_RE.search(text) |
+ if m: |
+ lang = '' |
+ if m.group('lang'): |
+ lang = LANG_TAG % m.group('lang') |
+ |
+ # If config is not empty, then the codehighlite extension |
+ # is enabled, so we call it to highlite the code |
+ if self.codehilite_conf: |
+ highliter = CodeHilite(m.group('code'), |
+ linenums=self.codehilite_conf['linenums'][0], |
+ guess_lang=self.codehilite_conf['guess_lang'][0], |
+ css_class=self.codehilite_conf['css_class'][0], |
+ style=self.codehilite_conf['pygments_style'][0], |
+ lang=(m.group('lang') or None), |
+ noclasses=self.codehilite_conf['noclasses'][0]) |
+ |
+ code = highliter.hilite() |
+ else: |
+ code = CODE_WRAP % (lang, self._escape(m.group('code'))) |
+ |
+ placeholder = self.markdown.htmlStash.store(code, safe=True) |
+ text = '%s\n%s\n%s'% (text[:m.start()], placeholder, text[m.end():]) |
+ else: |
+ break |
+ return text.split("\n") |
+ |
+ 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(configs=configs) |