Miskatonic University Press

less is more with a better .lessfilter

code unix

I have that complex feeling of being satisfied that I solved a problem but mildly dissatisfied because the problem was very small and I probably spent too long on it, but nevertheless satisfied that a very small part of my life (one hopes for many years to come) will be a tiny bit better.

Was it worth it? The likelihood is greater if I share what I did. So it goes with customizing one’s Unix environment, and life overall.

It all started when I realized that source-highlight doesn’t do syntax highlighting on Markdown files. That was a surprise, because Markdown is so popular. Pygments, on the other hand, does. And it does many more file formats, including JSON.

After a bunch of work, I got it so that if pygmentize is available on the system, it’s used for highlighting files when viewed with less, or if source-highlight is there then it falls back to that, or if neither is available, just plain old less on its own is used. If lessfile is on the system (it’s on all Linux systems, but not on a FreeBSD server I use) then that is mixed in for powerful magic.

In my .bashrc this sets things up:

# lessfile is a nice incantation that lets less open up tar and gz files
# and so on and show you what's inside.
if command -v lessfile > /dev/null 2>&1; then
    eval "$(lessfile)"
    # This sets LESSOPEN and will pick up on ~/.lessfilter.
else
    # Fall back to do the best we can.
    export LESSOPEN="| ~/.lessfilter %s"
fi

# If any syntax highlighters are available, use them.
# pygmentize does more, but source-highlight is still good.
if command -v pygmentize > /dev/null 2>&1; then
    export LESSCOLOURIZER="pygmentize -f terminal"
elif command -v source-highlight > /dev/null 2>&1; then
    export LESSCOLOURIZER="source-highlight --failsafe --infer-lang -f esc --style-file=esc.style -i"
fi

# Pass through raw ANSI colour escape sequences.  In other words, make colourizing work.
export LESS=' -R '

My .lessfilter has this:

if [ -v LESSCOLOURIZER ]; then
    case "$1" in
	# Could have .bashrc in here, but mine seems to mess it up, perhaps because of escape sequences.
	# pygmentize can handle many more file types; this is just what I want.
	.bash_|*.bat|*.bib|*.c|Changelog|*.diff|Gemfile|\
	*.gemspec|*.h|*.ini|*.js|*.json|*.jsonld|\
	Makefile|*.md|*.patch|*.php|*.pl|*.pm|*.py|Rakefile|\
	*.rake|*.rb|*.R|*.Rprofile|*.rss|*.sh|*.sql|*.xsl|\
	*.tex|*.toc|*.yaml|*.yml)
	    $LESSCOLOURIZER "$1" ;;
	*.pdf)
	    if command -v pdftotext > /dev/null 2>&1 ; then pdftotext -layout "$1" -
	    else echo "No pdftotext available; try installing poppler-utils"; fi ;;
	*)
	    # Pass through to lessfile
	    exit 1
    esac;
fi

# Hand whatever is left over to lessfile
exit 1

Now I can use less on binaries like tarballs and zip files (where it shows me a file listing) and PDFs (where it shows me the text), and on text files wherever possible it adds syntax highlighting. On any system where one part of the tool set isn’t available, it will fall back to something simpler, in the end arriving at just plain old unadorned less.

This is part of Conforguration. It will probably work on any Unix-like system (perhaps including macOS, but I don’t know).

Neither source-highlight or Pygments handles Org files, which surprises me. Maybe I can figure out a recipe to fix that.

(I should add that there were a bunch of the Stack Overflow answers and dotfile snippets on GitHub that helped along the way, but I closed all the tabs and don’t have the energy to track them down again. I hope anyone who stumbles across them in the future will also find this.)

One last thing. I also have this in my .bashrc:

alias more='less'

I never run less, I always run more. The habit was set decades ago, and it’s easier to alias than switch.

UPDATE (25 June 2020): Fixed shell redirection error in .lessfilter.