a blog by Christian Snodgrass
about programming, web and game design, and everything else

Adding a Code Box with Word Wrap

I’ve been tinkering here and there trying to make an awesome website (how am I doing? ;)). One thing I’ve done is created a handy dandy code block parser to my WordPress, so I can quickly add code in an easy to read format. This way I can spend more time writing and less time formatting.

And I thought, this would be a great topic for an article, so, here it is.

The Block

Just in case you haven’t seen my code block before, here is an example:

function helloWorld() { 
    // This is a very long comment to demonstrate the word wrap. 
    echo "Hello World"; 

It’s fairly basic. The only unique part is the hanging indent with the word wrap and the fancy little arrow indicating word wrap.

The Parts

There are really four parts to this:

If you are just looking for a specific part, feel free to jump ahead to them.

The WordPress Part

The WordPress part is pretty simple. We want to make sure that we process the content of the articles to do the changing we need to do. For that, we just hook in a filter on ‘the_content’ with a priority of 1. The priority of 1 is important. If we didn’t give it a high priority and WordPress’ built-in ‘the_content’ function goes first, it may add a lot of unnecessary paragraph or break tags, which we don’t want. Going first, we have it wrapped in elements so WordPress won’t do that.

Here is my filter:

// The first 1 indicates a priority of 1. 
// The second 1 indicates that we take 1 parameter in our function. 
add_filter('the_content', parseCode, 1, 1); 

The PHP Part

In the back-end, I use the <code> tag. I use the code tag for two reasons:

You can easily switch it to anything else you want (like a BBCode style [code] block or something else entirely), by simply tweaking the regex a little.

The final HTML for our code block needs to have a number of requirements:

This fancy little function does all of that:

function parseCode($contents) { 
	return preg_replace('#<code>v{0,2}?(.*)</code >#Ues', ''<div class="code"><pre>' . preg_replace('|v{2}|', '&nbsp;</pre><pre>', preg_quote(htmlentities('$1'), '|')) . '</pre></div>'', $contents); 

(Important: Remove the space in </code>... ironically our code can't handle the </code> tag properly without some extra stuff which I don't want to add for this one little part. =p)

That's a serious line... let's break it down.

The Pattern

First we have the outer preg_replace. It searches for this pattern:

'|<code>v{0,2}?(.*)</code >|Ues' 

The <code> and </code> parts are pretty obvious.

The \v{0,2}? part is a bit less obvious. \v is for any vertical white space character (essentially new lines). The {0,2} means we want 0 through 2. The ? means this whole thing is optional. This is here to prevent an empty new line from appearing from the beginning of our code blocks. This takes care of it both if you have the code right after the tag, or if you have a new line below it. This doesn't prevent empty lines between the <code> and the code (which is on purpose).

The next part is another comma-part, (.*) gets everything in between the things around it.

We have three modifiers on it: U, e, and s. The U makes the expression "ungreedy". Without the U, it would basically combine everything between the first code block and the last code block on the page combine, as well as everything else in between it. The s is "dot all". This causes s to also match newlines. Without it, it would only match one line code blocks. The e causes it to essentially runs the replace parameter through eval(), which means we can cram PHP in there using the matches... this is our magic trick.

The Replace

The replace parameter of our preg_replace is a bit more complex than the pattern. Here it is:

''<div class="code"><pre>' . preg_replace('|v{2}|', '&nbsp;</pre><pre>', preg_quote(htmlentities('$1'), '|')) . '</pre></div>'' 

So, when looking at this we have to remember that we are going to eval() the results of this, so we should look at it as if it were PHP. If we look at it like that, it'd be something like this:

'<div class="code"><pre>' . preg_replace('|v{2}|', '&nbsp;</pre><pre>', preg_quote(htmlentities('$1'), '|')) . '</pre></div>' 

Somewhat easier to look at. The very first string and the very last are easy... it's just the tags we wanted to wrap around everything. Let's focus in on the middle part.

Working from the innermost part of the middle block, we have htmlentities('$1'). $1 is of the first (and only) match from our pattern, which is (.*), essentially everything between our code tags. The htmlentities function converts all of our HTML entities (namely our <'s and >'s). After the htmlentities, we'll run it through preg_quote, just in case.

That then feeds into another preg_replace. This one has a much simpler pattern: |\v{2}|

This pattern means that we match every two vertical white space characters. Each newline typically has a \r and a \n. We want to catch both of those. If you're using a slightly different encoding, you may have to tweak this part, but it's doubtful. We replace each of those lines with "&nbsp;</pre><pre>". The &nbsp; is just a space. This puts a space in otherwise empty lines, so we can preserve the empty lines in our code blocks. The closing and opening pre basically split each of our lines with it's own pre.

All our requirements are done now. We have a div with the class of "code" filled with multiple single line pre tags.

The CSS Part

Finally, the CSS part. Compared to the PHP part, this is a cake walk.

The div itself has little bearing on the pre's, so I won't bother going into that. Just set your padding, margin, width, background, etc., however you want.

The special part is fixed onto the pre tags.

Here it is:

.code pre { 
	white-space: pre-wrap; 
	text-indent: -2em; 
	padding-left: 2em; 
	background: url(images/code_wrap.png) no-repeat left top; 

The value of the white-space is pre-wrap. If you aren't familiar with this value, it's basically the same as pre, except it can also wrap. Perfect.

The next line is text-indent. We give it a -2em, which means the first line moves to the left. This gives us our hanging indent, but then the whole thing is off. We fix this by adding 2em of padding to the left, pushing the first line back into position and moving all wrapped lines over 2em.

The last line puts in our special image.

The Image Part

This is that image (it's transparent and the arrows are the same color as this background, so it's in a dark div background):

Code Wrap Arrows

The image can handle up to four lines of wrap. Since I rarely go beyond one wrapped line, this is perfect for me. If you want to be able to handle more, you'll need to tweak the image for yourself.

Official "License": This particular image is under no license and may be used as is or modified for any purpose. There you go. ;)

Building the Image

This image is pretty simple. You can make it just about any way you want, but it has a few requirements. First, you need to figure out your line height. You may know it already, but it's pretty simple if you don't. Use Firebug or Chrome's Inspect to inspect the line. Look at the computed styles and find "line-height".

Once you have your line-height, create an image that is the width you want (if you want it wider, increase the 2em we used in the CSS part to allow for more room). Divide it vertically by your line-height. In my case, the line-height is 16px, so I divided my image into 16px. Leave the first section empty so we can leave our image at 0. You can trim it all up, but I prefer to leave the extra space since it takes almost virtually no extra file size in a PNG.

From there, divide each of your sections in half a gain. This middle point is where you'll want the point of your arrow to it, so it points right at your text. Aside from that, create your arrow however you choose and use it as your background.

And that's it! You now have your own WordPress-ready code block with word-wrapping!


Related Articles


Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>


Back to Top