summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Petrello <lists@ryanpetrello.com>2015-06-04 13:43:31 -0400
committerRyan Petrello <lists@ryanpetrello.com>2015-06-11 10:04:51 -0400
commit177c566ecae8a20750aa80d081e681137f8f9d51 (patch)
tree751fb442bd62a2c0df5d37175c33652f3dd42d49
parentd3159f1d6bec06845b152de836793f4454d95804 (diff)
downloadpecan-177c566ecae8a20750aa80d081e681137f8f9d51.tar.gz
Replace pecan's homegrown interactive debugging middleware with backlash
backlash is a port of Werkzeug's debugger middleware to Webob. It has no additional dependencies beyond Webob and is being used by the TurboGears2 team as an alternative to the antiquated Paste/WebError. Leveraging this as an *optional* dependency to pecan would: * Remove a sizable chunk of code from pecan, some of which is embedded JavaScript that packagers have traditionally balked at. * Improve the interactive debugging experience for developers in a very meaningful way (the Werkzeug-based middleware provides features like an in-browser console debugger, the ability to load source code on a frame-by-frame basis). * Improve the unified debugging experience amongst several popular Python frameworks (some form of the debugging interface will be in use by Flask, Pecan, and TurboGears2). Change-Id: I85f50f677c6052bd2afd32811dedf33835135e12
-rw-r--r--docs/source/debug-middleware-1.pngbin55246 -> 0 bytes
-rw-r--r--docs/source/debug-middleware-2.pngbin6767 -> 0 bytes
-rw-r--r--docs/source/development.rst37
-rw-r--r--pecan/__init__.py25
-rw-r--r--pecan/core.py4
-rw-r--r--pecan/middleware/__init__.py1
-rw-r--r--pecan/middleware/debug.py420
-rw-r--r--pecan/middleware/resources/XRegExp.js664
-rw-r--r--pecan/middleware/resources/__init__.py28
-rw-r--r--pecan/middleware/resources/brush-python.js64
-rw-r--r--pecan/middleware/resources/pecan.pngbin4454 -> 0 bytes
-rw-r--r--pecan/middleware/resources/shCore.js1731
-rw-r--r--pecan/middleware/resources/syntax.css226
-rw-r--r--pecan/middleware/resources/theme.css117
-rw-r--r--pecan/tests/middleware/test_debug.py83
-rw-r--r--pecan/tests/test_base.py35
16 files changed, 120 insertions, 3315 deletions
diff --git a/docs/source/debug-middleware-1.png b/docs/source/debug-middleware-1.png
deleted file mode 100644
index 10c91b0..0000000
--- a/docs/source/debug-middleware-1.png
+++ /dev/null
Binary files differ
diff --git a/docs/source/debug-middleware-2.png b/docs/source/debug-middleware-2.png
deleted file mode 100644
index 1c187b8..0000000
--- a/docs/source/debug-middleware-2.png
+++ /dev/null
Binary files differ
diff --git a/docs/source/development.rst b/docs/source/development.rst
index db9bd84..76b2267 100644
--- a/docs/source/development.rst
+++ b/docs/source/development.rst
@@ -21,37 +21,18 @@ in your applications. To enable the debugging middleware, simply set the
Once enabled, the middleware will automatically catch exceptions raised by your
application and display the Python stack trace and WSGI environment in your
-browser for easy debugging:
+browser when runtime exceptions are raised.
-.. figure:: debug-middleware-1.png
- :alt: Pecan debug middleware sample output.
- :width: 90%
+To improve debugging, including support for an interactive browser-based
+console, Pecan makes use of the Python `backlash
+<https://pypi.python.org/pypi/backlash>` library. You’ll need to install it
+for development use before continuing::
-To further aid in debugging, the middleware includes the ability to repeat the
-offending request, automatically inserting a breakpoint, and dropping your
-console into the Python debugger, ``pdb.post_mortem``:
+ $ pip install backlash
+ Downloading/unpacking backlash
+ ...
+ Successfully installed backlash
-.. figure:: debug-middleware-2.png
- :alt: Pecan debug middleware request debugger.
-
-You can also use any debugger with a suitable ``post_mortem`` entry point.
-For example, to use the `PuDB Debugger <http://pypi.python.org/pypi/pudb>`_,
-set ``debugger`` like so::
-
- import pudb
-
- app = {
- ...
- 'debug': True,
- 'debugger': pudb.post_mortem,
- ...
- }
-
-.. seealso::
-
- Refer to the `pdb documentation
- <http://docs.python.org/library/pdb.html>`_ for more information on
- using the Python debugger.
Serving Static Files
--------------------
diff --git a/pecan/__init__.py b/pecan/__init__.py
index 3987892..1adcc71 100644
--- a/pecan/__init__.py
+++ b/pecan/__init__.py
@@ -20,7 +20,6 @@ try:
except ImportError:
from logutils.dictconfig import dictConfig as load_logging_config # noqa
-import six
import warnings
@@ -44,8 +43,6 @@ def make_app(root, **kw):
debug mode is set.
:param debug: A flag to enable debug mode. This enables the debug
middleware and serving static files.
- :param debugger: A callable to start debugging, defaulting to the Python
- debugger entry point ``pdb.post_mortem``.
:param wrap_app: A function or middleware class to wrap the Pecan app.
This must either be a wsgi middleware class or a
function that returns a wsgi application. This wrapper
@@ -101,19 +98,19 @@ def make_app(root, **kw):
# Included for internal redirect support
app = middleware.recursive.RecursiveMiddleware(app)
- # When in debug mode, load our exception dumping middleware
+ # When in debug mode, load exception debugging middleware
static_root = kw.get('static_root', None)
if debug:
- debugger = kw.get('debugger', None)
- debugger_kwargs = {}
- if six.callable(debugger):
- debugger_kwargs['debugger'] = debugger
- elif debugger:
- warnings.warn(
- "`app.debugger` is not callable, ignoring",
- RuntimeWarning
- )
- app = middleware.debug.DebugMiddleware(app, **debugger_kwargs)
+ debug_kwargs = getattr(conf, 'debug', {})
+ debug_kwargs.setdefault('context_injectors', []).append(
+ lambda environ: {
+ 'request': environ.get('pecan.locals', {}).get('request')
+ }
+ )
+ app = DebugMiddleware(
+ app,
+ **debug_kwargs
+ )
# Support for serving static files (for development convenience)
if static_root:
diff --git a/pecan/core.py b/pecan/core.py
index 14b9ad3..567f8e5 100644
--- a/pecan/core.py
+++ b/pecan/core.py
@@ -660,6 +660,10 @@ class PecanBase(object):
req = self.request_cls(environ)
resp = self.response_cls()
state = RoutingState(req, resp, self)
+ environ['pecan.locals'] = {
+ 'request': req,
+ 'response': resp
+ }
controller = None
# handle the request
diff --git a/pecan/middleware/__init__.py b/pecan/middleware/__init__.py
index d95b453..0c82911 100644
--- a/pecan/middleware/__init__.py
+++ b/pecan/middleware/__init__.py
@@ -1,4 +1,3 @@
-from . import debug
from . import errordocument
from . import recursive
from . import static
diff --git a/pecan/middleware/debug.py b/pecan/middleware/debug.py
index ec2faa0..1a6a482 100644
--- a/pecan/middleware/debug.py
+++ b/pecan/middleware/debug.py
@@ -1,324 +1,96 @@
-from traceback import print_exc
-from pprint import pformat
-import pdb
-
-from six.moves import cStringIO as StringIO
-
-from mako.template import Template
-from webob import Response
-
-from .resources import (pecan_image, xregexp_js, syntax_js, syntax_css, theme,
- brush)
-
-
-debug_template_raw = '''<html>
- <head>
- <title>Pecan - Application Error</title>
-
- <link rel="stylesheet" type="text/css" href="${syntax_css}" />
- <link rel="stylesheet" type="text/css" href="${theme}" />
-
- <script type="text/javascript" src="${xregexp_js}"></script>
- <script type="text/javascript" src="${syntax_js}">
- /**
- * SyntaxHighlighter
- * http://alexgorbatchev.com/SyntaxHighlighter
- *
- * SyntaxHighlighter is donationware. If you are using it, please donate.
- * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
- *
- * @version
- * 3.0.83 (July 02 2010)
- *
- * @copyright
- * Copyright (C) 2004-2010 Alex Gorbatchev.
- *
- * @license
- * Dual licensed under the MIT and GPL licenses.
- */
- </script>
- <script type="text/javascript" src="${brush}">
- /**
- * SyntaxHighlighter
- * http://alexgorbatchev.com/SyntaxHighlighter
- *
- * SyntaxHighlighter is donationware. If you are using it, please donate.
- * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
- *
- * @version
- * 3.0.83 (July 02 2010)
- *
- * @copyright
- * Copyright (C) 2004-2010 Alex Gorbatchev.
- *
- * @license
- * Dual licensed under the MIT and GPL licenses.
- */
- </script>
-
- <style type="text/css">
- body {
- color: #000;
- background: #FFF;
- font-family: 'Helvetica Neue', 'Helvetica', 'Verdana', sans-serif;
- font-size: 12px;
- padding: 0;
- margin: 0;
- }
-
- a {
- color: #FAFF78;
- }
-
- h1, h2, h3, h4, h5, h6 {
- font-family: 'Helvetica', sans-serif;
- }
-
- h1 {
- margin: 0;
- padding: .75em 1.5em 1em 1.5em;
- color: #F90;
- font-size: 14px;
- font-weight: bold;
- }
-
- h1 img {
- padding-right: 5px;
- }
-
- h2 {
- color: #311F00;
- }
-
- header {
- width: 100%;
- background: #311F00;
- }
-
- div#error-content {
- padding: 0 2em;
- }
-
- .syntaxhighlighter a,
- .syntaxhighlighter div,
- .syntaxhighlighter code,
- .syntaxhighlighter table,
- .syntaxhighlighter table td,
- .syntaxhighlighter table tr,
- .syntaxhighlighter table tbody,
- .syntaxhighlighter table thead,
- .syntaxhighlighter table caption,
- .syntaxhighlighter textarea {
- font-family: monospace !important;
- }
-
- .syntaxhighlighter .container {
- background: #FDF6E3 !important;
- padding: 1em !important;
- }
-
- .syntaxhighlighter .container .line {
- background: #FDF6E3 !important;
- }
-
- .syntaxhighlighter .container .line .python.string {
- color: #C70 !important;
- }
-
- #debug {
- background: #FDF6E3;
- padding: 10px !important;
- margin-top: 10px;
- font-family: monospace;
- }
-
- </style>
- <script type="text/javascript">
- SyntaxHighlighter.defaults['gutter'] = false;
- SyntaxHighlighter.defaults['toolbar'] = false;
- SyntaxHighlighter.all()
- </script>
-
- <script type="text/javascript">
- function get_request() {
- /* ajax sans jquery makes me sad */
- var request = false;
-
- // Mozilla/Safari
- if (window.XMLHttpRequest) {
- request = new XMLHttpRequest();
- }
-
- // IE
- else if (window.ActiveXObject) {
- request = new ActiveXObject("Microsoft.XMLHTTP");
- }
-
- return request;
- }
-
- function debug_request(btn) {
- btn.disabled = true;
-
- request = get_request();
- request.open('GET', '/__pecan_initiate_pdb__', true);
- request.onreadystatechange = function() {
- if (request.readyState == 4) {
- btn.disabled = false;
- }
- }
- request.send('');
-
- /* automatically timeout after 5 minutes, re-enabling the button */
- setTimeout(function() {
- request.abort();
- }, 5 * 60 * 1000);
- }
- </script>
- </head>
- <body>
-
- <header>
- <h1>
- <img style="padding-top: 7px"
- align="center" alt="pecan logo"
- height="25"
- src="${pecan_image}" />
- application error
- </h1>
- </header>
-
- <div id="error-content">
-
- <p>
- <b>To disable this interface, set </b>
- <pre class="brush: python">conf.app.debug = False</pre>
- </p>
-
- <h2>Traceback</h2>
- <div id="traceback">
- <pre class="brush: python">${traceback}</pre>
- </div>
-
- % if not debugging:
- <b>Want to debug this request?</b>
- <div id="debug">
- You can <button onclick="debug_request(this)">
- repeat this request
- </button> with a Python debugger breakpoint.
- </div>
- % endif
-
- <h2>WSGI Environment</h2>
- <div id="environ">
- <pre class="brush: python">${environment}</pre>
- </div>
- </div>
- </body>
-</html>
-'''
-
-debug_template = Template(debug_template_raw)
-__debug_environ__ = None
-
-
-class PdbMiddleware(object):
- def __init__(self, app, debugger):
- self.app = app
- self.debugger = debugger
-
- def __call__(self, environ, start_response):
- try:
- return self.app(environ, start_response)
- except:
- self.debugger()
-
-
-class DebugMiddleware(object):
- """A WSGI middleware that provides debugging assistance for development
- environments.
-
- To enable the debugging middleware, simply set the ``debug`` flag to
- ``True`` in your configuration file::
-
- app = {
- ...
- 'debug': True,
- ...
- }
-
- Once enabled, the middleware will automatically catch exceptions raised by
- your application, and display the Python stack trace and WSGI environment
- in your browser for easy debugging.
-
- To further aid in debugging, the middleware includes the ability to repeat
- the offending request, automatically inserting a breakpoint, and dropping
- your console into the Python debugger, ``pdb.post_mortem``.
-
- You can also use any debugger with a suitable ``post_mortem`` entry point
- such as the `PuDB Debugger <http://pypi.python.org/pypi/pudb>`_,
-
- For more information, refer to the `documentation for pdb
- <http://docs.python.org/library/pdb.html>`_ available on the Python
- website.
-
- :param app: the application to wrap.
- :param debugger: a callable to start debugging, defaulting to the Python
- debugger entry point ``pdb.post_mortem``.
- """
-
- def __init__(self, app, debugger=pdb.post_mortem):
- self.app = app
- self.debugger = debugger
-
- def __call__(self, environ, start_response):
- if environ['wsgi.multiprocess']:
- raise RuntimeError(
- "The DebugMiddleware middleware is not usable in a "
- "multi-process environment"
- )
-
- if environ.get('paste.testing'):
- return self.app(environ, start_response)
-
- # initiate a PDB session if requested
- global __debug_environ__
- debugging = environ['PATH_INFO'] == '/__pecan_initiate_pdb__'
- if debugging:
- PdbMiddleware(self.app, self.debugger)(
- __debug_environ__, start_response
- )
- environ = __debug_environ__
-
- try:
- return self.app(environ, start_response)
- except:
- # save the environ for debugging
- if not debugging:
- __debug_environ__ = environ
-
- # get a formatted exception
- out = StringIO()
- print_exc(file=out)
-
- # get formatted WSGI environment
- formatted_environ = pformat(environ)
-
- # render our template
- result = debug_template.render(
- traceback=out.getvalue(),
- environment=formatted_environ,
- pecan_image=pecan_image,
- xregexp_js=xregexp_js,
- syntax_js=syntax_js,
- brush=brush,
- syntax_css=syntax_css,
- theme=theme,
- debugging=debugging
- )
-
- # construct and return our response
- response = Response()
- response.status_int = 400
- response.unicode_body = result
- return response(environ, start_response)
+__CONFIG_HELP__ = '''
+<div class="traceback">
+ <b>To disable this interface, set </b>
+ <a target="window"
+ href="https://pecan.readthedocs.org/en/latest/deployment.html#disabling-debug-mode">
+ <pre>conf.app.debug = False</pre>
+ </a>
+</div>
+''' # noqa
+
+try:
+ import re
+ from backlash.debug import DebuggedApplication
+
+ class DebugMiddleware(DebuggedApplication):
+
+ body_re = re.compile('(<body[^>]*>)', re.I)
+
+ def debug_application(self, environ, start_response):
+ for part in super(DebugMiddleware, self).debug_application(
+ environ, start_response
+ ):
+ yield self.body_re.sub('\g<1>%s' % __CONFIG_HELP__, part)
+
+
+except ImportError:
+ from traceback import print_exc
+ from pprint import pformat
+
+ from mako.template import Template
+ from six.moves import cStringIO as StringIO
+ from webob import Response
+ from webob.exc import HTTPException
+
+ debug_template_raw = '''<html>
+ <head>
+ <title>Pecan - Application Error</title>
+ <body>
+ <header>
+ <h1>
+ An error occurred!
+ </h1>
+ </header>
+ <div id="error-content">
+ <p>
+ %(config_help)s
+ Pecan offers support for interactive debugging by installing the <a href="https://pypi.python.org/pypi/backlash" target="window">backlash</a> package:
+ <br />
+ <b><pre>pip install backlash</pre></b>
+ ...and reloading this page.
+ </p>
+ <h2>Traceback</h2>
+ <div id="traceback">
+ <pre>${traceback}</pre>
+ </div>
+ <h2>WSGI Environment</h2>
+ <div id="environ">
+ <pre>${environment}</pre>
+ </div>
+ </div>
+ </body>
+ </html>
+ ''' % {'config_help': __CONFIG_HELP__} # noqa
+
+ debug_template = Template(debug_template_raw)
+
+ class DebugMiddleware(object):
+
+ def __init__(self, app, *args, **kwargs):
+ self.app = app
+
+ def __call__(self, environ, start_response):
+ try:
+ return self.app(environ, start_response)
+ except Exception as exc:
+ # get a formatted exception
+ out = StringIO()
+ print_exc(file=out)
+
+ # get formatted WSGI environment
+ formatted_environ = pformat(environ)
+
+ # render our template
+ result = debug_template.render(
+ traceback=out.getvalue(),
+ environment=formatted_environ
+ )
+
+ # construct and return our response
+ response = Response()
+ if isinstance(exc, HTTPException):
+ response.status_int = exc.status
+ else:
+ response.status_int = 500
+ response.unicode_body = result
+ return response(environ, start_response)
diff --git a/pecan/middleware/resources/XRegExp.js b/pecan/middleware/resources/XRegExp.js
deleted file mode 100644
index ebdb9c9..0000000
--- a/pecan/middleware/resources/XRegExp.js
+++ /dev/null
@@ -1,664 +0,0 @@
-// XRegExp 1.5.1
-// (c) 2007-2012 Steven Levithan
-// MIT License
-// <http://xregexp.com>
-// Provides an augmented, extensible, cross-browser implementation of regular expressions,
-// including support for additional syntax, flags, and methods
-
-var XRegExp;
-
-if (XRegExp) {
- // Avoid running twice, since that would break references to native globals
- throw Error("can't load XRegExp twice in the same frame");
-}
-
-// Run within an anonymous function to protect variables and avoid new globals
-(function (undefined) {
-
- //---------------------------------
- // Constructor
- //---------------------------------
-
- // Accepts a pattern and flags; returns a new, extended `RegExp` object. Differs from a native
- // regular expression in that additional syntax and flags are supported and cross-browser
- // syntax inconsistencies are ameliorated. `XRegExp(/regex/)` clones an existing regex and
- // converts to type XRegExp
- XRegExp = function (pattern, flags) {
- var output = [],
- currScope = XRegExp.OUTSIDE_CLASS,
- pos = 0,
- context, tokenResult, match, chr, regex;
-
- if (XRegExp.isRegExp(pattern)) {
- if (flags !== undefined)
- throw TypeError("can't supply flags when constructing one RegExp from another");
- return clone(pattern);
- }
- // Tokens become part of the regex construction process, so protect against infinite
- // recursion when an XRegExp is constructed within a token handler or trigger
- if (isInsideConstructor)
- throw Error("can't call the XRegExp constructor within token definition functions");
-
- flags = flags || "";
- context = { // `this` object for custom tokens
- hasNamedCapture: false,
- captureNames: [],
- hasFlag: function (flag) {return flags.indexOf(flag) > -1;},
- setFlag: function (flag) {flags += flag;}
- };
-
- while (pos < pattern.length) {
- // Check for custom tokens at the current position
- tokenResult = runTokens(pattern, pos, currScope, context);
-
- if (tokenResult) {
- output.push(tokenResult.output);
- pos += (tokenResult.match[0].length || 1);
- } else {
- // Check for native multicharacter metasequences (excluding character classes) at
- // the current position
- if (match = nativ.exec.call(nativeTokens[currScope], pattern.slice(pos))) {
- output.push(match[0]);
- pos += match[0].length;
- } else {
- chr = pattern.charAt(pos);
- if (chr === "[")
- currScope = XRegExp.INSIDE_CLASS;
- else if (chr === "]")
- currScope = XRegExp.OUTSIDE_CLASS;
- // Advance position one character
- output.push(chr);
- pos++;
- }
- }
- }
-
- regex = RegExp(output.join(""), nativ.replace.call(flags, flagClip, ""));
- regex._xregexp = {
- source: pattern,
- captureNames: context.hasNamedCapture ? context.captureNames : null
- };
- return regex;
- };
-
-
- //---------------------------------
- // Public properties
- //---------------------------------
-
- XRegExp.version = "1.5.1";
-
- // Token scope bitflags
- XRegExp.INSIDE_CLASS = 1;
- XRegExp.OUTSIDE_CLASS = 2;
-
-
- //---------------------------------
- // Private variables
- //---------------------------------
-
- var replacementToken = /\$(?:(\d\d?|[$&`'])|{([$\w]+)})/g,
- flagClip = /[^gimy]+|([\s\S])(?=[\s\S]*\1)/g, // Nonnative and duplicate flags
- quantifier = /^(?:[?*+]|{\d+(?:,\d*)?})\??/,
- isInsideConstructor = false,
- tokens = [],
- // Copy native globals for reference ("native" is an ES3 reserved keyword)
- nativ = {
- exec: RegExp.prototype.exec,
- test: RegExp.prototype.test,
- match: String.prototype.match,
- replace: String.prototype.replace,
- split: String.prototype.split
- },
- compliantExecNpcg = nativ.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups
- compliantLastIndexIncrement = function () {
- var x = /^/g;
- nativ.test.call(x, "");
- return !x.lastIndex;
- }(),
- hasNativeY = RegExp.prototype.sticky !== undefined,
- nativeTokens = {};
-
- // `nativeTokens` match native multicharacter metasequences only (including deprecated octals,
- // excluding character classes)
- nativeTokens[XRegExp.INSIDE_CLASS] = /^(?:\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S]))/;
- nativeTokens[XRegExp.OUTSIDE_CLASS] = /^(?:\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S])|\(\?[:=!]|[?*+]\?|{\d+(?:,\d*)?}\??)/;
-
-
- //---------------------------------
- // Public methods
- //---------------------------------
-
- // Lets you extend or change XRegExp syntax and create custom flags. This is used internally by
- // the XRegExp library and can be used to create XRegExp plugins. This function is intended for
- // users with advanced knowledge of JavaScript's regular expression syntax and behavior. It can
- // be disabled by `XRegExp.freezeTokens`
- XRegExp.addToken = function (regex, handler, scope, trigger) {
- tokens.push({
- pattern: clone(regex, "g" + (hasNativeY ? "y" : "")),
- handler: handler,
- scope: scope || XRegExp.OUTSIDE_CLASS,
- trigger: trigger || null
- });
- };
-
- // Accepts a pattern and flags; returns an extended `RegExp` object. If the pattern and flag
- // combination has previously been cached, the cached copy is returned; otherwise the newly
- // created regex is cached
- XRegExp.cache = function (pattern, flags) {
- var key = pattern + "/" + (flags || "");
- return XRegExp.cache[key] || (XRegExp.cache[key] = XRegExp(pattern, flags));
- };
-
- // Accepts a `RegExp` instance; returns a copy with the `/g` flag set. The copy has a fresh
- // `lastIndex` (set to zero). If you want to copy a regex without forcing the `global`
- // property, use `XRegExp(regex)`. Do not use `RegExp(regex)` because it will not preserve
- // special properties required for named capture
- XRegExp.copyAsGlobal = function (regex) {
- return clone(regex, "g");
- };
-
- // Accepts a string; returns the string with regex metacharacters escaped. The returned string
- // can safely be used at any point within a regex to match the provided literal string. Escaped
- // characters are [ ] { } ( ) * + ? - . , \ ^ $ | # and whitespace
- XRegExp.escape = function (str) {
- return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
- };
-
- // Accepts a string to search, regex to search with, position to start the search within the
- // string (default: 0), and an optional Boolean indicating whether matches must start at-or-
- // after the position or at the specified position only. This function ignores the `lastIndex`
- // of the provided regex in its own handling, but updates the property for compatibility
- XRegExp.execAt = function (str, regex, pos, anchored) {
- var r2 = clone(regex, "g" + ((anchored && hasNativeY) ? "y" : "")),
- match;
- r2.lastIndex = pos = pos || 0;
- match = r2.exec(str); // Run the altered `exec` (required for `lastIndex` fix, etc.)
- if (anchored && match && match.index !== pos)
- match = null;
- if (regex.global)
- regex.lastIndex = match ? r2.lastIndex : 0;
- return match;
- };
-
- // Breaks the unrestorable link to XRegExp's private list of tokens, thereby preventing
- // syntax and flag changes. Should be run after XRegExp and any plugins are loaded
- XRegExp.freezeTokens = function () {
- XRegExp.addToken = function () {
- throw Error("can't run addToken after freezeTokens");
- };
- };
-
- // Accepts any value; returns a Boolean indicating whether the argument is a `RegExp` object.
- // Note that this is also `true` for regex literals and regexes created by the `XRegExp`
- // constructor. This works correctly for variables created in another frame, when `instanceof`
- // and `constructor` checks would fail to work as intended
- XRegExp.isRegExp = function (o) {
- return Object.prototype.toString.call(o) === "[object RegExp]";
- };
-
- // Executes `callback` once per match within `str`. Provides a simpler and cleaner way to
- // iterate over regex matches compared to the traditional approaches of subverting
- // `String.prototype.replace` or repeatedly calling `exec` within a `while` loop
- XRegExp.iterate = function (str, regex, callback, context) {
- var r2 = clone(regex, "g"),
- i = -1, match;
- while (match = r2.exec(str)) { // Run the altered `exec` (required for `lastIndex` fix, etc.)
- if (regex.global)
- regex.lastIndex = r2.lastIndex; // Doing this to follow expectations if `lastIndex` is checked within `callback`
- callback.call(context, match, ++i, str, regex);
- if (r2.lastIndex === match.index)
- r2.lastIndex++;
- }
- if (regex.global)
- regex.lastIndex = 0;
- };
-
- // Accepts a string and an array of regexes; returns the result of using each successive regex
- // to search within the matches of the previous regex. The array of regexes can also contain
- // objects with `regex` and `backref` properties, in which case the named or numbered back-
- // references specified are passed forward to the next regex or returned. E.g.:
- // var xregexpImgFileNames = XRegExp.matchChain(html, [
- // {regex: /<img\b([^>]+)>/i, backref: 1}, // <img> tag attributes
- // {regex: XRegExp('(?ix) \\s src=" (?<src> [^"]+ )'), backref: "src"}, // src attribute values
- // {regex: XRegExp("^http://xregexp\\.com(/[^#?]+)", "i"), backref: 1}, // xregexp.com paths
- // /[^\/]+$/ // filenames (strip directory paths)
- // ]);
- XRegExp.matchChain = function (str, chain) {
- return function recurseChain (values, level) {
- var item = chain[level].regex ? chain[level] : {regex: chain[level]},
- regex = clone(item.regex, "g"),
- matches = [], i;
- for (i = 0; i < values.length; i++) {
- XRegExp.iterate(values[i], regex, function (match) {
- matches.push(item.backref ? (match[item.backref] || "") : match[0]);
- });
- }
- return ((level === chain.length - 1) || !matches.length) ?
- matches : recurseChain(matches, level + 1);
- }([str], 0);
- };
-
-
- //---------------------------------
- // New RegExp prototype methods
- //---------------------------------
-
- // Accepts a context object and arguments array; returns the result of calling `exec` with the
- // first value in the arguments array. the context is ignored but is accepted for congruity
- // with `Function.prototype.apply`
- RegExp.prototype.apply = function (context, args) {
- return this.exec(args[0]);
- };
-
- // Accepts a context object and string; returns the result of calling `exec` with the provided
- // string. the context is ignored but is accepted for congruity with `Function.prototype.call`
- RegExp.prototype.call = function (context, str) {
- return this.exec(str);
- };
-
-
- //---------------------------------
- // Overriden native methods
- //---------------------------------
-
- // Adds named capture support (with backreferences returned as `result.name`), and fixes two
- // cross-browser issues per ES3:
- // - Captured values for nonparticipating capturing groups should be returned as `undefined`,
- // rather than the empty string.
- // - `lastIndex` should not be incremented after zero-length matches.
- RegExp.prototype.exec = function (str) {
- var match, name, r2, origLastIndex;
- if (!this.global)
- origLastIndex = this.lastIndex;
- match = nativ.exec.apply(this, arguments);
- if (match) {
- // Fix browsers whose `exec` methods don't consistently return `undefined` for
- // nonparticipating capturing groups
- if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) {
- r2 = RegExp(this.source, nativ.replace.call(getNativeFlags(this), "g", ""));
- // Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed
- // matching due to characters outside the match
- nativ.replace.call((str + "").slice(match.index), r2, function () {
- for (var i = 1; i < arguments.length - 2; i++) {
- if (arguments[i] === undefined)
- match[i] = undefined;
- }
- });
- }
- // Attach named capture properties
- if (this._xregexp && this._xregexp.captureNames) {
- for (var i = 1; i < match.length; i++) {
- name = this._xregexp.captureNames[i - 1];
- if (name)
- match[name] = match[i];
- }
- }
- // Fix browsers that increment `lastIndex` after zero-length matches
- if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index))
- this.lastIndex--;
- }
- if (!this.global)
- this.lastIndex = origLastIndex; // Fix IE, Opera bug (last tested IE 9.0.5, Opera 11.61 on Windows)
- return match;
- };
-
- // Fix browser bugs in native method
- RegExp.prototype.test = function (str) {
- // Use the native `exec` to skip some processing overhead, even though the altered
- // `exec` would take care of the `lastIndex` fixes
- var match, origLastIndex;
- if (!this.global)
- origLastIndex = this.lastIndex;
- match = nativ.exec.call(this, str);
- // Fix browsers that increment `lastIndex` after zero-length matches
- if (match && !compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index))
- this.lastIndex--;
- if (!this.global)
- this.lastIndex = origLastIndex; // Fix IE, Opera bug (last tested IE 9.0.5, Opera 11.61 on Windows)
- return !!match;
- };
-
- // Adds named capture support and fixes browser bugs in native method
- String.prototype.match = function (regex) {
- if (!XRegExp.isRegExp(regex))
- regex = RegExp(regex); // Native `RegExp`
- if (regex.global) {
- var result = nativ.match.apply(this, arguments);
- regex.lastIndex = 0; // Fix IE bug
- return result;
- }
- return regex.exec(this); // Run the altered `exec`
- };
-
- // Adds support for `${n}` tokens for named and numbered backreferences in replacement text,
- // and provides named backreferences to replacement functions as `arguments[0].name`. Also
- // fixes cross-browser differences in replacement text syntax when performing a replacement
- // using a nonregex search value, and the value of replacement regexes' `lastIndex` property
- // during replacement iterations. Note that this doesn't support SpiderMonkey's proprietary
- // third (`flags`) parameter
- String.prototype.replace = function (search, replacement) {
- var isRegex = XRegExp.isRegExp(search),
- captureNames, result, str, origLastIndex;
-
- // There are too many combinations of search/replacement types/values and browser bugs that
- // preclude passing to native `replace`, so don't try
- //if (...)
- // return nativ.replace.apply(this, arguments);
-
- if (isRegex) {
- if (search._xregexp)
- captureNames = search._xregexp.captureNames; // Array or `null`
- if (!search.global)
- origLastIndex = search.lastIndex;
- } else {
- search = search + ""; // Type conversion
- }
-
- if (Object.prototype.toString.call(replacement) === "[object Function]") {
- result = nativ.replace.call(this + "", search, function () {
- if (captureNames) {
- // Change the `arguments[0]` string primitive to a String object which can store properties
- arguments[0] = new String(arguments[0]);
- // Store named backreferences on `arguments[0]`
- for (var i = 0; i < captureNames.length; i++) {
- if (captureNames[i])
- arguments[0][captureNames[i]] = arguments[i + 1];
- }
- }
- // Update `lastIndex` before calling `replacement` (fix browsers)
- if (isRegex && search.global)
- search.lastIndex = arguments[arguments.length - 2] + arguments[0].length;
- return replacement.apply(null, arguments);
- });
- } else {
- str = this + ""; // Type conversion, so `args[args.length - 1]` will be a string (given nonstring `this`)
- result = nativ.replace.call(str, search, function () {
- var args = arguments; // Keep this function's `arguments` available through closure
- return nativ.replace.call(replacement + "", replacementToken, function ($0, $1, $2) {
- // Numbered backreference (without delimiters) or special variable
- if ($1) {
- switch ($1) {
- case "$": return "$";
- case "&": return args[0];
- case "`": return args[args.length - 1].slice(0, args[args.length - 2]);
- case "'": return args[args.length - 1].slice(args[args.length - 2] + args[0].length);
- // Numbered backreference
- default:
- // What does "$10" mean?
- // - Backreference 10, if 10 or more capturing groups exist
- // - Backreference 1 followed by "0", if 1-9 capturing groups exist
- // - Otherwise, it's the string "$10"
- // Also note:
- // - Backreferences cannot be more than two digits (enforced by `replacementToken`)
- // - "$01" is equivalent to "$1" if a capturing group exists, otherwise it's the string "$01"
- // - There is no "$0" token ("$&" is the entire match)
- var literalNumbers = "";
- $1 = +$1; // Type conversion; drop leading zero
- if (!$1) // `$1` was "0" or "00"
- return $0;
- while ($1 > args.length - 3) {
- literalNumbers = String.prototype.slice.call($1, -1) + literalNumbers;
- $1 = Math.floor($1 / 10); // Drop the last digit
- }
- return ($1 ? args[$1] || "" : "$") + literalNumbers;
- }
- // Named backreference or delimited numbered backreference
- } else {
- // What does "${n}" mean?
- // - Backreference to numbered capture n. Two differences from "$n":
- // - n can be more than two digits
- // - Backreference 0 is allowed, and is the entire match
- // - Backreference to named capture n, if it exists and is not a number overridden by numbered capture
- // - Otherwise, it's the string "${n}"
- var n = +$2; // Type conversion; drop leading zeros
- if (n <= args.length - 3)
- return args[n];
- n = captureNames ? indexOf(captureNames, $2) : -1;
- return n > -1 ? args[n + 1] : $0;
- }
- });
- });
- }
-
- if (isRegex) {
- if (search.global)
- search.lastIndex = 0; // Fix IE, Safari bug (last tested IE 9.0.5, Safari 5.1.2 on Windows)
- else
- search.lastIndex = origLastIndex; // Fix IE, Opera bug (last tested IE 9.0.5, Opera 11.61 on Windows)
- }
-
- return result;
- };
-
- // A consistent cross-browser, ES3 compliant `split`
- String.prototype.split = function (s /* separator */, limit) {
- // If separator `s` is not a regex, use the native `split`
- if (!XRegExp.isRegExp(s))
- return nativ.split.apply(this, arguments);
-
- var str = this + "", // Type conversion
- output = [],
- lastLastIndex = 0,
- match, lastLength;
-
- // Behavior for `limit`: if it's...
- // - `undefined`: No limit
- // - `NaN` or zero: Return an empty array
- // - A positive number: Use `Math.floor(limit)`
- // - A negative number: No limit
- // - Other: Type-convert, then use the above rules
- if (limit === undefined || +limit < 0) {
- limit = Infinity;
- } else {
- limit = Math.floor(+limit);
- if (!limit)
- return [];
- }
-
- // This is required if not `s.global`, and it avoids needing to set `s.lastIndex` to zero
- // and restore it to its original value when we're done using the regex
- s = XRegExp.copyAsGlobal(s);
-
- while (match = s.exec(str)) { // Run the altered `exec` (required for `lastIndex` fix, etc.)
- if (s.lastIndex > lastLastIndex) {
- output.push(str.slice(lastLastIndex, match.index));
-
- if (match.length > 1 && match.index < str.length)
- Array.prototype.push.apply(output, match.slice(1));
-
- lastLength = match[0].length;
- lastLastIndex = s.lastIndex;
-
- if (output.length >= limit)
- break;
- }
-
- if (s.lastIndex === match.index)
- s.lastIndex++;
- }
-
- if (lastLastIndex === str.length) {
- if (!nativ.test.call(s, "") || lastLength)
- output.push("");
- } else {
- output.push(str.slice(lastLastIndex));
- }
-
- return output.length > limit ? output.slice(0, limit) : output;
- };
-
-
- //---------------------------------
- // Private helper functions
- //---------------------------------
-
- // Supporting function for `XRegExp`, `XRegExp.copyAsGlobal`, etc. Returns a copy of a `RegExp`
- // instance with a fresh `lastIndex` (set to zero), preserving properties required for named
- // capture. Also allows adding new flags in the process of copying the regex
- function clone (regex, additionalFlags) {
- if (!XRegExp.isRegExp(regex))
- throw TypeError("type RegExp expected");
- var x = regex._xregexp;
- regex = XRegExp(regex.source, getNativeFlags(regex) + (additionalFlags || ""));
- if (x) {
- regex._xregexp = {
- source: x.source,
- captureNames: x.captureNames ? x.captureNames.slice(0) : null
- };
- }
- return regex;
- }
-
- function getNativeFlags (regex) {
- return (regex.global ? "g" : "") +
- (regex.ignoreCase ? "i" : "") +
- (regex.multiline ? "m" : "") +
- (regex.extended ? "x" : "") + // Proposed for ES4; included in AS3
- (regex.sticky ? "y" : "");
- }
-
- function runTokens (pattern, index, scope, context) {
- var i = tokens.length,
- result, match, t;
- // Protect against constructing XRegExps within token handler and trigger functions
- isInsideConstructor = true;
- // Must reset `isInsideConstructor`, even if a `trigger` or `handler` throws
- try {
- while (i--) { // Run in reverse order
- t = tokens[i];
- if ((scope & t.scope) && (!t.trigger || t.trigger.call(context))) {
- t.pattern.lastIndex = index;
- match = t.pattern.exec(pattern); // Running the altered `exec` here allows use of named backreferences, etc.
- if (match && match.index === index) {
- result = {
- output: t.handler.call(context, match, scope),
- match: match
- };
- break;
- }
- }
- }
- } catch (err) {
- throw err;
- } finally {
- isInsideConstructor = false;
- }
- return result;
- }
-
- function indexOf (array, item, from) {
- if (Array.prototype.indexOf) // Use the native array method if available
- return array.indexOf(item, from);
- for (var i = from || 0; i < array.length; i++) {
- if (array[i] === item)
- return i;
- }
- return -1;
- }
-
-
- //---------------------------------
- // Built-in tokens
- //---------------------------------
-
- // Augment XRegExp's regular expression syntax and flags. Note that when adding tokens, the
- // third (`scope`) argument defaults to `XRegExp.OUTSIDE_CLASS`
-
- // Comment pattern: (?# )
- XRegExp.addToken(
- /\(\?#[^)]*\)/,
- function (match) {
- // Keep tokens separated unless the following token is a quantifier
- return nativ.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)";
- }
- );
-
- // Capturing group (match the opening parenthesis only).
- // Required for support of named capturing groups
- XRegExp.addToken(
- /\((?!\?)/,
- function () {
- this.captureNames.push(null);
- return "(";
- }
- );
-
- // Named capturing group (match the opening delimiter only): (?<name>
- XRegExp.addToken(
- /\(\?<([$\w]+)>/,
- function (match) {
- this.captureNames.push(match[1]);
- this.hasNamedCapture = true;
- return "(";
- }
- );
-
- // Named backreference: \k<name>
- XRegExp.addToken(
- /\\k<([\w$]+)>/,
- function (match) {
- var index = indexOf(this.captureNames, match[1]);
- // Keep backreferences separate from subsequent literal numbers. Preserve back-
- // references to named groups that are undefined at this point as literal strings
- return index > -1 ?
- "\\" + (index + 1) + (isNaN(match.input.charAt(match.index + match[0].length)) ? "" : "(?:)") :
- match[0];
- }
- );
-
- // Empty character class: [] or [^]
- XRegExp.addToken(
- /\[\^?]/,
- function (match) {
- // For cross-browser compatibility with ES3, convert [] to \b\B and [^] to [\s\S].
- // (?!) should work like \b\B, but is unreliable in Firefox
- return match[0] === "[]" ? "\\b\\B" : "[\\s\\S]";
- }
- );
-
- // Mode modifier at the start of the pattern only, with any combination of flags imsx: (?imsx)
- // Does not support x(?i), (?-i), (?i-m), (?i: ), (?i)(?m), etc.
- XRegExp.addToken(
- /^\(\?([imsx]+)\)/,
- function (match) {
- this.setFlag(match[1]);
- return "";
- }
- );
-
- // Whitespace and comments, in free-spacing (aka extended) mode only
- XRegExp.addToken(
- /(?:\s+|#.*)+/,
- function (match) {
- // Keep tokens separated unless the following token is a quantifier
- return nativ.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)";
- },
- XRegExp.OUTSIDE_CLASS,
- function () {return this.hasFlag("x");}
- );
-
- // Dot, in dotall (aka singleline) mode only
- XRegExp.addToken(
- /\./,
- function () {return "[\\s\\S]";},
- XRegExp.OUTSIDE_CLASS,
- function () {return this.hasFlag("s");}
- );
-
-
- //---------------------------------
- // Backward compatibility
- //---------------------------------
-
- // Uncomment the following block for compatibility with XRegExp 1.0-1.2:
- /*
- XRegExp.matchWithinChain = XRegExp.matchChain;
- RegExp.prototype.addFlags = function (s) {return clone(this, s);};
- RegExp.prototype.execAll = function (s) {var r = []; XRegExp.iterate(s, this, function (m) {r.push(m);}); return r;};
- RegExp.prototype.forEachExec = function (s, f, c) {return XRegExp.iterate(s, this, f, c);};
- RegExp.prototype.validate = function (s) {var r = RegExp("^(?:" + this.source + ")$(?!\\s)", getNativeFlags(this)); if (this.global) this.lastIndex = 0; return s.search(r) === 0;};
- */
-
-})();
-
diff --git a/pecan/middleware/resources/__init__.py b/pecan/middleware/resources/__init__.py
deleted file mode 100644
index 2d8c627..0000000
--- a/pecan/middleware/resources/__init__.py
+++ /dev/null
@@ -1,28 +0,0 @@
-import os
-from mimetypes import guess_type
-from contextlib import closing
-from base64 import b64encode
-
-from pecan.compat import quote
-
-
-def load_resource(filename):
- with closing(open(
- os.path.join(
- os.path.dirname(__file__),
- filename
- ),
- 'rb'
- )) as f:
- data = f.read()
- return 'data:%s;base64,%s' % (
- guess_type(filename)[0],
- quote(b64encode(data))
- )
-
-pecan_image = load_resource('pecan.png')
-xregexp_js = load_resource('XRegExp.js')
-syntax_js = load_resource('shCore.js')
-syntax_css = load_resource('syntax.css')
-theme = load_resource('theme.css')
-brush = load_resource('brush-python.js')
diff --git a/pecan/middleware/resources/brush-python.js b/pecan/middleware/resources/brush-python.js
deleted file mode 100644
index 30f0a8f..0000000
--- a/pecan/middleware/resources/brush-python.js
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * SyntaxHighlighter
- * http://alexgorbatchev.com/SyntaxHighlighter
- *
- * SyntaxHighlighter is donationware. If you are using it, please donate.
- * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
- *
- * @version
- * 3.0.83 (July 02 2010)
- *
- * @copyright
- * Copyright (C) 2004-2010 Alex Gorbatchev.
- *
- * @license
- * Dual licensed under the MIT and GPL licenses.
- */
-(function()
-{
- // CommonJS
- typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;
-
- function Brush()
- {
- // Contributed by Gheorghe Milas and Ahmad Sherif
-
- var keywords = 'and assert break class continue def del elif else ' +
- 'except exec finally for from global if import in is ' +
- 'lambda not or pass print raise return try yield while';
-
- var funcs = '__import__ abs all any apply basestring bin bool buffer callable ' +
- 'chr classmethod cmp coerce compile complex delattr dict dir ' +
- 'divmod enumerate eval execfile file filter float format frozenset ' +
- 'getattr globals hasattr hash help hex id input int intern ' +
- 'isinstance issubclass iter len list locals long map max min next ' +
- 'object oct open ord pow print property range raw_input reduce ' +
- 'reload repr reversed round set setattr slice sorted staticmethod ' +
- 'str sum super tuple type type unichr unicode vars xrange zip';
-
- var special = 'None True False self cls class_';
-
- this.regexList = [
- { regex: SyntaxHighlighter.regexLib.singleLinePerlComments, css: 'comments' },
- { regex: /^\s*@\w+/gm, css: 'decorator' },
- { regex: /(['\"]{3})([^\1])*?\1/gm, css: 'comments' },
- { regex: /"(?!")(?:\.|\\\"|[^\""\n])*"/gm, css: 'string' },
- { regex: /'(?!')(?:\.|(\\\')|[^\''\n])*'/gm, css: 'string' },
- { regex: /\+|\-|\*|\/|\%|=|==/gm, css: 'keyword' },
- { regex: /\b\d+\.?\w*/g, css: 'value' },
- { regex: new RegExp(this.getKeywords(funcs), 'gmi'), css: 'functions' },
- { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' },
- { regex: new RegExp(this.getKeywords(special), 'gm'), css: 'color1' }
- ];
-
- this.forHtmlScript(SyntaxHighlighter.regexLib.aspScriptTags);
- };
-
- Brush.prototype = new SyntaxHighlighter.Highlighter();
- Brush.aliases = ['py', 'python'];
-
- SyntaxHighlighter.brushes.Python = Brush;
-
- // CommonJS
- typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
-})();
diff --git a/pecan/middleware/resources/pecan.png b/pecan/middleware/resources/pecan.png
deleted file mode 100644
index 16f2490..0000000
--- a/pecan/middleware/resources/pecan.png
+++ /dev/null
Binary files differ
diff --git a/pecan/middleware/resources/shCore.js b/pecan/middleware/resources/shCore.js
deleted file mode 100644
index 320e0b5..0000000
--- a/pecan/middleware/resources/shCore.js
+++ /dev/null
@@ -1,1731 +0,0 @@
-/**
- * SyntaxHighlighter
- * http://alexgorbatchev.com/SyntaxHighlighter
- *
- * SyntaxHighlighter is donationware. If you are using it, please donate.
- * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
- *
- * @version
- * @VERSION@ (@DATE@)
- *
- * @copyright
- * Copyright (C) 2004-2010 Alex Gorbatchev.
- *
- * @license
- * Dual licensed under the MIT and GPL licenses.
- */
-
-//
-// Begin anonymous function. This is used to contain local scope variables without polutting global scope.
-//
-if (typeof(SyntaxHighlighter) == 'undefined') var SyntaxHighlighter = function() {
-
-// CommonJS
-if (typeof(require) != 'undefined' && typeof(XRegExp) == 'undefined')
-{
- XRegExp = require('XRegExp').XRegExp;
-}
-
-// Shortcut object which will be assigned to the SyntaxHighlighter variable.
-// This is a shorthand for local reference in order to avoid long namespace
-// references to SyntaxHighlighter.whatever...
-var sh = {
- defaults : {
- /** Additional CSS class names to be added to highlighter elements. */
- 'class-name' : '',
-
- /** First line number. */
- 'first-line' : 1,
-
- /**
- * Pads line numbers. Possible values are:
- *
- * false - don't pad line numbers.
- * true - automaticaly pad numbers with minimum required number of leading zeroes.
- * [int] - length up to which pad line numbers.
- */
- 'pad-line-numbers' : false,
-
- /** Lines to highlight. */
- 'highlight' : null,
-
- /** Title to be displayed above the code block. */
- 'title' : null,
-
- /** Enables or disables smart tabs. */
- 'smart-tabs' : true,
-
- /** Gets or sets tab size. */
- 'tab-size' : 4,
-
- /** Enables or disables gutter. */
- 'gutter' : true,
-
- /** Enables or disables toolbar. */
- 'toolbar' : true,
-
- /** Enables quick code copy and paste from double click. */
- 'quick-code' : true,
-
- /** Forces code view to be collapsed. */
- 'collapse' : false,
-
- /** Enables or disables automatic links. */
- 'auto-links' : true,
-
- /** Gets or sets light mode. Equavalent to turning off gutter and toolbar. */
- 'light' : false,
-
- 'unindent' : true,
-
- 'html-script' : false
- },
-
- config : {
- space : '&nbsp;',
-
- /** Enables use of <SCRIPT type="syntaxhighlighter" /> tags. */
- useScriptTags : true,
-
- /** Blogger mode flag. */
- bloggerMode : false,
-
- stripBrs : false,
-
- /** Name of the tag that SyntaxHighlighter will automatically look for. */
- tagName : 'pre',
-
- strings : {
- expandSource : 'expand source',
- help : '?',
- alert: 'SyntaxHighlighter\n\n',
- noBrush : 'Can\'t find brush for: ',
- brushNotHtmlScript : 'Brush wasn\'t configured for html-script option: ',
-
- // this is populated by the build script
- aboutDialog : '@ABOUT@'
- }
- },
-
- /** Internal 'global' variables. */
- vars : {
- discoveredBrushes : null,
- highlighters : {}
- },
-
- /** This object is populated by user included external brush files. */
- brushes : {},
-
- /** Common regular expressions. */
- regexLib : {
- multiLineCComments : /\/\*[\s\S]*?\*\//gm,
- singleLineCComments : /\/\/.*$/gm,
- singleLinePerlComments : /#.*$/gm,
- doubleQuotedString : /"([^\\"\n]|\\.)*"/g,
- singleQuotedString : /'([^\\'\n]|\\.)*'/g,
- multiLineDoubleQuotedString : new XRegExp('"([^\\\\"]|\\\\.)*"', 'gs'),
- multiLineSingleQuotedString : new XRegExp("'([^\\\\']|\\\\.)*'", 'gs'),
- xmlComments : /(&lt;|<)!--[\s\S]*?--(&gt;|>)/gm,
- url : /\w+:\/\/[\w-.\/?%&=:@;#]*/g,
-
- /** <?= ?> tags. */
- phpScriptTags : { left: /(&lt;|<)\?(?:=|php)?/g, right: /\?(&gt;|>)/g, 'eof' : true },
-
- /** <%= %> tags. */
- aspScriptTags : { left: /(&lt;|<)%=?/g, right: /%(&gt;|>)/g },
-
- /** <script> tags. */
- scriptScriptTags : { left: /(&lt;|<)\s*script.*?(&gt;|>)/gi, right: /(&lt;|<)\/\s*script\s*(&gt;|>)/gi }
- },
-
- toolbar: {
- /**
- * Generates HTML markup for the toolbar.
- * @param {Highlighter} highlighter Highlighter instance.
- * @return {String} Returns HTML markup.
- */
- getHtml: function(highlighter)
- {
- var html = '<div class="toolbar">',
- items = sh.toolbar.items,
- list = items.list
- ;
-
- function defaultGetHtml(highlighter, name)
- {
- return sh.toolbar.getButtonHtml(highlighter, name, sh.config.strings[name]);
- };
-
- for (var i = 0; i < list.length; i++)
- html += (items[list[i]].getHtml || defaultGetHtml)(highlighter, list[i]);
-
- html += '</div>';
-
- return html;
- },
-
- /**
- * Generates HTML markup for a regular button in the toolbar.
- * @param {Highlighter} highlighter Highlighter instance.
- * @param {String} commandName Command name that would be executed.
- * @param {String} label Label text to display.
- * @return {String} Returns HTML markup.
- */
- getButtonHtml: function(highlighter, commandName, label)
- {
- return '<span><a href="#" class="toolbar_item'
- + ' command_' + commandName
- + ' ' + commandName
- + '">' + label + '</a></span>'
- ;
- },
-
- /**
- * Event handler for a toolbar anchor.
- */
- handler: function(e)
- {
- var target = e.target,
- className = target.className || ''
- ;
-
- function getValue(name)
- {
- var r = new RegExp(name + '_(\\w+)'),
- match = r.exec(className)
- ;
-
- return match ? match[1] : null;
- };
-
- var highlighter = getHighlighterById(findParentElement(target, '.syntaxhighlighter').id),
- commandName = getValue('command')
- ;
-
- // execute the toolbar command
- if (highlighter && commandName)
- sh.toolbar.items[commandName].execute(highlighter);
-
- // disable default A click behaviour
- e.preventDefault();
- },
-
- /** Collection of toolbar items. */
- items : {
- // Ordered lis of items in the toolbar. Can't expect `for (var n in items)` to be consistent.
- list: ['expandSource', 'help'],
-
- expandSource: {
- getHtml: function(highlighter)
- {
- if (highlighter.getParam('collapse') != true)
- return '';
-
- var title = highlighter.getParam('title');
- return sh.toolbar.getButtonHtml(highlighter, 'expandSource', title ? title : sh.config.strings.expandSource);
- },
-
- execute: function(highlighter)
- {
- var div = getHighlighterDivById(highlighter.id);
- removeClass(div, 'collapsed');
- }
- },
-
- /** Command to display the about dialog window. */
- help: {
- execute: function(highlighter)
- {
- var wnd = popup('', '_blank', 500, 250, 'scrollbars=0'),
- doc = wnd.document
- ;
-
- doc.write(sh.config.strings.aboutDialog);
- doc.close();
- wnd.focus();
- }
- }
- }
- },
-
- /**
- * Finds all elements on the page which should be processes by SyntaxHighlighter.
- *
- * @param {Object} globalParams Optional parameters which override element's
- * parameters. Only used if element is specified.
- *
- * @param {Object} element Optional element to highlight. If none is
- * provided, all elements in the current document
- * are returned which qualify.
- *
- * @return {Array} Returns list of <code>{ target: DOMElement, params: Object }</code> objects.
- */
- findElements: function(globalParams, element)
- {
- var elements = element ? [element] : toArray(document.getElementsByTagName(sh.config.tagName)),
- conf = sh.config,
- result = []
- ;
-
- // support for <SCRIPT TYPE="syntaxhighlighter" /> feature
- if (conf.useScriptTags)
- elements = elements.concat(getSyntaxHighlighterScriptTags());
-
- if (elements.length === 0)
- return result;
-
- for (var i = 0; i < elements.length; i++)
- {
- var item = {
- target: elements[i],
- // local params take precedence over globals
- params: merge(globalParams, parseParams(elements[i].className))
- };
-
- if (item.params['brush'] == null)
- continue;
-
- result.push(item);
- }
-
- return result;
- },
-
- /**
- * Shorthand to highlight all elements on the page that are marked as
- * SyntaxHighlighter source code.
- *
- * @param {Object} globalParams Optional parameters which override element's
- * parameters. Only used if element is specified.
- *
- * @param {Object} element Optional element to highlight. If none is
- * provided, all elements in the current document
- * are highlighted.
- */
- highlight: function(globalParams, element)
- {
- var elements = this.findElements(globalParams, element),
- propertyName = 'innerHTML',
- highlighter = null,
- conf = sh.config
- ;
-
- if (elements.length === 0)
- return;
-
- for (var i = 0; i < elements.length; i++)
- {
- var element = elements[i],
- target = element.target,
- params = element.params,
- brushName = params.brush,
- code
- ;
-
- if (brushName == null)
- continue;
-
- // Instantiate a brush
- if (params['html-script'] == 'true' || sh.defaults['html-script'] == true)
- {
- highlighter = new sh.HtmlScript(brushName);
- brushName = 'htmlscript';
- }
- else
- {
- var brush = findBrush(brushName);
-
- if (brush)
- highlighter = new brush();
- else
- continue;
- }
-
- code = target[propertyName];
-
- // remove CDATA from <SCRIPT/> tags if it's present
- if (conf.useScriptTags)
- code = stripCData(code);
-
- // Inject title if the attribute is present
- if ((target.title || '') != '')
- params.title = target.title;
-
- params['brush'] = brushName;
- highlighter.init(params);
- element = highlighter.getDiv(code);
-
- // carry over ID
- if ((target.id || '') != '')
- element.id = target.id;
-
- target.parentNode.replaceChild(element, target);
- }
- },
-
- /**
- * Main entry point for the SyntaxHighlighter.
- * @param {Object} params Optional params to apply to all highlighted elements.
- */
- all: function(params)
- {
- attachEvent(
- window,
- 'load',
- function() { sh.highlight(params); }
- );
- }
-}; // end of sh
-
-/**
- * Checks if target DOM elements has specified CSS class.
- * @param {DOMElement} target Target DOM element to check.
- * @param {String} className Name of the CSS class to check for.
- * @return {Boolean} Returns true if class name is present, false otherwise.
- */
-function hasClass(target, className)
-{
- return target.className.indexOf(className) != -1;
-};
-
-/**
- * Adds CSS class name to the target DOM element.
- * @param {DOMElement} target Target DOM element.
- * @param {String} className New CSS class to add.
- */
-function addClass(target, className)
-{
- if (!hasClass(target, className))
- target.className += ' ' + className;
-};
-
-/**
- * Removes CSS class name from the target DOM element.
- * @param {DOMElement} target Target DOM element.
- * @param {String} className CSS class to remove.
- */
-function removeClass(target, className)
-{
- target.className = target.className.replace(className, '');
-};
-
-/**
- * Converts the source to array object. Mostly used for function arguments and
- * lists returned by getElementsByTagName() which aren't Array objects.
- * @param {List} source Source list.
- * @return {Array} Returns array.
- */
-function toArray(source)
-{
- var result = [];
-
- for (var i = 0; i < source.length; i++)
- result.push(source[i]);
-
- return result;
-};
-
-/**
- * Splits block of text into lines.
- * @param {String} block Block of text.
- * @return {Array} Returns array of lines.
- */
-function splitLines(block)
-{
- return block.split(/\r?\n/);
-}
-
-/**
- * Generates HTML ID for the highlighter.
- * @param {String} highlighterId Highlighter ID.
- * @return {String} Returns HTML ID.
- */
-function getHighlighterId(id)
-{
- var prefix = 'highlighter_';
- return id.indexOf(prefix) == 0 ? id : prefix + id;
-};
-
-/**
- * Finds Highlighter instance by ID.
- * @param {String} highlighterId Highlighter ID.
- * @return {Highlighter} Returns instance of the highlighter.
- */
-function getHighlighterById(id)
-{
- return sh.vars.highlighters[getHighlighterId(id)];
-};
-
-/**
- * Finds highlighter's DIV container.
- * @param {String} highlighterId Highlighter ID.
- * @return {Element} Returns highlighter's DIV element.
- */
-function getHighlighterDivById(id)
-{
- return document.getElementById(getHighlighterId(id));
-};
-
-/**
- * Stores highlighter so that getHighlighterById() can do its thing. Each
- * highlighter must call this method to preserve itself.
- * @param {Highilghter} highlighter Highlighter instance.
- */
-function storeHighlighter(highlighter)
-{
- sh.vars.highlighters[getHighlighterId(highlighter.id)] = highlighter;
-};
-
-/**
- * Looks for a child or parent node which has specified classname.
- * Equivalent to jQuery's $(container).find(".className")
- * @param {Element} target Target element.
- * @param {String} search Class name or node name to look for.
- * @param {Boolean} reverse If set to true, will go up the node tree instead of down.
- * @return {Element} Returns found child or parent element on null.
- */
-function findElement(target, search, reverse /* optional */)
-{
- if (target == null)
- return null;
-
- var nodes = reverse != true ? target.childNodes : [ target.parentNode ],
- propertyToFind = { '#' : 'id', '.' : 'className' }[search.substr(0, 1)] || 'nodeName',
- expectedValue,
- found
- ;
-
- expectedValue = propertyToFind != 'nodeName'
- ? search.substr(1)
- : search.toUpperCase()
- ;
-
- // main return of the found node
- if ((target[propertyToFind] || '').indexOf(expectedValue) != -1)
- return target;
-
- for (var i = 0; nodes && i < nodes.length && found == null; i++)
- found = findElement(nodes[i], search, reverse);
-
- return found;
-};
-
-/**
- * Looks for a parent node which has specified classname.
- * This is an alias to <code>findElement(container, className, true)</code>.
- * @param {Element} target Target element.
- * @param {String} className Class name to look for.
- * @return {Element} Returns found parent element on null.
- */
-function findParentElement(target, className)
-{
- return findElement(target, className, true);
-};
-
-/**
- * Finds an index of element in the array.
- * @ignore
- * @param {Object} searchElement
- * @param {Number} fromIndex
- * @return {Number} Returns index of element if found; -1 otherwise.
- */
-function indexOf(array, searchElement, fromIndex)
-{
- fromIndex = Math.max(fromIndex || 0, 0);
-
- for (var i = fromIndex; i < array.length; i++)
- if(array[i] == searchElement)
- return i;
-
- return -1;
-};
-
-/**
- * Generates a unique element ID.
- */
-function guid(prefix)
-{
- return (prefix || '') + Math.round(Math.random() * 1000000).toString();
-};
-
-/**
- * Merges two objects. Values from obj2 override values in obj1.
- * Function is NOT recursive and works only for one dimensional objects.
- * @param {Object} obj1 First object.
- * @param {Object} obj2 Second object.
- * @return {Object} Returns combination of both objects.
- */
-function merge(obj1, obj2)
-{
- var result = {}, name;
-
- for (name in obj1)
- result[name] = obj1[name];
-
- for (name in obj2)
- result[name] = obj2[name];
-
- return result;
-};
-
-/**
- * Attempts to convert string to boolean.
- * @param {String} value Input string.
- * @return {Boolean} Returns true if input was "true", false if input was "false" and value otherwise.
- */
-function toBoolean(value)
-{
- var result = { "true" : true, "false" : false }[value];
- return result == null ? value : result;
-};
-
-/**
- * Opens up a centered popup window.
- * @param {String} url URL to open in the window.
- * @param {String} name Popup name.
- * @param {int} width Popup width.
- * @param {int} height Popup height.
- * @param {String} options window.open() options.
- * @return {Window} Returns window instance.
- */
-function popup(url, name, width, height, options)
-{
- var x = (screen.width - width) / 2,
- y = (screen.height - height) / 2
- ;
-
- options += ', left=' + x +
- ', top=' + y +
- ', width=' + width +
- ', height=' + height
- ;
- options = options.replace(/^,/, '');
-
- var win = window.open(url, name, options);
- win.focus();
- return win;
-};
-
-/**
- * Adds event handler to the target object.
- * @param {Object} obj Target object.
- * @param {String} type Name of the event.
- * @param {Function} func Handling function.
- */
-function attachEvent(obj, type, func, scope)
-{
- function handler(e)
- {
- e = e || window.event;
-
- if (!e.target)
- {
- e.target = e.srcElement;
- e.preventDefault = function()
- {
- this.returnValue = false;
- };
- }
-
- func.call(scope || window, e);
- };
-
- if (obj.attachEvent)
- {
- obj.attachEvent('on' + type, handler);
- }
- else
- {
- obj.addEventListener(type, handler, false);
- }
-};
-
-/**
- * Displays an alert.
- * @param {String} str String to display.
- */
-function alert(str)
-{
- window.alert(sh.config.strings.alert + str);
-};
-
-/**
- * Finds a brush by its alias.
- *
- * @param {String} alias Brush alias.
- * @param {Boolean} showAlert Suppresses the alert if false.
- * @return {Brush} Returns bursh constructor if found, null otherwise.
- */
-function findBrush(alias, showAlert)
-{
- var brushes = sh.vars.discoveredBrushes,
- result = null
- ;
-
- if (brushes == null)
- {
- brushes = {};
-
- // Find all brushes
- for (var brush in sh.brushes)
- {
- var info = sh.brushes[brush],
- aliases = info.aliases
- ;
-
- if (aliases == null)
- continue;
-
- // keep the brush name
- info.brushName = brush.toLowerCase();
-
- for (var i = 0; i < aliases.length; i++)
- brushes[aliases[i]] = brush;
- }
-
- sh.vars.discoveredBrushes = brushes;
- }
-
- result = sh.brushes[brushes[alias]];
-
- if (result == null && showAlert)
- alert(sh.config.strings.noBrush + alias);
-
- return result;
-};
-
-/**
- * Executes a callback on each line and replaces each line with result from the callback.
- * @param {Object} str Input string.
- * @param {Object} callback Callback function taking one string argument and returning a string.
- */
-function eachLine(str, callback)
-{
- var lines = splitLines(str);
-
- for (var i = 0; i < lines.length; i++)
- lines[i] = callback(lines[i], i);
-
- // include \r to enable copy-paste on windows (ie8) without getting everything on one line
- return lines.join('\r\n');
-};
-
-/**
- * This is a special trim which only removes first and last empty lines
- * and doesn't affect valid leading space on the first line.
- *
- * @param {String} str Input string
- * @return {String} Returns string without empty first and last lines.
- */
-function trimFirstAndLastLines(str)
-{
- return str.replace(/^[ ]*[\n]+|[\n]*[ ]*$/g, '');
-};
-
-/**
- * Parses key/value pairs into hash object.
- *
- * Understands the following formats:
- * - name: word;
- * - name: [word, word];
- * - name: "string";
- * - name: 'string';
- *
- * For example:
- * name1: value; name2: [value, value]; name3: 'value'
- *
- * @param {String} str Input string.
- * @return {Object} Returns deserialized object.
- */
-function parseParams(str)
-{
- var match,
- result = {},
- arrayRegex = new XRegExp("^\\[(?<values>(.*?))\\]$"),
- regex = new XRegExp(
- "(?<name>[\\w-]+)" +
- "\\s*:\\s*" +
- "(?<value>" +
- "[\\w-%#]+|" + // word
- "\\[.*?\\]|" + // [] array
- '".*?"|' + // "" string
- "'.*?'" + // '' string
- ")\\s*;?",
- "g"
- )
- ;
-
- while ((match = regex.exec(str)) != null)
- {
- var value = match.value
- .replace(/^['"]|['"]$/g, '') // strip quotes from end of strings
- ;
-
- // try to parse array value
- if (value != null && arrayRegex.test(value))
- {
- var m = arrayRegex.exec(value);
- value = m.values.length > 0 ? m.values.split(/\s*,\s*/) : [];
- }
-
- result[match.name] = value;
- }
-
- return result;
-};
-
-/**
- * Wraps each line of the string into <code/> tag with given style applied to it.
- *
- * @param {String} str Input string.
- * @param {String} css Style name to apply to the string.
- * @return {String} Returns input string with each line surrounded by <span/> tag.
- */
-function wrapLinesWithCode(str, css)
-{
- if (str == null || str.length == 0 || str == '\n')
- return str;
-
- str = str.replace(/</g, '&lt;');
-
- // Replace two or more sequential spaces with &nbsp; leaving last space untouched.
- str = str.replace(/ {2,}/g, function(m)
- {
- var spaces = '';
-
- for (var i = 0; i < m.length - 1; i++)
- spaces += sh.config.space;
-
- return spaces + ' ';
- });
-
- // Split each line and apply <span class="...">...</span> to them so that
- // leading spaces aren't included.
- if (css != null)
- str = eachLine(str, function(line)
- {
- if (line.length == 0)
- return '';
-
- var spaces = '';
-
- line = line.replace(/^(&nbsp;| )+/, function(s)
- {
- spaces = s;
- return '';
- });
-
- if (line.length == 0)
- return spaces;
-
- return spaces + '<code class="' + css + '">' + line + '</code>';
- });
-
- return str;
-};
-
-/**
- * Pads number with zeros until it's length is the same as given length.
- *
- * @param {Number} number Number to pad.
- * @param {Number} length Max string length with.
- * @return {String} Returns a string padded with proper amount of '0'.
- */
-function padNumber(number, length)
-{
- var result = number.toString();
-
- while (result.length < length)
- result = '0' + result;
-
- return result;
-};
-
-/**
- * Replaces tabs with spaces.
- *
- * @param {String} code Source code.
- * @param {Number} tabSize Size of the tab.
- * @return {String} Returns code with all tabs replaces by spaces.
- */
-function processTabs(code, tabSize)
-{
- var tab = '';
-
- for (var i = 0; i < tabSize; i++)
- tab += ' ';
-
- return code.replace(/\t/g, tab);
-};
-
-/**
- * Replaces tabs with smart spaces.
- *
- * @param {String} code Code to fix the tabs in.
- * @param {Number} tabSize Number of spaces in a column.
- * @return {String} Returns code with all tabs replaces with roper amount of spaces.
- */
-function processSmartTabs(code, tabSize)
-{
- var lines = splitLines(code),
- tab = '\t',
- spaces = ''
- ;
-
- // Create a string with 1000 spaces to copy spaces from...
- // It's assumed that there would be no indentation longer than that.
- for (var i = 0; i < 50; i++)
- spaces += ' '; // 20 spaces * 50
-
- // This function inserts specified amount of spaces in the string
- // where a tab is while removing that given tab.
- function insertSpaces(line, pos, count)
- {
- return line.substr(0, pos)
- + spaces.substr(0, count)
- + line.substr(pos + 1, line.length) // pos + 1 will get rid of the tab
- ;
- };
-
- // Go through all the lines and do the 'smart tabs' magic.
- code = eachLine(code, function(line)
- {
- if (line.indexOf(tab) == -1)
- return line;
-
- var pos = 0;
-
- while ((pos = line.indexOf(tab)) != -1)
- {
- // This is pretty much all there is to the 'smart tabs' logic.
- // Based on the position within the line and size of a tab,
- // calculate the amount of spaces we need to insert.
- var spaces = tabSize - pos % tabSize;
- line = insertSpaces(line, pos, spaces);
- }
-
- return line;
- });
-
- return code;
-};
-
-/**
- * Performs various string fixes based on configuration.
- */
-function fixInputString(str)
-{
- var br = /<br\s*\/?>|&lt;br\s*\/?&gt;/gi;
-
- if (sh.config.bloggerMode == true)
- str = str.replace(br, '\n');
-
- if (sh.config.stripBrs == true)
- str = str.replace(br, '');
-
- return str;
-};
-
-/**
- * Removes all white space at the beginning and end of a string.
- *
- * @param {String} str String to trim.
- * @return {String} Returns string without leading and following white space characters.
- */
-function trim(str)
-{
- return str.replace(/^\s+|\s+$/g, '');
-};
-
-/**
- * Unindents a block of text by the lowest common indent amount.
- * @param {String} str Text to unindent.
- * @return {String} Returns unindented text block.
- */
-function unindent(str)
-{
- var lines = splitLines(fixInputString(str)),
- indents = new Array(),
- regex = /^\s*/,
- min = 1000
- ;
-
- // go through every line and check for common number of indents
- for (var i = 0; i < lines.length && min > 0; i++)
- {
- var line = lines[i];
-
- if (trim(line).length == 0)
- continue;
-
- var matches = regex.exec(line);
-
- // In the event that just one line doesn't have leading white space
- // we can't unindent anything, so bail completely.
- if (matches == null)
- return str;
-
- min = Math.min(matches[0].length, min);
- }
-
- // trim minimum common number of white space from the beginning of every line
- if (min > 0)
- for (var i = 0; i < lines.length; i++)
- lines[i] = lines[i].substr(min);
-
- return lines.join('\n');
-};
-
-/**
- * Callback method for Array.sort() which sorts matches by
- * index position and then by length.
- *
- * @param {Match} m1 Left object.
- * @param {Match} m2 Right object.
- * @return {Number} Returns -1, 0 or -1 as a comparison result.
- */
-function matchesSortCallback(m1, m2)
-{
- // sort matches by index first
- if(m1.index < m2.index)
- return -1;
- else if(m1.index > m2.index)
- return 1;
- else
- {
- // if index is the same, sort by length
- if(m1.length < m2.length)
- return -1;
- else if(m1.length > m2.length)
- return 1;
- }
-
- return 0;
-};
-
-/**
- * Executes given regular expression on provided code and returns all
- * matches that are found.
- *
- * @param {String} code Code to execute regular expression on.
- * @param {Object} regex Regular expression item info from <code>regexList</code> collection.
- * @return {Array} Returns a list of Match objects.
- */
-function getMatches(code, regexInfo)
-{
- function defaultAdd(match, regexInfo)
- {
- return match[0];
- };
-
- var index = 0,
- match = null,
- matches = [],
- func = regexInfo.func ? regexInfo.func : defaultAdd
- ;
-
- while((match = regexInfo.regex.exec(code)) != null)
- {
- var resultMatch = func(match, regexInfo);
-
- if (typeof(resultMatch) == 'string')
- resultMatch = [new sh.Match(resultMatch, match.index, regexInfo.css)];
-
- matches = matches.concat(resultMatch);
- }
-
- return matches;
-};
-
-/**
- * Turns all URLs in the code into <a/> tags.
- * @param {String} code Input code.
- * @return {String} Returns code with </a> tags.
- */
-function processUrls(code)
-{
- var gt = /(.*)((&gt;|&lt;).*)/;
-
- return code.replace(sh.regexLib.url, function(m)
- {
- var suffix = '',
- match = null
- ;
-
- // We include &lt; and &gt; in the URL for the common cases like <http://google.com>
- // The problem is that they get transformed into &lt;http://google.com&gt;
- // Where as &gt; easily looks like part of the URL string.
-
- if (match = gt.exec(m))
- {
- m = match[1];
- suffix = match[2];
- }
-
- return '<a href="' + m + '">' + m + '</a>' + suffix;
- });
-};
-
-/**
- * Finds all <SCRIPT TYPE="syntaxhighlighter" /> elementss.
- * @return {Array} Returns array of all found SyntaxHighlighter tags.
- */
-function getSyntaxHighlighterScriptTags()
-{
- var tags = document.getElementsByTagName('script'),
- result = []
- ;
-
- for (var i = 0; i < tags.length; i++)
- if (tags[i].type == 'syntaxhighlighter')
- result.push(tags[i]);
-
- return result;
-};
-
-/**
- * Strips <![CDATA[]]> from <SCRIPT /> content because it should be used
- * there in most cases for XHTML compliance.
- * @param {String} original Input code.
- * @return {String} Returns code without leading <![CDATA[]]> tags.
- */
-function stripCData(original)
-{
- var left = '<![CDATA[',
- right = ']]>',
- // for some reason IE inserts some leading blanks here
- copy = trim(original),
- changed = false,
- leftLength = left.length,
- rightLength = right.length
- ;
-
- if (copy.indexOf(left) == 0)
- {
- copy = copy.substring(leftLength);
- changed = true;
- }
-
- var copyLength = copy.length;
-
- if (copy.indexOf(right) == copyLength - rightLength)
- {
- copy = copy.substring(0, copyLength - rightLength);
- changed = true;
- }
-
- return changed ? copy : original;
-};
-
-
-/**
- * Quick code mouse double click handler.
- */
-function quickCodeHandler(e)
-{
- var target = e.target,
- highlighterDiv = findParentElement(target, '.syntaxhighlighter'),
- container = findParentElement(target, '.container'),
- textarea = document.createElement('textarea'),
- highlighter
- ;
-
- if (!container || !highlighterDiv || findElement(container, 'textarea'))
- return;
-
- highlighter = getHighlighterById(highlighterDiv.id);
-
- // add source class name
- addClass(highlighterDiv, 'source');
-
- // Have to go over each line and grab it's text, can't just do it on the
- // container because Firefox loses all \n where as Webkit doesn't.
- var lines = container.childNodes,
- code = []
- ;
-
- for (var i = 0; i < lines.length; i++)
- code.push(lines[i].innerText || lines[i].textContent);
-
- // using \r instead of \r or \r\n makes this work equally well on IE, FF and Webkit
- code = code.join('\r');
-
- // For Webkit browsers, replace nbsp with a breaking space
- code = code.replace(/\u00a0/g, " ");
-
- // inject <textarea/> tag
- textarea.appendChild(document.createTextNode(code));
- container.appendChild(textarea);
-
- // preselect all text
- textarea.focus();
- textarea.select();
-
- // set up handler for lost focus
- attachEvent(textarea, 'blur', function(e)
- {
- textarea.parentNode.removeChild(textarea);
- removeClass(highlighterDiv, 'source');
- });
-};
-
-/**
- * Match object.
- */
-sh.Match = function(value, index, css)
-{
- this.value = value;
- this.index = index;
- this.length = value.length;
- this.css = css;
- this.brushName = null;
-};
-
-sh.Match.prototype.toString = function()
-{
- return this.value;
-};
-
-/**
- * Simulates HTML code with a scripting language embedded.
- *
- * @param {String} scriptBrushName Brush name of the scripting language.
- */
-sh.HtmlScript = function(scriptBrushName)
-{
- var brushClass = findBrush(scriptBrushName),
- scriptBrush,
- xmlBrush = new sh.brushes.Xml(),
- bracketsRegex = null,
- ref = this,
- methodsToExpose = 'getDiv getHtml init'.split(' ')
- ;
-
- if (brushClass == null)
- return;
-
- scriptBrush = new brushClass();
-
- for(var i = 0; i < methodsToExpose.length; i++)
- // make a closure so we don't lose the name after i changes
- (function() {
- var name = methodsToExpose[i];
-
- ref[name] = function()
- {
- return xmlBrush[name].apply(xmlBrush, arguments);
- };
- })();
-
- if (scriptBrush.htmlScript == null)
- {
- alert(sh.config.strings.brushNotHtmlScript + scriptBrushName);
- return;
- }
-
- xmlBrush.regexList.push(
- { regex: scriptBrush.htmlScript.code, func: process }
- );
-
- function offsetMatches(matches, offset)
- {
- for (var j = 0; j < matches.length; j++)
- matches[j].index += offset;
- }
-
- function process(match, info)
- {
- var code = match.code,
- matches = [],
- regexList = scriptBrush.regexList,
- offset = match.index + match.left.length,
- htmlScript = scriptBrush.htmlScript,
- result
- ;
-
- // add all matches from the code
- for (var i = 0; i < regexList.length; i++)
- {
- result = getMatches(code, regexList[i]);
- offsetMatches(result, offset);
- matches = matches.concat(result);
- }
-
- // add left script bracket
- if (htmlScript.left != null && match.left != null)
- {
- result = getMatches(match.left, htmlScript.left);
- offsetMatches(result, match.index);
- matches = matches.concat(result);
- }
-
- // add right script bracket
- if (htmlScript.right != null && match.right != null)
- {
- result = getMatches(match.right, htmlScript.right);
- offsetMatches(result, match.index + match[0].lastIndexOf(match.right));
- matches = matches.concat(result);
- }
-
- for (var j = 0; j < matches.length; j++)
- matches[j].brushName = brushClass.brushName;
-
- return matches;
- }
-};
-
-/**
- * Main Highlither class.
- * @constructor
- */
-sh.Highlighter = function()
-{
- // not putting any code in here because of the prototype inheritance
-};
-
-sh.Highlighter.prototype = {
- /**
- * Returns value of the parameter passed to the highlighter.
- * @param {String} name Name of the parameter.
- * @param {Object} defaultValue Default value.
- * @return {Object} Returns found value or default value otherwise.
- */
- getParam: function(name, defaultValue)
- {
- var result = this.params[name];
- return toBoolean(result == null ? defaultValue : result);
- },
-
- /**
- * Shortcut to document.createElement().
- * @param {String} name Name of the element to create (DIV, A, etc).
- * @return {HTMLElement} Returns new HTML element.
- */
- create: function(name)
- {
- return document.createElement(name);
- },
-
- /**
- * Applies all regular expression to the code and stores all found
- * matches in the `this.matches` array.
- * @param {Array} regexList List of regular expressions.
- * @param {String} code Source code.
- * @return {Array} Returns list of matches.
- */
- findMatches: function(regexList, code)
- {
- var result = [];
-
- if (regexList != null)
- for (var i = 0; i < regexList.length; i++)
- // BUG: length returns len+1 for array if methods added to prototype chain (oising@gmail.com)
- if (typeof (regexList[i]) == "object")
- result = result.concat(getMatches(code, regexList[i]));
-
- // sort and remove nested the matches
- return this.removeNestedMatches(result.sort(matchesSortCallback));
- },
-
- /**
- * Checks to see if any of the matches are inside of other matches.
- * This process would get rid of highligted strings inside comments,
- * keywords inside strings and so on.
- */
- removeNestedMatches: function(matches)
- {
- // Optimized by Jose Prado (http://joseprado.com)
- for (var i = 0; i < matches.length; i++)
- {
- if (matches[i] === null)
- continue;
-
- var itemI = matches[i],
- itemIEndPos = itemI.index + itemI.length
- ;
-
- for (var j = i + 1; j < matches.length && matches[i] !== null; j++)
- {
- var itemJ = matches[j];
-
- if (itemJ === null)
- continue;
- else if (itemJ.index > itemIEndPos)
- break;
- else if (itemJ.index == itemI.index && itemJ.length > itemI.length)
- matches[i] = null;
- else if (itemJ.index >= itemI.index && itemJ.index < itemIEndPos)
- matches[j] = null;
- }
- }
-
- return matches;
- },
-
- /**
- * Creates an array containing integer line numbers starting from the 'first-line' param.
- * @return {Array} Returns array of integers.
- */
- figureOutLineNumbers: function(code)
- {
- var lines = [],
- firstLine = parseInt(this.getParam('first-line'))
- ;
-
- eachLine(code, function(line, index)
- {
- lines.push(index + firstLine);
- });
-
- return lines;
- },
-
- /**
- * Determines if specified line number is in the highlighted list.
- */
- isLineHighlighted: function(lineNumber)
- {
- var list = this.getParam('highlight', []);
-
- if (typeof(list) != 'object' && list.push == null)
- list = [ list ];
-
- return indexOf(list, lineNumber.toString()) != -1;
- },
-
- /**
- * Generates HTML markup for a single line of code while determining alternating line style.
- * @param {Integer} lineNumber Line number.
- * @param {String} code Line HTML markup.
- * @return {String} Returns HTML markup.
- */
- getLineHtml: function(lineIndex, lineNumber, code)
- {
- var classes = [
- 'line',
- 'number' + lineNumber,
- 'index' + lineIndex,
- 'alt' + (lineNumber % 2 == 0 ? 1 : 2).toString()
- ];
-
- if (this.isLineHighlighted(lineNumber))
- classes.push('highlighted');
-
- if (lineNumber == 0)
- classes.push('break');
-
- return '<div class="' + classes.join(' ') + '">' + code + '</div>';
- },
-
- /**
- * Generates HTML markup for line number column.
- * @param {String} code Complete code HTML markup.
- * @param {Array} lineNumbers Calculated line numbers.
- * @return {String} Returns HTML markup.
- */
- getLineNumbersHtml: function(code, lineNumbers)
- {
- var html = '',
- count = splitLines(code).length,
- firstLine = parseInt(this.getParam('first-line')),
- pad = this.getParam('pad-line-numbers')
- ;
-
- if (pad == true)
- pad = (firstLine + count - 1).toString().length;
- else if (isNaN(pad) == true)
- pad = 0;
-
- for (var i = 0; i < count; i++)
- {
- var lineNumber = lineNumbers ? lineNumbers[i] : firstLine + i,
- code = lineNumber == 0 ? sh.config.space : padNumber(lineNumber, pad)
- ;
-
- html += this.getLineHtml(i, lineNumber, code);
- }
-
- return html;
- },
-
- /**
- * Splits block of text into individual DIV lines.
- * @param {String} code Code to highlight.
- * @param {Array} lineNumbers Calculated line numbers.
- * @return {String} Returns highlighted code in HTML form.
- */
- getCodeLinesHtml: function(html, lineNumbers)
- {
- html = trim(html);
-
- var lines = splitLines(html),
- padLength = this.getParam('pad-line-numbers'),
- firstLine = parseInt(this.getParam('first-line')),
- html = '',
- brushName = this.getParam('brush')
- ;
-
- for (var i = 0; i < lines.length; i++)
- {
- var line = lines[i],
- indent = /^(&nbsp;|\s)+/.exec(line),
- spaces = null,
- lineNumber = lineNumbers ? lineNumbers[i] : firstLine + i;
- ;
-
- if (indent != null)
- {
- spaces = indent[0].toString();
- line = line.substr(spaces.length);
- spaces = spaces.replace(' ', sh.config.space);
- }
-
- line = trim(line);
-
- if (line.length == 0)
- line = sh.config.space;
-
- html += this.getLineHtml(
- i,
- lineNumber,
- (spaces != null ? '<code class="' + brushName + ' spaces">' + spaces + '</code>' : '') + line
- );
- }
-
- return html;
- },
-
- /**
- * Returns HTML for the table title or empty string if title is null.
- */
- getTitleHtml: function(title)
- {
- return title ? '<caption>' + title + '</caption>' : '';
- },
-
- /**
- * Finds all matches in the source code.
- * @param {String} code Source code to process matches in.
- * @param {Array} matches Discovered regex matches.
- * @return {String} Returns formatted HTML with processed mathes.
- */
- getMatchesHtml: function(code, matches)
- {
- var pos = 0,
- result = '',
- brushName = this.getParam('brush', '')
- ;
-
- function getBrushNameCss(match)
- {
- var result = match ? (match.brushName || brushName) : brushName;
- return result ? result + ' ' : '';
- };
-
- // Finally, go through the final list of matches and pull the all
- // together adding everything in between that isn't a match.
- for (var i = 0; i < matches.length; i++)
- {
- var match = matches[i],
- matchBrushName
- ;
-
- if (match === null || match.length === 0)
- continue;
-
- matchBrushName = getBrushNameCss(match);
-
- result += wrapLinesWithCode(code.substr(pos, match.index - pos), matchBrushName + 'plain')
- + wrapLinesWithCode(match.value, matchBrushName + match.css)
- ;
-
- pos = match.index + match.length + (match.offset || 0);
- }
-
- // don't forget to add whatever's remaining in the string
- result += wrapLinesWithCode(code.substr(pos), getBrushNameCss() + 'plain');
-
- return result;
- },
-
- /**
- * Generates HTML markup for the whole syntax highlighter.
- * @param {String} code Source code.
- * @return {String} Returns HTML markup.
- */
- getHtml: function(code)
- {
- var html = '',
- classes = [ 'syntaxhighlighter' ],
- tabSize,
- matches,
- lineNumbers
- ;
-
- // process light mode
- if (this.getParam('light') == true)
- this.params.toolbar = this.params.gutter = false;
-
- className = 'syntaxhighlighter';
-
- if (this.getParam('collapse') == true)
- classes.push('collapsed');
-
- if ((gutter = this.getParam('gutter')) == false)
- classes.push('nogutter');
-
- // add custom user style name
- classes.push(this.getParam('class-name'));
-
- // add brush alias to the class name for custom CSS
- classes.push(this.getParam('brush'));
-
- code = trimFirstAndLastLines(code)
- .replace(/\r/g, ' ') // IE lets these buggers through
- ;
-
- tabSize = this.getParam('tab-size');
-
- // replace tabs with spaces
- code = this.getParam('smart-tabs') == true
- ? processSmartTabs(code, tabSize)
- : processTabs(code, tabSize)
- ;
-
- // unindent code by the common indentation
- if (this.getParam('unindent'))
- code = unindent(code);
-
- if (gutter)
- lineNumbers = this.figureOutLineNumbers(code);
-
- // find matches in the code using brushes regex list
- matches = this.findMatches(this.regexList, code);
- // processes found matches into the html
- html = this.getMatchesHtml(code, matches);
- // finally, split all lines so that they wrap well
- html = this.getCodeLinesHtml(html, lineNumbers);
-
- // finally, process the links
- if (this.getParam('auto-links'))
- html = processUrls(html);
-
- if (typeof(navigator) != 'undefined' && navigator.userAgent && navigator.userAgent.match(/MSIE/))
- classes.push('ie');
-
- html =
- '<div id="' + getHighlighterId(this.id) + '" class="' + classes.join(' ') + '">'
- + (this.getParam('toolbar') ? sh.toolbar.getHtml(this) : '')
- + '<table border="0" cellpadding="0" cellspacing="0">'
- + this.getTitleHtml(this.getParam('title'))
- + '<tbody>'
- + '<tr>'
- + (gutter ? '<td class="gutter">' + this.getLineNumbersHtml(code) + '</td>' : '')
- + '<td class="code">'
- + '<div class="container">'
- + html
- + '</div>'
- + '</td>'
- + '</tr>'
- + '</tbody>'
- + '</table>'
- + '</div>'
- ;
-
- return html;
- },
-
- /**
- * Highlights the code and returns complete HTML.
- * @param {String} code Code to highlight.
- * @return {Element} Returns container DIV element with all markup.
- */
- getDiv: function(code)
- {
- if (code === null)
- code = '';
-
- this.code = code;
-
- var div = this.create('div');
-
- // create main HTML
- div.innerHTML = this.getHtml(code);
-
- // set up click handlers
- if (this.getParam('toolbar'))
- attachEvent(findElement(div, '.toolbar'), 'click', sh.toolbar.handler);
-
- if (this.getParam('quick-code'))
- attachEvent(findElement(div, '.code'), 'dblclick', quickCodeHandler);
-
- return div;
- },
-
- /**
- * Initializes the highlighter/brush.
- *
- * Constructor isn't used for initialization so that nothing executes during necessary
- * `new SyntaxHighlighter.Highlighter()` call when setting up brush inheritance.
- *
- * @param {Hash} params Highlighter parameters.
- */
- init: function(params)
- {
- this.id = guid();
-
- // register this instance in the highlighters list
- storeHighlighter(this);
-
- // local params take precedence over defaults
- this.params = merge(sh.defaults, params || {})
-
- // process light mode
- if (this.getParam('light') == true)
- this.params.toolbar = this.params.gutter = false;
- },
-
- /**
- * Converts space separated list of keywords into a regular expression string.
- * @param {String} str Space separated keywords.
- * @return {String} Returns regular expression string.
- */
- getKeywords: function(str)
- {
- str = str
- .replace(/^\s+|\s+$/g, '')
- .replace(/\s+/g, '|')
- ;
-
- return '\\b(?:' + str + ')\\b';
- },
-
- /**
- * Makes a brush compatible with the `html-script` functionality.
- * @param {Object} regexGroup Object containing `left` and `right` regular expressions.
- */
- forHtmlScript: function(regexGroup)
- {
- var regex = { 'end' : regexGroup.right.source };
-
- if(regexGroup.eof)
- regex.end = "(?:(?:" + regex.end + ")|$)";
-
- this.htmlScript = {
- left : { regex: regexGroup.left, css: 'script' },
- right : { regex: regexGroup.right, css: 'script' },
- code : new XRegExp(
- "(?<left>" + regexGroup.left.source + ")" +
- "(?<code>.*?)" +
- "(?<right>" + regex.end + ")",
- "sgi"
- )
- };
- }
-}; // end of Highlighter
-
-return sh;
-}(); // end of anonymous function
-
-// CommonJS
-typeof(exports) != 'undefined' ? exports.SyntaxHighlighter = SyntaxHighlighter : null;
diff --git a/pecan/middleware/resources/syntax.css b/pecan/middleware/resources/syntax.css
deleted file mode 100644
index 4f0021e..0000000
--- a/pecan/middleware/resources/syntax.css
+++ /dev/null
@@ -1,226 +0,0 @@
-/**
- * SyntaxHighlighter
- * http://alexgorbatchev.com/SyntaxHighlighter
- *
- * SyntaxHighlighter is donationware. If you are using it, please donate.
- * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
- *
- * @version
- * 3.0.83 (July 02 2010)
- *
- * @copyright
- * Copyright (C) 2004-2010 Alex Gorbatchev.
- *
- * @license
- * Dual licensed under the MIT and GPL licenses.
- */
-.syntaxhighlighter a,
-.syntaxhighlighter div,
-.syntaxhighlighter code,
-.syntaxhighlighter table,
-.syntaxhighlighter table td,
-.syntaxhighlighter table tr,
-.syntaxhighlighter table tbody,
-.syntaxhighlighter table thead,
-.syntaxhighlighter table caption,
-.syntaxhighlighter textarea {
- -moz-border-radius: 0 0 0 0 !important;
- -webkit-border-radius: 0 0 0 0 !important;
- background: none !important;
- border: 0 !important;
- bottom: auto !important;
- float: none !important;
- height: auto !important;
- left: auto !important;
- line-height: 1.1em !important;
- margin: 0 !important;
- outline: 0 !important;
- overflow: visible !important;
- padding: 0 !important;
- position: static !important;
- right: auto !important;
- text-align: left !important;
- top: auto !important;
- vertical-align: baseline !important;
- width: auto !important;
- box-sizing: content-box !important;
- font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important;
- font-weight: normal !important;
- font-style: normal !important;
- font-size: 1em !important;
- min-height: inherit !important;
- min-height: auto !important;
-}
-
-.syntaxhighlighter {
- width: 100% !important;
- margin: 1em 0 1em 0 !important;
- position: relative !important;
- overflow: auto !important;
- font-size: 1em !important;
-}
-.syntaxhighlighter.source {
- overflow: hidden !important;
-}
-.syntaxhighlighter .bold {
- font-weight: bold !important;
-}
-.syntaxhighlighter .italic {
- font-style: italic !important;
-}
-.syntaxhighlighter .line {
- white-space: pre !important;
-}
-.syntaxhighlighter table {
- width: 100% !important;
-}
-.syntaxhighlighter table caption {
- text-align: left !important;
- padding: .5em 0 0.5em 1em !important;
-}
-.syntaxhighlighter table td.code {
- width: 100% !important;
-}
-.syntaxhighlighter table td.code .container {
- position: relative !important;
-}
-.syntaxhighlighter table td.code .container textarea {
- box-sizing: border-box !important;
- position: absolute !important;
- left: 0 !important;
- top: 0 !important;
- width: 100% !important;
- height: 100% !important;
- border: none !important;
- background: white !important;
- padding-left: 1em !important;
- overflow: hidden !important;
- white-space: pre !important;
-}
-.syntaxhighlighter table td.gutter .line {
- text-align: right !important;
- padding: 0 0.5em 0 1em !important;
-}
-.syntaxhighlighter table td.code .line {
- padding: 0 1em !important;
-}
-.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line {
- padding-left: 0em !important;
-}
-.syntaxhighlighter.show {
- display: block !important;
-}
-.syntaxhighlighter.collapsed table {
- display: none !important;
-}
-.syntaxhighlighter.collapsed .toolbar {
- padding: 0.1em 0.8em 0em 0.8em !important;
- font-size: 1em !important;
- position: static !important;
- width: auto !important;
- height: auto !important;
-}
-.syntaxhighlighter.collapsed .toolbar span {
- display: inline !important;
- margin-right: 1em !important;
-}
-.syntaxhighlighter.collapsed .toolbar span a {
- padding: 0 !important;
- display: none !important;
-}
-.syntaxhighlighter.collapsed .toolbar span a.expandSource {
- display: inline !important;
-}
-.syntaxhighlighter .toolbar {
- position: absolute !important;
- right: 1px !important;
- top: 1px !important;
- width: 11px !important;
- height: 11px !important;
- font-size: 10px !important;
- z-index: 10 !important;
-}
-.syntaxhighlighter .toolbar span.title {
- display: inline !important;
-}
-.syntaxhighlighter .toolbar a {
- display: block !important;
- text-align: center !important;
- text-decoration: none !important;
- padding-top: 1px !important;
-}
-.syntaxhighlighter .toolbar a.expandSource {
- display: none !important;
-}
-.syntaxhighlighter.ie {
- font-size: .9em !important;
- padding: 1px 0 1px 0 !important;
-}
-.syntaxhighlighter.ie .toolbar {
- line-height: 8px !important;
-}
-.syntaxhighlighter.ie .toolbar a {
- padding-top: 0px !important;
-}
-.syntaxhighlighter.printing .line.alt1 .content,
-.syntaxhighlighter.printing .line.alt2 .content,
-.syntaxhighlighter.printing .line.highlighted .number,
-.syntaxhighlighter.printing .line.highlighted.alt1 .content,
-.syntaxhighlighter.printing .line.highlighted.alt2 .content {
- background: none !important;
-}
-.syntaxhighlighter.printing .line .number {
- color: #bbbbbb !important;
-}
-.syntaxhighlighter.printing .line .content {
- color: black !important;
-}
-.syntaxhighlighter.printing .toolbar {
- display: none !important;
-}
-.syntaxhighlighter.printing a {
- text-decoration: none !important;
-}
-.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a {
- color: black !important;
-}
-.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a {
- color: #008200 !important;
-}
-.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a {
- color: blue !important;
-}
-.syntaxhighlighter.printing .keyword {
- color: #006699 !important;
- font-weight: bold !important;
-}
-.syntaxhighlighter.printing .preprocessor {
- color: gray !important;
-}
-.syntaxhighlighter.printing .variable {
- color: #aa7700 !important;
-}
-.syntaxhighlighter.printing .value {
- color: #009900 !important;
-}
-.syntaxhighlighter.printing .functions {
- color: #ff1493 !important;
-}
-.syntaxhighlighter.printing .constants {
- color: #0066cc !important;
-}
-.syntaxhighlighter.printing .script {
- font-weight: bold !important;
-}
-.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a {
- color: gray !important;
-}
-.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a {
- color: #ff1493 !important;
-}
-.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a {
- color: red !important;
-}
-.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a {
- color: black !important;
-}
diff --git a/pecan/middleware/resources/theme.css b/pecan/middleware/resources/theme.css
deleted file mode 100644
index 8a870e4..0000000
--- a/pecan/middleware/resources/theme.css
+++ /dev/null
@@ -1,117 +0,0 @@
-/**
- * SyntaxHighlighter
- * http://alexgorbatchev.com/SyntaxHighlighter
- *
- * SyntaxHighlighter is donationware. If you are using it, please donate.
- * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
- *
- * @version
- * 3.0.83 (July 02 2010)
- *
- * @copyright
- * Copyright (C) 2004-2010 Alex Gorbatchev.
- *
- * @license
- * Dual licensed under the MIT and GPL licenses.
- */
-.syntaxhighlighter {
- background-color: white !important;
-}
-.syntaxhighlighter .line.alt1 {
- background-color: white !important;
-}
-.syntaxhighlighter .line.alt2 {
- background-color: white !important;
-}
-.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 {
- background-color: #e0e0e0 !important;
-}
-.syntaxhighlighter .line.highlighted.number {
- color: black !important;
-}
-.syntaxhighlighter table caption {
- color: black !important;
-}
-.syntaxhighlighter .gutter {
- color: #afafaf !important;
-}
-.syntaxhighlighter .gutter .line {
- border-right: 3px solid #6ce26c !important;
-}
-.syntaxhighlighter .gutter .line.highlighted {
- background-color: #6ce26c !important;
- color: white !important;
-}
-.syntaxhighlighter.printing .line .content {
- border: none !important;
-}
-.syntaxhighlighter.collapsed {
- overflow: visible !important;
-}
-.syntaxhighlighter.collapsed .toolbar {
- color: blue !important;
- background: white !important;
- border: 1px solid #6ce26c !important;
-}
-.syntaxhighlighter.collapsed .toolbar a {
- color: blue !important;
-}
-.syntaxhighlighter.collapsed .toolbar a:hover {
- color: red !important;
-}
-.syntaxhighlighter .toolbar {
- color: white !important;
- background: #6ce26c !important;
- border: none !important;
-}
-.syntaxhighlighter .toolbar a {
- color: white !important;
-}
-.syntaxhighlighter .toolbar a:hover {
- color: black !important;
-}
-.syntaxhighlighter .plain, .syntaxhighlighter .plain a {
- color: black !important;
-}
-.syntaxhighlighter .comments, .syntaxhighlighter .comments a {
- color: #008200 !important;
-}
-.syntaxhighlighter .string, .syntaxhighlighter .string a {
- color: blue !important;
-}
-.syntaxhighlighter .keyword {
- color: #006699 !important;
-}
-.syntaxhighlighter .preprocessor {
- color: gray !important;
-}
-.syntaxhighlighter .variable {
- color: #aa7700 !important;
-}
-.syntaxhighlighter .value {
- color: #009900 !important;
-}
-.syntaxhighlighter .functions {
- color: #ff1493 !important;
-}
-.syntaxhighlighter .constants {
- color: #0066cc !important;
-}
-.syntaxhighlighter .script {
- font-weight: bold !important;
- color: #006699 !important;
- background-color: none !important;
-}
-.syntaxhighlighter .color1, .syntaxhighlighter .color1 a {
- color: gray !important;
-}
-.syntaxhighlighter .color2, .syntaxhighlighter .color2 a {
- color: #ff1493 !important;
-}
-.syntaxhighlighter .color3, .syntaxhighlighter .color3 a {
- color: red !important;
-}
-
-.syntaxhighlighter .keyword {
- font-weight: bold !important;
-}
diff --git a/pecan/tests/middleware/test_debug.py b/pecan/tests/middleware/test_debug.py
deleted file mode 100644
index bc9d65f..0000000
--- a/pecan/tests/middleware/test_debug.py
+++ /dev/null
@@ -1,83 +0,0 @@
-from wsgiref.util import setup_testing_defaults
-
-from webtest import TestApp
-from six import b as b_
-
-from pecan.middleware.debug import DebugMiddleware
-from pecan.tests import PecanTestCase
-
-
-class StripPasteVar(object):
- def __init__(self, app):
- self.app = app
-
- def __call__(self, environ, start_response):
- environ.pop('paste.testing')
- return self.app(environ, start_response)
-
-
-class TestDebugMiddleware(PecanTestCase):
-
- def setUp(self):
- super(TestDebugMiddleware, self).setUp()
-
- def conditional_error_app(environ, start_response):
- setup_testing_defaults(environ)
- if environ['PATH_INFO'] == '/error':
- assert 1 == 2
- start_response("200 OK", [('Content-type', 'text/plain')])
- return [b_('requested page returned')]
- self.app = TestApp(StripPasteVar(DebugMiddleware(
- conditional_error_app
- )))
-
- def test_middleware_passes_through_when_no_exception_raised(self):
- r = self.app.get('/')
- assert r.status_int == 200
- assert r.body == b_('requested page returned')
-
- def test_middleware_gives_stack_trace_on_errors(self):
- r = self.app.get('/error', expect_errors=True)
- assert r.status_int == 400
- assert b_('AssertionError') in r.body
-
- def test_middleware_complains_in_multi_process_environment(self):
-
- class MultiProcessApp(object):
-
- def __init__(self, app):
- self.app = app
-
- def __call__(self, environ, start_response):
- environ['wsgi.multiprocess'] = True
- return self.app(environ, start_response)
-
- def conditional_error_app(environ, start_response):
- start_response("200 OK", [('Content-type', 'text/plain')])
- return ['Hello, World!']
-
- app = TestApp(MultiProcessApp(DebugMiddleware(conditional_error_app)))
- self.assertRaises(
- RuntimeError,
- app.get,
- '/'
- )
-
- def test_middlware_allows_for_post_mortem_debugging(self):
- def patch_debugger(d):
- def _patched_debug_request():
- d.append(True)
- return _patched_debug_request
-
- debugger = []
-
- app = TestApp(StripPasteVar(DebugMiddleware(
- self.app,
- patch_debugger(debugger)
- )))
-
- r = app.get('/error', expect_errors=True)
- assert r.status_int == 400
-
- r = app.get('/__pecan_initiate_pdb__', expect_errors=True)
- assert len(debugger) > 0
diff --git a/pecan/tests/test_base.py b/pecan/tests/test_base.py
index 785b522..e953d90 100644
--- a/pecan/tests/test_base.py
+++ b/pecan/tests/test_base.py
@@ -1683,41 +1683,6 @@ class TestNonCanonical(PecanTestCase):
assert len(wrapped_apps) == 1
-class TestDebugging(PecanTestCase):
- def test_debugger_setup(self):
- class RootController(object):
- pass
-
- def debugger():
- pass
-
- app_conf = dict(
- debug=True,
- debugger=debugger
- )
- with mock.patch('pecan.middleware.debug.DebugMiddleware') \
- as patched_debug_middleware:
- app = make_app(RootController(), **app_conf)
- args, kwargs = patched_debug_middleware.call_args
- assert kwargs.get('debugger') == debugger
-
- def test_invalid_debugger_setup(self):
- class RootController(object):
- pass
-
- debugger = 'not_a_valid_entry_point'
-
- app_conf = dict(
- debug=True,
- debugger=debugger
- )
- with mock.patch('pecan.middleware.debug.DebugMiddleware') \
- as patched_debug_middleware:
- app = make_app(RootController(), **app_conf)
- args, kwargs = patched_debug_middleware.call_args
- assert kwargs.get('debugger') is None
-
-
class TestLogging(PecanTestCase):
def test_logging_setup(self):