Neovim plugin specifications and key management

On this page

Describe the problem before adding a plugin. Keeping copied text after deleting something concerns registers; moving between an editor and multiplexer concerns key handoff. A clear task makes it possible to judge existing functionality and the behavioural cost of an extension.

How a plugin specification works

LazyVim merges tables returned from lua/plugins/. Save this as lua/plugins/editing.lua:

return {
  {
    "gbprod/cutlass.nvim",
    event = "VeryLazy",
    opts = {},
  },
}

The repository identifies the plugin, event selects loading time and opts supplies setup options. VeryLazy is a lazy.nvim event, not a promise never to load. Inspect installation and loading with :Lazy, then test the behaviour.

For distribution plugins, override opts or keys where possible. Replacing config can replace existing initialisation logic. Plugin configuration

Group plugins by responsibility

ResponsibilityExamplesVerify
Editing and registerscutlass, yanky, mini-surroundCopy, delete and paste behaviour
Navigationflash, aerialUseful jumps and structure browsing
Git changesgitsignsExact hunk staging and restoration
Language integrationrustaceanvim, roslyn.nvim, flutter-toolsSDKs, project roots and services
Interfacenoice, snacks, smear-cursorRecoverable messages and responsiveness
External servicesclaudecode.nvim, vim-wakatimeIntended actions and data destinations

This is a set of options, not a required installation list. Avoid copying complete defaults for plugins LazyVim already provides. Review and test AI-generated changes like other edits.

Plugins can change familiar actions

cutlass changes how deletion and modification affect registers. Repeat the editing exercise with dd, ciw, yy and p before keeping it. yanky history and the system clipboard provider are separate mechanisms.

flash offers labelled jumps and structural selection. Search, text objects and jump history remain useful when the plugin is unavailable.

gitsigns treats nearby changes as hunks. Staging helps organise a commit; resetting a hunk changes working files, so preview first. Always confirm prepared content with git diff --cached rather than relying only on gutter colours.

Name and scope mappings

Ordinary global mappings belong in lua/config/keymaps.lua:

vim.keymap.set("n", "<leader>uN", function()
  vim.wo.relativenumber = not vim.wo.relativenumber
end, { desc = "Toggle relative numbers" })

n selects normal mode, vim.wo affects the current window, and desc explains the action to hint tools. Check for an existing mapping before choosing the key.

:verbose nmap <leader>uN
:verbose nmap <C-h>

These commands report the mapping and its last definition. For file-specific failures, inspect buffer-local mappings and attachment events. If Neovim never receives the key, inspect the terminal and Zellij instead.

Add one capability at a time

  1. Save configuration and lockfile; choose a small test file or project.
  2. Add one specification and inspect installation/loading.
  3. Perform a task demonstrating the change, such as copy, delete, paste.
  4. Check mappings, startup cost and other file types.
  5. Commit configuration and lockfile if useful; otherwise remove the specification and restore versions.

Reuse the distribution's functional key groups and give actions meaningful names rather than inventing a prefix for each plugin.

Choose language integrations through projects

Start with the language extra, then add project-specific requirements. Roslyn versus OmniSharp, rustaceanvim and flutter-tools all need SDK and project verification. Better behaviour in one large project is conditional experience, not a universal stability ranking.

Continue with language tools, input and navigation integration, or maintenance.