Published 2020-10-03.
Last modified 2023-05-22.
Time to read: 5 minutes.
jekyll_plugins
collection, categorized under Jekyll.
3 Tags
This Jekyll plugin provides 3 Liquid tags that work together:
pre
,
noselect
and exec
.
Pre Tag
The pre
block tag can display a labeled heading, a copy button, number lines, and more.
{% pre [options] %}
Contents of pre tag
{% endpre %}
class="class1 class2"
– Replace default CSS classes (shadow
androunded
) with specified classes.-
clear
– (keyword option) Line break after floating HTML elements; ensures no floated elements overlap the renderedpre
tag. copyButton
– (keyword option) Generate a copy buttondark
– (keyword option) Dark modededent
– (keyword option) Remove leading spaces common to all lines, like Ruby's<<~
squiggly heredoc (default is false)-
label="This is a label"
– Apply text abovepre
tag. Thelabel
parameter value can also be specified in free text. The following two examples produce the same results:
{% pre label="This is a label" %}
Contents of pre tag
{% endpre %}Both of the above render as:{% pre This is a label %}
Contents of pre tag
{% endpre %}
This is a labelContents of pre tag
number
– (keyword option) Number the linesshell
– (keyword option) Equivalent tolabel='Shell'
style
– Apply CSS styles
Noselect Tag
The noselect
tag renders HTML content passed to it unselectable,
and generates a $
prompt if no content is provided.
{% pre %}
{% noselect [optional text string, defaults to $] %}Contents of pre tag
{% endpre %}
Exec Tag
The exec
tag executes a shell command and displays the result as unselectable text.
Output data is escaped, whitespace is condensed, and wrapped in the same
unselectable
class as the noselect
tag demonstrate.
{% exec [Options] [shell command] %}
Options
are:
-
cd="relative/or/absolute/directory"
– Change to specified directory before executing shell command. Environment variables in the directory path will be expanded. -
die_if_nonzero
– (keyword option) Setfalse
to treat non-zero return codes as non-fatal. Instead of terminating Jekyll with an error message, the message will be displayed as an error by the Jekyll logger, and a red message will appear in place of the result on the web page. -
die_if_error
(keyword option) – Setfalse
to treat exceptions generated by this plugin as non-fatal. Instead of terminating Jekyll with an error message, the message will be displayed as an error by the Jekyll logger. -
no_escape
– (keyword option) Do not HTML escape the result of running the shell command. -
no_strip
– (keyword option) Do not remove leading and trailing whitespace from the result.
Keyword Options
For all keyword options,
including keyword options for the pre
and exec
tags,
option values specified in the document may be provided.
If a value is not provided, the value true
is assumed.
Otherwise, if a value is provided, it must be wrapped in single or double quotes.
Examples
Specifying Tag Option Values
The following sets die_if_error
true
:
{% pre die_if_error %} ... {% endpre %}
The above is the same as writing:
{% pre die_if_error='true' %} ... {% endpre %}
Or writing:
{% pre die_if_error="true" %} ... {% endpre %}
Neglecting to provide surrounding quotes around the provided value causes the parser to not recognize the option.
Instead, what you had intended to be the keyword/value pair will be parsed as part of the command.
For the pre
tag,
this means the erroneous string becomes part of the label
value, unless label
is explicitly specified.
For the exec
tag, this means the erroneous string becomes part of the command to execute.
The following demonstrates the error.
{% pre die_if_error=false %} ... {% endpre %}
The above causes the label to be die_if_error=false
.
{% exec die_if_error=false ls %} ... {% endpre %}
The above causes the command to be executed to be die_if_error=false ls
,
instead of ls
.
Installation
Add the following highlighted line to your Jekyll project's Gemfile
,
within the jekyll_plugins
group:
group :jekyll_plugins do gem 'jekyll_pre' end
And then execute:
$ bundle
Configuration
Default options can be specified in the standard Jekyll configuration file,
_config.yml
.
Options are specified in the pre
key.
The names of each command line option is the same in the configuration file.
Option values specified in _config.yml
must be provided,
and the value true
cannot be implied.
Values that do not contain special characters may be wrapped in single or double quotes.
The following demonstrates setting a default value for every possible option. You certainly do not want to set these defaults; they are just here to show you possibilities and syntax.
pre: class: bg_yellow clear: true dark: true dedent: true highlight: 'Error:.*' label: Shell copyButton: true number: true style: 'font-face: courier' wrapper_class: rounded shadow wrapper_style: 'padding: 2em; border: thin green dashed;'
The default values used on mslinn.com
are:
pre: dedent: true label: Shell copyButton: true
Specifying Default Option Values
Specifying a default value for die_if_error
in _config.yml
could be written any of the following ways:
pre: die_if_error: true
pre: die_if_error: "true"
pre: die_if_error: 'true'
Selective Clipboard Support
Specifying the pre
tag’s copyButton
keyword option
causes a small clipboard icon to be displayed
at the top right corner of the pre
content.
Clicking on the icon causes the contents of the pre
tag to be highlighted and copied to the clipboard.
Unselectable content, such as that generated by the noselect
tag, is not highlighted or copied to the clipboard.
This allows readers of your content to be able to view commands and responses, but only copy commands. The selective copy makes is much faster and easier for your readers to type along with your content.
The copyButton
option requires Javascript.
You might want to load clipboard.js
in a Jekyll layout.
For example:
<script src="https://cdn.jsdelivr.net/npm/clipboard@2.0.10/dist/clipboard.min.js"></script>
After the JavaScript loads, a new ClipboardJS
instance must be created.
The constructor needs to know the CSS selector for the buttons that the user will click on when they want to copy text to the clipboard.
In this example, all of the buttons on the web page have class .copyBtn
.
new ClipboardJS('.copyBtn');
The clipboard button is fuctionally equivalent to the following HTML:
<button class="copyBtn" data-clipboard-target="#id098814fabaf3" title="Copy to clipboard"> <img src="/assets/images/clippy.svg" alt="Copy to clipboard" style="width: 13px"> </button>
The value of the data-clipboard-target
attribute is the id
of the container holding the text to be copied.
Examples
Defaults
If you have not specified default options in _config.yml
,
then this example will merely generate an HTML <pre> tag with the given content.
{% pre %}Contents<br>of<br>pre tag{% endpre %}
Generates:
<pre data-lt-active='false' class='maxOneScreenHigh' id='id377433c30186'>Contents<br>of<br>pre tag</pre>
Which renders as:
Contents
of
pre
tag
Dark Mode
Normally my website uses light colors, however some content displays better on a dark background. You can define the CSS any way you like.
{% pre copyButton dark label='Dark Mode Example' %} {% noselect %}irb {% noselect irb(main):001:0> %}p 'How now brown cow' {% noselect How now brown cow %} {% endpre %}
Renders as:
$ irb irb(main):001:0> p 'How now brown cow' How now brown cow
Dedent
{% pre dedent %} This line was indented 4 spaces This line was indented 6 spaces This line was indented 4 spaces {% endpre %}
Which renders as:
This line was indented 4 spaces This line was indented 6 spaces This line was indented 4 spaces
If you enable dedent
in _config.yml
,
then you might want to disable it for specific instances, like this:
{% pre dedent=false %} This line was indented 4 spaces This line was indented 6 spaces This line was indented 4 spaces {% endpre %}
Which renders as:
This line was indented 4 spaces This line was indented 6 spaces This line was indented 4 spaces
CopyButton
This example generates a copy button and does not demonstrate noselect
.
{% pre copyButton %}Contents<br>of<br>pre tag{% endpre %}
Generates:
<pre data-lt-active='false' class='maxOneScreenHigh copyContainer' id='id377433c30186'>Contents<br>of<br>pre tag</pre>
Which renders as (note the clipboard icon at the far right):
Contents
of
pre tag
CopyButton & Noselect
This example generates a copy button and demonstrates the default usage of noselect
,
which renders an unselectable dollar sign followed by a space.
{% pre copyButton %}
{% noselect %}Contents<br>of<br>pre tag
{% endpre %}
Generates:
<pre data-lt-active='false' class='maxOneScreenHigh copyContainer' id='id1e4a8fe53480'><button class='copyBtn' data-clipboard-target='#id1e4a8fe53480' title='Copy to clipboard'><img src='/assets/images/clippy.svg' alt='Copy to clipboard' style='width: 13px'></button><span class='unselectable'>$ </span>Contents<br>of<br>pre tag</pre>
Which renders as:
$ Contents
of
pre tag
CopyButton & Noselect
This example generates a copy button and demonstrates the noselect
being used twice:
the first time to render an unselectable custom prompt,
and the second time to render unselectable output.
{% pre copyButton %} {% noselect >>> %}Contents of pre tag {% noselect How now brown cow Uselectable line 2 Line 3 %}{% endpre %}
Generates:
<pre data-lt-active='false' class='maxOneScreenHigh copyContainer' id='idb58a6cf1761c'><button class='copyBtn' data-clipboard-target='#idb58a6cf1761c' title='Copy to clipboard'><img src='/assets/images/clippy.svg' alt='Copy to clipboard' style='width: 13px'></button><span class='unselectable'>>> </span>contents of pre tag <span class='unselectable'>How now brown cow Uselectable line 2 Line 3</span></pre>
Which renders as:
>>> Contents of pre tag How now brown cow Uselectable line 2 Line 3
Highlight
A regular expression can be passed to the highlight
option.
This causes text that matches the regex pattern to be wrapped within
a <span class="bg_yellow"></span>
tag.
The CSS stylesheet used for this page contains the following:
.bg_yellow { background-color: yellow; padding: 2px; }
This example demonstrates highlighting text that matches a regular expression.
Regular expressions match against lines, which are delimited via newlines (\n
).
{% pre copyButton highlight="Line 2" %} Line 1 Line 2 Line 3 Line 4 Line 5 Line 6 Line 7 {% endpre %}
Which renders as:
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Entire Line Highlight
Regular expressions match against lines, which are delimited via newlines (\n
).
Thus to match an entire line that contains a phrase, specify the regex as .*phrase.*
.
The following matches 3 possible phrases (2
, 4
or 6
), then selects the entire line if matched.
{% pre copyButton highlight=".*(2|4|6).*" %} Line 1 Line 2 Line 3 Line 4 Line 5 Line 6 Line 7 {% endpre %}
Which renders as:
Line 1 Line 2 Line 3 Line 4 Line 5 Line 6 Line 7
Float Image Right
This example floats an image to the right.
The jekyll_pre
plugin’s clear
option moves the generated HTML below the image.
<img src="jekyll.webp" style="float: right; width: 100px; height: auto;"> {% pre clear copyButton label='Clear example' %} Using clear, copyButton and label parameters {% endpre %}
Renders as:

