OLD | NEW |
| (Empty) |
1 """ | |
2 Admonition extension for Python-Markdown | |
3 ======================================== | |
4 | |
5 Adds rST-style admonitions. Inspired by [rST][] feature with the same name. | |
6 | |
7 [rST]: http://docutils.sourceforge.net/docs/ref/rst/directives.html#specific-adm
onitions # noqa | |
8 | |
9 See <https://pythonhosted.org/Markdown/extensions/admonition.html> | |
10 for documentation. | |
11 | |
12 Original code Copyright [Tiago Serafim](http://www.tiagoserafim.com/). | |
13 | |
14 All changes Copyright The Python Markdown Project | |
15 | |
16 License: [BSD](http://www.opensource.org/licenses/bsd-license.php) | |
17 | |
18 """ | |
19 | |
20 from __future__ import absolute_import | |
21 from __future__ import unicode_literals | |
22 from . import Extension | |
23 from ..blockprocessors import BlockProcessor | |
24 from ..util import etree | |
25 import re | |
26 | |
27 | |
28 class AdmonitionExtension(Extension): | |
29 """ Admonition extension for Python-Markdown. """ | |
30 | |
31 def extendMarkdown(self, md, md_globals): | |
32 """ Add Admonition to Markdown instance. """ | |
33 md.registerExtension(self) | |
34 | |
35 md.parser.blockprocessors.add('admonition', | |
36 AdmonitionProcessor(md.parser), | |
37 '_begin') | |
38 | |
39 | |
40 class AdmonitionProcessor(BlockProcessor): | |
41 | |
42 CLASSNAME = 'admonition' | |
43 CLASSNAME_TITLE = 'admonition-title' | |
44 RE = re.compile(r'(?:^|\n)!!!\ ?([\w\-]+)(?:\ "(.*?)")?') | |
45 | |
46 def test(self, parent, block): | |
47 sibling = self.lastChild(parent) | |
48 return self.RE.search(block) or \ | |
49 (block.startswith(' ' * self.tab_length) and sibling is not None and | |
50 sibling.get('class', '').find(self.CLASSNAME) != -1) | |
51 | |
52 def run(self, parent, blocks): | |
53 sibling = self.lastChild(parent) | |
54 block = blocks.pop(0) | |
55 m = self.RE.search(block) | |
56 | |
57 if m: | |
58 block = block[m.end() + 1:] # removes the first line | |
59 | |
60 block, theRest = self.detab(block) | |
61 | |
62 if m: | |
63 klass, title = self.get_class_and_title(m) | |
64 div = etree.SubElement(parent, 'div') | |
65 div.set('class', '%s %s' % (self.CLASSNAME, klass)) | |
66 if title: | |
67 p = etree.SubElement(div, 'p') | |
68 p.text = title | |
69 p.set('class', self.CLASSNAME_TITLE) | |
70 else: | |
71 div = sibling | |
72 | |
73 self.parser.parseChunk(div, block) | |
74 | |
75 if theRest: | |
76 # This block contained unindented line(s) after the first indented | |
77 # line. Insert these lines as the first block of the master blocks | |
78 # list for future processing. | |
79 blocks.insert(0, theRest) | |
80 | |
81 def get_class_and_title(self, match): | |
82 klass, title = match.group(1).lower(), match.group(2) | |
83 if title is None: | |
84 # no title was provided, use the capitalized classname as title | |
85 # e.g.: `!!! note` will render | |
86 # `<p class="admonition-title">Note</p>` | |
87 title = klass.capitalize() | |
88 elif title == '': | |
89 # an explicit blank title should not be rendered | |
90 # e.g.: `!!! warning ""` will *not* render `p` with a title | |
91 title = None | |
92 return klass, title | |
93 | |
94 | |
95 def makeExtension(*args, **kwargs): | |
96 return AdmonitionExtension(*args, **kwargs) | |
OLD | NEW |