Fun Times With Jekyll's Code Highlighting

Example of completed code highlighting

To get myself started with Jekyll, I figured I’d be sharing a decent amount of code (or at least posting it on here, regardless of whether or not it’ll be read). As such, I figured I should look into the syntax highlighting. Jekyll’s got a nifty syntax-highlighting scheme that I thought was pretty cool. I themed it with this Solarized Dark theme, and it looked pretty good! However, I wanted line numbers. This gets tricky; the default line numbers result in a span that’s in line with the code. This looks good, but it also makes the code uncopyable. No bueno.

There’s also a mode that offers it in tabular format, and while this is an improvement in some respects (the code is now highlightable), the table doesn’t do well with very long lines of code. It’ll either stretch past the limits of the screen (oh no), or it’ll wrap and make the inline code get out of sync with the line numbers. Either way, this is unacceptable. As such, I decided to do it client-side.

This article offers a very elegant client-side solution to the line numbers problem. Read over it if you’d like, but I essentially used that code verbatim. It resulted in a nice, unselectable, stylable, and properly-synced number next to each line, even when the line of code wraps. Perfect! I went ahead and applied a bit of styling as well; the resulting CSS code is this:

pre code {
    counter-reset: line-numbering;
    position: relative;
}
pre code .line
{
    padding:0;
    margin:0;
    display: inline-block;
    line-height: auto;
}
pre code .line::before {
    content: counter(line-numbering);
    counter-increment: line-numbering;
    width: 2em;
    text-align: right;
    font-size: small;
    opacity: 0.5;
    margin-right: 1.0em; /* space after numbers */
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    display: inline-block;
}

This resulted in nice line numbers! However, there are still a few bugs. For one, if a line is empty, it’ll result in weird bugs where the line number for the empty line digs into the following line. This wouldn’t do, so I implemented a simple fix by replacing empty lines with non-breaking spaces. This allows for the line to actually have dimensions, which will keep the line-numbering proper.

$("pre code .line").html(function(index, html)
{
  if(!html)
  {
    return "&nbsp";
  }else{
    return html;
  }
});

This was all well and good, but I wanted to be able to show what language the code is in as well. Jekyll offers no built-in options, and while I could probably do it via a plugin, I’m looking to host on Github Pages, so plugins are a no-go. I ended up implementing another jQuery stub for it. This time, I grabbed the class for the code object (stripping the ‘language-LANG’ variant created by Github-flavored block code), traverse back up the div container, wrap it in a container object, then slap a label for the language. It looks nice, in my opinion. The javascript code is here:

$('pre code').each(function( index )
{
  var codetype = $(this).attr( 'class' ).replace(/language-[^ ]*/g, "").trim();
  var hilite = $(this).parent().parent();
  hilite.wrap("<div class=\"codecontainer\"></div>");
  if(codetype)
  {
    hilite.before( "<span class=\"codelabel\"> code: <strong>"+codetype+"</strong> </span>" );
  }else{
    hilite.before( "<span class=\"codelabel\"> <strong>code</strong> </span>" );
  }
});

And the CSS is here:

.codecontainer
{
	background-color:#268bd2;
}
.codecontainer .codelabel
{
	padding: 0.5em;
	color: #FFF;
}

The end result? Highlightable, copyable code blocks with line numbers and a label for the language type. Not bad for a first go, I think. :dancer: