How to share system-level NixOs config with Darwin's home-manager in the same file?

Kanata is available as an option in NixOs but not in Darwin. So, I have to use a system-level config for NixOS and a home-manager config for Darwin. This is the code:

{
  lib,
  pkgs,
  config,
  ...
}: {
  options = {
    customized.kanata.enable =
      lib.mkEnableOption "Enable kanata (keyboard layout) with personal config";
  };

  config = lib.mkMerge [
    (lib.mkIf (config.customized.kanata.enable
      && pkgs.stdenv.hostPlatform.isLinux) {
      services.kanata = {
        enable = true;
        keyboards = {
          internalKeyboard = {
            config = builtins.readFile ./kanata.kbd;
          };
        };
      };
    })

    (lib.mkIf (config.customized.kanata.enable
      && pkgs.stdenv.hostPlatform.isDarwin) {
      # TODO: This doesn't compile in Linux because all mkIf braches must be evaluated, even if they are not used.
      home.packages = with pkgs; [
        kanata # Keyboard remap layouts.
      ];
      home.file.".config/kanata/kanata.kbd".source = ./kanata.kbd;
    })
  ];
}

It intuitively should work, but it doesn’t because even though Nix is lazy, it evaluates all paths (I believe for type-checking?), and, depending on the system I’m using, one branch will always fail. In Darwin, it fails because system.kanata doesn’t exist; In NixOs, it fails because home doesn’t exist. How can I solve this without splitting the configuration into two files?

Thank you in advance!

Create separate files and only import the darwin-relevant modules on darwin.

Thank you, @waffle8946! However, that’s exactly what I want to avoid. Having two files for the same config seems like an anti-pattern.

It’s not the same config, HM and NixOS are user- vs. system-level config, and their module arguments differ, which should be a hint that mixing them in the same file is an antipattern.

1 Like