From 7bb135b091f42654efc19fd1d0db9cd6c82bc314 Mon Sep 17 00:00:00 2001 From: Stanislav Asunkin <1353637+stasjok@users.noreply.github.com> Date: Sun, 27 Apr 2025 10:05:52 +0300 Subject: [PATCH 1/7] Revert "modules/performance: temporary add plenary to extraPlugins to fix tests" This reverts commit 5a491f4b2bc132cea2b56bfad0d445708c223113. --- modules/performance.nix | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/modules/performance.nix b/modules/performance.nix index 567f6d9371..d88222bac4 100644 --- a/modules/performance.nix +++ b/modules/performance.nix @@ -1,12 +1,6 @@ -{ - lib, - pkgs, - config, - ... -}: +{ lib, ... }: let inherit (lib) types; - cfg = config.performance; pathsToLink = [ # :h rtp @@ -95,17 +89,6 @@ in }; }; - # FIXME: The performance options do not correctly propagate lua module dependencies. - # We can explicitly specify 'plenary-nvim', as it is a very common dependency. - # While this is enough for our test suite to pass, end-users may be affected by other dependencies not covered by our test suite. - # - # See https://github.com/nix-community/nixvim/pull/3099 - config.extraPlugins = - lib.mkIf (cfg.combinePlugins.enable || (cfg.byteCompileLua.enable && cfg.byteCompileLua.plugins)) - [ - pkgs.vimPlugins.plenary-nvim - ]; - # Set option value with default priority so that values are appended by default config.performance.combinePlugins = { inherit pathsToLink; }; } From faa31d994cb5c2f320869dbb21252e21abcda3fc Mon Sep 17 00:00:00 2001 From: Stanislav Asunkin <1353637+stasjok@users.noreply.github.com> Date: Sun, 27 Apr 2025 10:39:40 +0300 Subject: [PATCH 2/7] Revert "tests/modules-performance: add nvim-cmp to extraPlugins when necessary" This reverts commit bb5b0a26556017f1f3a4c07f8bd20dee88f6ffb0. This change defeats the purpose of the dependency test. Revert it. The test should verify that dependencies are correctly pulled. If upstream plugin doesn't have dependency anymore, then a suitable alternative should be used, not dependencies added manually. --- tests/test-sources/modules/performance/combine-plugins.nix | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/test-sources/modules/performance/combine-plugins.nix b/tests/test-sources/modules/performance/combine-plugins.nix index b200db1d0b..07ede693e3 100644 --- a/tests/test-sources/modules/performance/combine-plugins.nix +++ b/tests/test-sources/modules/performance/combine-plugins.nix @@ -64,8 +64,6 @@ in extraPlugins = with pkgs.vimPlugins; [ # Depends on nvim-cmp cmp-dictionary - # We have to manually add cmp-dictionary's dependence: nvim-cmp - nvim-cmp # Depends on telescope-nvim which itself depends on plenary-nvim telescope-undo-nvim ]; @@ -334,8 +332,6 @@ in telescope-nvim # Only its dependency (nvim-cmp) won't be combined, but not the plugin itself cmp-dictionary - # We have to manually add cmp-dictionary's dependence: nvim-cmp - nvim-cmp # More plugins gitsigns-nvim luasnip From 014b143f6a78e13035c45d71061975387cde68e6 Mon Sep 17 00:00:00 2001 From: Stanislav Asunkin <1353637+stasjok@users.noreply.github.com> Date: Sun, 27 Apr 2025 12:39:11 +0300 Subject: [PATCH 3/7] tests/modules/performance/combine-plugins: restore test functionality Replace test plugins to those that reflect the intention for the test. --- .../modules/performance/combine-plugins.nix | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/tests/test-sources/modules/performance/combine-plugins.nix b/tests/test-sources/modules/performance/combine-plugins.nix index 07ede693e3..be7006b471 100644 --- a/tests/test-sources/modules/performance/combine-plugins.nix +++ b/tests/test-sources/modules/performance/combine-plugins.nix @@ -62,17 +62,17 @@ in { performance.combinePlugins.enable = true; extraPlugins = with pkgs.vimPlugins; [ - # Depends on nvim-cmp - cmp-dictionary - # Depends on telescope-nvim which itself depends on plenary-nvim - telescope-undo-nvim + # Depends on nui-nvim + noice-nvim + # Depends on null-ls-nvim which itself depends on plenary-nvim + mason-null-ls-nvim ]; extraConfigLuaPost = '' -- Plugins and its dependencies are loadable - require("cmp_dictionary") - require("cmp") - require("telescope-undo") - require("telescope") + require("noice") + require("nui.popup") + require("mason-null-ls.settings") -- Avoid calling deprecated functions + require("null-ls.helpers") -- Avoid calling deprecated functions require("plenary") ''; assertions = [ @@ -155,7 +155,7 @@ in # Optional plugin with dependency on plenary-nvim # Dependencies should not be duplicated { - plugin = telescope-nvim; + plugin = none-ls-nvim; optional = true; } ]; @@ -167,16 +167,16 @@ in -- 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") + ok = pcall(require, "null-ls") + assert(not ok, "null-ls-nvim plugin is loadable") -- Load plugins vim.cmd.packadd("nvim-treesitter") - vim.cmd.packadd("telescope.nvim") + vim.cmd.packadd("none-ls.nvim") -- Now opt plugins are loadable require("nvim-treesitter") - require("telescope") + require("null-ls") -- Only one copy of plenary-nvim should be available assert( @@ -321,17 +321,17 @@ in # By package itself nvim-lspconfig # Its dependency, plenary-nvim, not in this list, so will be combined - telescope-nvim + none-ls-nvim # Dependency of other plugin - "nvim-cmp" + "nui.nvim" ]; }; extraPlugins = with pkgs.vimPlugins; [ nvim-treesitter nvim-lspconfig - telescope-nvim - # Only its dependency (nvim-cmp) won't be combined, but not the plugin itself - cmp-dictionary + none-ls-nvim + # Only its dependency (nui-nvim) won't be combined, but not the plugin itself + noice-nvim # More plugins gitsigns-nvim luasnip @@ -340,10 +340,10 @@ in -- Plugins are loadable require("nvim-treesitter") require("lspconfig") - require("telescope") + require("null-ls") require("plenary") - require("cmp_dictionary") - require("cmp") + require("noice") + require("nui.popup") require("gitsigns") require("luasnip") @@ -357,18 +357,17 @@ in -- Standalone plugins assert(is_standalone("nvim-treesitter"), "nvim-treesitter is combined, expected standalone") assert(is_standalone("lspconfig"), "nvim-lspconfig is combined, expected standalone") - assert(is_standalone("telescope"), "telescope-nvim is combined, expected standalone") - -- Add trailing slash to ensure that it doesn't match cmp_dictionary - assert(is_standalone("cmp/", "nvim-cmp"), "nvim-cmp is combined, expected standalone") + assert(is_standalone("null-ls", "none-ls.nvim"), "none-ls-nvim is combined, expected standalone") + assert(is_standalone("nui"), "nui-nvim is combined, expected standalone") -- Combined plugins assert(not is_standalone("plenary"), "plenary-nvim is standalone, expected combined") - assert(not is_standalone("cmp_dictionary", "cmp-dictionary"), "cmp-dictionary is standalone, expected combined") + assert(not is_standalone("noice"), "noice-nvim is standalone, expected combined") assert(not is_standalone("gitsigns"), "gitsigns-nvim is standalone, expected combined") assert(not is_standalone("luasnip"), "luasnip is standalone, expected combined") ''; assertions = [ { - # plugin-pack, nvim-treesitter, nvim-lspconfig, telescope-nvim, nvim-cmp + # plugin-pack, nvim-treesitter, nvim-lspconfig, none-ls-nvim, nui-nvim assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 5; message = "Wrong number of plugins in packpathDirs"; } From 9c39ea4ccbfbd0077a799d01ba2aab632bededfa Mon Sep 17 00:00:00 2001 From: Stanislav Asunkin <1353637+stasjok@users.noreply.github.com> Date: Sun, 27 Apr 2025 14:01:37 +0300 Subject: [PATCH 4/7] tests/modules/performance/byte-compile-lua: fix tests telescope-nvim doesn't have explicit dependency on plenary-nvim anymore. Use noice-nvim which have a dependency on nui-nvim instead. --- .../modules/performance/byte-compile-lua.nix | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/tests/test-sources/modules/performance/byte-compile-lua.nix b/tests/test-sources/modules/performance/byte-compile-lua.nix index 5375425af6..a3041a5e00 100644 --- a/tests/test-sources/modules/performance/byte-compile-lua.nix +++ b/tests/test-sources/modules/performance/byte-compile-lua.nix @@ -248,8 +248,8 @@ in extraPlugins = with pkgs.vimPlugins; [ nvim-lspconfig - # Depends on plenary-nvim - telescope-nvim + # Depends on nui-nvim + noice-nvim # buildCommand plugin with python3 dependency ((pkgs.writeTextDir "/plugin/test.lua" "vim.opt.tabstop = 2").overrideAttrs { passthru.python3Dependencies = ps: [ ps.pyyaml ]; @@ -263,8 +263,8 @@ in -- Plugins are loadable require("lspconfig") - require("telescope") - require("plenary") + require("noice") + require("nui.popup") require("nvim-treesitter") -- Python modules are importable @@ -276,16 +276,13 @@ in test_rtp_file("plugin/lspconfig.lua", true) test_rtp_file("doc/lspconfig.txt", false) - -- telescope-nvim - test_rtp_file("lua/telescope/init.lua", true) - test_rtp_file("lua/telescope/builtin/init.lua", true) - test_rtp_file("plugin/telescope.lua", true) - test_rtp_file("autoload/health/telescope.vim", false) - test_rtp_file("doc/telescope.txt", false) + -- noice-nvim + test_rtp_file("lua/noice/init.lua", true) + test_rtp_file("lua/noice/config/init.lua", true) + test_rtp_file("doc/noice.nvim.txt", false) - -- Dependency of telescope-nvim (plenary-nvim) - test_rtp_file("lua/plenary/init.lua", true) - test_rtp_file("plugin/plenary.vim", false) + -- Dependency of noice-nvim (nui-nvim) + test_rtp_file("lua/nui/popup/init.lua", true) -- Test plugin test_rtp_file("plugin/test.lua", true) From 57e19ec3ecd45af908292ffd732847a64b29de51 Mon Sep 17 00:00:00 2001 From: Stanislav Asunkin <1353637+stasjok@users.noreply.github.com> Date: Sun, 27 Apr 2025 17:49:29 +0300 Subject: [PATCH 5/7] tests/modules/performance/combine-plugins: use stub plugins for tests During the last half of the year many dependencies of plugins used in the tests were changed in nixpkgs. To make tests more robust use a specially crafted stub plugins. --- .../modules/performance/combine-plugins.nix | 387 ++++++++++-------- 1 file changed, 213 insertions(+), 174 deletions(-) diff --git a/tests/test-sources/modules/performance/combine-plugins.nix b/tests/test-sources/modules/performance/combine-plugins.nix index be7006b471..ad8eb840e7 100644 --- a/tests/test-sources/modules/performance/combine-plugins.nix +++ b/tests/test-sources/modules/performance/combine-plugins.nix @@ -6,31 +6,99 @@ let pluginCount = pkg: files: type: builtins.length (builtins.filter (p: p != files) pkg.packpathDirs.myNeovimPackages.${type}); + + # Stub plugins + mkPlugin = + name: args: + pkgs.vimUtils.buildVimPlugin ( + { + pname = name; + version = "2025-04-27"; + src = pkgs.runCommand "${name}-source" { } '' + mkdir "$out" + # Add some colliding files + echo "# ${name}" > "$out/README.md" + echo "Copyright (c) ${name}" > "$out/LICENSE" + mkdir "$out/tests" + echo "return '${name}'" > "$out/tests/test.lua" + # Add import path + mkdir -p "$out/lua/${name}" + echo "return '${name}'" > "$out/lua/${name}/init.lua" + # Add doc + mkdir "$out/doc" + echo "*${name}.txt* ${name}" > "$out/doc/${name}.txt" + ''; + } + // args + ); + # Simple plugins without any features + simplePlugin1 = mkPlugin "simple-plugin-1" { }; + simplePlugin2 = mkPlugin "simple-plugin-2" { }; + simplePlugin3 = mkPlugin "simple-plugin-3" { }; + # Plugins with dependencies + pluginWithDeps1 = mkPlugin "plugin-with-deps-1" { + dependencies = [ simplePlugin1 ]; + }; + pluginWithDeps2 = mkPlugin "plugin-with-deps-2" { + dependencies = [ simplePlugin2 ]; + }; + pluginWithDeps3 = mkPlugin "plugin-with-deps-3" { + dependencies = [ simplePlugin3 ]; + }; + # Plugin with recursive dependencies + pluginWithRecDeps = mkPlugin "plugin-with-rec-deps" { + dependencies = [ + pluginWithDeps1 + pluginWithDeps2 + ]; + }; + # Plugin with non-standard files + pluginWithExtraFiles = mkPlugin "plugin-with-extra-files" { + postInstall = '' + mkdir "$out/_extra" + touch "$out/_extra/test" + ''; + }; + # Plugins with Python dependencies + pluginWithPyDeps1 = mkPlugin "plugin-with-py-deps-1" { + passthru.python3Dependencies = ps: [ ps.pyyaml ]; + }; + pluginWithPyDeps2 = mkPlugin "plugin-with-py-deps-2" { + passthru.python3Dependencies = ps: [ ps.pyyaml ]; + }; + pluginWithPyDeps3 = mkPlugin "plugin-with-py-deps-3" { + passthru.python3Dependencies = ps: [ ps.requests ]; + }; in { # Test basic functionality default = { config, ... }: + let + extraPlugins = [ + simplePlugin1 + simplePlugin2 + simplePlugin3 + ]; + in { performance.combinePlugins.enable = true; - extraPlugins = with pkgs.vimPlugins; [ - nvim-lspconfig - nvim-treesitter - ]; - extraConfigLuaPost = '' - -- Plugins are loadable - require("lspconfig") - require("nvim-treesitter") + inherit extraPlugins; + extraConfigLuaPost = lib.concatMapStringsSep "\n" ( + name: + # lua + '' + -- Plugin is loadable + require("${name}") - -- No separate plugin entries in nvim_list_runtime_paths - assert(not vim.iter(vim.api.nvim_list_runtime_paths()):any(function(entry) - return entry:find("treesitter") or entry:find("lspconfig") - end), "separate plugins are found in runtime") + -- No separate plugin entry in vim.api.nvim_list_runtime_paths() + assert(not vim.iter(vim.api.nvim_list_runtime_paths()):any(function(entry) + return entry:find("${name}", 1, true) + end), "plugin '${name}' found in runtime, expected to be combined") - -- Help tags are generated - assert(vim.fn.getcompletion("lspconfig", "help")[1], "no help tags for nvim-lspconfig") - assert(vim.fn.getcompletion("nvim-treesitter", "help")[1], "no help tags for nvim-treesitter") - ''; + -- Help tags are generated + assert(vim.fn.getcompletion("${name}", "help")[1], "no help tags for '${name}'") + '') (map lib.getName extraPlugins); assertions = [ { assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 1; @@ -42,12 +110,25 @@ in # Test disabled option disabled = { config, ... }: + let + extraPlugins = [ + simplePlugin1 + simplePlugin2 + simplePlugin3 + ]; + in { performance.combinePlugins.enable = false; - extraPlugins = with pkgs.vimPlugins; [ - nvim-lspconfig - nvim-treesitter - ]; + inherit extraPlugins; + extraConfigLuaPost = lib.concatMapStringsSep "\n" ( + name: + # lua + '' + -- Separate plugin entry in vim.api.nvim_list_runtime_paths() + assert(vim.iter(vim.api.nvim_list_runtime_paths()):any(function(entry) + return entry:find("${name}", 1, true) + end), "plugin '${name}' isn't found in runtime as a separate entry, expected not to be combined") + '') (map lib.getName extraPlugins); assertions = [ { assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" >= 2; @@ -61,19 +142,26 @@ in { config, ... }: { performance.combinePlugins.enable = true; - extraPlugins = with pkgs.vimPlugins; [ - # Depends on nui-nvim - noice-nvim - # Depends on null-ls-nvim which itself depends on plenary-nvim - mason-null-ls-nvim + extraPlugins = [ + # Depends on pluginWithDeps1 and pluginWithDeps2 which themselves depend on simplePlugin1 and simplePlugin2 + pluginWithRecDeps + # Depends on simplePlugin3 + pluginWithDeps3 + # Duplicated dependency + pluginWithDeps2 + # Duplicated plugin + simplePlugin2 ]; extraConfigLuaPost = '' - -- Plugins and its dependencies are loadable - require("noice") - require("nui.popup") - require("mason-null-ls.settings") -- Avoid calling deprecated functions - require("null-ls.helpers") -- Avoid calling deprecated functions - require("plenary") + -- Plugin 'pluginWithRecDeps' and its dependencies are loadable + require("plugin-with-rec-deps") + require("plugin-with-deps-1") + require("plugin-with-deps-2") + require("simple-plugin-1") + require("simple-plugin-2") + -- Plugin 'pluginWithDeps3' and its dependencies are loadable + require("plugin-with-deps-3") + require("simple-plugin-3") ''; assertions = [ { @@ -89,19 +177,15 @@ in { performance.combinePlugins = { enable = true; - # fzf native library is in build directory - pathsToLink = [ "/build" ]; + pathsToLink = [ "/_extra" ]; }; - extraPlugins = [ pkgs.vimPlugins.telescope-fzf-native-nvim ]; + extraPlugins = [ pluginWithExtraFiles ]; extraConfigLuaPost = '' - -- Native library is in runtimepath + -- Test file is in runtime assert( - vim.api.nvim_get_runtime_file("build/libfzf.so", false)[1], - "build/libfzf.so is not found in runtimepath" + vim.api.nvim_get_runtime_file("_extra/test", false)[1], + "'_extra/test' file isn't found in runtime, expected to be found" ) - - -- Native library is loadable - require("fzf_lib") ''; assertions = [ { @@ -116,14 +200,14 @@ in { config, ... }: { performance.combinePlugins.enable = true; - extraPlugins = with pkgs.vimPlugins; [ + extraPlugins = [ # No python3 dependencies - plenary-nvim - # Duplicate python3 dependencies - (nvim-lspconfig.overrideAttrs { passthru.python3Dependencies = ps: [ ps.pyyaml ]; }) - (nvim-treesitter.overrideAttrs { passthru.python3Dependencies = ps: [ ps.pyyaml ]; }) - # Another python3 dependency - (nvim-cmp.overrideAttrs { passthru.python3Dependencies = ps: [ ps.requests ]; }) + simplePlugin1 + # Duplicated python3-pyyaml dependency + pluginWithPyDeps1 + pluginWithPyDeps2 + # Python3-requests dependency + pluginWithPyDeps3 ]; extraConfigLuaPost = '' -- Python modules are importable @@ -143,46 +227,44 @@ in { config, ... }: { performance.combinePlugins.enable = true; - extraPlugins = with pkgs.vimPlugins; [ + extraPlugins = [ # Start plugins - plenary-nvim - nvim-lspconfig + simplePlugin1 + simplePlugin2 # Optional plugin { - plugin = nvim-treesitter; + plugin = simplePlugin3; optional = true; } - # Optional plugin with dependency on plenary-nvim + # Optional plugin with dependency on simplePlugin1 # Dependencies should not be duplicated { - plugin = none-ls-nvim; + plugin = pluginWithDeps1; optional = true; } ]; extraConfigLuaPost = '' -- Start plugins are loadable - require("plenary") - require("lspconfig") + require("simple-plugin-1") + require("simple-plugin-2") -- Opt plugins are not loadable - local ok = pcall(require, "nvim-treesitter") - assert(not ok, "nvim-treesitter plugin is loadable") - ok = pcall(require, "null-ls") - assert(not ok, "null-ls-nvim plugin is loadable") + local ok = pcall(require, "simple-plugin-3") + assert(not ok, "simplePlugin3 is loadable, expected it to be an opt plugin") + ok = pcall(require, "plugin-with-deps-1") + assert(not ok, "pluginWithDeps1 is loadable, expected it to be an opt plugin") -- Load plugins - vim.cmd.packadd("nvim-treesitter") - vim.cmd.packadd("none-ls.nvim") + vim.cmd.packadd("simple-plugin-3") + vim.cmd.packadd("plugin-with-deps-1") -- Now opt plugins are loadable - require("nvim-treesitter") - require("null-ls") + require("simple-plugin-3") + require("plugin-with-deps-1") - -- 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" - ) + -- Only one copy of simplePlugin1 should be available + local num_plugins = #vim.api.nvim_get_runtime_file("lua/simple-plugin-1/init.lua", true) + assert(num_plugins == 1, "expected 1 copy of simplePlugin1, got " .. num_plugins) ''; assertions = [ { @@ -201,35 +283,25 @@ in { config, ... }: { performance.combinePlugins.enable = true; - extraPlugins = with pkgs.vimPlugins; [ + extraPlugins = [ # A plugin without config - plenary-nvim - # Plugins with configs + simplePlugin1 + # Plugin with config { - plugin = nvim-treesitter; - config = "let g:treesitter_config = 1"; - } - { - plugin = nvim-lspconfig; - config = "let g:lspconfig_config = 1"; + plugin = simplePlugin2; + config = "let g:simple_plugin_2 = 1"; } # Optional plugin with config { - plugin = telescope-nvim; + plugin = simplePlugin3; optional = true; - config = "let g:telescope_config = 1"; + config = "let g:simple_plugin_3 = 1"; } ]; extraConfigLuaPost = '' - -- Plugins are loadable - require("plenary") - require("nvim-treesitter") - require("lspconfig") - -- Configs are evaluated - assert(vim.g.treesitter_config == 1, "nvim-treesitter config isn't evaluated") - assert(vim.g.lspconfig_config == 1, "nvim-lspconfig config isn't evaluated") - assert(vim.g.telescope_config == 1, "telescope-nvim config isn't evaluated") + assert(vim.g.simple_plugin_2 == 1, "simplePlugin2's config isn't evaluated") + assert(vim.g.simple_plugin_3 == 1, "simplePlugin3's config isn't evaluated") ''; assertions = [ { @@ -244,62 +316,36 @@ in { config, ... }: { performance.combinePlugins.enable = true; - extraPlugins = with pkgs.vimPlugins; [ - nvim-treesitter - vim-nix + extraPlugins = [ + simplePlugin1 + simplePlugin2 ]; - # Ensure that build.extraFiles is added extraPlugins + # Ensure that build.extraFiles is added to extraPlugins wrapRc = true; # Extra user files colliding with plugins extraFiles = { - "ftplugin/nix.vim".text = "let b:test = 1"; - "queries/nix/highlights.scm".text = '' - ;; extends - (comment) @comment - ''; + "lua/simple-plugin-1/init.lua".text = "return 1"; }; # Another form of user files files = { - "ftdetect/nix.vim" = { - autoCmd = [ - { - event = [ - "BufRead" - "BufNewFile" - ]; - pattern = "*.nix"; - command = "setf nix"; - } - ]; + "lua/simple-plugin-2/init.lua" = { + extraConfigLua = "return 1"; }; }; extraConfigLuaPost = '' - local function get_paths(name) - local paths = vim.api.nvim_get_runtime_file(name, true); - return vim.tbl_filter(function(v) - -- Skip paths from neovim runtime - return not v:find("/nvim/runtime/") - end, paths) - end + for _, file in ipairs({"lua/simple-plugin-1/init.lua", "lua/simple-plugin-2/init.lua"}) do + local paths_found = vim.api.nvim_get_runtime_file(file, true) + local num_found = #paths_found - -- Both plugin and user version are available - assert(#get_paths("ftplugin/nix.vim") == 2, "only one version of ftplugin/nix.vim") - assert(#get_paths("ftdetect/nix.vim") == 2, "only one version of ftdetect/nix.vim") - assert(#get_paths("queries/nix/highlights.scm") == 2, "only one version of queries/nix/highlights.scm") + -- Both plugin and user version are available + assert(num_found == 2, "expected exactly 2 versions of '" .. file .. "', got " .. num_found) - -- First found file is from build.extraFiles - assert( - get_paths("ftplugin/nix.vim")[1]:find("${lib.getName config.build.extraFiles}", 1, true), - "first found ftplugin/nix.vim isn't in build.extraFiles runtime path" - ) - assert( - get_paths("queries/nix/highlights.scm")[1]:find("${lib.getName config.build.extraFiles}", 1, true), - "first found queries/nix/highlights.scm isn't in build.extraFiles runtime path" - ) - assert( - get_paths("queries/nix/highlights.scm")[1]:find("${lib.getName config.build.extraFiles}", 1, true), - "first found queries/nix/highlights.scm isn't in build.extraFiles runtime path" - ) + -- First found file is from build.extraFiles + assert( + paths_found[1]:find("${lib.getName config.build.extraFiles}", 1, true), + "expected first found '" .. file .. "' to be from build.extraFiles, got " .. paths_found[1] + ) + end ''; assertions = [ { @@ -315,60 +361,53 @@ in { performance.combinePlugins = { enable = true; - standalonePlugins = with pkgs.vimPlugins; [ + standalonePlugins = [ # By plugin name - "nvim-treesitter" - # By package itself - nvim-lspconfig - # Its dependency, plenary-nvim, not in this list, so will be combined - none-ls-nvim + "simple-plugin-1" + # By package itself. Its dependency, simplePlugin2, not in this list, so will be combined + pluginWithDeps2 # Dependency of other plugin - "nui.nvim" + "simple-plugin-3" ]; }; - extraPlugins = with pkgs.vimPlugins; [ - nvim-treesitter - nvim-lspconfig - none-ls-nvim - # Only its dependency (nui-nvim) won't be combined, but not the plugin itself - noice-nvim - # More plugins - gitsigns-nvim - luasnip + extraPlugins = [ + simplePlugin1 + pluginWithDeps2 + pluginWithDeps3 + pluginWithExtraFiles ]; extraConfigLuaPost = '' - -- Plugins are loadable - require("nvim-treesitter") - require("lspconfig") - require("null-ls") - require("plenary") - require("noice") - require("nui.popup") - require("gitsigns") - require("luasnip") + local tests = { + {"simple-plugin-1", true}, + {"plugin-with-deps-2", true}, + {"simple-plugin-2", false}, + {"plugin-with-deps-3", false}, + {"simple-plugin-3", true}, + {"plugin-with-extra-files", false}, + } + for _, test in ipairs(tests) do + local name = test[1] + local expected_standalone = test[2] - -- Verify if plugin is standalone or combined - local function is_standalone(name, dirname) - local paths = vim.api.nvim_get_runtime_file("lua/" .. name, true); - assert(#paths == 1, "more than one copy of " .. name .. " in runtime") - return paths[1]:match("^(.+)/lua/"):find(dirname or name, 1, true) ~= nil - end + -- Plugin is loadable + require(test[1]) - -- Standalone plugins - assert(is_standalone("nvim-treesitter"), "nvim-treesitter is combined, expected standalone") - assert(is_standalone("lspconfig"), "nvim-lspconfig is combined, expected standalone") - assert(is_standalone("null-ls", "none-ls.nvim"), "none-ls-nvim is combined, expected standalone") - assert(is_standalone("nui"), "nui-nvim is combined, expected standalone") - -- Combined plugins - assert(not is_standalone("plenary"), "plenary-nvim is standalone, expected combined") - assert(not is_standalone("noice"), "noice-nvim is standalone, expected combined") - assert(not is_standalone("gitsigns"), "gitsigns-nvim is standalone, expected combined") - assert(not is_standalone("luasnip"), "luasnip is standalone, expected combined") + local paths = vim.api.nvim_get_runtime_file("lua/" .. name, true) + -- Plugins shouldn't be duplicated + assert(#paths == 1, "expected exactly 1 copy of '" .. name .. "' in runtime, got ", #paths) + -- Test if plugin is standalone. This matches directory name before '/lua/'. + local is_standalone = paths[1]:match("^(.+)/lua/"):find(name, 1, true) ~= nil + local expected_text = expected_standalone and "standalone" or "combined" + assert( + is_standalone == expected_standalone, + "expected '" .. name .. "' to be " .. expected_text .. ", found path: " .. paths[1] + ) + end ''; assertions = [ { - # plugin-pack, nvim-treesitter, nvim-lspconfig, none-ls-nvim, nui-nvim - assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 5; + # plugin-pack, simplePlugin1, pluginWithDeps2, simplePlugin3 + assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 4; message = "Wrong number of plugins in packpathDirs"; } ]; From f28d384ab5729647764b740680c5b54629eed50f Mon Sep 17 00:00:00 2001 From: Stanislav Asunkin <1353637+stasjok@users.noreply.github.com> Date: Sun, 27 Apr 2025 22:13:46 +0300 Subject: [PATCH 6/7] modules/performance/combine-plugins: propagate lua dependencies Plugins from luarocks (e.g. telescope-nvim) have dependencies specified in propagatedBuildInputs. These dependencies are not added as plugins in Nvim runtime. They are added to LUA_PATH env var for wrapped neovim. This commit collects all propagatedBuildInputs from input plugin list and puts them in the combined plugin. Note that such dependencies are never combined, because they are not plugins. --- modules/top-level/plugins/mk-plugin-pack.nix | 46 ++++++++++++------- .../modules/performance/combine-plugins.nix | 40 ++++++++++++++++ 2 files changed, 70 insertions(+), 16 deletions(-) diff --git a/modules/top-level/plugins/mk-plugin-pack.nix b/modules/top-level/plugins/mk-plugin-pack.nix index 6bb7adc297..e0f6e8b391 100644 --- a/modules/top-level/plugins/mk-plugin-pack.nix +++ b/modules/top-level/plugins/mk-plugin-pack.nix @@ -28,24 +28,38 @@ let (builtins.concatMap (f: f ps)) ]; + # propagatedBuildInputs contain lua dependencies + propagatedBuildInputs = lib.pipe pluginsToCombine [ + (builtins.catAttrs "plugin") + (builtins.catAttrs "propagatedBuildInputs") + builtins.concatLists + lib.unique + ]; + # Combined plugin - combinedPlugin = pkgs.vimUtils.toVimPlugin ( - pkgs.buildEnv { - name = "plugin-pack"; - paths = overriddenPlugins; - inherit pathsToLink; + combinedPlugin = + lib.pipe + { + name = "plugin-pack"; + paths = overriddenPlugins; + inherit pathsToLink; - # Remove empty directories and activate vimGenDocHook - # TODO: figure out why we are running the `preFixup` hook in `postBuild` - postBuild = '' - find $out -type d -empty -delete - runHook preFixup - ''; - passthru = { - inherit python3Dependencies; - }; - } - ); + # buildEnv uses runCommand under the hood. runCommand doesn't run any build phases. + # To run custom commands buildEnv takes postBuild argument. + # fixupPhase is used for propagating build inputs and to trigger vimGenDocHook + postBuild = '' + find $out -type d -empty -delete + fixupPhase + ''; + passthru = { + inherit python3Dependencies; + }; + } + [ + pkgs.buildEnv + pkgs.vimUtils.toVimPlugin + (drv: drv.overrideAttrs { inherit propagatedBuildInputs; }) + ]; # Combined plugin configs combinedConfig = lib.pipe pluginsToCombine [ diff --git a/tests/test-sources/modules/performance/combine-plugins.nix b/tests/test-sources/modules/performance/combine-plugins.nix index ad8eb840e7..58024b3fef 100644 --- a/tests/test-sources/modules/performance/combine-plugins.nix +++ b/tests/test-sources/modules/performance/combine-plugins.nix @@ -69,6 +69,17 @@ let pluginWithPyDeps3 = mkPlugin "plugin-with-py-deps-3" { passthru.python3Dependencies = ps: [ ps.requests ]; }; + # Plugins with Lua dependencies + ensureDep = + drv: dep: + drv.overrideAttrs (prev: { + propagatedBuildInputs = lib.unique ( + prev.propagatedBuildInputs or [ ] ++ [ prev.passthru.lua.pkgs.${dep} ] + ); + }); + pluginWithLuaDeps1 = ensureDep pkgs.vimPlugins.telescope-nvim "plenary-nvim"; + pluginWithLuaDeps2 = ensureDep pkgs.vimPlugins.nvim-cmp "plenary-nvim"; + pluginWithLuaDeps3 = ensureDep pkgs.vimPlugins.gitsigns-nvim "nui-nvim"; in { # Test basic functionality @@ -222,6 +233,35 @@ in ]; }; + # Test that plugin lua dependencies are handled + lua-dependencies = + { config, ... }: + { + performance.combinePlugins.enable = true; + extraPlugins = [ + simplePlugin1 + # Duplicated plenary-nvim dependency + pluginWithLuaDeps1 + pluginWithLuaDeps2 + # nui-nvim dependency + pluginWithLuaDeps3 + ]; + extraConfigLuaPost = '' + -- All packages and its dependencies are importable + require("telescope") + require("plenary") + require("cmp") + require("gitsigns") + require("nui.popup") + ''; + assertions = [ + { + assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 1; + message = "More than one plugin is defined in packpathDirs."; + } + ]; + }; + # Test that optional plugins are handled optional-plugins = { config, ... }: From 6415ae4a9779286b4248a2dd2ed742d96f74bbbf Mon Sep 17 00:00:00 2001 From: Stanislav Asunkin <1353637+stasjok@users.noreply.github.com> Date: Mon, 28 Apr 2025 16:59:09 +0300 Subject: [PATCH 7/7] tests/modules/performance/combine-plugins: improve assertion messages This commit eliminates assertions boilerplate and improves assertion message by returning the number of plugins and their names. --- .../modules/performance/combine-plugins.nix | 80 +++++++------------ 1 file changed, 31 insertions(+), 49 deletions(-) diff --git a/tests/test-sources/modules/performance/combine-plugins.nix b/tests/test-sources/modules/performance/combine-plugins.nix index 58024b3fef..fe0c3c4674 100644 --- a/tests/test-sources/modules/performance/combine-plugins.nix +++ b/tests/test-sources/modules/performance/combine-plugins.nix @@ -2,10 +2,24 @@ let inherit (pkgs) lib; - # Count plugins of given type excluding 'build.extraFiles' - pluginCount = - pkg: files: type: - builtins.length (builtins.filter (p: p != files) pkg.packpathDirs.myNeovimPackages.${type}); + # Assertion for a number of plugins of given type defined in nvimPackage.packpathDirs + expectNPlugins = + config: type: n: + let + # 'build.extraFiles' must not be combined, so exclude it from counting + plugins = builtins.filter ( + p: p != config.build.extraFiles + ) config.build.nvimPackage.packpathDirs.myNeovimPackages.${type}; + numPlugins = builtins.length plugins; + in + { + assertion = numPlugins == n; + message = "Expected ${toString n} '${type}' plugins defined in 'nvimPackage.packpathDirs', got ${toString numPlugins}: ${ + lib.concatMapStringsSep ", " lib.getName plugins + }."; + }; + # Assertion that exactly one start plugin is defined in nvimPackage.packpathDirs + expectOneStartPlugin = config: expectNPlugins config "start" 1; # Stub plugins mkPlugin = @@ -111,10 +125,7 @@ in assert(vim.fn.getcompletion("${name}", "help")[1], "no help tags for '${name}'") '') (map lib.getName extraPlugins); assertions = [ - { - assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 1; - message = "More than one plugin is defined in packpathDirs, expected one plugin pack."; - } + (expectOneStartPlugin config) ]; }; @@ -141,10 +152,7 @@ in end), "plugin '${name}' isn't found in runtime as a separate entry, expected not to be combined") '') (map lib.getName extraPlugins); assertions = [ - { - assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" >= 2; - message = "Only one plugin is defined in packpathDirs, expected at least two."; - } + (expectNPlugins config "start" (builtins.length extraPlugins)) ]; }; @@ -175,10 +183,7 @@ in require("simple-plugin-3") ''; assertions = [ - { - assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 1; - message = "More than one plugin is defined in packpathDirs."; - } + (expectOneStartPlugin config) ]; }; @@ -199,10 +204,7 @@ in ) ''; assertions = [ - { - assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 1; - message = "More than one plugin is defined in packpathDirs."; - } + (expectOneStartPlugin config) ]; }; @@ -226,10 +228,7 @@ in vim.cmd.py3("import requests") ''; assertions = [ - { - assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 1; - message = "More than one plugin is defined in packpathDirs."; - } + (expectOneStartPlugin config) ]; }; @@ -255,10 +254,7 @@ in require("nui.popup") ''; assertions = [ - { - assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 1; - message = "More than one plugin is defined in packpathDirs."; - } + (expectOneStartPlugin config) ]; }; @@ -307,14 +303,9 @@ in assert(num_plugins == 1, "expected 1 copy of simplePlugin1, got " .. num_plugins) ''; assertions = [ - { - assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 1; - message = "More than one start plugin is defined in packpathDirs"; - } - { - assertion = pluginCount config.build.nvimPackage config.build.extraFiles "opt" == 2; - message = "Less than two opt plugins are defined in packpathDirs"; - } + (expectOneStartPlugin config) + # simplePlugin3 pluginWithDeps1 + (expectNPlugins config "opt" 2) ]; }; @@ -344,10 +335,7 @@ in assert(vim.g.simple_plugin_3 == 1, "simplePlugin3's config isn't evaluated") ''; assertions = [ - { - assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 1; - message = "More than one start plugin is defined in packpathDirs"; - } + (expectOneStartPlugin config) ]; }; @@ -388,10 +376,7 @@ in end ''; assertions = [ - { - assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 1; - message = "More than one start plugin is defined in packpathDirs"; - } + (expectOneStartPlugin config) ]; }; @@ -445,11 +430,8 @@ in end ''; assertions = [ - { - # plugin-pack, simplePlugin1, pluginWithDeps2, simplePlugin3 - assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 4; - message = "Wrong number of plugins in packpathDirs"; - } + # plugin-pack, simplePlugin1, pluginWithDeps2, simplePlugin3 + (expectNPlugins config "start" 4) ]; };