Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
at devShellTools-shell 378 lines 13 kB view raw
1{ 2 stdenv, 3 lib, 4 makeWrapper, 5 bundlerEnv, 6 ruby, 7 nodejs, 8 writeText, 9 neovim-node-client, 10 python3, 11 callPackage, 12 neovimUtils, 13 perl, 14 lndir, 15 vimUtils, 16}: 17 18neovim-unwrapped: 19 20let 21 # inherit interpreter from neovim 22 lua = neovim-unwrapped.lua; 23 24 wrapper = 25 { 26 extraName ? "", 27 # certain plugins need a custom configuration (available in passthru.initLua) 28 # to work with nix. 29 # if true, the wrapper automatically appends those snippets when necessary 30 autoconfigure ? true, 31 32 # append to PATH runtime deps of plugins 33 autowrapRuntimeDeps ? true, 34 35 # should contain all args but the binary. Can be either a string or list 36 wrapperArgs ? [ ], 37 withPython2 ? false, 38 withPython3 ? true, 39 # the function you would have passed to python3.withPackages 40 extraPython3Packages ? (_: [ ]), 41 42 withNodeJs ? false, 43 withPerl ? false, 44 withRuby ? true, 45 46 # wether to create symlinks in $out/bin/vi(m) -> $out/bin/nvim 47 vimAlias ? false, 48 viAlias ? false, 49 50 # additional argument not generated by makeNeovimConfig 51 # it sets the VIMINIT environment variable to "lua dofile('${customRc}')" 52 # set to false if you want to control where to save the generated config 53 # (e.g., in ~/.config/init.vim or project/.nvimrc) 54 wrapRc ? true, 55 # vimL code that should be sourced as part of the generated init.lua file 56 neovimRcContent ? null, 57 # lua code to put into the generated init.lua file 58 luaRcContent ? "", 59 # DEPRECATED: entry to load in packpath 60 # use 'plugins' instead 61 packpathDirs ? null, # not used anymore 62 63 # a list of neovim plugin derivations, for instance 64 # plugins = [ 65 # { plugin=far-vim; config = "let g:far#source='rg'"; optional = false; } 66 # ] 67 plugins ? [ ], 68 ... 69 }@attrs: 70 assert 71 withPython2 72 -> throw "Python2 support has been removed from the neovim wrapper, please remove withPython2 and python2Env."; 73 74 assert 75 packpathDirs != null 76 -> throw "packpathdirs is not used anymore: pass a list of neovim plugin derivations in 'plugins' instead."; 77 78 stdenv.mkDerivation ( 79 finalAttrs: 80 let 81 pluginsNormalized = neovimUtils.normalizePlugins finalAttrs.plugins; 82 83 myVimPackage = neovimUtils.normalizedPluginsToVimPackage pluginsNormalized; 84 85 rubyEnv = bundlerEnv { 86 name = "neovim-ruby-env"; 87 gemdir = ./ruby_provider; 88 postBuild = '' 89 ln -sf ${ruby}/bin/* $out/bin 90 ''; 91 }; 92 93 pluginRC = lib.foldl ( 94 acc: p: if p.config != null then acc ++ [ p.config ] else acc 95 ) [ ] pluginsNormalized; 96 97 # a limited RC script used only to generate the manifest for remote plugins 98 manifestRc = ""; 99 # we call vimrcContent without 'packages' to avoid the init.vim generation 100 neovimRcContent' = lib.concatStringsSep "\n" ( 101 pluginRC ++ lib.optional (neovimRcContent != null) neovimRcContent 102 ); 103 104 packpathDirs.myNeovimPackages = myVimPackage; 105 finalPackdir = neovimUtils.packDir packpathDirs; 106 107 luaPluginRC = 108 let 109 op = 110 acc: normalizedPlugin: 111 acc 112 ++ lib.optional ( 113 finalAttrs.autoconfigure && normalizedPlugin.plugin.passthru ? initLua 114 ) normalizedPlugin.plugin.passthru.initLua; 115 in 116 lib.foldl' op [ ] pluginsNormalized; 117 118 rcContent = '' 119 ${luaRcContent} 120 '' 121 + lib.optionalString (neovimRcContent' != "") '' 122 vim.cmd.source "${writeText "init.vim" neovimRcContent'}" 123 '' 124 + lib.concatStringsSep "\n" luaPluginRC; 125 126 getDeps = attrname: map (plugin: plugin.${attrname} or (_: [ ])); 127 128 requiredPlugins = vimUtils.requiredPluginsForPackage myVimPackage; 129 pluginPython3Packages = getDeps "python3Dependencies" requiredPlugins; 130 131 python3Env = 132 lib.warnIf (attrs ? python3Env) 133 "Pass your python packages via the `extraPython3Packages`, e.g., `extraPython3Packages = ps: [ ps.pandas ]`" 134 python3.pkgs.python.withPackages 135 (ps: [ ps.pynvim ] ++ (extraPython3Packages ps) ++ (lib.concatMap (f: f ps) pluginPython3Packages)); 136 137 wrapperArgsStr = if lib.isString wrapperArgs then wrapperArgs else lib.escapeShellArgs wrapperArgs; 138 139 generatedWrapperArgs = [ 140 # vim accepts a limited number of commands so we join all the provider ones 141 "--add-flags" 142 ''--cmd "lua ${providerLuaRc}"'' 143 ] 144 ++ 145 lib.optionals 146 ( 147 finalAttrs.packpathDirs.myNeovimPackages.start != [ ] 148 || finalAttrs.packpathDirs.myNeovimPackages.opt != [ ] 149 ) 150 [ 151 "--add-flags" 152 ''--cmd "set packpath^=${finalPackdir}"'' 153 "--add-flags" 154 ''--cmd "set rtp^=${finalPackdir}"'' 155 ] 156 ++ lib.optionals finalAttrs.withRuby [ 157 "--set" 158 "GEM_HOME" 159 "${rubyEnv}/${rubyEnv.ruby.gemPath}" 160 ] 161 ++ lib.optionals (finalAttrs.runtimeDeps != [ ]) [ 162 "--suffix" 163 "PATH" 164 ":" 165 (lib.makeBinPath finalAttrs.runtimeDeps) 166 ]; 167 168 providerLuaRc = neovimUtils.generateProviderRc { 169 inherit (finalAttrs) 170 withPython3 171 withNodeJs 172 withPerl 173 withRuby 174 ; 175 }; 176 177 # If `configure` != {}, we can't generate the rplugin.vim file with e.g 178 # NVIM_SYSTEM_RPLUGIN_MANIFEST *and* NVIM_RPLUGIN_MANIFEST env vars set in 179 # the wrapper. That's why only when `configure` != {} (tested both here and 180 # when `postBuild` is evaluated), we call makeWrapper once to generate a 181 # wrapper with most arguments we need, excluding those that cause problems to 182 # generate rplugin.vim, but still required for the final wrapper. 183 finalMakeWrapperArgs = [ 184 "${neovim-unwrapped}/bin/nvim" 185 "${placeholder "out"}/bin/nvim" 186 ] 187 ++ [ 188 "--set" 189 "NVIM_SYSTEM_RPLUGIN_MANIFEST" 190 "${placeholder "out"}/rplugin.vim" 191 ] 192 ++ lib.optionals finalAttrs.wrapRc [ 193 "--set-default" 194 "VIMINIT" 195 "lua dofile('${writeText "init.lua" rcContent}')" 196 ] 197 ++ finalAttrs.generatedWrapperArgs; 198 199 perlEnv = perl.withPackages (p: [ 200 p.NeovimExt 201 p.Appcpanminus 202 ]); 203 204 pname = "neovim"; 205 version = lib.getVersion neovim-unwrapped; 206 in 207 { 208 name = "${pname}-${version}${extraName}"; 209 inherit pname version; 210 inherit plugins; 211 212 __structuredAttrs = true; 213 dontUnpack = true; 214 inherit 215 viAlias 216 vimAlias 217 withNodeJs 218 withPython3 219 withPerl 220 withRuby 221 ; 222 inherit 223 autoconfigure 224 autowrapRuntimeDeps 225 wrapRc 226 providerLuaRc 227 packpathDirs 228 ; 229 inherit python3Env rubyEnv; 230 inherit wrapperArgs generatedWrapperArgs; 231 232 runtimeDeps = 233 let 234 op = acc: normalizedPlugin: acc ++ normalizedPlugin.plugin.runtimeDeps or [ ]; 235 runtimeDeps = lib.foldl' op [ ] pluginsNormalized; 236 in 237 lib.optional finalAttrs.withRuby rubyEnv 238 ++ lib.optional finalAttrs.withNodeJs nodejs 239 ++ lib.optionals finalAttrs.autowrapRuntimeDeps runtimeDeps; 240 241 luaRcContent = rcContent; 242 # Remove the symlinks created by symlinkJoin which we need to perform 243 # extra actions upon 244 postBuild = 245 lib.optionalString stdenv.hostPlatform.isLinux '' 246 rm $out/share/applications/nvim.desktop 247 substitute ${neovim-unwrapped}/share/applications/nvim.desktop $out/share/applications/nvim.desktop \ 248 --replace-warn 'Name=Neovim' 'Name=Neovim wrapper' 249 '' 250 + lib.optionalString finalAttrs.withPython3 '' 251 makeWrapper ${python3Env.interpreter} $out/bin/nvim-python3 --unset PYTHONPATH --unset PYTHONSAFEPATH 252 '' 253 + lib.optionalString (finalAttrs.withRuby) '' 254 ln -s ${finalAttrs.rubyEnv}/bin/neovim-ruby-host $out/bin/nvim-ruby 255 '' 256 + lib.optionalString finalAttrs.withNodeJs '' 257 ln -s ${neovim-node-client}/bin/neovim-node-host $out/bin/nvim-node 258 '' 259 + lib.optionalString finalAttrs.withPerl '' 260 ln -s ${perlEnv}/bin/perl $out/bin/nvim-perl 261 '' 262 + lib.optionalString finalAttrs.vimAlias '' 263 ln -s $out/bin/nvim $out/bin/vim 264 '' 265 + lib.optionalString finalAttrs.viAlias '' 266 ln -s $out/bin/nvim $out/bin/vi 267 '' 268 + lib.optionalString (manifestRc != null) ( 269 let 270 manifestWrapperArgs = [ 271 "${neovim-unwrapped}/bin/nvim" 272 "${placeholder "out"}/bin/nvim-wrapper" 273 ] 274 ++ finalAttrs.generatedWrapperArgs; 275 in 276 '' 277 echo "Generating remote plugin manifest" 278 export NVIM_RPLUGIN_MANIFEST=$out/rplugin.vim 279 makeWrapper ${lib.escapeShellArgs manifestWrapperArgs} ${wrapperArgsStr} 280 281 # Some plugins assume that the home directory is accessible for 282 # initializing caches, temporary files, etc. Even if the plugin isn't 283 # actively used, it may throw an error as soon as Neovim is launched 284 # (e.g., inside an autoload script), causing manifest generation to 285 # fail. Therefore, let's create a fake home directory before generating 286 # the manifest, just to satisfy the needs of these plugins. 287 # 288 # See https://github.com/Yggdroot/LeaderF/blob/v1.21/autoload/lfMru.vim#L10 289 # for an example of this behavior. 290 export HOME="$(mktemp -d)" 291 # Launch neovim with a vimrc file containing only the generated plugin 292 # code. Pass various flags to disable temp file generation 293 # (swap/viminfo) and redirect errors to stderr. 294 # Only display the log on error since it will contain a few normally 295 # irrelevant messages. 296 if ! $out/bin/nvim-wrapper \ 297 -u ${writeText "manifest.vim" manifestRc} \ 298 -i NONE -n \ 299 -V1rplugins.log \ 300 +UpdateRemotePlugins +quit! > outfile 2>&1; then 301 cat outfile 302 echo -e "\nGenerating rplugin.vim failed!" 303 exit 1 304 fi 305 rm "${placeholder "out"}/bin/nvim-wrapper" 306 '' 307 ) 308 + '' 309 rm $out/bin/nvim 310 touch $out/rplugin.vim 311 312 echo "Looking for lua dependencies..." 313 source ${lua}/nix-support/utils.sh 314 315 _addToLuaPath "${finalPackdir}" 316 317 echo "LUA_PATH towards the end of packdir: $LUA_PATH" 318 319 makeWrapper ${lib.escapeShellArgs finalMakeWrapperArgs} ${wrapperArgsStr} \ 320 --prefix LUA_PATH ';' "$LUA_PATH" \ 321 --prefix LUA_CPATH ';' "$LUA_CPATH" 322 ''; 323 324 buildPhase = '' 325 runHook preBuild 326 mkdir -p $out 327 for i in ${neovim-unwrapped}; do 328 lndir -silent $i $out 329 done 330 runHook postBuild 331 ''; 332 333 preferLocalBuild = true; 334 335 nativeBuildInputs = [ 336 makeWrapper 337 lndir 338 ]; 339 340 # A Vim "package", see ':h packages' 341 vimPackage = myVimPackage; 342 343 checkPhase = '' 344 runHook preCheck 345 346 $out/bin/nvim -i NONE -e +quitall! 347 runHook postCheck 348 ''; 349 350 passthru = { 351 inherit providerLuaRc packpathDirs; 352 unwrapped = neovim-unwrapped; 353 initRc = neovimRcContent'; 354 355 tests = callPackage ./tests { 356 }; 357 }; 358 359 meta = { 360 inherit (neovim-unwrapped.meta) 361 description 362 longDescription 363 homepage 364 mainProgram 365 license 366 teams 367 platforms 368 ; 369 370 # To prevent builds on hydra 371 hydraPlatforms = [ ]; 372 # prefer wrapper over the package 373 priority = (neovim-unwrapped.meta.priority or lib.meta.defaultPriority) - 1; 374 }; 375 } 376 ); 377in 378lib.makeOverridable wrapper