flowchart TD A[Start] --> B{Is plugin in nixpkgs?} B -->|Yes| C[Add to optionalPlugins] B -->|No| D[Add to flake inputs] C --> E[Add any plugin dependencies and tools] D --> E E --> G[Register to lze in init.lua] G --> K[Run nix build .] K --> L[Test with ./result/bin/nvim]
Check it out: nixCats-nvim-example
Run git clone https://github.com/kohane27/nixCats-nvim-example.git ~/.config/nixCats-nvim
and start tinkering!
Caveat
My template assumes you are familiar with the Neovim plugin ecosystem, like adding plugins with lazy.nvim
in a normal Linux/MacOS environment. This guide only shows you how to do so in Nix/NixOS.
Introduction
I used nixCats-nvim’s example template to get started.
How to Use
git clone https://github.com/kohane27/nixCats-nvim-example.git ~/.config/nixCats-nvim
~/.config/nixCats-nvim/
. The directory name has to be called nixCats-nvim
.I. Using Nix to download and manage plugins and tools
1. Adding plugins to flake.nix
flake.nix
is the entry point for the plugins and tools you want to be managed by Nix. When you want to add any plugins or tools (LSP servers, fzf
, stylua
etc), this is the file to modify.
Check if the plugin is available in nixpkgs (The naming convention is suffixing -nvim
, i.e., if you want to download telescope.nvim
search telescope-nvim
).
If yes, add it to the optionalPlugins
attribute set
If the plugin is not available in nixpkgs, add the following to flake inputs:
"plugins-hlargs" = {
url = "github:m-demare/hlargs.nvim";
flake = false;
};
Note that the name must start with plugins-
.
2. Install the plugin’s dependencies
For example, for telescope.nvim
, the installation guide for lazy.nvim
is below:
{
"nvim-telescope/telescope.nvim",
dependencies = { "nvim-lua/plenary.nvim" },
}
So you need to put plenary-nvim
to startupPlugins
.
vim-repeat
, plenary-nvim
, dressing-nvim
, nui-nvim
, nvim-web-devicons
etc are required and shared by many plugins so I don’t bother setting them up in optionalPlugins
attribute set.3. Install the plugin’s external dependencies
For example, telescope.nvim
requires ripgrep
, so we put ripgrep
to lspsAndRuntimeDeps
.
What if the plugin is not available in Nix and requires a build step?
By build step I mean the following:
{
"nvim-telescope/telescope-fzf-native.nvim",
build = "cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release && cmake --build build --config Release",
}
Just cry and hope someone step up and contribute it to Nix. jk. You can study how it’s done (ref: avante-nvim) and package it yourself (and hopefully contribute to Nix so that other people can benefit from it).
II. Using lua to configure plugins
1. Import your plugin to lua/custom/plugins/init.lua
:
require("lze").load({
{ import = "custom.plugins.telescope" },
})
init.lua
. It’ll always be just require("custom")
.2. Create the plugin init.lua
:
With custom.plugins.telescope
, create the corresponding lua/custom/plugins/telescope/
and init.lua
:
return {
{ "telescope-fzf-native.nvim", dep_of = "telescope.nvim" },
{
"telescope.nvim",
after = function(plugin)
local telescope = require("telescope")
telescope.setup({
extensions = {
fzf = { fuzzy = true },
},
})
telescope.load_extension("fzf")
end,
},
}
2a. Declaring correct names
The name (line 4) is not necessarily the name you expect:
For plugins added via
inputs
inflake.nix
(i.e., plugins not available in nixpkgs), it’s just the plugin name without-nvim
, e.g., ifinputs
isplugins-hlargs
, the name required ishlargs
.For plugins from nixpkgs, it’s usually the plugin name wth
.nvim
, e.g., ifpkgs.vimPlugins.toggleterm-nvim
, the name istoggleterm.nvim
. For nvim-tree.lua, it’s NOTnvim-tree
ornvim-tree.nvim
, it’snvim-tree.lua
.
:NixCats pawsible
to confirm the required names.2b. Declaring correct dependencies
Continuing our telescope example above. The line { "telescope-fzf-native.nvim", dep_of = "telescope.nvim" }
is setting the dependency required by the extension fzf
.
{ "telescope-fzf-native.nvim", dep_of = "telescope.nvim" }
as “telescope-fzf-native.nvim is dependencies of telescope.nvim”.For example, when you see the following lazy.nvim
spec:
{
"yetone/avante.nvim",
dependencies = {
{
"MeanderingProgrammer/render-markdown.nvim",
ft = { "markdown", "Avante" },
},
},
})
The equivalent in lua/custom/plugins/ai/avante/init.lua
:
return {
{ "avante.nvim" },
{
"render-markdown.nvim",
dep_of = { "avante.nvim" },
},
}
As you can see, using lze
requires you to understand where the plugin comes from and what it needs. It’s more involved than just copying lazy.nvim
’s to a new file and have it configure for you.
III. Run nix build
~/.config/nixCats-nvim/
.Run nix build "."
to build the binary at ./result/bin/nvim
Execute and pray there’s no error and your plugin is working.
nix flake update
.home-manager
Integration
Since I’m using home-manager, I just add it to my path home.sessionPath = [ "$HOME/.config/nixCats-nvim/result/bin" ];
After rebooting:
➜ which nvim
/home/username/.config/nixCats-nvim/result/bin/nvim
Tips
1. Use regularCats
to quickly set up and config new plugins
Nobody has the patience to make a small change, run nix build .
and wait 20 seconds. regularCats
is the perfect use case for it.
The following builds the binary ./bin/regularCats
:
nix build ".#regularCats" --out-link regularCats
Once you have made sure the plugin is downloaded and loaded by Nix (:NixCats pawsible
), you just make changes to the plugin init.lua
and run ./bin/regularCats
to see the changes immediately.
I have the following in my home-manager’s aliases.nix
:
programs.zsh.shellAliases = {
v = "$(readlink -f ~/.config/nixCats-nvim/result/bin/nvim)";
vv = "$(readlink -f ~/.config/nixCats-nvim/regularCats/bin/regularCats)";
};
flake.nix
(add or remove plugins or adding new tools), you still need to run nix build "."
.2. Use GitHub search and reference other people’s nixCats-nvim
I used GitHub search when I was setting up mine. I believe my repo is the most complete bloated nixCats-nvim
on all of GitHub. But it also serves as an example of how to do various things. Just remove the stuff you don’t need.
3. Debugging
If your plugin is not working:
flake.nix
: Move the plugin fromoptionalPlugins
tostartupPlugins
attribute set- set
lazy = false
in your plugininit.lua
For example, when I was setting up typescript-tools-nvim, I realized it did not work if I put it under optionalPlugins
. Even adding lazy = false
did not work. After a lot of headache, BirdeeHub and I resolved it.