1
0
Fork
You've already forked nvf
0
Try nvf
  • Nix 100%
2026年06月24日 08:57:44 +00:00
modules fix(sessions): Fix saving 2026年06月24日 08:57:44 +00:00
.envrc feat: use .envrc to allow direnv 2026年04月19日 18:10:07 +00:00
.gitignore feat: Initial commit 2026年04月18日 20:30:58 +00:00
flake.lock feat(flake): Update 2026年06月23日 21:44:27 +00:00
flake.nix chore(flake): Improve formatting 2026年04月25日 07:05:18 +00:00
nvim.nix feat(flake): Enable tmux slits 2026年05月08日 19:47:25 +00:00
README.md feat(sessions): Improve the management 2026年06月24日 08:33:22 +00:00

nvf — minimal Neovim config

Neovim configured with nvf. No runtime plugin manager — everything is pinned and built by Nix. Language tooling (LSP servers, treesitter parsers) is delegated entirely to per-project devshells so the editor package stays small.

Structure

flake.nix inputs, package output, config devShell
nvim.nix root module — just a list of imports
modules/
 options.nix vim.o equivalents, clipboard, leader keys
 ui.nix theme (catppuccin frappe), mini.statusline,
 gitsigns, autopairs, comments
 treesitter.nix meta-language grammars only (nix, lua, bash,
 markdown, gitcommit, git_rebase)
 treesitter-textobjects.nix query files for mini-ai text objects
 lsp.nix LSP infra — no servers bundled
 lazydev.nix Neovim API type stubs for lua_ls
 completion.nix blink.cmp with Rust fuzzy engine
 picker.nix mini.pick + mini.extra + mini.visits + mini.icons
 whichkey.nix which-key keybinding hints + group labels
 oil.nix oil.nvim filesystem editor
 plenary.nix plenary.nvim shared dependency
 neogit.nix neogit git interface
 diffview.nix diffview.nvim diff/history viewer
 fidget.nix LSP progress spinner (bottom-right)
 flash.nix flash.nvim jump motions
 surround.nix mini.surround text object wrappers
 conform.nix conform.nvim autoformat (devshell-driven)
 lint.nix nvim-lint async linting (devshell-driven)
 mini-ai.nix mini.ai extended text objects (treesitter-powered)
 mini-sessions.nix mini.sessions: auto-restore on startup, direnv + LSP reload on switch
 mini-notify.nix mini.notify floating notification UI
 todo-comments.nix todo-comments.nvim highlight + navigation
 grug-far.nix grug-far.nvim live find-and-replace
 vim-sleuth.nix auto-detect indentation per file
 keymaps.nix keymaps, autocmds, LspAttach, parser path hook

Keybindings

<Space> is the leader key. Press it and wait to see which-key hints.

Navigation

Key Action
<C-h/j/k/l> Move between windows
<C-↑/↓/←/→> Resize windows
<S-h> / <S-l> Previous / next buffer
- Open parent directory in oil
jk Exit insert mode

Find (<leader>f)

Key Action
<leader>ff Find files
<leader>fr Frecency files (recent + frequent)
<leader>fg Live grep
<leader>fb Open buffers
<leader>fh Help tags
<leader>fd Diagnostics picker
<leader>fs Document symbols
<leader>fS Workspace symbols
<leader>ft Todo list
<leader>fR Find & replace (grug-far)

Git (<leader>g)

Key Action
<leader>gg Neogit status
<leader>gC Neogit commit popup
<leader>gc Git commits (picker)
<leader>gb Git branches (picker)
<leader>gd Diffview open (working tree vs index)
<leader>gh File history (current file)
<leader>gH Repo history

Inside neogit: s stage, u unstage, c commit, P push, F pull, d open diffview, q quit. Inside diffview: <Tab>/<S-Tab> cycle files, [c/]c hunks, q close, g? all bindings.

Surround (ys, cs, ds)

Key Action
ys{motion}{char} Add surrounding e.g. ysiw""word"
yss{char} Surround whole line
cs{old}{new} Change surrounding e.g. cs"''word'
ds{char} Delete surrounding e.g. ds"word
S{char} Surround visual selection

Text objects (mini.ai)

Works with operators (d, c, y, v) and dot-repeat. a = around, i = inside.

