Drupal: GeSHi Code Filtering

Recently, while searching through the web for a code snippet, I can across a site where the code was displayed just as it would look in an IDE. The comments, functions, variables, operators, etc, were all highlighted in different colors. This made the code really pop out, so that you could more easily follow the variables through a function, or ignore the comments. I thought that I had to get me some of that.

My first instinct was to, essentially, reinvent the wheel. I experimented with different HTML elements and style settings, eventually settling on something like this:

pre {
 color: #000;
 font-family: 'Courier New', Courier, monospace;
 display: block;
    white-space: pre;
    overflow: auto;
    line-height: 1.4;
    border: 1px solid #ccc;
    background-color: #f8f8f8;
    padding: 0.5em;
   margin: 0.5em;
 }

This worked okay. The code was neatly set off with a brighter background, the formatting was preserved, and everything was legible.

e.g.

// Test target directory
$bGo = true; // variable used to toggle a hard stop
$iAllFilesSize = 0; //global variable for size of full catalog
if(!is_dir ($sTARGET_DIR)){
        if(!mkdir ($sTARGET_DIR)){ // try to make the directory
                echo "!!Target directory " .$sTARGET_DIR . " does not exist!!\n";
                $bGo = false; // this should stop the rest of the program
        }else{
                echo "Creating target directory " .$sTARGET_DIR."\n";
        }
}

Unfortunately, it didn't wrap well, causing sliders to appear, and it didn't really mark-up the code like an IDE.

Enter GeSHi.

The GeSHi (for Generic Syntax Highlighter) project is an open source library supporting litterally dozens of languages, from the obvious (PHP, C++, Java) to the obscure (ABAP, CFDG, gnuplot). The Drupal implementation is handled by a project called GeSHiFilter. This is not the only code filter out there, but this is the only one with the high level of mark-up I wanted and server-side execution. Working properly, the difference in readability it can make to a code snippet is pretty striking.

e.g.

// Test target directory
$bGo = true; // variable used to toggle a hard stop
$iAllFilesSize = 0; //global variable for size of full catalog
if(!is_dir  ($sTARGET_DIR)){
        if(!mkdir  ($sTARGET_DIR)){ // try to make the directory
                echo "!!Target directory " .$sTARGET_DIR . " does not exist!!\n";
                $bGo = false; // this should stop the rest of the program
        }else{
                echo "Creating target directory " .$sTARGET_DIR."\n";
        }
}

Implementation was pretty easy, but only in hind sight. Both the library and module are going through rapid evolution, and 3/4ths of the instructions I found didn't actually apply to the current code base. That said, here's what worked late one night in the middle of 2010.

  1. Download the latest version of the GeSHiFilter module, from drupal.org, and unpack it anywhere.
  2. Download the GeSHi library from qbnz.com. Choose the most recent stable version, as anything else will probably not work with the Drupal module. Unpack it to a "geshi" subfolder in the "geshifilter" folder you just unpacked previously.
  3. Move the entire file set to your Drupal site's module folder. The structure should look something like this:
    yoursite\modules\geshifilter yoursite\modules\geshifilter\geshifilter.module
    yoursite\modules\geshifilte\geshi yoursite\modules\geshifilte\geshi\geshi.php
  4. Enable the "GeSHi Filter" module, like any other module, on the "admin/build/modules" page.
  5. "GeSHi Filter" will now show up under the Site Configuration menu. Crack it open and start choosing your favorite options. More on that later.
  6. Enable the "GeSHi filter" filter under the inputs formats you want it to work with on the "admin/settings/filters" page.
  7. Start marking up your code. <code></code> works out of the box, but this is configurable.

Most of the configuration happens under the "General settings" tab. The various options are well documented, including link-outs to internal and external pages with more information. I went with most of the default settings, here. With "Generic syntax highlighting tags" set to "code blockcode", and "Container tag style" enabling both "<foo>" and "[foo]", code enclosed in the following tags would be marked up by GeSHi:

<code></code>
<blockcode></blockcode>
[code][/code]
[blockcode][/blockcode]

Which you choose would make no difference.

One change I made was to choose the "GESHI_HEADER_DIV" container and wrapping technique. Since I chose not to use line numbering, this generated easy to read and easy to cut & paste code, but your preferences may vary.

Under the Languages tab, I disabled all the languages I knew I wouldn't be blogging about, and enabled the ones with which I tended to work. The more you choose, the more language specific hightlighting you get, and the harder your web server has to work to render every page. Anything GeSHi doesn't recognize receives the "default" treatment.

Here, you'll also see the "GeSHi language code" values you'll need to use in order to tell the code block listed above how to highlight the code. So, for instance, you might encapsulate your code like this:

<code lang="css"></code>
<blockcode lang="drupal6"></blockcode>
[code lang="php"][/code]
[blockcode lang="xml"][/blockcode]

If you don't set the "lang" value, you'll get the "Default highlighting mode" set on the General Option tab, "As plain text" by default.

You can also view and set custom tags here to simplify the enclosure process. For instance, I can use the "Tag/language attribute value" for PHP, <php> instead of the the slightly more taxing <code lang="php">. I know, a fifth way to say the same thing. It's a little confusing at first, but the convenience later makes it worth the head scratching.

The last tab to look at is "Filter Conflicts". I never saw anything here, but it's conceivable that another module you are using has it's own custom tags. <code>, for instance, has been used elsewhere, in my experience.

And that's it. Hopefully, you'll find this write-up before things change too much.