nvf

Custom Plugins

nvf exposes a very wide variety of plugins by default, which are consumed by module options. This is done for your convenience, and to bundle all necessary dependencies into nvf's runtime with full control of versioning, testing and dependencies. In the case a plugin you need is not available, you may consider making a pull request to add the package you're looking for, or you may add it to your configuration locally. The below section describes how new plugins may be added to the user's configuration.

Adding Plugins

Per nvf's design choices, there are several ways of adding custom plugins to your configuration as you need them. As we aim for extensive configuration, it is possible to add custom plugins (from nixpkgs, pinning tools, flake inputs, etc.) to your Neovim configuration before they are even implemented in nvf as a module.

Info

To add a plugin to your runtime, you will need to add it to list in your configuration. This is akin to cloning a plugin to ~/.config/nvim, but they are only ever placed in the Nix store and never exposed to the outside world for purity and full isolation.

As you would configure a cloned plugin, you must configure the new plugins that you've added to startPlugins. nvf provides multiple ways of configuring any custom plugins that you might have added to your configuration.

Configuring

Just making the plugin to your Neovim configuration available might not always be enough., for example, if the plugin requires a setup table. In that case, you can write custom Lua configuration using one of

Lazy Plugins

config.vim.lazy.plugins.*.setupOpts is useful for lazy-loading plugins, and uses an extended version of lz.n's PluginSpec to expose a familiar interface. setupModule and setupOpt can be used if the plugin uses a require('module').setup(...) pattern. Otherwise, the before and after hooks should do what you need.

{
  config.vim.lazy.plugins = {
    aerial.nvim = {
    # ^^^^^^^^^ this name should match the package.pname or package.name
      package = aerial-nvim;

      setupModule = "aerial";
      setupOpts = {option_name = false;};

      after = "print('aerial loaded')";
    };
  };
}

Standard API

vim.extraPlugins uses an attribute set, which maps DAG section names to a custom type, which has the fields package, after, setup. They allow you to set the package of the plugin, the sections its setup code should be after (note that the extraPlugins option has its own DAG scope), and the its setup code respectively. For example:

{pkgs, ...}: {
  config.vim.extraPlugins = {
    aerial = {
      package = pkgs.vimPlugins.aerial-nvim;
      setup = "require('aerial').setup {}";
    };

    harpoon = {
      package = pkgs.vimPlugins.harpoon;
      setup = "require('harpoon').setup {}";
      after = ["aerial"]; # place harpoon configuration after aerial
    };
  };
}

Setup using luaConfigRC

vim.luaConfigRC also uses an attribute set, but this one is resolved as a DAG directly. The attribute names denote the section names, and the values lua code. For example:

{
  # This will create a section called "aquarium" in the 'init.lua' with the
  # contents of your custom configuration. By default 'entryAnywhere' is implied
  # in DAGs, so this will be inserted to an arbitrary position. In the case you 
  # wish to control the position of this section with more precision, please
  # look into the DAGs section of the manual.
  config.vim.luaConfigRC.aquarium = "vim.cmd('colorscheme aquiarum')";
}

Note

One of the greatest strengths of nvf is the ability to order configuration snippets precisely using the [DAG system]. DAGs are a very powerful mechanism that allows specifying positions of individual sections of configuration as needed. We provide helper functions in the extended library, usually under inputs.nvf.lib.nvim.dag that you may use.

Please refer to the [DAG section] in the nvf manual to find out more about the DAG system.

# Lazy Method {#sec-lazy-method}

As of version 0.7, an API is exposed to allow configuring lazy-loaded plugins via lz.n and lzn-auto-require. Below is a comprehensive example of how it may be loaded to lazy-load an arbitrary plugin.

{
  config.vim.lazy.plugins = {
    "aerial.nvim" = {
      package = pkgs.vimPlugins.aerial-nvim;
      setupModule = "aerial";
      setupOpts = {
        option_name = true;
      };
      after = ''
        -- custom lua code to run after plugin is loaded
        print('aerial loaded')
      '';

      # Explicitly mark plugin as lazy. You don't need this if you define one of
      # the trigger "events" below
      lazy = true;

      # load on command
      cmd = ["AerialOpen"];

      # load on event
      event = ["BufEnter"];

      # load on keymap
      keys = [
        {
          key = "<leader>a";
          action = ":AerialToggle<CR>";
        }
      ];
    };
  };
}

LazyFile event

nvf re-implements LazyFile as a familiar user event to load a plugin when a file is opened:

{
  config.vim.lazy.plugins = {
    "aerial.nvim" = {
      package = pkgs.vimPlugins.aerial-nvim;
      event = [{event = "User"; pattern = "LazyFile";}];
      # ...
    };
  };
}

You can consider the LazyFile event as an alias to the combination of "BufReadPost", "BufNewFile" and "BufWritePre", i.e., a list containing all three of those events: ["BufReadPost" "BufNewFile" "BufWritePre"]

Non-lazy Method

As of version 0.5, we have a more extensive API for configuring plugins that should be preferred over the legacy method. This API is available as . Instead of using DAGs exposed by the library directly, you may use the extra plugin module as follows:

{pkgs, ...}: {
  config.vim.extraPlugins = {
    aerial = {
      package = pkgs.vimPlugins.aerial-nvim;
      setup = ''
        require('aerial').setup {
          -- some lua configuration here
        }
      '';
    };

    harpoon = {
      package = pkgs.vimPlugins.harpoon;
      setup = "require('harpoon').setup {}";
      after = ["aerial"];
    };
  };
}

This provides a level of abstraction over the DAG system for faster iteration.

Legacy Method

Prior to version 0.5, the method of adding new plugins was adding the plugin package to and adding its configuration as a DAG under one of vim.configRC or . While configRC has been deprecated, users who have not yet updated to 0.5 or those who prefer a more hands-on approach may choose to use the old method where the load order of the plugins is explicitly determined by DAGs without internal abstractions.

Adding New Plugins

To add a plugin not available in nvf as a module to your configuration using the legacy method, you must add it to in order to make it available to Neovim at runtime.

{pkgs, ...}: {
  # Add a Neovim plugin from Nixpkgs to the runtime.
  # This does not need to come explicitly from packages. 'vim.startPlugins'
  # takes a list of *string* (to load internal plugins) or *package* to load
  # a Neovim package from any source.
  vim.startPlugins = [pkgs.vimPlugins.aerial-nvim];
}

Once the package is available in Neovim's runtime, you may use the luaConfigRC option to provide configuration as a DAG using the nvf extended library in order to configure the added plugin,

{inputs, ...}: let
  # This assumes you have an input called 'nvf' in your flake inputs
  # and 'inputs' in your specialArgs. In the case you have passed 'nvf'
  # to specialArgs, the 'inputs' prefix may be omitted.
  inherit (inputs.nvf.lib.nvim.dag) entryAnywhere;
in {
  # luaConfigRC takes Lua configuration verbatim and inserts it at an arbitrary
  # position by default or if 'entryAnywhere' is used.
  vim.luaConfigRC.aerial-nvim= entryAnywhere ''
    require('aerial').setup {
      -- your configuration here
    }
  '';
}