GHCi custom key bindings

2018-08-21

Keyboard shortcuts in GHCi

I want to bind keyboard shortcuts to GHCi commands. GHCi makes use of the Haskeline package for performing line input. Thus, it is Haskeline’s configuration file, $HOME/.haskeline, where we’ll need to place our shortcuts.

As an example, I’m going to show you how to bind F7 to the GHCi :reload command.

The basics

Here’s the documentation for custom key bindings in Haskeline. We’ll need to add something of the following form to $HOME/.haskeline:

bind: <key> <keys>

F7, for <key> is simply f7. The string :reload needs to be decomposed into a space-separated sequence of <key> values, i.e. : r e l o a d. Thus, the first line in $HOME/.haskeline becomes:

bind: f7 : r e l o a d

Let’s fire up GHCi and see what happens when you press F7:

stack ghci

If you’re on Windows, you’re probably done at this point: this should just work. On Linux or macOs, F7 will probably do nothing at this point. To work on Posix platforms, you’ll need to add keyseq entry:

keyseq: <term> <string> <key>

So, we’ll need to add keyseq for F7. How do I get the appropriate key code? Fortunately, GHC can do this for you:

stack exec ghc -- -e getLine

At this point, press F7 followed by Enter and you’ll get output like the following:

^[[18~
"\ESC[18~"

The second line is the key sequence that you’ll use with Haskeline. Grab this string, create a new keyseq entry to map it to F7 and you’ll end up with a configuration file looking something like the following:

bind: f7 : r e l o a d
keyseq: "\ESC[18~" f7

And you’re done! Fire up GHCi, and F7 should generate :reload for you.

My current favourite configuration looks like:

bind: f7 : r e l o a d return : m a i n return
keyseq: "\ESC[18~" f7

This will cause F7 to reload the current module and run main all in one keypress. Nice!

Tags: GHCi, Haskeline, Haskell

All content © 2018 Richard Cook. All rights reserved.