aboutsummaryrefslogtreecommitdiffstats
path: root/markdown_extensions
diff options
context:
space:
mode:
authorWaylan Limberg <waylan@gmail.com>2008-11-20 19:45:33 -0500
committerWaylan Limberg <waylan@gmail.com>2008-11-20 19:45:33 -0500
commit34666742ee4b5cb03f9a9f6297d5784f553d5346 (patch)
treec9e7ece5ba86bdc3adbf7150c25cd6f9b4ed0bdb /markdown_extensions
parent517d38e552e91ebbe527a0286d43dd1daa585bcc (diff)
downloadmarkdown-34666742ee4b5cb03f9a9f6297d5784f553d5346.tar.gz
markdown-34666742ee4b5cb03f9a9f6297d5784f553d5346.tar.bz2
markdown-34666742ee4b5cb03f9a9f6297d5784f553d5346.zip
Moved markdown_extensions/ to markdown/extensions. Markdown is now one package instead of two.
Diffstat (limited to 'markdown_extensions')
-rw-r--r--markdown_extensions/__init__.py0
-rw-r--r--markdown_extensions/abbr.py95
-rw-r--r--markdown_extensions/codehilite.py224
-rw-r--r--markdown_extensions/def_list.py206
-rw-r--r--markdown_extensions/extra.py52
-rw-r--r--markdown_extensions/fenced_code.py117
-rw-r--r--markdown_extensions/footnotes.py293
-rw-r--r--markdown_extensions/headerid.py172
-rw-r--r--markdown_extensions/imagelinks.py119
-rw-r--r--markdown_extensions/legacy.py468
-rw-r--r--markdown_extensions/meta.py90
-rw-r--r--markdown_extensions/rss.py118
-rw-r--r--markdown_extensions/tables.py70
-rw-r--r--markdown_extensions/toc.py137
-rw-r--r--markdown_extensions/wikilinks.py138
15 files changed, 0 insertions, 2299 deletions
diff --git a/markdown_extensions/__init__.py b/markdown_extensions/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/markdown_extensions/__init__.py
+++ /dev/null
diff --git a/markdown_extensions/abbr.py b/markdown_extensions/abbr.py
deleted file mode 100644
index 551e4f5..0000000
--- a/markdown_extensions/abbr.py
+++ /dev/null
@@ -1,95 +0,0 @@
-'''
-Abbreviation Extension for Python-Markdown
-==========================================
-
-This extension adds abbreviation handling to Python-Markdown.
-
-Simple Usage:
-
- >>> import markdown
- >>> text = """
- ... Some text with an ABBR and a REF. Ignore REFERENCE and ref.
- ...
- ... *[ABBR]: Abbreviation
- ... *[REF]: Abbreviation Reference
- ... """
- >>> markdown.markdown(text, ['abbr'])
- u'<p>Some text with an <abbr title="Abbreviation">ABBR</abbr> and a <abbr title="Abbreviation Reference">REF</abbr>. Ignore REFERENCE and ref.</p>'
-
-Copyright 2007-2008
-* [Waylan Limberg](http://achinghead.com/)
-* [Seemant Kulleen](http://www.kulleen.org/)
-
-
-'''
-
-import markdown, re
-from markdown import etree
-
-# Global Vars
-ABBR_REF_RE = re.compile(r'[*]\[(?P<abbr>[^\]]*)\][ ]?:\s*(?P<title>.*)')
-
-class AbbrExtension(markdown.Extension):
- """ Abbreviation Extension for Python-Markdown. """
-
- def extendMarkdown(self, md, md_globals):
- """ Insert AbbrPreprocessor before ReferencePreprocessor. """
- md.preprocessors.add('abbr', AbbrPreprocessor(md), '<reference')
-
-
-class AbbrPreprocessor(markdown.Preprocessor):
- """ Abbreviation Preprocessor - parse text for abbr references. """
-
- def run(self, lines):
- '''
- Find and remove all Abbreviation references from the text.
- Each reference is set as a new AbbrPattern in the markdown instance.
-
- '''
- new_text = []
- for line in lines:
- m = ABBR_REF_RE.match(line)
- if m:
- abbr = m.group('abbr').strip()
- title = m.group('title').strip()
- self.markdown.inlinePatterns['abbr-%s'%abbr] = \
- AbbrPattern(self._generate_pattern(abbr), title)
- else:
- new_text.append(line)
- return new_text
-
- def _generate_pattern(self, text):
- '''
- Given a string, returns an regex pattern to match that string.
-
- 'HTML' -> r'(?P<abbr>[H][T][M][L])'
-
- Note: we force each char as a literal match (in brackets) as we don't
- know what they will be beforehand.
-
- '''
- chars = list(text)
- for i in range(len(chars)):
- chars[i] = r'[%s]' % chars[i]
- return r'(?P<abbr>\b%s\b)' % (r''.join(chars))
-
-
-class AbbrPattern(markdown.Pattern):
- """ Abbreviation inline pattern. """
-
- def __init__(self, pattern, title):
- markdown.Pattern.__init__(self, pattern)
- self.title = title
-
- def handleMatch(self, m):
- abbr = etree.Element('abbr')
- abbr.text = m.group('abbr')
- abbr.set('title', self.title)
- return abbr
-
-def makeExtension(configs=None):
- return AbbrExtension(configs=configs)
-
-if __name__ == "__main__":
- import doctest
- doctest.testmod()
diff --git a/markdown_extensions/codehilite.py b/markdown_extensions/codehilite.py
deleted file mode 100644
index bc75da2..0000000
--- a/markdown_extensions/codehilite.py
+++ /dev/null
@@ -1,224 +0,0 @@
-#!/usr/bin/python
-
-"""
-CodeHilite Extension for Python-Markdown
-========================================
-
-Adds code/syntax highlighting to standard Python-Markdown code blocks.
-
-Copyright 2006-2008 [Waylan Limberg](http://achinghead.com/).
-
-Project website: <http://www.freewisdom.org/project/python-markdown/CodeHilite>
-Contact: markdown@freewisdom.org
-
-License: BSD (see ../docs/LICENSE for details)
-
-Dependencies:
-* [Python 2.3+](http://python.org/)
-* [Markdown 2.0+](http://www.freewisdom.org/projects/python-markdown/)
-* [Pygments](http://pygments.org/)
-
-"""
-
-import markdown
-
-# --------------- CONSTANTS YOU MIGHT WANT TO MODIFY -----------------
-
-try:
- TAB_LENGTH = markdown.TAB_LENGTH
-except AttributeError:
- TAB_LENGTH = 4
-
-
-# ------------------ The Main CodeHilite Class ----------------------
-class CodeHilite:
- """
- Determine language of source code, and pass it into the pygments hilighter.
-
- Basic Usage:
- >>> code = CodeHilite(src = 'some text')
- >>> html = code.hilite()
-
- * src: Source string or any object with a .readline attribute.
-
- * linenos: (Boolen) Turn line numbering 'on' or 'off' (off by default).
-
- * css_class: Set class name of wrapper div ('codehilite' by default).
-
- Low Level Usage:
- >>> code = CodeHilite()
- >>> code.src = 'some text' # String or anything with a .readline attr.
- >>> code.linenos = True # True or False; Turns line numbering on or of.
- >>> html = code.hilite()
-
- """
-
- def __init__(self, src=None, linenos=False, css_class="codehilite"):
- self.src = src
- self.lang = None
- self.linenos = linenos
- self.css_class = css_class
-
- def hilite(self):
- """
- Pass code to the [Pygments](http://pygments.pocoo.org/) highliter with
- optional line numbers. The output should then be styled with css to
- your liking. No styles are applied by default - only styling hooks
- (i.e.: <span class="k">).
-
- returns : A string of html.
-
- """
-
- self.src = self.src.strip('\n')
-
- self._getLang()
-
- try:
- from pygments import highlight
- from pygments.lexers import get_lexer_by_name, guess_lexer, \
- TextLexer
- from pygments.formatters import HtmlFormatter
- except ImportError:
- # just escape and pass through
- txt = self._escape(self.src)
- if self.linenos:
- txt = self._number(txt)
- else :
- txt = '<div class="%s"><pre>%s</pre></div>\n'% \
- (self.css_class, txt)
- return txt
- else:
- try:
- lexer = get_lexer_by_name(self.lang)
- except ValueError:
- try:
- lexer = guess_lexer(self.src)
- except ValueError:
- lexer = TextLexer()
- formatter = HtmlFormatter(linenos=self.linenos,
- cssclass=self.css_class)
- return highlight(self.src, lexer, formatter)
-
- def _escape(self, txt):
- """ basic html escaping """
- txt = txt.replace('&', '&amp;')
- txt = txt.replace('<', '&lt;')
- txt = txt.replace('>', '&gt;')
- txt = txt.replace('"', '&quot;')
- return txt
-
- def _number(self, txt):
- """ Use <ol> for line numbering """
- # Fix Whitespace
- txt = txt.replace('\t', ' '*TAB_LENGTH)
- txt = txt.replace(" "*4, "&nbsp; &nbsp; ")
- txt = txt.replace(" "*3, "&nbsp; &nbsp;")
- txt = txt.replace(" "*2, "&nbsp; ")
-
- # Add line numbers
- lines = txt.splitlines()
- txt = '<div class="codehilite"><pre><ol>\n'
- for line in lines:
- txt += '\t<li>%s</li>\n'% line
- txt += '</ol></pre></div>\n'
- return txt
-
-
- def _getLang(self):
- """
- Determines language of a code block from shebang lines and whether said
- line should be removed or left in place. If the sheband line contains a
- path (even a single /) then it is assumed to be a real shebang lines and
- left alone. However, if no path is given (e.i.: #!python or :::python)
- then it is assumed to be a mock shebang for language identifitation of a
- code fragment and removed from the code block prior to processing for
- code highlighting. When a mock shebang (e.i: #!python) is found, line
- numbering is turned on. When colons are found in place of a shebang
- (e.i.: :::python), line numbering is left in the current state - off
- by default.
-
- """
-
- import re
-
- #split text into lines
- lines = self.src.split("\n")
- #pull first line to examine
- fl = lines.pop(0)
-
- c = re.compile(r'''
- (?:(?:::+)|(?P<shebang>[#]!)) # Shebang or 2 or more colons.
- (?P<path>(?:/\w+)*[/ ])? # Zero or 1 path
- (?P<lang>[\w+-]*) # The language
- ''', re.VERBOSE)
- # search first line for shebang
- m = c.search(fl)
- if m:
- # we have a match
- try:
- self.lang = m.group('lang').lower()
- except IndexError:
- self.lang = None
- if m.group('path'):
- # path exists - restore first line
- lines.insert(0, fl)
- if m.group('shebang'):
- # shebang exists - use line numbers
- self.linenos = True
- else:
- # No match
- lines.insert(0, fl)
-
- self.src = "\n".join(lines).strip("\n")
-
-
-
-# ------------------ The Markdown Extension -------------------------------
-class HiliteTreeprocessor(markdown.Treeprocessor):
- """ Hilight source code in code blocks. """
-
- def run(self, root):
- """ Find code blocks and store in htmlStash. """
- blocks = root.getiterator('pre')
- for block in blocks:
- children = block.getchildren()
- if len(children) == 1 and children[0].tag == 'code':
- code = CodeHilite(children[0].text,
- linenos=self.config['force_linenos'][0],
- css_class=self.config['css_class'][0])
- placeholder = self.markdown.htmlStash.store(code.hilite(),
- safe=True)
- # Clear codeblock in etree instance
- block.clear()
- # Change to p element which will later
- # be removed when inserting raw html
- block.tag = 'p'
- block.text = placeholder
-
-
-class CodeHiliteExtension(markdown.Extension):
- """ Add source code hilighting to markdown codeblocks. """
-
- def __init__(self, configs):
- # define default configs
- self.config = {
- 'force_linenos' : [False, "Force line numbers - Default: False"],
- 'css_class' : ["codehilite",
- "Set class name for wrapper <div> - Default: codehilite"],
- }
-
- # Override defaults with user settings
- for key, value in configs:
- self.setConfig(key, value)
-
- def extendMarkdown(self, md, md_globals):
- """ Add HilitePostprocessor to Markdown instance. """
- hiliter = HiliteTreeprocessor(md)
- hiliter.config = self.config
- md.treeprocessors.add("hilite", hiliter, "_begin")
-
-
-def makeExtension(configs={}):
- return CodeHiliteExtension(configs=configs)
-
diff --git a/markdown_extensions/def_list.py b/markdown_extensions/def_list.py
deleted file mode 100644
index 831e840..0000000
--- a/markdown_extensions/def_list.py
+++ /dev/null
@@ -1,206 +0,0 @@
-#!/usr/bin/env Python
-"""
-Definition List Extension for Python-Markdown
-=============================================
-
-Added parsing of Definition Lists to Python-Markdown.
-
-A simple example:
-
- Apple
- : Pomaceous fruit of plants of the genus Malus in
- the family Rosaceae.
- : An american computer company.
-
- Orange
- : The fruit of an evergreen tree of the genus Citrus.
-
-Copyright 2008 - [Waylan Limberg](http://achinghead.com)
-
-"""
-
-import markdown, re
-from markdown import etree, CORE_RE
-
-DEF_RE = re.compile(r'^[ ]{0,3}:[ ]{1,3}(.*)$')
-
-class DefListParser(markdown.MarkdownParser):
- """ Subclass of MarkdownParser which adds definition list parsing. """
-
- def parseChunk(self, parent_elem, lines, inList=0, looseList=0):
- """Process a chunk of markdown-formatted text and attach the parse to
- an ElementTree node.
-
- Process a section of a source document, looking for high
- level structural elements like lists, block quotes, code
- segments, html blocks, etc. Some those then get stripped
- of their high level markup (e.g. get unindented) and the
- lower-level markup is processed recursively.
-
- Keyword arguments:
-
- * parent_elem: The ElementTree element to which the content will be
- added.
- * lines: a list of lines
- * inList: a level
-
- Returns: None
-
- """
- # Loop through lines until none left.
- while lines:
- # Skipping empty line
- if not lines[0]:
- lines = lines[1:]
- continue
-
- # Check if this section starts with a list, a blockquote or
- # a code block. If so, process them.
- processFn = { 'ul': self._MarkdownParser__processUList,
- 'ol': self._MarkdownParser__processOList,
- 'quoted': self._MarkdownParser__processQuote,
- 'tabbed': self._MarkdownParser__processCodeBlock}
- for regexp in ['ul', 'ol', 'quoted', 'tabbed']:
- m = CORE_RE[regexp].match(lines[0])
- if m:
- processFn[regexp](parent_elem, lines, inList)
- return
-
- # We are NOT looking at one of the high-level structures like
- # lists or blockquotes. So, it's just a regular paragraph
- # (though perhaps nested inside a list or something else). If
- # we are NOT inside a list, we just need to look for a blank
- # line to find the end of the block. If we ARE inside a
- # list, however, we need to consider that a sublist does not
- # need to be separated by a blank line. Rather, the following
- # markup is legal:
- #
- # * The top level list item
- #
- # Another paragraph of the list. This is where we are now.
- # * Underneath we might have a sublist.
- #
-
- if inList:
- start, lines = self._MarkdownParser__linesUntil(lines, (lambda line:
- CORE_RE['ul'].match(line)
- or CORE_RE['ol'].match(line)
- or not line.strip()))
- self.parseChunk(parent_elem, start, inList-1,
- looseList=looseList)
- inList = inList-1
-
- else: # Ok, so it's just a simple block
- test = lambda line: not line.strip() or line[0] == '>'
- paragraph, lines = self._MarkdownParser__linesUntil(lines, test)
- if len(paragraph) and paragraph[0].startswith('#'):
- self._MarkdownParser__processHeader(parent_elem, paragraph)
- elif len(paragraph) and CORE_RE["isline3"].match(paragraph[0]):
- self._MarkdownParser__processHR(parent_elem)
- lines = paragraph[1:] + lines
- elif paragraph:
- paragraph, lines, looseList = self._processDefs(parent_elem,
- paragraph,
- lines,
- looseList)
- if len(paragraph):
- self._MarkdownParser__processParagraph(parent_elem,
- paragraph,
- inList,
- looseList)
-
- if lines and not lines[0].strip():
- lines = lines[1:] # skip the first (blank) line
-
-
- def _processDefs(self, parentElem, paragraph, lines, looseList):
- """ Check a paragraph for definition lists and process. """
- terms = []
- defs = []
- i = 0
- while i < len(paragraph):
- m = DEF_RE.match(paragraph[i])
- if m:
- d, theRest = self.detectTabbed(paragraph[i+1:])
- d.insert(0, m.group(1))
- if d:
- defs.append(d)
- i += len(d)
- else:
- terms.append(paragraph[i])
- i += 1
- if defs:
- if not terms:
- # The previous paragraph must contain the terms
- c = parentElem.getchildren()
- if c and c[-1].tag == "p" and c[-1].text:
- terms = c[-1].text.split("\n")
- parentElem.remove(c[-1])
- looseList = 1
- # check for extra paragraphs of a def
- extradef, lines = self.detectTabbed(lines)
- if extradef:
- looseList = 1
- defs[-1].extend(extradef)
- # Build a tree from the terms and defs
- c = parentElem.getchildren()
- if c and c[-1].tag == "dl":
- dl = c[-1]
- else:
- dl = etree.SubElement(parentElem, "dl")
- for term in terms:
- dt = etree.SubElement(dl, "dt")
- dt.text = term
- for d in defs:
- dd = etree.SubElement(dl, "dd")
- self.parseChunk(dd, d, looseList = looseList)
- return [], lines, looseList
- else:
- return terms, lines, looseList
-
- def _MarkdownParser__processParagraph(self, parentElem, paragraph,
- inList, looseList):
-
- if ((parentElem.tag == 'li' or parentElem.tag == 'dd')
- and not (looseList or parentElem.getchildren())):
-
- # If this is the first paragraph inside "li", don't
- # put <p> around it - append the paragraph bits directly
- # onto parentElem
- el = parentElem
- else:
- # Otherwise make a "p" element
- el = etree.SubElement(parentElem, "p")
-
- dump = []
-
- # Searching for hr or header
- for line in paragraph:
- # it's hr
- if CORE_RE["isline3"].match(line):
- el.text = "\n".join(dump)
- self._MarkdownParser__processHR(el)
- dump = []
- # it's header
- elif line.startswith("#"):
- el.text = "\n".join(dump)
- self._MarkdownParser__processHeader(parentElem, [line])
- dump = []
- else:
- dump.append(line)
- if dump:
- text = "\n".join(dump)
- el.text = text
-
-
-class DefListExtension(markdown.Extension):
- """ Add definition lists to Markdown. """
-
- def extendMarkdown(self, md, md_globals):
- """ Set the core parser to an instance of DefListParser. """
- md.parser = DefListParser()
-
-
-def makeExtension(configs={}):
- return DefListExtension(configs=configs)
-
diff --git a/markdown_extensions/extra.py b/markdown_extensions/extra.py
deleted file mode 100644
index e99bec4..0000000
--- a/markdown_extensions/extra.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env python
-"""
-Python-Markdown Extra Extension
-===============================
-
-A compilation of various Python-Markdown extensions that imitates
-[PHP Markdown Extra](http://michelf.com/projects/php-markdown/extra/).
-
-As no-one has yet written a Definition List extension for Python-
-Markdown, definition lists are not yet supported by Extra.
-
-Note that each of the individual extensions still need to be available
-on your PYTHONPATH. This extension simply wraps them all up as a
-convenience so that only one extension needs to be listed when
-initiating Markdown. See the documentation for each individual
-extension for specifics about that extension.
-
-In the event that one or more of the supported extensions are not
-available for import, Markdown will simply continue without that
-extension. If you would like to be notified of such failures,
-you may set Python-Markdown's logger level to "WARN".
-
-There may be additional extensions that are distributed with
-Python-Markdown that are not included here in Extra. Those extensions
-are not part of PHP Markdown Extra, and therefore, not part of
-Python-Markdown Extra. If you really would like Extra to include
-additional extensions, we suggest creating your own clone of Extra
-under a differant name. You could also edit the `extensions` global
-variable defined below, but be aware that such changes may be lost
-when you upgrade to any future version of Python-Markdown.
-
-"""
-
-import markdown
-
-extensions = ['fenced_code',
- 'footnotes',
- 'headerid',
- 'tables',
- 'abbr',
- ]
-
-
-class ExtraExtension(markdown.Extension):
- """ Add various extensions to Markdown class."""
-
- def extendMarkdown(self, md, md_globals):
- """ Register extension instances. """
- md.registerExtensions(extensions, self.config)
-
-def makeExtension(configs={}):
- return ExtraExtension(configs=dict(configs))
diff --git a/markdown_extensions/fenced_code.py b/markdown_extensions/fenced_code.py
deleted file mode 100644
index fa768c0..0000000
--- a/markdown_extensions/fenced_code.py
+++ /dev/null
@@ -1,117 +0,0 @@
-#!/usr/bin/env python
-
-"""
-Fenced Code Extension for Python Markdown
-=========================================
-
-This extension adds Fenced Code Blocks to Python-Markdown.
-
- >>> import markdown
- >>> text = '''
- ... A paragraph before a fenced code block:
- ...
- ... ~~~
- ... Fenced code block
- ... ~~~
- ... '''
- >>> html = markdown.markdown(text, extensions=['fenced_code'])
- >>> html
- u'<p>A paragraph before a fenced code block:</p>\\n<pre><code>Fenced code block\\n</code></pre>'
-
-Works with safe_mode also (we check this because we are using the HtmlStash):
-
- >>> markdown.markdown(text, extensions=['fenced_code'], safe_mode='replace')
- u'<p>A paragraph before a fenced code block:</p>\\n<pre><code>Fenced code block\\n</code></pre>'
-
-Include tilde's in a code block and wrap with blank lines:
-
- >>> text = '''
- ... ~~~~~~~~
- ...
- ... ~~~~
- ...
- ... ~~~~~~~~'''
- >>> markdown.markdown(text, extensions=['fenced_code'])
- u'<pre><code>\\n~~~~\\n\\n</code></pre>'
-
-Multiple blocks and language tags:
-
- >>> text = '''
- ... ~~~~
- ... block one
- ... ~~~~{.python}
- ...
- ... ~~~~
- ... <p>block two</p>
- ... ~~~~{.html}'''
- >>> markdown.markdown(text, extensions=['fenced_code'])
- u'<pre><code class="python">block one\\n</code></pre>\\n\\n<pre><code class="html">&lt;p&gt;block two&lt;/p&gt;\\n</code></pre>'
-
-Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/).
-
-Project website: <http://www.freewisdom.org/project/python-markdown/Fenced__Code__Blocks>
-Contact: markdown@freewisdom.org
-
-License: BSD (see ../docs/LICENSE for details)
-
-Dependencies:
-* [Python 2.3+](http://python.org)
-* [Markdown 2.0+](http://www.freewisdom.org/projects/python-markdown/)
-
-"""
-
-import markdown, re
-
-# Global vars
-FENCED_BLOCK_RE = re.compile( \
- r'(?P<fence>^~{3,})[ ]*\n(?P<code>.*?)(?P=fence)[ ]*(\{\.(?P<lang>[a-zA-Z0-9_-]*)\})?[ ]*$',
- re.MULTILINE|re.DOTALL
- )
-CODE_WRAP = '<pre><code%s>%s</code></pre>'
-LANG_TAG = ' class="%s"'
-
-
-class FencedCodeExtension(markdown.Extension):
-
- def extendMarkdown(self, md, md_globals):
- """ Add FencedBlockPreprocessor to the Markdown instance. """
-
- md.preprocessors.add('fenced_code_block',
- FencedBlockPreprocessor(md),
- "_begin")
-
-
-class FencedBlockPreprocessor(markdown.Preprocessor):
-
- def run(self, lines):
- """ Match and store Fenced Code Blocks in the HtmlStash. """
- text = "\n".join(lines)
- while 1:
- m = FENCED_BLOCK_RE.search(text)
- if m:
- lang = ''
- if m.group('lang'):
- lang = LANG_TAG % m.group('lang')
- code = CODE_WRAP % (lang, self._escape(m.group('code')))
- placeholder = self.markdown.htmlStash.store(code, safe=True)
- text = '%s\n%s\n%s'% (text[:m.start()], placeholder, text[m.end():])
- else:
- break
- return text.split("\n")
-
- def _escape(self, txt):
- """ basic html escaping """
- txt = txt.replace('&', '&amp;')
- txt = txt.replace('<', '&lt;')
- txt = txt.replace('>', '&gt;')
- txt = txt.replace('"', '&quot;')
- return txt
-
-
-def makeExtension(configs=None):
- return FencedCodeExtension()
-
-
-if __name__ == "__main__":
- import doctest
- doctest.testmod()
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, "&#8617;")
- return text.replace(NBSP_PLACEHOLDER, "&#160;")
-
-def makeExtension(configs=[]):
- """ Return an instance of the FootnoteExtension """
- return FootnoteExtension(configs=configs)
-
diff --git a/markdown_extensions/headerid.py b/markdown_extensions/headerid.py
deleted file mode 100644
index 294bfd9..0000000
--- a/markdown_extensions/headerid.py
+++ /dev/null
@@ -1,172 +0,0 @@
-#!/usr/bin/python
-
-"""
-HeaderID Extension for Python-Markdown
-======================================
-
-Adds ability to set HTML IDs for headers.
-
-Basic usage:
-
- >>> import markdown
- >>> text = "# Some Header # {#some_id}"
- >>> md = markdown.markdown(text, ['headerid'])
- >>> md
- u'<h1 id="some_id">Some Header</h1>'
-
-All header IDs are unique:
-
- >>> text = '''
- ... #Header
- ... #Another Header {#header}
- ... #Third Header {#header}'''
- >>> md = markdown.markdown(text, ['headerid'])
- >>> md
- u'<h1 id="header">Header</h1>\\n<h1 id="header_1">Another Header</h1>\\n<h1 id="header_2">Third Header</h1>'
-
-To fit within a html template's hierarchy, set the header base level:
-
- >>> text = '''
- ... #Some Header
- ... ## Next Level'''
- >>> md = markdown.markdown(text, ['headerid(level=3)'])
- >>> md
- u'<h3 id="some_header">Some Header</h3>\\n<h4 id="next_level">Next Level</h4>'
-
-Turn off auto generated IDs:
-
- >>> text = '''
- ... # Some Header
- ... # Header with ID # { #foo }'''
- >>> md = markdown.markdown(text, ['headerid(forceid=False)'])
- >>> md
- u'<h1>Some Header</h1>\\n<h1 id="foo">Header with ID</h1>'
-
-Use with MetaData extension:
-
- >>> text = '''header_level: 2
- ... header_forceid: Off
- ...
- ... # A Header'''
- >>> md = markdown.markdown(text, ['headerid', 'meta'])
- >>> md
- u'<h2>A Header</h2>'
-
-Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/).
-
-Project website: <http://www.freewisdom.org/project/python-markdown/HeaderId>
-Contact: markdown@freewisdom.org
-
-License: BSD (see ../docs/LICENSE for details)
-
-Dependencies:
-* [Python 2.3+](http://python.org)
-* [Markdown 2.0+](http://www.freewisdom.org/projects/python-markdown/)
-
-"""
-
-import markdown
-from markdown import etree
-import re
-from string import ascii_lowercase, digits, punctuation
-
-ID_CHARS = ascii_lowercase + digits + '-_'
-
-HEADER_RE = re.compile(r'''^(\#{1,6}) # group(1) = string of hashes
- ( [^{^#]*) # group(2) = Header text
- [\#]* # optional closing hashes
- (?:[ \t]*\{[ \t]*\#([-_:a-zA-Z0-9]+)[ \t]*\})? # group(3) = id attr''',
- re.VERBOSE)
-
-IDCOUNT_RE = re.compile(r'^(.*)_([0-9]+)$')
-
-class HeaderIdExtension (markdown.Extension) :
- def __init__(self, configs):
- # set defaults
- self.config = {
- 'level' : ['1', 'Base level for headers.'],
- 'forceid' : ['True', 'Force all headers to have an id.']
- }
-
- for key, value in configs:
- self.setConfig(key, value)
-
-
- def extendMarkdown(self, md, md_globals) :
-
- md.IDs = []
-
- def _processHeaderId(parent_elem, paragraph) :
- '''
- Overrides __processHeader of MarkdownParser() and
- adds an 'id' to the header.
- '''
- m = HEADER_RE.match(paragraph[0])
- if m :
- start_level, force_id = _get_meta()
- level = len(m.group(1)) + start_level
- if level > 6:
- level = 6
- h = etree.Element("h%d" % level)
- parent_elem.append(h)
- h.text = m.group(2).strip()
- if m.group(3) :
- h.set('id', _unique_id(m.group(3)))
- elif force_id:
- h.set('id', _create_id(m.group(2).strip()))
- else :
- message(CRITICAL, "We've got a problem header!")
-
- md.parser._MarkdownParser__processHeader = _processHeaderId
-
- def _get_meta():
- ''' Return meta data suported by this ext as a tuple '''
- level = int(self.config['level'][0]) - 1
- force = _str2bool(self.config['forceid'][0])
- if hasattr(md, 'Meta'):
- if md.Meta.has_key('header_level'):
- level = int(md.Meta['header_level'][0]) - 1
- if md.Meta.has_key('header_forceid'):
- force = _str2bool(md.Meta['header_forceid'][0])
- return level, force
-
- def _str2bool(s, default=False):
- ''' Convert a string to a booleen value. '''
- s = str(s)
- if s.lower() in ['0', 'f', 'false', 'off', 'no', 'n']:
- return False
- elif s.lower() in ['1', 't', 'true', 'on', 'yes', 'y']:
- return True
- return default
-
- def _unique_id(id):
- ''' Ensure ID is unique. Append '_1', '_2'... if not '''
- while id in md.IDs:
- m = IDCOUNT_RE.match(id)
- if m:
- id = '%s_%d'% (m.group(1), int(m.group(2))+1)
- else:
- id = '%s_%d'% (id, 1)
- md.IDs.append(id)
- return id
-
-
- def _create_id(header):
- ''' Return ID from Header text. '''
- h = ''
- for c in header.lower().replace(' ', '_'):
- if c in ID_CHARS:
- h += c
- elif c not in punctuation:
- h += '+'
- return _unique_id(h)
-
-
-
-def makeExtension(configs=None) :
- return HeaderIdExtension(configs=configs)
-
-if __name__ == "__main__":
- import doctest
- doctest.testmod()
-
diff --git a/markdown_extensions/imagelinks.py b/markdown_extensions/imagelinks.py
deleted file mode 100644
index ba86d24..0000000
--- a/markdown_extensions/imagelinks.py
+++ /dev/null
@@ -1,119 +0,0 @@
-"""
-========================= IMAGE LINKS =================================
-
-
-Turns paragraphs like
-
-<~~~~~~~~~~~~~~~~~~~~~~~~
-dir/subdir
-dir/subdir
-dir/subdir
-~~~~~~~~~~~~~~
-dir/subdir
-dir/subdir
-dir/subdir
-~~~~~~~~~~~~~~~~~~~>
-
-Into mini-photo galleries.
-
-"""
-
-import re, markdown
-import url_manager
-
-
-IMAGE_LINK = """<a href="%s"><img src="%s" title="%s"/></a>"""
-SLIDESHOW_LINK = """<a href="%s" target="_blank">[slideshow]</a>"""
-ALBUM_LINK = """&nbsp;<a href="%s">[%s]</a>"""
-
-
-class ImageLinksExtension (markdown.Extension):
-
- def extendMarkdown(self, md, md_globals) :
-
- md.preprocessors.add("imagelink", ImageLinkPreprocessor(md), "_begin")
-
-
-class ImageLinkPreprocessor (markdown.Preprocessor):
-
- def run(self, lines) :
-
- url = url_manager.BlogEntryUrl(url_manager.BlogUrl("all"),
- "2006/08/29/the_rest_of_our")
-
-
- all_images = []
- blocks = []
- in_image_block = False
-
- new_lines = []
-
- for line in lines :
-
- if line.startswith("<~~~~~~~") :
- albums = []
- rows = []
- in_image_block = True
-
- if not in_image_block :
-
- new_lines.append(line)
-
- else :
-
- line = line.strip()
-
- if line.endswith("~~~~~~>") or not line :
- in_image_block = False
- new_block = "<div><br/><center><span class='image-links'>\n"
-
- album_url_hash = {}
-
- for row in rows :
- for photo_url, title in row :
- new_block += "&nbsp;"
- new_block += IMAGE_LINK % (photo_url,
- photo_url.get_thumbnail(),
- title)
-
- album_url_hash[str(photo_url.get_album())] = 1
-
- new_block += "<br/>"
-
- new_block += "</span>"
- new_block += SLIDESHOW_LINK % url.get_slideshow()
-
- album_urls = album_url_hash.keys()
- album_urls.sort()
-
- if len(album_urls) == 1 :
- new_block += ALBUM_LINK % (album_urls[0], "complete album")
- else :
- for i in range(len(album_urls)) :
- new_block += ALBUM_LINK % (album_urls[i],
- "album %d" % (i + 1) )
-
- new_lines.append(new_block + "</center><br/></div>")
-
- elif line[1:6] == "~~~~~" :
- rows.append([]) # start a new row
- else :
- parts = line.split()
- line = parts[0]
- title = " ".join(parts[1:])
-
- album, photo = line.split("/")
- photo_url = url.get_photo(album, photo,
- len(all_images)+1)
- all_images.append(photo_url)
- rows[-1].append((photo_url, title))
-
- if not album in albums :
- albums.append(album)
-
- return new_lines
-
-
-def makeExtension(configs) :
- return ImageLinksExtension(configs)
-
diff --git a/markdown_extensions/legacy.py b/markdown_extensions/legacy.py
deleted file mode 100644
index 5b3a9c2..0000000
--- a/markdown_extensions/legacy.py
+++ /dev/null
@@ -1,468 +0,0 @@
-"""
-Legacy Extension for Python-Markdown
-====================================
-
-Replaces the core parser with the old one.
-
-"""
-
-import markdown, re
-from markdown import etree
-
-"""Basic and reusable regular expressions."""
-
-def wrapRe(raw_re) : return re.compile("^%s$" % raw_re, re.DOTALL)
-CORE_RE = {
- 'header': wrapRe(r'(#{1,6})[ \t]*(.*?)[ \t]*(#*)'), # # A title
- 'reference-def': wrapRe(r'(\ ?\ ?\ ?)\[([^\]]*)\]:\s*([^ ]*)(.*)'),
- # [Google]: http://www.google.com/
- 'containsline': wrapRe(r'([-]*)$|^([=]*)'), # -----, =====, etc.
- 'ol': wrapRe(r'[ ]{0,3}[\d]*\.\s+(.*)'), # 1. text
- 'ul': wrapRe(r'[ ]{0,3}[*+-]\s+(.*)'), # "* text"
- 'isline1': wrapRe(r'(\**)'), # ***
- 'isline2': wrapRe(r'(\-*)'), # ---
- 'isline3': wrapRe(r'(\_*)'), # ___
- 'tabbed': wrapRe(r'((\t)|( ))(.*)'), # an indented line
- 'quoted': wrapRe(r'[ ]{0,2}> ?(.*)'), # a quoted block ("> ...")
- 'containsline': re.compile(r'^([-]*)$|^([=]*)$', re.M),
- 'attr': re.compile("\{@([^\}]*)=([^\}]*)}") # {@id=123}
-}
-
-class MarkdownParser:
- """Parser Markdown into a ElementTree."""
-
- def __init__(self):
- pass
-
- def parseDocument(self, lines):
- """Parse a markdown string into an ElementTree."""
- # Create a ElementTree from the lines
- root = etree.Element("div")
- buffer = []
- for line in lines:
- if line.startswith("#"):
- self.parseChunk(root, buffer)
- buffer = [line]
- else:
- buffer.append(line)
-
- self.parseChunk(root, buffer)
-
- return etree.ElementTree(root)
-
- def parseChunk(self, parent_elem, lines, inList=0, looseList=0):
- """Process a chunk of markdown-formatted text and attach the parse to
- an ElementTree node.
-
- Process a section of a source document, looking for high
- level structural elements like lists, block quotes, code
- segments, html blocks, etc. Some those then get stripped
- of their high level markup (e.g. get unindented) and the
- lower-level markup is processed recursively.
-
- Keyword arguments:
-
- * parent_elem: The ElementTree element to which the content will be
- added.
- * lines: a list of lines
- * inList: a level
-
- Returns: None
-
- """
- # Loop through lines until none left.
- while lines:
- # Skipping empty line
- if not lines[0]:
- lines = lines[1:]
- continue
-
- # Check if this section starts with a list, a blockquote or
- # a code block. If so, process them.
- processFn = { 'ul': self.__processUList,
- 'ol': self.__processOList,
- 'quoted': self.__processQuote,
- 'tabbed': self.__processCodeBlock}
- for regexp in ['ul', 'ol', 'quoted', 'tabbed']:
- m = CORE_RE[regexp].match(lines[0])
- if m:
- processFn[regexp](parent_elem, lines, inList)
- return
-
- # We are NOT looking at one of the high-level structures like
- # lists or blockquotes. So, it's just a regular paragraph
- # (though perhaps nested inside a list or something else). If
- # we are NOT inside a list, we just need to look for a blank
- # line to find the end of the block. If we ARE inside a
- # list, however, we need to consider that a sublist does not
- # need to be separated by a blank line. Rather, the following
- # markup is legal:
- #
- # * The top level list item
- #
- # Another paragraph of the list. This is where we are now.
- # * Underneath we might have a sublist.
- #
-
- if inList:
- start, lines = self.__linesUntil(lines, (lambda line:
- CORE_RE['ul'].match(line)
- or CORE_RE['ol'].match(line)
- or not line.strip()))
- self.parseChunk(parent_elem, start, inList-1,
- looseList=looseList)
- inList = inList-1
-
- else: # Ok, so it's just a simple block
- test = lambda line: not line.strip() or line[0] == '>'
- paragraph, lines = self.__linesUntil(lines, test)
- if len(paragraph) and paragraph[0].startswith('#'):
- self.__processHeader(parent_elem, paragraph)
- elif len(paragraph) and CORE_RE["isline3"].match(paragraph[0]):
- self.__processHR(parent_elem)
- lines = paragraph[1:] + lines
- elif paragraph:
- self.__processParagraph(parent_elem, paragraph,
- inList, looseList)
-
- if lines and not lines[0].strip():
- lines = lines[1:] # skip the first (blank) line
-
- def __processHR(self, parentElem):
- hr = etree.SubElement(parentElem, "hr")
-
- def __processHeader(self, parentElem, paragraph):
- m = CORE_RE['header'].match(paragraph[0])
- if m:
- level = len(m.group(1))
- h = etree.SubElement(parentElem, "h%d" % level)
- h.text = m.group(2).strip()
- else:
- message(CRITICAL, "We've got a problem header!")
-
- def __processParagraph(self, parentElem, paragraph, inList, looseList):
-
- if ( parentElem.tag == 'li'
- and not (looseList or parentElem.getchildren())):
-
- # If this is the first paragraph inside "li", don't
- # put <p> around it - append the paragraph bits directly
- # onto parentElem
- el = parentElem
- else:
- # Otherwise make a "p" element
- el = etree.SubElement(parentElem, "p")
-
- dump = []
-
- # Searching for hr or header
- for line in paragraph:
- # it's hr
- if CORE_RE["isline3"].match(line):
- el.text = "\n".join(dump)
- self.__processHR(el)
- dump = []
- # it's header
- elif line.startswith("#"):
- el.text = "\n".join(dump)
- self.__processHeader(parentElem, [line])
- dump = []
- else:
- dump.append(line)
- if dump:
- text = "\n".join(dump)
- el.text = text
-
- def __processUList(self, parentElem, lines, inList):
- self.__processList(parentElem, lines, inList, listexpr='ul', tag='ul')
-
- def __processOList(self, parentElem, lines, inList):
- self.__processList(parentElem, lines, inList, listexpr='ol', tag='ol')
-
- def __processList(self, parentElem, lines, inList, listexpr, tag):
- """
- Given a list of document lines starting with a list item,
- finds the end of the list, breaks it up, and recursively
- processes each list item and the remainder of the text file.
-
- Keyword arguments:
-
- * parentElem: A ElementTree element to which the content will be added
- * lines: a list of lines
- * inList: a level
-
- Returns: None
-
- """
- ul = etree.SubElement(parentElem, tag) # ul might actually be '<ol>'
-
- looseList = 0
-
- # Make a list of list items
- items = []
- item = -1
-
- i = 0 # a counter to keep track of where we are
- for line in lines:
- loose = 0
- if not line.strip():
- # If we see a blank line, this _might_ be the end of the list
- i += 1
- loose = 1
-
- # Find the next non-blank line
- for j in range(i, len(lines)):
- if lines[j].strip():
- next = lines[j]
- break
- else:
- # There is no more text => end of the list
- break
-
- # Check if the next non-blank line is still a part of the list
-
- if ( CORE_RE[listexpr].match(next) or
- CORE_RE['tabbed'].match(next) ):
- # get rid of any white space in the line
- items[item].append(line.strip())
- looseList = loose or looseList
- continue
- else:
- break # found end of the list
-
- # Now we need to detect list items (at the current level)
- # while also detabing child elements if necessary
-
- for expr in ['ul', 'ol', 'tabbed']:
- m = CORE_RE[expr].match(line)
- if m:
- if expr in ['ul', 'ol']: # We are looking at a new item
- #if m.group(1) :
- # Removed the check to allow for a blank line
- # at the beginning of the list item
- items.append([m.group(1)])
- item += 1
- elif expr == 'tabbed': # This line needs to be detabbed
- items[item].append(m.group(4)) #after the 'tab'
- i += 1
- break
- else:
- items[item].append(line) # Just regular continuation
- i += 1 # added on 2006.02.25
- else:
- i += 1
-
- # Add the ElementTree elements
- for item in items:
- li = etree.SubElement(ul, "li")
- self.parseChunk(li, item, inList + 1, looseList = looseList)
-
- # Process the remaining part of the section
- self.parseChunk(parentElem, lines[i:], inList)
-
- def __linesUntil(self, lines, condition):
- """
- A utility function to break a list of lines upon the
- first line that satisfied a condition. The condition
- argument should be a predicate function.
-
- """
- i = -1
- for line in lines:
- i += 1
- if condition(line):
- break
- else:
- i += 1
- return lines[:i], lines[i:]
-
- def __processQuote(self, parentElem, lines, inList):
- """
- Given a list of document lines starting with a quote finds
- the end of the quote, unindents it and recursively
- processes the body of the quote and the remainder of the
- text file.
-
- Keyword arguments:
-
- * parentElem: ElementTree element to which the content will be added
- * lines: a list of lines
- * inList: a level
-
- Returns: None
-
- """
- dequoted = []
- i = 0
- blank_line = False # allow one blank line between paragraphs
- for line in lines:
- m = CORE_RE['quoted'].match(line)
- if m:
- dequoted.append(m.group(1))
- i += 1
- blank_line = False
- elif not blank_line and line.strip() != '':
- dequoted.append(line)
- i += 1
- elif not blank_line and line.strip() == '':
- dequoted.append(line)
- i += 1
- blank_line = True
- else:
- break
-
- blockquote = etree.SubElement(parentElem, "blockquote")
-
- self.parseChunk(blockquote, dequoted, inList)
- self.parseChunk(parentElem, lines[i:], inList)
-
- def __processCodeBlock(self, parentElem, lines, inList):
- """
- Given a list of document lines starting with a code block
- finds the end of the block, puts it into the ElementTree verbatim
- wrapped in ("<pre><code>") and recursively processes the
- the remainder of the text file.
-
- Keyword arguments:
-
- * parentElem: ElementTree element to which the content will be added
- * lines: a list of lines
- * inList: a level
-
- Returns: None
-
- """
- detabbed, theRest = self.detectTabbed(lines)
- pre = etree.SubElement(parentElem, "pre")
- code = etree.SubElement(pre, "code")
- text = "\n".join(detabbed).rstrip()+"\n"
- code.text = markdown.AtomicString(text)
- self.parseChunk(parentElem, theRest, inList)
-
- 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 = CORE_RE['tabbed'].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 HeaderPreprocessor(markdown.Preprocessor):
-
- """Replace underlined headers with hashed headers.
-
- (To avoid the need for lookahead later.)
-
- """
-
- def run (self, lines):
- i = -1
- while i+1 < len(lines):
- i = i+1
- if not lines[i].strip():
- continue
-
- if lines[i].startswith("#"):
- lines.insert(i+1, "\n")
-
- if (i+1 <= len(lines)
- and lines[i+1]
- and lines[i+1][0] in ['-', '=']):
-
- underline = lines[i+1].strip()
-
- if underline == "="*len(underline):
- lines[i] = "# " + lines[i].strip()
- lines[i+1] = ""
- elif underline == "-"*len(underline):
- lines[i] = "## " + lines[i].strip()
- lines[i+1] = ""
-
- return lines
-
-
-class LinePreprocessor(markdown.Preprocessor):
- """Convert HR lines to "___" format."""
- blockquote_re = re.compile(r'^(> )+')
-
- def run (self, lines):
- for i in range(len(lines)):
- prefix = ''
- m = self.blockquote_re.search(lines[i])
- if m:
- prefix = m.group(0)
- if self._isLine(lines[i][len(prefix):]):
- lines[i] = prefix + "___"
- return lines
-
- def _isLine(self, block):
- """Determine if a block should be replaced with an <HR>"""
- if block.startswith(" "):
- return False # a code block
- text = "".join([x for x in block if not x.isspace()])
- if len(text) <= 2:
- return False
- for pattern in ['isline1', 'isline2', 'isline3']:
- m = CORE_RE[pattern].match(text)
- if (m and m.group(1)):
- return True
- else:
- return False
-
-
-class LegacyExtension(markdown.Extension):
- """ Replace Markdown's core parser. """
-
- def extendMarkdown(self, md, md_globals):
- """ Set the core parser to an instance of MarkdownParser. """
- md.parser = MarkdownParser()
- md.preprocessors.add ("header", HeaderPreprocessor(self), "<reference")
- md.preprocessors.add("line", LinePreprocessor(self), "<reference")
-
-
-def makeExtension(configs={}):
- return LegacyExtension(configs=configs)
-
diff --git a/markdown_extensions/meta.py b/markdown_extensions/meta.py
deleted file mode 100644
index 52b71d9..0000000
--- a/markdown_extensions/meta.py
+++ /dev/null
@@ -1,90 +0,0 @@
-#!usr/bin/python
-
-"""
-Meta Data Extension for Python-Markdown
-=======================================
-
-This extension adds Meta Data handling to markdown.
-
-Basic Usage:
-
- >>> import markdown
- >>> text = '''Title: A Test Doc.
- ... Author: Waylan Limberg
- ... John Doe
- ... Blank_Data:
- ...
- ... The body. This is paragraph one.
- ... '''
- >>> md = markdown.Markdown(['meta'])
- >>> md.convert(text)
- u'<p>The body. This is paragraph one.</p>'
- >>> md.Meta
- {u'blank_data': [u''], u'author': [u'Waylan Limberg', u'John Doe'], u'title': [u'A Test Doc.']}
-
-Make sure text without Meta Data still works (markdown < 1.6b returns a <p>).
-
- >>> text = ' Some Code - not extra lines of meta data.'
- >>> md = markdown.Markdown(['meta'])
- >>> md.convert(text)
- u'<pre><code>Some Code - not extra lines of meta data.\\n</code></pre>'
- >>> md.Meta
- {}
-
-Copyright 2007-2008 [Waylan Limberg](http://achinghead.com).
-
-Project website: <http://www.freewisdom.org/project/python-markdown/Meta-Data>
-Contact: markdown@freewisdom.org
-
-License: BSD (see ../docs/LICENSE for details)
-
-"""
-
-import markdown, re
-
-# Global Vars
-META_RE = re.compile(r'^[ ]{0,3}(?P<key>[A-Za-z0-9_-]+):\s*(?P<value>.*)')
-META_MORE_RE = re.compile(r'^[ ]{4,}(?P<value>.*)')
-
-class MetaExtension (markdown.Extension):
- """ Meta-Data extension for Python-Markdown. """
-
- def extendMarkdown(self, md, md_globals):
- """ Add MetaPreprocessor to Markdown instance. """
-
- md.preprocessors.add("meta", MetaPreprocessor(md), "_begin")
-
-
-class MetaPreprocessor(markdown.Preprocessor):
- """ Get Meta-Data. """
-
- def run(self, lines):
- """ Parse Meta-Data and store in Markdown.Meta. """
- meta = {}
- key = None
- while 1:
- line = lines.pop(0)
- if line.strip() == '':
- break # blank line - done
- m1 = META_RE.match(line)
- if m1:
- key = m1.group('key').lower().strip()
- meta[key] = [m1.group('value').strip()]
- else:
- m2 = META_MORE_RE.match(line)
- if m2 and key:
- # Add another line to existing key
- meta[key].append(m2.group('value').strip())
- else:
- lines.insert(0, line)
- break # no meta data - done
- self.markdown.Meta = meta
- return lines
-
-
-def makeExtension(configs={}):
- return MetaExtension(configs=configs)
-
-if __name__ == "__main__":
- import doctest
- doctest.testmod()
diff --git a/markdown_extensions/rss.py b/markdown_extensions/rss.py
deleted file mode 100644
index fa05fef..0000000
--- a/markdown_extensions/rss.py
+++ /dev/null
@@ -1,118 +0,0 @@
-import markdown
-from markdown import etree
-
-DEFAULT_URL = "http://www.freewisdom.org/projects/python-markdown/"
-DEFAULT_CREATOR = "Yuri Takhteyev"
-DEFAULT_TITLE = "Markdown in Python"
-GENERATOR = "http://www.freewisdom.org/projects/python-markdown/markdown2rss"
-
-month_map = { "Jan" : "01",
- "Feb" : "02",
- "March" : "03",
- "April" : "04",
- "May" : "05",
- "June" : "06",
- "July" : "07",
- "August" : "08",
- "September" : "09",
- "October" : "10",
- "November" : "11",
- "December" : "12" }
-
-def get_time(heading):
-
- heading = heading.split("-")[0]
- heading = heading.strip().replace(",", " ").replace(".", " ")
-
- month, date, year = heading.split()
- month = month_map[month]
-
- return rdftime(" ".join((month, date, year, "12:00:00 AM")))
-
-def rdftime(time):
-
- time = time.replace(":", " ")
- time = time.replace("/", " ")
- time = time.split()
- return "%s-%s-%sT%s:%s:%s-08:00" % (time[0], time[1], time[2],
- time[3], time[4], time[5])
-
-
-def get_date(text):
- return "date"
-
-class RssExtension (markdown.Extension):
-
- def extendMarkdown(self, md, md_globals):
-
- self.config = { 'URL' : [DEFAULT_URL, "Main URL"],
- 'CREATOR' : [DEFAULT_CREATOR, "Feed creator's name"],
- 'TITLE' : [DEFAULT_TITLE, "Feed title"] }
-
- md.xml_mode = True
-
- # Insert a tree-processor that would actually add the title tag
- treeprocessor = RssTreeProcessor(self)
- treeprocessor.ext = self
- md.treeprocessors.append(treeprocessor)
- md.stripTopLevelTags = 0
- md.docType = '<?xml version="1.0" encoding="utf-8"?>\n'
-
-class RssTreeProcessor (markdown.Treeprocessor):
-
- def __init__(self, md):
-
- pass
-
- def run (self, root):
-
- rss = etree.Element("rss")
- rss.set("version", "2.0")
-
- channel = etree.SubElement(rss, "channel")
-
- for tag, text in (("title", self.ext.getConfig("TITLE")),
- ("link", self.ext.getConfig("URL")),
- ("description", None)):
-
- element = etree.SubElement(channel, tag)
- element.text = text
-
- for child in root:
-
-
- if child.tag in ["h1", "h2", "h3", "h4", "h5"] :
-
- heading = child.text.strip()
-
- item = etree.SubElement(channel, "item")
-
- link = etree.SubElement(item, "link")
- link.text = self.ext.getConfig("URL")
-
- title = etree.SubElement(item, "title")
- title.text = heading
-
- guid = ''.join([x for x in heading if x.isalnum()])
-
- guidElem = etree.SubElement(item, "guid")
- guidElem.text = guid
- guidElem.set("isPermaLink", "false")
-
- elif child.tag in ["p"] :
- if item:
- description = etree.SubElement(item, "description")
- if len(child):
- content = "\n".join([etree.tostring(node)
- for node in child])
- else:
- content = child.text
- pholder = self.stash.store("<![CDATA[ %s]]>" % content)
- description.text = pholder
-
- return rss
-
-
-def makeExtension(configs):
-
- return RssExtension(configs)
diff --git a/markdown_extensions/tables.py b/markdown_extensions/tables.py
deleted file mode 100644
index 0e5cd96..0000000
--- a/markdown_extensions/tables.py
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/usr/bin/env python
-
-"""
-Table extension for Python-Markdown
-"""
-
-import markdown
-from markdown import etree
-
-class TablePattern(markdown.Pattern) :
- def __init__ (self, md):
- markdown.Pattern.__init__(self, r'(^|\n)\|([^\n]*)\|')
- self.md = md
-
- def handleMatch(self, m):
-
- # a single line represents a row
- tr = etree.Element('tr')
-
- # chunks between pipes represent cells
-
- for t in m.group(3).split('|'):
-
- if len(t) >= 2 and t.startswith('*') and t.endswith('*'):
- # if a cell is bounded by asterisks, it is a <th>
- td = etree.Element('th')
- t = t[1:-1]
- else:
- # otherwise it is a <td>
- td = etree.Element('td')
-
- # add text ot inline section, later it will be
- # processed by core
-
- td.text = t
- tr.append(td)
- tr.tail = "\n"
-
- return tr
-
-class TableTreeprocessor(markdown.Treeprocessor):
-
- def _findElement(self, element, name):
- result = []
- for child in element:
- if child.tag == name:
- result.append(child)
- result += self._findElement(child, name)
- return result
-
- def run(self, root):
-
- for element in self._findElement(root, "p"):
- for child in element:
- if child.tail:
- element.tag = "table"
- break
-
-
-
-
-class TableExtension(markdown.Extension):
- def extendMarkdown(self, md, md_globals):
- md.inlinePatterns.add('table', TablePattern(md), "<backtick")
- md.treeprocessors.add('table', TableTreeprocessor(), "<prettify")
-
-
-def makeExtension(configs):
- return TableExtension(configs)
-
diff --git a/markdown_extensions/toc.py b/markdown_extensions/toc.py
deleted file mode 100644
index cc8c93b..0000000
--- a/markdown_extensions/toc.py
+++ /dev/null
@@ -1,137 +0,0 @@
-"""
-Table of Contents Extension for Python-Markdown
-* * *
-
-(c) 2008 [Jack Miller](http://codezen.org)
-
-Dependencies:
-* [Markdown 2.0+](http://www.freewisdom.org/projects/python-markdown/)
-
-"""
-import markdown
-from markdown import etree
-import re
-
-class TocTreeprocessor (markdown.Treeprocessor):
- # Iterator wrapper to get parent and child all at once
- def iterparent(self, root):
- for parent in root.getiterator():
- for child in parent:
- yield parent, child
-
- def run(self, doc) :
- div = etree.Element("div")
- div.attrib["class"] = "toc"
- last_li = None
-
- # Add title to the div
- if self.config["title"][0]:
- header = etree.SubElement(div, "span")
- header.attrib["class"] = "toctitle"
- header.text = self.config["title"][0]
-
- level = 0
- list_stack=[div]
- header_rgx = re.compile("[Hh][123456]")
-
- # Get a list of id attributes
- used_ids = []
- for c in doc.getiterator():
- if c.attrib.has_key("id"):
- used_ids.append(c.attrib["id"])
-
- for (p, c) in self.iterparent(doc):
- if not c.text:
- continue
-
- # To keep the output from screwing up the
- # validation by putting a <div> inside of a <p>
- # we actually replace the <p> in its entirety.
-
- if c.text.find(self.config["marker"][0]) > -1:
- for i in range(len(p)):
- if p[i] == c:
- p[i] = div
- break
-
- if header_rgx.match(c.tag):
- tag_level = int(c.tag[-1])
-
- # Regardless of how many levels we jumped
- # only one list should be created, since
- # empty lists containing lists are illegal.
-
- if tag_level < level:
- list_stack.pop()
- level = tag_level
-
- if tag_level > level:
- newlist = etree.Element("ul")
- if last_li:
- last_li.append(newlist)
- else:
- list_stack[-1].append(newlist)
- list_stack.append(newlist)
- level = tag_level
-
- # Do not override pre-existing ids
- if not c.attrib.has_key("id"):
- id = self.config["slugify"][0](c.text)
- if id in used_ids:
- ctr = 1
- while "%s_%d" % (id, ctr) in used_ids:
- ctr += 1
- id = "%s_%d" % (id, ctr)
- used_ids.append(id)
- c.attrib["id"] = id
- else:
- id = c.attrib["id"]
-
- # List item link, to be inserted into the toc div
- last_li = etree.Element("li")
- link = etree.SubElement(last_li, "a")
- link.text = c.text
- link.attrib["href"] = '#' + id
-
- if int(self.config["anchorlink"][0]):
- anchor = etree.SubElement(c, "a")
- anchor.text = c.text
- anchor.attrib["href"] = "#" + id
- anchor.attrib["class"] = "toclink"
- c.text = ""
-
- list_stack[-1].append(last_li)
-
-class TocExtension (markdown.Extension):
- def __init__(self, configs):
- self.config = { "marker" : ["[TOC]",
- "Text to find and replace with Table of Contents -"
- "Defaults to \"[TOC]\""],
- "slugify" : [self.slugify,
- "Function to generate anchors based on header text-"
- "Defaults to a built in slugify function."],
- "title" : [None,
- "Title to insert into TOC <div> - "
- "Defaults to None"],
- "anchorlink" : [0,
- "1 if header should be a self link"
- "Defaults to 0"]}
-
- for key, value in configs:
- self.setConfig(key, value)
-
- # This is exactly the same as Django's slugify
- def slugify(self, value):
- """ Slugify a string, to make it URL friendly. """
- import unicodedata
- value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
- value = unicode(re.sub('[^\w\s-]', '', value).strip().lower())
- return re.sub('[-\s]+','-',value)
-
- def extendMarkdown(self, md, md_globals) :
- tocext = TocTreeprocessor(md)
- tocext.config = self.config
- md.treeprocessors.add("toc", tocext, "_begin")
-
-def makeExtension(configs={}) :
- return TocExtension(configs=configs)
diff --git a/markdown_extensions/wikilinks.py b/markdown_extensions/wikilinks.py
deleted file mode 100644
index 0caeb48..0000000
--- a/markdown_extensions/wikilinks.py
+++ /dev/null
@@ -1,138 +0,0 @@
-#!/usr/bin/env python
-
-'''
-WikiLinks Extension for Python-Markdown
-======================================
-
-Converts [[WikiLinks]] to relative links. Requires Python-Markdown 2.0+
-
-Basic usage:
-
- >>> import markdown
- >>> text = "Some text with a [[WikiLink]]."
- >>> html = markdown.markdown(text, ['wikilinks'])
- >>> html
- u'<p>Some text with a <a class="wikilink" href="/WikiLink/">WikiLink</a>.</p>'
-
-Whitespace behavior:
-
- >>> markdown.markdown('[[ foo bar_baz ]]', ['wikilinks'])
- u'<p><a class="wikilink" href="/foo_bar_baz/">foo bar_baz</a></p>'
- >>> markdown.markdown('foo [[ ]] bar', ['wikilinks'])
- u'<p>foo bar</p>'
-
-To define custom settings the simple way:
-
- >>> markdown.markdown(text,
- ... ['wikilinks(base_url=/wiki/,end_url=.html,html_class=foo)']
- ... )
- u'<p>Some text with a <a class="foo" href="/wiki/WikiLink.html">WikiLink</a>.</p>'
-
-Custom settings the complex way:
-
- >>> md = markdown.Markdown(
- ... extensions = ['wikilinks'],
- ... extension_configs = {'wikilinks': [
- ... ('base_url', 'http://example.com/'),
- ... ('end_url', '.html'),
- ... ('html_class', '') ]},
- ... safe_mode = True)
- >>> md.convert(text)
- u'<p>Some text with a <a href="http://example.com/WikiLink.html">WikiLink</a>.</p>'
-
-Use MetaData with mdx_meta.py (Note the blank html_class in MetaData):
-
- >>> text = """wiki_base_url: http://example.com/
- ... wiki_end_url: .html
- ... wiki_html_class:
- ...
- ... Some text with a [[WikiLink]]."""
- >>> md = markdown.Markdown(extensions=['meta', 'wikilinks'])
- >>> md.convert(text)
- u'<p>Some text with a <a href="http://example.com/WikiLink.html">WikiLink</a>.</p>'
-
-MetaData should not carry over to next document:
-
- >>> md.convert("No [[MetaData]] here.")
- u'<p>No <a class="wikilink" href="/MetaData/">MetaData</a> here.</p>'
-
-From the command line:
-
- python markdown.py -x wikilinks(base_url=http://example.com/,end_url=.html,html_class=foo) src.txt
-
-By [Waylan Limberg](http://achinghead.com/).
-
-License: [BSD](http://www.opensource.org/licenses/bsd-license.php)
-
-Dependencies:
-* [Python 2.3+](http://python.org)
-* [Markdown 2.0+](http://www.freewisdom.org/projects/python-markdown/)
-'''
-
-import markdown
-
-class WikiLinkExtension (markdown.Extension) :
- def __init__(self, configs):
- # set extension defaults
- self.config = {
- 'base_url' : ['/', 'String to append to beginning or URL.'],
- 'end_url' : ['/', 'String to append to end of URL.'],
- 'html_class' : ['wikilink', 'CSS hook. Leave blank for none.']
- }
-
- # Override defaults with user settings
- for key, value in configs :
- self.setConfig(key, value)
-
- def extendMarkdown(self, md, md_globals):
- self.md = md
-
- # append to end of inline patterns
- WIKILINK_RE = r'\[\[([A-Za-z0-9_ -]+)\]\]'
- wikilinkPattern = WikiLinks(WIKILINK_RE, self.config)
- wikilinkPattern.md = md
- md.inlinePatterns.add('wikilink', wikilinkPattern, "_end")
-
-
-class WikiLinks (markdown.BasePattern) :
- def __init__(self, pattern, config):
- markdown.BasePattern.__init__(self, pattern)
- self.config = config
-
- def handleMatch(self, m):
- if m.group(2).strip():
- base_url, end_url, html_class = self._getMeta()
- label = m.group(2).strip()
- url = '%s%s%s'% (base_url, label.replace(' ', '_'), end_url)
- a = markdown.etree.Element('a')
- a.text = markdown.AtomicString(label)
- a.set('href', url)
- if html_class:
- a.set('class', html_class)
- else:
- a = ''
- return a
-
- def _getMeta(self):
- """ Return meta data or config data. """
- base_url = self.config['base_url'][0]
- end_url = self.config['end_url'][0]
- html_class = self.config['html_class'][0]
- if hasattr(self.md, 'Meta'):
- if self.md.Meta.has_key('wiki_base_url'):
- base_url = self.md.Meta['wiki_base_url'][0]
- if self.md.Meta.has_key('wiki_end_url'):
- end_url = self.md.Meta['wiki_end_url'][0]
- if self.md.Meta.has_key('wiki_html_class'):
- html_class = self.md.Meta['wiki_html_class'][0]
- return base_url, end_url, html_class
-
-
-def makeExtension(configs=None) :
- return WikiLinkExtension(configs=configs)
-
-
-if __name__ == "__main__":
- import doctest
- doctest.testmod()
-