diff options
Diffstat (limited to 'markdown_extensions/footnotes.py')
-rw-r--r-- | markdown_extensions/footnotes.py | 293 |
1 files changed, 0 insertions, 293 deletions
diff --git a/markdown_extensions/footnotes.py b/markdown_extensions/footnotes.py deleted file mode 100644 index f65a79d..0000000 --- a/markdown_extensions/footnotes.py +++ /dev/null @@ -1,293 +0,0 @@ -""" -========================= FOOTNOTES ================================= - -This section adds footnote handling to markdown. It can be used as -an example for extending python-markdown with relatively complex -functionality. While in this case the extension is included inside -the module itself, it could just as easily be added from outside the -module. Not that all markdown classes above are ignorant about -footnotes. All footnote functionality is provided separately and -then added to the markdown instance at the run time. - -Footnote functionality is attached by calling extendMarkdown() -method of FootnoteExtension. The method also registers the -extension to allow it's state to be reset by a call to reset() -method. - -Example: - Footnotes[^1] have a label[^label] and a definition[^!DEF]. - - [^1]: This is a footnote - [^label]: A footnote on "label" - [^!DEF]: The footnote for definition - -""" - -import re, markdown -from markdown import etree - -FN_BACKLINK_TEXT = "zz1337820767766393qq" -NBSP_PLACEHOLDER = "qq3936677670287331zz" -DEF_RE = re.compile(r'(\ ?\ ?\ ?)\[\^([^\]]*)\]:\s*(.*)') -TABBED_RE = re.compile(r'((\t)|( ))(.*)') - -class FootnoteExtension(markdown.Extension): - """ Footnote Extension. """ - - def __init__ (self, configs): - """ Setup configs. """ - self.config = {'PLACE_MARKER': - ["///Footnotes Go Here///", - "The text string that marks where the footnotes go"]} - - for key, value in configs: - self.config[key][0] = value - - self.reset() - - def extendMarkdown(self, md, md_globals): - """ Add pieces to Markdown. """ - md.registerExtension(self) - self.parser = md.parser - # Insert a preprocessor before ReferencePreprocessor - md.preprocessors.add("footnote", FootnotePreprocessor(self), - "<reference") - # Insert an inline pattern before ImageReferencePattern - FOOTNOTE_RE = r'\[\^([^\]]*)\]' # blah blah [^1] blah - md.inlinePatterns.add("footnote", FootnotePattern(FOOTNOTE_RE, self), - "<reference") - # Insert a tree-processor that would actually add the footnote div - # This must be before the inline treeprocessor so inline patterns - # run on the contents of the div. - md.treeprocessors.add("footnote", FootnoteTreeprocessor(self), - "<inline") - # Insert a postprocessor after amp_substitute oricessor - md.postprocessors.add("footnote", FootnotePostprocessor(self), - ">amp_substitute") - - def reset(self): - """ Clear the footnotes on reset. """ - self.footnotes = markdown.OrderedDict() - - def findFootnotesPlaceholder(self, root): - """ Return ElementTree Element that contains Footnote placeholder. """ - def finder(element): - for child in element: - if child.text: - if child.text.find(self.getConfig("PLACE_MARKER")) > -1: - return child, True - if child.tail: - if child.tail.find(self.getConfig("PLACE_MARKER")) > -1: - return (child, element), False - finder(child) - return None - - res = finder(root) - return res - - def setFootnote(self, id, text): - """ Store a footnote for later retrieval. """ - self.footnotes[id] = text - - def makeFootnoteId(self, id): - """ Return footnote link id. """ - return 'fn:%s' % id - - def makeFootnoteRefId(self, id): - """ Return footnote back-link id. """ - return 'fnref:%s' % id - - def makeFootnotesDiv(self, root): - """ Return div of footnotes as et Element. """ - - if not self.footnotes.keys(): - return None - - div = etree.Element("div") - div.set('class', 'footnote') - hr = etree.SubElement(div, "hr") - ol = etree.SubElement(div, "ol") - - for id in self.footnotes.keys(): - li = etree.SubElement(ol, "li") - li.set("id", self.makeFootnoteId(id)) - self.parser.parseChunk(li, self.footnotes[id]) - backlink = etree.Element("a") - backlink.set("href", "#" + self.makeFootnoteRefId(id)) - backlink.set("rev", "footnote") - backlink.set("title", "Jump back to footnote %d in the text" % \ - (self.footnotes.index(id)+1)) - backlink.text = FN_BACKLINK_TEXT - - if li.getchildren(): - node = li[-1] - if node.tag == "p": - node.text = node.text + NBSP_PLACEHOLDER - node.append(backlink) - else: - p = etree.SubElement(li, "p") - p.append(backlink) - return div - - -class FootnotePreprocessor(markdown.Preprocessor): - """ Find all footnote references and store for later use. """ - - def __init__ (self, footnotes): - self.footnotes = footnotes - - def run(self, lines): - lines = self._handleFootnoteDefinitions(lines) - text = "\n".join(lines) - return text.split("\n") - - def _handleFootnoteDefinitions(self, lines): - """ - Recursively find all footnote definitions in lines. - - Keywords: - - * lines: A list of lines of text - - Return: A list of lines with footnote definitions removed. - - """ - i, id, footnote = self._findFootnoteDefinition(lines) - - if id : - plain = lines[:i] - detabbed, theRest = self.detectTabbed(lines[i+1:]) - self.footnotes.setFootnote(id, - footnote + "\n" - + "\n".join(detabbed)) - more_plain = self._handleFootnoteDefinitions(theRest) - return plain + [""] + more_plain - else : - return lines - - def _findFootnoteDefinition(self, lines): - """ - Find the parts of a footnote definition. - - Keywords: - - * lines: A list of lines of text. - - Return: A three item tuple containing the index of the first line of a - footnote definition, the id of the definition and the body of the - definition. - - """ - counter = 0 - for line in lines: - m = DEF_RE.match(line) - if m: - return counter, m.group(2), m.group(3) - counter += 1 - return counter, None, None - - def detectTabbed(self, lines): - """ Find indented text and remove indent before further proccesing. - - Keyword arguments: - - * lines: an array of strings - - Returns: a list of post processed items and the unused - remainder of the original list - - """ - items = [] - item = -1 - i = 0 # to keep track of where we are - - def detab(line): - match = TABBED_RE.match(line) - if match: - return match.group(4) - - for line in lines: - if line.strip(): # Non-blank line - line = detab(line) - if line: - items.append(line) - i += 1 - continue - else: - return items, lines[i:] - - else: # Blank line: _maybe_ we are done. - i += 1 # advance - - # Find the next non-blank line - for j in range(i, len(lines)): - if lines[j].strip(): - next_line = lines[j]; break - else: - break # There is no more text; we are done. - - # Check if the next non-blank line is tabbed - if detab(next_line): # Yes, more work to do. - items.append("") - continue - else: - break # No, we are done. - else: - i += 1 - - return items, lines[i:] - - -class FootnotePattern(markdown.Pattern): - """ InlinePattern for footnote markers in a document's body text. """ - - def __init__(self, pattern, footnotes): - markdown.Pattern.__init__(self, pattern) - self.footnotes = footnotes - - def handleMatch(self, m): - sup = etree.Element("sup") - a = etree.SubElement(sup, "a") - id = m.group(2) - sup.set('id', self.footnotes.makeFootnoteRefId(id)) - a.set('href', '#' + self.footnotes.makeFootnoteId(id)) - a.set('rel', 'footnote') - a.text = str(self.footnotes.footnotes.index(id) + 1) - return sup - - -class FootnoteTreeprocessor(markdown.Treeprocessor): - """ Build and append footnote div to end of document. """ - - def __init__ (self, footnotes): - self.footnotes = footnotes - - def run(self, root): - footnotesDiv = self.footnotes.makeFootnotesDiv(root) - if footnotesDiv: - result = self.footnotes.findFootnotesPlaceholder(root) - if result: - node, isText = result - if isText: - node.text = None - node.getchildren().insert(0, footnotesDiv) - else: - child, element = node - ind = element.getchildren().find(child) - element.getchildren().insert(ind + 1, footnotesDiv) - child.tail = None - fnPlaceholder.parent.replaceChild(fnPlaceholder, footnotesDiv) - else: - root.append(footnotesDiv) - -class FootnotePostprocessor(markdown.Postprocessor): - """ Replace placeholders with html entities. """ - - def run(self, text): - text = text.replace(FN_BACKLINK_TEXT, "↩") - return text.replace(NBSP_PLACEHOLDER, " ") - -def makeExtension(configs=[]): - """ Return an instance of the FootnoteExtension """ - return FootnoteExtension(configs=configs) - |