diff --git a/pkgs/applications/editors/neovim/utils.nix b/pkgs/applications/editors/neovim/utils.nix index 9f0aa86de48ca8e..4b478850b0ac166 100644 --- a/pkgs/applications/editors/neovim/utils.nix +++ b/pkgs/applications/editors/neovim/utils.nix @@ -13,113 +13,45 @@ let inherit (vimUtils) toVimPlugin; - /* returns everything needed for the caller to wrap its own neovim: - - the generated content of the future init.vim - - the arguments to wrap neovim with - The caller is responsible for writing the init.vim and adding it to the wrapped - arguments (["-u" writeText "init.vim" GENERATEDRC)]). - This makes it possible to write the config anywhere: on a per-project basis - .nvimrc or in $XDG_CONFIG_HOME/nvim/init.vim to avoid sideeffects. - Indeed, note that wrapping with `-u init.vim` has sideeffects like .nvimrc wont be loaded - anymore, $MYVIMRC wont be set etc - */ - makeNeovimConfig = - { withPython3 ? true - /* the function you would have passed to python3.withPackages */ - , extraPython3Packages ? (_: [ ]) - , withNodeJs ? false - , withRuby ? true - /* the function you would have passed to lua.withPackages */ - , extraLuaPackages ? (_: [ ]) - - # expects a list of plugin configuration - # expects { plugin=far-vim; config = "let g:far#source='rg'"; optional = false; } - , plugins ? [] - # custom viml config appended after plugin-specific config - , customRC ? "" - - # for forward compability, when adding new environments, haskell etc. - , ... - }@args: - let - rubyEnv = bundlerEnv { - name = "neovim-ruby-env"; - gemdir = ./ruby_provider; - postBuild = '' - ln -sf ${ruby}/bin/* $out/bin - ''; - }; - - # transform all plugins into an attrset - # { optional = bool; plugin = package; } - pluginsNormalized = let + /* transform all plugins into an attrset + { optional = bool; plugin = package; } + */ + normalizePlugins = plugins: + let defaultPlugin = { plugin = null; config = null; optional = false; }; in + # TODO use (coercedTo package (v: { plugin = v; }) pluginWithConfigType); map (x: defaultPlugin // (if (x ? plugin) then x else { plugin = x; })) plugins; - pluginRC = lib.foldl (acc: p: if p.config != null then acc ++ [p.config] else acc) [] pluginsNormalized; - pluginsPartitioned = lib.partition (x: x.optional == true) pluginsNormalized; - requiredPlugins = vimUtils.requiredPluginsForPackage myVimPackage; - getDeps = attrname: map (plugin: plugin.${attrname} or (_: [ ])); - myVimPackage = { - start = map (x: x.plugin) pluginsPartitioned.wrong; - opt = map (x: x.plugin) pluginsPartitioned.right; - }; - - pluginPython3Packages = getDeps "python3Dependencies" requiredPlugins; - python3Env = python3Packages.python.withPackages (ps: - [ ps.pynvim ] - ++ (extraPython3Packages ps) - ++ (lib.concatMap (f: f ps) pluginPython3Packages)); - - luaEnv = neovim-unwrapped.lua.withPackages extraLuaPackages; - - # as expected by packdir - packpathDirs.myNeovimPackages = myVimPackage; - ## Here we calculate all of the arguments to the 1st call of `makeWrapper` - # We start with the executable itself NOTE we call this variable "initial" - # because if configure != {} we need to call makeWrapper twice, in order to - # avoid double wrapping, see comment near finalMakeWrapperArgs - makeWrapperArgs = - let - binPath = lib.makeBinPath (lib.optionals withRuby [ rubyEnv ] ++ lib.optionals withNodeJs [ nodejs ]); - in - [ - "--inherit-argv0" - ] ++ lib.optionals withRuby [ - "--set" "GEM_HOME" "${rubyEnv}/${rubyEnv.ruby.gemPath}" - ] ++ lib.optionals (binPath != "") [ - "--suffix" "PATH" ":" binPath - ] ++ lib.optionals (luaEnv != null) [ - "--prefix" "LUA_PATH" ";" (neovim-unwrapped.lua.pkgs.luaLib.genLuaPathAbsStr luaEnv) - "--prefix" "LUA_CPATH" ";" (neovim-unwrapped.lua.pkgs.luaLib.genLuaCPathAbsStr luaEnv) - ]; - - manifestRc = vimUtils.vimrcContent { customRC = ""; }; - # we call vimrcContent without 'packages' to avoid the init.vim generation - neovimRcContent = vimUtils.vimrcContent { - beforePlugins = ""; - customRC = lib.concatStringsSep "\n" (pluginRC ++ [customRC]); - packages = null; + /* accepts a list of + */ + normalizedPluginsToVimPackage = normalizedPlugins: + let + pluginsPartitioned = lib.partition (x: x.optional == true) normalizedPlugins; + in { + start = map (x: x.plugin) pluginsPartitioned.wrong; + opt = map (x: x.plugin) pluginsPartitioned.right; }; - in - builtins.removeAttrs args ["plugins"] // { - wrapperArgs = makeWrapperArgs; - inherit packpathDirs; - inherit neovimRcContent; - inherit manifestRc; - inherit python3Env; - inherit luaEnv; - inherit withNodeJs; - } // lib.optionalAttrs withRuby { - inherit rubyEnv; - }; + /* returns everything needed for the caller to wrap its own neovim: + - the generated content of the future init.vim + - the arguments to wrap neovim with + The caller is responsible for writing the init.vim and adding it to the wrapped + arguments (["-u" writeText "init.vim" GENERATEDRC)]). + This makes it possible to write the config anywhere: on a per-project basis + .nvimrc or in $XDG_CONFIG_HOME/nvim/init.vim to avoid sideeffects. + Indeed, note that wrapping with `-u init.vim` has sideeffects like .nvimrc wont be loaded + anymore, $MYVIMRC wont be set etc + */ + makeNeovimConfig = { customRC ? "", ...}@attrs: attrs // { + neovimRcContent = customRC; + wrapperArgs = []; # for backwards compat + }; # to keep backwards compatibility for people using neovim.override @@ -198,6 +130,9 @@ let in lib.concatStringsSep ";" hostProviderLua; + /* Converts a lua package into a neovim plugin. + Does so by installing the lua package with a flat hierarchy of folders + */ buildNeovimPlugin = callPackage ./build-neovim-plugin.nix { inherit (vimUtils) toVimPlugin; inherit lua; @@ -275,6 +210,7 @@ in inherit legacyWrapper; inherit grammarToPlugin; inherit packDir; + inherit normalizePlugins normalizedPluginsToVimPackage; inherit buildNeovimPlugin; buildNeovimPluginFrom2Nix = lib.warn "buildNeovimPluginFrom2Nix was renamed to buildNeovimPlugin" buildNeovimPlugin; diff --git a/pkgs/applications/editors/neovim/wrapper.nix b/pkgs/applications/editors/neovim/wrapper.nix index 8bcd1b5ebbd669a..57277ef5d44b3b4 100644 --- a/pkgs/applications/editors/neovim/wrapper.nix +++ b/pkgs/applications/editors/neovim/wrapper.nix @@ -1,4 +1,7 @@ { stdenv, symlinkJoin, lib, makeWrapper +, bundlerEnv +, ruby +, nodejs , writeText , nodePackages , python3 @@ -6,6 +9,7 @@ , neovimUtils , perl , lndir +, vimUtils }: neovim-unwrapped: @@ -19,9 +23,12 @@ let # should contain all args but the binary. Can be either a string or list , wrapperArgs ? [] # a limited RC script used only to generate the manifest for remote plugins - , manifestRc ? null + # , manifestRc ? null , withPython2 ? false - , withPython3 ? true, python3Env ? python3 + , withPython3 ? true + /* the function you would have passed to python3.withPackages */ + , extraPython3Packages ? (_: [ ]) + , withNodeJs ? false , withPerl ? false , rubyEnv ? null @@ -40,22 +47,59 @@ let # lua code to put into the generated init.lua file , luaRcContent ? "" # entry to load in packpath - , packpathDirs + , packpathDirs ? null # not used anymore + , plugins ? [] , ... - }: + }@attrs: assert withPython2 -> throw "Python2 support has been removed from the neovim wrapper, please remove withPython2 and python2Env."; + # assert packpathDirs -> throw "Packpathdirs removed"; + stdenv.mkDerivation (finalAttrs: let + pluginsNormalized = neovimUtils.normalizePlugins plugins; + + myVimPackage = neovimUtils.normalizedPluginsToVimPackage pluginsNormalized; + + rubyEnv = bundlerEnv { + name = "neovim-ruby-env"; + gemdir = ./ruby_provider; + postBuild = '' + ln -sf ${ruby}/bin/* $out/bin + ''; + }; + + pluginRC = lib.foldl (acc: p: if p.config != null then acc ++ [p.config] else acc) [] pluginsNormalized; + + manifestRc = vimUtils.vimrcContent { customRC = ""; }; + # we call vimrcContent without 'packages' to avoid the init.vim generation + neovimRcContent' = vimUtils.vimrcContent { + beforePlugins = ""; + customRC = lib.concatStringsSep "\n" (pluginRC ++ [neovimRcContent]); + packages = null; + }; finalPackdir = neovimUtils.packDir packpathDirs; rcContent = '' ${luaRcContent} - '' + lib.optionalString (!isNull neovimRcContent) '' - vim.cmd.source "${writeText "init.vim" neovimRcContent}" + '' + lib.optionalString (!isNull neovimRcContent') '' + vim.cmd.source "${writeText "init.vim" neovimRcContent'}" ''; + getDeps = attrname: map (plugin: plugin.${attrname} or (_: [ ])); + + requiredPlugins = vimUtils.requiredPluginsForPackage myVimPackage; + pluginPython3Packages = getDeps "python3Dependencies" requiredPlugins; + + python3Env = lib.warnIf (attrs ? python3Env) "Pass your python packages via the `extraPython3Packages`, e.g., `extraPython3Packages = ps: [ ps.pandas ]`" + python3.pkgs.python.withPackages (ps: + [ ps.pynvim ] + ++ (extraPython3Packages ps) + ++ (lib.concatMap (f: f ps) pluginPython3Packages)); + + packpathDirs.myNeovimPackages = myVimPackage; + wrapperArgsStr = if lib.isString wrapperArgs then wrapperArgs else lib.escapeShellArgs wrapperArgs; generatedWrapperArgs = @@ -94,6 +138,7 @@ let in { name = "${pname}-${version}${extraName}"; inherit pname version; + inherit plugins; __structuredAttrs = true; dontUnpack = true; @@ -193,7 +238,7 @@ let passthru = { inherit providerLuaRc packpathDirs; unwrapped = neovim-unwrapped; - initRc = neovimRcContent; + initRc = neovimRcContent'; tests = callPackage ./tests { };