Code Highlighting

I’ve taken on a little side project recently…setting up a nice little script that will let me copy a bit of code to the clipboard, click a button, and paste it as highlighted code (in HTML format).  It hasn’t been easy.  The first trouble was figuring out what app/library to use to highlight the code in the first place.  I played with the program simply known as “highlight” by Andre Simon, Ultraviolet for Ruby, and CodeRay for Ruby.  I finally decided on CodeRay, since that would let me generate a single div with inline styling.  The other options would either force me to generate an entire HTML document or have the css styles pulled out separate.

It would be fairly easily cobble together a Ruby script to highlight code given the simple examples on the CodeRay website.  The next step was to figure out how to access the info on the clipboard, and put back what I wanted.  For this, there are two commands in Linux: xsel, and xclip.  I tried xclip, but I couldn’t seem to get it to access the “context-menu” clipboard even when specifying the “-s clipboard” option.  It seemed always to want to use the “middle-click” clipboard.  Xsel, on the other hand, did exactly what I wanted—it could read from the right clipboard, and put stuff back on it.

The only thing that disappointed me was that I couldn’t seem to get it to work the way some other programs work.  I can copy highlighted code in a page on Firefox, then simply paste it into a Thunderbird email and it will appear as formatted text.  By copying HTML to the clipboard with xsel, when I paste I get raw code.  I only know a little about the internal workings of the X clipboard, and I know the content type has to be set.  Brandon Tilley pointed out to me that the MacOS equivalent program, pbpaste, looks for an RTF header at the beginning of the input.  If it’s there, it treats it as RTF data.

That knowledge in hand, I switched my script around to use the “highlight” command line program to output RTF, piped it to xsel, pasted and…I saw raw RTF code in my email.  No luck.  So, I posted a question on superuser.com asking if anyone knew of an xsel substitute that could handle RTF, and it has not been answered yet.  So for now, here’s my script:

require 'coderay'

language = "auto";
if(ARGV.length > 0)
    language = ARGV[0];
end

codeToHighlight = `xsel --clipboard`
highlightedCode = CodeRay.scan(codeToHighlight, language.intern()).div

IO.popen("xsel --clipboard", mode='w') do |io|
  io.write highlightedCode
end

It takes the language of the code as a command line argument, since the auto detector doesn’t really work. It works pretty well…I have an extra little menu on my Gnome panel that pops down with the different highlighters. I did notice I had to set the application type to “Application in a Terminal” for it to work, but that’s ok; it just means I briefly see a gnome-terminal window flash. The code above was actually highlighted by the script.

Update (October 11, 2010):
When I upgraded from Karmic to Jaunty, the above script stopped working via my gnome menu (which basically uses the gnome-terminal equivalent of `xterm -e`, I think) though it still worked if run directly within a terminal. After doing testing, I found that everything seemed to be working except the pipe that feeds the output to xsel. After a lot of searching online, I found this post which was never answered: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/138423.

Using his idea, I added the following to the end of my script, and it started working:

10000.times do
   puts ""
end

Apparently it’s a timing issue. I asked about it on stackoverflow.com, but got no answers. I’m comforted when a problem I can’t solve also proves difficult to others, but it’s rather counterproductive to have such a knack for asking unanswerable questions. 😉

As of this update, my super user question also remains unanswered.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: