Swift code syntax highlighting in WordPress

The built-in “code” block for WordPress (the CMS I use for this site) is virtually useless – it’s just a <pre> block, essentially.

The appearance may vary depending on WordPress theme, but will virtually always be bland.

In fact, it’s not even guaranteed to use a monospaced font – the example I’ve shown here is what you’ll probably get with any given WordPress theme, but it’s not actually the default for the theme I use (GeneratePress) due to a known bug in GeneratePress (which the theme authors outright refuse to fix!).

In any case, you have to use WordPress plug-ins to extend or replace it with something that actually looks in any way decent.

Unfortunately, Swift is a complicated language, even just at the “superficial” level of syntax highlighting. And most generally-popular syntax highlighting tools are both:

  1. Focused on languages like JavaScript and HTML, not Swift.
  2. Written in JavaScript or Ruby, with no access to standard tooling like the Swift Language Server Protocol.

Since I’m using WordPress for this site, Ruby’s not a good option (and I didn’t find any relevant WordPress plug-ins which rely on it, anyway). Hypothetically I could add a Ruby environment to my server and do static generation through it, but, ugh. It’s annoying enough dealing with JavaScript and PHP. If you’re going to go to that much trouble, you’d probably be better off actually using Swift (e.g. SwiftSyntax). And while I’d welcome a WordPress plug-in which does exactly that, alas no such plug-in exists today.

So, I spent way too much of my time trying out a bunch of the available WordPress plug-ins, and now I shall report the results so others don’t have to suffer [as much].

I’ve presented previews for both light and dark modes (but my apologies to dark-mode viewers that all the samples default to light mode – an unfortunate limitation of my CMS).

Baseline: Xcode

Syntax highlighting theming is a very subjective and somewhat personal preference. I really must stress this, as something to keep in mind as I critique these plug-ins based on my preference, which is pretty close to Xcode’s default theme.

I’ve tried to focus mostly on how well the plug-ins understand Swift syntax & grammar and what functionality they offer broadly, rather than which ones look prettier out of the box. Most have at least some degree of custom theming support, or at least permit unofficial theming through straightforward CSS overrides.

It is unsurprising that Xcode does by far the best job of understanding and correctly syntax-highlighting Swift code, of anything tested here. It has the advantage of being able to actually compile and analyse the code with full context – the example shown here has supporting type and function definitions “off-screen” – which WordPress plug-ins do not1. While I set out on this exploration hoping to find something effectively as good as Xcode, I wasn’t really expecting to (and spoiler: I did not).

Allow me to call out a particular few things Xcode does right, that (as you’ll see) few if any of the WordPress plug-ins do:

  • In short, it supports all Swift syntax. It correctly identifies all the keywords (and things that are not keywords but happen to be the same word, such as static properties called default as in the example code).
  • It utilises not just colour but font and font weight. This permits it to effectively delineate things without having to use an excessive variety of hues.

    Some might finds its results comparatively bland with the default theme as shown here, in light mode especially, but it has other themes for those that want a more hue-centric approach, and supports a very good degree of theme customisation.

    The default theme doesn’t “demo” well (in light mode), in the same way that colour-accurate TVs look rather bland and unattractive in the showroom but are actually great in real-world use in your home.
  • Even though it uses multiple font weights, it still preserves correct letter spacing.
  • It understands DocC’s limited Markdown-like markup within documentation comments (and can even render them as properly styled text, although that’s not shown here).

I’ll also call out one thing which – in my opinion – it gets wrong, which is essentially not recognising custom type names. It renders them as plain text – no highlighting at all – yet gives special treatment to “built-in” types (from the Swift standard library) like String. It’s fine if it wants to distinguish between those two sets of type names, but it should use some kind of highlighting for both of them. Many of the WordPress plug-ins actually do a better job in this respect.

Common limitation: no Light/Dark mode support

One thing that none of these plug-ins do, that you would think they could and reasonably should, is explicitly support light / dark mode – even though most include both light and dark themes (some plug-ins even include light and dark variations of the same theme – so close!).

Instead, you have to pick just one theme. Furthermore, if you want proper light and dark mode support you have to pick a light theme specifically, to match WordPress’s default mode of light. This limits your control over the appearance in dark mode – and may make it difficult for you to find a theme which suits your aesthetic preferences in both modes.

WordPress itself doesn’t support light/dark mode – you have to2 use 3rd-party plug-ins. Depending on which one you use, you might get viable automatic switching anyway. The several that I experimented with were all able to make my theme adapt actually quite well.

I initially used WP Dark Mode, but discovered it was buggy in that it would load pages in light mode first and only after the initial render would it switch them to dark, making browsing my site in dark mode very uncomfortable. It also didn’t work properly with SyntaxHighlighter Evolved. I consequently switched to Dracula Dark Mode which is a very similar plug-in but doesn’t have those bugs.

Note that most of the dark-mode screenshots shown here were taken while using WP Dark Mode. There may be slight differences in colours with Dracula Dark Mode (or some other dark mode plug-in), but in my brief experimentation the results are virtually indistinguishable.

The contestants

Code Block Pro

This advertises itself as using the syntax highlighting engine from Visual Studio Code, but that’s actually misleading – it uses Shiki, which is really its own engine albeit one that utilises the same TextMate-inspired grammar definitions and themes as does Visual Studio Code.

