Nix-shells in Emacs Org-mode source blocks

I discovered this week that using the :shebang option for org-mode source blocks, we can execute source blocks within a nix-shell.

Using this, org-mode can define the dependencies and runtime available for literate programming org-mode documents.

Define your shell.nix in a source block

  #+begin_src nix :tangle /tmp/shell.nix
    {pkgs ? import <nixpkgs> {} }:
    pkgs.mkShell {
      buildInputs = [ pkgs.hello ];
    }
  #+end_src

Tangle it with ‘M-x org-babel-tangle’

Then you can use this shell:

  #+begin_src shell :shebang "#!/usr/bin/env nix-shell\n#!nix-shell /tmp/shell.nix -i bash --pure" :results output
    hello
  #+end_src

  #+RESULTS:
  : Hello, World!

This also works for other interpreted languages:
Python:

  #+begin_src nix :tangle /tmp/python.nix
    {pkgs ? import <nixpkgs> {} }:
    pkgs.mkShell {
      buildInputs = [ pkgs.python3 ];
      name = "World";
    }
  #+end_src
  
  #+begin_src shell :shebang "#!/usr/bin/env nix-shell\n#!nix-shell /tmp/python.nix -i python --pure" :results output
    import os
    print("Hello, {}!".format(os.environ['name']))
  #+end_src

  #+RESULTS:
  : Hello, World!

Nodejs:

    {pkgs ? import <nixpkgs> {} }:
    pkgs.mkShell {
      buildInputs = [ pkgs.nodejs ];
      name = "Emacs";
    }
  #+end_src

  
  #+begin_src shell :shebang "#!/usr/bin/env nix-shell\n`\n#!nix-shell /tmp/node.nix -i node --pure\n`" :results output
    console.log(`Hello, ${process.env.name}!`);
  #+end_src

  #+RESULTS:
  : Hello, Emacs!

Example org doc:

Thanks for reading! Any ideas on how to make this better or other ways to use this paradigm?

4 Likes

Indeed cool. Sounds like a polyglot in-emacs jupyter.