Using Emacs in a local Nix environment
In this blog post, I explain how to use Emacs in a local Nix environment for all modes, without needing mode-specific configuration.
Recently, I was trying to get
haskell-mode in Emacs to work inside a (local) Nix environment, à la
nix-shell. I use Nix to manage my Haskell dependencies1. Those dependencies aren’t installed globally (or rather, aren’t in my
$PATH), and I don’t want them to be installed by Cabal, so building the project and running GHCI should happen inside a Nix environment.
haskell-mode, you can run the function
haskell-process-load-file to run GHCI inside Emacs. If you set
'cabal-new-repl), GHCI will use Cabal to manage dependencies, but it will run
cabal in your
$PATH, or the program specified in
So I created a script with the following contents:
args=$@ nix-shell --run "cabal $args"
…, and set
haskell-process-path-cabal to the path to the script.
This works quite well, but isn’t very elegant.
Then I discovered the
haskell-process-wrapper-function, which ‘wraps or transforms Haskell process commands (…)’, according to the documentation. The documentation even contains an example value which makes the process commands run inside a
nix-shell (simplified a bit here):
setq haskell-process-wrapper-function (lambda (argv) (list "nix-shell" ("-I" "." "--command" " ")))) (mapconcat 'identity argv
This is works well, and is a lot more elegant than the script above. But it only works for
haskell-mode: when I want to run Python with packages managed by Nix inside Emacs, I’ll have to search
python-mode for an option similar to
haskell-process-wrapper-function. And when I want to use yet another language, …
lorri and direnv
So I tried to find a general solution, and found lorri. lorri integrates direnv with Nix. With lorri, you don’t need
nix-shell anymore, since direnv automatically changes your path, and lorri automatically builds your shell environment. (See the lorri demonstration.)
The direnv home page explains how to install a direnv hook into your shell, but you can also add direnv to Emacs: the emacs-direnv package adds direnv support. It’s as simple as adding the following to your Emacs configuration (if you use
use-package direnv ( :config (direnv-mode))
If you now visit a file in a directory where lorri is initialised, your environment variables will be updated, and you can run all sorts of processes (
eshell, etc.) inside a Nix environment.
direnv changes the environment variables (such as
$PATH) that were generated by lorri in a local directory. Because your
$PATH is changed when you visit a file in that directory, there is no need for any mode-specific Emacs configuration.
Read how to do this in the Nixpkgs manual.↩︎