Bill Mill web site logo

New For Cherry Blossom: Syntax Highlighting

This morning's project was to write a cherry blossom plugin that would use pygments to highlight inline source code in entries. If you load this plugin, just put code in a block like: <code lang="language_name"> ...code... </code>

I think it's a nice illustration of the simplicity of cherry blossom; see how little it gets in your way. The source is 42 lines long, and only five of them are devoted to making Cherry Blossom happy.

To test it out, here's its own source code. Note that you can't have the token </code> in your source; I avoided it with an empty comment in the regex:

"""Prerequisites: pygments (http://pygments.org)

Configuration for SyntaxHighlight module should be in a [SyntaxHighlight] 
    secion of your cherryblossom.conf file.

options:
syntax_style (string): Style to use for highlighting text. Check out the style 
    documentation at http://pygments.org/docs/styles/ and take the styles out 
    for a test drive at http://pygments.org/demo/"""

import re
import pygments
from pygments.lexers import get_lexer_by_name
from pygments.formatters import HtmlFormatter
from utils import config

CODE_RE = re.compile("<code (?:\s*lang=(.*?))*>(.*?)<(?#)/code>", re.S)

class SyntaxHighlight(object):
    def __init__(self, parent): pass

    def cb_story_start(self, entries):
        self.render_css = True

    #story is an Entry object
    def cb_story(self, story):
        for lang, code in CODE_RE.findall(story._text):
            if not lang: lang = "python"

            try:
                lexer = get_lexer_by_name(lang.strip('"'))
            except ClassNotFound:
                return
            formatter = HtmlFormatter(style=config("syntax_style", "default", 
                "SyntaxHighlight"))
            code = pygments.highlight(code, lexer, formatter)

            if self.render_css:
                code = '<style type="text/css">%s</style>\\n%s' % \
                    (formatter.get_style_defs(), code)
                self.render_css = False
            story._text = CODE_RE.sub(code, story._text, 1)

I should also mention, kudos to the pygments guys, your module rocks.

UPDATE: clearly there's some kinks with the RSS, I'm working on those.

UPDATE 2: Rss should be fixed. I hadn't noticed that you were allowed to simply enclose encoded data in the description field.