Style Shell Commands with CSS

Do you provide shell, terminal, or other command line examples on your site? Learn how to style them with CSS using a custom, lightweight plugin for Prism.

Updated on 12/30/2015: The Command Line plugin is now part of the Prism project, but it may be converted from a plugin to a language add-on. I've left this blog entry here for reference.

I launched this site before it was "code complete" and there are still features I've yet to implement. One of the next posts I wanted to write involved shell commands, so I needed to address styling those commands to make them easy to read and understand. I searched for some examples to see what others suggested before deciding that shell commands are essentially just code samples, so I switched gears to decide how I wanted to implement general code highlighting.

There were several great libraries available including Prettify, Prism, and Snippet. I found Snippet to be very flexible with some nice features, but it's also somewhat bulky in comparison to the others. Both Prettify and Prism are lightweight and designed to work with semantic markup—huge positives for me. They're also used on some very large code-focused web sites including Google Code, Stack Overflow, A List Apart, and Mozilla Developer Network. That's a good sign that they both do the job well. In the end, I chose Prism mostly for its extensibility including the plugin architecture's hooking mechanism, which I leveraged to add support for styling shell commands.

Design and Implementation

Let's look at the requirements for good shell command styling. Most of the examples I found online focused on making it look like a terminal window. That's fine and it looks cool, but I'd rather emphasize readability and let the visual style match my site. One item that makes shell sessions more readable is having an informative prompt. Many users customize their prompt for that exact reason: it provides context that gives visual cues/reminders. What elements constitute a useful prompt for instructional examples?

  1. Username: The name of the logged in user normally won't matter, but it does when commands should be executed as root. It's common to use a different symbol such as # for root or $ for non-root, but that's very subtle and explicitly showing a username stands out.
  2. Host name: The real benefit of having the host name in the prompt can be seen when some commands are to be issued locally while some are intended for remote machines. Making that clear in your samples is a big win.
  3. Output: There should be a visual indicator to distinguish output from commands. This might be considered the anti-prompt, because it's normally the absence of a prompt on a given line that provides this indicator.

There's no reason to reinvent the wheel, so I started by looking for similar plugins. The Line Numbers plugin is comparable to how a shell prompt should appear except with numbers instead of prompts. Also, the Line Highlight plugin provides a simple model for indicating lines that require special treatment (e.g., output). I used the JavaScript from these two plugins and the CSS from the Line Numbers plugin as starting points. This is the resulting JavaScript:

 

The content for the prompt is controlled by CSS, so it's easy to modify. You can also specify a custom prompt using the data-prompt attribute on your pre. Below is the CSS that styles the prompts for us:

 

That's all of the JavaScript and CSS we need for the Command Line plugin.

Usage Examples

Now we can use markup such as the following to depict local shell commands ran as root:

<pre class="command-line" data-user="root" data-host="localhost">
<code class="language-bash">cd /usr/local/etc
cp php.ini php.ini.bak
vi php.ini</code>
</pre>

We've specified the user and host in the data attributes on line 1. Any user other than root automatically shows $ for the prompt with root showing #. The output looks like this:

cd /usr/local/etc
cp php.ini php.ini.bak
vi php.ini

The following markup could be used to show commands ran on a remote host as non-root:

<pre class="command-line" data-user="chris" data-host="remotehost" data-output="2, 4-8">
<code class="language-bash">pwd
/usr/home/chris/bin
ls -la
total 2
drwxr-xr-x   2 chris  chris     11 Jan 10 16:48 .
drwxr--r-x  45 chris  chris     92 Feb 14 11:10 ..
-rwxr-xr-x   1 chris  chris    444 Aug 25  2013 backup
-rwxr-xr-x   1 chris  chris    642 Jan 17 14:42 deploy</code>
</pre>

Note the additional data-output attribute on line 1 indicating the line and line range that shouldn't display a prompt. That markup is rendered like so:

pwd
/usr/home/chris/bin
ls -la
total 2
drwxr-xr-x   2 chris  chris     11 Jan 10 16:48 .
drwxr--r-x  45 chris  chris     92 Feb 14 11:10 ..
-rwxr-xr-x   1 chris  chris    444 Aug 25  2013 backup
-rwxr-xr-x   1 chris  chris    642 Jan 17 14:42 deploy

That's all there is to it! Nice, clean, easy to read shell sessions styled using CSS. If you'd like to use it in one of your projects, just include the Command Line plugin when you download the Prism code. Also, be sure to select Bash or whatever language is appropriate for the command line you're displaying. After you try it, I'd love to hear your feedback in the comments below.

, , , ,
comments powered by Disqus