Twinkler

Why not take a look?

I hit some more dumb inspiration today and made a silly toy to make source code twinkle.

It uses pygments to parse uploaded code, and the colours are from emacs’ wombat theme.

Pygments will try to auto-detect which language you’re using, but it doesn’t always get it right. Things like a Python import statement tend to help. As this is effectively a shiny, hosted wrapper around pygments, made with a limited time budget, I’m not likely to improve that - wouldn’t know where to start, except maybe a dropdown to hint which language you’re using!

Also, Heroku is a surprisingly wonderful platform for deploying a Flask app.

Thumbnail of the Twinkler toy, showing colourful code.

Just want some code you can paste in? Try this.
from typing import Tuple, Iterable

from flask import Flask, render_template, request, make_response, redirect
from pygments import highlight
from pygments.lexers import guess_lexer
from pygments.formatters import HtmlFormatter

app = Flask(__name__)

app.config['TEMPLATES_AUTO_RELOAD'] = True

# These templates are rendered once at launch and then re-used for every request.
# They're global variables as that really seems like the most Flasky way to do it:
# flask.g: is per "application context" which is per-request, despite the name
# flask.current_app['varname']: doesn't work like that
# flask.current_app['config']: works, but feels wrong as it's not configuration
# flask.session: is per user/client session, not app 'session'
rendered_smart_css, rendered_smart_js = None, None
# pygments stuff
formatter = HtmlFormatter(linenos=False)


def get_pygments_classes() -> Tuple[Iterable[str], Iterable[str]]:
    """ A function to contain the ugly.
    Get a list of pygments' possible CSS classes and turn them into
        1) CSS selectors
        2) names for variables to accompany them. """
    pygments_css_classes = HtmlFormatter().get_token_style_defs('.highlight')
    classes = [line[:line.find('{')].replace('.highlight ', 'span') for line in pygments_css_classes]
    var_names = [line.replace('.', '. ', 1).replace('.', '-').replace(' ', '') for line in classes]
    return classes, var_names


@app.before_first_request
def set_up() -> None:
    global rendered_smart_css, rendered_smart_js
    pygments_css_classes, pygments_css_variables = get_pygments_classes()
    rendered_smart_css = render_template(
        'twinkle_smart.css',
        # we must list() the zip() because it will be iterated over multiple times
        css_classes_and_variables=list(zip(pygments_css_classes, pygments_css_variables)))
    rendered_smart_js = render_template('twinkle_smart.js', css_variables=pygments_css_variables)
    rendered_smart_css = rendered_smart_css