Object Target
af / if Function (treesitter)
ac / ic Class (treesitter)
aa / ia Argument / parameter (treesitter)
ab / ib Any bracket pair ( [ {
aq / iq Any quote " ' ``

Flash (jump)

Key Action
s{char}{char} Jump to any visible position
S{char}{char} Treesitter-aware node jump
r (op-pending) Remote flash — apply operator at distance

Code / LSP (<leader>c, gr*)

Key Action
<leader>cf Format buffer
<leader>cd Show diagnostic float
[d / ]d Previous / next diagnostic
gd Go to definition
gD Go to declaration
K Hover docs
grr References (0.12 built-in)
gri Implementation (0.12 built-in)
grn Rename (0.12 built-in)
gra Code action (0.12 built-in)
gO Document symbols (0.12 built-in)

UI toggles (<leader>u)

Key Action
<leader>un Notification history
<leader>uf Toggle autoformat (buffer-local)
<leader>ud Toggle diagnostics

Buffers (<leader>b)

Key Action
<leader>bd Delete buffer

Sessions (<leader>s)

On startup with no file arguments, the session for the current directory is restored automatically. Sessions are named by full path (/home/user/proj%home%user%proj) so projects with the same basename don't collide.

Key Action
<leader>ss Save session for current directory
<leader>sl Browse sessions by recency and load
<leader>sd Delete a saved session

Switching sessions stops the old project's LSP servers, reloads the new project's direnv environment, and restarts LSP/formatters/linters from the updated env vars.

Todo comments

Key Action
]t / [t Next / previous todo

Misc

Key Action
<leader>: Command history buffer (cmdwin)
<leader>U Undotree (0.12 built-in)
<leader>q Diagnostics quickfix list
<leader>Q Quit all

Oil (<leader>e, -)

Key Action
- Open parent directory (full window)
<leader>e Open oil (floating window)
<CR> Open file or directory
g. Toggle hidden files
:w Apply changes (rename, delete, move)

Local usage

nix run .# # open Neovim
nix build .# # build into ./result/bin/nvim
nix develop # enter the config devShell (lua-language-server)
nix flake update # bump nvf + nixpkgs, then nix build .#

Using this repo in another flake

Once this config is in a public git repository, other flakes can consume it directly as an input. The built Neovim package is exposed as packages.<system>.default.

NixOS (system-wide)

# your system flake.nix
{
 inputs = {
 nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
 my-nvim.url = "github:yourusername/your-nvim-repo";
 };
 outputs = { nixpkgs, my-nvim, ... }: {
 nixosConfigurations.hostname = nixpkgs.lib.nixosSystem {
 system = "x86_64-linux";
 modules = [
 ./configuration.nix
 ({ pkgs, ... }: {
 environment.systemPackages = [
 my-nvim.packages.x86_64-linux.default
 ];
 })
 ];
 };
 };
}

Home Manager (per-user)

# your home.nix or home-manager module
{ inputs, pkgs, ... }: {
 home.packages = [
 inputs.my-nvim.packages.${pkgs.stdenv.hostPlatform.system}.default
 ];
 # optional: make it the default editor
 home.sessionVariables.EDITOR = "nvim";
}

Using pkgs.stdenv.hostPlatform.system instead of a hardcoded string means the same config works on x86_64-linux, aarch64-linux, x86_64-darwin, and aarch64-darwin without changes.

Updating independently

# update only this nvim config, leave everything else pinned
nix flake update my-nvim
# update everything
nix flake update

Roll back to a specific commit:

nix flake lock --update-input my-nvim \
 --override-input my-nvim github:yourusername/your-nvim-repo/<commit-sha>

Integrating nvf as a NixOS / Home Manager module

If you prefer nvf's module system over a pre-built package:

# NixOS
imports = [ inputs.nvf.nixosModules.default ];
programs.nvf.enable = true;
programs.nvf.settings = (import ./nvim.nix { inherit pkgs; }).config.vim;
# Home Manager
imports = [ inputs.nvf.homeManagerModules.default ];
programs.nvf.enable = true;
programs.nvf.settings = (import ./nvim.nix { inherit pkgs; }).config.vim;

Project devShell template

Copy this into your project's flake.nix and fill in sections 1–3. The Neovim package itself is not listed here — it is expected to be in your system packages or on $PATH already.

How it works

  • LSP servers are plain executables. lspconfig finds them by name on $PATH; adding them to packages is all that is needed.
  • Treesitter parsers are built by Nix. The shellHook sets NVIM_TREESITTER_PARSER_PATH, which modules/keymaps.nix reads at startup and appends to runtimepath. Outside a devshell the variable is unset and the block is a silent no-op.
# In your project's flake.nix outputs:
devShells = forAllSystems (system:
 let
 pkgs = nixpkgs.legacyPackages.${system};
 # ── 1. Treesitter parsers ──────────────────────────────────────
 # Use withPlugins + symlinkJoin of .dependencies — NOT builtGrammars
 # directly. nixpkgs has two levels of grammar derivations:
 #
 # builtGrammars.{lang} — raw grammar; `parser` is a plain file
 # withPlugins.dependencies — processed via grammarToPlugin/
 # toNvimTreesitterGrammar; each has
 # `parser/{lang}.so` — the layout Neovim
 # expects when searching runtimepath.
 #
 # symlinkJoin merges all `parser/{lang}.so` files into one root with
 # no name collisions. The result also includes per-language query files.
 #
 # Browse available parsers in a Nix repl:
 # nix repl> :l <nixpkgs>
 # nix repl> pkgs.vimPlugins.nvim-treesitter.builtGrammars.<TAB>
 projectParsers =
 let
 withSelectedParsers = pkgs.vimPlugins.nvim-treesitter.withPlugins (p: [
 p.python
 p.typescript
 p.javascript
 p.tsx
 p.rust
 p.go
 p.html
 p.css
 p.json
 p.yaml
 p.toml
 ]);
 in
 pkgs.symlinkJoin {
 name = "project-nvim-parsers";
 paths = withSelectedParsers.dependencies;
 };
 in {
 default = pkgs.mkShell {
 packages = [
 # ── 2. LSP servers ──────────────────────────────────────────
 # Server ↔ nixpkgs package mapping:
 # https://github.com/neovim/nvim-lspconfig/blob/master/doc/configs.md
 # Search: nix search nixpkgs <server-name>
 # Python
 pkgs.pyright
 # pkgs.ruff # linter + formatter
 # TypeScript / JavaScript
 pkgs.nodePackages.typescript-language-server
 # pkgs.nodePackages.prettier # formatter
 # Rust
 # pkgs.rust-analyzer
 # Go
 # pkgs.gopls
 # Lua
 # pkgs.lua-language-server
 # Nix — nixd LSP, alejandra formatter, statix + deadnix linters are
 # bundled in the Neovim package; no need to add them here.
 # ── 3. Other project tools ──────────────────────────────────
 # pkgs.nodejs
 # pkgs.cargo
 ];
 shellHook = ''
 # Expose Nix-built parsers to Neovim.
 # projectParsers is a derivation with parser/{lang}.so files.
 # modules/keymaps.nix appends this path to runtimepath at startup;
 # modules/treesitter.nix handles the nvim-treesitter runtime/ fix
 # and the registry patch for text-object / indent support.
 export NVIM_TREESITTER_PARSER_PATH="${projectParsers}"
 # ── 4. Formatters and linters ──────────────────────────────
 # JSON objects mapping filetypes to tool lists.
 # Tools must be in packages above to be on $PATH.
 # modules/conform.nix and modules/lint.nix read these at startup
 # and merge them with the hardcoded nix/alejandra + nix/statix entries.
 #
 # Formatter names: https://github.com/stevearc/conform.nvim#formatters
 # Linter names: https://github.com/mfussenegger/nvim-lint#available-linters
 export NVIM_FORMATTERS='{"python":["black"],"javascript":["prettier"]}'
 export NVIM_LINTERS='{"python":["ruff"],"javascript":["eslint_d"]}'
 # JSON array of nvim-lspconfig server names to enable.
 # Servers must be on $PATH (installed above or via the project's package manager).
 # Config names: https://github.com/neovim/nvim-lspconfig/blob/master/doc/configs.md
 export NVIM_LSP_SERVERS='["pyright","ruff"]'
 '';
 };
 });