Apply 'pygmentize' to 'less' to Make it Pretty

I use less heavily. It's what's known as a "pager," a program that lets you look at the contents of a file and page through it. For a long time I've wished that less would syntax-highlight the files I was looking at, but I haven't done anything about it because I assumed it wasn't possible (I was wrong). Today I started thinking about how nice it would be if my SVN logs (yeah, yeah, move to git ... I hear you, we're working on it) were colourized. That's the subject of a different blog entry, but it led me to this discovery as well. And, I'm happy to say, this is surprisingly easy to set up.

First you need to understand that less is a classic Unix tool: "do one thing and do it well." It displays text, and it lets you search text, not much else (but within that purview it's pretty much the best there is). And "display text" includes an edge case: it can display colour codes. So if you were to use another program to parse your file and insert colour codes, then less would show it colourized. And that program is pygmentize (there are probably other options, but this seems to be the leading choice these days). Pygments is another Unix tool: it colourizes files. Really, that's what it does, that's all it does.

(I should also point out that Pygments is the group of programs that my blog software uses to colourize code samples in this blog.)

Installation

less is installed on every Linux system in the known universe. pygmentize is far less common, but it's well known enough to be available through most package managers. Search for the term "pygment" and you'll almost certainly find it. On Fedora: dnf install python3-pygments. On Mac, brew install pygments. If your package manager doesn't have it available, there's another package manager that probably does: pip3 install Pygments (I prefer to use OS-level packages, if you're a heavy Python user you may prefer this method).

Set Up

First, make sure the $LESS environment variable includes "R". I recommend you put a line in one of your shell start-up files ( ~/.bashrc, ~/.profile, /etc/bashrc, ~/.zshrc, like that) that says export LESS=MR but the "M" isn't necessary for this. Check by typing echo $LESS.

There are two ways to set this up (I'm sure there are more, but let's go with two). First, test whether or not you have a filter for less in place by running echo $LESSOPEN. On Fedora, the response is ||/usr/bin/lesspipe.sh %s - that's a system default, I didn't set it up. The main point being that something is already handling the (pre-)parsing of less files. On Mac, I got an empty response. Either of the following methods will work with either OS, but I have the preferences expressed below based on the existing set-up.

Of these two, the Mac is slightly simpler to set up: in one of your shell start-up files, you need to add the line export LESSOPEN='|pygmentize -g %s'. The -g parameter to pygmentize means essentially "guess the filetype." And honestly, it's damn good at guessing so I prefer this method to what I've set up on Fedora ... but the other method has advantages too.

If you find that the $LESSOPEN environment variable is set, then less will probably use a file called ~/.lessfilter to determine how you want to treat files before they're passed to less. Let's create that file (make it executable as well!):

case "$1" in
    *.hpml)
        pygmentize -l html "$1";;

    *)
        pygmentize -g "$1";;
esac

exit 0

The point of that weird file extension is that this is where you can filter and change pygmentize's behaviour based on file extension. Some years ago I decided that "HPML" was a good renaming of "HTML" with the "P" standing for "Partial:" several of these files would be assembled into one HTML file. Since that filetype is an invention of mine, I tell pygmentize to treat it as HTML. And then I tell pygmentize to make a guess on everything else.

On Fedora, installing this file was all that was needed to get less doing syntax highlighting on pretty much every kind of file there is. If this doesn't immediately work for you, you may need to reset the $LESSOPEN environment variable as mentioned above.

Testing

I don't think you'll need this, but if for some reason you want to see pygmentize in action without your less setup working, use something like pygmentize -g ~/.bashrc as a test (you can of course pipe it to less -R). Use man pygmentize (no man page on Mac, you'll have to settle for the shorter pygmentize -h) to get a handle on the options and try them out.

Bibliography

This is almost entirely based on https://superuser.com/questions/117841/when-reading-a-file-with-less-or-more-how-can-i-get-the-content-in-colors . After spending a couple hours tinkering, I concluded that the ~/.lessfilter file in the main answer is too complex to no good end ... and may be unnecessary. If you have the patience to do so, I would recommend reading that whole page as well so you can come to your own conclusion.