What is iTerm2


iTerm2 is a feature-rich terminal emulation replacement for on OSX machines. It is donationware and is under the GPL v2 license.

If you use OSX on a regular basis but prefer to interact with Emacs running somewhere else, iTerm2’s features will get you as close as possible to feeling as if you were running the Emacs GUI on your local machine.

Where to download

You can get it from here.

Advantages over

While OSX's default is fairly feature-rich, it comes with limitations.

  1. It doesn’t support complicated key bindings, which makes it hard to get the <super> and <hyper> keys working in Emacs
  2. Emoji support is limited (it’s there, but it’s limited)
  3. Minute font-adjustments are a bit clunky (albeit less clunky than the font-face rendering and customization in Emacs itself)

iTerm2 has some notable features, namely:

Mouse support

Believe it or not, you can get basic mouse functions working in iTerm2 pretty easily. Try this in your ~/.emacs file:

    (unless window-system
      (require 'mouse)
      (xterm-mouse-mode t)
      (defun track-mouse (e)) 
      (setq mouse-sel-mode t)

And then make sure you enable mouse support in your iTerm2 connection profile, like this:


You can now resize Emacs windows using your mouse, as well as clicking on hyperlinks (but you don’t NEED a mouse to do that, don’t you?)

Rendering Powerline arrows in iTerm2


Go to the Powerline font patch site on GitHub and install the fonts on your Mac, and switch iTerm2 to use one of the “(Font Name) for Powerline” fonts. Powerline will now render with proper separators.

Emacs Frames

Emacs in terminal mode makes frames a very useful feature. These behave like screen/tmux screens.

C-x 5 2 creates a new frame. Emacs will add a full-screen window to the frame and use the buffer of whatever you had focused on in the previous frame.

C-x 5 o will cycle frames (or M-x other-frame)

C-x 0 deletes the frame you’re looking at. The buffer that you were working on is still around, but no longer visible.

C-x 1 will wipe all the other Emacs frames you’re not looking at.

Let’s demonstrate this behavior:

Start Emacs in your remote session. Then press C-x 2 to split the window horizontally. Use C-x C-b or C-x b to switch one of the windows to another buffer, like Messages

Now press C-x 5 2 (which is Control-X followed by 5 then 2). You will now see a new screen with the buffer you were working on displayed in full.

Now, press C-x 5 o (Control-X, then 5 and the letter o). This sends you back to the frame you were on previously. Press C-x 5 o again to switch back to the second frame.

Since I like to have a lot of half-screen buffers open at once and I switch between them a lot, I bind other-frame to F12. For instance, one frame has all the IRC channels I am watching, another frame has Slack channels I am on, another frame will be the current code files I’m editing, another frame is where I am comparing source code with git, and so on.

Emoji Support

iTerm2 supports the full range of Unicode (provided you have the fonts installed), including emoji.

Install emojify and company-emoji from the MELPA repository. If you use company-mode (and who doesn’t?), typing a colon and the first two letters of the emoji’s common name will yield this:


File transfers and remote image display in iTerm2 sessions


iTerm2 comes with some installable scripts you can put on the remote computer that make it quite useful. You can do that under the iTerm2 menu, here:


Some of my favorite commands to run on the remote host are it2ul to upload a file, itdl, which downloads a file.

You can do a quick preview of an image with imgcat, which outputs the picture to your terminal:


If you have to maintain a remote web server and make post-op edits these tools can come in handy. These tools work by sending proprietary terminal escape codes which iTerm2 understands and reacts to. File transfers might be a tad slow, but it’s amazing that it works at all—given the terminal display technology from the 1970s that lies underneath. The same techniques were used in the 1970s, 80s and early 90s to send files using programs like Minicom and kermit and the X, Y and Z-modem protocols found in bulletin board systems.

Getting the Super and Hyper Keys working in iTerm2


First, let’s explain why getting Super and Hyper working in a terminal is not straightforward:

Emacs users over ssh terminals have a notorious time trying to get the Super (s) and Hyper (H) keys working to expand the possible local and global keybindings available. The reason for this has to do a lot with DEC terminal history and the keys that were available in some of the earliest possible terminals, in particular the DEC VT-100 terminal which was one of the most popular serial displays for Unix machines and was adapted for time-sharing and remote communication. Consequently the DEC terminal became the default basis of emulation for most software.

Contrast this with the Space-cadet keyboard that influenced the design of Emacs, made for MIT Lisp machines. It included several modifier keys which allowed multiple character sets as well as a large macro space for binding commands to key combinations. Two modifier keys to the left of the space bar on the Space-cadet keyboard include the Super and Hyper keys. While insanely useful for the experienced user, fewer people worked on Lisp machines compared to the widespread availability of VT-series character terminals. All command line and serial-terminal interaction you’ll ever find supports VT-100.

In GUI mode most emacsen will bind the Windows or Option key to Super. Or if you’re a Mac user, you might have swapped Alt and ⌘ so the Meta key is closest to the spacebar and easier to reach.

When you press a key on your keyboard your terminal emulator will send a character or an escape sequence down the connection. For DEC or xterm terminals, some keys may not send signals such as <f13>-<f24>, <print>, etc. Or, if you have a custom keyboard or a keyboard with media keys (like Play, Stop, Fast-forward) those may not be sent down the connection either. iTerm2 can make use of any key that OSX will respond to and you can customize it to run commands locally, remotely or send signals down the terminal connection to the remote machine.

So, let’s do an exercise to send some custom signals down the terminal connection and bind them so Emacs can detect the key, and then bind that key to a command.

Testing escape codes

First, connect your remote machine and issue the cat command with no parameters. Depending on your OS, termcap on the remote and the codepage your keyboard is set to, you’ll see either a character or an escape sequence when you type something.

Let’s see how the Latin letter O works when pressed with modifier keys.

These combos are being read by the remote machine and being fed to STDIN to cat (and cat is reading them back as output). They’re also the most basic escape sequences, as ^ is the code for COMMAND, and ^[ is for ALT/META, known as the escape sequence ^[ . For terminals and IBM PCs, the ^[ signifies some sort of terminal code, signifying a keypress or some action to be taken on the terminal or the remote. If your keyboard has a D-pad, try hitting <up> <down> <right> and <left>. Usually these will be ^[[A, ^[[B, ^[[C and ^[[D, respectively.

You can press C-c to get out of cat.

Now let’s try sending a more complicated escape sequence using some keys on your keyboard and fool Emacs on the remote into thinking you pressed a Hyper key combo. Go into your iTerm2 settings for your connection profile. In the Keys panel, let’s set a key combo for Ctrl+⌘+Option+A, which is the three leftmost keys next to the space bar plus the letter A. I’m pretty confident your remote termcap probably does not have an entry for ^[[1;P9, so let’s start off with that code. Your setting should look like this:


Let’s get Emacs to listen for this key. Evaluate the following Lisp code in an Emacs session (I took the liberty of adding escapes for the rest of the keys):

     (let ((map (if (boundp 'input-decode-map)
     (define-key map "\e[1;P9"  (kbd "H-a"))
     (define-key map "\e[1;P10" (kbd "H-b"))
     (define-key map "\e[1;P11" (kbd "H-c"))
     (define-key map "\e[1;P12" (kbd "H-d"))
     (define-key map "\e[1;P13" (kbd "H-e"))
     (define-key map "\e[1;P14" (kbd "H-f"))
     (define-key map "\e[1;P15" (kbd "H-g"))
     (define-key map "\e[1;P16" (kbd "H-h"))
     (define-key map "\e[1;P17" (kbd "H-i"))
     (define-key map "\e[1;P18" (kbd "H-j"))
     (define-key map "\e[1;P19" (kbd "H-k"))
     (define-key map "\e[1;P20" (kbd "H-l"))
     (define-key map "\e[1;P21" (kbd "H-m"))
     (define-key map "\e[1;P22" (kbd "H-n"))
     (define-key map "\e[1;P23" (kbd "H-o"))
     (define-key map "\e[1;P24" (kbd "H-p"))
     (define-key map "\e[1;P25" (kbd "H-q"))
     (define-key map "\e[1;P26" (kbd "H-r"))
     (define-key map "\e[1;P27" (kbd "H-s"))
     (define-key map "\e[1;P28" (kbd "H-t"))
     (define-key map "\e[1;P29" (kbd "H-u"))
     (define-key map "\e[1;P30" (kbd "H-v"))
     (define-key map "\e[1;P31" (kbd "H-w"))
     (define-key map "\e[1;P32" (kbd "H-x"))
     (define-key map "\e[1;P33" (kbd "H-y"))
     (define-key map "\e[1;P34" (kbd "H-z"))
     (define-key map "\e[1;P35" (kbd "H-0"))
     (define-key map "\e[1;P36" (kbd "H-1"))
     (define-key map "\e[1;P37" (kbd "H-2"))
     (define-key map "\e[1;P38" (kbd "H-3"))
     (define-key map "\e[1;P39" (kbd "H-4"))
     (define-key map "\e[1;P40" (kbd "H-5"))
     (define-key map "\e[1;P41" (kbd "H-6"))
     (define-key map "\e[1;P42" (kbd "H-7"))
     (define-key map "\e[1;P43" (kbd "H-8"))
     (define-key map "\e[1;P44" (kbd "H-9"))
     (define-key map "\e[1;P45" (kbd "H-<f1>"))
     (define-key map "\e[1;P46" (kbd "H-<f2>"))
     (define-key map "\e[1;P47" (kbd "H-<f3>"))
     (define-key map "\e[1;P48" (kbd "H-<f4>"))
     (define-key map "\e[1;P49" (kbd "H-<f5>"))
     (define-key map "\e[1;P50" (kbd "H-<f6>"))
     (define-key map "\e[1;P51" (kbd "H-<f7>"))
     (define-key map "\e[1;P52" (kbd "H-<f8>"))
     (define-key map "\e[1;P53" (kbd "H-<f9>"))
     (define-key map "\e[1;P54" (kbd "H-<f10>"))
     (define-key map "\e[1;P55" (kbd "H-<f11>"))
     (define-key map "\e[1;P56" (kbd "H-<f12>"))

Now we can bind Hyper to something. Let’s try this:

     (global-set-key (kbd "H-a") 'dired)

Now when you press Ctrl+⌘+Option+A, dired should pop up. Proceed with adding the rest of the keys and escape codes in your iTerm2 setup. Also, you can use the cat command to check your work and ensure that the proper escape sequences are reaching the remote machine.

You can also make combinations with Control and META such as C-c H-o with this technique. For C-c H-o you would hit C-c and then release the keys, then Ctrl+⌘+Option+o for the H-o part.

Now you can make loads more keybindings for all your favorite Emacs commands.