#!/usr/bin/env python """ 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): !!! [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:

Note

This is the first line inside the box

You can also specify the title and CSS class of the admonition: !!! custom "Did you know?" Another line here. Outputs:

Did you know?

Another line here.

[rST]: http://docutils.sourceforge.net/docs/ref/rst/directives.html#specific-admonitions By [Tiago Serafim](http://www.tiagoserafim.com/). """ import re import markdown from markdown.util import etree class AdmonitionExtension(markdown.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(markdown.blockprocessors.BlockProcessor): CLASSNAME = 'admonition' CLASSNAME_TITLE = 'admonition-title' RE = re.compile(r'(?:^|\n)!!!\ ?([\w\-]+)(?:\ "?([^"\n]+)"?)?') def __init__(self, parser): markdown.blockprocessors.BlockProcessor.__init__(self, parser) 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', u'%s %s' % (self.CLASSNAME, klass)) 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), match.group(2) if not title: title = klass.capitalize() return klass, title def makeExtension(configs={}): return AdmonitionExtension(configs=configs)