summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-03-12 14:22:46 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2012-03-12 14:22:46 -0400
commit10228fad9797a85a879286eb51ec4ea287225c97 (patch)
treee8a5da4ad419e8a8c5b8965dd8981f648ea4b711
parent8bebfc205230d41429a88c98b56d45acf7e67226 (diff)
downloadmako-10228fad9797a85a879286eb51ec4ea287225c97.tar.gz
- [feature] The html_error_template() will now
apply Pygments highlighting to the source code displayed in the traceback, if Pygments if available. Courtesy Ben Trofatter [ticket:95]
-rw-r--r--CHANGES6
-rw-r--r--mako/exceptions.py51
-rw-r--r--mako/ext/pygmentplugin.py33
-rw-r--r--test/test_exceptions.py65
4 files changed, 131 insertions, 24 deletions
diff --git a/CHANGES b/CHANGES
index c84fb92..b07a295 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,10 @@
0.6.3
+- [feature] The html_error_template() will now
+ apply Pygments highlighting to the source
+ code displayed in the traceback, if Pygments
+ if available. Courtesy Ben Trofatter
+ [ticket:95]
+
- [feature] Added support for context managers,
i.e. "% with x as e:/ % endwith" support.
Courtesy Ben Trofatter [ticket:147]
diff --git a/mako/exceptions.py b/mako/exceptions.py
index bce99b7..c9e04ea 100644
--- a/mako/exceptions.py
+++ b/mako/exceptions.py
@@ -227,6 +227,15 @@ Traceback (most recent call last):
${tback.errorname}: ${tback.message}
""")
+
+try:
+ from mako.ext.pygmentplugin import syntax_highlight, pygments_html_formatter
+except ImportError:
+ from mako.filters import html_escape
+ pygments_html_formatter = None
+ def syntax_highlight(filename='', language=None):
+ return html_escape
+
def html_error_template():
"""Provides a template that renders a stack trace in an HTML format,
providing an excerpt of code as well as substituting source template
@@ -242,7 +251,7 @@ def html_error_template():
import mako.template
return mako.template.Template(r"""
<%!
- from mako.exceptions import RichTraceback
+ from mako.exceptions import RichTraceback, syntax_highlight, pygments_html_formatter
%>
<%page args="full=True, css=True, error=None, traceback=None"/>
% if full:
@@ -262,6 +271,21 @@ def html_error_template():
.location { font-size:80%; }
.highlight { white-space:pre; }
.sampleline { white-space:pre; }
+
+ % if pygments_html_formatter:
+ ${pygments_html_formatter.get_style_defs()}
+ .linenos { min-width: 2.5em; text-align: right; }
+ pre { margin: 0; }
+ .syntax-highlighted { padding: 0 10px; }
+ .syntax-highlightedtable { border-spacing: 1px; }
+ .nonhighlight { border-top: 1px solid #DFDFDF; border-bottom: 1px solid #DFDFDF; }
+ .stacktrace .nonhighlight { margin: 5px 15px 10px; }
+ .sourceline { margin: 0 0; font-family:monospace; }
+ .code { background-color: #F8F8F8; width: 100%; }
+ .error .code { background-color: #FFBDBD; }
+ .error .syntax-highlighted { background-color: #FFBDBD; }
+ % endif
+
</style>
% endif
% if full:
@@ -285,10 +309,23 @@ def html_error_template():
<div class="sample">
<div class="nonhighlight">
% for index in range(max(0, line-4),min(len(lines), line+5)):
+ <%
+ if pygments_html_formatter:
+ pygments_html_formatter.linenostart = index + 1
+ %>
% if index + 1 == line:
-<div class="highlight">${index + 1} ${lines[index] | h}</div>
+ <%
+ if pygments_html_formatter:
+ old_cssclass = pygments_html_formatter.cssclass
+ pygments_html_formatter.cssclass = 'error ' + old_cssclass
+ %>
+ ${lines[index] | syntax_highlight(language='mako')}
+ <%
+ if pygments_html_formatter:
+ pygments_html_formatter.cssclass = old_cssclass
+ %>
% else:
-<div class="sampleline">${index + 1} ${lines[index] | h}</div>
+ ${lines[index] | syntax_highlight(language='mako')}
% endif
% endfor
</div>
@@ -298,7 +335,13 @@ def html_error_template():
<div class="stacktrace">
% for (filename, lineno, function, line) in tback.reverse_traceback:
<div class="location">${filename}, line ${lineno}:</div>
- <div class="sourceline">${line | h}</div>
+ <div class="nonhighlight">
+ <%
+ if pygments_html_formatter:
+ pygments_html_formatter.linenostart = lineno
+ %>
+ <div class="sourceline">${line | syntax_highlight(filename)}</div>
+ </div>
% endfor
</div>
diff --git a/mako/ext/pygmentplugin.py b/mako/ext/pygmentplugin.py
index 0b15126..98e0c5d 100644
--- a/mako/ext/pygmentplugin.py
+++ b/mako/ext/pygmentplugin.py
@@ -4,20 +4,16 @@
# This module is part of Mako and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php
-import re
-try:
- set
-except NameError:
- from sets import Set as set
-
from pygments.lexers.web import \
HtmlLexer, XmlLexer, JavascriptLexer, CssLexer
-from pygments.lexers.agile import PythonLexer
-from pygments.lexer import Lexer, DelegatingLexer, RegexLexer, bygroups, \
- include, using, this
-from pygments.token import Error, Punctuation, \
- Text, Comment, Operator, Keyword, Name, String, Number, Other, Literal
-from pygments.util import html_doctype_matches, looks_like_xml
+from pygments.lexers.agile import PythonLexer, Python3Lexer
+from pygments.lexer import DelegatingLexer, RegexLexer, bygroups, \
+ include, using
+from pygments.token import \
+ Text, Comment, Operator, Keyword, Name, String, Other
+from pygments.formatters.html import HtmlFormatter
+from pygments import highlight
+from mako import util
class MakoLexer(RegexLexer):
name = 'Mako'
@@ -105,3 +101,16 @@ class MakoCssLexer(DelegatingLexer):
def __init__(self, **options):
super(MakoCssLexer, self).__init__(CssLexer, MakoLexer,
**options)
+
+
+pygments_html_formatter = HtmlFormatter(cssclass='syntax-highlighted', linenos=True)
+def syntax_highlight(filename='', language=None):
+ mako_lexer = MakoLexer()
+ if util.py3k:
+ python_lexer = Python3Lexer()
+ else:
+ python_lexer = PythonLexer()
+ if filename.startswith('memory:') or language == 'mako':
+ return lambda string: highlight(string, mako_lexer, pygments_html_formatter)
+ return lambda string: highlight(string, python_lexer, pygments_html_formatter)
+
diff --git a/test/test_exceptions.py b/test/test_exceptions.py
index 97987e6..ea27dda 100644
--- a/test/test_exceptions.py
+++ b/test/test_exceptions.py
@@ -87,10 +87,25 @@ ${u'привет'}
html_error
if util.py3k:
- assert u"3 ${&#39;привет&#39;}".encode(sys.getdefaultencoding(),
+ try:
+ import pygments
+ assert u"".encode(sys.getdefaultencoding(),
+ 'htmlentityreplace') in html_error
+ except ImportError:
+ assert u"3 ${&#39;привет&#39;}".encode(sys.getdefaultencoding(),
'htmlentityreplace') in html_error
else:
- assert u"3 ${u&#39;привет&#39;}".encode(sys.getdefaultencoding(),
+ try:
+ import pygments
+ assert u'<pre>3</pre></div></td><td class="code">'\
+ '<div class="syntax-highlighted"><pre><span '\
+ 'class="cp">${</span><span class="s">u&#39;'\
+ '&#x43F;&#x440;&#x438;&#x432;&#x435;&#x442;'\
+ '&#39;</span><span class="cp">}</span>'.encode(
+ sys.getdefaultencoding(),
+ 'htmlentityreplace') in html_error
+ except ImportError:
+ assert u"3 ${u&#39;привет&#39;}".encode(sys.getdefaultencoding(),
'htmlentityreplace') in html_error
else:
assert False, ("This function should trigger a CompileException, "
@@ -138,7 +153,16 @@ ${foobar}
${self.body()}
""")
- assert '<div class="sourceline">${foobar}</div>' in \
+ try:
+ import pygments
+ assert '<div class="sourceline"><table class="syntax-highlightedtable">'\
+ '<tr><td class="linenos"><div class="linenodiv"><pre>3</pre>'\
+ '</div></td><td class="code"><div class="syntax-highlighted">'\
+ '<pre><span class="err">$</span><span class="p">{</span>'\
+ '<span class="n">foobar</span><span class="p">}</span>' in \
+ result_lines(l.get_template("foo.html").render_unicode())
+ except ImportError:
+ assert '<div class="sourceline">${foobar}</div>' in \
result_lines(l.get_template("foo.html").render_unicode())
def test_utf8_format_exceptions(self):
@@ -152,12 +176,37 @@ ${foobar}
l.put_string("foo.html", """# -*- coding: utf-8 -*-\n${u'привет' + foobar}""")
if util.py3k:
- assert u'<div class="sourceline">${&#39;привет&#39; + foobar}</div>'\
- in result_lines(l.get_template("foo.html").render().decode('utf-8'))
+ try:
+ import pygments
+ assert '<table class="error syntax-highlightedtable"><tr><td '\
+ 'class="linenos"><div class="linenodiv"><pre>2</pre>'\
+ '</div></td><td class="code"><div class="error '\
+ 'syntax-highlighted"><pre><span class="cp">${</span>'\
+ '<span class="s">&#39;привет&#39;</span> <span class="o">+</span> '\
+ '<span class="n">foobar</span><span class="cp">}</span>'\
+ '<span class="x"></span>' in \
+ result_lines(l.get_template("foo.html").render().decode('utf-8'))
+ except ImportError:
+ assert u'<div class="sourceline">${&#39;привет&#39; + foobar}</div>'\
+ in result_lines(l.get_template("foo.html").render().decode('utf-8'))
else:
- assert '<div class="highlight">2 ${u&#39;&#x43F;&#x440;'\
- '&#x438;&#x432;&#x435;&#x442;&#39; + foobar}</div>' \
- in result_lines(l.get_template("foo.html").render().decode('utf-8'))
+ try:
+ import pygments
+
+ assert '<table class="error syntax-highlightedtable"><tr><td '\
+ 'class="linenos"><div class="linenodiv"><pre>2</pre>'\
+ '</div></td><td class="code"><div class="error '\
+ 'syntax-highlighted"><pre><span class="cp">${</span>'\
+ '<span class="s">u&#39;&#x43F;&#x440;&#x438;&#x432;'\
+ '&#x435;&#x442;&#39;</span> <span class="o">+</span> '\
+ '<span class="n">foobar</span><span class="cp">}</span>'\
+ '<span class="x"></span>' in \
+ result_lines(l.get_template("foo.html").render().decode('utf-8'))
+
+ except ImportError:
+ assert '<div class="highlight">2 ${u&#39;&#x43F;&#x440;'\
+ '&#x438;&#x432;&#x435;&#x442;&#39; + foobar}</div>' \
+ in result_lines(l.get_template("foo.html").render().decode('utf-8'))
def test_custom_tback(self):