lol

vimPlugins: use lua derivation if it exists (#178180)

Neovim plugins are now more often than not written in lua.
One advantage of the lua ecosystem over vim's is the existence of
luarocks and the rockspec format, which allows to specify a package
dependencies formally.
I would like more neovim plugins to have a formal description,
"rockspec" being the current candidate.
This MR allows to use nix lua packages as neovim plugins, so as to enjoy
every benefit that rockspecs bring:
- dependdency discovery
- ability to run test suite
- luarocks versioning
- rockspec metadata

the vim update.py script will check if an attribute with the vim plugin
pname exists in lua51Packages. If it does, it uses
buildNeovimPluginFrom2Nix on it, which modifies the luarocks config to
do an almost flat install (luarocks will install the package in the lua
folder instead of share/5.1/lua etc).
It also calls toVimPlugin on it to get all the vim plugin niceties.

The list of packages that could benefit from this is available at
https://luarocks.org/labels/neovim
but I hope it grows.

authored by

Matthieu Coudron and committed by
GitHub
ce505a39 849bf88a

+105 -43
+35
pkgs/applications/editors/neovim/build-neovim-plugin.nix
··· 1 + { lib 2 + , stdenv 3 + , buildVimPluginFrom2Nix 4 + , buildLuarocksPackage 5 + , lua51Packages 6 + , toVimPlugin 7 + }: 8 + let 9 + # sanitizeDerivationName 10 + normalizeName = lib.replaceStrings [ "." ] [ "-" ]; 11 + in 12 + 13 + # function to create vim plugin from lua packages that are already packaged in 14 + # luaPackages 15 + { 16 + # the lua attribute name that matches this vim plugin. Both should be equal 17 + # in the majority of cases but we make it possible to have different attribute names 18 + luaAttr ? (normalizeName attrs.pname) 19 + , ... 20 + }@attrs: 21 + let 22 + originalLuaDrv = lua51Packages.${luaAttr}; 23 + luaDrv = lua51Packages.lib.overrideLuarocks originalLuaDrv (drv: { 24 + extraConfig = '' 25 + -- to create a flat hierarchy 26 + lua_modules_path = "lua" 27 + ''; 28 + }); 29 + finalDrv = toVimPlugin (luaDrv.overrideAttrs(oa: { 30 + nativeBuildInputs = oa.nativeBuildInputs or [] ++ [ 31 + lua51Packages.luarocksMoveDataFolder 32 + ]; 33 + })); 34 + in 35 + finalDrv
+7
pkgs/applications/editors/neovim/utils.nix
··· 1 1 { lib 2 + , buildLuarocksPackage 3 + , callPackage 2 4 , vimUtils 3 5 , nodejs 4 6 , neovim-unwrapped ··· 184 186 { 185 187 inherit makeNeovimConfig; 186 188 inherit legacyWrapper; 189 + 190 + buildNeovimPluginFrom2Nix = callPackage ./build-neovim-plugin.nix { 191 + inherit (vimUtils) buildVimPluginFrom2Nix toVimPlugin; 192 + inherit buildLuarocksPackage; 193 + }; 187 194 }
+3 -7
pkgs/applications/editors/vim/plugins/build-vim-plugin.nix
··· 4 4 , vimCommandCheckHook 5 5 , vimGenDocHook 6 6 , neovimRequireCheckHook 7 + , toVimPlugin 7 8 }: 8 9 9 10 rec { ··· 23 24 let drv = stdenv.mkDerivation (attrs // { 24 25 name = namePrefix + name; 25 26 26 - # dont move the doc folder since vim expects it 27 - forceShare= [ "man" "info" ]; 28 - 29 - nativeBuildInputs = attrs.nativeBuildInputs or [] 30 - ++ lib.optionals (stdenv.hostPlatform == stdenv.buildPlatform) [ vimCommandCheckHook vimGenDocHook ]; 31 27 inherit unpackPhase configurePhase buildPhase addonInfo preInstall postInstall; 32 28 33 29 installPhase = '' ··· 40 36 runHook postInstall 41 37 ''; 42 38 }); 43 - in drv.overrideAttrs(oa: { 39 + in toVimPlugin(drv.overrideAttrs(oa: { 44 40 rtp = "${drv}"; 45 - }); 41 + })); 46 42 47 43 buildVimPluginFrom2Nix = attrs: buildVimPlugin ({ 48 44 # vim plugins may override this
+6 -16
pkgs/applications/editors/vim/plugins/default.nix
··· 1 1 # TODO check that no license information gets lost 2 - { callPackage, config, lib, vimUtils, vim, darwin, llvmPackages, luaPackages }: 2 + { callPackage, config, lib, vimUtils, vim, darwin, llvmPackages 3 + , neovimUtils 4 + , luaPackages 5 + }: 3 6 4 7 let 5 8 ··· 8 11 9 12 inherit (lib) extends; 10 13 11 - initialPackages = self: { 12 - # Convert derivation to a vim plugin. 13 - toVimPlugin = drv: 14 - drv.overrideAttrs(oldAttrs: { 15 - 16 - nativeBuildInputs = oldAttrs.nativeBuildInputs or [] ++ [ 17 - vimGenDocHook 18 - vimCommandCheckHook 19 - ]; 20 - passthru = (oldAttrs.passthru or {}) // { 21 - vimPlugin = true; 22 - }; 23 - }); 24 - }; 14 + initialPackages = self: { }; 25 15 26 16 plugins = callPackage ./generated.nix { 27 17 inherit buildVimPluginFrom2Nix; 28 - inherit (vimUtils) buildNeovimPluginFrom2Nix; 18 + inherit (neovimUtils) buildNeovimPluginFrom2Nix; 29 19 }; 30 20 31 21 # TL;DR
+4 -4
pkgs/applications/editors/vim/plugins/generated.nix
··· 2527 2527 meta.homepage = "https://github.com/nvim-lua/diagnostic-nvim/"; 2528 2528 }; 2529 2529 2530 - diffview-nvim = buildNeovimPluginFrom2Nix { 2530 + diffview-nvim = buildVimPluginFrom2Nix { 2531 2531 pname = "diffview.nvim"; 2532 2532 version = "2022-06-09"; 2533 2533 src = fetchFromGitHub { ··· 3154 3154 meta.homepage = "https://github.com/ruifm/gitlinker.nvim/"; 3155 3155 }; 3156 3156 3157 - gitsigns-nvim = buildNeovimPluginFrom2Nix { 3157 + gitsigns-nvim = buildVimPluginFrom2Nix { 3158 3158 pname = "gitsigns.nvim"; 3159 3159 version = "2022-05-26"; 3160 3160 src = fetchFromGitHub { ··· 4282 4282 meta.homepage = "https://github.com/iamcco/markdown-preview.nvim/"; 4283 4283 }; 4284 4284 4285 - marks-nvim = buildNeovimPluginFrom2Nix { 4285 + marks-nvim = buildVimPluginFrom2Nix { 4286 4286 pname = "marks.nvim"; 4287 4287 version = "2022-05-13"; 4288 4288 src = fetchFromGitHub { ··· 5110 5110 meta.homepage = "https://github.com/RRethy/nvim-base16/"; 5111 5111 }; 5112 5112 5113 - nvim-biscuits = buildNeovimPluginFrom2Nix { 5113 + nvim-biscuits = buildVimPluginFrom2Nix { 5114 5114 pname = "nvim-biscuits"; 5115 5115 version = "2022-05-31"; 5116 5116 src = fetchFromGitHub {
+23 -14
pkgs/applications/editors/vim/plugins/vim-utils.nix
··· 205 205 ln -sf ${plugin}/${rtpPath} $out/pack/${packageName}/${dir}/${lib.getName plugin} 206 206 ''; 207 207 208 - link = pluginPath: if hasLuaModule pluginPath 209 - then linkLuaPlugin pluginPath 210 - else linkVimlPlugin pluginPath; 211 208 212 209 packageLinks = packageName: {start ? [], opt ? []}: 213 210 let ··· 225 222 [ "mkdir -p $out/pack/${packageName}/start" ] 226 223 # To avoid confusion, even dependencies of optional plugins are added 227 224 # to `start` (except if they are explicitly listed as optional plugins). 228 - ++ (builtins.map (x: link x packageName "start") allPlugins) 225 + ++ (builtins.map (x: linkVimlPlugin x packageName "start") allPlugins) 229 226 ++ ["mkdir -p $out/pack/${packageName}/opt"] 230 - ++ (builtins.map (x: link x packageName "opt") opt) 227 + ++ (builtins.map (x: linkVimlPlugin x packageName "opt") opt) 231 228 # Assemble all python3 dependencies into a single `site-packages` to avoid doing recursive dependency collection 232 229 # for each plugin. 233 230 # This directory is only for python import search path, and will not slow down the startup time. ··· 290 287 /* vim-plug is an extremely popular vim plugin manager. 291 288 */ 292 289 plugImpl = 293 - ('' 290 + '' 294 291 source ${vimPlugins.vim-plug.rtp}/plug.vim 295 292 silent! call plug#begin('/dev/null') 296 293 297 294 '' + (lib.concatMapStringsSep "\n" (pkg: "Plug '${pkg.rtp}'") plug.plugins) + '' 298 295 299 296 call plug#end() 300 - ''); 297 + ''; 301 298 302 299 /* 303 300 vim-addon-manager = VAM ··· 533 530 } ./neovim-require-check-hook.sh) {}; 534 531 535 532 inherit (import ./build-vim-plugin.nix { 536 - inherit lib stdenv rtpPath vim vimGenDocHook vimCommandCheckHook neovimRequireCheckHook; 533 + inherit lib stdenv rtpPath vim vimGenDocHook 534 + toVimPlugin vimCommandCheckHook neovimRequireCheckHook; 537 535 }) buildVimPlugin buildVimPluginFrom2Nix; 538 536 539 - 540 - # TODO placeholder to ease working on automatic plugin detection 541 - # this should be a luarocks "flat" install with appropriate vim hooks 542 - buildNeovimPluginFrom2Nix = attrs: let drv = (buildVimPluginFrom2Nix attrs); in drv.overrideAttrs(oa: { 543 - nativeBuildInputs = oa.nativeBuildInputs ++ [ neovimRequireCheckHook ]; 544 - }); 545 537 546 538 # used to figure out which python dependencies etc. neovim needs 547 539 requiredPlugins = { ··· 566 558 nativePlugins = lib.concatMap ({start?[], opt?[], knownPlugins?vimPlugins}: start++opt) nativePluginsConfigs; 567 559 in 568 560 nativePlugins ++ nonNativePlugins; 561 + 562 + toVimPlugin = drv: 563 + drv.overrideAttrs(oldAttrs: { 564 + # dont move the "doc" folder since vim expects it 565 + forceShare = [ "man" "info" ]; 566 + 567 + nativeBuildInputs = oldAttrs.nativeBuildInputs or [] 568 + ++ lib.optionals (stdenv.hostPlatform == stdenv.buildPlatform) [ 569 + vimCommandCheckHook vimGenDocHook 570 + # many neovim plugins keep using buildVimPlugin 571 + neovimRequireCheckHook 572 + ]; 573 + 574 + passthru = (oldAttrs.passthru or {}) // { 575 + vimPlugin = true; 576 + }; 577 + }); 569 578 }
+8
pkgs/development/interpreters/lua-5/hooks/default.nix
··· 29 29 name = "luarocks-check-hook"; 30 30 deps = [ luarocks ]; 31 31 } ./luarocks-check-hook.sh) {}; 32 + 33 + # luarocks installs data in a non-overridable location. Until a proper luarocks patch, 34 + # we move the files around ourselves 35 + luarocksMoveDataFolder = callPackage ({ }: 36 + makeSetupHook { 37 + name = "luarocks-move-rock"; 38 + deps = [ ]; 39 + } ./luarocks-move-data.sh) {}; 32 40 }
+15
pkgs/development/interpreters/lua-5/hooks/luarocks-move-data.sh
··· 1 + # luarocks installs data in a non-overridable location. Until a proper luarocks patch, 2 + # we move the files around ourselves 3 + echo "Sourcing luarocks-move-data-hook.sh" 4 + 5 + luarocksMoveDataHook () { 6 + echo "Executing luarocksMoveDataHook" 7 + if [ -d "$out/$rocksSubdir" ]; then 8 + cp -rfv "$out/$rocksSubdir/$pname/$version/." "$out" 9 + fi 10 + 11 + echo "Finished executing luarocksMoveDataHook" 12 + } 13 + 14 + echo "Using luarocksMoveDataHook" 15 + preDistPhases+=" luarocksMoveDataHook"
+3 -1
pkgs/top-level/all-packages.nix
··· 30449 30449 lua = luajit; 30450 30450 }; 30451 30451 30452 - neovimUtils = callPackage ../applications/editors/neovim/utils.nix { }; 30452 + neovimUtils = callPackage ../applications/editors/neovim/utils.nix { 30453 + inherit (lua51Packages) buildLuarocksPackage; 30454 + }; 30453 30455 neovim = wrapNeovim neovim-unwrapped { }; 30454 30456 30455 30457 neovim-qt-unwrapped = libsForQt5.callPackage ../applications/editors/neovim/neovim-qt.nix { };
+1 -1
pkgs/top-level/lua-packages.nix
··· 50 50 getLuaCPath = drv: getPath drv luaLib.luaCPathList; 51 51 52 52 inherit (callPackage ../development/interpreters/lua-5/hooks { inherit (args) lib;}) 53 - luarocksCheckHook lua-setup-hook; 53 + luarocksMoveDataFolder luarocksCheckHook lua-setup-hook; 54 54 55 55 inherit lua callPackage; 56 56 inherit buildLuaPackage buildLuarocksPackage buildLuaApplication;