Introduction

Envy is a framework for Nix/Vim integration, providing:

  • A convenient way to pin and package Vim plugins as Nix derivations.
  • The ability for Vim plugin derivations to correctly depend on and pull in one another, and system dependencies (including plugin-native-language dependencies, C library dependencies, and executable dependencies).
  • A Nix-based configuration mechanism that allows individual plugin configuration to depend on the install-time state of other plugins, dependencies, and potentially the system (in NixOS).
  • A way to "layer" per-project plugins+configuration on top of per-user, in turn on top of per-system (albeit at a large memory cost at install-time).
  • A method for existing users of NixOS/home-manager to tightly integrate neovim configuration into it, meaning that aspects of their neovim configuration can reliably depend upon aspects of their system or user configuration.
  • More complexity than you want or need (probably).
  • An end to world hunger.

The numbered chapters are intended to be read in order, as they build upon information in earlier chapters. The appendices are intended more as reference material.

Why?

Mostly because neovim plugin configuration is a bit of a clusterfuck. There's a deceptively (and increasingly) large amount of inherent complexity to the problem space, because neo/vim plugins can have dependencies on many axes (inter-plugin, external executable, Lua modules, remote host language modules, etc.), and those in turn have their own dependency closures, and may also depend on the system or user-level configuration.

Trying to reliably manage this cross-language, cross-system complexity using anything other than Nix quickly descends into either A) madness, or B) compromise. I'm not big on compromise.

1. Basic Usage

The main Envy module can basically be used in three different ways:

  1. It can be used as a NixOS module, to configure neovim system-wide.
  2. It can be used as a home-manager module, to configure neovim on a per-user basis.
  3. It can be used standalone, e.g. in order to configure a custom neovim instance for a project's shell.nix.

In each of these uses, the module is configured in basically the same way, but adding/accessing the module to begin with differs.

Module Setup

Both the NixOS and home-manager modules expose the configuration interface under sn.programs.neovim in NixOS; if you want to use a different attribute path for it, take a look at the envy/nixos.nix/envy/home-manager.nix source and manually do the same.

Both modules take an enabled argument, which defaults to true, rather than exposing a sn.programs.neovim.enable option, due to a technical limitation.

NixOS

Add the envy/nixos.nix module to imports in your configuration.nix:

