Completed
Push — master ( 32cfa8...ec62d3 )
by Dongxin
48s
created

MarkdownInHtmlProcessor   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 57
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 57
rs 10
wmc 13

3 Methods

Rating   Name   Duplication   Size   Complexity  
D run() 0 33 8
A test() 0 2 1
A _process_nests() 0 17 4
1
"""
2
Python-Markdown Extra Extension
3
===============================
4
5
A compilation of various Python-Markdown extensions that imitates
6
[PHP Markdown Extra](http://michelf.com/projects/php-markdown/extra/).
7
8
Note that each of the individual extensions still need to be available
9
on your PYTHONPATH. This extension simply wraps them all up as a
10
convenience so that only one extension needs to be listed when
11
initiating Markdown. See the documentation for each individual
12
extension for specifics about that extension.
13
14
There may be additional extensions that are distributed with
15
Python-Markdown that are not included here in Extra. Those extensions
16
are not part of PHP Markdown Extra, and therefore, not part of
17
Python-Markdown Extra. If you really would like Extra to include
18
additional extensions, we suggest creating your own clone of Extra
19
under a differant name. You could also edit the `extensions` global
20
variable defined below, but be aware that such changes may be lost
21
when you upgrade to any future version of Python-Markdown.
22
23
See <https://pythonhosted.org/Markdown/extensions/extra.html>
24
for documentation.
25
26
Copyright The Python Markdown Project
27
28
License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
29
30
"""
31
32
from __future__ import absolute_import
33
from __future__ import unicode_literals
34
from . import Extension
35
from ..blockprocessors import BlockProcessor
36
from .. import util
37
import re
38
39
extensions = [
40
    'markdown.extensions.smart_strong',
41
    'markdown.extensions.fenced_code',
42
    'markdown.extensions.footnotes',
43
    'markdown.extensions.attr_list',
44
    'markdown.extensions.def_list',
45
    'markdown.extensions.tables',
46
    'markdown.extensions.abbr'
47
]
48
49
50
class ExtraExtension(Extension):
51
    """ Add various extensions to Markdown class."""
52
53
    def __init__(self, *args, **kwargs):
54
        """ config is a dumb holder which gets passed to actual ext later. """
55
        self.config = kwargs.pop('configs', {})
56
        self.config.update(kwargs)
57
58
    def extendMarkdown(self, md, md_globals):
59
        """ Register extension instances. """
60
        md.registerExtensions(extensions, self.config)
61
        if not md.safeMode:
62
            # Turn on processing of markdown text within raw html
63
            md.preprocessors['html_block'].markdown_in_raw = True
64
            md.parser.blockprocessors.add('markdown_block',
65
                                          MarkdownInHtmlProcessor(md.parser),
66
                                          '_begin')
67
            md.parser.blockprocessors.tag_counter = -1
68
            md.parser.blockprocessors.contain_span_tags = re.compile(
69
                r'^(p|h[1-6]|li|dd|dt|td|th|legend|address)$', re.IGNORECASE)
70
71
72
def makeExtension(*args, **kwargs):
73
    return ExtraExtension(*args, **kwargs)
74
75
76
class MarkdownInHtmlProcessor(BlockProcessor):
77
    """Process Markdown Inside HTML Blocks."""
78
    def test(self, parent, block):
79
        return block == util.TAG_PLACEHOLDER % \
80
            str(self.parser.blockprocessors.tag_counter + 1)
81
82
    def _process_nests(self, element, block):
83
        """Process the element's child elements in self.run."""
84
        # Build list of indexes of each nest within the parent element.
85
        nest_index = []  # a list of tuples: (left index, right index)
86
        i = self.parser.blockprocessors.tag_counter + 1
87
        while len(self._tag_data) > i and self._tag_data[i]['left_index']:
88
            left_child_index = self._tag_data[i]['left_index']
89
            right_child_index = self._tag_data[i]['right_index']
90
            nest_index.append((left_child_index - 1, right_child_index))
91
            i += 1
92
93
        # Create each nest subelement.
94
        for i, (left_index, right_index) in enumerate(nest_index[:-1]):
95
            self.run(element, block[left_index:right_index],
96
                     block[right_index:nest_index[i + 1][0]], True)
97
        self.run(element, block[nest_index[-1][0]:nest_index[-1][1]],  # last
98
                 block[nest_index[-1][1]:], True)                      # nest
99
100
    def run(self, parent, blocks, tail=None, nest=False):
101
        self._tag_data = self.parser.markdown.htmlStash.tag_data
102
103
        self.parser.blockprocessors.tag_counter += 1
104
        tag = self._tag_data[self.parser.blockprocessors.tag_counter]
105
106
        # Create Element
107
        markdown_value = tag['attrs'].pop('markdown')
108
        element = util.etree.SubElement(parent, tag['tag'], tag['attrs'])
109
110
        # Slice Off Block
111
        if nest:
112
            self.parser.parseBlocks(parent, tail)  # Process Tail
113
            block = blocks[1:]
114
        else:  # includes nests since a third level of nesting isn't supported
115
            block = blocks[tag['left_index'] + 1: tag['right_index']]
116
            del blocks[:tag['right_index']]
117
118
        # Process Text
119
        if (self.parser.blockprocessors.contain_span_tags.match(  # Span Mode
120
                tag['tag']) and markdown_value != 'block') or \
121
                markdown_value == 'span':
122
            element.text = '\n'.join(block)
123
        else:                                                     # Block Mode
124
            i = self.parser.blockprocessors.tag_counter + 1
125
            if len(self._tag_data) > i and self._tag_data[i]['left_index']:
126
                first_subelement_index = self._tag_data[i]['left_index'] - 1
127
                self.parser.parseBlocks(
128
                    element, block[:first_subelement_index])
129
                if not nest:
130
                    block = self._process_nests(element, block)
131
            else:
132
                self.parser.parseBlocks(element, block)
133