Code Highlighting in MacOS Using Services

Update July 7, 2014: Since so much in MacOS is done in unicode, it’s possible that the highlighting code won’t work. I am updating the examples below so that only ASCII characters are passed into the scripts by prepending:

1
LANG=C tr -cd '\11\12\15\40-\176' |

Un-highlighted code looks awful in documentation

I write a lot of documentation, and not always in a markup language where code highlighting is just a tag away. Getting nicely formatted code into Word, Pages, and Curio can be inconvenient. There is a pretty slick way to handle it in MacOS that can save time. MacOS offers “Services” in the menu for each application, it is trivial to create a service that will reformat the clipboard’s contents as syntax highlighted rich text.

I’ll show how to set up a menu that will paste the contents of the clipboard formatted as syntax-highlighted text in any application. I assume that macports is installed in my examples, and if you don’t have macports it’s not difficult to get the necessary tools installed without installing macports, but you are on your own for that. The first thing is to get pygmentize installed, I used macports to install it, but you can just as easily use ‘pip’; see the documentation for various install options.

1
2
3
4
$ ls /opt/local/bin/python*
/opt/local/bin/python2.7@        /opt/local/bin/python2.7-config@ /opt/local/bin/pythonw2.7@
$ sudo port install py27-pygments
--->  Computing dependencies for py27-pygments
  • Install the version of pygments that matches the installed python.

Or without macports:

1
2
3
4
5
6
7
8
9
10
# easy_install pip
Searching for pip
Reading http://pypi.python.org/simple/pip/
Best match: pip 1.5.6
. . .
# pip install Pygments
Downloading/unpacking Pygments
  Downloading Pygments-1.6.tar.gz (1.4MB): 1.4MB downloaded
  Running setup.py (path:/Users/tag/.tmp/pip_build_root/Pygments/setup.py) egg_info for package Pygments
. . .
  • If you install via pip, the pygmentize executable will be different from my examples (/usr/local/bin/pygmentize)

Next open Automater and create a Services project. There are three components, the first grabs the text from the pasteboard, then a shell script, and an AppleScript object that needs to be created. The shell script will process everything and place the formatted RTF in the paste buffer, then the AppleScript pastes the formatted text into the document. The commands available aren’t limited to just performing syntax highlighting, and in a couple of my examples I do more than just highlight; for example it’s possible to perform code beautification or perform regular expression replacements to remove host names in $PS1 prompts before pasting in. Here’s my Service for colorizing bash scripts:

The scripts

1
LANG=C tr -cd '\11\12\15\40-\176'

This limits the characters in the pipeline to the valid ASCII printable range.

1
/opt/local/bin/pygmentize-2.7 -l bash -f rtf -O "style=vs,fontface=Source Code Pro"

The “-l” option specifies the type of highlighting, in this case a bash shell script. I specify RTF output using the “-f” switch, and the “-O” switch offers some formatting options. The “style” looks similar to visual studio, and it is using the Source Code Pro font.

1
sed 's/\\f0/\\f0\\fs18/g'

Because the RTF output from pygmentize doesn’t allow setting font size, this sed command adds the necessary attribute. I found this on an emptysqua.re blog post. Multiply the desired font size by two, so in the above example it will use a 9 point font.

1
pbcopy -Prefer rtf

This is a fantastic utility that takes either a file, or STDIN and puts it on the clipboard. The impressive part is that it can accept either plain text, postscript, or rich text as input. The “-Prefer rtf” switch instructs pbcopy to interpret the input as RTF first.

AppleScript:

1
2
3
4
5
on run {}
  tell application "System Events"
      keystroke "v" using command down
  end tell
end run

I guess I could have just left it at having nicely formatted code on the clipboard, but laziness is a fantastic motivator. So this short piece of code will finish up by pasting directly into the document.

It is also pretty cool to be able to beautify the text and highlight it. While there are some risks to beautifiers mangling things, it is useful to have proper indentation, and so on. I take the chance in a few cases (minified JavaScript, for example.)

Here are a few examples of Services I have created

(note, these are cut-and-pasteable, so to see the whole command you will have to scroll right):

astyle formatted C++ in Visual Studio colorscheme
1
LANG=C tr -cd '\11\12\15\40-\176' |/opt/local/bin/astyle |/opt/local/bin/pygmentize-2.7 -l cpp -f rtf -O "style=vs,fontface=Source Code Pro"|sed 's/\\f0/\\f0\\fs18/g' |pbcopy -Prefer rtf
Terminal logs
1
LANG=C tr -cd '\11\12\15\40-\176' |perl -pe "s/^\[.*?\]([\\\$\#])\s?/\1 /g" | /opt/local/bin/pygmentize-2.7 -l console -f rtf -O "style=friendly,fontface=Source Code Pro"|sed 's/\\f0/\\f0\\fs18/g' |pbcopy -Prefer rtf
  • Here a perl regex strips my custom PS1 prompt down, saving space and not putting host names in documents. Also the syntax highlighter in pygmentize doesn’t recognize the formatting of my prompt, and the regex puts it in a format that is recognized.
Beautified ruby in Tango colorsheme
1
LANG=C tr -cd '\11\12\15\40-\176' |/usr/bin/rbeautify | /opt/local/bin/pygmentize-2.7 -l ruby -f rtf -O "style=tango,fontface=Source Code Pro"|sed 's/\\f0/\\f0\\fs18/g' |pbcopy -Prefer rtf

Here is a tar-bzipped copy of my ruby service that can be used as a starting point.

Extract it in the “~/Library/Services” directory, and you can modify as needed (and it will likely need modification for your system.) Because this service isn’t signed, Gatekeeper will block it from running, here’s how to open it:

First extract the files and open the folder in the Finder:
1
2
3
4
5
$ cd Library/Services/
$ tar jxvf ~/Downloads/ruby-service.tbz
x ./._Paste clipboard as ruby.workflow
. . .
$ open .

Then right click and select “open”

Now gatekeeper will prompt to open, if you don’t accept it will not allow running, or even editing the service.

So, how does it look?

Here are some screen captures:

Pasted terminal session … formatted using: ‘-l console -f rtf -O “style=friendly,fontface=Source Code Pro”’

Excerpt from my .bash_profile … formatted using: ‘-l bash -f rtf -O “style=vs,fontface=Source Code Pro”’

And a little ruby … formatted using: ‘-l ruby -f rtf -O “style=tango,fontface=Source Code Pro”’

Tips:

  • Use the “-L” flag in pygmentize to list more formatting options. It covers a surprisingly wide range of code types, and has several color schemes that are well-suited for printed documentation.
  • If you work a lot in a specific language, it is possible to assign a shortcut to the service by going to “System Preferences –> Keyboard –> Shortcuts –> Services”. (Actually, this might not work as expected the shortcuts I have tested didn’t seem to work. I’ll update this post if I figure it out.)
  • You can pipe entire files directly into the paste buffer from the command line, it’s not necessary to copy and paste, just run ‘cat your-file |pbcopy’, and then use the Service menu in your word processor to paste it in formatted, no more scrolling through hundreds of lines in your terminal to copy that file.

Enjoy your newfound productivity :)