diff --git a/issues/templates/issues/issue_stacktrace.html b/issues/templates/issues/issue_stacktrace.html index dae1705..d00557f 100644 --- a/issues/templates/issues/issue_stacktrace.html +++ b/issues/templates/issues/issue_stacktrace.html @@ -26,6 +26,7 @@ {% for frame in exception.stacktrace.frames %} + {% with frame=frame|pygmentize %}
{# per frame div #} @@ -47,8 +48,6 @@
{# convience div for padding & border; the border is basically the top-border of the next header #}
{# code listing #} - {{ frame|pygmentize }} - {% comment %} {# the spread-out pX-6 in this code is intentional to ensure the padding is visible when scrolling to the right, and not visible when scrolling is possible (i.e. the text is cut-off awkwardly to hint at scrolling #}
    {% for line in frame.pre_context %}
  1. {{ line }} {# leave space to avoid collapse #}
  2. {% endfor %} @@ -57,7 +56,6 @@
  3. {{ frame.context_line }} {# leave space to avoid collapse #}
  4. {% for line in frame.post_context %}
  5. {{ line }} {# leave space to avoid collapse #}
  6. {% endfor %}
- {% endcomment %}
{% if frame.vars %} @@ -80,6 +78,7 @@
{# per frame div #} + {% endwith %} {% endfor %} {# frame #} {#
#} {# per-exception div in the multi-exception case #} diff --git a/theme/templatetags/issues.py b/theme/templatetags/issues.py index 9ec6832..89af0eb 100644 --- a/theme/templatetags/issues.py +++ b/theme/templatetags/issues.py @@ -8,11 +8,42 @@ from django.utils.safestring import mark_safe register = template.Library() +def _split(joined, lengths): + result = [] + start = 0 + for length in lengths: + result.append(joined[start:start + length]) + start += length + + assert [len(r) for r in result] == lengths + return result + + +def noempty(lines): + # if the line is empty, replace it with a space; this is needed to avoid pygments dropping empty lines (I've + # obvserved this for leading empty lines, but the problem might be more general) + # https://github.com/pygments/pygments/issues/2673 + return [" " if not line else line for line in lines] + + @register.filter def pygmentize(value): # first, get the actual code from the frame - code = "\n".join(value['pre_context'] + [value['context_line']] + value['post_context']) - return(mark_safe(highlight(code, PythonLexer(), HtmlFormatter()))) + lengths = [len(value['pre_context']), 1, len(value['post_context'])] + + code = "\n".join(noempty(value['pre_context']) + [value['context_line']] + noempty(value['post_context'])) + pygments_result = highlight(code, PythonLexer(), HtmlFormatter(nowrap=True)) + lines = pygments_result.split('\n')[:-1] # remove the last empty line, which is a result of split() + + assert len(lines) == sum(lengths), "%d != %d" % (len(lines), sum(lengths)) + + pre_context, context_lines, post_context = _split(lines, lengths) + + value['pre_context'] = [mark_safe(s) for s in pre_context] + value['context_line'] = mark_safe(context_lines[0]) + value['post_context'] = [mark_safe(s) for s in post_context] + + return value @register.filter(name='firstlineno')