Trying to setup nix with emacs on wayland and emacs-direnv elisp package

Hi everyone,

I think I ran into a dead end. Some time ago I started with Nix and then I heard all will be flakes soon so I tried to switch to a flake config then someone told me just imprt the configuration.nix to the flake. So this i where I started off.

Then I wanted to set up emacs as editor for some coding, I thought I’d make use of direnv and emacs-direnv so the proper environment is loaded when I open a file in a certain project.

Then I thought, let’s try out some LLM to help me and it seemed to work really good in the beginning, especially since all the nix docs I found on the internet where a bit overwhelming and I thought maybe this is a good way to better get into things. Hint: it’s not.

So what do I have? I have a /etc/nixos/flake.nix, a /etc/nixos/configuration.nix, a /etc/nixos/emacs.nix and a /etc/nixos/overlays/emacs-direnv.nix

Flake and configuration.nix should be clear, the emacs.nix is meant to contain everything emacs related (and is used in flake.nix) and emacs-direnv.nix is a custom overlay since I came to the conclusion (might be wrong) the emacs community overlay does not contain emacs-direnv.

Ah, and I am on wayland, so I think I need to use emacs-pgtk?

Anyways, when I try to build with

sudo nixos-rebuild switch --flake /etc/nixos#nixos

I get the following error:

    error: attribute 'emacs-direnv' missing
       at /nix/store/pxpm17d1aggli918zy59a9zz8cgxl5si-source/emacs.nix:11:7:
           10|       epkgs.nix-mode
           11|       epkgs.emacs-direnv
             |       ^
           12|     ]);

Of course this wouldn’t help you help me, so here are the contents of the files:

/etc/nixos/flake.nix:


  description = "The system configuration";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
    emacs-overlay.url = "github:nix-community/emacs-overlay";
  };

  outputs = { self, nixpkgs, emacs-overlay, ... }@inputs: {
    nixosConfigurations.nixos = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [
        ./configuration.nix
        ./emacs.nix
      ];
      # Add the overlay here:
      specialArgs = {};
      pkgs = import nixpkgs {
        system = "x86_64-linux";
        overlays = [ 
          emacs-overlay.overlay
          (import ./overlays/emacs-direnv.nix) 
        ];
      };
    };
  };
}

/etc/nixos/configuration.nix:

{ config, pkgs, ... }:

{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
    ];

  nix.settings.experimental-features = ["nix-command" "flakes"];

  # disable while typing
  services.libinput.touchpad.disableWhileTyping = false;

  # Use the systemd-boot EFI boot loader.
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  networking.hostName = "nixos"; # Define your hostname.
  # Pick only one of the below networking options.
  networking.wireless.enable = true;  # Enables wireless support via wpa_supplicant.
  networking.wireless.networks = {
  # secret
  };  
  # networking.networkmanager.enable = true;  # Easiest to use and most distros use this by default.

  

  # Set your time zone.
  time.timeZone = "Europe/Berlin";

  # Configure network proxy if necessary
  # networking.proxy.default = "http://user:password@proxy:port/";
  # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";

  # Select internationalisation properties.
  i18n.defaultLocale = "de_DE.UTF-8";
  console = {
    font = "Lat2-Terminus16";
    keyMap = pkgs.lib.mkForce "de-latin1";
    useXkbConfig = true; # use xkbOptions in tty.
  };

  fonts.packages = with pkgs; [ (nerdfonts.override { fonts = [ "OpenDyslexic" ]; }) ];

  # Enable the X11 windowing system.
  services.xserver.enable = false;

  # Enable Hyprland wayland Compositor
  programs.hyprland.enable = true;
  
  # Configure keymap in X11
  services.xserver.xkb.layout = "de";
  # services.xserver.xkbOptions = "eurosign:e,caps:escape";
  services.displayManager.sddm.wayland.enable = true;

  

  # Enable CUPS to print documents.
  services.printing.enable = true;

  # Enable sound.
  #sound.enable = false; # conflicts with pipewire, also was removed I think
  security.rtkit.enable = true;
  services.pipewire.enable = true;
  services.pipewire.audio.enable = true;
  services.pipewire.wireplumber.enable = true;
  services.pipewire.pulse.enable = true;
  services.pipewire.jack.enable = true;
  services.pipewire.alsa.enable = true;
  services.pipewire.alsa.support32Bit = true;
  
  # enable Bluetooth
  hardware.bluetooth.enable = true;
  services.blueman.enable = true;

  # Enable & setup polkit auth agent
  security.polkit.enable = true;
  security.polkit.extraConfig = ''
    polkit.addRule(function(action, subject) {
      if (
        subject.isInGroup("users")
          && (
            action.id == "org.freedesktop.login1.reboot" ||
            action.id == "org.freedesktop.login1.reboot-multiple-sessions" ||
            action.id == "org.freedesktop.login1.power-off" ||
            action.id == "org.freedesktop.login1.power-off-multiple-sessions" ||
          )
        )
      {
        returnpolkit.Result.YES;
      }
    })
  '';

  # Enable touchpad support (enabled default in most desktopManager).
  services.libinput.enable = true;

  # Define a user account. Don't forget to set a password with ‘passwd’.
  users.users.benny = {
    home = "/home/benny";
    hashedPassword = "1234";
    isNormalUser = true;
    extraGroups = [ "wheel"     # Enable 'sudo' for the user.
                    "audio"     # Enable ‘sound’ for the user.
                    "users"     # Group that can reboot and power off
                  ];
     packages = with pkgs; [
       firefox-wayland
       tree
       htop
       netcat
       nmap
       evolution
       pamixer
       brightnessctl
       wev
       mpg123
       minetest
    ];
  };

  # List packages installed in system profile. To search, run:
  # $ nix search wget
  environment.systemPackages = with pkgs; [
    vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default.
    wget
    kitty
    xdg-desktop-portal-hyprland
    libsForQt5.polkit-kde-agent
    qt5.qtwayland
    qt6.qtwayland
    eww
    killall
    unzip
    wallust
    hyprpaper
    mako
    libnotify
    waypaper
  ];


  # direnv and nix-direnv (for better integration)
  programs.direnv.enable = true;
  programs.direnv.nix-direnv.enable = true;

  # environment variables
  environment.sessionVariables = rec {
    XDG_CACHE_HOME  = "$HOME/.cache";
    XDG_CONFIG_HOME = "$HOME/.config";
    XDG_DATA_HOME   = "$HOME/.local/share";
    XDG_STATE_HOME  = "$HOME/.local/state";

    # Not officially in the specification
    XDG_BIN_HOME    = "$HOME/.local/bin";
    PATH = [ 
      "${XDG_BIN_HOME}"
    ];
  };
  system.stateVersion = "23.05"; # Did you read the comment?

}


