16516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruimport markdown 26516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruimport re 36516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 46516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Querudef isString(s): 56516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ Check if it's string """ 66516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return isinstance(s, unicode) or isinstance(s, str) 76516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 86516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruclass Processor: 96516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def __init__(self, markdown_instance=None): 106516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if markdown_instance: 116516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self.markdown = markdown_instance 126516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 136516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruclass Treeprocessor(Processor): 146516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ 156516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Treeprocessors are run on the ElementTree object before serialization. 166516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 176516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Each Treeprocessor implements a "run" method that takes a pointer to an 186516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru ElementTree, modifies it as necessary and returns an ElementTree 196516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru object. 206516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 216516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Treeprocessors must extend markdown.Treeprocessor. 226516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 236516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ 246516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def run(self, root): 256516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ 266516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Subclasses of Treeprocessor should implement a `run` method, which 276516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru takes a root ElementTree. This method can return another ElementTree 286516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru object, and the existing root ElementTree will be replaced, or it can 296516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru modify the current tree and return None. 306516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ 316516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru pass 326516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 336516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 346516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruclass InlineProcessor(Treeprocessor): 356516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ 366516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru A Treeprocessor that traverses a tree, applying inline patterns. 376516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ 386516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 396516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def __init__ (self, md): 406516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self.__placeholder_prefix = markdown.INLINE_PLACEHOLDER_PREFIX 416516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self.__placeholder_suffix = markdown.ETX 426516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self.__placeholder_length = 4 + len(self.__placeholder_prefix) \ 436516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru + len(self.__placeholder_suffix) 446516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self.__placeholder_re = re.compile(markdown.INLINE_PLACEHOLDER % r'([0-9]{4})') 456516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self.markdown = md 466516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 476516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def __makePlaceholder(self, type): 486516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ Generate a placeholder """ 496516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru id = "%04d" % len(self.stashed_nodes) 506516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru hash = markdown.INLINE_PLACEHOLDER % id 516516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return hash, id 526516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 536516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def __findPlaceholder(self, data, index): 546516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ 556516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Extract id from data string, start from index 566516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 576516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Keyword arguments: 586516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 596516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru * data: string 606516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru * index: index, from which we start search 616516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 626516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Returns: placeholder id and string index, after the found placeholder. 636516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ 646516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 656516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru m = self.__placeholder_re.search(data, index) 666516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if m: 676516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return m.group(1), m.end() 686516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru else: 696516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return None, index + 1 706516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 716516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def __stashNode(self, node, type): 726516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ Add node to stash """ 736516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru placeholder, id = self.__makePlaceholder(type) 746516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self.stashed_nodes[id] = node 756516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return placeholder 766516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 776516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def __handleInline(self, data, patternIndex=0): 786516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ 796516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Process string with inline patterns and replace it 806516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru with placeholders 816516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 826516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Keyword arguments: 836516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 846516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru * data: A line of Markdown text 856516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru * patternIndex: The index of the inlinePattern to start with 866516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 876516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Returns: String with placeholders. 886516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 896516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ 906516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if not isinstance(data, markdown.AtomicString): 916516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru startIndex = 0 926516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru while patternIndex < len(self.markdown.inlinePatterns): 936516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru data, matched, startIndex = self.__applyPattern( 946516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self.markdown.inlinePatterns.value_for_index(patternIndex), 956516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru data, patternIndex, startIndex) 966516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if not matched: 976516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru patternIndex += 1 986516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return data 996516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1006516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def __processElementText(self, node, subnode, isText=True): 1016516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ 1026516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Process placeholders in Element.text or Element.tail 1036516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru of Elements popped from self.stashed_nodes. 1046516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1056516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Keywords arguments: 1066516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1076516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru * node: parent node 1086516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru * subnode: processing node 1096516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru * isText: bool variable, True - it's text, False - it's tail 1106516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1116516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Returns: None 1126516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1136516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ 1146516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if isText: 1156516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru text = subnode.text 1166516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru subnode.text = None 1176516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru else: 1186516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru text = subnode.tail 1196516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru subnode.tail = None 1206516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1216516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru childResult = self.__processPlaceholders(text, subnode) 1226516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1236516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if not isText and node is not subnode: 1246516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru pos = node.getchildren().index(subnode) 1256516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru node.remove(subnode) 1266516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru else: 1276516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru pos = 0 1286516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1296516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru childResult.reverse() 1306516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru for newChild in childResult: 1316516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru node.insert(pos, newChild) 1326516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1336516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def __processPlaceholders(self, data, parent): 1346516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ 1356516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Process string with placeholders and generate ElementTree tree. 1366516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1376516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Keyword arguments: 1386516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1396516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru * data: string with placeholders instead of ElementTree elements. 1406516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru * parent: Element, which contains processing inline data 1416516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1426516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Returns: list with ElementTree elements with applied inline patterns. 1436516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ 1446516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def linkText(text): 1456516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if text: 1466516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if result: 1476516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if result[-1].tail: 1486516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru result[-1].tail += text 1496516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru else: 1506516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru result[-1].tail = text 1516516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru else: 1526516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if parent.text: 1536516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru parent.text += text 1546516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru else: 1556516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru parent.text = text 1566516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1576516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru result = [] 1586516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru strartIndex = 0 1596516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru while data: 1606516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru index = data.find(self.__placeholder_prefix, strartIndex) 1616516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if index != -1: 1626516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru id, phEndIndex = self.__findPlaceholder(data, index) 1636516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1646516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if id in self.stashed_nodes: 1656516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru node = self.stashed_nodes.get(id) 1666516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1676516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if index > 0: 1686516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru text = data[strartIndex:index] 1696516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru linkText(text) 1706516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1716516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if not isString(node): # it's Element 1726516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru for child in [node] + node.getchildren(): 1736516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if child.tail: 1746516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if child.tail.strip(): 1756516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self.__processElementText(node, child, False) 1766516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if child.text: 1776516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if child.text.strip(): 1786516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self.__processElementText(child, child) 1796516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru else: # it's just a string 1806516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru linkText(node) 1816516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru strartIndex = phEndIndex 1826516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru continue 1836516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1846516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru strartIndex = phEndIndex 1856516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru result.append(node) 1866516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1876516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru else: # wrong placeholder 1886516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru end = index + len(prefix) 1896516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru linkText(data[strartIndex:end]) 1906516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru strartIndex = end 1916516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru else: 1926516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru text = data[strartIndex:] 1936516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru linkText(text) 1946516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru data = "" 1956516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1966516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return result 1976516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 1986516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def __applyPattern(self, pattern, data, patternIndex, startIndex=0): 1996516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ 2006516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Check if the line fits the pattern, create the necessary 2016516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru elements, add it to stashed_nodes. 2026516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2036516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Keyword arguments: 2046516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2056516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru * data: the text to be processed 2066516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru * pattern: the pattern to be checked 2076516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru * patternIndex: index of current pattern 2086516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru * startIndex: string index, from which we starting search 2096516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2106516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Returns: String with placeholders instead of ElementTree elements. 2116516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2126516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ 2136516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru match = pattern.getCompiledRegExp().match(data[startIndex:]) 2146516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru leftData = data[:startIndex] 2156516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2166516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if not match: 2176516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return data, False, 0 2186516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2196516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru node = pattern.handleMatch(match) 2206516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2216516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if node is None: 2226516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return data, True, len(leftData) + match.span(len(match.groups()))[0] 2236516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2246516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if not isString(node): 2256516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if not isinstance(node.text, markdown.AtomicString): 2266516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru # We need to process current node too 2276516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru for child in [node] + node.getchildren(): 2286516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if not isString(node): 2296516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if child.text: 2306516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru child.text = self.__handleInline(child.text, 2316516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru patternIndex + 1) 2326516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if child.tail: 2336516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru child.tail = self.__handleInline(child.tail, 2346516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru patternIndex) 2356516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2366516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru placeholder = self.__stashNode(node, pattern.type()) 2376516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2386516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return "%s%s%s%s" % (leftData, 2396516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru match.group(1), 2406516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru placeholder, match.groups()[-1]), True, 0 2416516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2426516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def run(self, tree): 2436516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """Apply inline patterns to a parsed Markdown tree. 2446516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2456516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Iterate over ElementTree, find elements with inline tag, apply inline 2466516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru patterns and append newly created Elements to tree. If you don't 2476516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru want process your data with inline paterns, instead of normal string, 2486516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru use subclass AtomicString: 2496516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2506516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru node.text = markdown.AtomicString("data won't be processed with inline patterns") 2516516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2526516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Arguments: 2536516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2546516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru * markdownTree: ElementTree object, representing Markdown tree. 2556516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2566516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru Returns: ElementTree object with applied inline patterns. 2576516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2586516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ 2596516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self.stashed_nodes = {} 2606516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2616516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru stack = [tree] 2626516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2636516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru while stack: 2646516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru currElement = stack.pop() 2656516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru insertQueue = [] 2666516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru for child in currElement.getchildren(): 2676516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if child.text and not isinstance(child.text, markdown.AtomicString): 2686516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru text = child.text 2696516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru child.text = None 2706516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru lst = self.__processPlaceholders(self.__handleInline( 2716516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru text), child) 2726516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru stack += lst 2736516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru insertQueue.append((child, lst)) 2746516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2756516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if child.getchildren(): 2766516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru stack.append(child) 2776516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2786516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru for element, lst in insertQueue: 2796516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if element.text: 2806516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru element.text = \ 2816516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru markdown.inlinepatterns.handleAttributes(element.text, 2826516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru element) 2836516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru i = 0 2846516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru for newChild in lst: 2856516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru # Processing attributes 2866516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if newChild.tail: 2876516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru newChild.tail = \ 2886516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru markdown.inlinepatterns.handleAttributes(newChild.tail, 2896516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru element) 2906516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if newChild.text: 2916516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru newChild.text = \ 2926516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru markdown.inlinepatterns.handleAttributes(newChild.text, 2936516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru newChild) 2946516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru element.insert(i, newChild) 2956516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru i += 1 2966516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru return tree 2976516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2986516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 2996516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruclass PrettifyTreeprocessor(Treeprocessor): 3006516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ Add linebreaks to the html document. """ 3016516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 3026516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def _prettifyETree(self, elem): 3036516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ Recursively add linebreaks to ElementTree children. """ 3046516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 3056516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru i = "\n" 3066516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if markdown.isBlockLevel(elem.tag) and elem.tag not in ['code', 'pre']: 3076516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if (not elem.text or not elem.text.strip()) \ 3086516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru and len(elem) and markdown.isBlockLevel(elem[0].tag): 3096516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru elem.text = i 3106516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru for e in elem: 3116516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if markdown.isBlockLevel(e.tag): 3126516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self._prettifyETree(e) 3136516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if not elem.tail or not elem.tail.strip(): 3146516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru elem.tail = i 3156516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if not elem.tail or not elem.tail.strip(): 3166516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru elem.tail = i 3176516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 3186516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru def run(self, root): 3196516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru """ Add linebreaks to ElementTree root object. """ 3206516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru 3216516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru self._prettifyETree(root) 3226516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru # Do <br />'s seperately as they are often in the middle of 3236516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru # inline content and missed by _prettifyETree. 3246516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru brs = root.getiterator('br') 3256516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru for br in brs: 3266516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru if not br.tail or not br.tail.strip(): 3276516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru br.tail = '\n' 3286516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru else: 3296516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru br.tail = '\n%s' % br.tail 330