diff --git a/modules/top-level/output.nix b/modules/top-level/output.nix index 93e0aed1..0e1bd024 100644 --- a/modules/top-level/output.nix +++ b/modules/top-level/output.nix @@ -74,64 +74,83 @@ in config = let + # Plugin normalization + normalize = + p: + let + defaultPlugin = { + plugin = null; + config = ""; + optional = false; + }; + in + defaultPlugin // (if p ? plugin then p else { plugin = p; }); + normalizePluginList = plugins: map normalize plugins; + + # Normalized plugin list + normalizedPlugins = normalizePluginList config.extraPlugins; + # Plugin list extended with dependencies allPlugins = let - pluginWithItsDeps = p: [ p ] ++ builtins.concatMap pluginWithItsDeps p.dependencies or [ ]; + pluginWithItsDeps = + p: [ p ] ++ builtins.concatMap pluginWithItsDeps (normalizePluginList p.plugin.dependencies or [ ]); in - lib.unique (builtins.concatMap pluginWithItsDeps config.extraPlugins); + lib.unique (builtins.concatMap pluginWithItsDeps normalizedPlugins); - # All plugins with doc tags removed - allPluginsOverridden = map ( - plugin: - plugin.overrideAttrs (prev: { - nativeBuildInputs = lib.remove pkgs.vimUtils.vimGenDocHook prev.nativeBuildInputs or [ ]; - configurePhase = builtins.concatStringsSep "\n" ( - builtins.filter (s: s != ":") [ - prev.configurePhase or ":" - "rm -vf doc/tags" - ] - ); - }) - ) allPlugins; + # Separated start and opt plugins + partitionedPlugins = builtins.partition (p: p.optional) allPlugins; + startPlugins = partitionedPlugins.wrong; + # Remove opt plugin dependencies since they are already available in start plugins + optPlugins = map ( + p: p // { plugin = builtins.removeAttrs p.plugin [ "dependencies" ]; } + ) partitionedPlugins.right; - # Python3 dependencies from all plugins - python3Dependencies = + # Combine start plugins into a single pack + pluginPack = let - deps = map (p: p.python3Dependencies or (_: [ ])) allPluginsOverrided; - in - ps: builtins.concatMap (f: f ps) deps; + # Plugins with doc tags removed + overriddenPlugins = map ( + plugin: + plugin.plugin.overrideAttrs (prev: { + nativeBuildInputs = lib.remove pkgs.vimUtils.vimGenDocHook prev.nativeBuildInputs or [ ]; + configurePhase = builtins.concatStringsSep "\n" ( + builtins.filter (s: s != ":") [ + prev.configurePhase or ":" + "rm -vf doc/tags" + ] + ); + }) + ) startPlugins; - # Combine all plugins into a single pack - pluginPack = pkgs.vimUtils.toVimPlugin ( - pkgs.buildEnv { - name = "plugin-pack"; - paths = allPluginsOverridden; - inherit (config.performance.combinePlugins) pathsToLink; - # Remove empty directories and activate vimGenDocHook - postBuild = '' - find $out -type d -empty -delete - runHook preFixup - ''; - passthru = { - inherit python3Dependencies; - }; - } - ); + # Python3 dependencies + python3Dependencies = + let + deps = map (p: p.plugin.python3Dependencies or (_: [ ])) startPlugins; + in + ps: builtins.concatMap (f: f ps) deps; + in + pkgs.vimUtils.toVimPlugin ( + pkgs.buildEnv { + name = "plugin-pack"; + paths = overriddenPlugins; + inherit (config.performance.combinePlugins) pathsToLink; + # Remove empty directories and activate vimGenDocHook + postBuild = '' + find $out -type d -empty -delete + runHook preFixup + ''; + passthru = { + inherit python3Dependencies; + }; + } + ); # Combined plugins - combinedPlugins = [ pluginPack ]; + combinedPlugins = [ (normalize pluginPack) ] ++ optPlugins; # Plugins to use in finalPackage - plugins = if config.performance.combinePlugins.enable then combinedPlugins else config.extraPlugins; - - defaultPlugin = { - plugin = null; - config = ""; - optional = false; - }; - - normalizedPlugins = map (x: defaultPlugin // (if x ? plugin then x else { plugin = x; })) plugins; + plugins = if config.performance.combinePlugins.enable then combinedPlugins else normalizedPlugins; neovimConfig = pkgs.neovimUtils.makeNeovimConfig ( { @@ -144,7 +163,7 @@ in withNodeJs ; # inherit customRC; - plugins = normalizedPlugins; + inherit plugins; } # Necessary to make sure the runtime path is set properly in NixOS 22.05, # or more generally before the commit: @@ -152,7 +171,7 @@ in // optionalAttrs (lib.functionArgs pkgs.neovimUtils.makeNeovimConfig ? configure) { configure.packages = { nixvim = { - start = map (x: x.plugin) normalizedPlugins; + start = map (x: x.plugin) plugins; opt = [ ]; }; }; diff --git a/tests/test-sources/modules/performance/combine-plugins.nix b/tests/test-sources/modules/performance/combine-plugins.nix index c9bec0d6..f04b61c5 100644 --- a/tests/test-sources/modules/performance/combine-plugins.nix +++ b/tests/test-sources/modules/performance/combine-plugins.nix @@ -129,4 +129,66 @@ } ]; }; + + # Test that optional plugins are handled + optional-plugins.module = + { config, ... }: + { + performance.combinePlugins.enable = true; + extraPlugins = with pkgs.vimPlugins; [ + # Start plugins + plenary-nvim + nvim-lspconfig + # Optional plugin + { + plugin = nvim-treesitter; + optional = true; + } + # Optional plugin with dependency on plenary-nvim + # Dependencies should not be duplicated + { + plugin = telescope-nvim; + optional = true; + } + ]; + extraConfigLuaPost = '' + -- Start plugins are loadable + require("plenary") + require("lspconfig") + + -- Opt plugins are not loadable + local ok = pcall(require, "nvim-treesitter") + assert(not ok, "nvim-treesitter plugin is loadable") + ok = pcall(require, "telescope") + assert(not ok, "telescope-nvim plugin is loadable") + + -- Load plugins + vim.cmd.packadd("nvim-treesitter") + vim.cmd.packadd("telescope.nvim") + + -- Now opt plugins are loadable + require("nvim-treesitter") + require("telescope") + + -- Only one copy of plenary-nvim should be available + assert( + #vim.api.nvim_get_runtime_file("lua/plenary/init.lua", true) == 1, + "plenary-nvim is duplicated" + ) + ''; + assertions = + let + packages = config.finalPackage.packpathDirs.myNeovimPackages; + in + [ + { + assertion = builtins.length packages.start == 1; + message = "More than one start plugin is defined in packpathDirs"; + } + { + assertion = builtins.length packages.opt == 2; + message = "Less than two opt plugins are defined in packpathDirs"; + } + ]; + }; }