Starting with Nix home-manager
All of the messiness with configuring email with Emacs reminded me that there might be a better way using Nix. Let's give it a try with some other packages.
Follow the quick install instructions to get a nix
command.
Home Manager "provides a basic system for managing a user environment using the Nix package manager." I'm not sure what exactly that means over using just nix-shell
, but it seems to be related to managing configuration dotfiles for the software installed using home-manager
. The Home Manager manual say you can install with:
nix-shell '<home-manager>' -A install
There's also a note that we're supposed to source the
$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh
file in my shell configuration, but that this only supports Bash or ZSH, not fish.
Fishing digression
Luckily, we can use the foreign-env plugin in fish (installed using Oh My Fish), which provides an fenv
function for sourcing variables using bash syntax. Now we can add a ~/.config/fish/nix.fish
:
if test -e '/home/shaun/.nix-profile/etc/profile.d/nix.sh' fenv source '/home/shaun/.nix-profile/etc/profile.d/nix.sh' end if test -e '/home/shaun/.nix-profile/etc/profile.d/hm-session-vars.sh' fenv source '/home/shaun/.nix-profile/etc/profile.d/hm-session-vars.sh' end
and call this from ~/.config/fish/config.fish
. ~/.config/fish/nix.fish
and after restarting the fish
session, the variables are set:
❯ export |grep HM_SESS __HM_SESS_VARS_SOURCED 1
Great. (There's also a ~/.nix-profile/etc/profile.d/nix-daemon.sh
file too. Do I need that? Not sourcing it hasn't seemed to cause an issue yet.)
Configuring packages with home-manager
Installing home-manager created a ~/.config/nixpkgs/home.nix
file.
{ config, pkgs, ... }: { # Let Home Manager install and manage itself. programs.home-manager.enable = true; # Home Manager needs a bit of information about you and the # paths it should manage. home.username = "shaun"; home.homeDirectory = "/home/shaun"; # This value determines the Home Manager release that your # configuration is compatible with. This helps avoid breakage # when a new Home Manager release introduces backwards # incompatible changes. # # You can update Home Manager without changing this value. See # the Home Manager release notes for a list of state version # changes in each release. home.stateVersion = "21.05"; }
Let's start with something (hopefully) simple and install Emacs, since I had been building from source to get Emacs 27. Is Emacs 27 available?
❯ nix search emacs27 * nixpkgs.emacs27 (emacs-27.1) The extensible, customizable GNU text editor * nixpkgs.emacs27-nox (emacs-nox-27.1) The extensible, customizable GNU text editor
Ok, so let's try to install it by adding the appropriate incantations to ~/.config/nixpkgs/home.nix
. These "options" are documented at https://rycee.gitlab.io/home-manager/options.html. I don't know why most other tutorials don't link to this, and I only found this in a Reddit thread. The Home Manager documentation links to it in the Table of Contents, but I skipped right over it the first time.
Some of the tutorials list packages in a home.packages
expression, which defines " The set of packages to appear in the user environment."
home.packages = with pkgs; [ emacs27 ];
This sounds reasonable. On the other hand, there's also a programs.emacs
group, so I could do:
programs.emacs = { enable = true; };
I tried both. That caused a conflict:
❯ home-manager switch these derivations will be built: /nix/store/1q13zc9ybdbvm918viav0v1jrlynk8q2-home-manager-path.drv /nix/store/pfcddd9ghlj7ixmcvbpkqcxysq9nl9pk-activation-script.drv /nix/store/cc09h27dkycp1jy8sprn1ng1s8y4vmx7-home-manager-generation.drv building '/nix/store/1q13zc9ybdbvm918viav0v1jrlynk8q2-home-manager-path.drv'... collision between `/nix/store/m1mgx2y1drqmx90m2x6aql00biigzi89-emacs-27.1/bin/ctags' and `/nix/store/26zz4k67p8rpiqsgg82dvssky3k0d49r-emacs-with-packages-27.1/bin/ctags' builder for '/nix/store/1q13zc9ybdbvm918viav0v1jrlynk8q2-home-manager-path.drv' failed with exit code 25 cannot build derivation '/nix/store/cc09h27dkycp1jy8sprn1ng1s8y4vmx7-home-manager-generation.drv': 1 dependencies couldn't be built error: build of '/nix/store/cc09h27dkycp1jy8sprn1ng1s8y4vmx7-home-manager-generation.drv' failed
For more details:
❯ home-manager switch these derivations will be built: /nix/store/1q13zc9ybdbvm918viav0v1jrlynk8q2-home-manager-path.drv /nix/store/pfcddd9ghlj7ixmcvbpkqcxysq9nl9pk-activation-script.drv /nix/store/cc09h27dkycp1jy8sprn1ng1s8y4vmx7-home-manager-generation.drv building '/nix/store/1q13zc9ybdbvm918viav0v1jrlynk8q2-home-manager-path.drv'... collision between `/nix/store/m1mgx2y1drqmx90m2x6aql00biigzi89-emacs-27.1/bin/ctags' and `/nix/store/26zz4k67p8rpiqsgg82dvssky3k0d49r-emacs-with-packages-27.1/bin/ctags' builder for '/nix/store/1q13zc9ybdbvm918viav0v1jrlynk8q2-home-manager-path.drv' failed with exit code 25 cannot build derivation '/nix/store/cc09h27dkycp1jy8sprn1ng1s8y4vmx7-home-manager-generation.drv': 1 dependencies couldn't be built error: build of '/nix/store/cc09h27dkycp1jy8sprn1ng1s8y4vmx7-home-manager-generation.drv' failed
Ok, so some clash between emacs-27.1
and emacs-with-packages-27.1
. Let's get rid of the entry from home.packages
:
❯ home-manager switch /nix/store/lidm821d00nn86im15gic2gjdh984i3w-home-manager-generation Starting home manager activation Activating checkFilesChanged Activating checkLinkTargets Activating writeBoundary Activating installPackages replacing old 'home-manager-path' installing 'home-manager-path' Activating linkGeneration Cleaning up orphan links from /home/shaun No change so reusing latest profile generation 9 Creating home file links in /home/shaun Activating onFilesChange Activating reloadSystemd
Looks promising. Let's try it:
❯ which emacs /home/shaun/.nix-profile/bin/emacs
Running emacs
at the prompt starts GUI Emacs, as desired. Wonderful.
Unfortunately, this new Emacs installation doesn't appear when I search for "emacs" using the Gnome Activities overlay by pressing
Super
.
Digging around led me to some instructions on using Emacs as Default Editor, which indicated that I need an
~/.local/share/applications/emacs.desktop
file. Adapting the example from that page (which was configured for EmacsClient):
[Desktop Entry] Name=Emacs GenericName=Text Editor Comment=Edit text MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++; Exec=emacs Icon=emacs Type=Application Terminal=false Categories=Development;TextEditor; StartupWMClass=Emacs
And now I can launch emacs from the Activity overview, complete with an Emacs icon. It would have been nice if there was a home-manager option that would create this file, but I couldn't find one. So let's just cram it into a generic config file option:
home.file
:
home.file.emacsDesktop = { target = "./.local/share/applications/emacs.desktop"; text = "[Desktop Entry] Name=Emacs GenericName=Text Editor Comment=Edit text MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++; Exec=emacs Icon=emacs Type=Application Terminal=false Categories=Development;TextEditor; StartupWMClass=Emacs"; };
And it still works! This configuration process wasn't so bad. Next up, mail configuration using home-manager.
Edit
It turns out home-manager did create an emacs.desktop
file, which is in ~/.nix-profile/share/applications
. The problem is that my desktop environment wasn't looking for these XDG files there. I tried adding ~/.nix-profile/share/applications
to XDG_DATA_DIRS
using home.sessionVariables
, but according to this Github thread, that's too late in the process. On the other hand, this post on the thread seemed to do what I wanted. so now home.nix
includes these lines (xdg.mime.enable
is true
by default so unnecessary to add):
xdg.enable = true; targets.genericLinux.enable = true;
And then I edited .profile
to include:
if [ -e /home/shaun/.nix-profile/share ] ; then XDG_DATA_DIRS="/home/shaun/.nix-profile/share:$XDG_DATA_DIRS" fi
Log out, log in, and it works perfectly. So now I can delete the expression that manually generates the emacs.desktop
file.