A fully reproducible Neovim distribution: plugins, LSPs, formatters, linters and treesitter grammars โ all declared in Nix, lazy-loaded with lze, and running on Neovim nightly.
Built on BirdeeHub/nix-wrapper-modules (migrated from nixCats โ see the migration table).
- ๐ 100 % reproducible โ plugins, LSPs, formatters, linters, treesitter grammars,
even the
python3/node/perlprovider hosts come from the flake. No mason, no:PlugInstall, nothing is fetched at runtime. - ๐ Neovim nightly is bundled, including experiments with the new
vim._core.ui2message UI: floating message window, animated LSP progress spinner,cmdheight = 0with tiny-cmdline.nvim. - โก Lazy loading via lze + lzextras (pinned from source for freshness),
with a custom
auto_enablehandler that silently disables lua specs whose plugin nix didn't install โ so nix stays the single source of truth. - ๐งฉ
plugins-<name>inputs โ any flake input prefixed withplugins-is built straight from its repo and exposed asconfig.nvim-lib.neovimPlugins.<name>(that's howflash.nvim,bafa.nvim,tiny-inline-diagnostic.nvim, โฆ stay fresh). - ๐๏ธ Per-language specs โ every language owns its plugins, its CLI tools and
its info values (
mainInfo);config.specs.<lang>.enable = falseremoves all three from the wrapper โ the plugins, thePATHentries and thenixInfovalues. - โ๏ธ blink.cmp completion โ LuaSnip snippets, colorful-menu rendering, cmdline completion.
- ๐ฆ Deep Rust setup โ rust-analyzer (nightly), bacon-ls diagnostics as you
type, RustOwl lifetime/ownership hints, crates.nvim in
Cargo.toml. - โ๏ธ Nix-native editing โ nixd + nil, alejandra / statix / deadnix, and nixd autocompleting the edited flake's NixOS / Home-Manager options (auto-detected, no hardcoded hostnames).
- ๐ฎ The statusline awards XP for editing (triforce.nvim). Yes, really.
Requirements: Nix with flakes, x86_64-linux, a truecolor terminal.
Everything else โ including Neovim itself โ is in the flake.
# try it without installing
nix run github:meflove/angeldust-nvimWrap
# install into your profile
nix profile install github:meflove/angeldust-nvimWrap
# build locally
nix build github:meflove/angeldust-nvimWrapThe first build compiles a lot (all treesitter grammars, a Rust toolchain, rust-analyzer nightly, โฆ). Point nix at the binary cache to skip most of it โ the public key is listed on https://meflove.cachix.org:
substituters = [ "https://meflove.cachix.org" ];
inputs.angeldust-nvimWrap.url = "github:meflove/angeldust-nvimWrap";As an overlay โ self-contained, replaces pkgs.neovim with the wrapped editor:
nixpkgs.overlays = [ inputs.angeldust-nvimWrap.overlays.default ];
environment.systemPackages = [ pkgs.neovim ];As a module โ importable and overridable from the host config:
imports = [ inputs.angeldust-nvimWrap.nixosModules.neovim ]; # or .homeModules.neovim
wrappers.neovim = {
enable = true;
# override anything from nix/module.nix:
settings.colorscheme = "catppuccin-mocha";
};
home.sessionVariables.EDITOR = lib.getExe config.wrappers.neovim.wrapper;
โ ๏ธ Thepackagesandoverlaysoutputs are self-contained. ThenixosModules/homeModulespath evaluatesnix/module.nixagainst your nixpkgs, which then needs the tooling overlays fromflake.nix(fenix,bacon-ls,nu-lint,emmylua-ls,statix,rustowl) applied. See the nix-wrapper-modules getting-started guide for details.
.
โโโ flake.nix # inputs, tooling overlays, flake outputs
โโโ init.lua # bootstrap: leader keys, vim.loader, require("config")
โโโ nix/
โ โโโ module.nix # composition root: imports, settings, package, hosts
โ โโโ nvim-lib.nix # nvim-lib helpers + spec fields (runtimePkgs, mainInfo)
โ โโโ general.nix # lze engine, colorscheme and the bulk of the editor
โ โโโ langs.nix # per-language specs, each with its own mainInfo
โ โโโ nixd.nix # runtime-evaluated nixd expr: the edited flake's options
โ โโโ treefmt.nix # `nix fmt` โ alejandra, statix, deadnix, luafmt, prettier
โโโ lua/config/
โ โโโ init.lua # nixInfo bridge + lze handler registration
โ โโโ options.lua # vim.opt / vim.o
โ โโโ keymaps.lua # global keymaps
โ โโโ autocmds.lua # cursor restore, auto-mkdir, LSP cleanup, โฆ
โ โโโ colorscheme.lua # theme setup (rose-pine / catppuccin / tokyonight)
โ โโโ ui2.lua # vim._core.ui2 message routing (nightly)
โ โโโ format.lua # conform.nvim
โ โโโ nvim-lint.lua # nvim-lint
โ โโโ lsp/ # core + on_attach + per-language specs
โ โ โโโ languages/ # bash, cpp, json, lua, md, nix, nulang, python, rust, ts, typst, yaml
โ โโโ plugins/ # lze specs by concern: ui, editor, git, completion, โฆ
โ โโโ snippets/ # LuaSnip snippets (lua, nix, python)
โ โโโ utils/ # lze handlers: auto_enable, which-key, lsp ft fallback
โโโ after/queries/ # custom treesitter query injections
โโโ devenv.nix # dev shell + git hooks (prek)
โโโ .github/workflows/ # cachix push, lock updates, codeberg/tangled mirror
How the two halves talk to each other:
- The
nix/modules decide what exists โ each spec carries its plugins (data), its CLI tools (runtimePkgs) and itsmainInfovalues;nvim-lib.nixcollects the latter two into the wrapper'sPATHand theinfoplugin. init.luaexposes them as thenixInfoglobal (the replacement for the oldnixCatsglobal) and registers lze handlers.- The
auto_enablehandler compares each lua spec against the nix-installed plugin list and disables the ones nix didn't provide.
# nix/module.nix
settings.colorscheme = "rose-pine-moon";Available: rose-pine, rose-pine-moon, catppuccin-macchiato,
catppuccin-mocha, tokyonight-storm.
# nix/langs.nix โ the lua side follows automatically via auto_enable
config.specs.rust.enable = false;
# โ drops the rust plugins AND rust-analyzer / bacon / fenix from PATH# flake.nix โ the plugins- prefix is all it takes
plugins-myplugin.url = "github:author/myplugin.nvim";
plugins-myplugin.flake = false;
# nix/general.nix
general.data = [ config.nvim-lib.neovimPlugins.myplugin ];Migration mapping (click to expand)
| nixCats | here |
|---|---|
lspsAndRuntimeDeps.<cat> |
config.specs.<cat>.runtimePkgs |
startupPlugins.<cat> |
config.specs.<cat>.data (lazy = false) |
optionalPlugins.<cat> |
config.specs.<cat>.data (lazy = true) |
categories.<cat> = true |
config.specs.<cat>.enable (defaults to true) |
nixCats.extra.<x> |
config.specs.<cat>.mainInfo.<x> โ config.info |
packageDefinitions / nixCats(...) |
the nixInfo global + wlib.wrapperModules.neovim |
neovim-unwrapped override |
config.package |
| Language | LSP | Formatting | Linting | Extra plugins |
|---|---|---|---|---|
| Lua | emmylua_ls | luafmt (emmylua_formatter) | โ | lazydev.nvim |
| Nix | nixd, nil | alejandra | statix | โ |
| Python | ty, ruff | ruff (format + imports) | โ | โ |
| Rust | rust-analyzer (nightly), bacon-ls, RustOwl | rustfmt (LSP fallback) | clippy (via bacon) | rustaceanvim, crates.nvim, rustowl-nvim |
| TOML | taplo | โ | โ | crates.nvim |
| TypeScript/JS | typescript-language-server | prettierd | eslint_d | typescript-tools.nvim |
| JSON | vscode-json-languageserver | fixjson, json_repair | jsonlint | SchemaStore.nvim |
| YAML | yaml-language-server | yamlfmt, yamlfix | yamllint | โ |
| Shell | bash-language-server | shfmt | shellcheck | โ |
| C / C++ | clangd | clang-format | clangtidy | clangd_extensions.nvim |
| Markdown | marksman | prettierd | โ | markview.nvim, markdown-preview.nvim |
| Typst | tinymist | typstyle | โ | typst-preview.nvim |
| Nushell | nu-lint | โ | โ | โ |
Also on the wrapper's PATH for everything else: ripgrep, fd,
universal-ctags, tree-sitter, sqlite, unzip, ghostscript, tectonic,
mermaid-cli.
<leader> is <Space>. Press <leader>? for buffer-local maps โ and see the
which-key groups: c code, d diff, g git, m markdown, r rename,
s search, t trouble, w workspace.
| Key | Action |
|---|---|
<C-s> |
save (any mode) |
<leader><leader> |
Neural Open โ fast file switcher |
<leader>e / <leader>E |
toggle / focus the Snacks explorer |
<leader>/ |
live grep |
<leader>ss |
LSP symbols |
<leader>su |
undo history |
<leader>sr |
search & replace (grug-far.nvim) |
<leader>. |
scratch buffer |
gb |
buffer switcher (bafa.nvim) |
s / S |
flash jump / treesitter select |
<C-space> |
treesitter incremental selection |
am im ac ic as |
textobjects: function / class / scope |
<leader>y Y p P |
clipboard yank / paste helpers |
| Key | Action |
|---|---|
gd / gD |
definition / declaration |
K |
hover (hover.nvim previews) |
<C-k> |
signature help |
<leader>rn |
rename |
<leader>ca |
code action |
<leader>D |
type definition |
<leader>wa wr wl |
workspace folders: add / remove / list |
<leader>txx / <leader>txX |
Trouble: project / buffer diagnostics |
| Key | Action |
|---|---|
]c / [c |
next / previous hunk |
<leader>gs / <leader>gr |
stage / reset hunk |
<leader>gS / <leader>gR |
stage / reset buffer |
<leader>gu |
undo stage hunk |
<leader>gp |
preview hunk |
<leader>gb |
blame line |
<leader>gd / <leader>gD |
diff against index / last commit |
<leader>gtb / <leader>gtd |
toggle line blame / deleted lines |
ih |
hunk textobject |
<leader>dm dl da |
deltaview menu / view / delta |
| Key | Action |
|---|---|
<leader>ca |
rust code actions (grouped, rustaceanvim) |
<leader>cro cre crd |
RustOwl: toggle / enable / disable |
<leader>cv cf cU cA โฆ |
crates.nvim in Cargo.toml |
<leader>mp ms mt |
markdown preview: start / stop / toggle |
nix develop # or: direnv allow โ devenv shell with prek git hooks
nix fmt # treefmt: alejandra, statix, deadnix, luafmt, prettier
nix flake check # formatting check
nix build .#neovim # local buildThe dev shell runs prek hooks on commit: alejandra, statix, luafmt, lua-ls, end-of-file / trailing-whitespace fixes, private-key detection.
- push-to-cachix โ every push to
mainbuilds the wrapper and pushes it to meflove.cachix.org. - update-flake-lock โ Mon & Thu: bumps
flake.lockanddevenv.lock. - mirror โ pushes
mainto Codeberg and Tangled.
- BirdeeHub/nix-wrapper-modules โ the build system, and the template this config started from.
- BirdeeHub/birdeevim โ the reference for the
nix/module layout (nvim-lib.nix/general.nix/langs.nixand themainInfospec field). - lze / lzextras โ lazy loading that plays well with nix.
- Everyone who wrote the plugins listed in
nix/general.nixandnix/langs.nix.