I’ve been wanting to upgrade the syntax highlighting on this site for some time now. It’s perfect for Ruby, but it lacks support for other languages. Particularly, though, Rails’ view code looks horrible. It parses everything between the slashes, <td/>...</tr> for example, as a regex.
the solution
Enter Ultraviolet. To quote the site, “it is able to produce html output for all the syntaxes in Textmate’s repository.” Which is a ton. It also supports themes, line numbers, and has xhtml output. Here are a couple of examples…
html = Uv.parse(text, "xhtml", "ruby_on_rails", true, "blackboard")
html = Uv.parse(text, "xhtml", "html_rails", false, "sunburst")
It’s pretty cool. Chris was kind enough to show his implementation for syntax highlighting, but I needed to make a minor modification to the regexp to support code.[language] instead of only code.ruby. Here’s the Ultraviolet version:
require 'uv'
def colorize_code
r = RedCloth.new(self[:body] || '')
self[:body_html] = r.gsub(/<code.(\w+)>\s(.*?)<\/code.\1>/m) do
lang, code = $1, $2
html = "<notextile>" + Uv.parse(code, "xhtml", lang, true, "sunburst") + "</notextile>"
end.to_html
end
I enjoy the line numbers, but by default they’re included with each line of code—to copy and paste means to remove each line number. If you care about that, here’s a way to create your own line numbers so that the code and line numbers are separated.
require 'uv'
def colorize_code
r = RedCloth.new(self[:body] || '')
self[:body_html] = r.gsub(/<code.(\w+)>\s(.*?)<\/code.\1>/m) do
lang, code = $1, $2
html = Uv.parse(code, "xhtml", lang, false, "sunburst")
result = "<notextile><pre class=\"lines\">"
result << (1..code.split("\n").size).to_a.join("\n")
result << "</pre>#{ html }</notextile>"
end.to_html
end
Then just do a float:left; on the .lines CSS class, and viola, your line numbers are separate from your code. There’s one more thing to make note of, though. As horrible as this sounds, you may want to use an inline style on the pre tag in place of the CSS class. The reason is because of how the code will look when it goes out to an RSS reader. What it’s doing is putting an extra pre block with just the line numbers above your code, but the CSS makes it appear beside it. Personally, I found style="float:left;padding-left:10px;" to work well.
ultraviolet in production
So the implementation is pretty easy, but here’s where things get difficult and very annoying. This is also why I’m not currently using Ultraviolet (in production) yet. You see, Ultraviolet indirectly requires the use of the (what is supposed to incredible) Oniguruma regular expression library, which isn’t packaged with Ruby until Ruby 1.9 (but is available as a gem).
I installed the gem without any problems on my machine; however, I could not for the life of me get it working on DreamHost. I freeze my gems, but the problem is that it had to be installed and frozen from the server and not my local machine. Since I’m on Windows (blah) in development, the oregexp.c file was compiled for an mswin32 environment, which is not the case in production. Apparently that matters. I have very little experience modifying environment variables and .bash_profile and all the other jazz I found online, so I was a little timid to go further than I’d be able to fix.
unfortunate conclusions
After a couple (or few?) hours of hacking at things I didn’t really know how to hack, I ended up back at the beginning: using the plain old syntax gem. What a great feeling it is to waste hours of my personal time.
I considered extending the syntax library to satisfy me for the time being (mainly for view templates), but I haven’t decided yet if I want to get into that or not. But definitely not today. I’m burnt out on syntax highlighting.
In the end, Ultraviolet is an awesome syntax highlighting library, and you should think about using it. Unfortunately for me, I was unable to get it working on DreamHost thanks to Oniguruma, but maybe (if you actually know what you’re doing) it’ll go better for you. Good luck!