# 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. """ Admonition extension for Python-Markdown ======================================== Adds rST-style admonitions. Inspired by [rST][] feature with the same name. The syntax is (followed by an indented block with the contents): !!! [type] [optional explicit title] Where `type` is used as a CSS class name of the div. If not present, `title` defaults to the capitalized `type`, so "note" -> "Note". rST suggests the following `types`, but you're free to use whatever you want: attention, caution, danger, error, hint, important, note, tip, warning A simple example: !!! note This is the first line inside the box. Outputs: <div class="admonition note"> <p class="admonition-title">Note</p> <p>This is the first line inside the box</p> </div> You can also specify the title and CSS class of the admonition: !!! custom "Did you know?" Another line here. Outputs: <div class="admonition custom"> <p class="admonition-title">Did you know?</p> <p>Another line here.</p> </div> [rST]: http://docutils.sourceforge.net/docs/ref/rst/directives.html#specific-admonitions By [Tiago Serafim](http://www.tiagoserafim.com/). """ from __future__ import absolute_import from __future__ import unicode_literals from . import Extension from ..blockprocessors import BlockProcessor from ..util import etree import re class AdmonitionExtension(Extension): """ Admonition extension for Python-Markdown. """ def extendMarkdown(self, md, md_globals): """ Add Admonition to Markdown instance. """ md.registerExtension(self) md.parser.blockprocessors.add('admonition', AdmonitionProcessor(md.parser), '_begin') class AdmonitionProcessor(BlockProcessor): CLASSNAME = 'admonition' CLASSNAME_TITLE = 'admonition-title' RE = re.compile(r'(?:^|\n)!!!\ ?([\w\-]+)(?:\ "(.*?)")?') def test(self, parent, block): sibling = self.lastChild(parent) return self.RE.search(block) or \ (block.startswith(' ' * self.tab_length) and sibling and \ sibling.get('class', '').find(self.CLASSNAME) != -1) def run(self, parent, blocks): sibling = self.lastChild(parent) block = blocks.pop(0) m = self.RE.search(block) if m: block = block[m.end() + 1:] # removes the first line block, theRest = self.detab(block) if m: klass, title = self.get_class_and_title(m) div = etree.SubElement(parent, 'div') div.set('class', '%s %s' % (self.CLASSNAME, klass)) if title: p = etree.SubElement(div, 'p') p.text = title p.set('class', self.CLASSNAME_TITLE) else: 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): klass, title = match.group(1).lower(), match.group(2) if title is None: # no title was provided, use the capitalized classname as title # e.g.: `!!! note` will render `<p class="admonition-title">Note</p>` title = klass.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(configs={}): return AdmonitionExtension(configs=configs)