Using clear, copyButton and label parameters
Exec
The following executes ls -alF /
and displays the output.
{% pre clear copyButton label='Exec without error' %} {% noselect %}{% exec die_if_nonzero=false ls -alF / %} {% endpre %}
This is the rendered result:
$ ls -alF / total 2008 drwxr-xr-x 19 root root 4096 Jun 3 08:42 ./ drwxr-xr-x 19 root root 4096 Jun 3 08:42 ../ lrwxrwxrwx 1 root root 7 Jan 3 16:40 bin -> usr/bin/ drwxr-xr-x 2 root root 4096 Apr 18 2022 boot/ drwxr-xr-x 16 root root 3540 Jun 3 08:43 dev/ drwxr-xr-x 97 root root 4096 Jun 4 07:17 etc/ drwxr-xr-x 3 root root 4096 Jan 24 09:00 home/ -rwxrwxrwx 1 root root 1978872 Apr 19 18:55 init* lrwxrwxrwx 1 root root 7 Jan 3 16:40 lib -> usr/lib/ lrwxrwxrwx 1 root root 9 Jan 3 16:40 lib32 -> usr/lib32/ lrwxrwxrwx 1 root root 9 Jan 3 16:40 lib64 -> usr/lib64/ lrwxrwxrwx 1 root root 10 Jan 3 16:40 libx32 -> usr/libx32/ drwx------ 2 root root 16384 Jan 24 08:59 lost+found/ drwxr-xr-x 2 root root 4096 Jan 3 16:40 media/ drwxr-xr-x 6 root root 4096 Jan 24 13:34 mnt/ drwxr-xr-x 2 root root 4096 Jan 3 16:40 opt/ dr-xr-xr-x 290 root root 0 Jun 3 08:42 proc/ drwx------ 4 root root 4096 May 28 09:58 root/ drwxr-xr-x 25 root root 700 Jun 4 06:39 run/ lrwxrwxrwx 1 root root 8 Jan 3 16:40 sbin -> usr/sbin/ drwxr-xr-x 10 root root 4096 May 27 10:16 snap/ drwxr-xr-x 2 root root 4096 Jan 3 16:40 srv/ dr-xr-xr-x 11 root root 0 Jun 3 08:42 sys/ drwxrwxrwt 13 root root 4096 Jun 4 07:37 tmp/ drwxr-xr-x 14 root root 4096 Jan 3 16:40 usr/ drwxr-xr-x 14 root root 4096 Jan 24 14:19 var/
Exec Error
The following executes ls -alF /invalid_directory
and displays the output.
{% pre clear copyButton label='Exec without error' %} {% noselect %}{% exec die_if_nonzero=false ls -alF /invalid_directory %} {% endpre %}
This is the rendered result:
$ ls -alF /invalid_directory Error code 2
Change Directory & Execute
The following changes to the home directory ($HOME
),
then executes pwd
and displays the output.
{% pre clear copyButton label='Exec from $HOME' %}{% noselect %} {% exec cd="$HOME" die_if_nonzero=false pwd %} {% endpre %}
Renders as:
$ pwd /home/mslinn
CSS
Below are the CSS declarations that I defined for the pre
tag that produced the above output.
This CSS is the same as used by flexible_include
.
/* Shared between jekyll_pre and jekyll_flexible_include_plugin */ .jekyll_pre { display: inline-block; margin-bottom: 30px; max-width: 100%; width: 100%; } .jekyll_pre + ul, .jekyll_pre + ol, .jekyll_pre + dl { margin-top: 0; } pre.dark { color: #eee; background-color: #222; } pre.dark .unselectable, pre.dark .unselectable > code { color: rgb(155, 150, 150); } .bg_yellow { background-color: yellow; padding: 2px; } .codeLabel { color: white; background-color: #666; display: flow-root; font-family: $mono-font; font-stretch: semi-condensed; margin-bottom: 0; padding-bottom: 2px; padding-left: 10px; padding-right: 10px; padding-top: 2px; } .darkLabel { color: ivory; } li div.codeLabel { padding-left: 2em; } .clear { clear: both; } .codeLabel.unselectable, div.codeLabel.unselectable > code { color: yellow; } .codeLabel + pre { margin-top: 0; } .codeLabel a { color: #c0e6fb; } .codeLabel a:hover { color: #FFE59F; } .copyBtn { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; background-color: #eee; background-image: linear-gradient(#fcfcfc, #eee); border: 1px solid #d5d5d5; border-radius: 3px; color: #333; cursor: pointer; float: right; font-size: 13px; font-weight: 700; line-height: 20px; padding: 2px 2px 0 4px;; position: -webkit-sticky; position: sticky; right: 4px; top: 0; user-select: none; z-index: 1; } .copyContainer { position: relative; } ol li .codeLabel { padding-left: 1.75em; } .maxOneScreenHigh { max-height: 500px; } .numbered_line, .unselectable.numbered_line, .numbered_line.unselectable { color: #5fb25f; } .unselectable { color: #7922f9; -moz-user-select: none; -khtml-user-select: none; user-select: none; } .wrap_pre { white-space: pre-wrap; } /* Added for jekyll_pre v1.2.2 */ .error { color: white; background-color: darkred; padding: 2px; } /* Flexible include only */ .flexible_error { color: white; background-color: red; padding: 2pt 1em 2pt 1em; } .flexible_error code { color: lightgray; font-size: 9pt; }
Comprehensive Example
The code that generates the above CSS is a good example of how the plugins work together with
the from
and to
tags from my
from_to_until
plugin:
{% capture css %}{% flexible_include '_sass/mystyle.scss' %}{% endcapture %} {% pre copyButton %}{{ css | from: '.copyBtn' | to: '^$' | strip }} {{ css | from: '.copyContainer' | to: '^$' | strip }} {{ css | from: '.maxOneScreenHigh' | to: '^$' | strip }} {{ css | from: '.unselectable' | to: '^$' | strip }} {% endpre %}
© Copyright 1994-2023 Michael Slinn. All rights reserved.
For requests to use this copyright-protected work in any manner, email mslinn@mslinn.com.