core.lazy
Bootstraps Lazy and loads core options before plugins.
A practical map of how this Lua configuration boots, where behavior belongs, and which plugin owns each editing concern.
init.lua is intentionally boring. It establishes Lazy first, then layers presentation, mappings, editor events, highlights, and one specialized LSP helper.
Bootstraps Lazy and loads core options before plugins.
Lazy discovers specs and installs handlers for events, commands, and keys.
Catppuccin Macchiato supplies the visual baseline.
Core editing, LSP, commands, and group labels register.
Editor-level reactions attach once through named augroups.
Small local highlight overrides apply after the theme.
The file-pattern-specific helper starts only where relevant.
Maintenance gets easier when two plugins do not compete for the same surface. Select a row to inspect the boundary.
Conform runs explicit tools per filetype. Python prefers Ruff, with isort and Black as the fallback toolchain. LSP formatting is deliberately set to never, so a newly attached server cannot silently change save behavior.
nvim-lint runs once on BufWritePost. Ruff supplies Python diagnostics. Pydoclint and Codespell join only when their executables exist, avoiding noisy missing-tool warnings.
nvim-cmp gathers sources and LuaSnip expands snippets. None-ls was not part of this path, so removing it does not remove completion.
Snacks owns general notifications. Fidget owns LSP progress. Noice owns the command line and message history, with its notification forwarding and LSP progress disabled.
<leader>fb and <leader>nt both open Snacks Explorer, preserving muscle memory while removing nvim-tree and Telescope file-browser.
ToggleTerm owns splits, tabs, floats, and named sessions for btop, IPython, iotop, Lazydocker, nvtop, and rmpc. Snacks Terminal remains explicitly disabled.
The configuration uses two mapping paths. The deciding question is whether the mapping requires a plugin.
Editing motions, workspace operations, LSP calls, and local helper commands use vim.keymap.set inside lua/core/keymaps/.
Telescope, Snacks, CodeCompanion, images, Diffview, and terminals declare mappings in their Lazy keys tables. The mapping becomes the load trigger.
map("n", "<leader>ca", vim.lsp.buf.code_action, { desc = "Code action", })
keys = {
{ "<leader>fb", function()
Snacks.explorer()
end, desc = "File browser" },
}Every file in lua/plugins/ returns one plugin spec. The spec keeps the trigger, dependencies, mappings, options, and exceptional setup in one navigable place.
opts for ordinary setupWhen a plugin follows require(module).setup(opts), its configuration stays declarative. Lazy can merge it and call setup at the correct time.
return { "stevearc/conform.nvim", opts = { -- formatter policy }, }
config for real orchestrationToggleTerm needs named terminal objects and a terminal-buffer autocmd. That lifecycle is real behavior, so a focused config function is justified.
config = function(_, opts) require("toggleterm").setup(opts) -- create named sessions once end
The cleanup favors replacement over compatibility layers. Old aliases remain where useful, but dead modules and duplicate owners do not.
One browser, two preserved entry mappings.
Search stays focused on pickers and discovery.
General messages move to the plugin already loaded at startup.
Formatting, linting, and completion now have separate owners.
One in-editor AI workflow remains, alongside Copilot completion.
Less indirection between a key and the behavior it invokes.
Run these from ~/.config/nvim. Each check covers a different failure class: style drift, static mistakes, or startup integration.
stylua --check .luacheck .jq empty lazy-lock.jsonnvim --headless -i NONE -u ./init.lua '+qa'