1 # markdown is released under the BSD license 2 # Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later) 3 # Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) 4 # Copyright 2004 Manfred Stienstra (the original version) 5 # 6 # All rights reserved. 7 # 8 # Redistribution and use in source and binary forms, with or without 9 # modification, are permitted provided that the following conditions are met: 10 # 11 # * Redistributions of source code must retain the above copyright 12 # notice, this list of conditions and the following disclaimer. 13 # * Redistributions in binary form must reproduce the above copyright 14 # notice, this list of conditions and the following disclaimer in the 15 # documentation and/or other materials provided with the distribution. 16 # * Neither the name of the <organization> nor the 17 # names of its contributors may be used to endorse or promote products 18 # derived from this software without specific prior written permission. 19 # 20 # THIS SOFTWARE IS PROVIDED BY THE PYTHON MARKDOWN PROJECT ''AS IS'' AND ANY 21 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 # DISCLAIMED. IN NO EVENT SHALL ANY CONTRIBUTORS TO THE PYTHON MARKDOWN PROJECT 24 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 # POSSIBILITY OF SUCH DAMAGE. 31 32 33 """ 34 Definition List Extension for Python-Markdown 35 ============================================= 36 37 Added parsing of Definition Lists to Python-Markdown. 38 39 A simple example: 40 41 Apple 42 : Pomaceous fruit of plants of the genus Malus in 43 the family Rosaceae. 44 : An american computer company. 45 46 Orange 47 : The fruit of an evergreen tree of the genus Citrus. 48 49 Copyright 2008 - [Waylan Limberg](http://achinghead.com) 50 51 """ 52 53 from __future__ import absolute_import 54 from __future__ import unicode_literals 55 from . import Extension 56 from ..blockprocessors import BlockProcessor, ListIndentProcessor 57 from ..util import etree 58 import re 59 60 61 class DefListProcessor(BlockProcessor): 62 """ Process Definition Lists. """ 63 64 RE = re.compile(r'(^|\n)[ ]{0,3}:[ ]{1,3}(.*?)(\n|$)') 65 NO_INDENT_RE = re.compile(r'^[ ]{0,3}[^ :]') 66 67 def test(self, parent, block): 68 return bool(self.RE.search(block)) 69 70 def run(self, parent, blocks): 71 72 raw_block = blocks.pop(0) 73 m = self.RE.search(raw_block) 74 terms = [l.strip() for l in raw_block[:m.start()].split('\n') if l.strip()] 75 block = raw_block[m.end():] 76 no_indent = self.NO_INDENT_RE.match(block) 77 if no_indent: 78 d, theRest = (block, None) 79 else: 80 d, theRest = self.detab(block) 81 if d: 82 d = '%s\n%s' % (m.group(2), d) 83 else: 84 d = m.group(2) 85 sibling = self.lastChild(parent) 86 if not terms and sibling is None: 87 # This is not a definition item. Most likely a paragraph that 88 # starts with a colon at the begining of a document or list. 89 blocks.insert(0, raw_block) 90 return False 91 if not terms and sibling.tag == 'p': 92 # The previous paragraph contains the terms 93 state = 'looselist' 94 terms = sibling.text.split('\n') 95 parent.remove(sibling) 96 # Aquire new sibling 97 sibling = self.lastChild(parent) 98 else: 99 state = 'list' 100 101 if sibling and sibling.tag == 'dl': 102 # This is another item on an existing list 103 dl = sibling 104 if len(dl) and dl[-1].tag == 'dd' and len(dl[-1]): 105 state = 'looselist' 106 else: 107 # This is a new list 108 dl = etree.SubElement(parent, 'dl') 109 # Add terms 110 for term in terms: 111 dt = etree.SubElement(dl, 'dt') 112 dt.text = term 113 # Add definition 114 self.parser.state.set(state) 115 dd = etree.SubElement(dl, 'dd') 116 self.parser.parseBlocks(dd, [d]) 117 self.parser.state.reset() 118 119 if theRest: 120 blocks.insert(0, theRest) 121 122 class DefListIndentProcessor(ListIndentProcessor): 123 """ Process indented children of definition list items. """ 124 125 ITEM_TYPES = ['dd'] 126 LIST_TYPES = ['dl'] 127 128 def create_item(self, parent, block): 129 """ Create a new dd and parse the block with it as the parent. """ 130 dd = etree.SubElement(parent, 'dd') 131 self.parser.parseBlocks(dd, [block]) 132 133 134 135 class DefListExtension(Extension): 136 """ Add definition lists to Markdown. """ 137 138 def extendMarkdown(self, md, md_globals): 139 """ Add an instance of DefListProcessor to BlockParser. """ 140 md.parser.blockprocessors.add('defindent', 141 DefListIndentProcessor(md.parser), 142 '>indent') 143 md.parser.blockprocessors.add('deflist', 144 DefListProcessor(md.parser), 145 '>ulist') 146 147 148 def makeExtension(configs={}): 149 return DefListExtension(configs=configs) 150 151