It’s open source and free for the most part – for a token $12 you can support the author and obtain a couple of dozen extra themes, adding to the two dozen or so that it includes by default.

Performance

If you’re familiar with Visual Studio Code for Swift development, then you basically already know how it performs, as the results are (in my testing) identical.

That’s only mostly a compliment, though. This plug-in, like Visual Studio Code, doesn’t really understand Swift, it merely does a relatively good job of faking it.

Unlike every other plug-in tested, where the grammar parsing is completely independent of the theming, the performance of this plug-in does vary between themes. Thus, some themes might have colours you hate yet be the only ones that actually identify Swift keywords correctly, while others are the reverse. This is demonstrated in the example shown here – the Light Plus theme – where the colours are the least ugly of the themes available but it doesn’t recognise some basic Swift syntax, like protocol conformances, which is recognised in other – albeit uglier – themes.

But, in general, it:

  • Actually understands the difference between function parameter labels, parameter names, and parameter types.
  • Tends not to recognise custom type names, only the Swift stdlib & Foundation ones (e.g. notice it doesn’t recognise Floor but does recognise String). This is somewhat common behaviour amongst the plug-ins tested (and Xcode itself).
  • Doesn’t recognise some important keywords, such as async and some.

    As it happens, this is because the Swift grammar file it uses is quite a few years old and seems like it might be largely abandoned (other than sporadic community updates such as this which might or might not be incorporated by this plug-in). This is the same grammar file that Visual Studio Code uses, making it doubly-surprising, but I guess it says a lot about the level of interest the Visual Studio Code community has in Swift.
  • Is not easily fooled by the use of ambiguous names, e.g. the default static property of HomeItem that’s often mistaken for the default keyword by other plug-ins.

Pros

  • Includes the ability to highlight an arbitrary set of lines by blurring out all the others (but readers can mouse over the code block to unblur everything, if they want to see the full context of what you’re highlighting). This particular approach – blurring rather than just using a different background colour – is unique amongst all the plug-ins I found, and aesthetically far superior. Most of the other plug-ins don’t even have a way to highlight or hide certain lines.
  • Uses server-side rendering with CSS inlined into the HTML, so code is highlighted right from page load without delays or visual glitches.

    Some other plug-ins tested here do server-side syntax analysis too, but to actually effect styling they use class tagging of HTML spans with CSS, which can mean rendering glitches if the CSS takes a while to load and the browser renders the code without it in the interim. Code Block Pro avoids that (and might also play better with other styling plug-ins or modifications, such as dark mode plug-ins).
  • Has a live playground so you can easily test it out (although that playground is hard-coded to use the Fira Code font, which is only one of a number of open-source font options it provides).

