Implementing a code-snippet system
Dunstan Orchard has just had a little redesign. To me, one of the more notable features of this new site is not embedding code snippets directly into weblog entries but instead pulling them on the fly from a different folder. I thought this was a fantastic idea: the code snippets are available for easy download, and multiple entries can display the same snippet without repeated code (and of course, if you were to change that code snippet, all pages displaying it change automagically). It also allowed me to have advanced snippet features: line count, long lines wrapping without confusion, etc. This is how I’ve implemented this system:
First I needed a way to identify where the snippets were to come from. I copied Dunstan’s approach here: use XML (that’s not quite true: Dunstan uses pseudo-XML in the form of <codeins="..." />, I’m using ‘real’ XML). I promptly made up my own tag: code-snippet with one single attribute: src, which describes the filename of the snippet (minus the .txt extension). The filenames are constructed with the sanitized name of the entry they were initially posted in, followed by a hyphen and a number that describes their position in that post. So, for example, the first snippet in this post would have the filename implementing-a-code-snippet-system-1.txt. The code to display it would therefore be: <code-snippet src="implementing-a-code-snippet-system-1" />.
Next, I wrote a PHP function to find these XML tidbits within an entry’s content, pull the code and display it with an ordered list of lines. The entire function looks like this (by the way, this code snippet is displayed with this system :)):
I’ve written this a function so that it can be inserted into my WordPress installation via filters, but you could just as easily write this as straight code. Here’s how the function works:
- Line 4: I’m looping through the entire text, matching each occurance of a
code-snippettag with a regular expression. I’m sure there’s an easier way to match each occurance rather than usingpreg_matchon the same text and increasing the offset each time, but this works for me. - Line 5: When a match is found, the file that corresponds to that tag is opened. (
$matches[1]contains thesrcattribute of the tag) - Line 6: The offset for the next
preg_matchis generated (where that function should start its search from), based on the position of the match we’ve just found in the converted text so far, plus the length of the code we’re about to insert. - Line 8: The converted text so far (
$output) is set to all the text in itself up to the position of the match we’re currently converting, plus the opening tag for the unordered list we’re about to generate. - Line 9: Looping through the code line by line (
$codeis an array of lines as it was opened withfile) - Line 10: The number of tabs (”t” characters) is determined.
- Line 12: The code for this line is output. If there were more than 0 tabs, a class is added to indicate this (then with a bit of CSS, the
lis with a tab-* class hadpadding-leftadded to them). - Line 14: The closing tag for this code-snippet is added, and all the text that came after this current match is appended.
If you’re a WordPress user, the entire plugin is available here. Download it, copy it over to your /wp-content/plugins/ folder, get rid of the .txt extension and then activate it in the Plugins section of the WordPress admin.
Just noticed: The above WP plugin invalidates your pages, due to a block level element ( Note: these ammendments only need to be made if you’ve already downloaded from the above link (ie: before I posted this message, 23 June 04). If you’ve just read this message, there’s no need, as I’ve updated the file with the source in.ol) getting caught in the automatic paragraphing function of WordPress, wpautop (wp-includes/functions-formattion.php). Hence, you need to add the following lines:
This plugin is now documented. Further changes will appear over at that post.
