How to colorize a tree output in Gatsby's Prism plugin
Written on
For a blog post I'm currently writing, I want to display a folder structure for a better overview. Of course I could use an image for this purpose, but I prefer to keep my content easy-to-read.
To display the output of my tree
command I will use a code block in Markdown, which is then rendered by the gatsby-remark-prismjs
plugin.
Let's see how the output of the command tree -F -a -L 2 demo/
will look like:
demo/
├── composer.json
├── Dockerfile
├── .env.sample
├── .gitignore
├── phpunit.xml -> tests/phpunit.xml
├── README.md
├── src/
│ └── Demo/
├── tests/
│ ├── integration/
│ ├── phpunit.xml
│ └── unit/
└── .travis.yml
Not so bad, but honestly not great either. And it would be even worse if I hadn't used the -F
option, where the slashes are displayed to better distinction between files and folders.
There is a plugin for that
Yes, I know there is a Treeview
plugin for Prism
, but this is where the problem begins. There is simply no place in the gatsby-remark-prismjs
configuration where you can define Prism1 plugins.
// In your gatsby-config.js
plugins: [
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
{
resolve: `gatsby-remark-prismjs`,
options: {
// Class prefix for <pre> tags containing syntax highlighting;
// defaults to 'language-' (e.g. <pre class="language-js">).
// If your site loads Prism into the browser at runtime,
// (e.g. for use with libraries like react-live),
// you may use this to prevent Prism from re-processing syntax.
// This is an uncommon use-case though;
// If you're unsure, it's best to use the default value.
classPrefix: "language-",
// This is used to allow setting a language for inline code
// (i.e. single backticks) by creating a separator.
// This separator is a string and will do no white-space
// stripping.
// A suggested value for English speakers is the non-ascii
// character '›'.
inlineCodeMarker: null,
// This lets you set up language aliases. For example,
// setting this to '{ sh: "bash" }' will let you use
// the language "sh" which will highlight using the
// bash highlighter.
aliases: {},
// This toggles the display of line numbers globally alongside the code.
// To use it, add the following line in gatsby-browser.js
// right after importing the prism color scheme:
// require("prismjs/plugins/line-numbers/prism-line-numbers.css")
// Defaults to false.
// If you wish to only show line numbers on certain code blocks,
// leave false and use the {numberLines: true} syntax below
showLineNumbers: false,
// If setting this to true, the parser won't handle and highlight inline
// code used in markdown i.e. single backtick code like `this`.
noInlineHighlight: false,
// This adds a new language definition to Prism or extend an already
// existing language definition. More details on this option can be
// found under the header "Add new language definition or extend an
// existing language" below.
languageExtensions: [
{
language: "superscript",
extend: "javascript",
definition: {
superscript_types: /(SuperType)/,
},
insertBefore: {
function: {
superscript_keywords: /(superif|superelse)/,
},
},
},
],
// Customize the prompt used in shell output
// Values below are default
prompt: {
user: "root",
host: "localhost",
global: false,
},
// By default the HTML entities <>&'" are escaped.
// Add additional HTML escapes by providing a mapping
// of HTML entities and their escape value IE: { '}': '{' }
escapeEntities: {},
},
},
],
},
},
]
Gatsby also provides an explanation in their implementation notes for it:
PrismJS plugins assume you're running things client side, but we are build-time folks. — Excerpt from the gatsby-remark-prismjs Readme on GitHub.
What now?
Of course, I could wait until the feature is implemented, especially since the topic is up for debate — most recently ~170 days ago.
On the other hand, I can use the LanguageExtensions
option in the gatsby-remark-prismjs
configuration to write my own implementation, which I did as you can see below:
demo/
├── composer.json
├── Dockerfile
├── .env.sample
├── .gitignore
├── phpunit.xml -> tests/phpunit.xml
├── README.md
├── src/
│ └── Demo/
├── tests/
│ ├── integration/
│ ├── phpunit.xml
│ └── unit/
└── .travis.yml
Isn't that much nicer and easier to read? It almost feels like viewing a terminal output.
How to implement your own extension
The configuration itself is quite simple, the tricky part are the regular expressions. I used most of the rules from the Treeview
plugin you'll find on GitHub as a starting point, like the line and stroke rules.
// In your gatsby-config.js
plugins: [
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
{
resolve: `gatsby-remark-prismjs`,
options: {
languageExtensions: [
{
language: "tree",
extend: "json",
definition: {
'entry-line': [
{
pattern: /\|-- |├── /,
alias: 'line-h'
},
{
pattern: /\| |│ /,
alias: 'line-v'
},
{
pattern: /`-- |└── /,
alias: 'line-v-last'
},
{
pattern: / {4}/,
alias: 'line-v-gap'
}
],
'entry-dir': {
pattern: /.*[\/](?!\w).*/,
inside: {
// symlink
'operator': / -> /,
}
},
'entry-symlink': {
pattern: /.*\S.* (-> .*)/,
inside: {
'operator': / -> /,
'file': /(.*)/,
}
},
'entry-name': {
pattern: /.*\S.*/,
inside: {
// symlink
'operator': / -> /,
}
},
},
},
]
}
},
],
}
}
]
All that remains to be done is to style the elements according to your own needs.
What's next?
Well, for now, I've' created a gist with the configuration above, so you can either use it for yourself or help me improve it if you like.
Disclaimer: I am by far not a professional when it comes to regular expressions or JavaScript. So if you find an error, feel free to correct it in the gist or leave me a comment here.