Published 2020-10-03.
Last modified 2023-12-01.
Time to read: 6 minutes.
jekyll_plugins
collection.
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 %}
options
are:
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 a text label above the generated HTMLpre
tag. The default value isShell
. Examples:
HTML or markdown{% pre label="This is a label" %}
Contents of pre tag
{% endpre %}
The above renders as:
This is a labelContents of pre tag
Another example:
HTML or markdown{% pre %}
Contents of pre tag
{% endpre %}
The above renders as:
ShellContents of pre tag
number
– (keyword option) Number the lines within thepre
tag area.-
shell
– (keyword option) Equivalent tolabel='Shell'
. This is the default label. 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 $] %}More pre tag content
{% endpre %}
Example:
{% pre %}
{% noselect %}Type a command here
{% endpre %}
Renders as:
$ Type a command here
Another example:
{% pre label='irb' %}
{% noselect irb(main):001> %}
{% endpre %}
Renders as:
irb(main):001>
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.
Example:
{% exec date %}
Renders as:
date
Mon Dec 16 13:46:16 EST 2024
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
Gem
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
CSS and Assets
Copy assets and CSS from the demo/
directory of the jekyll_pre
GitHub project.
-
Copy
demo/assets/images/clippy.svg
to a directory of the same name in your Jekyll project. -
Copy
demo/assets/css/jekyll_plugin_support.css
to your Jekyll project assets directory. -
Copy
demo/assets/css/shared_include_pre.css
to your Jekyll project assets directory. -
Copy
demo/assets/css/jekyll_pre.css
to your Jekyll project assets directory. -
Incorporate the CSS stylesheets into the appropriate layout in your Jekyll project:
_layouts/default.html{% assign nowMillis = site.time | date: '%s' %} <link rel="stylesheet" href="{{ '/assets/css/jekyll_plugin_support.css?v=' | append: nowMillis }}" type="text/css"> <link rel="stylesheet" href="{{ '/assets/css/shared_include_pre.css?v=' | append: nowMillis }}" type="text/css"> <link rel="stylesheet" href="{{ '/assets/css/jekyll_pre.css?v=' | append: nowMillis }}" type="text/css">
JavaScript
Copy demo/assets/js/clipboard.min.js
from the jekyll_flexible_include_plugin
GitHub project to your Jekyll project’s JavaScript directory.
Modify the Jekyll layout or selected pages to load the JavaScript. You can load it from your project, as shown below, or from a CDN.
<script defer src="/assets/js/clipboard.min.js"></script>
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:
Exec
The following executes ls -alF /
and displays the output.
{% pre clear copyButton label='Exec without error' %} {% noselect %}{% exec no_stderr die_if_nonzero=false ls -alF / %} {% endpre %}
This is the rendered result:
$ ls -alF / total 1976 drwxr-xr-x 23 root root 4096 Dec 15 14:49 ./ drwxr-xr-x 23 root root 4096 Dec 15 14:49 ../ -rw-r--r-- 1 root root 0 Oct 3 04:51 .skip-cloud-init-warning lrwxrwxrwx 1 root root 7 Apr 23 2020 bin -> usr/bin/ drwxr-xr-x 2 root root 4096 May 23 2024 boot/ drwx------ 2 root root 4096 Apr 3 2022 crossdistroHHGKih/ drwx------ 2 root root 4096 Feb 4 2022 crossdistroaHfIbk/ drwx------ 2 root root 4096 Feb 4 2022 crossdistromBdAgG/ drwxr-xr-x 16 root root 3540 Dec 15 18:40 dev/ drwxr-xr-x 187 root root 12288 Dec 16 13:25 etc/ drwxr-xr-x 3 root root 4096 Jan 12 2022 home/ -rwxrwxrwx 1 root root 1928824 Feb 16 2024 init* drwxr-xr-x 2 root root 4096 May 3 2022 keybase/ lrwxrwxrwx 1 root root 7 Apr 23 2020 lib -> usr/lib/ lrwxrwxrwx 1 root root 9 May 23 2024 lib32 -> usr/lib32/ lrwxrwxrwx 1 root root 9 Apr 23 2020 lib64 -> usr/lib64/ lrwxrwxrwx 1 root root 10 Apr 23 2020 libx32 -> usr/libx32/ drwx------ 2 root root 16384 Apr 10 2019 lost+found/ drwxr-xr-x 2 root root 4096 Apr 23 2020 media/ drwxr-xr-x 17 root root 4096 Jun 13 2024 mnt/ drwxr-xr-x 3 root root 4096 May 3 2022 opt/ dr-xr-xr-x 446 root root 0 Dec 15 14:49 proc/ drwx------ 12 root root 4096 Aug 29 12:53 root/ drwxr-xr-x 40 root root 1100 Dec 16 09:07 run/ lrwxrwxrwx 1 root root 8 Apr 23 2020 sbin -> usr/sbin/ drwxr-xr-x 18 root root 4096 May 24 2024 snap/ drwxr-xr-x 2 root root 4096 Apr 23 2020 srv/ dr-xr-xr-x 11 root root 0 Dec 15 18:41 sys/ drwxrwxrwt 18 root root 540 Dec 16 13:45 tmp/ drwxr-xr-x 14 root root 4096 Jan 21 2022 usr/ drwxr-xr-x 16 root root 4096 May 23 2024 var/
Exec Error
The following executes ls -alF /invalid_directory
and displays the output.
{% pre clear copyButton dedent label='Exec without error' %} {% noselect %}{% exec no_stderr 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 no_stderr 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
.
.clear { clear: both; } ol li .codeLabel { padding-left: 1.75em; } .error { color: white; background-color: darkred; padding: 2px; } #main-content li > div.jekyll_pre, li > div.jekyll_pre { margin-top: 20px; } .jekyll_pre + div, .jekyll_pre + p, .jekyll_pre + ul, .jekyll_pre + ol, .jekyll_pre + dl { margin-top: 20px; } .jekyll_pre + .jekyll_pre { margin-top: 2em; } .pre_tag { margin-bottom: 1em; } .tree { line-height: 1; }
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/jekyll_pre.scss' %}{% endcapture %}
{% pre copyButton dedent label="CSS Fragment" %} {{ css | from: '.error' | to: '}' | strip }}
{{ css | from: '.pre_tag' | to: '}' | strip }} {% endpre %}
Output is:
.error { color: white; background-color: darkred; padding: 2px; }
.pre_tag { margin-bottom: 1em; }