Take me home

Syntax highlighter

Written by August Lilleaas, published November 26, 2007

How I syntax highlight code in this blog. CodeRay + regular expressions.

I’m using this app-only plugin called cache_html. It lets me do this:

class Post < ActiveRecord::Base
  cache_html :intro, :content
end

This runs some parsing – textile and coderay – on that content, and stores it in [column_name]_html. Honestly, that’s kind of useless, as this app is using page caching, but oh well. Even the RSS feed is page cached, yawn.

So, the cache_html does it’s thing before_save, and this is one of the things:

def coderay(text)
  duped = text.dup
  expression = /(<source(?:\:([a-z]+))?>(.+?)<\/source>)/m
  text.scan(expression) do |all, language, code|
    language ||= :ruby

    if (code.scan(/\n/)).empty? # has no newlines?
      highlighted = '<span class="inline_code">'
      highlighted += CodeRay.scan(code, language.to_sym).div(:wrap => nil, :css => :class)
      highlighted += '</span>'
    else
      code.strip!
      highlighted = CodeRay.scan(code, language.to_sym).div(:css => :class)
    end

    duped.gsub!(all, "<notextile>#{highlighted}</notextile>")
  end

  duped
end

There ya go. Some notes:

  • It’s dirty. This is strictly ActionView stuff. I should have used content_tag and all sorts of neat helpers, but I can’t do that, as I’m in the ActiveRecord scope.
  • It’s looking for <source> tags, and highlights that. I can also go <source:language>. It’s Ruby by default.
  • I’m doing dup because a string can’t modify (gsub) itself inside a scan block.
  • It scans the content for newlines. If there’s no newlines around, it’s considered an in-line code sample.
  • <notextile> makes sure textile doesn’t parse the code samples (that’d be rather silly)

Questions or comments?

Feel free to contact me on Twitter, @augustl, or e-mail me at august@augustl.com.