diff --git a/check50/renderer/_renderers.py b/check50/renderer/_renderers.py index 0ddc252a..0d42244b 100644 --- a/check50/renderer/_renderers.py +++ b/check50/renderer/_renderers.py @@ -14,11 +14,56 @@ def to_html(slug, results, version): content = f.read() template = jinja2.Template( - content, autoescape=jinja2.select_autoescape(enabled_extensions=("html",))) - html = template.render(slug=slug, results=results, version=version) + content, autoescape=jinja2.select_autoescape(enabled_extensions=("html",)) + ) + + html = template.render( + slug=slug, + results=results, + version=version, + fmt_special_chars=_fmt_special_chars, + color="808080" # RGB (128, 128, 128) + ) return html +def _fmt_special_chars(txt, color): + """Converts a plaintext string into a string of HTML elements that highlights special chars.""" + def highlight_char(char, color): + """Highlights and escapes a char.""" + return f"{repr(char)[1:-1]}" + + # We'd like to interpret whitespace (ws) as HTML in only these specific cases: + ws_to_html = { + "\n": "
", + " ": " ", + } + fmtted_txt = [] + + for i, char in enumerate(txt): + is_last = i == len(txt) - 1 + + if not char.isprintable() and char not in ws_to_html: + # Most special invisible characters, excluding those in ws_to_html, are highlighted + fmtted_txt.append(highlight_char(char, color)) + elif char in ws_to_html: + # If there's a trailing whitespace character, we highlight it + if is_last: + # Spaces aren't normally highlightable, so we convert to nbsp. + if char == ' ': + char = ws_to_html[char] + + fmtted_txt.append(highlight_char(char, color)) + else: + # Certain special chars are interpreted in HTML, without escaping or highlighting + fmtted_txt.append(ws_to_html[char]) + else: + # Non-special characters are unchanged + fmtted_txt.append(char) + + # Return the text as a string of plaintext + html elements + return ''.join(fmtted_txt) + def to_json(slug, results, version): return json.dumps({"slug": slug, "results": results, "version": version}, indent=4) diff --git a/check50/renderer/templates/results.html b/check50/renderer/templates/results.html index 6a51efa8..40b58d7f 100644 --- a/check50/renderer/templates/results.html +++ b/check50/renderer/templates/results.html @@ -86,7 +86,7 @@

:| {{ check.description }}

{% else %} {% set expected = check.cause.expected | e %} {% endif %} - {{ expected | replace(" ", " ") | replace("\n", "
") }} + {{ fmt_special_chars(expected, color) }} {% endautoescape %} @@ -102,12 +102,13 @@

:| {{ check.description }}

{% else %} {% set actual = check.cause.actual | e %} {% endif %} - {{ actual | replace(" ", " ") | replace("\n", "
") }} + {{ fmt_special_chars(actual, color) }} {% endautoescape %} +
{% endif %} {# Missing if there was one #}