{ config, lib, pkgs, ... }:
let
  envy = (builtins.fetchgit { url = https://github.com/Shados/envy; ref = "master"; });
in
{
  imports = [
    (import "${envy}/nixos.nix" { })
    ...
  ];
  ...
}

home-manager

Add the envy/home-manager.nix module to imports in your configuration.nix:

{ config, lib, pkgs, ... }:
let
  envy = (builtins.fetchgit { url = https://github.com/Shados/envy; ref = "master"; });
in
{
  imports = [
    (import "${envy}/home-manager.nix" { mergeNixosDefinitions = false; })
    ...
  ];
  ...
}

mergeNixosDefinitions controls whether or not any sn.programs.neovim settings from the current system's NixOS configuration should be merged into the home-manager defintions. This allows for "layering" user-level neovim configuration on top of the system-wide config. It is false by default.

Standalone Setup

Usage as a standalone module is slightly more complicated, and is most easily done by use of the configuredNeovimModule in Envy's lib module:

{ nixpkgs ? import <nixpkgs> { } }:
let
  envy = (builtins.fetchgit { url = https://github.com/Shados/envy; ref = "master"; });
  envyLib = (import "${envy}/lib.nix" { inherit nixpkgs; });
  envyModule = envyLib.configuredNeovimModule {
    # Whether or not to merge in Envy config pulled from the current NixOS Envy
    # module configuration
    withNixosConfig = false;
    # Whether or not to merge in Envy config pulled from the current
    # home-manager-in-NixOS Envy module configuration
    withNixosHMConfig = false;
    # Whether or not to merge in Envy config pulled from the current
    # home-manager Envy module configuration
    withHMConfig = false;
    nvimConfig = { config, lib, pkgs, ... }: {
      # Envy module config here
      pluginRegistry = {
        ...
      };
    };
  }
in
nixpkgs.mkShell {
  ...
  buildInputs = [
    envyModule.wrappedNeovim
    ...
  ];
}

2. Module Configuration

The full set of available configuration options is documented in Appendix A; this chapter serves as an overview of the configuration process and provides examples of how the options may be used.

Broadly, the process for configuring Envy is:

  1. Add non-plugin init.vim configuration.
  2. Enable the plugins you want to use.
  3. Specify any additional dependencies the plugins may have.
  4. Add per-plugin configuration.
  5. Pre-fetch and pin any shortname plugins (see chapter 3).

Non-plugin Configuration

Adapt your non-plugin init.vim configuration to use Envy's module options.

By "non-plugin" here we mean specifically things that either don't depend on/configure any plugin, or that could depend on any one of several plugins (in which case, you should use Nix functionality to check which/whether any of those plugins are enabled and adapt the generated configuration appropriately).

Envy provides a wide array of options here, so some examples may be helpful:

{ config, lib, pkgs, ... }:
{
  # Configfuration items that should or must precede everything else, including
  # per-plugin pre-plugin-load configuration items
  earlyConfig = ''
    let mapleader = "\<Space>"
    augroup vimrc
      autocmd!
    augroup END
  '';
  # Configuration items that should be done prior to loading any plugins (but
  # don't depend on any single plugin); there is also `postPluginConfig` for
  # configuration items that should be done after loading *all* plugins.
  prePluginConfig = ''
    set termguicolors
    syntax enable
  '';
  # General configuration items that don't have any specific ordering
  # requirements; these are appended to the generated init.vim file, so you can
  # use e.g. `lib.mkAfter` if you need something to go at the very end of the
  # file.
  extraConfig = ''
    set incsearch
    set hlsearch
    set ignorecase
    set smartcase
    set number
    set relativenumber
    set autoindent
    set shiftwidth=2
    set softtabstop=2
    set tabstop=2
    set expandtab

    " Use The Silver Searcher (ag) for search backend
    let g:ackprg = 'ag --nogroup --column'
    set grepprg:ag\ --nogroup\ --nocolor
    nnoremap <Leader>o :exe ':silent !xdg-open % &'<CR>
  '';
  # A list of packages whose executables should be added to the $PATH for
  # neovim. These will *only* be added to neovim's path, not to the system or
  # user profiles.
  extraBinPackages = with pkgs; [
    silver-searcher
    xdg_utils # xdg-open
  ];
  # See chapter 3
  mergePlugins = true;
  # `files` can be used to build a symlink tree of files and folders, which
  # would typically consist of any extra/local contents of .config/nvim/ in a
  # non-Nix neovim setup.
  files = {
    neosnippets.source = "/my/snippet/files/";
  };
}

Enabling Plugins

You can enable both pre-existing Nix vim plugin derivations (e.g. from nixpkgs), and vim plugins on github, both by using pluginRegistry.<pluginName>.enable.

There are several ways to specify the source for a plugin, depending on what you want:

{ config, lib, pkgs, ... }:
{
  pluginRegistry = {
    # In this case, the name 'ale' is automatically 'resolved' against
    # pkgs.vimPlugins to select the plugin source
    ale.enable = true;
    # In this case, `source` is explicitly pointed to an existing Vim plugin
    # derivation.
    "denite.nvim" = {
      enable = true;
      source = pkgs.vimPlugins.denite-nvim;
    };
    # In this case, the name fails to resolve against pkgs.vimPlugins, so
    # `source` is automatically inferred from the `name`, on the assumption
    # that it is a vim-plug-compatible 'shortname', which will be used to
    # dynamically construct a derivation from a Vim plugin sourced from
    # https://github.com/Shados/vim-session (see chapter 3).
    "Shados/vim-session".enable = true;
    vim-buffet = {
      enable = true;
      # In this case, we again are using a shortname for the source, but we set
      # it explicitly.
      source = "bagrat/vim-buffet";
      # Additionally, we specify the exact commit we want to pin and use for the git source.
      # Generally you are better off relying on the separate JSON pin files to
      # pin to a specific commit, but in this case the version after this
      # commit has breaking changes, which would mean the configuration of the
      # plugin would also have to change, meaning that the commit information
      # is more an element of configuration than of state. 'branch' and 'tag'
      # are also supported for specifying what to fetch.
      commit = "044f2954a5e49aea8625973de68dda8750f1c42d";
    };
    localPlugin = {
      enable = true;
      # In this case, Envy will dynamically construct a derivation using the
      # given Nix store path as the source.
      source = /some/local/path/or/store/path;
    };
    inDevPlugin = {
      enable = true;
      # Here we instead instruct Envy to have Vim load the plugin from a local
      # filesystem path at run-time, rather than bundling it into the Nix
      # store. This is useful for doing plugin development, or if you otherwise
      # want to use a plugin outside of the Nix store, while still allowing you
      # to leverage Envy's configuration and dependency
      # specification/resolution mechanisms.
      dir = "/a/local/path/string";
    };
  };
}

Specifying Dependencies

Envy allows for specifying a wide variety of dependency types:

{ config, lib, pkgs, ... }:
{
  pluginRegistry = {
    # Inter-plugin dependencies; the items should preferably be the names of
    # `pluginRegistry` or `vim.vimPlugins` items, but can alternatively be Vim
    # plugin derivations.
    neosnippet-snippets.dependencies = [ "neosnippet-vim" ];
    # Specifies that a plugin needs external executables from the given
    # packages made available in neovim's $PATH.
    ale.binDeps = with pkgs; [
      bash
      shellcheck
      shfmt
    ];
    # Ensures that the specified Lua modules will be made available in
    # neovim's LUA_PATH/LUA_CPATH, meaning that the main neovim process can
    # load them for in-process Lua plugins and scripts to use.
    "Shados/precog.nvim".luaDeps = ps: with ps; [
      luafilesystem
    ];
    # Flags a plugin as being a 'remote' plugin requiring a plugin host for a
    # specific language (here, Python 3).
    denite-nvim.remote.python3 = true;
    # Pulls in plugin-host-language dependencies.
    # Automatically implies `remote.python2 = true;`.
    aPythonPlugin.remote.python2Deps = ps: with ps; [
      requests
    ];
  };
}

Inter-plugin dependencies also determine the order in which Vim plugins are loaded at Vim run-time (by vim-plug).

There are additionally two "soft" dependency options (before and after, both of which take lists of plugin names only), that change how plugins are ordered if both are enabled, but does not cause the "dependency" to be enabled if the "dependent" plugin is, e.g.:

{ config, lib, pkgs, ... }:
{
  pluginRegistry = {
    # vim-devicons needs to be loaded after these plugins, if they
    # are being used, as per its installation guide
    vim-devicons.after = [
      "nerdtree" "vim-airline" "ctrlp-vim" "powerline/powerline" "denite-nvim"
      "unite-vim" "lightline-vim" "vim-startify" "vimfiler" "vim-flagship"
    ];
  };
}

Plugin Configuration

There are per-plugin versions of the earlyConfig, prePluginConfig, and postPluginConfig options under pluginRegistry.<pluginName>.nvimrc, named early, prePlugin, and postPlugin respectively. These are inserted into the generated neovim init.vim file immediately after or before the generic versions.

3. Packaging Plugins

If you are using any plugins whose source is specified by 'shortname', then you will need to prefetch those sources, pin the versions, and provide the pinned source information to the Envy module in order for it to construct Vim plugin derivations from the sources.

Pinning Sources

The envy-pins tool is provided to do this. It has a myriad of modes of usage depending on how you are set up, but the easiest way to do things is:

# If you are using the NixOS module, use -n to have envy-pins source the list
# of 'shortname' # plugins to pin directly from the module
envy-pins -n ./pin/storage/directory/ update-all
# -m for the home-manager module
envy-pins -m ./pin/storage/directory/ update-all
# -s for the home-manager NixOS sub-module
envy-pins -s ./pin/storage/directory/ update-all

envy-pins will be installed if you enable either the NixOS or home-maanger Envy modules. Alternatively, you could access just it with a Nix expression like:

{ pkgs }:
let
  envy = (builtins.fetchgit { url = https://github.com/Shados/envy; ref = "master"; });
in pkgs.callPackage "${envy}/envy-pins-package.nix" { }

In order to limit the installation closure size on systems where it may not directly be used (but is still pulled in by an Envy module), envy-pins makes use of a nix-shell's shebang functionality, meaning that it uses Nix to download its dependencies at run-time, rather than at install-time. This also means that it can be run directly from a checkout of Envy.

Specifying Pins To Use

The top-level sourcePins option maps pluginRegistry attribute names to source information. While the individual source pins can be manually set if desired, it is easier to make use of the JSON pin files produced by envy-pins and the built-in helpers to read them:

{ config, lib, pkgs, ... }:
{
  sourcePins = config.sn.programs.neovim.lib.fillPinsFromDir /directory/of/envy-pins/output/;
}

or:

{ config, lib, pkgs, ... }:
let
  envy = (builtins.fetchgit { url = https://github.com/Shados/envy; ref = "master"; });
  envyLib = import "${envy}/lib.nix" { nixpkgs = pkgs; };
in
{
  sourcePins = lib.fillPinsFromDir /directory/of/envy-pins/output/;
}


4. Advanced Usage

This chapter provides some notes on more complicated usages of Envy.

Plugin Merging

The mergePlugins option can be used to merge plugin directories into symlink trees. This is useful because it reduces the number of directories that have to be added to neovim's runtimepath, and as a result it can significantly improve neovim startup times.

There are some restrictions:

  • It may break some plugins outright.
  • It will only merge plugins that are within the same 'bucket' in the plugin load order (so that dependent plugins are still loaded after their dependencies).
  • It will likely cause issues in cases of colliding file names.

As such, it is not enabled by default. If you do enable it, you can disable merging on a per-plugin basis using the pluginRegistry.<pluginName>.mergeable option.

Layering Configuration

TODO

A. Configuration Options

baseVimPlugins

Base set of vim plugin derivations to resolve string/name-based plugin dependencies against.

  • Type: attribute set

  • Default: pkgs.vimPlugins

earlyConfig

Extra lines of init.vim configuration that need to be as early as possible in the file.

  • Type: strings concatenated with "\n"

  • Default: ""

extraBinPackages

A list of derivations containing executables that need to be available in the $PATH of the neovim process for this plugin to use.

Using the per-plugin binDeps is generally preferred; this should only be necessary if you need to make executables available for either:

  • A plugin that is not being managed by this module.
  • A binding or function in your init.vim, or other direct use from within neovim.
  • Type: list of packages

  • Default: {}

extraConfig

Extra lines of init.vim configuration to append to the generated ones.

  • Type: strings concatenated with "\n"

  • Default: ""

extraPython2Packages

A function in python.withPackages format, which returns a list of Python 2 packages required for your plugins to work.

Using the per-plugin python2Deps is strongly preferred; this should only be necessary if you need some Python 2 packages made available to neovim for a plugin that is not being managed by this module.

  • Type: python2 packages in `python2.withPackages` format

  • Default: ps: []

  • Example:

    (ps: with ps; [ pandas jedi ])
    

extraPython3Packages

A function in python.withPackages format, which returns a list of Python 3 packages required for your plugins to work.

Using the per-plugin python3Deps is strongly preferred; this should only be necessary if you need some Python 3 packages made available to neovim for a plugin that is not being managed by this module.

  • Type: python3 packages in `python3.withPackages` format

  • Default: ps: []

  • Example:

    (ps: with ps; [ python-language-server ])
    

files

Files and folders to link into a folder in the runtimepath; outside of Nix these would typically be locally-managed files in the ~/.config/nvim folder.

  • Type: attribute set of submodules

  • Default: {}

  • Example:

    {
      autoload.source = ./neovim/autoload;
      ftplugin.source = ./neovim/ftplugin;
      "neosnippets/nix.snip".text = ''
        snippet nxo
        abbr    NixOS Module Option
        	mkOption {
        		type = with types; ''${1:str};
        		default = "''${2}";
        		description = ''
        		  ''${3}
        		'';
        		example = "''${4}''${0}";
        	};
      '';
    }
    

files.<name>.enable

Whether or not this neovim file should be generated. This option allows specific files to be disabled.

  • Type: boolean

  • Default: true

files.<name>.source

Path to the file or directory to symlink in.

If the source is a directory, a directory with a corresponding name will be created in the folder added to the neovim runtimepath, with symlinks to files in the source directory, and same the treatment applied recursively for child directories.

Overrides the text option if both are set.

  • Type: path

files.<name>.target

Name of the symlink, relative to the folder added to the neovim runtimepath. Defaults to the attribute name.

  • Type: string

files.<name>.text

Literal text of the file. Used to generate a file to set the source option.

  • Type: null or strings concatenated with "\n"

  • Default: null

fullPluginRegistry.<name>.enable

Whether or not this neovim plugin should be installed and used.

  • Type: boolean

fullPluginRegistry.<name>.after

List of other vim plugins that this plugin should be loaded after.

This can be seen as a "soft" form of making each of the listed plugins dependencies of this plugin.

Items must be strings representings either vim-plug-compatible git repository urls, or base vimPlugins attribute names.

  • Type: list of strings

  • Default: {}

fullPluginRegistry.<name>.before

List of other vim plugins that this plugin should be loaded before.

This can be seen as a "soft" form of making this plugin a dependency of each of the listed plugins.

Items must be strings representings either vim-plug-compatible git repository urls, or base vimPlugins attribute names.

  • Type: list of strings

  • Default: {}

fullPluginRegistry.<name>.binDeps

A list of derivations containing executables that need to be available in the $PATH of the neovim process for this plugin to use.

  • Type: list of packages

  • Default: {}

fullPluginRegistry.<name>.branch

Branch of the git source to fetch and use. The tag and commit options effectively override this.

Leave as null to simply use the branch of HEAD (typically, master).

  • Type: null or string

  • Default: null

fullPluginRegistry.<name>.commit

Commit of the git source to fetch and use.

Leave as null to simply use the HEAD.

  • Type: null or string

  • Default: null

fullPluginRegistry.<name>.dependencies

List of other vim plugins that are dependencies of this plugin.

Items can be either strings representings vim-plug-compatible git repository urls, base vimPlugins attribute names, or existing vim plugin derivations.

  • Type: list of string or packages

  • Default: {}

fullPluginRegistry.<name>.dir

If set, specifies a directory path that the plugin should be loaded from at neovim run-time, avoiding the use of a Nix-provided plugin directory.

Relative paths will be relative to the generated init.vim, which is in the Nix store. As the value is passed into a '-quoted VimL string, it is possible to escape this to use a relative path, e.g.:

' . $HOME. '/.config/vim/local/some-plugin

If this is set, source will not be used.

  • Type: null or string

  • Default: null

fullPluginRegistry.<name>.for

One or more filetypes that should trigger on-demand loading of this plugin.

Can be specified with either a single string or list of strings.

  • Type: string or list of strings

  • Default: {}

fullPluginRegistry.<name>.luaDeps

A function that takes an attribute set of Lua packages (typically passed from nixpkgs) and returns a list of Lua packages that this plugin depends on.

  • Type: lua packages in `lua.withPackages` format

  • Default: packageSet: []

  • Example:

    (packageSet: with packageSet: [ luafilesystem ])
    

fullPluginRegistry.<name>.mergeable

Whether or not it is safe to merge this plugin with others in the same bucket in the load order.

  • Type: boolean

  • Default: true

fullPluginRegistry.<name>.nvimrc.condition

A VimL expression that will be evaluated to determine whether or not to execute the vim-plug 'Plug' command for this plugin (which will typically load the plugin, or configure it to be lazily loaded).

Leave null in order to unconditionally always run the 'Plug' command for this plugin.

  • Type: null or string

  • Default: null

fullPluginRegistry.<name>.nvimrc.early

Extra lines of init.vim configuration associated with this plugin, that need to be as early as possible in the file.

Leave null if no such extra configuration is required.

  • Type: null or strings concatenated with "\n"

  • Default: null

fullPluginRegistry.<name>.nvimrc.postPlugin

Extra lines of init.vim configuration associated with this plugin, that need to be executed after the plugin loading.

Leave null if no such extra configuration is required.

  • Type: null or strings concatenated with "\n"

  • Default: null

fullPluginRegistry.<name>.nvimrc.prePlugin

Extra lines of init.vim configuration associated with this plugin, that need to be executed before the plugin loading.

Leave null if no such extra configuration is required.

  • Type: null or strings concatenated with "\n"

  • Default: null

fullPluginRegistry.<name>.on

One or more command or <Plug>-mappings that should trigger on-demand loading of this plugin.

Can be specified with either a single string or list of strings.

  • Type: string or list of strings

  • Default: {}

fullPluginRegistry.<name>.remote.python2

Whether or not this plugin requires the remote plugin host for Python 2.

Will effectively be set to true if any Python 2 package dependencies are specified for this plugin.

  • Type: boolean

fullPluginRegistry.<name>.remote.python2Deps

A function that takes an attribute set of Python 2 packages (typically passed from nixpkgs) and returns a list of Python 2 packages that this plugin depends on.

  • Type: python2 packages in `python2.withPackages` format

  • Default: packageSet: []

  • Example:

    (packageSet: with packageSet: [ pandas jedi ])
    

fullPluginRegistry.<name>.remote.python3

Whether or not this plugin requires the remote plugin host for Python 3.

Will effectively be set to true if any Python 3 package dependencies are specified for this plugin.

  • Type: boolean

fullPluginRegistry.<name>.remote.python3Deps

A function that takes an attribute set of Python 3 packages (typically passed from nixpkgs) and returns a list of Python 3 packages that this plugin depends on.

  • Type: python3 packages in `python3.withPackages` format

  • Default: packageSet: []

  • Example:

    (packageSet: with packageSet: [ python-language-server ])
    

fullPluginRegistry.<name>.rtp

Subdirectory of the plugin source that contains the Vim plugin.

Leave as null to simply use the root of the source.

  • Type: null or string

  • Default: null

fullPluginRegistry.<name>.source

Source of the vim plugin.

Leave as null to let the module infer the source as a vim-plug shortname from the name of this pluginConfig attribute.

Otherwise, set to a string representing a vim-plug-compatible git repository url, an existing vim plugin derivation, or to a Nix store path to build a vim plugin derivation from.

If left null or set to a string, a pin for the source must be present in sourcePins in order to build the neovim configuration.

  • Type: null or package or string or path

  • Default: null

fullPluginRegistry.<name>.tag

Tag of the git source to fetch and use. The commit option effectively overrides this.

Leave as null to simply use the HEAD.

  • Type: null or string

  • Default: null

mergePlugins

Whether or not to collect plugins into "buckets" based upon their position in the load order, and then merge those which can be merged, in order to minimise the number of directories added to vim's runtimepath, decreasing startup time.

  • Type: boolean

neovimPackage

The base neovim package to wrap.

  • Type: package

  • Default: pkgs.neovim-unwrapped

pluginRegistry

An attribute set describing the available/known neovim plugins.

  • Type: attribute set of submodules

  • Default: {}

  • Example:

    {
      # A "source" plugin, where the source is inferred from the attribute
      # name, treated as a vim-plug-compatible shortname
      "bagrat/vim-buffet" = {
        enable = true;
        dependencies = [
          "lightline-vim"
        ];
        # The specific commit to use for the source checkout
        commit = "044f2954a5e49aea8625973de68dda8750f1c42d";
        nvimrc = {
          prePlugin = ''
            " Customize vim-workspace colours based on gruvbox colours
            function g:WorkspaceSetCustomColors()
              highlight WorkspaceBufferCurrentDefault guibg=#a89984 guifg=#282828
              highlight WorkspaceBufferActiveDefault guibg=#504945 guifg=#a89984
              highlight WorkspaceBufferHiddenDefault guibg=#3c3836 guifg=#a89984
              highlight WorkspaceBufferTruncDefault guibg=#3c3836 guifg=#b16286
              highlight WorkspaceTabCurrentDefault guibg=#689d6a guifg=#282828
              highlight WorkspaceTabHiddenDefault guibg=#458588 guifg=#282828
              highlight WorkspaceFillDefault guibg=#3c3836 guifg=#3c3836
              highlight WorkspaceIconDefault guibg=#3c3836 guifg=#3c3836
            endfunction
          '';
          postPlugin = ''
            " vim-workspace
            " Disable lightline's tabline functionality, as it conflicts with this
            let g:lightline.enable = { 'tabline': 0 }
            " Prettify
            let g:workspace_powerline_separators = 1
            let g:workspace_tab_icon = "\uf00a"
            let g:workspace_left_trunc_icon = "\uf0a8"
            let g:workspace_right_trunc_icon = "\uf0a9"
          '';
        };
      };
    
      "Shados/nvim-moonmaker" = {
        enable = false;
        # Decide whether or not to load at run-time based on the result of
        # a VimL expression
        nvimrc.condition = "executable('moonc')";
      };
    
      vim-auto-save = {
        enable = true;
        # Lazily load on opening a tex file
        for = "tex";
      };
    
      nerdtree = {
        enable = true;
        # Lazily load on command usage
        on = "NERDTreeToggle";
        nvimrc.postPlugin = ''
          " Prettify NERDTree
          let NERDTreeMinimalUI = 1
          let NERDTreeDirArrows = 1
        '';
      };
    
      # Use upstream LanguageClient-neovim derivation
      LanguageClient-neovim.enable = true;
    
      # A "path" plugin built from a source path
      "nginx.vim" = {
        enable = true;
        source = ../nvim-files/local/nginx;
      };
    
      # A "local" plugin not directly managed by Nix, merely loaded at nvim
      # run-time from the specified directory
      "devplugin" = {
        enable = true;
        dir = "/home/shados/projects/vim/devplugin";
      };
    
      # A plugin configured but not enabled
      vim-devicons = {
        # vim-devicons needs to be loaded after these plugins, if they
        # are being used, as per its installation guide
        after = [
          "nerdtree" "vim-airline" "ctrlp-vim" "powerline/powerline"
          "denite-nvim" "unite-vim" "lightline-vim" "vim-startify"
          "vimfiler" "vim-flagship"
        ];
      };
    }
    

pluginRegistry.<name>.enable

Whether or not this neovim plugin should be installed and used.

  • Type: boolean

pluginRegistry.<name>.after

List of other vim plugins that this plugin should be loaded after.

This can be seen as a "soft" form of making each of the listed plugins dependencies of this plugin.

Items must be strings representings either vim-plug-compatible git repository urls, or base vimPlugins attribute names.

  • Type: list of strings

  • Default: {}

pluginRegistry.<name>.before

List of other vim plugins that this plugin should be loaded before.

This can be seen as a "soft" form of making this plugin a dependency of each of the listed plugins.

Items must be strings representings either vim-plug-compatible git repository urls, or base vimPlugins attribute names.

  • Type: list of strings

  • Default: {}

pluginRegistry.<name>.binDeps

A list of derivations containing executables that need to be available in the $PATH of the neovim process for this plugin to use.

  • Type: list of packages

  • Default: {}

pluginRegistry.<name>.branch

Branch of the git source to fetch and use. The tag and commit options effectively override this.

Leave as null to simply use the branch of HEAD (typically, master).

  • Type: null or string

  • Default: null

pluginRegistry.<name>.commit

Commit of the git source to fetch and use.

Leave as null to simply use the HEAD.

  • Type: null or string

  • Default: null

pluginRegistry.<name>.dependencies

List of other vim plugins that are dependencies of this plugin.

Items can be either strings representings vim-plug-compatible git repository urls, base vimPlugins attribute names, or existing vim plugin derivations.

  • Type: list of string or packages

  • Default: {}

pluginRegistry.<name>.dir

If set, specifies a directory path that the plugin should be loaded from at neovim run-time, avoiding the use of a Nix-provided plugin directory.

Relative paths will be relative to the generated init.vim, which is in the Nix store. As the value is passed into a '-quoted VimL string, it is possible to escape this to use a relative path, e.g.:

' . $HOME. '/.config/vim/local/some-plugin

If this is set, source will not be used.

  • Type: null or string

  • Default: null

pluginRegistry.<name>.for

One or more filetypes that should trigger on-demand loading of this plugin.

Can be specified with either a single string or list of strings.

  • Type: string or list of strings

  • Default: {}

pluginRegistry.<name>.luaDeps

A function that takes an attribute set of Lua packages (typically passed from nixpkgs) and returns a list of Lua packages that this plugin depends on.

  • Type: lua packages in `lua.withPackages` format

  • Default: packageSet: []

  • Example:

    (packageSet: with packageSet: [ luafilesystem ])
    

pluginRegistry.<name>.mergeable

Whether or not it is safe to merge this plugin with others in the same bucket in the load order.

  • Type: boolean

  • Default: true

pluginRegistry.<name>.nvimrc.condition

A VimL expression that will be evaluated to determine whether or not to execute the vim-plug 'Plug' command for this plugin (which will typically load the plugin, or configure it to be lazily loaded).

Leave null in order to unconditionally always run the 'Plug' command for this plugin.

  • Type: null or string

  • Default: null

pluginRegistry.<name>.nvimrc.early

Extra lines of init.vim configuration associated with this plugin, that need to be as early as possible in the file.

Leave null if no such extra configuration is required.

  • Type: null or strings concatenated with "\n"

  • Default: null

pluginRegistry.<name>.nvimrc.postPlugin

Extra lines of init.vim configuration associated with this plugin, that need to be executed after the plugin loading.

Leave null if no such extra configuration is required.

  • Type: null or strings concatenated with "\n"

  • Default: null

pluginRegistry.<name>.nvimrc.prePlugin

Extra lines of init.vim configuration associated with this plugin, that need to be executed before the plugin loading.

Leave null if no such extra configuration is required.

  • Type: null or strings concatenated with "\n"

  • Default: null

pluginRegistry.<name>.on

One or more command or <Plug>-mappings that should trigger on-demand loading of this plugin.

Can be specified with either a single string or list of strings.

  • Type: string or list of strings

  • Default: {}

pluginRegistry.<name>.remote.python2

Whether or not this plugin requires the remote plugin host for Python 2.

Will effectively be set to true if any Python 2 package dependencies are specified for this plugin.

  • Type: boolean

pluginRegistry.<name>.remote.python2Deps

A function that takes an attribute set of Python 2 packages (typically passed from nixpkgs) and returns a list of Python 2 packages that this plugin depends on.

  • Type: python2 packages in `python2.withPackages` format

  • Default: packageSet: []

  • Example:

    (packageSet: with packageSet: [ pandas jedi ])
    

pluginRegistry.<name>.remote.python3

Whether or not this plugin requires the remote plugin host for Python 3.

Will effectively be set to true if any Python 3 package dependencies are specified for this plugin.

  • Type: boolean

pluginRegistry.<name>.remote.python3Deps

A function that takes an attribute set of Python 3 packages (typically passed from nixpkgs) and returns a list of Python 3 packages that this plugin depends on.

  • Type: python3 packages in `python3.withPackages` format

  • Default: packageSet: []

  • Example:

    (packageSet: with packageSet: [ python-language-server ])
    

pluginRegistry.<name>.rtp

Subdirectory of the plugin source that contains the Vim plugin.

Leave as null to simply use the root of the source.

  • Type: null or string

  • Default: null

pluginRegistry.<name>.source

Source of the vim plugin.

Leave as null to let the module infer the source as a vim-plug shortname from the name of this pluginConfig attribute.

Otherwise, set to a string representing a vim-plug-compatible git repository url, an existing vim plugin derivation, or to a Nix store path to build a vim plugin derivation from.

If left null or set to a string, a pin for the source must be present in sourcePins in order to build the neovim configuration.

  • Type: null or package or string or path

  • Default: null

pluginRegistry.<name>.tag

Tag of the git source to fetch and use. The commit option effectively overrides this.

Leave as null to simply use the HEAD.

  • Type: null or string

  • Default: null

postPluginConfig

Extra lines of init.vim configuration that need to be executed after the plugin loading.

  • Type: strings concatenated with "\n"

  • Default: ""

prePluginConfig

Extra lines of init.vim configuration that need to be executed before the plugin loading.

  • Type: strings concatenated with "\n"

  • Default: ""

sourcePins

Attribute set of source pins for vim plugins. Attribute names should map directly to pluginRegistry attribute names.

  • Type: attribute set of submodules

  • Default: {}

sourcePins.<name>.fetchType

Type of the fetcher to use.

  • Type: one of "git", "github"

sourcePins.<name>.rev

pkgs.fetchgit-compatible git revision string.

  • Type: string

sourcePins.<name>.sha256

pkgs.fetchgit-compatible sha256 string.

  • Type: string

sourcePins.<name>.url

pkgs.fetchgit-compatible git url string.

  • Type: string

sourcePins.<name>.version

Version string appropriate for a nixpkgs derivation.

  • Type: string

withPython2

Enable Python 2 provider. Set to true to use Python 2 plugins.

  • Type: boolean

withPython3

Enable Python 3 provider. Set to true to use Python 3 plugins.

  • Type: boolean

B. Tools

TODO: Automatically generate a man-page-like segment for here, from envy-pins, using the argparse parser object?