summaryrefslogtreecommitdiffstats
path: root/third_party/markdown
diff options
context:
space:
mode:
authornoamsml@google.com <noamsml@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-09 22:56:35 +0000
committernoamsml@google.com <noamsml@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-09 22:56:35 +0000
commit0f7b29d9a33444d495b2e37251aafac4bdd6969b (patch)
tree6561907b34e37afad86da3bbb411349863765299 /third_party/markdown
parent731ed569f46dabb5efbdd02574521eb3c337a5b9 (diff)
downloadchromium_src-0f7b29d9a33444d495b2e37251aafac4bdd6969b.zip
chromium_src-0f7b29d9a33444d495b2e37251aafac4bdd6969b.tar.gz
chromium_src-0f7b29d9a33444d495b2e37251aafac4bdd6969b.tar.bz2
Revert 243980 "Docserver: Support markdown for HTML content."
> Docserver: Support markdown for HTML content. > > R=kalman@chromium.org > BUG=293681 > > Review URL: https://codereview.chromium.org/93743005 TBR=hukun@chromium.org Review URL: https://codereview.chromium.org/132753002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@244010 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/markdown')
-rw-r--r--third_party/markdown/LICENSE30
-rw-r--r--third_party/markdown/OWNERS2
-rw-r--r--third_party/markdown/README.chromium12
-rw-r--r--third_party/markdown/__init__.py443
-rw-r--r--third_party/markdown/__main__.py87
-rw-r--r--third_party/markdown/__version__.py28
-rw-r--r--third_party/markdown/blockparser.py99
-rw-r--r--third_party/markdown/blockprocessors.py558
-rw-r--r--third_party/markdown/extensions/__init__.py53
-rw-r--r--third_party/markdown/extensions/abbr.py96
-rw-r--r--third_party/markdown/extensions/admonition.py118
-rw-r--r--third_party/markdown/extensions/attr_list.py140
-rw-r--r--third_party/markdown/extensions/codehilite.py240
-rw-r--r--third_party/markdown/extensions/def_list.py118
-rw-r--r--third_party/markdown/extensions/extra.py54
-rw-r--r--third_party/markdown/extensions/fenced_code.py161
-rw-r--r--third_party/markdown/extensions/footnotes.py313
-rw-r--r--third_party/markdown/extensions/headerid.py199
-rw-r--r--third_party/markdown/extensions/meta.py93
-rw-r--r--third_party/markdown/extensions/nl2br.py38
-rw-r--r--third_party/markdown/extensions/sane_lists.py51
-rw-r--r--third_party/markdown/extensions/smart_strong.py42
-rw-r--r--third_party/markdown/extensions/tables.py100
-rw-r--r--third_party/markdown/extensions/toc.py221
-rw-r--r--third_party/markdown/extensions/wikilinks.py151
-rw-r--r--third_party/markdown/inlinepatterns.py483
-rw-r--r--third_party/markdown/odict.py194
-rw-r--r--third_party/markdown/postprocessors.py104
-rw-r--r--third_party/markdown/preprocessors.py298
-rw-r--r--third_party/markdown/serializers.py277
-rw-r--r--third_party/markdown/treeprocessors.py360
-rw-r--r--third_party/markdown/util.py136
32 files changed, 0 insertions, 5299 deletions
diff --git a/third_party/markdown/LICENSE b/third_party/markdown/LICENSE
deleted file mode 100644
index 4cd8b14..0000000
--- a/third_party/markdown/LICENSE
+++ /dev/null
@@ -1,30 +0,0 @@
-Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later)
-Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
-Copyright 2004 Manfred Stienstra (the original version)
-
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-* Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-* Neither the name of the <organization> nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE PYTHON MARKDOWN PROJECT ''AS IS'' AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL ANY CONTRIBUTORS TO THE PYTHON MARKDOWN PROJECT
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
diff --git a/third_party/markdown/OWNERS b/third_party/markdown/OWNERS
deleted file mode 100644
index 57fc739..0000000
--- a/third_party/markdown/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-hukun@chromium.org
-kalman@chromium.org
diff --git a/third_party/markdown/README.chromium b/third_party/markdown/README.chromium
deleted file mode 100644
index 1d0f218..0000000
--- a/third_party/markdown/README.chromium
+++ /dev/null
@@ -1,12 +0,0 @@
-Name: markdown, a text-to-HTML conversion tool for web writers
-Short Name: markdown
-URL: https://pypi.python.org/pypi/Markdown
-Version: 2.3.1
-Date: March 22, 2013
-Revision: commit 0ea0bac85a749a13381b721cde44214d9193406c
-License: BSD License
-License File: LICENSE
-Security Critical: no
-
-Description:
-Markdown allows you to write using an easy-to-read, easy-to-write plain text format, then convert it to structurally valid XHTML (or HTML).
diff --git a/third_party/markdown/__init__.py b/third_party/markdown/__init__.py
deleted file mode 100644
index f352f4b..0000000
--- a/third_party/markdown/__init__.py
+++ /dev/null
@@ -1,443 +0,0 @@
-"""
-Python Markdown
-===============
-
-Python Markdown converts Markdown to HTML and can be used as a library or
-called from the command line.
-
-## Basic usage as a module:
-
- import markdown
- html = markdown.markdown(your_text_string)
-
-See <http://packages.python.org/Markdown/> for more
-information and instructions on how to extend the functionality of
-Python Markdown. Read that before you try modifying this file.
-
-## Authors and License
-
-Started by [Manfred Stienstra](http://www.dwerg.net/). Continued and
-maintained by [Yuri Takhteyev](http://www.freewisdom.org), [Waylan
-Limberg](http://achinghead.com/) and [Artem Yunusov](http://blog.splyer.com).
-
-Contact: markdown@freewisdom.org
-
-Copyright 2007-2013 The Python Markdown Project (v. 1.7 and later)
-Copyright 200? Django Software Foundation (OrderedDict implementation)
-Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
-Copyright 2004 Manfred Stienstra (the original version)
-
-License: BSD (see LICENSE for details).
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from .__version__ import version, version_info
-import re
-import codecs
-import sys
-import logging
-from . import util
-from .preprocessors import build_preprocessors
-from .blockprocessors import build_block_parser
-from .treeprocessors import build_treeprocessors
-from .inlinepatterns import build_inlinepatterns
-from .postprocessors import build_postprocessors
-from .extensions import Extension
-from .serializers import to_html_string, to_xhtml_string
-
-__all__ = ['Markdown', 'markdown', 'markdownFromFile']
-
-logger = logging.getLogger('MARKDOWN')
-
-
-class Markdown(object):
- """Convert Markdown to HTML."""
-
- doc_tag = "div" # Element used to wrap document - later removed
-
- option_defaults = {
- 'html_replacement_text' : '[HTML_REMOVED]',
- 'tab_length' : 4,
- 'enable_attributes' : True,
- 'smart_emphasis' : True,
- 'lazy_ol' : True,
- }
-
- output_formats = {
- 'html' : to_html_string,
- 'html4' : to_html_string,
- 'html5' : to_html_string,
- 'xhtml' : to_xhtml_string,
- 'xhtml1': to_xhtml_string,
- 'xhtml5': to_xhtml_string,
- }
-
- ESCAPED_CHARS = ['\\', '`', '*', '_', '{', '}', '[', ']',
- '(', ')', '>', '#', '+', '-', '.', '!']
-
- def __init__(self, *args, **kwargs):
- """
- Creates a new Markdown instance.
-
- Keyword arguments:
-
- * extensions: A list of extensions.
- If they are of type string, the module mdx_name.py will be loaded.
- If they are a subclass of markdown.Extension, they will be used
- as-is.
- * extension_configs: Configuration settingis for extensions.
- * output_format: Format of output. Supported formats are:
- * "xhtml1": Outputs XHTML 1.x. Default.
- * "xhtml5": Outputs XHTML style tags of HTML 5
- * "xhtml": Outputs latest supported version of XHTML (currently XHTML 1.1).
- * "html4": Outputs HTML 4
- * "html5": Outputs HTML style tags of HTML 5
- * "html": Outputs latest supported version of HTML (currently HTML 4).
- Note that it is suggested that the more specific formats ("xhtml1"
- and "html4") be used as "xhtml" or "html" may change in the future
- if it makes sense at that time.
- * safe_mode: Disallow raw html. One of "remove", "replace" or "escape".
- * html_replacement_text: Text used when safe_mode is set to "replace".
- * tab_length: Length of tabs in the source. Default: 4
- * enable_attributes: Enable the conversion of attributes. Default: True
- * smart_emphasis: Treat `_connected_words_` intelegently Default: True
- * lazy_ol: Ignore number of first item of ordered lists. Default: True
-
- """
-
- # For backward compatibility, loop through old positional args
- pos = ['extensions', 'extension_configs', 'safe_mode', 'output_format']
- c = 0
- for arg in args:
- if pos[c] not in kwargs:
- kwargs[pos[c]] = arg
- c += 1
- if c == len(pos):
- # ignore any additional args
- break
-
- # Loop through kwargs and assign defaults
- for option, default in self.option_defaults.items():
- setattr(self, option, kwargs.get(option, default))
-
- self.safeMode = kwargs.get('safe_mode', False)
- if self.safeMode and 'enable_attributes' not in kwargs:
- # Disable attributes in safeMode when not explicitly set
- self.enable_attributes = False
-
- self.registeredExtensions = []
- self.docType = ""
- self.stripTopLevelTags = True
-
- self.build_parser()
-
- self.references = {}
- self.htmlStash = util.HtmlStash()
- self.set_output_format(kwargs.get('output_format', 'xhtml1'))
- self.registerExtensions(extensions=kwargs.get('extensions', []),
- configs=kwargs.get('extension_configs', {}))
- self.reset()
-
- def build_parser(self):
- """ Build the parser from the various parts. """
- self.preprocessors = build_preprocessors(self)
- self.parser = build_block_parser(self)
- self.inlinePatterns = build_inlinepatterns(self)
- self.treeprocessors = build_treeprocessors(self)
- self.postprocessors = build_postprocessors(self)
- return self
-
- def registerExtensions(self, extensions, configs):
- """
- Register extensions with this instance of Markdown.
-
- Keyword arguments:
-
- * extensions: A list of extensions, which can either
- be strings or objects. See the docstring on Markdown.
- * configs: A dictionary mapping module names to config options.
-
- """
- for ext in extensions:
- if isinstance(ext, util.string_type):
- ext = self.build_extension(ext, configs.get(ext, []))
- if isinstance(ext, Extension):
- ext.extendMarkdown(self, globals())
- elif ext is not None:
- raise TypeError(
- 'Extension "%s.%s" must be of type: "markdown.Extension"'
- % (ext.__class__.__module__, ext.__class__.__name__))
-
- return self
-
- def build_extension(self, ext_name, configs = []):
- """Build extension by name, then return the module.
-
- The extension name may contain arguments as part of the string in the
- following format: "extname(key1=value1,key2=value2)"
-
- """
-
- # Parse extensions config params (ignore the order)
- configs = dict(configs)
- pos = ext_name.find("(") # find the first "("
- if pos > 0:
- ext_args = ext_name[pos+1:-1]
- ext_name = ext_name[:pos]
- pairs = [x.split("=") for x in ext_args.split(",")]
- configs.update([(x.strip(), y.strip()) for (x, y) in pairs])
-
- # Setup the module name
- module_name = ext_name
- if '.' not in ext_name:
- module_name = '.'.join(['third_party.markdown.extensions', ext_name])
-
- # Try loading the extension first from one place, then another
- try: # New style (markdown.extensons.<extension>)
- module = __import__(module_name, {}, {}, [module_name.rpartition('.')[0]])
- except ImportError:
- module_name_old_style = '_'.join(['mdx', ext_name])
- try: # Old style (mdx_<extension>)
- module = __import__(module_name_old_style)
- except ImportError as e:
- message = "Failed loading extension '%s' from '%s' or '%s'" \
- % (ext_name, module_name, module_name_old_style)
- e.args = (message,) + e.args[1:]
- raise
-
- # If the module is loaded successfully, we expect it to define a
- # function called makeExtension()
- try:
- return module.makeExtension(configs.items())
- except AttributeError as e:
- message = e.args[0]
- message = "Failed to initiate extension " \
- "'%s': %s" % (ext_name, message)
- e.args = (message,) + e.args[1:]
- raise
-
- def registerExtension(self, extension):
- """ This gets called by the extension """
- self.registeredExtensions.append(extension)
- return self
-
- def reset(self):
- """
- Resets all state variables so that we can start with a new text.
- """
- self.htmlStash.reset()
- self.references.clear()
-
- for extension in self.registeredExtensions:
- if hasattr(extension, 'reset'):
- extension.reset()
-
- return self
-
- def set_output_format(self, format):
- """ Set the output format for the class instance. """
- self.output_format = format.lower()
- try:
- self.serializer = self.output_formats[self.output_format]
- except KeyError as e:
- valid_formats = list(self.output_formats.keys())
- valid_formats.sort()
- message = 'Invalid Output Format: "%s". Use one of %s.' \
- % (self.output_format,
- '"' + '", "'.join(valid_formats) + '"')
- e.args = (message,) + e.args[1:]
- raise
- return self
-
- def convert(self, source):
- """
- Convert markdown to serialized XHTML or HTML.
-
- Keyword arguments:
-
- * source: Source text as a Unicode string.
-
- Markdown processing takes place in five steps:
-
- 1. A bunch of "preprocessors" munge the input text.
- 2. BlockParser() parses the high-level structural elements of the
- pre-processed text into an ElementTree.
- 3. A bunch of "treeprocessors" are run against the ElementTree. One
- such treeprocessor runs InlinePatterns against the ElementTree,
- detecting inline markup.
- 4. Some post-processors are run against the text after the ElementTree
- has been serialized into text.
- 5. The output is written to a string.
-
- """
-
- # Fixup the source text
- if not source.strip():
- return '' # a blank unicode string
-
- try:
- source = util.text_type(source)
- except UnicodeDecodeError as e:
- # Customise error message while maintaining original trackback
- e.reason += '. -- Note: Markdown only accepts unicode input!'
- raise
-
- # Split into lines and run the line preprocessors.
- self.lines = source.split("\n")
- for prep in self.preprocessors.values():
- self.lines = prep.run(self.lines)
-
- # Parse the high-level elements.
- root = self.parser.parseDocument(self.lines).getroot()
-
- # Run the tree-processors
- for treeprocessor in self.treeprocessors.values():
- newRoot = treeprocessor.run(root)
- if newRoot:
- root = newRoot
-
- # Serialize _properly_. Strip top-level tags.
- output = self.serializer(root)
- if self.stripTopLevelTags:
- try:
- start = output.index('<%s>'%self.doc_tag)+len(self.doc_tag)+2
- end = output.rindex('</%s>'%self.doc_tag)
- output = output[start:end].strip()
- except ValueError:
- if output.strip().endswith('<%s />'%self.doc_tag):
- # We have an empty document
- output = ''
- else:
- # We have a serious problem
- raise ValueError('Markdown failed to strip top-level tags. Document=%r' % output.strip())
-
- # Run the text post-processors
- for pp in self.postprocessors.values():
- output = pp.run(output)
-
- return output.strip()
-
- def convertFile(self, input=None, output=None, encoding=None):
- """Converts a markdown file and returns the HTML as a unicode string.
-
- Decodes the file using the provided encoding (defaults to utf-8),
- passes the file content to markdown, and outputs the html to either
- the provided stream or the file with provided name, using the same
- encoding as the source file. The 'xmlcharrefreplace' error handler is
- used when encoding the output.
-
- **Note:** This is the only place that decoding and encoding of unicode
- takes place in Python-Markdown. (All other code is unicode-in /
- unicode-out.)
-
- Keyword arguments:
-
- * input: File object or path. Reads from stdin if `None`.
- * output: File object or path. Writes to stdout if `None`.
- * encoding: Encoding of input and output files. Defaults to utf-8.
-
- """
-
- encoding = encoding or "utf-8"
-
- # Read the source
- if input:
- if isinstance(input, util.string_type):
- input_file = codecs.open(input, mode="r", encoding=encoding)
- else:
- input_file = codecs.getreader(encoding)(input)
- text = input_file.read()
- input_file.close()
- else:
- text = sys.stdin.read()
- if not isinstance(text, util.text_type):
- text = text.decode(encoding)
-
- text = text.lstrip('\ufeff') # remove the byte-order mark
-
- # Convert
- html = self.convert(text)
-
- # Write to file or stdout
- if output:
- if isinstance(output, util.string_type):
- output_file = codecs.open(output, "w",
- encoding=encoding,
- errors="xmlcharrefreplace")
- output_file.write(html)
- output_file.close()
- else:
- writer = codecs.getwriter(encoding)
- output_file = writer(output, errors="xmlcharrefreplace")
- output_file.write(html)
- # Don't close here. User may want to write more.
- else:
- # Encode manually and write bytes to stdout.
- html = html.encode(encoding, "xmlcharrefreplace")
- try:
- # Write bytes directly to buffer (Python 3).
- sys.stdout.buffer.write(html)
- except AttributeError:
- # Probably Python 2, which works with bytes by default.
- sys.stdout.write(html)
-
- return self
-
-
-"""
-EXPORTED FUNCTIONS
-=============================================================================
-
-Those are the two functions we really mean to export: markdown() and
-markdownFromFile().
-"""
-
-def markdown(text, *args, **kwargs):
- """Convert a markdown string to HTML and return HTML as a unicode string.
-
- This is a shortcut function for `Markdown` class to cover the most
- basic use case. It initializes an instance of Markdown, loads the
- necessary extensions and runs the parser on the given text.
-
- Keyword arguments:
-
- * text: Markdown formatted text as Unicode or ASCII string.
- * Any arguments accepted by the Markdown class.
-
- Returns: An HTML document as a string.
-
- """
- md = Markdown(*args, **kwargs)
- return md.convert(text)
-
-
-def markdownFromFile(*args, **kwargs):
- """Read markdown code from a file and write it to a file or a stream.
-
- This is a shortcut function which initializes an instance of Markdown,
- and calls the convertFile method rather than convert.
-
- Keyword arguments:
-
- * input: a file name or readable object.
- * output: a file name or writable object.
- * encoding: Encoding of input and output.
- * Any arguments accepted by the Markdown class.
-
- """
- # For backward compatibility loop through positional args
- pos = ['input', 'output', 'extensions', 'encoding']
- c = 0
- for arg in args:
- if pos[c] not in kwargs:
- kwargs[pos[c]] = arg
- c += 1
- if c == len(pos):
- break
-
- md = Markdown(**kwargs)
- md.convertFile(kwargs.get('input', None),
- kwargs.get('output', None),
- kwargs.get('encoding', None))
-
diff --git a/third_party/markdown/__main__.py b/third_party/markdown/__main__.py
deleted file mode 100644
index 8ee8c82..0000000
--- a/third_party/markdown/__main__.py
+++ /dev/null
@@ -1,87 +0,0 @@
-"""
-COMMAND-LINE SPECIFIC STUFF
-=============================================================================
-
-"""
-
-import markdown
-import sys
-import optparse
-
-import logging
-from logging import DEBUG, INFO, CRITICAL
-
-logger = logging.getLogger('MARKDOWN')
-
-def parse_options():
- """
- Define and parse `optparse` options for command-line usage.
- """
- usage = """%prog [options] [INPUTFILE]
- (STDIN is assumed if no INPUTFILE is given)"""
- desc = "A Python implementation of John Gruber's Markdown. " \
- "http://packages.python.org/Markdown/"
- ver = "%%prog %s" % markdown.version
-
- parser = optparse.OptionParser(usage=usage, description=desc, version=ver)
- parser.add_option("-f", "--file", dest="filename", default=None,
- help="Write output to OUTPUT_FILE. Defaults to STDOUT.",
- metavar="OUTPUT_FILE")
- parser.add_option("-e", "--encoding", dest="encoding",
- help="Encoding for input and output files.",)
- parser.add_option("-q", "--quiet", default = CRITICAL,
- action="store_const", const=CRITICAL+10, dest="verbose",
- help="Suppress all warnings.")
- parser.add_option("-v", "--verbose",
- action="store_const", const=INFO, dest="verbose",
- help="Print all warnings.")
- parser.add_option("-s", "--safe", dest="safe", default=False,
- metavar="SAFE_MODE",
- help="'replace', 'remove' or 'escape' HTML tags in input")
- parser.add_option("-o", "--output_format", dest="output_format",
- default='xhtml1', metavar="OUTPUT_FORMAT",
- help="'xhtml1' (default), 'html4' or 'html5'.")
- parser.add_option("--noisy",
- action="store_const", const=DEBUG, dest="verbose",
- help="Print debug messages.")
- parser.add_option("-x", "--extension", action="append", dest="extensions",
- help = "Load extension EXTENSION.", metavar="EXTENSION")
- parser.add_option("-n", "--no_lazy_ol", dest="lazy_ol",
- action='store_false', default=True,
- help="Observe number of first item of ordered lists.")
-
- (options, args) = parser.parse_args()
-
- if len(args) == 0:
- input_file = None
- else:
- input_file = args[0]
-
- if not options.extensions:
- options.extensions = []
-
- return {'input': input_file,
- 'output': options.filename,
- 'safe_mode': options.safe,
- 'extensions': options.extensions,
- 'encoding': options.encoding,
- 'output_format': options.output_format,
- 'lazy_ol': options.lazy_ol}, options.verbose
-
-def run():
- """Run Markdown from the command line."""
-
- # Parse options and adjust logging level if necessary
- options, logging_level = parse_options()
- if not options: sys.exit(2)
- logger.setLevel(logging_level)
- logger.addHandler(logging.StreamHandler())
-
- # Run
- markdown.markdownFromFile(**options)
-
-if __name__ == '__main__':
- # Support running module as a commandline command.
- # Python 2.5 & 2.6 do: `python -m markdown.__main__ [options] [args]`.
- # Python 2.7 & 3.x do: `python -m markdown [options] [args]`.
- run()
diff --git a/third_party/markdown/__version__.py b/third_party/markdown/__version__.py
deleted file mode 100644
index a13559c..0000000
--- a/third_party/markdown/__version__.py
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# markdown/__version__.py
-#
-# version_info should conform to PEP 386
-# (major, minor, micro, alpha/beta/rc/final, #)
-# (1, 1, 2, 'alpha', 0) => "1.1.2.dev"
-# (1, 2, 0, 'beta', 2) => "1.2b2"
-version_info = (2, 3, 1, 'final', 0)
-
-def _get_version():
- " Returns a PEP 386-compliant version number from version_info. "
- assert len(version_info) == 5
- assert version_info[3] in ('alpha', 'beta', 'rc', 'final')
-
- parts = 2 if version_info[2] == 0 else 3
- main = '.'.join(map(str, version_info[:parts]))
-
- sub = ''
- if version_info[3] == 'alpha' and version_info[4] == 0:
- # TODO: maybe append some sort of git info here??
- sub = '.dev'
- elif version_info[3] != 'final':
- mapping = {'alpha': 'a', 'beta': 'b', 'rc': 'c'}
- sub = mapping[version_info[3]] + str(version_info[4])
-
- return str(main + sub)
-
-version = _get_version()
diff --git a/third_party/markdown/blockparser.py b/third_party/markdown/blockparser.py
deleted file mode 100644
index 4504a16..0000000
--- a/third_party/markdown/blockparser.py
+++ /dev/null
@@ -1,99 +0,0 @@
-from __future__ import unicode_literals
-from __future__ import absolute_import
-from . import util
-from . import odict
-
-class State(list):
- """ Track the current and nested state of the parser.
-
- This utility class is used to track the state of the BlockParser and
- support multiple levels if nesting. It's just a simple API wrapped around
- a list. Each time a state is set, that state is appended to the end of the
- list. Each time a state is reset, that state is removed from the end of
- the list.
-
- Therefore, each time a state is set for a nested block, that state must be
- reset when we back out of that level of nesting or the state could be
- corrupted.
-
- While all the methods of a list object are available, only the three
- defined below need be used.
-
- """
-
- def set(self, state):
- """ Set a new state. """
- self.append(state)
-
- def reset(self):
- """ Step back one step in nested state. """
- self.pop()
-
- def isstate(self, state):
- """ Test that top (current) level is of given state. """
- if len(self):
- return self[-1] == state
- else:
- return False
-
-class BlockParser:
- """ Parse Markdown blocks into an ElementTree object.
-
- A wrapper class that stitches the various BlockProcessors together,
- looping through them and creating an ElementTree object.
- """
-
- def __init__(self, markdown):
- self.blockprocessors = odict.OrderedDict()
- self.state = State()
- self.markdown = markdown
-
- def parseDocument(self, lines):
- """ Parse a markdown document into an ElementTree.
-
- Given a list of lines, an ElementTree object (not just a parent Element)
- is created and the root element is passed to the parser as the parent.
- The ElementTree object is returned.
-
- This should only be called on an entire document, not pieces.
-
- """
- # Create a ElementTree from the lines
- self.root = util.etree.Element(self.markdown.doc_tag)
- self.parseChunk(self.root, '\n'.join(lines))
- return util.etree.ElementTree(self.root)
-
- def parseChunk(self, parent, text):
- """ Parse a chunk of markdown text and attach to given etree node.
-
- While the ``text`` argument is generally assumed to contain multiple
- blocks which will be split on blank lines, it could contain only one
- block. Generally, this method would be called by extensions when
- block parsing is required.
-
- The ``parent`` etree Element passed in is altered in place.
- Nothing is returned.
-
- """
- self.parseBlocks(parent, text.split('\n\n'))
-
- def parseBlocks(self, parent, blocks):
- """ Process blocks of markdown text and attach to given etree node.
-
- Given a list of ``blocks``, each blockprocessor is stepped through
- until there are no blocks left. While an extension could potentially
- call this method directly, it's generally expected to be used internally.
-
- This is a public method as an extension may need to add/alter additional
- BlockProcessors which call this method to recursively parse a nested
- block.
-
- """
- while blocks:
- for processor in self.blockprocessors.values():
- if processor.test(parent, blocks[0]):
- if processor.run(parent, blocks) is not False:
- # run returns True or None
- break
-
-
diff --git a/third_party/markdown/blockprocessors.py b/third_party/markdown/blockprocessors.py
deleted file mode 100644
index 61977b4..0000000
--- a/third_party/markdown/blockprocessors.py
+++ /dev/null
@@ -1,558 +0,0 @@
-"""
-CORE MARKDOWN BLOCKPARSER
-===========================================================================
-
-This parser handles basic parsing of Markdown blocks. It doesn't concern itself
-with inline elements such as **bold** or *italics*, but rather just catches
-blocks, lists, quotes, etc.
-
-The BlockParser is made up of a bunch of BlockProssors, each handling a
-different type of block. Extensions may add/replace/remove BlockProcessors
-as they need to alter how markdown blocks are parsed.
-"""
-
-from __future__ import absolute_import
-from __future__ import division
-from __future__ import unicode_literals
-import logging
-import re
-from . import util
-from .blockparser import BlockParser
-
-logger = logging.getLogger('MARKDOWN')
-
-
-def build_block_parser(md_instance, **kwargs):
- """ Build the default block parser used by Markdown. """
- parser = BlockParser(md_instance)
- parser.blockprocessors['empty'] = EmptyBlockProcessor(parser)
- parser.blockprocessors['indent'] = ListIndentProcessor(parser)
- parser.blockprocessors['code'] = CodeBlockProcessor(parser)
- parser.blockprocessors['hashheader'] = HashHeaderProcessor(parser)
- parser.blockprocessors['setextheader'] = SetextHeaderProcessor(parser)
- parser.blockprocessors['hr'] = HRProcessor(parser)
- parser.blockprocessors['olist'] = OListProcessor(parser)
- parser.blockprocessors['ulist'] = UListProcessor(parser)
- parser.blockprocessors['quote'] = BlockQuoteProcessor(parser)
- parser.blockprocessors['paragraph'] = ParagraphProcessor(parser)
- return parser
-
-
-class BlockProcessor:
- """ Base class for block processors.
-
- Each subclass will provide the methods below to work with the source and
- tree. Each processor will need to define it's own ``test`` and ``run``
- methods. The ``test`` method should return True or False, to indicate
- whether the current block should be processed by this processor. If the
- test passes, the parser will call the processors ``run`` method.
-
- """
-
- def __init__(self, parser):
- self.parser = parser
- self.tab_length = parser.markdown.tab_length
-
- def lastChild(self, parent):
- """ Return the last child of an etree element. """
- if len(parent):
- return parent[-1]
- else:
- return None
-
- def detab(self, text):
- """ Remove a tab from the front of each line of the given text. """
- newtext = []
- lines = text.split('\n')
- for line in lines:
- if line.startswith(' '*self.tab_length):
- newtext.append(line[self.tab_length:])
- elif not line.strip():
- newtext.append('')
- else:
- break
- return '\n'.join(newtext), '\n'.join(lines[len(newtext):])
-
- def looseDetab(self, text, level=1):
- """ Remove a tab from front of lines but allowing dedented lines. """
- lines = text.split('\n')
- for i in range(len(lines)):
- if lines[i].startswith(' '*self.tab_length*level):
- lines[i] = lines[i][self.tab_length*level:]
- return '\n'.join(lines)
-
- def test(self, parent, block):
- """ Test for block type. Must be overridden by subclasses.
-
- As the parser loops through processors, it will call the ``test`` method
- on each to determine if the given block of text is of that type. This
- method must return a boolean ``True`` or ``False``. The actual method of
- testing is left to the needs of that particular block type. It could
- be as simple as ``block.startswith(some_string)`` or a complex regular
- expression. As the block type may be different depending on the parent
- of the block (i.e. inside a list), the parent etree element is also
- provided and may be used as part of the test.
-
- Keywords:
-
- * ``parent``: A etree element which will be the parent of the block.
- * ``block``: A block of text from the source which has been split at
- blank lines.
- """
- pass
-
- def run(self, parent, blocks):
- """ Run processor. Must be overridden by subclasses.
-
- When the parser determines the appropriate type of a block, the parser
- will call the corresponding processor's ``run`` method. This method
- should parse the individual lines of the block and append them to
- the etree.
-
- Note that both the ``parent`` and ``etree`` keywords are pointers
- to instances of the objects which should be edited in place. Each
- processor must make changes to the existing objects as there is no
- mechanism to return new/different objects to replace them.
-
- This means that this method should be adding SubElements or adding text
- to the parent, and should remove (``pop``) or add (``insert``) items to
- the list of blocks.
-
- Keywords:
-
- * ``parent``: A etree element which is the parent of the current block.
- * ``blocks``: A list of all remaining blocks of the document.
- """
- pass
-
-
-class ListIndentProcessor(BlockProcessor):
- """ Process children of list items.
-
- Example:
- * a list item
- process this part
-
- or this part
-
- """
-
- ITEM_TYPES = ['li']
- LIST_TYPES = ['ul', 'ol']
-
- def __init__(self, *args):
- BlockProcessor.__init__(self, *args)
- self.INDENT_RE = re.compile(r'^(([ ]{%s})+)'% self.tab_length)
-
- def test(self, parent, block):
- return block.startswith(' '*self.tab_length) and \
- not self.parser.state.isstate('detabbed') and \
- (parent.tag in self.ITEM_TYPES or \
- (len(parent) and parent[-1] and \
- (parent[-1].tag in self.LIST_TYPES)
- )
- )
-
- def run(self, parent, blocks):
- block = blocks.pop(0)
- level, sibling = self.get_level(parent, block)
- block = self.looseDetab(block, level)
-
- self.parser.state.set('detabbed')
- if parent.tag in self.ITEM_TYPES:
- # It's possible that this parent has a 'ul' or 'ol' child list
- # with a member. If that is the case, then that should be the
- # parent. This is intended to catch the edge case of an indented
- # list whose first member was parsed previous to this point
- # see OListProcessor
- if len(parent) and parent[-1].tag in self.LIST_TYPES:
- self.parser.parseBlocks(parent[-1], [block])
- else:
- # The parent is already a li. Just parse the child block.
- self.parser.parseBlocks(parent, [block])
- elif sibling.tag in self.ITEM_TYPES:
- # The sibling is a li. Use it as parent.
- self.parser.parseBlocks(sibling, [block])
- elif len(sibling) and sibling[-1].tag in self.ITEM_TYPES:
- # The parent is a list (``ol`` or ``ul``) which has children.
- # Assume the last child li is the parent of this block.
- if sibling[-1].text:
- # If the parent li has text, that text needs to be moved to a p
- # The p must be 'inserted' at beginning of list in the event
- # that other children already exist i.e.; a nested sublist.
- p = util.etree.Element('p')
- p.text = sibling[-1].text
- sibling[-1].text = ''
- sibling[-1].insert(0, p)
- self.parser.parseChunk(sibling[-1], block)
- else:
- self.create_item(sibling, block)
- self.parser.state.reset()
-
- def create_item(self, parent, block):
- """ Create a new li and parse the block with it as the parent. """
- li = util.etree.SubElement(parent, 'li')
- self.parser.parseBlocks(li, [block])
-
- def get_level(self, parent, block):
- """ Get level of indent based on list level. """
- # Get indent level
- m = self.INDENT_RE.match(block)
- if m:
- indent_level = len(m.group(1))/self.tab_length
- else:
- indent_level = 0
- if self.parser.state.isstate('list'):
- # We're in a tightlist - so we already are at correct parent.
- level = 1
- else:
- # We're in a looselist - so we need to find parent.
- level = 0
- # Step through children of tree to find matching indent level.
- while indent_level > level:
- child = self.lastChild(parent)
- if child and (child.tag in self.LIST_TYPES or child.tag in self.ITEM_TYPES):
- if child.tag in self.LIST_TYPES:
- level += 1
- parent = child
- else:
- # No more child levels. If we're short of indent_level,
- # we have a code block. So we stop here.
- break
- return level, parent
-
-
-class CodeBlockProcessor(BlockProcessor):
- """ Process code blocks. """
-
- def test(self, parent, block):
- return block.startswith(' '*self.tab_length)
-
- def run(self, parent, blocks):
- sibling = self.lastChild(parent)
- block = blocks.pop(0)
- theRest = ''
- if sibling and sibling.tag == "pre" and len(sibling) \
- and sibling[0].tag == "code":
- # The previous block was a code block. As blank lines do not start
- # new code blocks, append this block to the previous, adding back
- # linebreaks removed from the split into a list.
- code = sibling[0]
- block, theRest = self.detab(block)
- code.text = util.AtomicString('%s\n%s\n' % (code.text, block.rstrip()))
- else:
- # This is a new codeblock. Create the elements and insert text.
- pre = util.etree.SubElement(parent, 'pre')
- code = util.etree.SubElement(pre, 'code')
- block, theRest = self.detab(block)
- code.text = util.AtomicString('%s\n' % block.rstrip())
- if theRest:
- # This block contained unindented line(s) after the first indented
- # line. Insert these lines as the first block of the master blocks
- # list for future processing.
- blocks.insert(0, theRest)
-
-
-class BlockQuoteProcessor(BlockProcessor):
-
- RE = re.compile(r'(^|\n)[ ]{0,3}>[ ]?(.*)')
-
- def test(self, parent, block):
- return bool(self.RE.search(block))
-
- def run(self, parent, blocks):
- block = blocks.pop(0)
- m = self.RE.search(block)
- if m:
- before = block[:m.start()] # Lines before blockquote
- # Pass lines before blockquote in recursively for parsing forst.
- self.parser.parseBlocks(parent, [before])
- # Remove ``> `` from begining of each line.
- block = '\n'.join([self.clean(line) for line in
- block[m.start():].split('\n')])
- sibling = self.lastChild(parent)
- if sibling and sibling.tag == "blockquote":
- # Previous block was a blockquote so set that as this blocks parent
- quote = sibling
- else:
- # This is a new blockquote. Create a new parent element.
- quote = util.etree.SubElement(parent, 'blockquote')
- # Recursively parse block with blockquote as parent.
- # change parser state so blockquotes embedded in lists use p tags
- self.parser.state.set('blockquote')
- self.parser.parseChunk(quote, block)
- self.parser.state.reset()
-
- def clean(self, line):
- """ Remove ``>`` from beginning of a line. """
- m = self.RE.match(line)
- if line.strip() == ">":
- return ""
- elif m:
- return m.group(2)
- else:
- return line
-
-class OListProcessor(BlockProcessor):
- """ Process ordered list blocks. """
-
- TAG = 'ol'
- # Detect an item (``1. item``). ``group(1)`` contains contents of item.
- RE = re.compile(r'^[ ]{0,3}\d+\.[ ]+(.*)')
- # Detect items on secondary lines. they can be of either list type.
- CHILD_RE = re.compile(r'^[ ]{0,3}((\d+\.)|[*+-])[ ]+(.*)')
- # Detect indented (nested) items of either type
- INDENT_RE = re.compile(r'^[ ]{4,7}((\d+\.)|[*+-])[ ]+.*')
- # The integer (python string) with which the lists starts (default=1)
- # Eg: If list is intialized as)
- # 3. Item
- # The ol tag will get starts="3" attribute
- STARTSWITH = '1'
- # List of allowed sibling tags.
- SIBLING_TAGS = ['ol', 'ul']
-
- def test(self, parent, block):
- return bool(self.RE.match(block))
-
- def run(self, parent, blocks):
- # Check fr multiple items in one block.
- items = self.get_items(blocks.pop(0))
- sibling = self.lastChild(parent)
-
- if sibling and sibling.tag in self.SIBLING_TAGS:
- # Previous block was a list item, so set that as parent
- lst = sibling
- # make sure previous item is in a p- if the item has text, then it
- # it isn't in a p
- if lst[-1].text:
- # since it's possible there are other children for this sibling,
- # we can't just SubElement the p, we need to insert it as the
- # first item
- p = util.etree.Element('p')
- p.text = lst[-1].text
- lst[-1].text = ''
- lst[-1].insert(0, p)
- # if the last item has a tail, then the tail needs to be put in a p
- # likely only when a header is not followed by a blank line
- lch = self.lastChild(lst[-1])
- if lch is not None and lch.tail:
- p = util.etree.SubElement(lst[-1], 'p')
- p.text = lch.tail.lstrip()
- lch.tail = ''
-
- # parse first block differently as it gets wrapped in a p.
- li = util.etree.SubElement(lst, 'li')
- self.parser.state.set('looselist')
- firstitem = items.pop(0)
- self.parser.parseBlocks(li, [firstitem])
- self.parser.state.reset()
- elif parent.tag in ['ol', 'ul']:
- # this catches the edge case of a multi-item indented list whose
- # first item is in a blank parent-list item:
- # * * subitem1
- # * subitem2
- # see also ListIndentProcessor
- lst = parent
- else:
- # This is a new list so create parent with appropriate tag.
- lst = util.etree.SubElement(parent, self.TAG)
- # Check if a custom start integer is set
- if not self.parser.markdown.lazy_ol and self.STARTSWITH !='1':
- lst.attrib['start'] = self.STARTSWITH
-
- self.parser.state.set('list')
- # Loop through items in block, recursively parsing each with the
- # appropriate parent.
- for item in items:
- if item.startswith(' '*self.tab_length):
- # Item is indented. Parse with last item as parent
- self.parser.parseBlocks(lst[-1], [item])
- else:
- # New item. Create li and parse with it as parent
- li = util.etree.SubElement(lst, 'li')
- self.parser.parseBlocks(li, [item])
- self.parser.state.reset()
-
- def get_items(self, block):
- """ Break a block into list items. """
- items = []
- for line in block.split('\n'):
- m = self.CHILD_RE.match(line)
- if m:
- # This is a new list item
- # Check first item for the start index
- if not items and self.TAG=='ol':
- # Detect the integer value of first list item
- INTEGER_RE = re.compile('(\d+)')
- self.STARTSWITH = INTEGER_RE.match(m.group(1)).group()
- # Append to the list
- items.append(m.group(3))
- elif self.INDENT_RE.match(line):
- # This is an indented (possibly nested) item.
- if items[-1].startswith(' '*self.tab_length):
- # Previous item was indented. Append to that item.
- items[-1] = '%s\n%s' % (items[-1], line)
- else:
- items.append(line)
- else:
- # This is another line of previous item. Append to that item.
- items[-1] = '%s\n%s' % (items[-1], line)
- return items
-
-
-class UListProcessor(OListProcessor):
- """ Process unordered list blocks. """
-
- TAG = 'ul'
- RE = re.compile(r'^[ ]{0,3}[*+-][ ]+(.*)')
-
-
-class HashHeaderProcessor(BlockProcessor):
- """ Process Hash Headers. """
-
- # Detect a header at start of any line in block
- RE = re.compile(r'(^|\n)(?P<level>#{1,6})(?P<header>.*?)#*(\n|$)')
-
- def test(self, parent, block):
- return bool(self.RE.search(block))
-
- def run(self, parent, blocks):
- block = blocks.pop(0)
- m = self.RE.search(block)
- if m:
- before = block[:m.start()] # All lines before header
- after = block[m.end():] # All lines after header
- if before:
- # As the header was not the first line of the block and the
- # lines before the header must be parsed first,
- # recursively parse this lines as a block.
- self.parser.parseBlocks(parent, [before])
- # Create header using named groups from RE
- h = util.etree.SubElement(parent, 'h%d' % len(m.group('level')))
- h.text = m.group('header').strip()
- if after:
- # Insert remaining lines as first block for future parsing.
- blocks.insert(0, after)
- else:
- # This should never happen, but just in case...
- logger.warn("We've got a problem header: %r" % block)
-
-
-class SetextHeaderProcessor(BlockProcessor):
- """ Process Setext-style Headers. """
-
- # Detect Setext-style header. Must be first 2 lines of block.
- RE = re.compile(r'^.*?\n[=-]+[ ]*(\n|$)', re.MULTILINE)
-
- def test(self, parent, block):
- return bool(self.RE.match(block))
-
- def run(self, parent, blocks):
- lines = blocks.pop(0).split('\n')
- # Determine level. ``=`` is 1 and ``-`` is 2.
- if lines[1].startswith('='):
- level = 1
- else:
- level = 2
- h = util.etree.SubElement(parent, 'h%d' % level)
- h.text = lines[0].strip()
- if len(lines) > 2:
- # Block contains additional lines. Add to master blocks for later.
- blocks.insert(0, '\n'.join(lines[2:]))
-
-
-class HRProcessor(BlockProcessor):
- """ Process Horizontal Rules. """
-
- RE = r'^[ ]{0,3}((-+[ ]{0,2}){3,}|(_+[ ]{0,2}){3,}|(\*+[ ]{0,2}){3,})[ ]*'
- # Detect hr on any line of a block.
- SEARCH_RE = re.compile(RE, re.MULTILINE)
-
- def test(self, parent, block):
- m = self.SEARCH_RE.search(block)
- # No atomic grouping in python so we simulate it here for performance.
- # The regex only matches what would be in the atomic group - the HR.
- # Then check if we are at end of block or if next char is a newline.
- if m and (m.end() == len(block) or block[m.end()] == '\n'):
- # Save match object on class instance so we can use it later.
- self.match = m
- return True
- return False
-
- def run(self, parent, blocks):
- block = blocks.pop(0)
- # Check for lines in block before hr.
- prelines = block[:self.match.start()].rstrip('\n')
- if prelines:
- # Recursively parse lines before hr so they get parsed first.
- self.parser.parseBlocks(parent, [prelines])
- # create hr
- util.etree.SubElement(parent, 'hr')
- # check for lines in block after hr.
- postlines = block[self.match.end():].lstrip('\n')
- if postlines:
- # Add lines after hr to master blocks for later parsing.
- blocks.insert(0, postlines)
-
-
-
-class EmptyBlockProcessor(BlockProcessor):
- """ Process blocks that are empty or start with an empty line. """
-
- def test(self, parent, block):
- return not block or block.startswith('\n')
-
- def run(self, parent, blocks):
- block = blocks.pop(0)
- filler = '\n\n'
- if block:
- # Starts with empty line
- # Only replace a single line.
- filler = '\n'
- # Save the rest for later.
- theRest = block[1:]
- if theRest:
- # Add remaining lines to master blocks for later.
- blocks.insert(0, theRest)
- sibling = self.lastChild(parent)
- if sibling and sibling.tag == 'pre' and len(sibling) and sibling[0].tag == 'code':
- # Last block is a codeblock. Append to preserve whitespace.
- sibling[0].text = util.AtomicString('%s%s' % (sibling[0].text, filler))
-
-
-class ParagraphProcessor(BlockProcessor):
- """ Process Paragraph blocks. """
-
- def test(self, parent, block):
- return True
-
- def run(self, parent, blocks):
- block = blocks.pop(0)
- if block.strip():
- # Not a blank block. Add to parent, otherwise throw it away.
- if self.parser.state.isstate('list'):
- # The parent is a tight-list.
- #
- # Check for any children. This will likely only happen in a
- # tight-list when a header isn't followed by a blank line.
- # For example:
- #
- # * # Header
- # Line 2 of list item - not part of header.
- sibling = self.lastChild(parent)
- if sibling is not None:
- # Insetrt after sibling.
- if sibling.tail:
- sibling.tail = '%s\n%s' % (sibling.tail, block)
- else:
- sibling.tail = '\n%s' % block
- else:
- # Append to parent.text
- if parent.text:
- parent.text = '%s\n%s' % (parent.text, block)
- else:
- parent.text = block.lstrip()
- else:
- # Create a regular paragraph
- p = util.etree.SubElement(parent, 'p')
- p.text = block.lstrip()
diff --git a/third_party/markdown/extensions/__init__.py b/third_party/markdown/extensions/__init__.py
deleted file mode 100644
index 184c4d1..0000000
--- a/third_party/markdown/extensions/__init__.py
+++ /dev/null
@@ -1,53 +0,0 @@
-"""
-Extensions
------------------------------------------------------------------------------
-"""
-
-from __future__ import unicode_literals
-
-class Extension(object):
- """ Base class for extensions to subclass. """
- def __init__(self, configs = {}):
- """Create an instance of an Extention.
-
- Keyword arguments:
-
- * configs: A dict of configuration setting used by an Extension.
- """
- self.config = configs
-
- def getConfig(self, key, default=''):
- """ Return a setting for the given key or an empty string. """
- if key in self.config:
- return self.config[key][0]
- else:
- return default
-
- def getConfigs(self):
- """ Return all configs settings as a dict. """
- return dict([(key, self.getConfig(key)) for key in self.config.keys()])
-
- def getConfigInfo(self):
- """ Return all config descriptions as a list of tuples. """
- return [(key, self.config[key][1]) for key in self.config.keys()]
-
- def setConfig(self, key, value):
- """ Set a config setting for `key` with the given `value`. """
- self.config[key][0] = value
-
- def extendMarkdown(self, md, md_globals):
- """
- Add the various proccesors and patterns to the Markdown Instance.
-
- This method must be overriden by every extension.
-
- Keyword arguments:
-
- * md: The Markdown instance.
-
- * md_globals: Global variables in the markdown module namespace.
-
- """
- raise NotImplementedError('Extension "%s.%s" must define an "extendMarkdown"' \
- 'method.' % (self.__class__.__module__, self.__class__.__name__))
-
diff --git a/third_party/markdown/extensions/abbr.py b/third_party/markdown/extensions/abbr.py
deleted file mode 100644
index 5e46f1d..0000000
--- a/third_party/markdown/extensions/abbr.py
+++ /dev/null
@@ -1,96 +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
- ... """
- >>> print markdown.markdown(text, ['abbr'])
- <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/)
-
-
-'''
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import Extension
-from ..preprocessors import Preprocessor
-from ..inlinepatterns import Pattern
-from ..util import etree
-import re
-
-# Global Vars
-ABBR_REF_RE = re.compile(r'[*]\[(?P<abbr>[^\]]*)\][ ]?:\s*(?P<title>.*)')
-
-class AbbrExtension(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(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(Pattern):
- """ Abbreviation inline pattern. """
-
- def __init__(self, pattern, title):
- super(AbbrPattern, self).__init__(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)
diff --git a/third_party/markdown/extensions/admonition.py b/third_party/markdown/extensions/admonition.py
deleted file mode 100644
index 9a45b92..0000000
--- a/third_party/markdown/extensions/admonition.py
+++ /dev/null
@@ -1,118 +0,0 @@
-"""
-Admonition extension for Python-Markdown
-========================================
-
-Adds rST-style admonitions. Inspired by [rST][] feature with the same name.
-
-The syntax is (followed by an indented block with the contents):
- !!! [type] [optional explicit title]
-
-Where `type` is used as a CSS class name of the div. If not present, `title`
-defaults to the capitalized `type`, so "note" -> "Note".
-
-rST suggests the following `types`, but you're free to use whatever you want:
- attention, caution, danger, error, hint, important, note, tip, warning
-
-
-A simple example:
- !!! note
- This is the first line inside the box.
-
-Outputs:
- <div class="admonition note">
- <p class="admonition-title">Note</p>
- <p>This is the first line inside the box</p>
- </div>
-
-You can also specify the title and CSS class of the admonition:
- !!! custom "Did you know?"
- Another line here.
-
-Outputs:
- <div class="admonition custom">
- <p class="admonition-title">Did you know?</p>
- <p>Another line here.</p>
- </div>
-
-[rST]: http://docutils.sourceforge.net/docs/ref/rst/directives.html#specific-admonitions
-
-By [Tiago Serafim](http://www.tiagoserafim.com/).
-
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import Extension
-from ..blockprocessors import BlockProcessor
-from ..util import etree
-import re
-
-
-class AdmonitionExtension(Extension):
- """ Admonition extension for Python-Markdown. """
-
- def extendMarkdown(self, md, md_globals):
- """ Add Admonition to Markdown instance. """
- md.registerExtension(self)
-
- md.parser.blockprocessors.add('admonition',
- AdmonitionProcessor(md.parser),
- '_begin')
-
-
-class AdmonitionProcessor(BlockProcessor):
-
- CLASSNAME = 'admonition'
- CLASSNAME_TITLE = 'admonition-title'
- RE = re.compile(r'(?:^|\n)!!!\ ?([\w\-]+)(?:\ "(.*?)")?')
-
- def test(self, parent, block):
- sibling = self.lastChild(parent)
- return self.RE.search(block) or \
- (block.startswith(' ' * self.tab_length) and sibling and \
- sibling.get('class', '').find(self.CLASSNAME) != -1)
-
- def run(self, parent, blocks):
- sibling = self.lastChild(parent)
- block = blocks.pop(0)
- m = self.RE.search(block)
-
- if m:
- block = block[m.end() + 1:] # removes the first line
-
- block, theRest = self.detab(block)
-
- if m:
- klass, title = self.get_class_and_title(m)
- div = etree.SubElement(parent, 'div')
- div.set('class', '%s %s' % (self.CLASSNAME, klass))
- if title:
- p = etree.SubElement(div, 'p')
- p.text = title
- p.set('class', self.CLASSNAME_TITLE)
- else:
- div = sibling
-
- self.parser.parseChunk(div, block)
-
- if theRest:
- # This block contained unindented line(s) after the first indented
- # line. Insert these lines as the first block of the master blocks
- # list for future processing.
- blocks.insert(0, theRest)
-
- def get_class_and_title(self, match):
- klass, title = match.group(1).lower(), match.group(2)
- if title is None:
- # no title was provided, use the capitalized classname as title
- # e.g.: `!!! note` will render `<p class="admonition-title">Note</p>`
- title = klass.capitalize()
- elif title == '':
- # an explicit blank title should not be rendered
- # e.g.: `!!! warning ""` will *not* render `p` with a title
- title = None
- return klass, title
-
-
-def makeExtension(configs={}):
- return AdmonitionExtension(configs=configs)
diff --git a/third_party/markdown/extensions/attr_list.py b/third_party/markdown/extensions/attr_list.py
deleted file mode 100644
index c98aa85..0000000
--- a/third_party/markdown/extensions/attr_list.py
+++ /dev/null
@@ -1,140 +0,0 @@
-"""
-Attribute List Extension for Python-Markdown
-============================================
-
-Adds attribute list syntax. Inspired by
-[maruku](http://maruku.rubyforge.org/proposal.html#attribute_lists)'s
-feature of the same name.
-
-Copyright 2011 [Waylan Limberg](http://achinghead.com/).
-
-Contact: markdown@freewisdom.org
-
-License: BSD (see ../LICENSE.md for details)
-
-Dependencies:
-* [Python 2.4+](http://python.org)
-* [Markdown 2.1+](http://packages.python.org/Markdown/)
-
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import Extension
-from ..treeprocessors import Treeprocessor
-from ..util import isBlockLevel
-import re
-
-try:
- Scanner = re.Scanner
-except AttributeError:
- # must be on Python 2.4
- from sre import Scanner
-
-def _handle_double_quote(s, t):
- k, v = t.split('=')
- return k, v.strip('"')
-
-def _handle_single_quote(s, t):
- k, v = t.split('=')
- return k, v.strip("'")
-
-def _handle_key_value(s, t):
- return t.split('=')
-
-def _handle_word(s, t):
- if t.startswith('.'):
- return '.', t[1:]
- if t.startswith('#'):
- return 'id', t[1:]
- return t, t
-
-_scanner = Scanner([
- (r'[^ ]+=".*?"', _handle_double_quote),
- (r"[^ ]+='.*?'", _handle_single_quote),
- (r'[^ ]+=[^ ]*', _handle_key_value),
- (r'[^ ]+', _handle_word),
- (r' ', None)
-])
-
-def get_attrs(str):
- """ Parse attribute list and return a list of attribute tuples. """
- return _scanner.scan(str)[0]
-
-def isheader(elem):
- return elem.tag in ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
-
-class AttrListTreeprocessor(Treeprocessor):
-
- BASE_RE = r'\{\:?([^\}]*)\}'
- HEADER_RE = re.compile(r'[ ]*%s[ ]*$' % BASE_RE)
- BLOCK_RE = re.compile(r'\n[ ]*%s[ ]*$' % BASE_RE)
- INLINE_RE = re.compile(r'^%s' % BASE_RE)
- NAME_RE = re.compile(r'[^A-Z_a-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02ff\u0370-\u037d'
- r'\u037f-\u1fff\u200c-\u200d\u2070-\u218f\u2c00-\u2fef'
- r'\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd'
- r'\:\-\.0-9\u00b7\u0300-\u036f\u203f-\u2040]+')
-
- def run(self, doc):
- for elem in doc.getiterator():
- if isBlockLevel(elem.tag):
- # Block level: check for attrs on last line of text
- RE = self.BLOCK_RE
- if isheader(elem):
- # header: check for attrs at end of line
- RE = self.HEADER_RE
- if len(elem) and elem[-1].tail:
- # has children. Get from tail of last child
- m = RE.search(elem[-1].tail)
- if m:
- self.assign_attrs(elem, m.group(1))
- elem[-1].tail = elem[-1].tail[:m.start()]
- if isheader(elem):
- # clean up trailing #s
- elem[-1].tail = elem[-1].tail.rstrip('#').rstrip()
- elif elem.text:
- # no children. Get from text.
- m = RE.search(elem.text)
- if m:
- self.assign_attrs(elem, m.group(1))
- elem.text = elem.text[:m.start()]
- if isheader(elem):
- # clean up trailing #s
- elem.text = elem.text.rstrip('#').rstrip()
- else:
- # inline: check for attrs at start of tail
- if elem.tail:
- m = self.INLINE_RE.match(elem.tail)
- if m:
- self.assign_attrs(elem, m.group(1))
- elem.tail = elem.tail[m.end():]
-
- def assign_attrs(self, elem, attrs):
- """ Assign attrs to element. """
- for k, v in get_attrs(attrs):
- if k == '.':
- # add to class
- cls = elem.get('class')
- if cls:
- elem.set('class', '%s %s' % (cls, v))
- else:
- elem.set('class', v)
- else:
- # assign attr k with v
- elem.set(self.sanitize_name(k), v)
-
- def sanitize_name(self, name):
- """
- Sanitize name as 'an XML Name, minus the ":"'.
- See http://www.w3.org/TR/REC-xml-names/#NT-NCName
- """
- return self.NAME_RE.sub('_', name)
-
-
-class AttrListExtension(Extension):
- def extendMarkdown(self, md, md_globals):
- md.treeprocessors.add('attr_list', AttrListTreeprocessor(md), '>prettify')
-
-
-def makeExtension(configs={}):
- return AttrListExtension(configs=configs)
diff --git a/third_party/markdown/extensions/codehilite.py b/third_party/markdown/extensions/codehilite.py
deleted file mode 100644
index 72b40fd..0000000
--- a/third_party/markdown/extensions/codehilite.py
+++ /dev/null
@@ -1,240 +0,0 @@
-"""
-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://packages.python.org/Markdown/extensions/code_hilite.html>
-Contact: markdown@freewisdom.org
-
-License: BSD (see ../LICENSE.md for details)
-
-Dependencies:
-* [Python 2.3+](http://python.org/)
-* [Markdown 2.0+](http://packages.python.org/Markdown/)
-* [Pygments](http://pygments.org/)
-
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import Extension
-from ..treeprocessors import Treeprocessor
-import warnings
-try:
- from pygments import highlight
- from pygments.lexers import get_lexer_by_name, guess_lexer, TextLexer
- from pygments.formatters import HtmlFormatter
- pygments = True
-except ImportError:
- pygments = False
-
-# ------------------ The Main CodeHilite Class ----------------------
-class CodeHilite(object):
- """
- 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.
-
- * linenums: (Boolean) Set line numbering to 'on' (True), 'off' (False) or 'auto'(None).
- Set to 'auto' by default.
-
- * guess_lang: (Boolean) Turn language auto-detection 'on' or 'off' (on 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, linenums=None, guess_lang=True,
- css_class="codehilite", lang=None, style='default',
- noclasses=False, tab_length=4):
- self.src = src
- self.lang = lang
- self.linenums = linenums
- self.guess_lang = guess_lang
- self.css_class = css_class
- self.style = style
- self.noclasses = noclasses
- self.tab_length = tab_length
-
- 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')
-
- if self.lang is None:
- self._getLang()
-
- if pygments:
- try:
- lexer = get_lexer_by_name(self.lang)
- except ValueError:
- try:
- if self.guess_lang:
- lexer = guess_lexer(self.src)
- else:
- lexer = TextLexer()
- except ValueError:
- lexer = TextLexer()
- formatter = HtmlFormatter(linenos=self.linenums,
- cssclass=self.css_class,
- style=self.style,
- noclasses=self.noclasses)
- return highlight(self.src, lexer, formatter)
- else:
- # just escape and build markup usable by JS highlighting libs
- txt = self.src.replace('&', '&amp;')
- txt = txt.replace('<', '&lt;')
- txt = txt.replace('>', '&gt;')
- txt = txt.replace('"', '&quot;')
- classes = []
- if self.lang:
- classes.append('language-%s' % self.lang)
- if self.linenums:
- classes.append('linenums')
- class_str = ''
- if classes:
- class_str = ' class="%s"' % ' '.join(classes)
- return '<pre class="%s"><code%s>%s</code></pre>\n'% \
- (self.css_class, class_str, txt)
-
- def _getLang(self):
- """
- Determines language of a code block from shebang line 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 line 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 self.linenums is None and m.group('shebang'):
- # Overridable and Shebang exists - use line numbers
- self.linenums = True
- else:
- # No match
- lines.insert(0, fl)
-
- self.src = "\n".join(lines).strip("\n")
-
-
-
-# ------------------ The Markdown Extension -------------------------------
-class HiliteTreeprocessor(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,
- linenums=self.config['linenums'],
- guess_lang=self.config['guess_lang'],
- css_class=self.config['css_class'],
- style=self.config['pygments_style'],
- noclasses=self.config['noclasses'],
- tab_length=self.markdown.tab_length)
- 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(Extension):
- """ Add source code hilighting to markdown codeblocks. """
-
- def __init__(self, configs):
- # define default configs
- self.config = {
- 'linenums': [None, "Use lines numbers. True=yes, False=no, None=auto"],
- 'force_linenos' : [False, "Depreciated! Use 'linenums' instead. Force line numbers - Default: False"],
- 'guess_lang' : [True, "Automatic language detection - Default: True"],
- 'css_class' : ["codehilite",
- "Set class name for wrapper <div> - Default: codehilite"],
- 'pygments_style' : ['default', 'Pygments HTML Formatter Style (Colorscheme) - Default: default'],
- 'noclasses': [False, 'Use inline styles instead of CSS classes - Default false']
- }
-
- # Override defaults with user settings
- for key, value in configs:
- # convert strings to booleans
- if value == 'True': value = True
- if value == 'False': value = False
- if value == 'None': value = None
-
- if key == 'force_linenos':
- warnings.warn('The "force_linenos" config setting'
- ' to the CodeHilite extension is deprecrecated.'
- ' Use "linenums" instead.', PendingDeprecationWarning)
- if value:
- # Carry 'force_linenos' over to new 'linenos'.
- self.setConfig('linenums', True)
-
- self.setConfig(key, value)
-
- def extendMarkdown(self, md, md_globals):
- """ Add HilitePostprocessor to Markdown instance. """
- hiliter = HiliteTreeprocessor(md)
- hiliter.config = self.getConfigs()
- md.treeprocessors.add("hilite", hiliter, "<inline")
-
- md.registerExtension(self)
-
-
-def makeExtension(configs={}):
- return CodeHiliteExtension(configs=configs)
-
diff --git a/third_party/markdown/extensions/def_list.py b/third_party/markdown/extensions/def_list.py
deleted file mode 100644
index 8684652..0000000
--- a/third_party/markdown/extensions/def_list.py
+++ /dev/null
@@ -1,118 +0,0 @@
-"""
-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)
-
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import Extension
-from ..blockprocessors import BlockProcessor, ListIndentProcessor
-from ..util import etree
-import re
-
-
-class DefListProcessor(BlockProcessor):
- """ Process Definition Lists. """
-
- RE = re.compile(r'(^|\n)[ ]{0,3}:[ ]{1,3}(.*?)(\n|$)')
- NO_INDENT_RE = re.compile(r'^[ ]{0,3}[^ :]')
-
- def test(self, parent, block):
- return bool(self.RE.search(block))
-
- def run(self, parent, blocks):
-
- raw_block = blocks.pop(0)
- m = self.RE.search(raw_block)
- terms = [l.strip() for l in raw_block[:m.start()].split('\n') if l.strip()]
- block = raw_block[m.end():]
- no_indent = self.NO_INDENT_RE.match(block)
- if no_indent:
- d, theRest = (block, None)
- else:
- d, theRest = self.detab(block)
- if d:
- d = '%s\n%s' % (m.group(2), d)
- else:
- d = m.group(2)
- sibling = self.lastChild(parent)
- if not terms and sibling is None:
- # This is not a definition item. Most likely a paragraph that
- # starts with a colon at the begining of a document or list.
- blocks.insert(0, raw_block)
- return False
- if not terms and sibling.tag == 'p':
- # The previous paragraph contains the terms
- state = 'looselist'
- terms = sibling.text.split('\n')
- parent.remove(sibling)
- # Aquire new sibling
- sibling = self.lastChild(parent)
- else:
- state = 'list'
-
- if sibling and sibling.tag == 'dl':
- # This is another item on an existing list
- dl = sibling
- if len(dl) and dl[-1].tag == 'dd' and len(dl[-1]):
- state = 'looselist'
- else:
- # This is a new list
- dl = etree.SubElement(parent, 'dl')
- # Add terms
- for term in terms:
- dt = etree.SubElement(dl, 'dt')
- dt.text = term
- # Add definition
- self.parser.state.set(state)
- dd = etree.SubElement(dl, 'dd')
- self.parser.parseBlocks(dd, [d])
- self.parser.state.reset()
-
- if theRest:
- blocks.insert(0, theRest)
-
-class DefListIndentProcessor(ListIndentProcessor):
- """ Process indented children of definition list items. """
-
- ITEM_TYPES = ['dd']
- LIST_TYPES = ['dl']
-
- def create_item(self, parent, block):
- """ Create a new dd and parse the block with it as the parent. """
- dd = etree.SubElement(parent, 'dd')
- self.parser.parseBlocks(dd, [block])
-
-
-
-class DefListExtension(Extension):
- """ Add definition lists to Markdown. """
-
- def extendMarkdown(self, md, md_globals):
- """ Add an instance of DefListProcessor to BlockParser. """
- md.parser.blockprocessors.add('defindent',
- DefListIndentProcessor(md.parser),
- '>indent')
- md.parser.blockprocessors.add('deflist',
- DefListProcessor(md.parser),
- '>ulist')
-
-
-def makeExtension(configs={}):
- return DefListExtension(configs=configs)
-
diff --git a/third_party/markdown/extensions/extra.py b/third_party/markdown/extensions/extra.py
deleted file mode 100644
index e6a1e82..0000000
--- a/third_party/markdown/extensions/extra.py
+++ /dev/null
@@ -1,54 +0,0 @@
-"""
-Python-Markdown Extra Extension
-===============================
-
-A compilation of various Python-Markdown extensions that imitates
-[PHP Markdown Extra](http://michelf.com/projects/php-markdown/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 issue a warning and simply continue
-without that extension.
-
-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.
-
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import Extension
-
-extensions = ['smart_strong',
- 'fenced_code',
- 'footnotes',
- 'attr_list',
- 'def_list',
- 'tables',
- 'abbr',
- ]
-
-
-class ExtraExtension(Extension):
- """ Add various extensions to Markdown class."""
-
- def extendMarkdown(self, md, md_globals):
- """ Register extension instances. """
- md.registerExtensions(extensions, self.config)
- if not md.safeMode:
- # Turn on processing of markdown text within raw html
- md.preprocessors['html_block'].markdown_in_raw = True
-
-def makeExtension(configs={}):
- return ExtraExtension(configs=dict(configs))
diff --git a/third_party/markdown/extensions/fenced_code.py b/third_party/markdown/extensions/fenced_code.py
deleted file mode 100644
index ecdb20d..0000000
--- a/third_party/markdown/extensions/fenced_code.py
+++ /dev/null
@@ -1,161 +0,0 @@
-"""
-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'])
- >>> print html
- <p>A paragraph before a fenced code block:</p>
- <pre><code>Fenced code block
- </code></pre>
-
-Works with safe_mode also (we check this because we are using the HtmlStash):
-
- >>> print markdown.markdown(text, extensions=['fenced_code'], safe_mode='replace')
- <p>A paragraph before a fenced code block:</p>
- <pre><code>Fenced code block
- </code></pre>
-
-Include tilde's in a code block and wrap with blank lines:
-
- >>> text = '''
- ... ~~~~~~~~
- ...
- ... ~~~~
- ... ~~~~~~~~'''
- >>> print markdown.markdown(text, extensions=['fenced_code'])
- <pre><code>
- ~~~~
- </code></pre>
-
-Language tags:
-
- >>> text = '''
- ... ~~~~{.python}
- ... # Some python code
- ... ~~~~'''
- >>> print markdown.markdown(text, extensions=['fenced_code'])
- <pre><code class="python"># Some python code
- </code></pre>
-
-Optionally backticks instead of tildes as per how github's code block markdown is identified:
-
- >>> text = '''
- ... `````
- ... # Arbitrary code
- ... ~~~~~ # these tildes will not close the block
- ... `````'''
- >>> print markdown.markdown(text, extensions=['fenced_code'])
- <pre><code># Arbitrary code
- ~~~~~ # these tildes will not close the block
- </code></pre>
-
-Copyright 2007-2008 [Waylan Limberg](http://achinghead.com/).
-
-Project website: <http://packages.python.org/Markdown/extensions/fenced_code_blocks.html>
-Contact: markdown@freewisdom.org
-
-License: BSD (see ../docs/LICENSE for details)
-
-Dependencies:
-* [Python 2.4+](http://python.org)
-* [Markdown 2.0+](http://packages.python.org/Markdown/)
-* [Pygments (optional)](http://pygments.org)
-
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import Extension
-from ..preprocessors import Preprocessor
-from .codehilite import CodeHilite, CodeHiliteExtension
-import re
-
-# Global vars
-FENCED_BLOCK_RE = re.compile( \
- r'(?P<fence>^(?:~{3,}|`{3,}))[ ]*(\{?\.?(?P<lang>[a-zA-Z0-9_+-]*)\}?)?[ ]*\n(?P<code>.*?)(?<=\n)(?P=fence)[ ]*$',
- re.MULTILINE|re.DOTALL
- )
-CODE_WRAP = '<pre><code%s>%s</code></pre>'
-LANG_TAG = ' class="%s"'
-
-class FencedCodeExtension(Extension):
-
- def extendMarkdown(self, md, md_globals):
- """ Add FencedBlockPreprocessor to the Markdown instance. """
- md.registerExtension(self)
-
- md.preprocessors.add('fenced_code_block',
- FencedBlockPreprocessor(md),
- ">normalize_whitespace")
-
-
-class FencedBlockPreprocessor(Preprocessor):
-
- def __init__(self, md):
- super(FencedBlockPreprocessor, self).__init__(md)
-
- self.checked_for_codehilite = False
- self.codehilite_conf = {}
-
- def run(self, lines):
- """ Match and store Fenced Code Blocks in the HtmlStash. """
-
- # Check for code hilite extension
- if not self.checked_for_codehilite:
- for ext in self.markdown.registeredExtensions:
- if isinstance(ext, CodeHiliteExtension):
- self.codehilite_conf = ext.config
- break
-
- self.checked_for_codehilite = True
-
- 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')
-
- # If config is not empty, then the codehighlite extension
- # is enabled, so we call it to highlite the code
- if self.codehilite_conf:
- highliter = CodeHilite(m.group('code'),
- linenums=self.codehilite_conf['linenums'][0],
- guess_lang=self.codehilite_conf['guess_lang'][0],
- css_class=self.codehilite_conf['css_class'][0],
- style=self.codehilite_conf['pygments_style'][0],
- lang=(m.group('lang') or None),
- noclasses=self.codehilite_conf['noclasses'][0])
-
- code = highliter.hilite()
- else:
- 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(configs=configs)
diff --git a/third_party/markdown/extensions/footnotes.py b/third_party/markdown/extensions/footnotes.py
deleted file mode 100644
index 65ed597..0000000
--- a/third_party/markdown/extensions/footnotes.py
+++ /dev/null
@@ -1,313 +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
-
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import Extension
-from ..preprocessors import Preprocessor
-from ..inlinepatterns import Pattern
-from ..treeprocessors import Treeprocessor
-from ..postprocessors import Postprocessor
-from ..util import etree, text_type
-from ..odict import OrderedDict
-import re
-
-FN_BACKLINK_TEXT = "zz1337820767766393qq"
-NBSP_PLACEHOLDER = "qq3936677670287331zz"
-DEF_RE = re.compile(r'[ ]{0,3}\[\^([^\]]*)\]:\s*(.*)')
-TABBED_RE = re.compile(r'((\t)|( ))(.*)')
-
-class FootnoteExtension(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"],
- 'UNIQUE_IDS':
- [False,
- "Avoid name collisions across "
- "multiple calls to reset()."],
- "BACKLINK_TEXT":
- ["&#8617;",
- "The text string that links from the footnote to the reader's place."]
- }
-
- for key, value in configs:
- self.config[key][0] = value
-
- # In multiple invocations, emit links that don't get tangled.
- self.unique_prefix = 0
-
- self.reset()
-
- def extendMarkdown(self, md, md_globals):
- """ Add pieces to Markdown. """
- md.registerExtension(self)
- self.parser = md.parser
- self.md = md
- self.sep = ':'
- if self.md.output_format in ['html5', 'xhtml5']:
- self.sep = '-'
- # 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 all other treeprocessors (i.e., inline and
- # codehilite) so they can run on the the contents of the div.
- md.treeprocessors.add("footnote", FootnoteTreeprocessor(self),
- "_begin")
- # Insert a postprocessor after amp_substitute oricessor
- md.postprocessors.add("footnote", FootnotePostprocessor(self),
- ">amp_substitute")
-
- def reset(self):
- """ Clear the footnotes on reset, and prepare for a distinct document. """
- self.footnotes = OrderedDict()
- self.unique_prefix += 1
-
- 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, element, 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. """
- if self.getConfig("UNIQUE_IDS"):
- return 'fn%s%d-%s' % (self.sep, self.unique_prefix, id)
- else:
- return 'fn%s%s' % (self.sep, id)
-
- def makeFootnoteRefId(self, id):
- """ Return footnote back-link id. """
- if self.getConfig("UNIQUE_IDS"):
- return 'fnref%s%d-%s' % (self.sep, self.unique_prefix, id)
- else:
- return 'fnref%s%s' % (self.sep, id)
-
- def makeFootnotesDiv(self, root):
- """ Return div of footnotes as et Element. """
-
- if not list(self.footnotes.keys()):
- return None
-
- div = etree.Element("div")
- div.set('class', 'footnote')
- 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))
- if self.md.output_format not in ['html5', 'xhtml5']:
- backlink.set("rev", "footnote") # Invalid in HTML5
- backlink.set("class", "footnote-backref")
- 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(Preprocessor):
- """ Find all footnote references and store for later use. """
-
- def __init__ (self, footnotes):
- self.footnotes = footnotes
-
- def run(self, lines):
- """
- Loop through lines and find, set, and remove footnote definitions.
-
- Keywords:
-
- * lines: A list of lines of text
-
- Return: A list of lines of text with footnote definitions removed.
-
- """
- newlines = []
- i = 0
- while True:
- m = DEF_RE.match(lines[i])
- if m:
- fn, _i = self.detectTabbed(lines[i+1:])
- fn.insert(0, m.group(2))
- i += _i-1 # skip past footnote
- self.footnotes.setFootnote(m.group(1), "\n".join(fn))
- else:
- newlines.append(lines[i])
- if len(lines) > i+1:
- i += 1
- else:
- break
- return newlines
-
- 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 index of last line.
-
- """
- items = []
- blank_line = False # have we encountered a blank line yet?
- 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
- detabbed_line = detab(line)
- if detabbed_line:
- items.append(detabbed_line)
- i += 1
- continue
- elif not blank_line and not DEF_RE.match(line):
- # not tabbed but still part of first par.
- items.append(line)
- i += 1
- continue
- else:
- return items, i+1
-
- else: # Blank line: _maybe_ we are done.
- blank_line = True
- 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, i
-
-
-class FootnotePattern(Pattern):
- """ InlinePattern for footnote markers in a document's body text. """
-
- def __init__(self, pattern, footnotes):
- super(FootnotePattern, self).__init__(pattern)
- self.footnotes = footnotes
-
- def handleMatch(self, m):
- id = m.group(2)
- if id in self.footnotes.footnotes.keys():
- sup = etree.Element("sup")
- a = etree.SubElement(sup, "a")
- sup.set('id', self.footnotes.makeFootnoteRefId(id))
- a.set('href', '#' + self.footnotes.makeFootnoteId(id))
- if self.footnotes.md.output_format not in ['html5', 'xhtml5']:
- a.set('rel', 'footnote') # invalid in HTML5
- a.set('class', 'footnote-ref')
- a.text = text_type(self.footnotes.footnotes.index(id) + 1)
- return sup
- else:
- return None
-
-
-class FootnoteTreeprocessor(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:
- child, parent, isText = result
- ind = parent.getchildren().index(child)
- if isText:
- parent.remove(child)
- parent.insert(ind, footnotesDiv)
- else:
- parent.insert(ind + 1, footnotesDiv)
- child.tail = None
- else:
- root.append(footnotesDiv)
-
-class FootnotePostprocessor(Postprocessor):
- """ Replace placeholders with html entities. """
- def __init__(self, footnotes):
- self.footnotes = footnotes
-
- def run(self, text):
- text = text.replace(FN_BACKLINK_TEXT, self.footnotes.getConfig("BACKLINK_TEXT"))
- return text.replace(NBSP_PLACEHOLDER, "&#160;")
-
-def makeExtension(configs=[]):
- """ Return an instance of the FootnoteExtension """
- return FootnoteExtension(configs=configs)
-
diff --git a/third_party/markdown/extensions/headerid.py b/third_party/markdown/extensions/headerid.py
deleted file mode 100644
index 7681b8d..0000000
--- a/third_party/markdown/extensions/headerid.py
+++ /dev/null
@@ -1,199 +0,0 @@
-"""
-HeaderID Extension for Python-Markdown
-======================================
-
-Auto-generate id attributes for HTML headers.
-
-Basic usage:
-
- >>> import markdown
- >>> text = "# Some Header #"
- >>> md = markdown.markdown(text, ['headerid'])
- >>> print md
- <h1 id="some-header">Some Header</h1>
-
-All header IDs are unique:
-
- >>> text = '''
- ... #Header
- ... #Header
- ... #Header'''
- >>> md = markdown.markdown(text, ['headerid'])
- >>> print md
- <h1 id="header">Header</h1>
- <h1 id="header_1">Header</h1>
- <h1 id="header_2">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)'])
- >>> print md
- <h3 id="some-header">Some Header</h3>
- <h4 id="next-level">Next Level</h4>
-
-Works with inline markup.
-
- >>> text = '#Some *Header* with [markup](http://example.com).'
- >>> md = markdown.markdown(text, ['headerid'])
- >>> print md
- <h1 id="some-header-with-markup">Some <em>Header</em> with <a href="http://example.com">markup</a>.</h1>
-
-Turn off auto generated IDs:
-
- >>> text = '''
- ... # Some Header
- ... # Another Header'''
- >>> md = markdown.markdown(text, ['headerid(forceid=False)'])
- >>> print md
- <h1>Some Header</h1>
- <h1>Another Header</h1>
-
-Use with MetaData extension:
-
- >>> text = '''header_level: 2
- ... header_forceid: Off
- ...
- ... # A Header'''
- >>> md = markdown.markdown(text, ['headerid', 'meta'])
- >>> print md
- <h2>A Header</h2>
-
-Copyright 2007-2011 [Waylan Limberg](http://achinghead.com/).
-
-Project website: <http://packages.python.org/Markdown/extensions/header_id.html>
-Contact: markdown@freewisdom.org
-
-License: BSD (see ../docs/LICENSE for details)
-
-Dependencies:
-* [Python 2.3+](http://python.org)
-* [Markdown 2.0+](http://packages.python.org/Markdown/)
-
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import Extension
-from ..treeprocessors import Treeprocessor
-import re
-import logging
-import unicodedata
-
-logger = logging.getLogger('MARKDOWN')
-
-IDCOUNT_RE = re.compile(r'^(.*)_([0-9]+)$')
-
-
-def slugify(value, separator):
- """ Slugify a string, to make it URL friendly. """
- value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
- value = re.sub('[^\w\s-]', '', value.decode('ascii')).strip().lower()
- return re.sub('[%s\s]+' % separator, separator, value)
-
-
-def unique(id, ids):
- """ Ensure id is unique in set of ids. Append '_1', '_2'... if not """
- while id in ids or not id:
- m = IDCOUNT_RE.match(id)
- if m:
- id = '%s_%d'% (m.group(1), int(m.group(2))+1)
- else:
- id = '%s_%d'% (id, 1)
- ids.add(id)
- return id
-
-
-def itertext(elem):
- """ Loop through all children and return text only.
-
- Reimplements method of same name added to ElementTree in Python 2.7
-
- """
- if elem.text:
- yield elem.text
- for e in elem:
- for s in itertext(e):
- yield s
- if e.tail:
- yield e.tail
-
-
-class HeaderIdTreeprocessor(Treeprocessor):
- """ Assign IDs to headers. """
-
- IDs = set()
-
- def run(self, doc):
- start_level, force_id = self._get_meta()
- slugify = self.config['slugify']
- sep = self.config['separator']
- for elem in doc.getiterator():
- if elem.tag in ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']:
- if force_id:
- if "id" in elem.attrib:
- id = elem.get('id')
- else:
- id = slugify(''.join(itertext(elem)), sep)
- elem.set('id', unique(id, self.IDs))
- if start_level:
- level = int(elem.tag[-1]) + start_level
- if level > 6:
- level = 6
- elem.tag = 'h%d' % level
-
-
- def _get_meta(self):
- """ Return meta data suported by this ext as a tuple """
- level = int(self.config['level']) - 1
- force = self._str2bool(self.config['forceid'])
- if hasattr(self.md, 'Meta'):
- if 'header_level' in self.md.Meta:
- level = int(self.md.Meta['header_level'][0]) - 1
- if 'header_forceid' in self.md.Meta:
- force = self._str2bool(self.md.Meta['header_forceid'][0])
- return level, force
-
- def _str2bool(self, 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
-
-
-class HeaderIdExtension(Extension):
- def __init__(self, configs):
- # set defaults
- self.config = {
- 'level' : ['1', 'Base level for headers.'],
- 'forceid' : ['True', 'Force all headers to have an id.'],
- 'separator' : ['-', 'Word separator.'],
- 'slugify' : [slugify, 'Callable to generate anchors'],
- }
-
- for key, value in configs:
- self.setConfig(key, value)
-
- def extendMarkdown(self, md, md_globals):
- md.registerExtension(self)
- self.processor = HeaderIdTreeprocessor()
- self.processor.md = md
- self.processor.config = self.getConfigs()
- if 'attr_list' in md.treeprocessors.keys():
- # insert after attr_list treeprocessor
- md.treeprocessors.add('headerid', self.processor, '>attr_list')
- else:
- # insert after 'prettify' treeprocessor.
- md.treeprocessors.add('headerid', self.processor, '>prettify')
-
- def reset(self):
- self.processor.IDs = set()
-
-
-def makeExtension(configs=None):
- return HeaderIdExtension(configs=configs)
diff --git a/third_party/markdown/extensions/meta.py b/third_party/markdown/extensions/meta.py
deleted file mode 100644
index aaff436..0000000
--- a/third_party/markdown/extensions/meta.py
+++ /dev/null
@@ -1,93 +0,0 @@
-"""
-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'])
- >>> print md.convert(text)
- <p>The body. This is paragraph one.</p>
- >>> print 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'])
- >>> print md.convert(text)
- <pre><code>Some Code - not extra lines of meta data.
- </code></pre>
- >>> md.Meta
- {}
-
-Copyright 2007-2008 [Waylan Limberg](http://achinghead.com).
-
-Project website: <http://packages.python.org/Markdown/meta_data.html>
-Contact: markdown@freewisdom.org
-
-License: BSD (see ../LICENSE.md for details)
-
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import Extension
-from ..preprocessors import Preprocessor
-import 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 (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(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()
- value = m1.group('value').strip()
- try:
- meta[key].append(value)
- except KeyError:
- meta[key] = [value]
- 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)
diff --git a/third_party/markdown/extensions/nl2br.py b/third_party/markdown/extensions/nl2br.py
deleted file mode 100644
index da4b339..0000000
--- a/third_party/markdown/extensions/nl2br.py
+++ /dev/null
@@ -1,38 +0,0 @@
-"""
-NL2BR Extension
-===============
-
-A Python-Markdown extension to treat newlines as hard breaks; like
-GitHub-flavored Markdown does.
-
-Usage:
-
- >>> import markdown
- >>> print markdown.markdown('line 1\\nline 2', extensions=['nl2br'])
- <p>line 1<br />
- line 2</p>
-
-Copyright 2011 [Brian Neal](http://deathofagremmie.com/)
-
-Dependencies:
-* [Python 2.4+](http://python.org)
-* [Markdown 2.1+](http://packages.python.org/Markdown/)
-
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import Extension
-from ..inlinepatterns import SubstituteTagPattern
-
-BR_RE = r'\n'
-
-class Nl2BrExtension(Extension):
-
- def extendMarkdown(self, md, md_globals):
- br_tag = SubstituteTagPattern(BR_RE, 'br')
- md.inlinePatterns.add('nl', br_tag, '_end')
-
-
-def makeExtension(configs=None):
- return Nl2BrExtension(configs)
diff --git a/third_party/markdown/extensions/sane_lists.py b/third_party/markdown/extensions/sane_lists.py
deleted file mode 100644
index 23e9a7f..0000000
--- a/third_party/markdown/extensions/sane_lists.py
+++ /dev/null
@@ -1,51 +0,0 @@
-"""
-Sane List Extension for Python-Markdown
-=======================================
-
-Modify the behavior of Lists in Python-Markdown t act in a sane manor.
-
-In standard Markdown sytex, the following would constitute a single
-ordered list. However, with this extension, the output would include
-two lists, the first an ordered list and the second and unordered list.
-
- 1. ordered
- 2. list
-
- * unordered
- * list
-
-Copyright 2011 - [Waylan Limberg](http://achinghead.com)
-
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import Extension
-from ..blockprocessors import OListProcessor, UListProcessor
-import re
-
-
-class SaneOListProcessor(OListProcessor):
-
- CHILD_RE = re.compile(r'^[ ]{0,3}((\d+\.))[ ]+(.*)')
- SIBLING_TAGS = ['ol']
-
-
-class SaneUListProcessor(UListProcessor):
-
- CHILD_RE = re.compile(r'^[ ]{0,3}(([*+-]))[ ]+(.*)')
- SIBLING_TAGS = ['ul']
-
-
-class SaneListExtension(Extension):
- """ Add sane lists to Markdown. """
-
- def extendMarkdown(self, md, md_globals):
- """ Override existing Processors. """
- md.parser.blockprocessors['olist'] = SaneOListProcessor(md.parser)
- md.parser.blockprocessors['ulist'] = SaneUListProcessor(md.parser)
-
-
-def makeExtension(configs={}):
- return SaneListExtension(configs=configs)
-
diff --git a/third_party/markdown/extensions/smart_strong.py b/third_party/markdown/extensions/smart_strong.py
deleted file mode 100644
index 4818cf9..0000000
--- a/third_party/markdown/extensions/smart_strong.py
+++ /dev/null
@@ -1,42 +0,0 @@
-'''
-Smart_Strong Extension for Python-Markdown
-==========================================
-
-This extention adds smarter handling of double underscores within words.
-
-Simple Usage:
-
- >>> import markdown
- >>> print markdown.markdown('Text with double__underscore__words.',
- ... extensions=['smart_strong'])
- <p>Text with double__underscore__words.</p>
- >>> print markdown.markdown('__Strong__ still works.',
- ... extensions=['smart_strong'])
- <p><strong>Strong</strong> still works.</p>
- >>> print markdown.markdown('__this__works__too__.',
- ... extensions=['smart_strong'])
- <p><strong>this__works__too</strong>.</p>
-
-Copyright 2011
-[Waylan Limberg](http://achinghead.com)
-
-'''
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import Extension
-from ..inlinepatterns import SimpleTagPattern
-
-SMART_STRONG_RE = r'(?<!\w)(_{2})(?!_)(.+?)(?<!_)\2(?!\w)'
-STRONG_RE = r'(\*{2})(.+?)\2'
-
-class SmartEmphasisExtension(Extension):
- """ Add smart_emphasis extension to Markdown class."""
-
- def extendMarkdown(self, md, md_globals):
- """ Modify inline patterns. """
- md.inlinePatterns['strong'] = SimpleTagPattern(STRONG_RE, 'strong')
- md.inlinePatterns.add('strong2', SimpleTagPattern(SMART_STRONG_RE, 'strong'), '>emphasis2')
-
-def makeExtension(configs={}):
- return SmartEmphasisExtension(configs=dict(configs))
diff --git a/third_party/markdown/extensions/tables.py b/third_party/markdown/extensions/tables.py
deleted file mode 100644
index ad52ec1..0000000
--- a/third_party/markdown/extensions/tables.py
+++ /dev/null
@@ -1,100 +0,0 @@
-"""
-Tables Extension for Python-Markdown
-====================================
-
-Added parsing of tables to Python-Markdown.
-
-A simple example:
-
- First Header | Second Header
- ------------- | -------------
- Content Cell | Content Cell
- Content Cell | Content Cell
-
-Copyright 2009 - [Waylan Limberg](http://achinghead.com)
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import Extension
-from ..blockprocessors import BlockProcessor
-from ..util import etree
-
-class TableProcessor(BlockProcessor):
- """ Process Tables. """
-
- def test(self, parent, block):
- rows = block.split('\n')
- return (len(rows) > 2 and '|' in rows[0] and
- '|' in rows[1] and '-' in rows[1] and
- rows[1].strip()[0] in ['|', ':', '-'])
-
- def run(self, parent, blocks):
- """ Parse a table block and build table. """
- block = blocks.pop(0).split('\n')
- header = block[0].strip()
- seperator = block[1].strip()
- rows = block[2:]
- # Get format type (bordered by pipes or not)
- border = False
- if header.startswith('|'):
- border = True
- # Get alignment of columns
- align = []
- for c in self._split_row(seperator, border):
- if c.startswith(':') and c.endswith(':'):
- align.append('center')
- elif c.startswith(':'):
- align.append('left')
- elif c.endswith(':'):
- align.append('right')
- else:
- align.append(None)
- # Build table
- table = etree.SubElement(parent, 'table')
- thead = etree.SubElement(table, 'thead')
- self._build_row(header, thead, align, border)
- tbody = etree.SubElement(table, 'tbody')
- for row in rows:
- self._build_row(row.strip(), tbody, align, border)
-
- def _build_row(self, row, parent, align, border):
- """ Given a row of text, build table cells. """
- tr = etree.SubElement(parent, 'tr')
- tag = 'td'
- if parent.tag == 'thead':
- tag = 'th'
- cells = self._split_row(row, border)
- # We use align here rather than cells to ensure every row
- # contains the same number of columns.
- for i, a in enumerate(align):
- c = etree.SubElement(tr, tag)
- try:
- c.text = cells[i].strip()
- except IndexError:
- c.text = ""
- if a:
- c.set('align', a)
-
- def _split_row(self, row, border):
- """ split a row of text into list of cells. """
- if border:
- if row.startswith('|'):
- row = row[1:]
- if row.endswith('|'):
- row = row[:-1]
- return row.split('|')
-
-
-class TableExtension(Extension):
- """ Add tables to Markdown. """
-
- def extendMarkdown(self, md, md_globals):
- """ Add an instance of TableProcessor to BlockParser. """
- md.parser.blockprocessors.add('table',
- TableProcessor(md.parser),
- '<hashheader')
-
-
-def makeExtension(configs={}):
- return TableExtension(configs=configs)
diff --git a/third_party/markdown/extensions/toc.py b/third_party/markdown/extensions/toc.py
deleted file mode 100644
index 73b0844..0000000
--- a/third_party/markdown/extensions/toc.py
+++ /dev/null
@@ -1,221 +0,0 @@
-"""
-Table of Contents Extension for Python-Markdown
-* * *
-
-(c) 2008 [Jack Miller](http://codezen.org)
-
-Dependencies:
-* [Markdown 2.1+](http://packages.python.org/Markdown/)
-
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import Extension
-from ..treeprocessors import Treeprocessor
-from ..util import etree
-from .headerid import slugify, unique, itertext
-import re
-
-
-def order_toc_list(toc_list):
- """Given an unsorted list with errors and skips, return a nested one.
- [{'level': 1}, {'level': 2}]
- =>
- [{'level': 1, 'children': [{'level': 2, 'children': []}]}]
-
- A wrong list is also converted:
- [{'level': 2}, {'level': 1}]
- =>
- [{'level': 2, 'children': []}, {'level': 1, 'children': []}]
- """
-
- def build_correct(remaining_list, prev_elements=[{'level': 1000}]):
-
- if not remaining_list:
- return [], []
-
- current = remaining_list.pop(0)
- if not 'children' in current.keys():
- current['children'] = []
-
- if not prev_elements:
- # This happens for instance with [8, 1, 1], ie. when some
- # header level is outside a scope. We treat it as a
- # top-level
- next_elements, children = build_correct(remaining_list, [current])
- current['children'].append(children)
- return [current] + next_elements, []
-
- prev_element = prev_elements.pop()
- children = []
- next_elements = []
- # Is current part of the child list or next list?
- if current['level'] > prev_element['level']:
- #print "%d is a child of %d" % (current['level'], prev_element['level'])
- prev_elements.append(prev_element)
- prev_elements.append(current)
- prev_element['children'].append(current)
- next_elements2, children2 = build_correct(remaining_list, prev_elements)
- children += children2
- next_elements += next_elements2
- else:
- #print "%d is ancestor of %d" % (current['level'], prev_element['level'])
- if not prev_elements:
- #print "No previous elements, so appending to the next set"
- next_elements.append(current)
- prev_elements = [current]
- next_elements2, children2 = build_correct(remaining_list, prev_elements)
- current['children'].extend(children2)
- else:
- #print "Previous elements, comparing to those first"
- remaining_list.insert(0, current)
- next_elements2, children2 = build_correct(remaining_list, prev_elements)
- children.extend(children2)
- next_elements += next_elements2
-
- return next_elements, children
-
- ordered_list, __ = build_correct(toc_list)
- return ordered_list
-
-
-class TocTreeprocessor(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 add_anchor(self, c, elem_id): #@ReservedAssignment
- if self.use_anchors:
- anchor = etree.Element("a")
- anchor.text = c.text
- anchor.attrib["href"] = "#" + elem_id
- anchor.attrib["class"] = "toclink"
- c.text = ""
- for elem in c.getchildren():
- anchor.append(elem)
- c.remove(elem)
- c.append(anchor)
-
- def build_toc_etree(self, div, toc_list):
- # Add title to the div
- if self.config["title"]:
- header = etree.SubElement(div, "span")
- header.attrib["class"] = "toctitle"
- header.text = self.config["title"]
-
- def build_etree_ul(toc_list, parent):
- ul = etree.SubElement(parent, "ul")
- for item in toc_list:
- # List item link, to be inserted into the toc div
- li = etree.SubElement(ul, "li")
- link = etree.SubElement(li, "a")
- link.text = item.get('name', '')
- link.attrib["href"] = '#' + item.get('id', '')
- if item['children']:
- build_etree_ul(item['children'], li)
- return ul
-
- return build_etree_ul(toc_list, div)
-
- def run(self, doc):
-
- div = etree.Element("div")
- div.attrib["class"] = "toc"
- header_rgx = re.compile("[Hh][123456]")
-
- self.use_anchors = self.config["anchorlink"] in [1, '1', True, 'True', 'true']
-
- # Get a list of id attributes
- used_ids = set()
- for c in doc.getiterator():
- if "id" in c.attrib:
- used_ids.add(c.attrib["id"])
-
- toc_list = []
- marker_found = False
- for (p, c) in self.iterparent(doc):
- text = ''.join(itertext(c)).strip()
- if not 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.
- # We do not allow the marker inside a header as that
- # would causes an enless loop of placing a new TOC
- # inside previously generated TOC.
- if c.text and c.text.strip() == self.config["marker"] and \
- not header_rgx.match(c.tag) and c.tag not in ['pre', 'code']:
- for i in range(len(p)):
- if p[i] == c:
- p[i] = div
- break
- marker_found = True
-
- if header_rgx.match(c.tag):
-
- # Do not override pre-existing ids
- if not "id" in c.attrib:
- elem_id = unique(self.config["slugify"](text, '-'), used_ids)
- c.attrib["id"] = elem_id
- else:
- elem_id = c.attrib["id"]
-
- tag_level = int(c.tag[-1])
-
- toc_list.append({'level': tag_level,
- 'id': elem_id,
- 'name': text})
-
- self.add_anchor(c, elem_id)
-
- toc_list_nested = order_toc_list(toc_list)
- self.build_toc_etree(div, toc_list_nested)
- prettify = self.markdown.treeprocessors.get('prettify')
- if prettify: prettify.run(div)
- if not marker_found:
- # serialize and attach to markdown instance.
- toc = self.markdown.serializer(div)
- for pp in self.markdown.postprocessors.values():
- toc = pp.run(toc)
- self.markdown.toc = toc
-
-
-class TocExtension(Extension):
-
- TreeProcessorClass = TocTreeprocessor
-
- def __init__(self, configs=[]):
- self.config = { "marker" : ["[TOC]",
- "Text to find and replace with Table of Contents -"
- "Defaults to \"[TOC]\""],
- "slugify" : [slugify,
- "Function to generate anchors based on header text-"
- "Defaults to the headerid ext's 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)
-
- def extendMarkdown(self, md, md_globals):
- tocext = self.TreeProcessorClass(md)
- tocext.config = self.getConfigs()
- # Headerid ext is set to '>prettify'. With this set to '_end',
- # it should always come after headerid ext (and honor ids assinged
- # by the header id extension) if both are used. Same goes for
- # attr_list extension. This must come last because we don't want
- # to redefine ids after toc is created. But we do want toc prettified.
- md.treeprocessors.add("toc", tocext, "_end")
-
-
-def makeExtension(configs={}):
- return TocExtension(configs=configs)
diff --git a/third_party/markdown/extensions/wikilinks.py b/third_party/markdown/extensions/wikilinks.py
deleted file mode 100644
index 877890b..0000000
--- a/third_party/markdown/extensions/wikilinks.py
+++ /dev/null
@@ -1,151 +0,0 @@
-'''
-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'])
- >>> print html
- <p>Some text with a <a class="wikilink" href="/WikiLink/">WikiLink</a>.</p>
-
-Whitespace behavior:
-
- >>> print markdown.markdown('[[ foo bar_baz ]]', ['wikilinks'])
- <p><a class="wikilink" href="/foo_bar_baz/">foo bar_baz</a></p>
- >>> print markdown.markdown('foo [[ ]] bar', ['wikilinks'])
- <p>foo bar</p>
-
-To define custom settings the simple way:
-
- >>> print markdown.markdown(text,
- ... ['wikilinks(base_url=/wiki/,end_url=.html,html_class=foo)']
- ... )
- <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)
- >>> print md.convert(text)
- <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'])
- >>> print md.convert(text)
- <p>Some text with a <a href="http://example.com/WikiLink.html">WikiLink</a>.</p>
-
-MetaData should not carry over to next document:
-
- >>> print md.convert("No [[MetaData]] here.")
- <p>No <a class="wikilink" href="/MetaData/">MetaData</a> here.</p>
-
-Define a custom URL builder:
-
- >>> def my_url_builder(label, base, end):
- ... return '/bar/'
- >>> md = markdown.Markdown(extensions=['wikilinks'],
- ... extension_configs={'wikilinks' : [('build_url', my_url_builder)]})
- >>> print md.convert('[[foo]]')
- <p><a class="wikilink" href="/bar/">foo</a></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://packages.python.org/Markdown/)
-'''
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import Extension
-from ..inlinepatterns import Pattern
-from ..util import etree
-import re
-
-def build_url(label, base, end):
- """ Build a url from the label, a base, and an end. """
- clean_label = re.sub(r'([ ]+_)|(_[ ]+)|([ ]+)', '_', label)
- return '%s%s%s'% (base, clean_label, end)
-
-
-class WikiLinkExtension(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.'],
- 'build_url' : [build_url, 'Callable formats URL from label.'],
- }
-
- # 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'\[\[([\w0-9_ -]+)\]\]'
- wikilinkPattern = WikiLinks(WIKILINK_RE, self.getConfigs())
- wikilinkPattern.md = md
- md.inlinePatterns.add('wikilink', wikilinkPattern, "<not_strong")
-
-
-class WikiLinks(Pattern):
- def __init__(self, pattern, config):
- super(WikiLinks, self).__init__(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 = self.config['build_url'](label, base_url, end_url)
- a = etree.Element('a')
- a.text = 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']
- end_url = self.config['end_url']
- html_class = self.config['html_class']
- if hasattr(self.md, 'Meta'):
- if 'wiki_base_url' in self.md.Meta:
- base_url = self.md.Meta['wiki_base_url'][0]
- if 'wiki_end_url' in self.md.Meta:
- end_url = self.md.Meta['wiki_end_url'][0]
- if 'wiki_html_class' in self.md.Meta:
- html_class = self.md.Meta['wiki_html_class'][0]
- return base_url, end_url, html_class
-
-
-def makeExtension(configs=None) :
- return WikiLinkExtension(configs=configs)
diff --git a/third_party/markdown/inlinepatterns.py b/third_party/markdown/inlinepatterns.py
deleted file mode 100644
index de957ef..0000000
--- a/third_party/markdown/inlinepatterns.py
+++ /dev/null
@@ -1,483 +0,0 @@
-"""
-INLINE PATTERNS
-=============================================================================
-
-Inline patterns such as *emphasis* are handled by means of auxiliary
-objects, one per pattern. Pattern objects must be instances of classes
-that extend markdown.Pattern. Each pattern object uses a single regular
-expression and needs support the following methods:
-
- pattern.getCompiledRegExp() # returns a regular expression
-
- pattern.handleMatch(m) # takes a match object and returns
- # an ElementTree element or just plain text
-
-All of python markdown's built-in patterns subclass from Pattern,
-but you can add additional patterns that don't.
-
-Also note that all the regular expressions used by inline must
-capture the whole block. For this reason, they all start with
-'^(.*)' and end with '(.*)!'. In case with built-in expression
-Pattern takes care of adding the "^(.*)" and "(.*)!".
-
-Finally, the order in which regular expressions are applied is very
-important - e.g. if we first replace http://.../ links with <a> tags
-and _then_ try to replace inline html, we would end up with a mess.
-So, we apply the expressions in the following order:
-
-* escape and backticks have to go before everything else, so
- that we can preempt any markdown patterns by escaping them.
-
-* then we handle auto-links (must be done before inline html)
-
-* then we handle inline HTML. At this point we will simply
- replace all inline HTML strings with a placeholder and add
- the actual HTML to a hash.
-
-* then inline images (must be done before links)
-
-* then bracketed links, first regular then reference-style
-
-* finally we apply strong and emphasis
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import util
-from . import odict
-import re
-try:
- from urllib.parse import urlparse, urlunparse
-except ImportError:
- from urlparse import urlparse, urlunparse
-try:
- from html import entities
-except ImportError:
- import htmlentitydefs as entities
-
-
-def build_inlinepatterns(md_instance, **kwargs):
- """ Build the default set of inline patterns for Markdown. """
- inlinePatterns = odict.OrderedDict()
- inlinePatterns["backtick"] = BacktickPattern(BACKTICK_RE)
- inlinePatterns["escape"] = EscapePattern(ESCAPE_RE, md_instance)
- inlinePatterns["reference"] = ReferencePattern(REFERENCE_RE, md_instance)
- inlinePatterns["link"] = LinkPattern(LINK_RE, md_instance)
- inlinePatterns["image_link"] = ImagePattern(IMAGE_LINK_RE, md_instance)
- inlinePatterns["image_reference"] = \
- ImageReferencePattern(IMAGE_REFERENCE_RE, md_instance)
- inlinePatterns["short_reference"] = \
- ReferencePattern(SHORT_REF_RE, md_instance)
- inlinePatterns["autolink"] = AutolinkPattern(AUTOLINK_RE, md_instance)
- inlinePatterns["automail"] = AutomailPattern(AUTOMAIL_RE, md_instance)
- inlinePatterns["linebreak"] = SubstituteTagPattern(LINE_BREAK_RE, 'br')
- if md_instance.safeMode != 'escape':
- inlinePatterns["html"] = HtmlPattern(HTML_RE, md_instance)
- inlinePatterns["entity"] = HtmlPattern(ENTITY_RE, md_instance)
- inlinePatterns["not_strong"] = SimpleTextPattern(NOT_STRONG_RE)
- inlinePatterns["strong_em"] = DoubleTagPattern(STRONG_EM_RE, 'strong,em')
- inlinePatterns["strong"] = SimpleTagPattern(STRONG_RE, 'strong')
- inlinePatterns["emphasis"] = SimpleTagPattern(EMPHASIS_RE, 'em')
- if md_instance.smart_emphasis:
- inlinePatterns["emphasis2"] = SimpleTagPattern(SMART_EMPHASIS_RE, 'em')
- else:
- inlinePatterns["emphasis2"] = SimpleTagPattern(EMPHASIS_2_RE, 'em')
- return inlinePatterns
-
-"""
-The actual regular expressions for patterns
------------------------------------------------------------------------------
-"""
-
-NOBRACKET = r'[^\]\[]*'
-BRK = ( r'\[('
- + (NOBRACKET + r'(\[')*6
- + (NOBRACKET+ r'\])*')*6
- + NOBRACKET + r')\]' )
-NOIMG = r'(?<!\!)'
-
-BACKTICK_RE = r'(?<!\\)(`+)(.+?)(?<!`)\2(?!`)' # `e=f()` or ``e=f("`")``
-ESCAPE_RE = r'\\(.)' # \<
-EMPHASIS_RE = r'(\*)([^\*]+)\2' # *emphasis*
-STRONG_RE = r'(\*{2}|_{2})(.+?)\2' # **strong**
-STRONG_EM_RE = r'(\*{3}|_{3})(.+?)\2' # ***strong***
-SMART_EMPHASIS_RE = r'(?<!\w)(_)(?!_)(.+?)(?<!_)\2(?!\w)' # _smart_emphasis_
-EMPHASIS_2_RE = r'(_)(.+?)\2' # _emphasis_
-LINK_RE = NOIMG + BRK + \
-r'''\(\s*(<.*?>|((?:(?:\(.*?\))|[^\(\)]))*?)\s*((['"])(.*?)\12\s*)?\)'''
-# [text](url) or [text](<url>) or [text](url "title")
-
-IMAGE_LINK_RE = r'\!' + BRK + r'\s*\((<.*?>|([^\)]*))\)'
-# ![alttxt](http://x.com/) or ![alttxt](<http://x.com/>)
-REFERENCE_RE = NOIMG + BRK+ r'\s?\[([^\]]*)\]' # [Google][3]
-SHORT_REF_RE = NOIMG + r'\[([^\]]+)\]' # [Google]
-IMAGE_REFERENCE_RE = r'\!' + BRK + '\s?\[([^\]]*)\]' # ![alt text][2]
-NOT_STRONG_RE = r'((^| )(\*|_)( |$))' # stand-alone * or _
-AUTOLINK_RE = r'<((?:[Ff]|[Hh][Tt])[Tt][Pp][Ss]?://[^>]*)>' # <http://www.123.com>
-AUTOMAIL_RE = r'<([^> \!]*@[^> ]*)>' # <me@example.com>
-
-HTML_RE = r'(\<([a-zA-Z/][^\>]*?|\!--.*?--)\>)' # <...>
-ENTITY_RE = r'(&[\#a-zA-Z0-9]*;)' # &amp;
-LINE_BREAK_RE = r' \n' # two spaces at end of line
-
-
-def dequote(string):
- """Remove quotes from around a string."""
- if ( ( string.startswith('"') and string.endswith('"'))
- or (string.startswith("'") and string.endswith("'")) ):
- return string[1:-1]
- else:
- return string
-
-ATTR_RE = re.compile("\{@([^\}]*)=([^\}]*)}") # {@id=123}
-
-def handleAttributes(text, parent):
- """Set values of an element based on attribute definitions ({@id=123})."""
- def attributeCallback(match):
- parent.set(match.group(1), match.group(2).replace('\n', ' '))
- return ATTR_RE.sub(attributeCallback, text)
-
-
-"""
-The pattern classes
------------------------------------------------------------------------------
-"""
-
-class Pattern(object):
- """Base class that inline patterns subclass. """
-
- def __init__(self, pattern, markdown_instance=None):
- """
- Create an instant of an inline pattern.
-
- Keyword arguments:
-
- * pattern: A regular expression that matches a pattern
-
- """
- self.pattern = pattern
- self.compiled_re = re.compile("^(.*?)%s(.*?)$" % pattern,
- re.DOTALL | re.UNICODE)
-
- # Api for Markdown to pass safe_mode into instance
- self.safe_mode = False
- if markdown_instance:
- self.markdown = markdown_instance
-
- def getCompiledRegExp(self):
- """ Return a compiled regular expression. """
- return self.compiled_re
-
- def handleMatch(self, m):
- """Return a ElementTree element from the given match.
-
- Subclasses should override this method.
-
- Keyword arguments:
-
- * m: A re match object containing a match of the pattern.
-
- """
- pass
-
- def type(self):
- """ Return class name, to define pattern type """
- return self.__class__.__name__
-
- def unescape(self, text):
- """ Return unescaped text given text with an inline placeholder. """
- try:
- stash = self.markdown.treeprocessors['inline'].stashed_nodes
- except KeyError:
- return text
- def itertext(el):
- ' Reimplement Element.itertext for older python versions '
- tag = el.tag
- if not isinstance(tag, util.string_type) and tag is not None:
- return
- if el.text:
- yield el.text
- for e in el:
- for s in itertext(e):
- yield s
- if e.tail:
- yield e.tail
- def get_stash(m):
- id = m.group(1)
- if id in stash:
- value = stash.get(id)
- if isinstance(value, util.string_type):
- return value
- else:
- # An etree Element - return text content only
- return ''.join(itertext(value))
- return util.INLINE_PLACEHOLDER_RE.sub(get_stash, text)
-
-
-class SimpleTextPattern(Pattern):
- """ Return a simple text of group(2) of a Pattern. """
- def handleMatch(self, m):
- text = m.group(2)
- if text == util.INLINE_PLACEHOLDER_PREFIX:
- return None
- return text
-
-
-class EscapePattern(Pattern):
- """ Return an escaped character. """
-
- def handleMatch(self, m):
- char = m.group(2)
- if char in self.markdown.ESCAPED_CHARS:
- return '%s%s%s' % (util.STX, ord(char), util.ETX)
- else:
- return '\\%s' % char
-
-
-class SimpleTagPattern(Pattern):
- """
- Return element of type `tag` with a text attribute of group(3)
- of a Pattern.
-
- """
- def __init__ (self, pattern, tag):
- Pattern.__init__(self, pattern)
- self.tag = tag
-
- def handleMatch(self, m):
- el = util.etree.Element(self.tag)
- el.text = m.group(3)
- return el
-
-
-class SubstituteTagPattern(SimpleTagPattern):
- """ Return an element of type `tag` with no children. """
- def handleMatch (self, m):
- return util.etree.Element(self.tag)
-
-
-class BacktickPattern(Pattern):
- """ Return a `<code>` element containing the matching text. """
- def __init__ (self, pattern):
- Pattern.__init__(self, pattern)
- self.tag = "code"
-
- def handleMatch(self, m):
- el = util.etree.Element(self.tag)
- el.text = util.AtomicString(m.group(3).strip())
- return el
-
-
-class DoubleTagPattern(SimpleTagPattern):
- """Return a ElementTree element nested in tag2 nested in tag1.
-
- Useful for strong emphasis etc.
-
- """
- def handleMatch(self, m):
- tag1, tag2 = self.tag.split(",")
- el1 = util.etree.Element(tag1)
- el2 = util.etree.SubElement(el1, tag2)
- el2.text = m.group(3)
- return el1
-
-
-class HtmlPattern(Pattern):
- """ Store raw inline html and return a placeholder. """
- def handleMatch (self, m):
- rawhtml = self.unescape(m.group(2))
- place_holder = self.markdown.htmlStash.store(rawhtml)
- return place_holder
-
- def unescape(self, text):
- """ Return unescaped text given text with an inline placeholder. """
- try:
- stash = self.markdown.treeprocessors['inline'].stashed_nodes
- except KeyError:
- return text
- def get_stash(m):
- id = m.group(1)
- value = stash.get(id)
- if value is not None:
- try:
- return self.markdown.serializer(value)
- except:
- return '\%s' % value
-
- return util.INLINE_PLACEHOLDER_RE.sub(get_stash, text)
-
-
-class LinkPattern(Pattern):
- """ Return a link element from the given match. """
- def handleMatch(self, m):
- el = util.etree.Element("a")
- el.text = m.group(2)
- title = m.group(13)
- href = m.group(9)
-
- if href:
- if href[0] == "<":
- href = href[1:-1]
- el.set("href", self.sanitize_url(self.unescape(href.strip())))
- else:
- el.set("href", "")
-
- if title:
- title = dequote(self.unescape(title))
- el.set("title", title)
- return el
-
- def sanitize_url(self, url):
- """
- Sanitize a url against xss attacks in "safe_mode".
-
- Rather than specifically blacklisting `javascript:alert("XSS")` and all
- its aliases (see <http://ha.ckers.org/xss.html>), we whitelist known
- safe url formats. Most urls contain a network location, however some
- are known not to (i.e.: mailto links). Script urls do not contain a
- location. Additionally, for `javascript:...`, the scheme would be
- "javascript" but some aliases will appear to `urlparse()` to have no
- scheme. On top of that relative links (i.e.: "foo/bar.html") have no
- scheme. Therefore we must check "path", "parameters", "query" and
- "fragment" for any literal colons. We don't check "scheme" for colons
- because it *should* never have any and "netloc" must allow the form:
- `username:password@host:port`.
-
- """
- url = url.replace(' ', '%20')
- if not self.markdown.safeMode:
- # Return immediately bipassing parsing.
- return url
-
- try:
- scheme, netloc, path, params, query, fragment = url = urlparse(url)
- except ValueError:
- # Bad url - so bad it couldn't be parsed.
- return ''
-
- locless_schemes = ['', 'mailto', 'news']
- allowed_schemes = locless_schemes + ['http', 'https', 'ftp', 'ftps']
- if scheme not in allowed_schemes:
- # Not a known (allowed) scheme. Not safe.
- return ''
-
- if netloc == '' and scheme not in locless_schemes:
- # This should not happen. Treat as suspect.
- return ''
-
- for part in url[2:]:
- if ":" in part:
- # A colon in "path", "parameters", "query" or "fragment" is suspect.
- return ''
-
- # Url passes all tests. Return url as-is.
- return urlunparse(url)
-
-class ImagePattern(LinkPattern):
- """ Return a img element from the given match. """
- def handleMatch(self, m):
- el = util.etree.Element("img")
- src_parts = m.group(9).split()
- if src_parts:
- src = src_parts[0]
- if src[0] == "<" and src[-1] == ">":
- src = src[1:-1]
- el.set('src', self.sanitize_url(self.unescape(src)))
- else:
- el.set('src', "")
- if len(src_parts) > 1:
- el.set('title', dequote(self.unescape(" ".join(src_parts[1:]))))
-
- if self.markdown.enable_attributes:
- truealt = handleAttributes(m.group(2), el)
- else:
- truealt = m.group(2)
-
- el.set('alt', self.unescape(truealt))
- return el
-
-class ReferencePattern(LinkPattern):
- """ Match to a stored reference and return link element. """
-
- NEWLINE_CLEANUP_RE = re.compile(r'[ ]?\n', re.MULTILINE)
-
- def handleMatch(self, m):
- try:
- id = m.group(9).lower()
- except IndexError:
- id = None
- if not id:
- # if we got something like "[Google][]" or "[Goggle]"
- # we'll use "google" as the id
- id = m.group(2).lower()
-
- # Clean up linebreaks in id
- id = self.NEWLINE_CLEANUP_RE.sub(' ', id)
- if not id in self.markdown.references: # ignore undefined refs
- return None
- href, title = self.markdown.references[id]
-
- text = m.group(2)
- return self.makeTag(href, title, text)
-
- def makeTag(self, href, title, text):
- el = util.etree.Element('a')
-
- el.set('href', self.sanitize_url(href))
- if title:
- el.set('title', title)
-
- el.text = text
- return el
-
-
-class ImageReferencePattern(ReferencePattern):
- """ Match to a stored reference and return img element. """
- def makeTag(self, href, title, text):
- el = util.etree.Element("img")
- el.set("src", self.sanitize_url(href))
- if title:
- el.set("title", title)
-
- if self.markdown.enable_attributes:
- text = handleAttributes(text, el)
-
- el.set("alt", self.unescape(text))
- return el
-
-
-class AutolinkPattern(Pattern):
- """ Return a link Element given an autolink (`<http://example/com>`). """
- def handleMatch(self, m):
- el = util.etree.Element("a")
- el.set('href', self.unescape(m.group(2)))
- el.text = util.AtomicString(m.group(2))
- return el
-
-class AutomailPattern(Pattern):
- """
- Return a mailto link Element given an automail link (`<foo@example.com>`).
- """
- def handleMatch(self, m):
- el = util.etree.Element('a')
- email = self.unescape(m.group(2))
- if email.startswith("mailto:"):
- email = email[len("mailto:"):]
-
- def codepoint2name(code):
- """Return entity definition by code, or the code if not defined."""
- entity = entities.codepoint2name.get(code)
- if entity:
- return "%s%s;" % (util.AMP_SUBSTITUTE, entity)
- else:
- return "%s#%d;" % (util.AMP_SUBSTITUTE, code)
-
- letters = [codepoint2name(ord(letter)) for letter in email]
- el.text = util.AtomicString(''.join(letters))
-
- mailto = "mailto:" + email
- mailto = "".join([util.AMP_SUBSTITUTE + '#%d;' %
- ord(letter) for letter in mailto])
- el.set('href', mailto)
- return el
-
diff --git a/third_party/markdown/odict.py b/third_party/markdown/odict.py
deleted file mode 100644
index 8089ece..0000000
--- a/third_party/markdown/odict.py
+++ /dev/null
@@ -1,194 +0,0 @@
-from __future__ import unicode_literals
-from __future__ import absolute_import
-from . import util
-
-from copy import deepcopy
-
-def iteritems_compat(d):
- """Return an iterator over the (key, value) pairs of a dictionary.
- Copied from `six` module."""
- return iter(getattr(d, _iteritems)())
-
-class OrderedDict(dict):
- """
- A dictionary that keeps its keys in the order in which they're inserted.
-
- Copied from Django's SortedDict with some modifications.
-
- """
- def __new__(cls, *args, **kwargs):
- instance = super(OrderedDict, cls).__new__(cls, *args, **kwargs)
- instance.keyOrder = []
- return instance
-
- def __init__(self, data=None):
- if data is None or isinstance(data, dict):
- data = data or []
- super(OrderedDict, self).__init__(data)
- self.keyOrder = list(data) if data else []
- else:
- super(OrderedDict, self).__init__()
- super_set = super(OrderedDict, self).__setitem__
- for key, value in data:
- # Take the ordering from first key
- if key not in self:
- self.keyOrder.append(key)
- # But override with last value in data (dict() does this)
- super_set(key, value)
-
- def __deepcopy__(self, memo):
- return self.__class__([(key, deepcopy(value, memo))
- for key, value in self.items()])
-
- def __copy__(self):
- # The Python's default copy implementation will alter the state
- # of self. The reason for this seems complex but is likely related to
- # subclassing dict.
- return self.copy()
-
- def __setitem__(self, key, value):
- if key not in self:
- self.keyOrder.append(key)
- super(OrderedDict, self).__setitem__(key, value)
-
- def __delitem__(self, key):
- super(OrderedDict, self).__delitem__(key)
- self.keyOrder.remove(key)
-
- def __iter__(self):
- return iter(self.keyOrder)
-
- def __reversed__(self):
- return reversed(self.keyOrder)
-
- def pop(self, k, *args):
- result = super(OrderedDict, self).pop(k, *args)
- try:
- self.keyOrder.remove(k)
- except ValueError:
- # Key wasn't in the dictionary in the first place. No problem.
- pass
- return result
-
- def popitem(self):
- result = super(OrderedDict, self).popitem()
- self.keyOrder.remove(result[0])
- return result
-
- def _iteritems(self):
- for key in self.keyOrder:
- yield key, self[key]
-
- def _iterkeys(self):
- for key in self.keyOrder:
- yield key
-
- def _itervalues(self):
- for key in self.keyOrder:
- yield self[key]
-
- if util.PY3:
- items = _iteritems
- keys = _iterkeys
- values = _itervalues
- else:
- iteritems = _iteritems
- iterkeys = _iterkeys
- itervalues = _itervalues
-
- def items(self):
- return [(k, self[k]) for k in self.keyOrder]
-
- def keys(self):
- return self.keyOrder[:]
-
- def values(self):
- return [self[k] for k in self.keyOrder]
-
- def update(self, dict_):
- for k, v in iteritems_compat(dict_):
- self[k] = v
-
- def setdefault(self, key, default):
- if key not in self:
- self.keyOrder.append(key)
- return super(OrderedDict, self).setdefault(key, default)
-
- def value_for_index(self, index):
- """Returns the value of the item at the given zero-based index."""
- return self[self.keyOrder[index]]
-
- def insert(self, index, key, value):
- """Inserts the key, value pair before the item with the given index."""
- if key in self.keyOrder:
- n = self.keyOrder.index(key)
- del self.keyOrder[n]
- if n < index:
- index -= 1
- self.keyOrder.insert(index, key)
- super(OrderedDict, self).__setitem__(key, value)
-
- def copy(self):
- """Returns a copy of this object."""
- # This way of initializing the copy means it works for subclasses, too.
- return self.__class__(self)
-
- def __repr__(self):
- """
- Replaces the normal dict.__repr__ with a version that returns the keys
- in their Ordered order.
- """
- return '{%s}' % ', '.join(['%r: %r' % (k, v) for k, v in iteritems_compat(self)])
-
- def clear(self):
- super(OrderedDict, self).clear()
- self.keyOrder = []
-
- def index(self, key):
- """ Return the index of a given key. """
- try:
- return self.keyOrder.index(key)
- except ValueError:
- raise ValueError("Element '%s' was not found in OrderedDict" % key)
-
- def index_for_location(self, location):
- """ Return index or None for a given location. """
- if location == '_begin':
- i = 0
- elif location == '_end':
- i = None
- elif location.startswith('<') or location.startswith('>'):
- i = self.index(location[1:])
- if location.startswith('>'):
- if i >= len(self):
- # last item
- i = None
- else:
- i += 1
- else:
- raise ValueError('Not a valid location: "%s". Location key '
- 'must start with a ">" or "<".' % location)
- return i
-
- def add(self, key, value, location):
- """ Insert by key location. """
- i = self.index_for_location(location)
- if i is not None:
- self.insert(i, key, value)
- else:
- self.__setitem__(key, value)
-
- def link(self, key, location):
- """ Change location of an existing item. """
- n = self.keyOrder.index(key)
- del self.keyOrder[n]
- try:
- i = self.index_for_location(location)
- if i is not None:
- self.keyOrder.insert(i, key)
- else:
- self.keyOrder.append(key)
- except Exception as e:
- # restore to prevent data loss and reraise
- self.keyOrder.insert(n, key)
- raise e
diff --git a/third_party/markdown/postprocessors.py b/third_party/markdown/postprocessors.py
deleted file mode 100644
index 5f3f032..0000000
--- a/third_party/markdown/postprocessors.py
+++ /dev/null
@@ -1,104 +0,0 @@
-"""
-POST-PROCESSORS
-=============================================================================
-
-Markdown also allows post-processors, which are similar to preprocessors in
-that they need to implement a "run" method. However, they are run after core
-processing.
-
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import util
-from . import odict
-import re
-
-
-def build_postprocessors(md_instance, **kwargs):
- """ Build the default postprocessors for Markdown. """
- postprocessors = odict.OrderedDict()
- postprocessors["raw_html"] = RawHtmlPostprocessor(md_instance)
- postprocessors["amp_substitute"] = AndSubstitutePostprocessor()
- postprocessors["unescape"] = UnescapePostprocessor()
- return postprocessors
-
-
-class Postprocessor(util.Processor):
- """
- Postprocessors are run after the ElementTree it converted back into text.
-
- Each Postprocessor implements a "run" method that takes a pointer to a
- text string, modifies it as necessary and returns a text string.
-
- Postprocessors must extend markdown.Postprocessor.
-
- """
-
- def run(self, text):
- """
- Subclasses of Postprocessor should implement a `run` method, which
- takes the html document as a single text string and returns a
- (possibly modified) string.
-
- """
- pass
-
-
-class RawHtmlPostprocessor(Postprocessor):
- """ Restore raw html to the document. """
-
- def run(self, text):
- """ Iterate over html stash and restore "safe" html. """
- for i in range(self.markdown.htmlStash.html_counter):
- html, safe = self.markdown.htmlStash.rawHtmlBlocks[i]
- if self.markdown.safeMode and not safe:
- if str(self.markdown.safeMode).lower() == 'escape':
- html = self.escape(html)
- elif str(self.markdown.safeMode).lower() == 'remove':
- html = ''
- else:
- html = self.markdown.html_replacement_text
- if self.isblocklevel(html) and (safe or not self.markdown.safeMode):
- text = text.replace("<p>%s</p>" %
- (self.markdown.htmlStash.get_placeholder(i)),
- html + "\n")
- text = text.replace(self.markdown.htmlStash.get_placeholder(i),
- html)
- return text
-
- def escape(self, html):
- """ Basic html escaping """
- html = html.replace('&', '&amp;')
- html = html.replace('<', '&lt;')
- html = html.replace('>', '&gt;')
- return html.replace('"', '&quot;')
-
- def isblocklevel(self, html):
- m = re.match(r'^\<\/?([^ >]+)', html)
- if m:
- if m.group(1)[0] in ('!', '?', '@', '%'):
- # Comment, php etc...
- return True
- return util.isBlockLevel(m.group(1))
- return False
-
-
-class AndSubstitutePostprocessor(Postprocessor):
- """ Restore valid entities """
-
- def run(self, text):
- text = text.replace(util.AMP_SUBSTITUTE, "&")
- return text
-
-
-class UnescapePostprocessor(Postprocessor):
- """ Restore escaped chars """
-
- RE = re.compile('%s(\d+)%s' % (util.STX, util.ETX))
-
- def unescape(self, m):
- return util.int2str(int(m.group(1)))
-
- def run(self, text):
- return self.RE.sub(self.unescape, text)
diff --git a/third_party/markdown/preprocessors.py b/third_party/markdown/preprocessors.py
deleted file mode 100644
index 72b2ed6..0000000
--- a/third_party/markdown/preprocessors.py
+++ /dev/null
@@ -1,298 +0,0 @@
-"""
-PRE-PROCESSORS
-=============================================================================
-
-Preprocessors work on source text before we start doing anything too
-complicated.
-"""
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import util
-from . import odict
-import re
-
-
-def build_preprocessors(md_instance, **kwargs):
- """ Build the default set of preprocessors used by Markdown. """
- preprocessors = odict.OrderedDict()
- preprocessors['normalize_whitespace'] = NormalizeWhitespace(md_instance)
- if md_instance.safeMode != 'escape':
- preprocessors["html_block"] = HtmlBlockPreprocessor(md_instance)
- preprocessors["reference"] = ReferencePreprocessor(md_instance)
- return preprocessors
-
-
-class Preprocessor(util.Processor):
- """
- Preprocessors are run after the text is broken into lines.
-
- Each preprocessor implements a "run" method that takes a pointer to a
- list of lines of the document, modifies it as necessary and returns
- either the same pointer or a pointer to a new list.
-
- Preprocessors must extend markdown.Preprocessor.
-
- """
- def run(self, lines):
- """
- Each subclass of Preprocessor should override the `run` method, which
- takes the document as a list of strings split by newlines and returns
- the (possibly modified) list of lines.
-
- """
- pass
-
-
-class NormalizeWhitespace(Preprocessor):
- """ Normalize whitespace for consistant parsing. """
-
- def run(self, lines):
- source = '\n'.join(lines)
- source = source.replace(util.STX, "").replace(util.ETX, "")
- source = source.replace("\r\n", "\n").replace("\r", "\n") + "\n\n"
- source = source.expandtabs(self.markdown.tab_length)
- source = re.sub(r'(?<=\n) +\n', '\n', source)
- return source.split('\n')
-
-
-class HtmlBlockPreprocessor(Preprocessor):
- """Remove html blocks from the text and store them for later retrieval."""
-
- right_tag_patterns = ["</%s>", "%s>"]
- attrs_pattern = r"""
- \s+(?P<attr>[^>"'/= ]+)=(?P<q>['"])(?P<value>.*?)(?P=q) # attr="value"
- | # OR
- \s+(?P<attr1>[^>"'/= ]+)=(?P<value1>[^> ]+) # attr=value
- | # OR
- \s+(?P<attr2>[^>"'/= ]+) # attr
- """
- left_tag_pattern = r'^\<(?P<tag>[^> ]+)(?P<attrs>(%s)*)\s*\/?\>?' % attrs_pattern
- attrs_re = re.compile(attrs_pattern, re.VERBOSE)
- left_tag_re = re.compile(left_tag_pattern, re.VERBOSE)
- markdown_in_raw = False
-
- def _get_left_tag(self, block):
- m = self.left_tag_re.match(block)
- if m:
- tag = m.group('tag')
- raw_attrs = m.group('attrs')
- attrs = {}
- if raw_attrs:
- for ma in self.attrs_re.finditer(raw_attrs):
- if ma.group('attr'):
- if ma.group('value'):
- attrs[ma.group('attr').strip()] = ma.group('value')
- else:
- attrs[ma.group('attr').strip()] = ""
- elif ma.group('attr1'):
- if ma.group('value1'):
- attrs[ma.group('attr1').strip()] = ma.group('value1')
- else:
- attrs[ma.group('attr1').strip()] = ""
- elif ma.group('attr2'):
- attrs[ma.group('attr2').strip()] = ""
- return tag, len(m.group(0)), attrs
- else:
- tag = block[1:].split(">", 1)[0].lower()
- return tag, len(tag)+2, {}
-
- def _recursive_tagfind(self, ltag, rtag, start_index, block):
- while 1:
- i = block.find(rtag, start_index)
- if i == -1:
- return -1
- j = block.find(ltag, start_index)
- # if no ltag, or rtag found before another ltag, return index
- if (j > i or j == -1):
- return i + len(rtag)
- # another ltag found before rtag, use end of ltag as starting
- # point and search again
- j = block.find('>', j)
- start_index = self._recursive_tagfind(ltag, rtag, j + 1, block)
- if start_index == -1:
- # HTML potentially malformed- ltag has no corresponding
- # rtag
- return -1
-
- def _get_right_tag(self, left_tag, left_index, block):
- for p in self.right_tag_patterns:
- tag = p % left_tag
- i = self._recursive_tagfind("<%s" % left_tag, tag, left_index, block)
- if i > 2:
- return tag.lstrip("<").rstrip(">"), i
- return block.rstrip()[-left_index:-1].lower(), len(block)
-
- def _equal_tags(self, left_tag, right_tag):
- if left_tag[0] in ['?', '@', '%']: # handle PHP, etc.
- return True
- if ("/" + left_tag) == right_tag:
- return True
- if (right_tag == "--" and left_tag == "--"):
- return True
- elif left_tag == right_tag[1:] \
- and right_tag[0] == "/":
- return True
- else:
- return False
-
- def _is_oneliner(self, tag):
- return (tag in ['hr', 'hr/'])
-
- def run(self, lines):
- text = "\n".join(lines)
- new_blocks = []
- text = text.rsplit("\n\n")
- items = []
- left_tag = ''
- right_tag = ''
- in_tag = False # flag
-
- while text:
- block = text[0]
- if block.startswith("\n"):
- block = block[1:]
- text = text[1:]
-
- if block.startswith("\n"):
- block = block[1:]
-
- if not in_tag:
- if block.startswith("<") and len(block.strip()) > 1:
-
- if block[1] == "!":
- # is a comment block
- left_tag, left_index, attrs = "--", 2, {}
- else:
- left_tag, left_index, attrs = self._get_left_tag(block)
- right_tag, data_index = self._get_right_tag(left_tag,
- left_index,
- block)
- # keep checking conditions below and maybe just append
-
- if data_index < len(block) \
- and (util.isBlockLevel(left_tag)
- or left_tag == '--'):
- text.insert(0, block[data_index:])
- block = block[:data_index]
-
- if not (util.isBlockLevel(left_tag) \
- or block[1] in ["!", "?", "@", "%"]):
- new_blocks.append(block)
- continue
-
- if self._is_oneliner(left_tag):
- new_blocks.append(block.strip())
- continue
-
- if block.rstrip().endswith(">") \
- and self._equal_tags(left_tag, right_tag):
- if self.markdown_in_raw and 'markdown' in attrs.keys():
- start = re.sub(r'\smarkdown(=[\'"]?[^> ]*[\'"]?)?',
- '', block[:left_index])
- end = block[-len(right_tag)-2:]
- block = block[left_index:-len(right_tag)-2]
- new_blocks.append(
- self.markdown.htmlStash.store(start))
- new_blocks.append(block)
- new_blocks.append(
- self.markdown.htmlStash.store(end))
- else:
- new_blocks.append(
- self.markdown.htmlStash.store(block.strip()))
- continue
- else:
- # if is block level tag and is not complete
-
- if util.isBlockLevel(left_tag) or left_tag == "--" \
- and not block.rstrip().endswith(">"):
- items.append(block.strip())
- in_tag = True
- else:
- new_blocks.append(
- self.markdown.htmlStash.store(block.strip()))
-
- continue
-
- new_blocks.append(block)
-
- else:
- items.append(block)
-
- right_tag, data_index = self._get_right_tag(left_tag, 0, block)
-
- if self._equal_tags(left_tag, right_tag):
- # if find closing tag
-
- if data_index < len(block):
- # we have more text after right_tag
- items[-1] = block[:data_index]
- text.insert(0, block[data_index:])
-
- in_tag = False
- if self.markdown_in_raw and 'markdown' in attrs.keys():
- start = re.sub(r'\smarkdown(=[\'"]?[^> ]*[\'"]?)?',
- '', items[0][:left_index])
- items[0] = items[0][left_index:]
- end = items[-1][-len(right_tag)-2:]
- items[-1] = items[-1][:-len(right_tag)-2]
- new_blocks.append(
- self.markdown.htmlStash.store(start))
- new_blocks.extend(items)
- new_blocks.append(
- self.markdown.htmlStash.store(end))
- else:
- new_blocks.append(
- self.markdown.htmlStash.store('\n\n'.join(items)))
- items = []
-
- if items:
- if self.markdown_in_raw and 'markdown' in attrs.keys():
- start = re.sub(r'\smarkdown(=[\'"]?[^> ]*[\'"]?)?',
- '', items[0][:left_index])
- items[0] = items[0][left_index:]
- end = items[-1][-len(right_tag)-2:]
- items[-1] = items[-1][:-len(right_tag)-2]
- new_blocks.append(
- self.markdown.htmlStash.store(start))
- new_blocks.extend(items)
- if end.strip():
- new_blocks.append(
- self.markdown.htmlStash.store(end))
- else:
- new_blocks.append(
- self.markdown.htmlStash.store('\n\n'.join(items)))
- #new_blocks.append(self.markdown.htmlStash.store('\n\n'.join(items)))
- new_blocks.append('\n')
-
- new_text = "\n\n".join(new_blocks)
- return new_text.split("\n")
-
-
-class ReferencePreprocessor(Preprocessor):
- """ Remove reference definitions from text and store for later use. """
-
- TITLE = r'[ ]*(\"(.*)\"|\'(.*)\'|\((.*)\))[ ]*'
- RE = re.compile(r'^[ ]{0,3}\[([^\]]*)\]:\s*([^ ]*)[ ]*(%s)?$' % TITLE, re.DOTALL)
- TITLE_RE = re.compile(r'^%s$' % TITLE)
-
- def run (self, lines):
- new_text = [];
- while lines:
- line = lines.pop(0)
- m = self.RE.match(line)
- if m:
- id = m.group(1).strip().lower()
- link = m.group(2).lstrip('<').rstrip('>')
- t = m.group(5) or m.group(6) or m.group(7)
- if not t:
- # Check next line for title
- tm = self.TITLE_RE.match(lines[0])
- if tm:
- lines.pop(0)
- t = tm.group(2) or tm.group(3) or tm.group(4)
- self.markdown.references[id] = (link, t)
- else:
- new_text.append(line)
-
- return new_text #+ "\n"
diff --git a/third_party/markdown/serializers.py b/third_party/markdown/serializers.py
deleted file mode 100644
index b19d61c..0000000
--- a/third_party/markdown/serializers.py
+++ /dev/null
@@ -1,277 +0,0 @@
-# markdown/searializers.py
-#
-# Add x/html serialization to Elementree
-# Taken from ElementTree 1.3 preview with slight modifications
-#
-# Copyright (c) 1999-2007 by Fredrik Lundh. All rights reserved.
-#
-# fredrik@pythonware.com
-# http://www.pythonware.com
-#
-# --------------------------------------------------------------------
-# The ElementTree toolkit is
-#
-# Copyright (c) 1999-2007 by Fredrik Lundh
-#
-# By obtaining, using, and/or copying this software and/or its
-# associated documentation, you agree that you have read, understood,
-# and will comply with the following terms and conditions:
-#
-# Permission to use, copy, modify, and distribute this software and
-# its associated documentation for any purpose and without fee is
-# hereby granted, provided that the above copyright notice appears in
-# all copies, and that both that copyright notice and this permission
-# notice appear in supporting documentation, and that the name of
-# Secret Labs AB or the author not be used in advertising or publicity
-# pertaining to distribution of the software without specific, written
-# prior permission.
-#
-# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
-# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
-# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
-# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
-# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
-# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
-# OF THIS SOFTWARE.
-# --------------------------------------------------------------------
-
-
-from __future__ import absolute_import
-from __future__ import unicode_literals
-from . import util
-ElementTree = util.etree.ElementTree
-QName = util.etree.QName
-if hasattr(util.etree, 'test_comment'):
- Comment = util.etree.test_comment
-else:
- Comment = util.etree.Comment
-PI = util.etree.PI
-ProcessingInstruction = util.etree.ProcessingInstruction
-
-__all__ = ['to_html_string', 'to_xhtml_string']
-
-HTML_EMPTY = ("area", "base", "basefont", "br", "col", "frame", "hr",
- "img", "input", "isindex", "link", "meta" "param")
-
-try:
- HTML_EMPTY = set(HTML_EMPTY)
-except NameError:
- pass
-
-_namespace_map = {
- # "well-known" namespace prefixes
- "http://www.w3.org/XML/1998/namespace": "xml",
- "http://www.w3.org/1999/xhtml": "html",
- "http://www.w3.org/1999/02/22-rdf-syntax-ns#": "rdf",
- "http://schemas.xmlsoap.org/wsdl/": "wsdl",
- # xml schema
- "http://www.w3.org/2001/XMLSchema": "xs",
- "http://www.w3.org/2001/XMLSchema-instance": "xsi",
- # dublic core
- "http://purl.org/dc/elements/1.1/": "dc",
-}
-
-
-def _raise_serialization_error(text):
- raise TypeError(
- "cannot serialize %r (type %s)" % (text, type(text).__name__)
- )
-
-def _encode(text, encoding):
- try:
- return text.encode(encoding, "xmlcharrefreplace")
- except (TypeError, AttributeError):
- _raise_serialization_error(text)
-
-def _escape_cdata(text):
- # escape character data
- try:
- # it's worth avoiding do-nothing calls for strings that are
- # shorter than 500 character, or so. assume that's, by far,
- # the most common case in most applications.
- if "&" in text:
- text = text.replace("&", "&amp;")
- if "<" in text:
- text = text.replace("<", "&lt;")
- if ">" in text:
- text = text.replace(">", "&gt;")
- return text
- except (TypeError, AttributeError):
- _raise_serialization_error(text)
-
-
-def _escape_attrib(text):
- # escape attribute value
- try:
- if "&" in text:
- text = text.replace("&", "&amp;")
- if "<" in text:
- text = text.replace("<", "&lt;")
- if ">" in text:
- text = text.replace(">", "&gt;")
- if "\"" in text:
- text = text.replace("\"", "&quot;")
- if "\n" in text:
- text = text.replace("\n", "&#10;")
- return text
- except (TypeError, AttributeError):
- _raise_serialization_error(text)
-
-def _escape_attrib_html(text):
- # escape attribute value
- try:
- if "&" in text:
- text = text.replace("&", "&amp;")
- if "<" in text:
- text = text.replace("<", "&lt;")
- if ">" in text:
- text = text.replace(">", "&gt;")
- if "\"" in text:
- text = text.replace("\"", "&quot;")
- return text
- except (TypeError, AttributeError):
- _raise_serialization_error(text)
-
-
-def _serialize_html(write, elem, qnames, namespaces, format):
- tag = elem.tag
- text = elem.text
- if tag is Comment:
- write("<!--%s-->" % _escape_cdata(text))
- elif tag is ProcessingInstruction:
- write("<?%s?>" % _escape_cdata(text))
- else:
- tag = qnames[tag]
- if tag is None:
- if text:
- write(_escape_cdata(text))
- for e in elem:
- _serialize_html(write, e, qnames, None, format)
- else:
- write("<" + tag)
- items = elem.items()
- if items or namespaces:
- items.sort() # lexical order
- for k, v in items:
- if isinstance(k, QName):
- k = k.text
- if isinstance(v, QName):
- v = qnames[v.text]
- else:
- v = _escape_attrib_html(v)
- if qnames[k] == v and format == 'html':
- # handle boolean attributes
- write(" %s" % v)
- else:
- write(" %s=\"%s\"" % (qnames[k], v))
- if namespaces:
- items = namespaces.items()
- items.sort(key=lambda x: x[1]) # sort on prefix
- for v, k in items:
- if k:
- k = ":" + k
- write(" xmlns%s=\"%s\"" % (k, _escape_attrib(v)))
- if format == "xhtml" and tag in HTML_EMPTY:
- write(" />")
- else:
- write(">")
- tag = tag.lower()
- if text:
- if tag == "script" or tag == "style":
- write(text)
- else:
- write(_escape_cdata(text))
- for e in elem:
- _serialize_html(write, e, qnames, None, format)
- if tag not in HTML_EMPTY:
- write("</" + tag + ">")
- if elem.tail:
- write(_escape_cdata(elem.tail))
-
-def _write_html(root,
- encoding=None,
- default_namespace=None,
- format="html"):
- assert root is not None
- data = []
- write = data.append
- qnames, namespaces = _namespaces(root, default_namespace)
- _serialize_html(write, root, qnames, namespaces, format)
- if encoding is None:
- return "".join(data)
- else:
- return _encode("".join(data))
-
-
-# --------------------------------------------------------------------
-# serialization support
-
-def _namespaces(elem, default_namespace=None):
- # identify namespaces used in this tree
-
- # maps qnames to *encoded* prefix:local names
- qnames = {None: None}
-
- # maps uri:s to prefixes
- namespaces = {}
- if default_namespace:
- namespaces[default_namespace] = ""
-
- def add_qname(qname):
- # calculate serialized qname representation
- try:
- if qname[:1] == "{":
- uri, tag = qname[1:].split("}", 1)
- prefix = namespaces.get(uri)
- if prefix is None:
- prefix = _namespace_map.get(uri)
- if prefix is None:
- prefix = "ns%d" % len(namespaces)
- if prefix != "xml":
- namespaces[uri] = prefix
- if prefix:
- qnames[qname] = "%s:%s" % (prefix, tag)
- else:
- qnames[qname] = tag # default element
- else:
- if default_namespace:
- raise ValueError(
- "cannot use non-qualified names with "
- "default_namespace option"
- )
- qnames[qname] = qname
- except TypeError:
- _raise_serialization_error(qname)
-
- # populate qname and namespaces table
- try:
- iterate = elem.iter
- except AttributeError:
- iterate = elem.getiterator # cET compatibility
- for elem in iterate():
- tag = elem.tag
- if isinstance(tag, QName) and tag.text not in qnames:
- add_qname(tag.text)
- elif isinstance(tag, util.string_type):
- if tag not in qnames:
- add_qname(tag)
- elif tag is not None and tag is not Comment and tag is not PI:
- _raise_serialization_error(tag)
- for key, value in elem.items():
- if isinstance(key, QName):
- key = key.text
- if key not in qnames:
- add_qname(key)
- if isinstance(value, QName) and value.text not in qnames:
- add_qname(value.text)
- text = elem.text
- if isinstance(text, QName) and text.text not in qnames:
- add_qname(text.text)
- return qnames, namespaces
-
-def to_html_string(element):
- return _write_html(ElementTree(element).getroot(), format="html")
-
-def to_xhtml_string(element):
- return _write_html(ElementTree(element).getroot(), format="xhtml")
diff --git a/third_party/markdown/treeprocessors.py b/third_party/markdown/treeprocessors.py
deleted file mode 100644
index e6d3dc93..0000000
--- a/third_party/markdown/treeprocessors.py
+++ /dev/null
@@ -1,360 +0,0 @@
-from __future__ import unicode_literals
-from __future__ import absolute_import
-from . import util
-from . import odict
-from . import inlinepatterns
-
-
-def build_treeprocessors(md_instance, **kwargs):
- """ Build the default treeprocessors for Markdown. """
- treeprocessors = odict.OrderedDict()
- treeprocessors["inline"] = InlineProcessor(md_instance)
- treeprocessors["prettify"] = PrettifyTreeprocessor(md_instance)
- return treeprocessors
-
-
-def isString(s):
- """ Check if it's string """
- if not isinstance(s, util.AtomicString):
- return isinstance(s, util.string_type)
- return False
-
-
-class Treeprocessor(util.Processor):
- """
- Treeprocessors are run on the ElementTree object before serialization.
-
- Each Treeprocessor implements a "run" method that takes a pointer to an
- ElementTree, modifies it as necessary and returns an ElementTree
- object.
-
- Treeprocessors must extend markdown.Treeprocessor.
-
- """
- def run(self, root):
- """
- Subclasses of Treeprocessor should implement a `run` method, which
- takes a root ElementTree. This method can return another ElementTree
- object, and the existing root ElementTree will be replaced, or it can
- modify the current tree and return None.
- """
- pass
-
-
-class InlineProcessor(Treeprocessor):
- """
- A Treeprocessor that traverses a tree, applying inline patterns.
- """
-
- def __init__(self, md):
- self.__placeholder_prefix = util.INLINE_PLACEHOLDER_PREFIX
- self.__placeholder_suffix = util.ETX
- self.__placeholder_length = 4 + len(self.__placeholder_prefix) \
- + len(self.__placeholder_suffix)
- self.__placeholder_re = util.INLINE_PLACEHOLDER_RE
- self.markdown = md
-
- def __makePlaceholder(self, type):
- """ Generate a placeholder """
- id = "%04d" % len(self.stashed_nodes)
- hash = util.INLINE_PLACEHOLDER % id
- return hash, id
-
- def __findPlaceholder(self, data, index):
- """
- Extract id from data string, start from index
-
- Keyword arguments:
-
- * data: string
- * index: index, from which we start search
-
- Returns: placeholder id and string index, after the found placeholder.
-
- """
- m = self.__placeholder_re.search(data, index)
- if m:
- return m.group(1), m.end()
- else:
- return None, index + 1
-
- def __stashNode(self, node, type):
- """ Add node to stash """
- placeholder, id = self.__makePlaceholder(type)
- self.stashed_nodes[id] = node
- return placeholder
-
- def __handleInline(self, data, patternIndex=0):
- """
- Process string with inline patterns and replace it
- with placeholders
-
- Keyword arguments:
-
- * data: A line of Markdown text
- * patternIndex: The index of the inlinePattern to start with
-
- Returns: String with placeholders.
-
- """
- if not isinstance(data, util.AtomicString):
- startIndex = 0
- while patternIndex < len(self.markdown.inlinePatterns):
- data, matched, startIndex = self.__applyPattern(
- self.markdown.inlinePatterns.value_for_index(patternIndex),
- data, patternIndex, startIndex)
- if not matched:
- patternIndex += 1
- return data
-
- def __processElementText(self, node, subnode, isText=True):
- """
- Process placeholders in Element.text or Element.tail
- of Elements popped from self.stashed_nodes.
-
- Keywords arguments:
-
- * node: parent node
- * subnode: processing node
- * isText: bool variable, True - it's text, False - it's tail
-
- Returns: None
-
- """
- if isText:
- text = subnode.text
- subnode.text = None
- else:
- text = subnode.tail
- subnode.tail = None
-
- childResult = self.__processPlaceholders(text, subnode)
-
- if not isText and node is not subnode:
- pos = node.getchildren().index(subnode)
- node.remove(subnode)
- else:
- pos = 0
-
- childResult.reverse()
- for newChild in childResult:
- node.insert(pos, newChild)
-
- def __processPlaceholders(self, data, parent):
- """
- Process string with placeholders and generate ElementTree tree.
-
- Keyword arguments:
-
- * data: string with placeholders instead of ElementTree elements.
- * parent: Element, which contains processing inline data
-
- Returns: list with ElementTree elements with applied inline patterns.
-
- """
- def linkText(text):
- if text:
- if result:
- if result[-1].tail:
- result[-1].tail += text
- else:
- result[-1].tail = text
- else:
- if parent.text:
- parent.text += text
- else:
- parent.text = text
- result = []
- strartIndex = 0
- while data:
- index = data.find(self.__placeholder_prefix, strartIndex)
- if index != -1:
- id, phEndIndex = self.__findPlaceholder(data, index)
-
- if id in self.stashed_nodes:
- node = self.stashed_nodes.get(id)
-
- if index > 0:
- text = data[strartIndex:index]
- linkText(text)
-
- if not isString(node): # it's Element
- for child in [node] + node.getchildren():
- if child.tail:
- if child.tail.strip():
- self.__processElementText(node, child,False)
- if child.text:
- if child.text.strip():
- self.__processElementText(child, child)
- else: # it's just a string
- linkText(node)
- strartIndex = phEndIndex
- continue
-
- strartIndex = phEndIndex
- result.append(node)
-
- else: # wrong placeholder
- end = index + len(self.__placeholder_prefix)
- linkText(data[strartIndex:end])
- strartIndex = end
- else:
- text = data[strartIndex:]
- if isinstance(data, util.AtomicString):
- # We don't want to loose the AtomicString
- text = util.AtomicString(text)
- linkText(text)
- data = ""
-
- return result
-
- def __applyPattern(self, pattern, data, patternIndex, startIndex=0):
- """
- Check if the line fits the pattern, create the necessary
- elements, add it to stashed_nodes.
-
- Keyword arguments:
-
- * data: the text to be processed
- * pattern: the pattern to be checked
- * patternIndex: index of current pattern
- * startIndex: string index, from which we start searching
-
- Returns: String with placeholders instead of ElementTree elements.
-
- """
- match = pattern.getCompiledRegExp().match(data[startIndex:])
- leftData = data[:startIndex]
-
- if not match:
- return data, False, 0
-
- node = pattern.handleMatch(match)
-
- if node is None:
- return data, True, len(leftData)+match.span(len(match.groups()))[0]
-
- if not isString(node):
- if not isinstance(node.text, util.AtomicString):
- # We need to process current node too
- for child in [node] + node.getchildren():
- if not isString(node):
- if child.text:
- child.text = self.__handleInline(child.text,
- patternIndex + 1)
- if child.tail:
- child.tail = self.__handleInline(child.tail,
- patternIndex)
-
- placeholder = self.__stashNode(node, pattern.type())
-
- return "%s%s%s%s" % (leftData,
- match.group(1),
- placeholder, match.groups()[-1]), True, 0
-
- def run(self, tree):
- """Apply inline patterns to a parsed Markdown tree.
-
- Iterate over ElementTree, find elements with inline tag, apply inline
- patterns and append newly created Elements to tree. If you don't
- want to process your data with inline paterns, instead of normal string,
- use subclass AtomicString:
-
- node.text = markdown.AtomicString("This will not be processed.")
-
- Arguments:
-
- * tree: ElementTree object, representing Markdown tree.
-
- Returns: ElementTree object with applied inline patterns.
-
- """
- self.stashed_nodes = {}
-
- stack = [tree]
-
- while stack:
- currElement = stack.pop()
- insertQueue = []
- for child in currElement.getchildren():
- if child.text and not isinstance(child.text, util.AtomicString):
- text = child.text
- child.text = None
- lst = self.__processPlaceholders(self.__handleInline(
- text), child)
- stack += lst
- insertQueue.append((child, lst))
- if child.tail:
- tail = self.__handleInline(child.tail)
- dumby = util.etree.Element('d')
- tailResult = self.__processPlaceholders(tail, dumby)
- if dumby.text:
- child.tail = dumby.text
- else:
- child.tail = None
- pos = currElement.getchildren().index(child) + 1
- tailResult.reverse()
- for newChild in tailResult:
- currElement.insert(pos, newChild)
- if child.getchildren():
- stack.append(child)
-
- for element, lst in insertQueue:
- if self.markdown.enable_attributes:
- if element.text and isString(element.text):
- element.text = \
- inlinepatterns.handleAttributes(element.text,
- element)
- i = 0
- for newChild in lst:
- if self.markdown.enable_attributes:
- # Processing attributes
- if newChild.tail and isString(newChild.tail):
- newChild.tail = \
- inlinepatterns.handleAttributes(newChild.tail,
- element)
- if newChild.text and isString(newChild.text):
- newChild.text = \
- inlinepatterns.handleAttributes(newChild.text,
- newChild)
- element.insert(i, newChild)
- i += 1
- return tree
-
-
-class PrettifyTreeprocessor(Treeprocessor):
- """ Add linebreaks to the html document. """
-
- def _prettifyETree(self, elem):
- """ Recursively add linebreaks to ElementTree children. """
-
- i = "\n"
- if util.isBlockLevel(elem.tag) and elem.tag not in ['code', 'pre']:
- if (not elem.text or not elem.text.strip()) \
- and len(elem) and util.isBlockLevel(elem[0].tag):
- elem.text = i
- for e in elem:
- if util.isBlockLevel(e.tag):
- self._prettifyETree(e)
- if not elem.tail or not elem.tail.strip():
- elem.tail = i
- if not elem.tail or not elem.tail.strip():
- elem.tail = i
-
- def run(self, root):
- """ Add linebreaks to ElementTree root object. """
-
- self._prettifyETree(root)
- # Do <br />'s seperately as they are often in the middle of
- # inline content and missed by _prettifyETree.
- brs = root.getiterator('br')
- for br in brs:
- if not br.tail or not br.tail.strip():
- br.tail = '\n'
- else:
- br.tail = '\n%s' % br.tail
- # Clean up extra empty lines at end of code blocks.
- pres = root.getiterator('pre')
- for pre in pres:
- if len(pre) and pre[0].tag == 'code':
- pre[0].text = pre[0].text.rstrip() + '\n'
diff --git a/third_party/markdown/util.py b/third_party/markdown/util.py
deleted file mode 100644
index 1036197..0000000
--- a/third_party/markdown/util.py
+++ /dev/null
@@ -1,136 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-import re
-import sys
-
-
-"""
-Python 3 Stuff
-=============================================================================
-"""
-PY3 = sys.version_info[0] == 3
-
-if PY3:
- string_type = str
- text_type = str
- int2str = chr
-else:
- string_type = basestring
- text_type = unicode
- int2str = unichr
-
-
-"""
-Constants you might want to modify
------------------------------------------------------------------------------
-"""
-
-BLOCK_LEVEL_ELEMENTS = re.compile("^(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul"
- "|script|noscript|form|fieldset|iframe|math"
- "|hr|hr/|style|li|dt|dd|thead|tbody"
- "|tr|th|td|section|footer|header|group|figure"
- "|figcaption|aside|article|canvas|output"
- "|progress|video)$", re.IGNORECASE)
-# Placeholders
-STX = '\u0002' # Use STX ("Start of text") for start-of-placeholder
-ETX = '\u0003' # Use ETX ("End of text") for end-of-placeholder
-INLINE_PLACEHOLDER_PREFIX = STX+"klzzwxh:"
-INLINE_PLACEHOLDER = INLINE_PLACEHOLDER_PREFIX + "%s" + ETX
-INLINE_PLACEHOLDER_RE = re.compile(INLINE_PLACEHOLDER % r'([0-9]{4})')
-AMP_SUBSTITUTE = STX+"amp"+ETX
-
-"""
-Constants you probably do not need to change
------------------------------------------------------------------------------
-"""
-
-RTL_BIDI_RANGES = ( ('\u0590', '\u07FF'),
- # Hebrew (0590-05FF), Arabic (0600-06FF),
- # Syriac (0700-074F), Arabic supplement (0750-077F),
- # Thaana (0780-07BF), Nko (07C0-07FF).
- ('\u2D30', '\u2D7F'), # Tifinagh
- )
-
-# Extensions should use "markdown.util.etree" instead of "etree" (or do `from
-# markdown.util import etree`). Do not import it by yourself.
-
-try: # Is the C implemenation of ElementTree available?
- import xml.etree.cElementTree as etree
- from xml.etree.ElementTree import Comment
- # Serializers (including ours) test with non-c Comment
- etree.test_comment = Comment
- if etree.VERSION < "1.0.5":
- raise RuntimeError("cElementTree version 1.0.5 or higher is required.")
-except (ImportError, RuntimeError):
- # Use the Python implementation of ElementTree?
- import xml.etree.ElementTree as etree
- if etree.VERSION < "1.1":
- raise RuntimeError("ElementTree version 1.1 or higher is required")
-
-
-"""
-AUXILIARY GLOBAL FUNCTIONS
-=============================================================================
-"""
-
-
-def isBlockLevel(tag):
- """Check if the tag is a block level HTML tag."""
- if isinstance(tag, string_type):
- return BLOCK_LEVEL_ELEMENTS.match(tag)
- # Some ElementTree tags are not strings, so return False.
- return False
-
-"""
-MISC AUXILIARY CLASSES
-=============================================================================
-"""
-
-class AtomicString(text_type):
- """A string which should not be further processed."""
- pass
-
-
-class Processor(object):
- def __init__(self, markdown_instance=None):
- if markdown_instance:
- self.markdown = markdown_instance
-
-
-class HtmlStash(object):
- """
- This class is used for stashing HTML objects that we extract
- in the beginning and replace with place-holders.
- """
-
- def __init__ (self):
- """ Create a HtmlStash. """
- self.html_counter = 0 # for counting inline html segments
- self.rawHtmlBlocks=[]
-
- def store(self, html, safe=False):
- """
- Saves an HTML segment for later reinsertion. Returns a
- placeholder string that needs to be inserted into the
- document.
-
- Keyword arguments:
-
- * html: an html segment
- * safe: label an html segment as safe for safemode
-
- Returns : a placeholder string
-
- """
- self.rawHtmlBlocks.append((html, safe))
- placeholder = self.get_placeholder(self.html_counter)
- self.html_counter += 1
- return placeholder
-
- def reset(self):
- self.html_counter = 0
- self.rawHtmlBlocks = []
-
- def get_placeholder(self, key):
- return "%swzxhzdk:%d%s" % (STX, key, ETX)
-