Using Prism for syntax highlighting with Sculpin
Update: since publishing this article I have replaced Prism with Pygments, a Python package that is run when building the Sculpin site so that JavaScript is no longer required to view my site. Although this removes the original issue that inspired me to write this article, the solution can still be useful for other people, so I've decided to keep this article on my blog.
I have been playing with the idea of starting my own blog for a while, but until
now my website consisted of just a static index.html
(along with
some Sass file and images). Writing the HTML manually worked fine for a single
landing page, but I realised that for a blog this would quickly become
cumbersome. In order to keep the management of my site as easy as possible,
without having to run a fully-fledged, database-backed content management
system, I decided to go for a static site generator.
When it comes to static site generators, there are a lot of options available, written in many different programming languages. I decided to go with Sculpin, a static site generator written in PHP and based on Symfony. Just as most static site generators, Sculpin allows converting lightweight markup languages such as Markdown and Textile to HTML. Together with a template (written in Twig) this is rendered into a full HTML page. If you want to read more about Sculpin, my former colleague Matthias Noback has written some excellent blog posts about it.
After having set up Sculpin, a basic layout based on Bootstrap and some pages, the result was starting to look like a proper blog. However, obviously a blog about programming is not complete without code samples and syntax highlighting. At first I installed highlight.js for syntax highlighting, as I already had some limited experience with it from creating a presentation with code samples using reveal.js. However, after playing around with it for a bit, I discovered that the functionalities of highlight are a bit limited as it lacks support for certain syntax elements such as variable and method names.
Disappointed, I started searching for an alternative, and found Prism. Like highlight.js, Prism is a JavaScript library that offers syntax highlighting for a lot of different languages and supports multiple themes. However, the syntax highlighting offered by Prism seems far more complete than that of highlight.js, and when using the Darcula theme it displays my piece of test PHP code almost exactly the same as PhpStorm does:
<?php
declare(strict_types=1);
namespace NicWortel\Demo;
class Foo
{
private const MY_CONST = 1;
/**
* @var string
*/
private $bar = '';
public function __construct(string $bar)
{
$this->bar = $bar;
}
public function getBar(): string
{
return $this->bar;
}
public function getFoo(): string
{
echo self::MY_CONST;
return $this->getBar();
}
}
But in order to get Prism working with my Sculpin blog, there was one more
hurdle to take. The Markdown parser used by Sculpin surrounds code blocks
(either indented or "fenced") with <pre><code>
tags. When using fenced code
blocks, you can add the language name after the three backticks which will
translate into a class
being set on the <code>
tag:
```javascript
var s = "JavaScript syntax highlighting";
```
<pre><code class="javascript">var s = "JavaScript syntax highlighting";</code></pre>
While this works fine for highlight.js (which will even try to detect the
language automatically if the class is omitted), Prism is a lot more strict and
only works when code blocks have a language-xxx
(or lang-xxx
) class.
Unfortunately, this doesn't play nicely with Markdown. I could decide
to use ```language-xxx
in my Markdown files, but this would disable all
syntax highlighting within my Markdown files in PhpStorm, GitHub, etc.
Luckily PHP Markdown, the Markdown
parser used by Sculpin, supports configuring a class prefix for fenced code
blocks by setting the code_class_prefix
property on the MarkdownExtra
class.
So the only remaining question was how to change the value of this property on
the instance of MarkdownExtra
used by Sculpin. And because Sculpin is based on
the Symfony framework, this was actually quite easy. Just like Symfony, Sculpin
can be configured using YAML files. In order to change the value of the
code_class_prefix
property, all I had to do was to create a file
app/config/sculpin_services.yml
and override the service definition of the
Markdown parser:
# app/config/sculpin_services.yml
services:
sculpin_markdown.parser:
class: '%sculpin_markdown.parser.class%'
properties:
code_class_prefix: language-
And that was it! The Markdown parser now prepends all code classes in the
generated HTML with language-
, enabling syntax highlighting with Prism while
keeping syntax highlighting inside the source Markdown files intact.