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
|
|
|
|