15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# markdown is released under the BSD license
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later)
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# Copyright 2004 Manfred Stienstra (the original version)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# All rights reserved.
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# Redistribution and use in source and binary forms, with or without
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# modification, are permitted provided that the following conditions are met:
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# *   Redistributions of source code must retain the above copyright
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#     notice, this list of conditions and the following disclaimer.
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# *   Redistributions in binary form must reproduce the above copyright
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#     notice, this list of conditions and the following disclaimer in the
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#     documentation and/or other materials provided with the distribution.
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# *   Neither the name of the <organization> nor the
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#     names of its contributors may be used to endorse or promote products
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#     derived from this software without specific prior written permission.
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# THIS SOFTWARE IS PROVIDED BY THE PYTHON MARKDOWN PROJECT ''AS IS'' AND ANY
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# DISCLAIMED. IN NO EVENT SHALL ANY CONTRIBUTORS TO THE PYTHON MARKDOWN PROJECT
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# POSSIBILITY OF SUCH DAMAGE.
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)"""
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)CORE MARKDOWN BLOCKPARSER
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)===========================================================================
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)This parser handles basic parsing of Markdown blocks.  It doesn't concern itself
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)with inline elements such as **bold** or *italics*, but rather just catches
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)blocks, lists, quotes, etc.
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)The BlockParser is made up of a bunch of BlockProssors, each handling a
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)different type of block. Extensions may add/replace/remove BlockProcessors
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)as they need to alter how markdown blocks are parsed.
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)"""
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from __future__ import absolute_import
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from __future__ import division
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from __future__ import unicode_literals
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import logging
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import re
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from . import util
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from .blockparser import BlockParser
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)logger =  logging.getLogger('MARKDOWN')
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)def build_block_parser(md_instance, **kwargs):
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """ Build the default block parser used by Markdown. """
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    parser = BlockParser(md_instance)
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    parser.blockprocessors['empty'] = EmptyBlockProcessor(parser)
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    parser.blockprocessors['indent'] = ListIndentProcessor(parser)
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    parser.blockprocessors['code'] = CodeBlockProcessor(parser)
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    parser.blockprocessors['hashheader'] = HashHeaderProcessor(parser)
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    parser.blockprocessors['setextheader'] = SetextHeaderProcessor(parser)
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    parser.blockprocessors['hr'] = HRProcessor(parser)
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    parser.blockprocessors['olist'] = OListProcessor(parser)
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    parser.blockprocessors['ulist'] = UListProcessor(parser)
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    parser.blockprocessors['quote'] = BlockQuoteProcessor(parser)
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    parser.blockprocessors['paragraph'] = ParagraphProcessor(parser)
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return parser
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class BlockProcessor:
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """ Base class for block processors.
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Each subclass will provide the methods below to work with the source and
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    tree. Each processor will need to define it's own ``test`` and ``run``
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    methods. The ``test`` method should return True or False, to indicate
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    whether the current block should be processed by this processor. If the
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    test passes, the parser will call the processors ``run`` method.
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def __init__(self, parser):
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self.parser = parser
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self.tab_length = parser.markdown.tab_length
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def lastChild(self, parent):
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        """ Return the last child of an etree element. """
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if len(parent):
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            return parent[-1]
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        else:
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            return None
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def detab(self, text):
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        """ Remove a tab from the front of each line of the given text. """
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        newtext = []
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        lines = text.split('\n')
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        for line in lines:
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if line.startswith(' '*self.tab_length):
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                newtext.append(line[self.tab_length:])
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            elif not line.strip():
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                newtext.append('')
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            else:
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                break
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return '\n'.join(newtext), '\n'.join(lines[len(newtext):])
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def looseDetab(self, text, level=1):
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        """ Remove a tab from front of lines but allowing dedented lines. """
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        lines = text.split('\n')
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        for i in range(len(lines)):
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if lines[i].startswith(' '*self.tab_length*level):
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                lines[i] = lines[i][self.tab_length*level:]
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return '\n'.join(lines)
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def test(self, parent, block):
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        """ Test for block type. Must be overridden by subclasses.
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        As the parser loops through processors, it will call the ``test`` method
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        on each to determine if the given block of text is of that type. This
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        method must return a boolean ``True`` or ``False``. The actual method of
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        testing is left to the needs of that particular block type. It could
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        be as simple as ``block.startswith(some_string)`` or a complex regular
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        expression. As the block type may be different depending on the parent
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        of the block (i.e. inside a list), the parent etree element is also
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        provided and may be used as part of the test.
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        Keywords:
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        * ``parent``: A etree element which will be the parent of the block.
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        * ``block``: A block of text from the source which has been split at
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            blank lines.
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        """
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        pass
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def run(self, parent, blocks):
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        """ Run processor. Must be overridden by subclasses.
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        When the parser determines the appropriate type of a block, the parser
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        will call the corresponding processor's ``run`` method. This method
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        should parse the individual lines of the block and append them to
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        the etree.
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        Note that both the ``parent`` and ``etree`` keywords are pointers
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        to instances of the objects which should be edited in place. Each
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        processor must make changes to the existing objects as there is no
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        mechanism to return new/different objects to replace them.
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        This means that this method should be adding SubElements or adding text
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        to the parent, and should remove (``pop``) or add (``insert``) items to
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        the list of blocks.
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        Keywords:
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        * ``parent``: A etree element which is the parent of the current block.
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        * ``blocks``: A list of all remaining blocks of the document.
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        """
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        pass
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class ListIndentProcessor(BlockProcessor):
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """ Process children of list items.
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Example:
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        * a list item
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            process this part
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            or this part
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ITEM_TYPES = ['li']
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LIST_TYPES = ['ul', 'ol']
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def __init__(self, *args):
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        BlockProcessor.__init__(self, *args)
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self.INDENT_RE = re.compile(r'^(([ ]{%s})+)'% self.tab_length)
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def test(self, parent, block):
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return block.startswith(' '*self.tab_length) and \
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                not self.parser.state.isstate('detabbed') and  \
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                (parent.tag in self.ITEM_TYPES or \
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    (len(parent) and parent[-1] and \
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        (parent[-1].tag in self.LIST_TYPES)
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    )
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                )
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def run(self, parent, blocks):
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        block = blocks.pop(0)
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        level, sibling = self.get_level(parent, block)
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        block = self.looseDetab(block, level)
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self.parser.state.set('detabbed')
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if parent.tag in self.ITEM_TYPES:
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # It's possible that this parent has a 'ul' or 'ol' child list
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # with a member.  If that is the case, then that should be the
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # parent.  This is intended to catch the edge case of an indented
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # list whose first member was parsed previous to this point
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # see OListProcessor
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if len(parent) and parent[-1].tag in self.LIST_TYPES:
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                self.parser.parseBlocks(parent[-1], [block])
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            else:
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # The parent is already a li. Just parse the child block.
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                self.parser.parseBlocks(parent, [block])
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        elif sibling.tag in self.ITEM_TYPES:
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # The sibling is a li. Use it as parent.
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            self.parser.parseBlocks(sibling, [block])
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        elif len(sibling) and sibling[-1].tag in self.ITEM_TYPES:
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # The parent is a list (``ol`` or ``ul``) which has children.
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # Assume the last child li is the parent of this block.
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if sibling[-1].text:
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # If the parent li has text, that text needs to be moved to a p
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # The p must be 'inserted' at beginning of list in the event
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # that other children already exist i.e.; a nested sublist.
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                p = util.etree.Element('p')
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                p.text = sibling[-1].text
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                sibling[-1].text = ''
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                sibling[-1].insert(0, p)
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            self.parser.parseChunk(sibling[-1], block)
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        else:
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            self.create_item(sibling, block)
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self.parser.state.reset()
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def create_item(self, parent, block):
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        """ Create a new li and parse the block with it as the parent. """
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        li = util.etree.SubElement(parent, 'li')
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self.parser.parseBlocks(li, [block])
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def get_level(self, parent, block):
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        """ Get level of indent based on list level. """
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # Get indent level
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        m = self.INDENT_RE.match(block)
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if m:
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            indent_level = len(m.group(1))/self.tab_length
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        else:
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            indent_level = 0
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if self.parser.state.isstate('list'):
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # We're in a tightlist - so we already are at correct parent.
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            level = 1
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        else:
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # We're in a looselist - so we need to find parent.
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            level = 0
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # Step through children of tree to find matching indent level.
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        while indent_level > level:
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            child = self.lastChild(parent)
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if child and (child.tag in self.LIST_TYPES or child.tag in self.ITEM_TYPES):
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                if child.tag in self.LIST_TYPES:
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    level += 1
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                parent = child
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            else:
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # No more child levels. If we're short of indent_level,
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # we have a code block. So we stop here.
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                break
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return level, parent
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class CodeBlockProcessor(BlockProcessor):
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """ Process code blocks. """
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def test(self, parent, block):
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return block.startswith(' '*self.tab_length)
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def run(self, parent, blocks):
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        sibling = self.lastChild(parent)
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        block = blocks.pop(0)
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        theRest = ''
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if sibling and sibling.tag == "pre" and len(sibling) \
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    and sibling[0].tag == "code":
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # The previous block was a code block. As blank lines do not start
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # new code blocks, append this block to the previous, adding back
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # linebreaks removed from the split into a list.
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            code = sibling[0]
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            block, theRest = self.detab(block)
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            code.text = util.AtomicString('%s\n%s\n' % (code.text, block.rstrip()))
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        else:
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # This is a new codeblock. Create the elements and insert text.
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            pre = util.etree.SubElement(parent, 'pre')
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            code = util.etree.SubElement(pre, 'code')
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            block, theRest = self.detab(block)
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            code.text = util.AtomicString('%s\n' % block.rstrip())
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if theRest:
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # This block contained unindented line(s) after the first indented
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # line. Insert these lines as the first block of the master blocks
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # list for future processing.
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            blocks.insert(0, theRest)
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class BlockQuoteProcessor(BlockProcessor):
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RE = re.compile(r'(^|\n)[ ]{0,3}>[ ]?(.*)')
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def test(self, parent, block):
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return bool(self.RE.search(block))
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def run(self, parent, blocks):
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        block = blocks.pop(0)
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        m = self.RE.search(block)
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if m:
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            before = block[:m.start()] # Lines before blockquote
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # Pass lines before blockquote in recursively for parsing forst.
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            self.parser.parseBlocks(parent, [before])
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # Remove ``> `` from begining of each line.
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            block = '\n'.join([self.clean(line) for line in
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            block[m.start():].split('\n')])
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        sibling = self.lastChild(parent)
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if sibling and sibling.tag == "blockquote":
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # Previous block was a blockquote so set that as this blocks parent
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            quote = sibling
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        else:
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # This is a new blockquote. Create a new parent element.
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            quote = util.etree.SubElement(parent, 'blockquote')
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # Recursively parse block with blockquote as parent.
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # change parser state so blockquotes embedded in lists use p tags
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self.parser.state.set('blockquote')
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self.parser.parseChunk(quote, block)
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self.parser.state.reset()
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def clean(self, line):
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        """ Remove ``>`` from beginning of a line. """
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        m = self.RE.match(line)
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if line.strip() == ">":
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            return ""
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        elif m:
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            return m.group(2)
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        else:
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            return line
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class OListProcessor(BlockProcessor):
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """ Process ordered list blocks. """
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    TAG = 'ol'
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Detect an item (``1. item``). ``group(1)`` contains contents of item.
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RE = re.compile(r'^[ ]{0,3}\d+\.[ ]+(.*)')
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Detect items on secondary lines. they can be of either list type.
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    CHILD_RE = re.compile(r'^[ ]{0,3}((\d+\.)|[*+-])[ ]+(.*)')
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Detect indented (nested) items of either type
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    INDENT_RE = re.compile(r'^[ ]{4,7}((\d+\.)|[*+-])[ ]+.*')
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # The integer (python string) with which the lists starts (default=1)
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Eg: If list is intialized as)
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    #   3. Item
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # The ol tag will get starts="3" attribute
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    STARTSWITH = '1'
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # List of allowed sibling tags.
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SIBLING_TAGS = ['ol', 'ul']
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def test(self, parent, block):
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return bool(self.RE.match(block))
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def run(self, parent, blocks):
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # Check fr multiple items in one block.
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        items = self.get_items(blocks.pop(0))
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        sibling = self.lastChild(parent)
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if sibling and sibling.tag in self.SIBLING_TAGS:
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # Previous block was a list item, so set that as parent
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            lst = sibling
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # make sure previous item is in a p- if the item has text, then it
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # it isn't in a p
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if lst[-1].text:
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # since it's possible there are other children for this sibling,
3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # we can't just SubElement the p, we need to insert it as the
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # first item
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                p = util.etree.Element('p')
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                p.text = lst[-1].text
3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                lst[-1].text = ''
3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                lst[-1].insert(0, p)
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # if the last item has a tail, then the tail needs to be put in a p
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # likely only when a header is not followed by a blank line
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            lch = self.lastChild(lst[-1])
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if lch is not None and lch.tail:
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                p = util.etree.SubElement(lst[-1], 'p')
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                p.text = lch.tail.lstrip()
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                lch.tail = ''
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # parse first block differently as it gets wrapped in a p.
3765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            li = util.etree.SubElement(lst, 'li')
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            self.parser.state.set('looselist')
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            firstitem = items.pop(0)
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            self.parser.parseBlocks(li, [firstitem])
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            self.parser.state.reset()
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        elif parent.tag in ['ol', 'ul']:
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # this catches the edge case of a multi-item indented list whose
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # first item is in a blank parent-list item:
3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # * * subitem1
3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            #     * subitem2
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # see also ListIndentProcessor
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            lst = parent
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        else:
3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # This is a new list so create parent with appropriate tag.
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            lst = util.etree.SubElement(parent, self.TAG)
3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # Check if a custom start integer is set
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if not self.parser.markdown.lazy_ol and self.STARTSWITH !='1':
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                lst.attrib['start'] = self.STARTSWITH
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self.parser.state.set('list')
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # Loop through items in block, recursively parsing each with the
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # appropriate parent.
3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        for item in items:
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if item.startswith(' '*self.tab_length):
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # Item is indented. Parse with last item as parent
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                self.parser.parseBlocks(lst[-1], [item])
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            else:
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # New item. Create li and parse with it as parent
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                li = util.etree.SubElement(lst, 'li')
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                self.parser.parseBlocks(li, [item])
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self.parser.state.reset()
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def get_items(self, block):
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        """ Break a block into list items. """
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        items = []
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        for line in block.split('\n'):
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            m = self.CHILD_RE.match(line)
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if m:
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # This is a new list item
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # Check first item for the start index
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                if not items and self.TAG=='ol':
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    # Detect the integer value of first list item
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    INTEGER_RE = re.compile('(\d+)')
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    self.STARTSWITH = INTEGER_RE.match(m.group(1)).group()
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # Append to the list
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                items.append(m.group(3))
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            elif self.INDENT_RE.match(line):
4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # This is an indented (possibly nested) item.
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                if items[-1].startswith(' '*self.tab_length):
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    # Previous item was indented. Append to that item.
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    items[-1] = '%s\n%s' % (items[-1], line)
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                else:
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    items.append(line)
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            else:
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # This is another line of previous item. Append to that item.
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                items[-1] = '%s\n%s' % (items[-1], line)
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return items
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class UListProcessor(OListProcessor):
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """ Process unordered list blocks. """
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    TAG = 'ul'
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RE = re.compile(r'^[ ]{0,3}[*+-][ ]+(.*)')
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class HashHeaderProcessor(BlockProcessor):
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """ Process Hash Headers. """
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Detect a header at start of any line in block
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RE = re.compile(r'(^|\n)(?P<level>#{1,6})(?P<header>.*?)#*(\n|$)')
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def test(self, parent, block):
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return bool(self.RE.search(block))
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def run(self, parent, blocks):
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        block = blocks.pop(0)
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        m = self.RE.search(block)
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if m:
4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            before = block[:m.start()] # All lines before header
4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            after = block[m.end():]    # All lines after header
4575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if before:
4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # As the header was not the first line of the block and the
4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # lines before the header must be parsed first,
4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # recursively parse this lines as a block.
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                self.parser.parseBlocks(parent, [before])
4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # Create header using named groups from RE
4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            h = util.etree.SubElement(parent, 'h%d' % len(m.group('level')))
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            h.text = m.group('header').strip()
4655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if after:
4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # Insert remaining lines as first block for future parsing.
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                blocks.insert(0, after)
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        else:
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # This should never happen, but just in case...
4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            logger.warn("We've got a problem header: %r" % block)
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class SetextHeaderProcessor(BlockProcessor):
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """ Process Setext-style Headers. """
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Detect Setext-style header. Must be first 2 lines of block.
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RE = re.compile(r'^.*?\n[=-]+[ ]*(\n|$)', re.MULTILINE)
4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def test(self, parent, block):
4805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return bool(self.RE.match(block))
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def run(self, parent, blocks):
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        lines = blocks.pop(0).split('\n')
4845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # Determine level. ``=`` is 1 and ``-`` is 2.
4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if lines[1].startswith('='):
4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            level = 1
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        else:
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            level = 2
4895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        h = util.etree.SubElement(parent, 'h%d' % level)
4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        h.text = lines[0].strip()
4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if len(lines) > 2:
4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # Block contains additional lines. Add to  master blocks for later.
4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            blocks.insert(0, '\n'.join(lines[2:]))
4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class HRProcessor(BlockProcessor):
4975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """ Process Horizontal Rules. """
4985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RE = r'^[ ]{0,3}((-+[ ]{0,2}){3,}|(_+[ ]{0,2}){3,}|(\*+[ ]{0,2}){3,})[ ]*'
5005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Detect hr on any line of a block.
5015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SEARCH_RE = re.compile(RE, re.MULTILINE)
5025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def test(self, parent, block):
5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        m = self.SEARCH_RE.search(block)
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # No atomic grouping in python so we simulate it here for performance.
5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # The regex only matches what would be in the atomic group - the HR.
5075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # Then check if we are at end of block or if next char is a newline.
5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if m and (m.end() == len(block) or block[m.end()] == '\n'):
5095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # Save match object on class instance so we can use it later.
5105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            self.match = m
5115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            return True
5125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return False
5135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def run(self, parent, blocks):
5155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        block = blocks.pop(0)
5165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # Check for lines in block before hr.
5175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        prelines = block[:self.match.start()].rstrip('\n')
5185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if prelines:
5195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # Recursively parse lines before hr so they get parsed first.
5205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            self.parser.parseBlocks(parent, [prelines])
5215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # create hr
5225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        util.etree.SubElement(parent, 'hr')
5235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        # check for lines in block after hr.
5245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        postlines = block[self.match.end():].lstrip('\n')
5255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if postlines:
5265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # Add lines after hr to master blocks for later parsing.
5275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            blocks.insert(0, postlines)
5285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class EmptyBlockProcessor(BlockProcessor):
5325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """ Process blocks that are empty or start with an empty line. """
5335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def test(self, parent, block):
5355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return not block or block.startswith('\n')
5365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def run(self, parent, blocks):
5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        block = blocks.pop(0)
5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        filler = '\n\n'
5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if block:
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # Starts with empty line
5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # Only replace a single line.
5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            filler = '\n'
5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # Save the rest for later.
5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            theRest = block[1:]
5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if theRest:
5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # Add remaining lines to master blocks for later.
5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                blocks.insert(0, theRest)
5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        sibling = self.lastChild(parent)
5505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if sibling and sibling.tag == 'pre' and len(sibling) and sibling[0].tag == 'code':
5515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # Last block is a codeblock. Append to preserve whitespace.
5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            sibling[0].text = util.AtomicString('%s%s' % (sibling[0].text, filler))
5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class ParagraphProcessor(BlockProcessor):
5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """ Process Paragraph blocks. """
5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def test(self, parent, block):
5595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return True
5605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    def run(self, parent, blocks):
5625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        block = blocks.pop(0)
5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if block.strip():
5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            # Not a blank block. Add to parent, otherwise throw it away.
5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            if self.parser.state.isstate('list'):
5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # The parent is a tight-list.
5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                #
5685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # Check for any children. This will likely only happen in a
5695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # tight-list when a header isn't followed by a blank line.
5705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # For example:
5715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                #
5725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                #     * # Header
5735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                #     Line 2 of list item - not part of header.
5745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                sibling = self.lastChild(parent)
5755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                if sibling is not None:
5765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    # Insetrt after sibling.
5775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    if sibling.tail:
5785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        sibling.tail = '%s\n%s' % (sibling.tail, block)
5795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    else:
5805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        sibling.tail = '\n%s' % block
5815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                else:
5825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    # Append to parent.text
5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    if parent.text:
5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        parent.text = '%s\n%s' % (parent.text, block)
5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    else:
5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        parent.text = block.lstrip()
5875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            else:
5885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                # Create a regular paragraph
5895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                p = util.etree.SubElement(parent, 'p')
5905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                p.text = block.lstrip()
591