Cons

  • No global settings – if you decide to change any settings, such as the theme, at any point, you have to manually find and adjust every existing code snippet manually.

    This might be considered a positive by some users, where they want existing content to remain as-is. However, some plug-ins offer both a global setting and the ability to override that on a per-case basis, providing more flexibility.
  • The provided themes – even with the paid expansion pack – are predominately intended only for dark mode, and most of the light mode ones are pastel. So if you want a clean light mode theme, as I do, you have only about three options with this plug-in.

    Furthermore, the performance varies between themes, as – unlike every other plug-in tested here – the themes are in essence tied into the parsing.

    None of the provided themes really do Swift justice compared to how well they work for other languages. Especially within the limited selection of light-mode themes, there’s precious few that don’t make obvious mistakes (like conflating the some keyword with operators, or being confounded by generics syntax).
  • Theme customisation options are extremely limited, not just officially but even unofficially with custom CSS. Although, the author seems receptive to theme suggestions – to add to the paid expansion pack – if you find something you like in the Visual Studio Code Marketplace.
    • The only way it officially allows any custom theming is with an unusual mechanism documented only in a tangential GitHub discussion: you select the theme called “Use CSS Variables”, which is a ‘theme’ that merely specifies var(--xyz) values for the color CSS property. You’re then expected to specify values for those CSS variables in some suitable stylesheet (which the plug-in does not facilitate).

      This custom theming functionality is only available in the paid version.
    • It only officially supports adjusting the colours – you nominally don’t have the ability to adjust font families, sizes, weights, or styles.

      It is possible to match each type of element, but it’s pretty clumsy and fragile, because…
    • As mentioned under Pros, it inlines the style information directly into the HTML span tags, as simple color style attributes. While that’s good for avoiding rendering glitches, the downsides are that:
      • It produces more verbose HTML than if it just used a short class name on the spans (as all the other plug-ins do), which can hurt page load times.
      • It’s more difficult to customise the styling with CSS, since you have to match on the colours – using CSS attribute queries like span[style*=#xxyyzz] – which is not just awkward but can be impossible to do precisely for multiple distinct grammar elements depending on the base theme used.
      • It optimises the HTML by merging (server-side) span elements with the same style information. That’s great for reducing page size and load times, but if the base theme doesn’t already visually distinguish between two distinct grammar elements, it’s impossible to distinguish them through custom CSS.
  • Custom themes don’t render in the post editor – you just get plain pre-formatted text. (built-in themes work fine in the editor)
  • Uses a custom Gutenberg block type, rather than just extending the standard Code block. So you can’t just upgrade your whole existing site – you have to manually go through and find every existing Code block, and manually migrate each one.

    Inversely it’ll also be more difficult to migrate away from, if you choose to do that some day, as you’ll likely have to repeat that whole process no matter what replacement plug-in you choose.
  • If you enable the ‘Copy’ button for the convenience of your readers, it includes a duplicate copy of the code in a hidden span (as do at least some of the other plug-ins tested, although I didn’t always call it out here).

So in a nutshell, if you’re completely happy with its built-in theme options, then this is one of your better options. But if you want theme customisation, it becomes worse than many of the other plug-ins, sadly.

CodeColorer

A very old – though nominally still maintained – plug-in uniquely based on GeSHi.

It’s open source and free (as is the GeSHi engine underneath it).

Neither the plug-in itself nor the GeSHi engine have seen a lot of activity in recent years (and confusingly the old GeSHi webpage is still up as is the early GeSHi page on SourceForge, creating an even worse first impression). Both predate the [public] existence of Swift entirely.

To be honest I’m including it here only for completeness. It basically doesn’t work – especially for Swift – and shouldn’t actually be considered. It seems intended solely for use via shortcodes – even though it does take over all existing <code> blocks – which I didn’t test as the use of shortcodes in WordPress is archaic, and poorly supported in the modern (Gutenberg) editor. They seem to still be officially supported, and not formally deprecated, but I think introducing any new reliance on them at this point is foolish.

Performance

So, yeah… no syntax highlighting at all. It’s not apparent to me if this is a failure specific to Swift or if the plug-in in general just doesn’t work. It does offer a [non-live] preview in its settings, which does work for its example snippet of JavaScript.

It also (by default) forces the code into a tiny box, although you can fix this through its settings.

There’s no per-use customisation since it just takes over any existing <code> blocks, and there’s very few global settings – including an absence of any setting for a default language.

I won’t bother trying to enumerate its specific pros and cons – it’s clearly not a viable contender.

Code Syntax Block

A simple plug-in based on Prism.js, with very limited customisation options.

It’s open source and free (as is the Prism.js engine underneath it).

Performance

Prism.js prides itself on being [relatively] small. Perhaps because of that goal of being “lightweight”, its performance is a bit mediocre.

The default theme makes it look even worse than it really is, because it bizarrely doesn’t provide any distinguishing styling for important things, like type names.

On the upside, it does get a few things right which other plug-ins often don’t – even others which also use Prism.js, curiously, like Highlighting Code Block. Things like it:

  • Recognises @-attributes, such as macro and property wrapper invocations.
  • Recognises relatively new Swift keywords such as async & await.
  • Understands multi-line and raw strings.

On the downside it:

  • Doesn’t recognise a lot of very basic Swift syntax – or, at least, doesn’t distinguish them with a span and therefore resigns them to the default, plain text styling of the overall code block – including but not limited to:
    • Variable names (neither their declaration nor references to them).
    • Function parameter labels & names.
    • Property names.
    • Tuple field labels.
  • Doesn’t recognise method calls consistently (e.g. pack & reduce vs map in the example shown).

Although you can’t tell with its default theme, it actually recognises custom type names (although doesn’t distinguish them from Swift standard library types, like Xcode – though it’s debatable whether that’s a feature).

It uses font weight, not just colour, which would go a long way towards giving it higher fidelity without making it look garish if it didn’t use it really weirdly. Instead of bolding keywords, for example, it bolds function & method names – sometimes, when it recognises them correctly.

At least it defaults to Menlo, which is actually a respectable choice and makes it one of the few plug-ins tested that have a decent default for Apple platforms. In case you’re unfamiliar, Menlo was the default monospace font for Snow Leopard through Yosemite (before it was replaced by SF Mono). You’d most likely have encountered it in Terminal or Xcode, if you used a Mac in that timeframe (2009 – 2015). It’s still available on every Apple device (as of time of writing, December 2023).

Pros

  • Extends the built-in, standard Code block. This makes it comparatively trivial to adopt if you’ve already got Code blocks on your website (although you may still need to go through and customise some things, such as the language in case auto-detection doesn’t work correctly).

    This also makes it easier to switch syntax-highlighting plug-ins, provided that the one you switch from or to also supports the standard Code block, which is sadly a minority of them.

Cons

  • Hasn’t been updated in a year – possibly abandoned.
  • Does everything client-side, so there’s a noticeable delay before syntax highlighting is actually applied (especially on first load, when the relevant JavaScript & CSS isn’t cached in the browser). It’s a bit visually jarring as the unstyled code is replaced with the styled.
  • Adds its Prism CSS & JavaScript files to every page load, irrespective of whether the page actually needs them or not. This is the core Prism.js library only – the grammar file for each language is only loaded when actually needed.

    They are somewhat small files, at least – most of it is Prism.js at 30 KB alone, plus a few extra KBs for the chosen theme’s CSS. With Brotli compression they’re ~13 KB. Language grammar files tend to be only 3 KB or less.
  • Very few built-in themes – only four – and using a custom theme is technically possible but awkward. The official instructions didn’t work for me, either – I had to use the WPCode plug-in to execute the relevant PHP:

    add_filter('mkaz_prism_css_url', function() {
        return '/wp-content/themes/prism-xcode.css';
    });
  • Theming is controlled globally with no ability to override it for specific uses.

    This is (IMO) better than not having any global controls at all, as with some plug-ins, but it can be problematic if you use more than one language in these code blocks across your website, as you might prefer different themes for different languages.

    You can technically work around this limitation using custom CSS, since the language is included as a class on the relevant pre and code HTML elements.
  • Doesn’t render the syntax highlighting in the Gutenberg editor, so you’re stuck with the generic pre appearance there.

Enlighter

The official WordPress plug-in for the EnlighterJS engine.

It’s open source and free (as is the EnlighterJS engine underneath it).

Performance

Generally it does a poor job, with Swift code, and it’s not really a mystery why – its grammar file for Swift is especially spartan and hasn’t been updated since it was created over five years ago! That’s the Swift 4.1 era at best.

It actually behaves very similarly to the SyntaxHighlighter Evolved plug-in, but with the significant difference that it leaves things it doesn’t understand as the plain text colour (e.g. black in Light mode), so it’s much more apparent even at a glance that it doesn’t really understand much.

For example, it:

  • Doesn’t understand @-attributes, such as macro and property wrapper invocations.
  • Has no idea about the difference between function parameter labels and parameter arguments.
  • Doesn’t consistently recognise references to properties, such as when they’re part of KeyPaths.
  • Doesn’t understand some important keywords, like async, await, Never, etc.
  • Recognises only a limited selection of types – all from the Swift standard library – and has no idea about custom types.
  • Doesn’t recognise method calls consistently (e.g. pack & reduce vs map in the example shown).

In a nutshell, it’s doing little more than picking out a pre-defined list of keywords, identifying string & numeric literals, and comments.

Though it does at least handle multi-line and raw strings correctly (albeit only in some themes – in a few it underlines strings and mistakes the indentation as part of the string, for multi-line strings).

The choice of Courier New as the default font is… brave. It’s not actually its preferred default – it favours Source Code Pro foremost, with Liberation Mono as a second choice. They’re both reasonable open-source monospace fonts, but neither are standard fonts on any Apple devices, and the plug-in doesn’t include them.

You can customise the font to a very limited degree – the plug-in provides only five options, none of which are standard Apple OS fonts so the choice is effectively pointless. Thankfully you can override its font choices, like pretty much all its styling, with custom CSS.

Pros

  • Supports both a global theme setting as well as use-specific overrides.
  • Supports both soft & hard wrapping (the latter meaning it uses a horizontal scroller if necessary, rather than fitting the text to the viewport – generally not what I recommend since it’s pretty hostile to small screens but it’s a notable feature to make this behaviour configurable).
  • Includes a pretty extensive theme customiser, as an actual HTML forms-style interface in the plug-in settings pages. That GUI is ultimately just a bespoke configurator for the CSS – which helpfully it also provides, in case you want to save or serve that elsewhere.

    And if that proves insufficient – or you just prefer to do it manually – it uses a sensible system of spans with suitable classes, so it’s easy to write custom CSS for styling.
  • Provides its own Gutenberg block, but can also optionally be applied to the built-in WordPress Code block, as well as potentially blocks from other plug-ins (Crayon Syntax Highlighter & CodeColorer are explicitly supported – unclear if it also supports Urvanov Syntax Highlighter, the ‘reincarnation’ of the otherwise abandoned Crayon Syntax Highlighter).

Cons

  • Built-in themes are pretty limited and (IMO) pretty ugly, at least for the light-style ones (which is ten of the thirteen). The one demonstrated here is the default – just called “Enlighter” – which is about the best it has to offer. 😕
  • Puts its settings item at the top level of the WordPress admin menu, rather than under Settings.
  • Adds its CSS & JavaScript files to every page load, irrespective of whether the page actually uses the Enlighter block or not. Along with some inline JavaScript in every page header.

    And they’re not trivial files, either. The CSS is 80 KB uncompressed – ~10 KB with Brotli compression, larger with GZip or Zip (Deflate). That’s factoring in CSS minification, too. The JavaScript is 63 KB uncompressed (~19 KB with Brotli).

    It does offer an option to supposedly avoid this – “Dynamic Resource Invocation” – but it’s disabled by default, and still requires inclusion of a “small” 1 KB JavaScript file with every page load just to determine if the rest of the code & CSS should be loaded. So, kind of a hack to try to cover up a design flaw. Alternatively, you can disable automatic inclusion of the CSS & JavaScript files and handle that manually, but I can’t imagine anyone actually wants to have to deal with that.
  • Doesn’t render the syntax highlighting in the Gutenberg editor, so you’re stuck with the generic pre appearance there.

So, overall a pretty poor option, both in terms of how well it understands Swift – i.e. particularly badly – and how it looks out of the box. It does have a lot more options than most of the other plug-ins, and its GUI for theme editing might be a unique selling point for a – presumably rather limited – market of people that want to include Swift code on their website but aren’t comfortable writing CSS. Even that withstanding for argument’s sake, I think it falls solidly towards the bottom of the pile.

Highlighting Code Block

A relatively simple plug-in based on Prism.js, with limited customisation options.

It’s open source and free (as is the Prism.js engine underneath it).

Performance

Prism.js prides itself on being [relatively] small. Perhaps because of that goal of being “lightweight”, its performance is pretty poor – and pretty obviously so even at just a glance.

For example, it:

  • Doesn’t understand @-attributes, such as macro and property wrapper invocations.
  • Has no idea about the difference between function parameter labels and parameter arguments.
  • Doesn’t consistently recognise references to properties, such as when they’re part of KeyPaths.
  • Doesn’t understand some important keywords, like async & await.
  • Doesn’t recognise method calls consistently (e.g. pack & reduce vs map in the example shown).
  • Doesn’t understand multi-line nor raw strings.

On the positive side, it actually recognises custom type names (although doesn’t distinguish them from Swift standard library types, like Xcode – though it’s debatable whether that’s a feature).

It uses italics, not just colour, which goes a long way towards giving it higher fidelity without making it look garish. Unfortunately, its use of italics is weirdly inconsistent – e.g. it italicises some keywords but not all (e.g. final vs class), and italicises some type names but not others (e.g. VStack vs Image & Text).

It doesn’t take much effort to understand why – it’s using a very simplistic parser that knows virtually nothing about the language (other than a hard-coded list of keywords) and instead is just going off of capitalisation, mostly. Which is somewhat clever, and gets it a long way for such a simple method, but ultimately results in poor performance.

At least it defaults to Menlo, which is actually a respectable choice and makes it one of the few plug-ins tested that have a decent default for Apple platforms. In case you’re unfamiliar, Menlo was the default monospace font for Snow Leopard through Yosemite (before it was replaced by SF Mono). You’d most likely have encountered it in Terminal or Xcode, if you used a Mac in that timeframe (2009 – 2015). It’s still available on every Apple device (as of time of writing, December 2023).

It’s a bit weird that the performance is significantly different from some other Prism.js-based plug-ins, like Code Syntax Block. It’d be explicable if one plug-in were strictly superior to the other – suggesting simply use of a newer version of Prism.js by one than the other – but it’s actually a weird mix of improvements and regressions.

Pros

  • Good bang-for-your-buck configuration options, which is to say that it has relatively few but it includes the essentials and with maximum flexibility (e.g. font customisation is by entering the actual font-family CSS string, rather than being limited to do a predefined short list of options as with most other plug-ins).

Cons

  • Does everything client-side, so there’s a noticeable delay before syntax highlighting is actually applied (especially on first load, when the relevant JavaScript & CSS isn’t cached in the browser). It’s a bit visually jarring as the unstyled code is replaced with the styled.
  • Adds its CSS & JavaScript files to every page load, plus some inline CSS & JavaScript, irrespective of whether the page actually needs it or not. This includes the entire Prism.js library with grammar parsers for every supported language, irrespective of which ones are actually used.

    And they’re not entirely trivial files, either – mainly because of Prism.js at 35 KB alone. Overall they’re 41 KB before compression (~18 KB with Brotli).
  • Limited theming control – it has an unnamed built-in default, which you can override by specifying a server-side path to a custom CSS file (although functionally this isn’t much different from just putting your custom CSS in your website’s general custom CSS file, because of the aforementioned flaw whereby this plug-in inserts its CSS into every page load).
  • Theming is controlled globally with no ability to override it for specific uses.

    This is (IMO) better than not having any global controls at all, as with some plug-ins, but it can be problematic if you use more than one language in these code blocks across your website, as you might prefer different themes for different languages.

    You can technically work around this limitation using custom CSS, since the language is included as a class on the relevant pre and code HTML elements.
  • Includes support for a relatively small number of languages (by default), although that does include Swift and Objective-C, among many other popular languages. I list this as ‘con’ only in a relative sense – for most users its built-in shortlist is likely quite sufficient.

    You can provide a custom build of Prism.js if you need others, although it’s left as an exercise to the user to figure out how to do that (and to then maintain it).
  • Doesn’t render the syntax highlighting in the Gutenberg editor, so you’re stuck with the generic pre appearance there.
  • Uses a custom Gutenberg block type, rather than just extending the standard Code block. So you can’t just upgrade your whole existing site – you have to manually go through and find every existing Code block, and manually migrate each one.

    Inversely it’ll also be more difficult to migrate away from, if you choose to do that some day, as you’ll likely have to repeat that whole process no matter what replacement plug-in you choose.

Prismatic

A uniquely versatile plug-in that supports both the Prism.js and highlight.js engines.

It’s open source and free (as are the Prism.js and highlight.js engines underneath it).

Unfortunately, it immediately disqualified itself by simply not working. After installing & activating it in WordPress, nothing happens. The built-in Code block doesn’t change, there is no new Gutenberg block (contrary to its documentation which claims it adds a “Prismatic” block), and nothing appears anywhere in the WordPress Admin menu, such as a global settings page.

I checked the PHP logs and found no mention of the plug-in nor any relevant log messages.

It’s unusual – in my experience – for a WordPress plug-in to just silently fail like this. While it might be possible to enable WordPress debug logging and ultimately figure out what’s going on, in my experience first impressions are indicative when it comes to WordPress plug-ins, so I’m not going to spend time trying to get a plug-in to work at all when it’s probable it’ll have numerous other problems anyway.

Syntax-highlighting Code Block (with Server-side Rendering)

Nominally a fork of Code Syntax Block that renders server-side instead of client-side, although it uses a different engine – Highlight.php instead of Prism.js.

highlight.php is a PHP port of Highlight.js. It’s unclear to me how closely or promptly that tracks changes to the original JavaScript library.

It’s open source and free (as is the highlight.php engine underneath it).

Performance

The default theme is particularly bland. It’s actually hard to judge its understanding of Swift purely from its appearance since so much of it looks the same.

It’s noteworthy as a particularly hostile plug-in (with its default theme) for colourblind viewers, due to its use of very similar shades for almost everything, and in particular its use of red vs grey in a way which makes them virtually indistinguishable to a significant portion of the population. It’s not the only plug-in to be thoughtless in this way, but it is the worst.

It does come with a lot of other themes – nearly ninety at time of writing – but you’d be forgiven for thinking it does not, as it puts the theme selection setting in a surprising location – the ‘Customize’ section of WordPress’s Appearance settings. While this actually makes tremendous sense, no other syntax-highlighting plug-ins put their settings there. It’s hard to hold that against this plug-in, for being the one plug-in which (arguably) does the right thing, but I almost overlooked this critical functionality – I only discovered it by chance because I happened upon its Advanced Usage documentation.

That all said, one thing the bland default does have going for it is that the visual sameness helps to slightly obscure how poorly the plug-in understands Swift.

For example, it:

  • Doesn’t understand @-attributes, such as macro and property wrapper invocations.
  • Has no idea about the difference between function parameter labels and parameter arguments.
  • Doesn’t consistently recognise references to properties, such as when they’re part of KeyPaths.
  • Doesn’t understand some important keywords, like async & await.
  • Doesn’t recognise method calls consistently (e.g. pack vs reduce & map in the example shown).
  • Doesn’t understand raw strings (though it does handle multi-line strings correctly).
  • Is fooled by the use of keyword-looking names in places where they aren’t keywords, e.g. the default static property of HomeItem.

It’s pretty apparent, especially once you look at the HTML itself, that it’s doing only a rudimentary analysis mainly based on a hard-coded list of keywords and heuristics like whether words start with capital letters. That’s why it confuses literals (strings & numbers) with type names, function names with property names, and so forth. It’s not the only plug-in to try to fake it with such a simplistic algorithm, but it does the worst job of pulling it off.

It renders keywords in bold (like Xcode), which greatly aids readability.

Since it uses the built-in WordPress Code block as its basis, and doesn’t muck with the fonts, it defaults to whatever the active WordPress theme uses. As shown in this example, with GeneratePress, that’s not even necessarily a monospaced font! Worst, the plug-in has no built-in configuration option for font (although you can use custom CSS to override it).

Pros

  • Extends the built-in, standard Code block. This makes it comparatively trivial to adopt if you’ve already got Code blocks on your website (although you may still need to go through and customise some things, such as the language in case auto-detection doesn’t work correctly).

    This also makes it easier to switch syntax-highlighting plug-ins, provided that the one you switch from or to also supports the standard Code block, which is sadly a minority of them.

Cons

  • No official theming support.

    You can use custom CSS to re-theme it, thanks to its use of sensible class names for its spans, but other than fixing its bland default colours you can’t really improve it much, since a lot of the code is emitted as runs of plain text because of the plug-in’s very poor understanding of Swift.
  • No global settings – if you decide to change any settings, at any point, you have to manually find and adjust every existing code snippet manually.

    This might be considered a positive by some users, where they want existing content to remain as-is. However, some plug-ins offer both a global setting and the ability to override that on a per-case basis, providing more flexibility.
  • Very limited settings – just the language (if you don’t want to rely on auto-detection), which line(s) to highlight, whether to soft wrap, and whether to show line numbers.

SyntaxHighlighter Evolved

This is what I was using for years. It’s completely free and open source. It uses a proprietary syntax parsing system based on regular expressions.

Performance

It’s an interesting one, because it actually understands so little Swift syntax that most of it is bucketed together as ‘plain’ text. However, because it renders ‘plain’ text in a colour other than black, it gives the surprisingly convincing (at a glance) illusion that it understands much more than it really does.

Overall its rendering is close to Xcode’s, which is very surprising given its highly rudimentary grammar parser.

It is actually pretty good about identifying keywords – it actually gets async which many do not – but it doesn’t understand them with context, e.g. it mistakes the default static property of HomeItem with the default keyword.

It renders keywords in bold (like Xcode) which greatly aids readability, although note how (unlike Xcode) it messes up the letter spacing as a result (this is a result of the font used – Monaco – and thus can be fixed by overriding that with a better font, e.g. SF Mono).

While it covers up a lot of its ignorance with its clever colour choices, there’s still a few important things that it gets visibly wrong. For example, it:

  • Doesn’t understand @-attributes, such as macro and property wrapper invocations.
  • Has no idea about the difference between function parameter labels and parameter arguments.
  • Doesn’t understand raw strings.

Its choice of Monaco as its font is… interesting, although modern versions of Monaco are thankfully a little smoother than their 1980s ancestor. That’s easy to override, however, via custom CSS in a suitable WordPress-generic stylesheet (the plug-in doesn’t provide any direct way to manipulate styling, beyond choosing from a short list of built-in themes).

Pros

  • Most of its settings are global. So changing themes for a whole site is trivial.
  • Uses sensible HTML structure and class names, so it’s easy to unofficially re-theme (although it has a very limited vocabulary of grammar, so you can’t greatly improve what you see here).
  • Supports end-user editing of the code (with the syntax highlighting updating appropriately). This is purely superficial text editing – there’s no support for interpreting, compiling, or executing the code. So I’m not really sure what the point of this feature is, but I list it here since it is unique to this plug-in (amongst all those I tested).

Cons

  • Doesn’t formally support light/dark mode (as do none of the plug-ins tested). Colours are fixed (to whatever theme you choose) irrespective of the end-user’s light/dark setting (again, same as all the other plug-ins). However, one difference versus all the other plug-ins is that this one doesn’t work properly with WP Dark Mode – it remains in light mode even while the rest of the page renders correctly in dark mode.

    I strongly suspect the fault lies in WP Dark Mode, not SyntaxHighlighter Evolved, but irrespective it is there and might be a deal-breaker if you’re particularly attached to WP Dark Mode.
  • Doesn’t render the syntax highlighting in the Gutenberg editor, so you’re stuck with the generic pre appearance there.
  • Uses a custom Gutenberg block type, rather than just extending the standard Code block. So you can’t just upgrade your whole existing site – you have to manually go through and find every existing Code block, and manually migrate each one.
  • Doesn’t get updated super often, although it has been around for years and has generally kept up with new WordPress versions, eventually.

Urvanov Syntax Highlighter

A fork of the abandoned Crayon Syntax Highlighter that uses its own syntax-highlighting engine.

It’s open source and free.

I almost didn’t include this because (a) it’s really very broken and (b) it doesn’t really support Swift at all. I strongly recommend against using it, for numerous reasons.

Performance

Pretty terrible, in a nutshell. I’m not going to go into full detail here because the plug-in is largely broken anyway (details shortly, in the Cons section).

Ironically it works better out of the box than if you actually configure it “correctly”; it doesn’t recognise this example as any specific language and falls back to some generic “Default” grammar parser. If you explicitly set it to Swift, the syntax highlighting actually gets markedly worse, and it’s no surprise why – its Swift grammar definition is nearly a decade old, dating back to Swift 1.0 in 2014!

One of its most egregious rendering problems is that it translates various special characters – [, <, >, etc – to their escaped HTML entities. This can be ‘corrected’ in its settings – it has a “Decode HTML entities in code” option – but that’s a hacky bandaid over the bug, that precludes you from actually using HTML entities in your code example (so you can’t use this plug-in for the HTML language itself).

Another rendering annoyance is that it makes the code block’s width 100%, irrespective of the actual width of the code. Most of the plug-ins do that, actually, but it’s much more apparent with this one because of its use of a visual border and alternating line background colours. You can configure a maximum width in its global settings, but (as with most of these plug-ins) there’s no (built-in) way to make it size to fit.

On syntax understanding itself, it basically has none. It simply recognises some fairly general syntax patterns, such as strings, literals, and parenthesis-indicated function calls. It doesn’t recognise most keywords, even.

Pros

  • Very configurable – perhaps the most configurable plug-in tested. Beyond just theming options – including the ability to easily change the font from its default of Monaco – it includes options rarely covered by other plug-ins such as margin customisations.

Cons

  • Nominally offers a Gutenberg block, but it doesn’t work – you cannot actually edit the textual contents, in the Gutenberg editor, and it doesn’t render at all on the actual published page. Thus you can only use the plug-in by having it take over existing <code> and/or <pre> blocks…
  • Takes over all existing <code> and <pre> blocks by default, even those by other plug-ins, and those that don’t contain code at all (e.g. where you were simply presenting monospaced text such as Terminal output). You can configure this in the settings, including turning it off, but given the Gutenberg block doesn’t work, this is the only way to actually use the plug-in.

    Screenshot of the'Tag' settings for the Urvanov Syntax Highlighter WordPress plug-in

    I spent some time playing with different combinations of these settings, but many combinations are inexplicably unusable – they just result in broken rendering – and I couldn’t find anything that improved on the default behaviour.

    As such, this is an especially all-or-nothing syntax highlighter. It really doesn’t play well with others.
  • Since it just takes over existing <code> and/or <pre> blocks, there’s no per-use customisation possible – everything is exclusively controlled through global settings, including the code language.
  • By default adds its CSS & JavaScript files to every page load, plus some inline CSS & JavaScript, irrespective of whether the page actually needs it or not. This can nominally be corrected in the settings, via the “Attempt to load Crayon’s CSS and JavaScript only when needed” option, but I didn’t test it (and it’s not encouraging that it’s both disabled by default and uses the word attempt, both suggesting this feature doesn’t work reliably).

    And they’re not entirely trivial files, either, even though rendering is done server-side – its JavaScript is 65 KB alone! Its CSS is another 28 KB. With Brotli compression they’re ~18 KB. They compress well in part for the same reason they’re so egregiously large – the use of “urvanov-syntax-highlighter” / “urvanov_syntax_highlighter” prefixes on so many of the names. This bloats up the page source as well, with oversized HTML class names for every snippet of styled code.
  • Doesn’t render the syntax highlighting in the Gutenberg editor, so you’re stuck with the generic pre appearance there.

The winner

…is hard to pick unilaterally. Each plug-in has significant limitations or trade-offs. Which is best may depend on your personal preferences and specific needs.

Most of the plug-ins do a pretty atrocious job at actually understanding Swift, and at best for them it’s a question of how well they can fake it through clever heuristics and styling choices. SyntaxHighlighter Evolved warrants an honourable mention in this regard for doing a particularly impressive job despite its very limited brains. There’s a reason I used it for years with relatively few complaints, and if it hadn’t had issues with WP Dark Mode – before I realised WP Dark Mode was buggy anyway and had to be replaced – I probably wouldn’t have bothered doing all this competitive research, and wouldn’t be switching away from it.

The most common engines used by syntax-highlighting plug-ins are Prism.js and Highlight.js / Highlight.php, but frankly they’re bad at Swift – a situation that’s unlikely to change given Swift is such a niche language for them; they’re clearly focused on browser languages like JavaScript, HTML, and CSS. Even that aside, they tend to use client-side rendering which is slower and buggier.

Ultimately, I tentatively believe that Code Block Pro is the best option.

It currently does a somewhat average job in understanding Swift and rendering it pleasingly – just like all the plug-ins tested – but it seems to have the most promising foundation, being based on the same grammar & theme files as are used by Visual Studio Code (and GitHub). So it has the possibility of significant improvements in future; at the very least it would make sense for the Swift community to focus on it since the benefits will be applicable not just to WordPress websites but also Visual Studio Code and GitHub.

Refinements to Code Block Pro

Every light-style theme available with Code Block Pro – including the paid expansion pack – has significant rendering errors for Swift, but after spending an egregious amount of time exploring the themes and experimenting with fixes for them, I’ve concluded that Light Plus is the least bad option. With some crude but simple CSS I’m able to adjust its appearance as shown here, which is loosely styled after Xcode’s default (light mode) theme.

I didn’t do much to accomodate Dark mode, limiting my modifications there to merely using SF Pro (“system-ui”) for comments. I don’t use Dark mode myself, so I might not have a good eye for what looks good there, but the default colours (from the simple inversion by the Dracula Dark Mode plug-in) seem alright to me. And pragmatically, I’d have to overwrite every colour used in the theme in order to ensure no rendering issues, and that’s a whole lot of CSS I don’t want to write nor bloat my page loads with.

I also turn on “Disable padding” in its “Extra Settings”, as by default it uses (a) hard-coded padding dimensions, in pixels and (b) padding, not margins. A strange choice, but at least it has the option to disable it.

div.wp-block-kevinbatdorf-code-block-pro {
	font-family: "SF Mono", SFMono-Regular, ui-monospace, monospace;
	width: fit-content;
	margin: 1em;
	
	& span[style*=\#0000FF], span[style*=\#AF00DB] { /* Keywords */
		font-weight: 675;
		color: #9B2393 !important;
	}
	
	& span[style*=\#008000], span[style*=\#81f179] { /* Comments */
		font-family: system-ui !important;
		font-style: italic;
	}
	
	& span[style*=\#008000] { /* Comments */
		color: #5D6C79 !important;
	}
	
	& span[style*=\#001080] { /* Properties */
		color: #3E8087 !important;
	}
	
	& span[style*=\#795E26] { /* Function names and argument labels */
		color: #804FB8 !important;
	}
	
	& span[style*=\#267F99] { /* Type names */
		color: #4B22B0 !important;
	}
	
	& span[style*=\#A31515] { /* String literals */
		font-weight: 500;
		color: #D12F1B !important;
	}
	
	& span[style*=\#098658] { /* Numeric literals */
		font-weight: 500;
		color: #272AD8 !important;
	}
}

What are other websites using?

I figured it might be helpful to look at what other Swift-code-rendering websites use, to see if there’s any I missed (there wasn’t) and which the community seems to believe is best.

If you’re keeping score, that’s (syntax-highlighter-wise):

  • Prism.js: 7
  • Rouge: 5
  • Unknown: 2
  • Highlight.js: 1
  • Splash: 1

And platform-wise:

  • WordPress: 5
  • Unknown: 3
  • Jekyll: 2
  • Proprietary: 2
  • Bootstrap: 1
  • Hugo: 1
  • Substack: 1
  • Squarespace: 1
  • Publish: 1

It’s notable that not one is using Code Block Pro nor the underlying Shiki engine, even though (with the serious caveats mentioned earlier) they do the best job of actually understanding Swift.

  1. Strictly-speaking not for any technical reason, as the plug-ins could run more advanced tooling on the server (as some bespoke CMS’s do), but I have not encountered any WordPress plug-in which does so. ↩︎
  2. Technically you can do it with just custom CSS, by overriding your theme’s defaults inside a @media (prefers-color-scheme: dark) block, but this is likely impractical for all but the most simplistic and static WordPress installations – you have to be sure you catch every GUI element and colour. A good plug-in will dynamically rewrite the CSS client-side, ensuring everything is covered. ↩︎

4 thoughts on “Swift code syntax highlighting in WordPress”

  1. hi Wade, thanks for the shoutout, love the blog! just wanted to clarify that i have not actually used any proprietary highlighter on Swiftinit in many years, today we just use SwiftSyntax! this means we “bake” the highlights before the code ever gets uploaded to the server, so neither the server nor the client does any highlighting at all.

    i’d love to discuss the highlighting system more if you’re interested. but first, can you update my name in this post? thanks!

    Reply

Leave a Comment