/etc/nixos/emacs.nix:

{ config, pkgs, ... }:

let
  epkgs = pkgs.emacsPackagesFor pkgs.emacs-git;
in
{
  services.emacs = {
    enable = true;
    package = epkgs.emacsWithPackages (epkgs: [
      epkgs.nix-mode
      epkgs.emacs-direnv
    ]);
  };
}

/etc/nixos/overlays/emacs-direnv.nix:

self: super: {
  emacsPackagesFor = emacs:
    let
      base = super.emacsPackagesFor emacs;
      emacs-direnv = base.melpaBuild {
        pname = "emacs-direnv";
        version = "2.2.0";
        src = super.fetchFromGitHub {
          owner = "wbolster";
          repo = "emacs-direnv";
          rev = "2.2.0";
          sha256 = "sha256-zDVAd1gJT7ba+F02lT5O+RniKGwONmfrACpRPd+1xTE=";
        };
      };
    in
      base // { emacs-direnv = emacs-direnv; };
}

So, this is all the info I could think of that might be relevant. You see I am not really knowing what I’m doing. I tried to learn the nix language, understood a bit but then all those readily available functions overwhelm me and I quickly get lost in real world nix files.

You can guess I am open to any recommendation. Thanks in advance

the emacs direnv package is in nixpkgs as emacsPackages.direnv
The correct call is epkgs.direnv and you don’t need the (import ./overlays/emacs-direnv.nix) or the emacs-direnv overlay

In general you do not need the emacs-overlay unless you are managing your emacs init files through nix, when then it can generate all the nix calls to load the emacs packages without listing the packages in nix. Or if you want the latest emacs from git.

Re emacs I find envrc is better for direnv as it alters emacs environment as a locl buffer change and not globally as emacs direnv does.

1 Like

Hey, thank you for the quick answer. I got rid of the overlays, replaces emacs-direnv with envrc and also changed the emacs variant to emacs30-pgtk (because wayland).

Now the build ran through. The only problem now is that for some reason the emacs daemon is not running and when I start plain emacs it seems to not pick up my ~/.config/emacs/init.el

Good - however I run on macOS and so no services.
The only thing I can think of is have you a (server-start) in your init.el

re init what is your user-emacs-directory in emacs?

After rebooting the daemon was present, so I guess this is solved. Alsoyes, playing with the overlays seems to have created a ~/.emacs file somy config in ~/config/emacs was not read.
Now I gotta look how to use the overlay to have the init files also managed by nix. Thank you for this hint