2023-12-09 22:03:58 +03:00
|
|
|
|
# Adding Plugins {#sec-additional-plugins}
|
|
|
|
|
|
|
2025-07-20 16:13:19 +03:00
|
|
|
|
There are two methods for adding new Neovim plugins to **nvf**. npins is the
|
|
|
|
|
|
faster option that should be preferred if the plugin consists of pure Lua or
|
|
|
|
|
|
Vimscript code. In which case there is no building required, and we can easily
|
|
|
|
|
|
handle the copying of plugin files. Alternative method, which is required when
|
|
|
|
|
|
plugins try to build their own libraries (e.g., in Rust or C) that need to be
|
|
|
|
|
|
built with Nix to function correctly.
|
|
|
|
|
|
|
|
|
|
|
|
## With npins {#sec-npins-for-plugins}
|
|
|
|
|
|
|
|
|
|
|
|
npins is the standard method of adding new plugins to **nvf**. You simply need
|
|
|
|
|
|
the repository URL for the plugin, and can add it as a source to be built
|
|
|
|
|
|
automatically with one command. To add a new Neovim plugin, use `npins`. For
|
|
|
|
|
|
example:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
nix-shell -p npins # or nix shell nixpkgs#npins if using flakes
|
|
|
|
|
|
```
|
2023-12-09 22:03:58 +03:00
|
|
|
|
|
2025-07-20 16:13:19 +03:00
|
|
|
|
Then run:
|
2025-02-06 17:43:54 +03:00
|
|
|
|
|
2025-07-20 16:13:19 +03:00
|
|
|
|
```bash
|
|
|
|
|
|
npins add --name <plugin name> github <owner> <repo> -b <branch>
|
|
|
|
|
|
```
|
2025-02-06 17:43:54 +03:00
|
|
|
|
|
2025-07-20 16:13:19 +03:00
|
|
|
|
::: {.note}
|
|
|
|
|
|
|
|
|
|
|
|
Be sure to replace any non-alphanumeric characters with `-` for `--name`. For
|
|
|
|
|
|
example
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
npins add --name lazydev-nvim github folke lazydev.nvim -b main
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
|
|
|
|
Once the `npins` command is done, you can start referencing the plugin as a
|
|
|
|
|
|
**string**.
|
|
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
|
{
|
|
|
|
|
|
config.vim.startPlugins = ["lazydev-nvim"];
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Packaging Complex Plugins {#sec-pkgs-for-plugins}
|
|
|
|
|
|
|
|
|
|
|
|
[blink.cmp]: https://github.com/Saghen/blink.cmp
|
2025-02-06 17:43:54 +03:00
|
|
|
|
|
2025-07-20 16:13:19 +03:00
|
|
|
|
Some plugins require additional packages to be built and substituted to function
|
|
|
|
|
|
correctly. For example [blink.cmp] requires its own fuzzy matcher library, built
|
|
|
|
|
|
with Rust, to be installed or else defaults to a much slower Lua implementation.
|
|
|
|
|
|
In the Blink documentation, you are advised to build with `cargo` but that is
|
|
|
|
|
|
not ideal since we are leveraging the power of Nix. In this case the ideal
|
|
|
|
|
|
solution is to write a derivation for the plugin.
|
2025-02-06 17:43:54 +03:00
|
|
|
|
|
2025-07-20 16:13:19 +03:00
|
|
|
|
We use `buildRustPackage` to build the library from the repository root, and
|
|
|
|
|
|
copy everything in the `postInstall` phase.
|
2023-12-09 22:03:58 +03:00
|
|
|
|
|
2025-07-20 16:13:19 +03:00
|
|
|
|
```nix
|
|
|
|
|
|
postInstall = ''
|
|
|
|
|
|
cp -r {lua,plugin} "$out"
|
|
|
|
|
|
|
|
|
|
|
|
mkdir -p "$out/doc"
|
|
|
|
|
|
cp 'doc/'*'.txt' "$out/doc/"
|
|
|
|
|
|
|
|
|
|
|
|
mkdir -p "$out/target"
|
|
|
|
|
|
mv "$out/lib" "$out/target/release"
|
|
|
|
|
|
'';
|
|
|
|
|
|
```
|
2024-11-08 12:20:16 +03:00
|
|
|
|
|
2025-07-20 16:13:19 +03:00
|
|
|
|
In a similar fashion, you may utilize `stdenv.mkDerivation` and other Nixpkgs
|
|
|
|
|
|
builders to build your library from source, and copy the relevant files and Lua
|
|
|
|
|
|
plugin files in the `postInstall` phase. Do note, however, that you still need
|
|
|
|
|
|
to fetch the plugin sources somehow. npins is, once again, the recommended
|
|
|
|
|
|
option to fetch the plugin sources. Refer to the previous section on how to use
|
|
|
|
|
|
npins to add a new plugin.
|
2023-12-09 22:03:58 +03:00
|
|
|
|
|
2025-07-20 16:13:19 +03:00
|
|
|
|
Plugins built from source must go into the `flake/pkgs/by-name` overlay. It will
|
|
|
|
|
|
automatically create flake outputs for individual packages. Lastly, you must add
|
|
|
|
|
|
your package to the plugin builder (`pluginBuilders`) function manually in
|
|
|
|
|
|
`modules/wrapper/build/config.nix`. Once done, you may refer to your plugin as a
|
|
|
|
|
|
**string**.
|
2023-12-09 22:03:58 +03:00
|
|
|
|
|
|
|
|
|
|
```nix
|
2025-07-20 16:13:19 +03:00
|
|
|
|
{
|
|
|
|
|
|
config.vim.startPlugins = ["blink-cmp"];
|
|
|
|
|
|
}
|
2023-12-09 22:03:58 +03:00
|
|
|
|
```
|
2024-04-06 20:33:31 +00:00
|
|
|
|
|
|
|
|
|
|
## Modular setup options {#sec-modular-setup-options}
|
|
|
|
|
|
|
|
|
|
|
|
Most plugins is initialized with a call to `require('plugin').setup({...})`.
|
|
|
|
|
|
|
2024-11-08 12:20:16 +03:00
|
|
|
|
We use a special function that lets you easily add support for such setup
|
|
|
|
|
|
options in a modular way: `mkPluginSetupOption`.
|
2024-04-06 20:33:31 +00:00
|
|
|
|
|
2024-11-08 12:20:16 +03:00
|
|
|
|
Once you have added the source of the plugin as shown above, you can define the
|
|
|
|
|
|
setup options like this:
|
2024-04-06 20:33:31 +00:00
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
|
# in modules/.../your-plugin/your-plugin.nix
|
|
|
|
|
|
|
|
|
|
|
|
{lib, ...}:
|
|
|
|
|
|
let
|
|
|
|
|
|
inherit (lib.types) bool int;
|
|
|
|
|
|
inherit (lib.nvim.types) mkPluginSetupOption;
|
|
|
|
|
|
in {
|
|
|
|
|
|
options.vim.your-plugin = {
|
|
|
|
|
|
setupOpts = mkPluginSetupOption "plugin name" {
|
|
|
|
|
|
enable_feature_a = mkOption {
|
|
|
|
|
|
type = bool;
|
|
|
|
|
|
default = false;
|
|
|
|
|
|
# ...
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
number_option = mkOption {
|
|
|
|
|
|
type = int;
|
|
|
|
|
|
default = 3;
|
|
|
|
|
|
# ...
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
|
# in modules/.../your-plugin/config.nix
|
|
|
|
|
|
{lib, config, ...}:
|
|
|
|
|
|
let
|
|
|
|
|
|
cfg = config.vim.your-plugin;
|
|
|
|
|
|
in {
|
|
|
|
|
|
vim.luaConfigRC = lib.nvim.dag.entryAnywhere ''
|
|
|
|
|
|
require('plugin-name').setup(${lib.nvim.lua.toLuaObject cfg.setupOpts})
|
|
|
|
|
|
'';
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2025-07-20 16:13:19 +03:00
|
|
|
|
This above config will result in this Lua script:
|
2024-04-06 20:33:31 +00:00
|
|
|
|
|
|
|
|
|
|
```lua
|
|
|
|
|
|
require('plugin-name').setup({
|
|
|
|
|
|
enable_feature_a = false,
|
|
|
|
|
|
number_option = 3,
|
|
|
|
|
|
})
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2024-11-08 12:20:16 +03:00
|
|
|
|
Now users can set any of the pre-defined option field, and can also add their
|
|
|
|
|
|
own fields!
|
2024-04-06 20:33:31 +00:00
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
|
# in user's config
|
|
|
|
|
|
{
|
|
|
|
|
|
vim.your-plugin.setupOpts = {
|
|
|
|
|
|
enable_feature_a = true;
|
|
|
|
|
|
number_option = 4;
|
|
|
|
|
|
another_field = "hello";
|
|
|
|
|
|
size = { # nested fields work as well
|
|
|
|
|
|
top = 10;
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Details of toLuaObject {#sec-details-of-toluaobject}
|
|
|
|
|
|
|
2025-08-21 09:20:05 +03:00
|
|
|
|
As you've seen above, `toLuaObject` is used to convert our `cfg.setupOpts`, a
|
|
|
|
|
|
Nix attribute set, into Lua tables across the codebase. Here are some rules of
|
|
|
|
|
|
the conversion:
|
2024-04-06 20:33:31 +00:00
|
|
|
|
|
2025-08-21 09:20:05 +03:00
|
|
|
|
1. Nix `null` converts to Lua `nil`
|
|
|
|
|
|
- `foo = null;` -> `foo = nil`
|
|
|
|
|
|
2. Number and strings convert to their Lua counterparts
|
2025-07-20 16:13:19 +03:00
|
|
|
|
3. Nix attribute sets (`{}`) and lists (`[]`) convert into Lua dictionaries and
|
|
|
|
|
|
tables respectively. Here is an example of Nix -> Lua conversion.
|
|
|
|
|
|
- `{foo = "bar"}` -> `{["foo"] = "bar"}`
|
|
|
|
|
|
- `["foo" "bar"]` -> `{"foo", "bar"}`
|
2025-08-21 09:20:05 +03:00
|
|
|
|
- You may also write **mixed tables** using `toLuaObject`, using a special
|
|
|
|
|
|
syntax to describe a key's position in the table. Let's say you want to get
|
|
|
|
|
|
something like `{"foo", bar = "baz"}` expressed in Lua using Nix. The
|
|
|
|
|
|
appropriate Nix syntax to express mixed tables is as follows:
|
|
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
|
# Notice the position indicator, "@1"
|
|
|
|
|
|
{ "@1" = "foo"; bar = "baz"; };
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
This will result in a mixed Lua table that is as follows:
|
|
|
|
|
|
|
|
|
|
|
|
```lua
|
|
|
|
|
|
{"foo", bar = "baz"}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2025-07-20 16:13:19 +03:00
|
|
|
|
4. You can write raw Lua code using `lib.generators.mkLuaInline`. This function
|
|
|
|
|
|
is part of nixpkgs, and is accessible without relying on **nvf**'s extended
|
|
|
|
|
|
library.
|
|
|
|
|
|
- `mkLuaInline "function add(a, b) return a + b end"` will yield the
|
|
|
|
|
|
following result:
|
|
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
|
{
|
|
|
|
|
|
_type = "lua-inline";
|
|
|
|
|
|
expr = "function add(a, b) return a + b end";
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
The above expression will be interpreted as a Lua expression in the final
|
|
|
|
|
|
config. Without the `mkLuaInline` function, you will only receive a string
|
|
|
|
|
|
literal. You can use it to feed plugin configuration tables Lua functions
|
|
|
|
|
|
that return specific values as expected by the plugins.
|
|
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
|
{
|
|
|
|
|
|
vim.your-plugin.setupOpts = {
|
|
|
|
|
|
on_init = lib.generators.mkLuaInline ''
|
|
|
|
|
|
function()
|
|
|
|
|
|
print('we can write lua!')
|
|
|
|
|
|
end
|
|
|
|
|
|
'';
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
2024-11-04 16:50:50 +01:00
|
|
|
|
|
|
|
|
|
|
## Lazy plugins {#sec-lazy-plugins}
|
|
|
|
|
|
|
2024-11-08 12:20:16 +03:00
|
|
|
|
If the plugin can be lazy-loaded, `vim.lazy.plugins` should be used to add it.
|
|
|
|
|
|
Lazy plugins are managed by `lz.n`.
|
2024-11-04 16:50:50 +01:00
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
|
# in modules/.../your-plugin/config.nix
|
2025-07-20 16:13:19 +03:00
|
|
|
|
{config, ...}: let
|
2024-11-04 16:50:50 +01:00
|
|
|
|
cfg = config.vim.your-plugin;
|
|
|
|
|
|
in {
|
|
|
|
|
|
vim.lazy.plugins.your-plugin = {
|
2025-07-20 16:13:19 +03:00
|
|
|
|
# Instead of vim.startPlugins, use this:
|
2024-11-04 16:50:50 +01:00
|
|
|
|
package = "your-plugin";
|
|
|
|
|
|
|
2025-07-20 16:13:19 +03:00
|
|
|
|
# ıf your plugin uses the `require('your-plugin').setup{...}` pattern
|
2024-11-04 16:50:50 +01:00
|
|
|
|
setupModule = "your-plugin";
|
|
|
|
|
|
inherit (cfg) setupOpts;
|
|
|
|
|
|
|
2025-07-20 16:13:19 +03:00
|
|
|
|
# Events that trigger this plugin to be loaded
|
2024-11-04 16:50:50 +01:00
|
|
|
|
event = ["DirChanged"];
|
|
|
|
|
|
cmd = ["YourPluginCommand"];
|
|
|
|
|
|
|
2025-07-20 16:13:19 +03:00
|
|
|
|
# Plugin Keymaps
|
2024-11-04 16:50:50 +01:00
|
|
|
|
keys = [
|
2025-07-20 16:13:19 +03:00
|
|
|
|
# We'll cover this in detail in the 'keybinds' section
|
2024-11-04 16:50:50 +01:00
|
|
|
|
{
|
|
|
|
|
|
key = "<leader>d";
|
|
|
|
|
|
mode = "n";
|
|
|
|
|
|
action = ":YourPluginCommand";
|
|
|
|
|
|
}
|
|
|
|
|
|
];
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
This results in the following lua code:
|
2024-11-08 12:20:16 +03:00
|
|
|
|
|
2024-11-04 16:50:50 +01:00
|
|
|
|
```lua
|
|
|
|
|
|
require('lz.n').load({
|
|
|
|
|
|
{
|
|
|
|
|
|
"name-of-your-plugin",
|
|
|
|
|
|
after = function()
|
2025-07-20 16:13:19 +03:00
|
|
|
|
require('your-plugin').setup({
|
|
|
|
|
|
--[[ your setupOpts ]]--
|
|
|
|
|
|
})
|
2024-11-04 16:50:50 +01:00
|
|
|
|
end,
|
|
|
|
|
|
|
|
|
|
|
|
event = {"DirChanged"},
|
|
|
|
|
|
cmd = {"YourPluginCommand"},
|
|
|
|
|
|
keys = {
|
|
|
|
|
|
{"<leader>d", ":YourPluginCommand", mode = {"n"}},
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2025-07-20 16:13:19 +03:00
|
|
|
|
[`vim.lazy.plugins` spec]: https://notashelf.github.io/nvf/options.html#opt-vim.lazy.plugins
|
|
|
|
|
|
|
|
|
|
|
|
A full list of options can be found in the [`vim.lazy.plugins` spec] on the
|
|
|
|
|
|
rendered manual.
|