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, ... }:
{
  # Configuration items that should be done prior to any per-plugin configuration
  prePluginConfig = ''
    let mapleader = "\<Space>"
    augroup vimrc
      autocmd!
    augroup END
    set termguicolors
  '';
  # General configuration items that are appended to the end of the generated
  # vimrc. 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 Ripgrep (rg) for search backend
    let g:ackprg = '${pkgs.ripgrep}/bin/rg --vimgrep --smart-case --no-heading --max-filesize=4M'
    set grepprg:${pkgs.ripgrep}/bin/rg\ --vimgrep\ --smart-case\ --no-heading\ --max-filesize=4M

    nnoremap <Leader>o :exe ':silent !${pkgs.xdg-utils}/bin/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"
    ];
  };
}

It should be noted that lazy-loaded plugins don't fully respect ordering options, and don't trigger lazy-loading of dependencies. Either ensure dependencies aren't also being lazy-loaded, or put them behind the same lazy-load triggers as their dependents.

Plugin Configuration

There is a per-plugin version of the extraConfig option, under pluginRegistry.<pluginName>.extraConfig. These are inserted into the generated nvimrc after the prePluginConfig, before the top-level extraConfig, and in the same order plugins are loaded (that is, based on dependencies and explicit ordering information).