diff --git a/modules/top-level/nixpkgs.nix b/modules/top-level/nixpkgs.nix index 3116ec7603..a497f9559a 100644 --- a/modules/top-level/nixpkgs.nix +++ b/modules/top-level/nixpkgs.nix @@ -55,31 +55,100 @@ in > Use this option with care. ''; }; + + overlays = lib.mkOption { + type = + let + overlayType = lib.mkOptionType { + name = "nixpkgs-overlay"; + description = "nixpkgs overlay"; + check = lib.isFunction; + merge = lib.mergeOneOption; + }; + in + lib.types.listOf overlayType; + default = [ ]; + # First example from https://nixos.org/manual/nixpkgs/unstable/#what-if-your-favourite-vim-plugin-isnt-already-packaged + # Second example from https://github.com/nix-community/nixvim/pull/2430#discussion_r1805700738 + # Third example from https://github.com/atimofeev/nixos-config/blob/0b1c1c47c4359d6a2aa9a5eeecb32fa89ad08c88/overlays/neovim-unwrapped.nix + example = lib.literalExpression '' + [ + + # Add a vim plugin that isn't packaged in nixpkgs + (final: prev: { + easygrep = final.vimUtils.buildVimPlugin { + name = "vim-easygrep"; + src = final.fetchFromGitHub { + owner = "dkprice"; + repo = "vim-easygrep"; + rev = "d0c36a77cc63c22648e792796b1815b44164653a"; + hash = "sha256-bL33/S+caNmEYGcMLNCanFZyEYUOUmSsedCVBn4tV3g="; + }; + }; + }) + + # Override neovim-unwrapped with one from a flake input + # Using `stdenv.hostPlatform` to access `system` + (final: prev: { + neovim-unwrapped = + inputs.neovim-nightly-overlay.packages.''${final.stdenv.hostPlatform.system}.default; + }) + + # Override neovim-unwrapped to tweak its desktop entry + (final: prev: { + neovim-unwrapped = prev.neovim-unwrapped.overrideAttrs (old: { + postInstall = old.postInstall or "" + ''' + substituteInPlace $out/share/applications/nvim.desktop \ + --replace "TryExec=nvim" "" \ + --replace "Terminal=true" "Terminal=false" \ + --replace "Exec=nvim %F" "Exec=kitty -e nvim %F" + '''; + }); + }) + + ] + ''; + description = '' + List of overlays to apply to Nixpkgs. + This option allows modifying the Nixpkgs package set accessed through the `pkgs` module argument. + + For details, see the [Overlays chapter in the Nixpkgs manual](https://nixos.org/manual/nixpkgs/stable/#chap-overlays). + + + Overlays specified using the {option}`nixpkgs.overlays` option will be + applied after the overlays that were already included in `nixpkgs.pkgs`. + + + ''; + }; }; - config = { - # For now we only set this when `nixpkgs.pkgs` is defined - # TODO: construct a default pkgs instance from pkgsPath and cfg options - # https://github.com/nix-community/nixvim/issues/1784 - _module.args = lib.optionalAttrs opt.pkgs.isDefined { + config = + let + # TODO: construct a default pkgs instance from pkgsPath and cfg options + # https://github.com/nix-community/nixvim/issues/1784 + + finalPkgs = + if opt.pkgs.isDefined then + cfg.pkgs.appendOverlays cfg.overlays + else + # TODO: Remove once pkgs can be constructed internally + throw '' + nixvim: `nixpkgs.pkgs` is not defined. In the future, this option will be optional. + Currently a pkgs instance must be evaluated externally and assigned to `nixpkgs.pkgs` option. + ''; + in + { # We explicitly set the default override priority, so that we do not need # to evaluate finalPkgs in case an override is placed on `_module.args.pkgs`. # After all, to determine a definition priority, we need to evaluate `._type`, # which is somewhat costly for Nixpkgs. With an explicit priority, we only # evaluate the wrapper to find out that the priority is lower, and then we # don't need to evaluate `finalPkgs`. - pkgs = lib.mkOverride lib.modules.defaultOverridePriority cfg.pkgs.__splicedPackages; + _module.args.pkgs = lib.mkOverride lib.modules.defaultOverridePriority finalPkgs.__splicedPackages; }; - - assertions = [ - { - # TODO: Remove or rephrase once pkgs can be constructed internally - assertion = config._module.args ? pkgs; - message = '' - `nixpkgs.pkgs` is not defined. In the future, this option will be optional. - Currently a pkgs instance must be evaluated externally and assigned to `nixpkgs.pkgs` option. - ''; - } - ]; - }; } diff --git a/tests/main.nix b/tests/main.nix index e2c2de1ba4..a205b450c9 100644 --- a/tests/main.nix +++ b/tests/main.nix @@ -7,6 +7,8 @@ linkFarm, pkgs, pkgsUnfree, + self, + system, }: let fetchTests = callTest ./fetch-tests.nix { }; @@ -20,6 +22,11 @@ let module = { _file = file; imports = [ module ]; + _module.args = { + # Give tests access to the flake + inherit self system; + inherit (self) inputs; + }; }; pkgs = pkgsUnfree; }; diff --git a/tests/test-sources/modules/nixpkgs.nix b/tests/test-sources/modules/nixpkgs.nix new file mode 100644 index 0000000000..6efce76a93 --- /dev/null +++ b/tests/test-sources/modules/nixpkgs.nix @@ -0,0 +1,74 @@ +{ + # TODO: expect not setting `nixpkgs.pkgs` to throw + + overlays = + { pkgs, ... }: + { + test.runNvim = false; + + nixpkgs.overlays = [ + (final: prev: { + foobar = "foobar"; + }) + ]; + + assertions = [ + { + assertion = pkgs.foobar or null == "foobar"; + message = '' + Expected `pkgs.foobar` to be "foobar" + ''; + } + ]; + }; + + # Test that overlays from both `nixpkgs.pkgs` _and_ `nixpkgs.overlays` are applied + stacked_overlays = + { + inputs, + system, + pkgs, + ... + }: + { + test.runNvim = false; + + nixpkgs.pkgs = import inputs.nixpkgs { + inherit system; + overlays = [ + (final: prev: { + foobar = "foobar"; + conflict = "a"; + }) + ]; + }; + + nixpkgs.overlays = [ + (final: prev: { + hello = "world"; + conflict = "b"; + }) + ]; + + assertions = [ + { + assertion = pkgs.foobar or null == "foobar"; + message = '' + Expected `pkgs.foobar` to be "foobar" + ''; + } + { + assertion = pkgs.hello or null == "world"; + message = '' + Expected `pkgs.hello` to be "world" + ''; + } + { + assertion = pkgs.conflict or null == "b"; + message = '' + Expected `pkgs.conflict` to be "b" + ''; + } + ]; + }; +}