OLD | NEW |
| (Empty) |
1 """ | |
2 Definition List Extension for Python-Markdown | |
3 ============================================= | |
4 | |
5 Adds parsing of Definition Lists to Python-Markdown. | |
6 | |
7 See <https://pythonhosted.org/Markdown/extensions/definition_lists.html> | |
8 for documentation. | |
9 | |
10 Original code Copyright 2008 [Waylan Limberg](http://achinghead.com) | |
11 | |
12 All changes Copyright 2008-2014 The Python Markdown Project | |
13 | |
14 License: [BSD](http://www.opensource.org/licenses/bsd-license.php) | |
15 | |
16 """ | |
17 | |
18 from __future__ import absolute_import | |
19 from __future__ import unicode_literals | |
20 from . import Extension | |
21 from ..blockprocessors import BlockProcessor, ListIndentProcessor | |
22 from ..util import etree | |
23 import re | |
24 | |
25 | |
26 class DefListProcessor(BlockProcessor): | |
27 """ Process Definition Lists. """ | |
28 | |
29 RE = re.compile(r'(^|\n)[ ]{0,3}:[ ]{1,3}(.*?)(\n|$)') | |
30 NO_INDENT_RE = re.compile(r'^[ ]{0,3}[^ :]') | |
31 | |
32 def test(self, parent, block): | |
33 return bool(self.RE.search(block)) | |
34 | |
35 def run(self, parent, blocks): | |
36 | |
37 raw_block = blocks.pop(0) | |
38 m = self.RE.search(raw_block) | |
39 terms = [l.strip() for l in | |
40 raw_block[:m.start()].split('\n') if l.strip()] | |
41 block = raw_block[m.end():] | |
42 no_indent = self.NO_INDENT_RE.match(block) | |
43 if no_indent: | |
44 d, theRest = (block, None) | |
45 else: | |
46 d, theRest = self.detab(block) | |
47 if d: | |
48 d = '%s\n%s' % (m.group(2), d) | |
49 else: | |
50 d = m.group(2) | |
51 sibling = self.lastChild(parent) | |
52 if not terms and sibling is None: | |
53 # This is not a definition item. Most likely a paragraph that | |
54 # starts with a colon at the begining of a document or list. | |
55 blocks.insert(0, raw_block) | |
56 return False | |
57 if not terms and sibling.tag == 'p': | |
58 # The previous paragraph contains the terms | |
59 state = 'looselist' | |
60 terms = sibling.text.split('\n') | |
61 parent.remove(sibling) | |
62 # Aquire new sibling | |
63 sibling = self.lastChild(parent) | |
64 else: | |
65 state = 'list' | |
66 | |
67 if sibling is not None and sibling.tag == 'dl': | |
68 # This is another item on an existing list | |
69 dl = sibling | |
70 if not terms and len(dl) and dl[-1].tag == 'dd' and len(dl[-1]): | |
71 state = 'looselist' | |
72 else: | |
73 # This is a new list | |
74 dl = etree.SubElement(parent, 'dl') | |
75 # Add terms | |
76 for term in terms: | |
77 dt = etree.SubElement(dl, 'dt') | |
78 dt.text = term | |
79 # Add definition | |
80 self.parser.state.set(state) | |
81 dd = etree.SubElement(dl, 'dd') | |
82 self.parser.parseBlocks(dd, [d]) | |
83 self.parser.state.reset() | |
84 | |
85 if theRest: | |
86 blocks.insert(0, theRest) | |
87 | |
88 | |
89 class DefListIndentProcessor(ListIndentProcessor): | |
90 """ Process indented children of definition list items. """ | |
91 | |
92 ITEM_TYPES = ['dd'] | |
93 LIST_TYPES = ['dl'] | |
94 | |
95 def create_item(self, parent, block): | |
96 """ Create a new dd and parse the block with it as the parent. """ | |
97 dd = etree.SubElement(parent, 'dd') | |
98 self.parser.parseBlocks(dd, [block]) | |
99 | |
100 | |
101 class DefListExtension(Extension): | |
102 """ Add definition lists to Markdown. """ | |
103 | |
104 def extendMarkdown(self, md, md_globals): | |
105 """ Add an instance of DefListProcessor to BlockParser. """ | |
106 md.parser.blockprocessors.add('defindent', | |
107 DefListIndentProcessor(md.parser), | |
108 '>indent') | |
109 md.parser.blockprocessors.add('deflist', | |
110 DefListProcessor(md.parser), | |
111 '>ulist') | |
112 | |
113 | |
114 def makeExtension(*args, **kwargs): | |
115 return DefListExtension(*args, **kwargs) | |
OLD | NEW |