16516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
26516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru"""
36516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruPRE-PROCESSORS
46516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru=============================================================================
56516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
66516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruPreprocessors work on source text before we start doing anything too
76516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Querucomplicated.
86516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru"""
96516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
106516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruimport re
116516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruimport markdown
126516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
136516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruHTML_PLACEHOLDER_PREFIX = markdown.STX+"wzxhzdk:"
146516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste QueruHTML_PLACEHOLDER = HTML_PLACEHOLDER_PREFIX + "%d" + markdown.ETX
156516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
166516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruclass Processor:
176516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    def __init__(self, markdown_instance=None):
186516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        if markdown_instance:
196516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            self.markdown = markdown_instance
206516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
216516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruclass Preprocessor (Processor):
226516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    """
236516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    Preprocessors are run after the text is broken into lines.
246516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
256516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    Each preprocessor implements a "run" method that takes a pointer to a
266516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    list of lines of the document, modifies it as necessary and returns
276516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    either the same pointer or a pointer to a new list.
286516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
296516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    Preprocessors must extend markdown.Preprocessor.
306516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
316516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    """
326516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    def run(self, lines):
336516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        """
346516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        Each subclass of Preprocessor should override the `run` method, which
356516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        takes the document as a list of strings split by newlines and returns
366516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        the (possibly modified) list of lines.
376516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
386516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        """
396516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        pass
406516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
416516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruclass HtmlStash:
426516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    """
436516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    This class is used for stashing HTML objects that we extract
446516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    in the beginning and replace with place-holders.
456516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    """
466516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
476516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    def __init__ (self):
486516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        """ Create a HtmlStash. """
496516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        self.html_counter = 0 # for counting inline html segments
506516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        self.rawHtmlBlocks=[]
516516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
526516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    def store(self, html, safe=False):
536516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        """
546516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        Saves an HTML segment for later reinsertion.  Returns a
556516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        placeholder string that needs to be inserted into the
566516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        document.
576516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
586516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        Keyword arguments:
596516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
606516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        * html: an html segment
616516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        * safe: label an html segment as safe for safemode
626516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
636516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        Returns : a placeholder string
646516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
656516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        """
666516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        self.rawHtmlBlocks.append((html, safe))
676516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        placeholder = HTML_PLACEHOLDER % self.html_counter
686516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        self.html_counter += 1
696516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        return placeholder
706516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
716516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    def reset(self):
726516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        self.html_counter = 0
736516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        self.rawHtmlBlocks = []
746516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
756516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
766516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruclass HtmlBlockPreprocessor(Preprocessor):
776516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    """Remove html blocks from the text and store them for later retrieval."""
786516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
796516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    right_tag_patterns = ["</%s>", "%s>"]
806516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
816516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    def _get_left_tag(self, block):
826516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        return block[1:].replace(">", " ", 1).split()[0].lower()
836516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
846516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    def _get_right_tag(self, left_tag, block):
856516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        for p in self.right_tag_patterns:
866516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            tag = p % left_tag
876516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            i = block.rfind(tag)
886516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            if i > 2:
896516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                return tag.lstrip("<").rstrip(">"), i + len(p)-2 + len(left_tag)
906516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        return block.rstrip()[-len(left_tag)-2:-1].lower(), len(block)
916516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
926516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    def _equal_tags(self, left_tag, right_tag):
936516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        if left_tag == 'div' or left_tag[0] in ['?', '@', '%']: # handle PHP, etc.
946516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            return True
956516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        if ("/" + left_tag) == right_tag:
966516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            return True
976516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        if (right_tag == "--" and left_tag == "--"):
986516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            return True
996516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        elif left_tag == right_tag[1:] \
1006516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            and right_tag[0] != "<":
1016516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            return True
1026516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        else:
1036516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            return False
1046516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1056516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    def _is_oneliner(self, tag):
1066516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        return (tag in ['hr', 'hr/'])
1076516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1086516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    def run(self, lines):
1096516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        text = "\n".join(lines)
1106516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        new_blocks = []
1116516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        text = text.split("\n\n")
1126516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        items = []
1136516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        left_tag = ''
1146516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        right_tag = ''
1156516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        in_tag = False # flag
1166516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1176516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        while text:
1186516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            block = text[0]
1196516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            if block.startswith("\n"):
1206516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                block = block[1:]
1216516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            text = text[1:]
1226516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1236516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            if block.startswith("\n"):
1246516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                block = block[1:]
1256516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1266516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            if not in_tag:
1276516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                if block.startswith("<"):
1286516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                    left_tag = self._get_left_tag(block)
1296516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                    right_tag, data_index = self._get_right_tag(left_tag, block)
1306516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1316516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                    if block[1] == "!":
1326516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        # is a comment block
1336516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        left_tag = "--"
1346516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        right_tag, data_index = self._get_right_tag(left_tag, block)
1356516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        # keep checking conditions below and maybe just append
1366516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1376516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                    if data_index < len(block) \
1386516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        and markdown.isBlockLevel(left_tag):
1396516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        text.insert(0, block[data_index:])
1406516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        block = block[:data_index]
1416516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1426516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                    if not (markdown.isBlockLevel(left_tag) \
1436516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        or block[1] in ["!", "?", "@", "%"]):
1446516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        new_blocks.append(block)
1456516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        continue
1466516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1476516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                    if self._is_oneliner(left_tag):
1486516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        new_blocks.append(block.strip())
1496516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        continue
1506516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1516516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                    if block.rstrip().endswith(">") \
1526516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        and self._equal_tags(left_tag, right_tag):
1536516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        new_blocks.append(
1546516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                            self.markdown.htmlStash.store(block.strip()))
1556516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        continue
1566516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                    else: #if not block[1] == "!":
1576516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        # if is block level tag and is not complete
1586516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1596516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        if markdown.isBlockLevel(left_tag) or left_tag == "--" \
1606516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                            and not block.rstrip().endswith(">"):
1616516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                            items.append(block.strip())
1626516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                            in_tag = True
1636516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        else:
1646516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                            new_blocks.append(
1656516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                            self.markdown.htmlStash.store(block.strip()))
1666516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1676516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        continue
1686516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1696516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                new_blocks.append(block)
1706516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1716516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            else:
1726516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                items.append(block.strip())
1736516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1746516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                right_tag, data_index = self._get_right_tag(left_tag, block)
1756516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1766516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                if self._equal_tags(left_tag, right_tag):
1776516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                    # if find closing tag
1786516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                    in_tag = False
1796516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                    new_blocks.append(
1806516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                        self.markdown.htmlStash.store('\n\n'.join(items)))
1816516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                    items = []
1826516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1836516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        if items:
1846516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            new_blocks.append(self.markdown.htmlStash.store('\n\n'.join(items)))
1856516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            new_blocks.append('\n')
1866516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1876516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        new_text = "\n\n".join(new_blocks)
1886516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        return new_text.split("\n")
1896516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1906516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1916516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queruclass ReferencePreprocessor(Preprocessor):
1926516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    """ Remove reference definitions from text and store for later use. """
1936516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1946516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    RE = re.compile(r'^(\ ?\ ?\ ?)\[([^\]]*)\]:\s*([^ ]*)(.*)$', re.DOTALL)
1956516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
1966516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru    def run (self, lines):
1976516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        new_text = [];
1986516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        for line in lines:
1996516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            m = self.RE.match(line)
2006516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            if m:
2016516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                id = m.group(2).strip().lower()
2026516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                t = m.group(4).strip()  # potential title
2036516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                if not t:
2046516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                    self.markdown.references[id] = (m.group(3), t)
2056516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                elif (len(t) >= 2
2066516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                      and (t[0] == t[-1] == "\""
2076516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                           or t[0] == t[-1] == "\'"
2086516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                           or (t[0] == "(" and t[-1] == ")") ) ):
2096516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                    self.markdown.references[id] = (m.group(3), t[1:-1])
2106516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                else:
2116516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                    new_text.append(line)
2126516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru            else:
2136516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru                new_text.append(line)
2146516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru
2156516b99bb74dfb7187a08f7090bf7ca22a006f15Jean-Baptiste Queru        return new_text #+ "\n"
216