Syntax highlighting plugin for PicoCMS


A PicoCMS plugin that adds Pygments syntax highlighting to code blocks that have a language definition.

The plugin does all its work server-side.
If you care about keeping your site javascript free, you might like this.
If not - I would recommend other solutions.

It is written in PHP, just like PicoCMS itself, but Pygments is written in Python and there is no PHP version of it.
Therefore it needs to execute an external program with exec, which is just python3 -I with an ad-hoc generated script (it does not call the pygmentize script included with python-pygmentize).
This increases loading times much more than any pure PHP solution (but IMO Pygments is still the best, most up-to-date solution for non-javascript syntax highlighting).

To minimise this impact the plugin

  • considers only code blocks that are marked with a language class (it does not guess at the language)
  • executes python at most once per page (and not once per code block)
  • caches Pygments' output and prefers to re-use that.

So the best-case scenario is that all code blocks have been cached peviously and will be read from (RAM)disk, and there's no need to call python at all.
I made some (unscientific, anecdotal) comparisons with Firefox' developer tools - the result is clear enough:

  • Without internal caching this plugin adds between 66% and 91% to the loading time (the HTML of the page only, no assets like images or CSS).
  • With internal caching (and all code blocks loaded from cache instead of being generated by pygments) the plugin adds between 2% and 5% to the loading time.


You need

  • to have PicoCMS up and running.
  • the DOM module for PHP (possibly also the SimpeXML and XML modules; on Debian, these are packaged into php-xml.
  • Python3 and a Python3 version of Pygments. I tested with both python3-pygments from Debian stable repos (2.3.1) and a much newer, pip-installed version - both worked.

Tested on Debian buster (stable), PicoCMS 2.1.4 and PHP 7.3.


There are two ways - cloning the git repository, or manually downloading the plugin.

Git clone-up-

  • Change into your PicoCMS install's /plugin directory, open a terminal there.
  • Execute git clone https://$site.org/ohnonot/PicoPygments, where $site is either framagit or notabug.

If you follow a few simple rules, you can always cd PicoPygments; git pull to the newest version:

  • Don't edit any files inside the repository.
  • Copy the picopygments.yml config file to your PicoCMS install's /config directory.
  • Create custom files inside the repository that have the word custom in their name (see .gitignore) and edit /config/picopygments.yml to point to those. Currently this only applies to the stylesheet configuration.

Manual download-up-

  • Download the master.zip into your PicoCMS install's /plugin directory.
  • Extract it in place - you should now have a PicoPygments folder that immediately contains PicoPygments.php and some other files. In other words, from your PicoCMS install's base directory, you should have /plugins/PicoPygments/PicoPygments.php (and some other files and directories).

That should be enough.

As usual, you should copy the picopygments.yml configuration file to your PicoCMS installation's /config folder and make your adjustments there.


The plugin should be enabled by default, and its own caching should also work by default.
If you want to make sure, set debug: true in your PicoCMS' config.yml, you will see some messages at the top of the page. After first loading a page all code blocks on that page should be cached, greatly reducing loading times. They are cached with a unique filename representing the code itself and PicoPygments' configuration. If anything changes there, new versions are generated.

CSS, colors-up-

Colors are customised through stylesheets that are linked into the page. A wide choice resides inside the plugin's css directory. You can preview all of them here.
That's all you need for now (see picopygments.yml), but here's how I got them:

  • Pygments comes with some styles included, but they come as small python scripts, not CSS.
  • Additionally, I installed a slightly outdated version of base16 for pygments like this: pip3 install pygments-base16.
  • Then the styles.py script generated CSS files from all styles it can find (it has a -h option, have a look).

Additional to colors, there's a _common.css file with overrides for all styles.

Line numbers-up-

It is possible by editing the formatteroptions configuration under the DANGER ZONE in /config/picopygments.yml.

I have tried to integrate line numbers, but this introduces too many quirks and (what I consider) inconsistencies in Pygments' behaviour. They work fine as such, but possibly

  • your code blocks will get even larger, with empty elements.
  • the code block will look weird, with double borders etc (fixable with some CSS-fu).
  • you have to decide if you want line number for either all code blocks or none.


You have a markdown article with a fenced code block. If you append a language keyword to the opening fence, this plugin will become active. Example:

## This is what I coded in Lua: ```lua -- try to find themes in $HOME themedir = os.getenv("HOME") .. '/.local/share/themes/' ```

will use Lua syntax highlighting for this block of code.

If you're unsure which language to choose for your code you can run the included guess.py script, enter the raw code in question, and Pygments will tell you what it thinks about it.

The plugin activates after PicoCMS has converted your Markdown articles to HTML, it replaces code blocks therein if they have a language class, like this: <code class="language-lua">...</code>. PicoCMS uses Parsedown and Parsedown Extra which is supposed to implement Markdown Extra, but I found that this particular feature is not as rich as outlined here:

  • It won't handle more than one class added.
  • If you don't use the simple syntax above, but try to add multiple classes or dots or brackets (e.g. ~~~ .lua, ~~~{.lua .my-code}, ~~~{.lua #my-code} etc.) the extra characters show up in the langauge class and you end up with something like <code class="language-{.lua">.

This plugin sanitizes these strings, but multiple classes won't work.

Highlighting inline code (not a block of code)-up-

Neither Markdown Extra nor Parsedown Extra have a means to put a CSS class on inline code, but you can write it out as HTML in your Markdown text. Instead of

I typed `while true; do echo Yes; done` without looking.

you have to write

I typed <code class="language-bash">while true; do echo Yes; done</code> without looking.

Get it here-up-