Remember my Neovim quickstart guide? The one with 18 plugins, a Lua file called init.lua that wasn't actually the init file, and a <C-f> mapping to FZF that I, a professional, never installed? Yeah. Neovim 0.12 came out and made about two thirds of that config obsolete. So this post does four things: it revisits what changed, reconfigures everything from scratch, reworks half my plugins into built-in features, and, naturally, re-headaches me in the process. I kept count. You'll see.
Neovim 0.12 ships a plugin manager, as-you-type completion, a one-liner LSP setup, an undo tree, a diff tool and a decent statusline out of the box. My config went from 18 plugins to 3, and it does more than before. The whole thing is below, tested on Neovim 0.12, ready for you to steal. Every red box titled Re-headache is a wall I hit while testing it, so you don't have to.
Revisited: what on earth changed?
Short answer: Neovim kept eating plugins. Long answer: over the last two releases the core team took the stuff everybody installs and baked it into the editor. Here's what happened to my old setup:
And the best thing is that the old config doesn't just look outdated, it straight up errors.
Remember the yamlls hack that called vim.diagnostic.disable() so Helm templates wouldn't scream at you? That function was deprecated in 0.10 and removed in 0.12. So if you copied my old config (you pesky thief), it's been quietly rotting on your disk. The old guide still works on 0.10, nags you on 0.11 and breaks on 0.12. You're welcome.
What you need
First, make sure you're actually on 0.12. Your distro might be a bit behind, especially if you're on one of those "stable" distros that consider 2023 to be the cutting edge.
$ nvim --version | head -1 NVIM v0.12.2
Then the usual suspects. On Arch it's mostly one command now, since half of the language servers made it into the official repos since last time:
sudo pacman -S neovim git gcc tree-sitter-cli ripgrep \
gopls pyright clang rust-analyzer terraform yaml-language-server
yay -S terraform-ls helm-ls-bin jdtls
| Package | Why you want it |
|---|---|
git | The new built-in plugin manager uses it to download plugins |
tree-sitter-cli + gcc | The new nvim-treesitter compiles parsers locally. Install it from your package manager, not npm |
ripgrep | Makes the fuzzy file finder fast (optional, there's a fallback) |
| gopls, pyright, clangd… | The language servers. Install only the ones you need, the config skips the rest |
The rewritten nvim-treesitter doesn't download ready-made parsers anymore, it compiles them. Skip tree-sitter-cli and your first launch greets you with fifteen "ENOENT: tree-sitter" errors in a row, one per parser. Fifteen. I counted, because that's what this post is about now.
Back up your old config before trying this. Future you will thank present you.
mv ~/.config/nvim ~/.config/nvim.bak mv ~/.local/share/nvim ~/.local/share/nvim.bak
Reconfigured: directory setup
Last time we had an init.vim plus a plugged/ folder that grew like mold. This time everything is Lua, and the plugin folder isn't even in your config directory anymore: Neovim keeps it in ~/.local/share/nvim/site/pack/core/opt, where you'll never have to look at it.
~/.config/nvim
├── init.lua ← the entry point (yes, the REAL one this time)
├── nvim-pack-lock.json ← generated, pins plugin versions
├── after/
│ └── lsp/
│ ├── gopls.lua ← per-server tweaks
│ ├── helm_ls.lua
│ └── yamlls.lua
└── lua/
├── options.lua
├── plugins.lua
├── lsp.lua
├── completion.lua
├── treesitter.lua
└── keymaps.lua
mkdir -p ~/.config/nvim/lua ~/.config/nvim/after/lsp
Notice something missing? There's no step to install a plugin manager. No curl-ing vim-plug into ~/.local/share/nvim/site/autoload/ like last time (and yes, vim-plug's file is called plug.vim even on Neovim, which confused me too while writing this). The plugin manager is already there. I'm almost sad, I had grown fond of that command.
The entry point: init.lua
This file does nothing but load the others, in order. Keep it boring.
-- ~/.config/nvim/init.lua
-- Leader goes first, before anything maps with it
vim.g.mapleader = ' '
require('options')
require('plugins')
require('lsp')
require('completion')
require('treesitter')
require('keymaps')
Each require('something') looks for lua/something.lua. No extension, no path. If you get a module not found error, it's a typo in the file name. It's always a typo in the file name.
Options
-- General settings
local o = vim.opt
o.number = true
o.relativenumber = true -- jump with 5j / 12k like a pro
o.cursorline = true
o.signcolumn = 'yes' -- no more text jumping when diagnostics appear
o.scrolloff = 8 -- keep 8 lines visible above/below the cursor
o.mouse = 'a'
o.clipboard = 'unnamedplus' -- share the system clipboard
o.ignorecase = true
o.smartcase = true -- ...unless you type a capital letter
o.tabstop = 2
o.softtabstop = 2
o.shiftwidth = 2
o.expandtab = true
o.undofile = true -- undo history survives closing the file
o.splitright = true
o.splitbelow = true
o.updatetime = 250
o.winborder = 'rounded' -- rounded borders on every floating window
o.pumborder = 'rounded' -- ...and on the completion menu (new in 0.12)
o.pummaxwidth = 50 -- keep the menu narrow so docs fit beside it (new in 0.12)
o.foldlevelstart = 99 -- open files unfolded
vim.diagnostic.config({
virtual_text = true,
severity_sort = true,
float = { source = true },
})
If you compare it with the old one, you'll notice a bunch of lines went missing: nocompatible, ttyfast, syntax on, filetype plugin indent on, hlsearch, incsearch… That's because they've been the default in Neovim for years. I was basically telling my editor to do things it was already doing. Very DevOps of me.
The new ones worth pointing out:
winbordergives every floating window (hover docs, diagnostics, signature help) a rounded border. One option, no plugin.pumborderandpummaxwidthare new in 0.12. Borders on the completion menu, and a width cap so long function signatures don't push the documentation popup off the screen.undofilekeeps your undo history after you close a file. You'll see why that's great in a minute.
Without pummaxwidth, Go's long function signatures make the completion menu as wide as the screen, and the documentation popup gets crammed into a 10-character strip on the left, right on top of your line numbers. It looked like a ransom note. One option, problem gone.
Plugins, the built-in way: vim.pack
This is the headline feature. Neovim 0.12 ships vim.pack, a plugin manager that lives inside the editor. You give it a list of Git URLs, it clones them, loads them, and writes a lockfile. That's it. That's the whole API you need on day one.
-- Plugins, managed by the built-in vim.pack (no vim-plug needed)
local gh = function(repo) return 'https://github.com/' .. repo end
-- Keep treesitter parsers in sync whenever the plugin is installed or updated
vim.api.nvim_create_autocmd('PackChanged', {
callback = function(ev)
local name, kind = ev.data.spec.name, ev.data.kind
if name == 'nvim-treesitter' and (kind == 'install' or kind == 'update') then
if not ev.data.active then vim.cmd.packadd('nvim-treesitter') end
vim.cmd('TSUpdate')
end
end,
})
vim.pack.add({
gh('AlexvZyl/nordic.nvim'), -- colorscheme
gh('neovim/nvim-lspconfig'), -- server configs
{ src = gh('nvim-treesitter/nvim-treesitter'), version = 'main' },
})
-- Opt-in plugins that ship with Neovim itself
vim.cmd.packadd('nvim.undotree') -- :Undotree
vim.cmd.packadd('nvim.difftool') -- :DiffTool
vim.cmd.colorscheme('nordic')
Three plugins. Three. Let's go through them:
- nordic.nvim: the colorscheme. Purely cosmetic, swap it for whatever you like.
- nvim-lspconfig: notice we never call
require('lspconfig')anymore (that's deprecated now). The plugin just ships ready-made server configs in anlsp/folder, and Neovim picks them up on its own. More on that below. - nvim-treesitter, pinned to the
mainbranch: this is a complete rewrite of the plugin and it is not compatible with the old setup. The oldrequire'nvim-treesitter.configs'.setup{}is gone.
The PackChanged autocommand is a hook: whenever nvim-treesitter is installed or updated, it rebuilds the parsers so they match the new version. It's the vim.pack equivalent of vim-plug's {'do': ':TSUpdate'}.
Neovim 0.12 ships :Undotree and :DiffTool, but they're opt-in, and nothing tells you. Type :Undotree on a fresh install and you get "E492: Not an editor command", which is a fun way to find out the feature you read about in the release notes is, technically, there. That's what the two packadd lines in plugins.lua are for.
Updating and removing plugins
To update everything, run this from inside Neovim:
:lua vim.pack.update()
It opens a tab listing every pending change, commit by commit. Read it (or pretend to), then :w to apply or :q to cancel. To remove a plugin, delete it from the list, :restart, and run :lua vim.pack.del({ 'plugin-name' }).
nvim-pack-lock.json records the exact commit of every plugin. If you keep your dotfiles in Git, commit it, and your config will install the exact same versions on every machine. No more "works on my laptop".
LSP: the part that got ridiculously simple
Remember the giant lsp.lua with lspconfig.gopls.setup{}, lspconfig.pyright.setup{} and so on, one block per language? Here's the 2026 version:
-- Language servers: config name -> executable it needs
local servers = {
gopls = 'gopls',
pyright = 'pyright-langserver',
clangd = 'clangd',
rust_analyzer = 'rust-analyzer',
jdtls = 'jdtls',
terraformls = 'terraform-ls',
helm_ls = 'helm_ls',
yamlls = 'yaml-language-server',
}
-- Only enable the ones actually installed, so missing servers don't nag you
for name, bin in pairs(servers) do
if vim.fn.executable(bin) == 1 then
vim.lsp.enable(name)
end
end
-- Helm detection (this replaces the whole vim-helm plugin)
local function in_chart(path)
return vim.fs.root(path, 'Chart.yaml') ~= nil
end
vim.filetype.add({
pattern = {
['.*/templates/.*%.ya?ml'] = function(path)
if in_chart(path) then return 'helm' end
end,
['.*/templates/.*%.tpl'] = 'helm',
['.*/values.*%.ya?ml'] = function(path)
if in_chart(path) then return 'yaml.helm-values' end
end,
},
})
vim.lsp.enable('gopls') is all it takes to turn on a language server. Neovim looks for a file called lsp/gopls.lua somewhere in its runtime path (nvim-lspconfig ships hundreds of them), reads the command, file types and root markers from there, and starts the server whenever you open a matching file.
The loop around it is my own little addition: it only enables servers that are actually installed. In the old config, if you didn't have terraform-ls, Neovim would nag you about it every time you opened a .tf file. Now it just quietly skips it. Install the server later, and it starts working. No config change needed.
Goodbye vim-helm, hello vim.filetype.add()
Neovim knows Terraform files out of the box now, so vim-terraform is gone. Helm templates it doesn't know, because to Neovim a Helm template is just a YAML file with weird curly braces in it. That's where those few vim.filetype.add() lines come in: any .yaml inside a templates/ folder that belongs to a chart (there's a Chart.yaml somewhere above it) becomes a helm file. And that replaces an entire plugin.
Here's the kicker: since your templates are now helm files and not yaml files, yamlls never attaches to them in the first place. Remember that on_attach hack that disabled diagnostics on Helm templates, the one I dared you to remove? Not needed anymore. The problem doesn't exist.
Per-server settings go in after/lsp/
Some servers need extra settings. Each one gets its own small file that just returns a table. They go in after/lsp/ rather than lsp/ so they're loaded after the defaults from nvim-lspconfig, so your settings always win.
-- ~/.config/nvim/after/lsp/gopls.lua
return {
settings = {
gopls = {
analyses = { unusedparams = true },
staticcheck = true,
gofumpt = true,
},
},
}
-- ~/.config/nvim/after/lsp/yamlls.lua
return {
settings = {
yaml = {
validate = true,
completion = true,
-- Auto-detects schemas for GitHub Actions, docker-compose, etc.
schemaStore = { enable = true, url = 'https://www.schemastore.org/api/json/catalog.json' },
-- Kubernetes manifests, matched by file name
schemas = {
kubernetes = {
'*deployment*.{yml,yaml}', '*service*.{yml,yaml}', '*ingress*.{yml,yaml}',
'*configmap*.{yml,yaml}', '*secret*.{yml,yaml}', '*statefulset*.{yml,yaml}',
'*pod*.{yml,yaml}', 'k8s/**/*.{yml,yaml}',
},
},
},
},
}
-- ~/.config/nvim/after/lsp/helm_ls.lua
return {
settings = {
['helm-ls'] = {
yamlls = { path = 'yaml-language-server' },
},
},
}
The YAML one also got smarter. Instead of the seven hard-coded schema URLs I had before, yaml-language-server understands the magic word kubernetes for K8s manifests, and schemaStore automatically picks up schemas for GitHub Actions, docker-compose, GitLab CI and a few hundred other formats.
The keymaps you get for free
You don't have to map any of this. As soon as a server attaches, these just work:
| Keys | What it does |
|---|---|
| K | Hover documentation |
| grn | Rename symbol everywhere |
| gra | Code actions (quick fixes, auto-imports…) |
| grr | Find references |
| gri | Go to implementation |
| grt | Go to type definition 0.12 |
| gO | Document outline (all functions, types, etc.) |
| Ctrl+] | Go to definition |
| Ctrl+S (insert mode) | Signature help, while you're typing function arguments |
| ]d / [d | Jump to next / previous diagnostic |
| Ctrl+W d | Show the diagnostic under the cursor in a float |
And if something isn't working, run :checkhealth vim.lsp. It tells you which servers are enabled, which ones attached to which buffer, and why the others didn't. It's the first place to look before you start blaming your config. Or me.
Reworked: completion without nvim-cmp
This is the one I was most skeptical about. The old setup used nvim-cmp plus five companion plugins and a 60-line config I had mostly copy-pasted from a README. In 0.12, the editor can show a completion menu as you type, all by itself, and it can pull suggestions from your language server. Here's the whole thing:
-- Completion without nvim-cmp (or its five friends)
vim.o.autocomplete = true -- pop the menu as you type
vim.o.complete = 'o^10,.^5,w^5,b^5' -- LSP first, then open buffers
vim.o.completeopt = 'menuone,noselect,popup,fuzzy'
vim.o.pumheight = 12
-- Let the LSP apply snippets, auto-imports & docs when you accept an item
vim.api.nvim_create_autocmd('LspAttach', {
group = vim.api.nvim_create_augroup('rs.completion', {}),
callback = function(ev)
local client = assert(vim.lsp.get_client_by_id(ev.data.client_id))
if client:supports_method('textDocument/completion') then
vim.lsp.completion.enable(true, client.id, ev.buf, { autotrigger = false })
end
end,
})
-- <Tab>/<S-Tab>: move through the menu, or jump through snippet fields
local function tab(dir, key, fallback)
return function()
if vim.fn.pumvisible() == 1 then return key end
if vim.snippet.active({ direction = dir }) then
return ('<Cmd>lua vim.snippet.jump(%d)<CR>'):format(dir)
end
return fallback
end
end
vim.keymap.set({ 'i', 's' }, '<Tab>', tab(1, '<C-n>', '<Tab>'), { expr = true })
vim.keymap.set({ 'i', 's' }, '<S-Tab>', tab(-1, '<C-p>', '<S-Tab>'), { expr = true })
-- <CR> accepts only an item you picked with <Tab>; otherwise it's a normal Enter
vim.keymap.set('i', '<CR>', function()
if vim.fn.pumvisible() == 1 and vim.fn.complete_info({ 'selected' }).selected ~= -1 then
return '<C-y>'
end
return vim.fn.pumvisible() == 1 and '<C-e><CR>' or '<CR>'
end, { expr = true })
-- <C-Space>: open the menu on demand (LSP if attached, otherwise buffer words)
vim.keymap.set('i', '<C-Space>', function()
return vim.bo.omnifunc ~= '' and '<C-x><C-o>' or '<C-n>'
end, { expr = true })
-- Command-line autocompletion for :, / and ?
vim.o.wildmode = 'noselect:lastused,full'
vim.o.wildoptions = 'pum'
vim.api.nvim_create_autocmd('CmdlineChanged', {
pattern = { ':', '/', '?' },
callback = function() vim.fn.wildtrigger() end,
})
The interesting bits:
vim.o.autocomplete = trueis new in 0.12. It pops the completion menu up as you type, no key needed.complete = 'o^10,.^5,w^5,b^5'tells it where to look, in order: the LSP first (o, up to 10 items), then the current buffer, other windows and other open buffers (5 each). One menu, every source, ranked.vim.lsp.completion.enable()doesn't open the menu here (autocompletealready does that), but it makes accepting an item apply the extra goodies: snippet expansion, auto-imports and the documentation popup.- Tab / Shift+Tab move through the menu, and jump between snippet fields when there's no menu. Enter only accepts an item you actually picked with Tab. If you didn't pick anything, it's a normal Enter and you get your new line. (My first version accepted the top suggestion on every Enter. Typing a new line and getting
ListenAndServeTLSinstead gets old fast.) - Ctrl+Space opens the menu on demand, for when you haven't typed anything yet. That one's my mapping, not a default: it asks the LSP if there is one, and falls back to words from your open buffers.
http.Lis in Go: gopls suggestions, function signatures and the docs popup, without a single completion plugin. And the bottom part gives the command line the same treatment. Type :, / or ? and suggestions appear while you type. That's what cmp-cmdline used to do, and fun fact: the old config configured cmp-cmdline but never installed it. I was on fire back then.
Treesitter
Highlighting is now handled by Neovim itself. The nvim-treesitter plugin's only job is to download and compile parsers (that's why you need tree-sitter-cli). You turn highlighting on yourself, which sounds like more work but is actually just one autocommand:
-- Treesitter: parsers from nvim-treesitter, highlighting from Neovim itself
require('nvim-treesitter').install({
'go', 'python', 'java', 'c', 'cpp', 'rust', 'lua', 'bash',
'hcl', 'terraform', 'yaml', 'helm', 'json', 'markdown',
})
vim.api.nvim_create_autocmd('FileType', {
group = vim.api.nvim_create_augroup('rs.treesitter', {}),
callback = function(ev)
-- pcall: quietly skip filetypes that have no parser installed
if not pcall(vim.treesitter.start, ev.buf) then return end
vim.wo[0][0].foldmethod = 'expr'
vim.wo[0][0].foldexpr = 'v:lua.vim.treesitter.foldexpr()'
vim.bo[ev.buf].indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()"
end,
})
The first time you start Neovim it'll compile all those parsers in the background. Give it a minute. Make a coffee. The pcall is there so file types without a parser just fall back to normal highlighting instead of throwing errors at you. As a bonus, you also get treesitter-based folding (za to toggle a fold) and smarter indentation.
In visual mode, press an to expand the selection to the surrounding syntax node (the expression, then the statement, then the function…) and in to shrink it again. New in 0.12. Try v then an an an inside a function. Once you get used to it, there's no going back.
Keymaps, and the stuff I didn't know Neovim could do
Here's where it gets fun. This is the part where I found out Neovim could do way more than I thought.
local map = vim.keymap.set
-- File tree: netrw as a sidebar (goodbye NERDTree)
vim.g.netrw_banner = 0
vim.g.netrw_liststyle = 3
vim.g.netrw_winsize = 25
map('n', '<C-t>', '<Cmd>Lexplore<CR>', { desc = 'Toggle file tree' })
-- Tabs (same as the old config)
map('n', '<C-n><C-n>', '<Cmd>tabnew<CR>')
map('n', '<C-n><C-p>', '<Cmd>tabprevious<CR>')
map('n', '<C-n><C-x>', '<Cmd>tabnext<CR>')
map('n', '<C-n><C-c>', '<Cmd>tabclose<CR>')
-- Fuzzy file finder built on :find (no fzf required)
local files
function _G.RsFind(arg, _)
if not files then
local list = vim.fn.executable('rg') == 1
and vim.fn.systemlist({ 'rg', '--files', '--hidden', '--glob', '!.git' })
or vim.fn.globpath('.', '**', true, true)
files = vim.tbl_map(function(f) return vim.fn.fnamemodify(f, ':.') end,
vim.tbl_filter(function(f) return vim.fn.isdirectory(f) == 0 end, list))
end
return arg == '' and files or vim.fn.matchfuzzy(files, arg)
end
vim.o.findfunc = 'v:lua.RsFind'
vim.api.nvim_create_autocmd('CmdlineEnter', {
pattern = ':',
callback = function() files = nil end, -- refresh the list each time
})
map('n', '<C-f>', ':find ', { desc = 'Fuzzy find file' })
-- The fun stuff
map('n', '<leader>u', '<Cmd>Undotree<CR>', { desc = 'Undo tree' })
map('n', '<leader>f', function() vim.lsp.buf.format() end, { desc = 'Format buffer' })
-- Toggle diagnostic virtual lines with <leader>d
map('n', '<leader>d', function()
local new_config = not vim.diagnostic.config().virtual_lines
vim.diagnostic.config({ virtual_lines = new_config })
end, { desc = 'Toggle diagnostic virtual_lines' })
A file tree without NERDTree
Neovim has always shipped with a file browser called netrw. It's just very ugly by default. Those three netrw_* lines hide the banner, switch to a tree view and make it 25% wide, and the <C-t> mapping in keymaps.lua toggles it as a sidebar with Ctrl+T, the same key I had for NERDTree. That one's my mapping, not a Neovim default, so pick whatever key you like. Press Enter to open a file, % to create one, d to create a folder, D to delete and R to rename.
A fuzzy finder without FZF
This one blew my mind a bit. Neovim has a :find command, and it lets you plug your own function into it (the findfunc option). Mine lists every file in the project with ripgrep and fuzzy-matches whatever you type. Combined with the command-line autocompletion from before, you get a live fuzzy file picker. With my <C-f> mapping from keymaps.lua: press Ctrl+F, type a few letters, Tab, Enter.
:find yaml fuzzy-matching every YAML file in the project. It's under 20 lines of Lua.Undo history as a tree
Here's something most people don't know: Vim's undo history isn't a list, it's a tree. If you undo three times and then type something new, the "redo" branch isn't gone, it's still there, just hidden. Run :Undotree (remember the packadd from Re-headache #4) and it shows you every branch. I mapped it to Space u in keymaps.lua (that's <leader>u, my mapping, not a default). Move the cursor to any state and your file goes back to exactly how it was. Combined with undofile, that works even after you closed the file yesterday. It's basically Git for people who forgot to commit.
Diagnostics you can actually read
By default, errors show up as text at the end of the line. That's fine until a message is longer than your screen. Since 0.11, Neovim can also show diagnostics as virtual lines: the full message on its own line underneath the problem, with a little arrow pointing at the exact spot. It's off by default, though. You switch it on through vim.diagnostic.config():
vim.diagnostic.config({ virtual_lines = true })
I didn't want it on all the time, so the <leader>d mapping at the bottom of keymaps.lua turns virtual lines on and off. The usual end-of-line message stays put, so with it on you get both: the short version at the end of the line and the full story underneath. With the leader set to space, that's Space d. Again: my shortcut, not a built-in one. If you skip that mapping, you won't have it.
E:1 in the statusline: that's the new default statusline counting errors. Bye, lualine.A few more toys
- :restart (or ZR) restarts Neovim right there in the same terminal. Perfect after changing your config, no more quitting and reopening like a caveman. It doesn't reopen your files by itself, though: if you want them back, use
:mksession! Session.vim | restart source Session.vim. - :DiffTool dir1 dir2 compares two files or two whole directories side by side. Great for "what's the difference between these two Helm charts".
- :lsp restart brings a stuck language server back to life (gopls, I'm looking at you). There's also
:lsp stop,:lsp enableand:lsp disable. - :checkhealth now shows a summary at the top. Run it once after setup; it tells you about anything missing (a parser, a server, the clipboard tool…).
Experimental: the new message UI (ui2)
Neovim 0.12 also includes a redesigned command line and message area that gets rid of the dreaded "Press ENTER or type command to continue" prompts and highlights your command line as you type. It's still experimental, so it's not in my config, but if you're feeling brave, add this to init.lua:
require('vim._core.ui2').enable()
If it breaks, delete the line. That's the beauty of experiments.
The first launch
Open Neovim. It'll ask you to confirm installing the three plugins: say yes. Then, once it's done:
- Run :restart so everything loads cleanly.
- Wait for the treesitter parsers to finish compiling (progress messages at the bottom).
- Open a file in a language you installed a server for, and run
:checkhealth vim.lspto make sure it attached.
That's it. No :PlugInstall, no :TSInstall helm, no running things from the terminal because they didn't work from inside the editor. It just installs itself.
Start Neovim with nvim --clean to get a completely default editor, then fix your config from there. And if it's truly cursed, delete ~/.local/share/nvim/site/pack/core and let vim.pack reinstall everything from scratch.
Re-cap
Let's take stock. The old config had 18 plugins, a plugin manager installed with curl, about 220 lines of which a good chunk was copy-pasted from READMEs, and two bugs I didn't know about. Now we only need 3 plugins, a plugin manager that came with the editor, completion with no completion plugin, an undo tree, a fuzzy finder, a diff tool, and roughly the same number of lines, except this time I actually understand every one of them.
Final score: revisited one release cycle's worth of changes, reconfigured ten files from scratch, reworked 15 plugins out of existence, and re-headached exactly four times. Four headaches, all documented, none of them yours anymore. That's a better ratio than the first time around, believe me.
The funniest part is that most of this was hiding in :help the whole time. I spent hours installing plugins for things Neovim was already doing, just because the internet told me to. So I guess every once in a while, reading the release notes comes in handy, doesn't it?. Run :help news right now. You might find your next favorite feature. Or a function you're using that just got removed.
And because copy-pasting ten files out of a blog post is just a hassle, I made stealing my config very hard for you and it now lives in a public repo, RattleNvim. It even has a ./install.sh script to make things even more inconvenient for you. Basically it checks you're on Neovim 0.12, backs up whatever config you had into ~/.config/nvim-old-config.tar.gz, and moves in. Bear in mind that that's my daily driver, not the lab version from this post, so it basically means it's very opinionated. That and also that a couple of old friends sneaked back in (Telescope for its popup, nvim-tree for its icons and kanso dark theme because I have feelings), so it runs 8 plugins instead of 3. Still a long way from 18. My secrets are yours too, but keep them between you an I, alright?
As always, take the config, break it, make it yours. And if you find another hidden gem, you know where to find me. Keep coding!
Comments
Post a Comment