Neovim from scratch / part 1
Rebuilding my Neovim config from scratch (Part 1: Options)
I deleted my whole Neovim config and started over on 0.12: no plugin manager, and I want to understand every line. Part 1 is the boring but essential layer, editor options.
I deleted my entire Neovim config. On purpose. All thirty-odd plugins, gone.
Here’s the thing. I could use my editor just fine, but I couldn’t explain it. Somebody else’s dotfiles, copied three years ago, decided how my LSP worked, and I’d been nodding along ever since. It all worked great, right up until something broke. Then I’d stare at it like a raccoon looking at a doorknob. Not a great feeling for the tool I spend eight hours a day in.
Honestly, I might have kept nodding along forever. The push came from my good friend, the one and only Sam, who’d been quietly evangelising the build-it-yourself route for ages. He finally wore me down.
So: clean slate. And since I’m starting over anyway, I’m doing it the stubborn way:
- From scratch. Empty folder. I type every line myself, and if I can’t say why it’s there, it doesn’t go in.
- No plugin manager. Neovim 0.12 ships its own built-in one now (
vim.pack), plus native LSP. So I’m skipping the third-party stuff entirely. Fewer moving parts I haven’t read. (Much more on that later. It deserves its own post.)
This is Part 1. No plugins yet, no fancy colours, no LSP. Just the plain editor settings: the least exciting layer, and also the one I touch every day. Let’s get the boring foundation right.
The one trick: vim.opt
Every Vim setting you’ve ever seen written as :set something has a Lua twin:
vim.opt.number = true
That’s… basically it. The whole “options file” is just a few dozen of those, grouped so future-me can find things. Mine lives at lua/dilee/core/options.lua and runs on startup. (How the files wire together is a later-post problem. For now, just trust that this one loads.)
The file
local opt = vim.opt -- so I can type `opt.x` instead of `vim.opt.x` forty times
-- Line numbers
opt.number = true -- real number on the current line
opt.relativenumber = true -- distance-from-cursor on the rest (hybrid mode)
-- Indentation
opt.tabstop = 2 -- a <Tab> looks like 2 columns
opt.shiftwidth = 2 -- one indent (>>, <<) = 2 columns
opt.expandtab = true -- spaces, not real tabs (fight me)
opt.autoindent = true -- new lines keep the previous indent
opt.smartindent = true -- ...and bump in a level after `{`, `if`, etc.
-- Search
opt.ignorecase = true -- case-insensitive by default...
opt.smartcase = true -- ...until I type a capital letter
opt.hlsearch = true -- light up all the matches
opt.incsearch = true -- jump to matches as I type
-- Appearance
opt.termguicolors = true -- 24-bit color (modern themes need it)
opt.signcolumn = "yes" -- always show the left gutter (no jumpy text)
opt.cursorline = true -- highlight the line I'm on
opt.scrolloff = 8 -- keep 8 lines of breathing room around the cursor
opt.colorcolumn = "100" -- a vertical line at column 100 to nag me
-- Splits
opt.splitright = true -- vertical splits open right
opt.splitbelow = true -- horizontal splits open below
-- Quality of life
opt.mouse = "a" -- yes I use the mouse sometimes, sue me
opt.clipboard = "unnamedplus" -- y and p use the system clipboard
opt.undofile = true -- undo history survives closing the file
opt.swapfile = false -- no .swp litter; undofile + git is plenty
opt.updatetime = 250 -- faster CursorHold (250ms, not 4 whole seconds)
opt.timeoutlen = 400 -- how long to wait mid-keybind-combo
opt.confirm = true -- :q with unsaved changes asks instead of yelling
The four that actually matter
Most of these you set once and forget forever. But a few changed how the editor feels, so here’s where I’d spend your attention:
Hybrid line numbers (number + relativenumber). The current line shows its true number. Every other line shows how far away it is. And that distance is the keystroke: a line labelled 5 is exactly 5j away. This is the setting that finally made Vim motions click for me.
smartcase is sneaky-good. Search is case-insensitive… until your query has a capital in it, then it snaps to case-sensitive. So error finds everything and Error finds just the shouty one. Two behaviours, zero brain effort. Love it.
signcolumn = "yes". Turn this on and never think about it again. Leave it off and the instant a git or error icon shows up, your whole file lurches one column to the right. Small thing. Will drive you up a wall once you’ve noticed it.
clipboard = "unnamedplus" is the one that connects Vim to the rest of my laptop. Now y and p talk to everything else like a normal program. If you’ve ever copied something in Vim and paste-failed into Slack one too many times, this is your fix.
Go break something
Best part of starting this low: the feedback loop is instant and impossible to mess up. Open this file, change colorcolumn to "80", save, reopen. The line moves. No “reload plugins,” no restart-the-LSP dance. It’s just the editor doing what you told it.
That tiny dopamine hit is exactly why I’m building from the floor up instead of pasting a 2,000-line config and praying.
Next time: keymaps, the shortcuts that turn a stock editor into mine, plus a quick tour of Vim’s modes for those of us who are, let’s be honest, still not fluent.
Cheers!
Comments
Comments require a GitHub account. No GitHub? Reply on Substack or email me.