Neovim: Making It Mine

16 May, 2025

Neovim out of the box is powerful, but requires some configuration to truly make it your own. This is how I approached it.

My Neovim configuration is all about control and efficiency. No fluff, just the tools I need to get things done without the editor getting in my way. The goal is a fast, intuitive environment that feels like an extension of my thoughts. You can find the complete configuration in my dotfiles repository.

Laying the Foundation: Getting Started Right

When I decided to properly commit to Neovim, the first step was figuring out how to manage plugins. I landed on Packer.nvim because it struck a good balance between being powerful and not overly complicated. I really appreciate that it can automatically sync plugins whenever I update my init.lua – one less thing to manually manage. My setup involves listing out the plugins I need, like this:

-- In my init.lua, Packer manages plugins like this:
require('packer').startup(function(use)
  use 'wbthomason/packer.nvim' -- Packer itself
  -- ... and then other plugins like LSP, completion, etc.
end)

Beyond plugins, a few core Neovim settings were crucial for making the editor feel comfortable and efficient. For instance, vim.opt.relativenumber = true was a game-changer. Being able to see line numbers relative to my cursor made jumping around with count-prefixed commands much faster than I was used to.

Another small but significant tweak was vim.opt.expandtab = true. This ensures I'm always using spaces instead of actual tab characters, which has saved me from countless headaches when collaborating or switching between different environments. And of course, making sure Neovim plays nice with the system clipboard (vim.opt.clipboard = 'unnamedplus') was a must for a smooth workflow.

Finally, I set my leader key to <Space> (vim.g.mapleader = ' '). It's easy to reach and doesn't conflict with default bindings, making it a great starting point for my custom shortcuts. These initial settings formed the bedrock of a Neovim environment that started to feel truly mine.

Aesthetics: A Personal Touch with Transparency

I like my workspace to feel integrated, and a solid block of editor opaque against my terminal always felt a bit jarring. That's why I opted for a touch of transparency in Neovim. By instructing it not to draw a background for elements like the main editing area (Normal) or my file explorer, my terminal's own transparency can show through. It's a small thing, but it makes Neovim feel more like a natural part of my setup rather than a heavy, separate application. A simple autocmd handles this:

-- Allowing terminal transparency to show through
vim.cmd [[
  augroup TransparentNvim
    autocmd!
    autocmd ColorScheme * highlight Normal guibg=NONE ctermbg=NONE
    " Similar for NormalNC, NvimTreeNormal, etc.
  augroup END
]]

The Brains: LSP, Completion, and Auto-Formatting

For me, a modern editor needs to understand my code. That's where the Language Server Protocol (LSP) comes in. Using neovim/nvim-lspconfig, I get essential features like go-to-definition, finding references, and seeing errors right as I type. It's like having a knowledgeable assistant built-in.

To cut down on typing and mistakes, hrsh7th/nvim-cmp for autocompletion has been invaluable. It pulls suggestions from various places, including the LSP and any snippets I have. This means less time typing boilerplate and more time thinking about the actual logic.

And then there's code formatting. I used to spend so much time manually tidying up my code. Now, with null-ls.nvim and formatters like Prettier, it all happens automatically when I save. This not only saves time but also keeps my projects consistent, especially when I'm jumping between them. My config for these is pretty standard, focusing on getting LSP servers, completion sources, and formatters hooked up.

-- Conceptual setup for LSP (e.g., pyright for Python)
-- require('lspconfig')['pyright'].setup { capabilities = ... }

-- nvim-cmp gets configured with sources like nvim_lsp, luasnip, etc.
-- require('cmp').setup({ sources = ... , mapping = ... })

-- null-ls is set up with desired formatters, e.g., Prettier
-- require('null-ls').setup({ sources = { formatting.prettier } })

Preview:

terminal

Smooth Navigation and Handy Utilities

Moving around a project efficiently is a big deal for me. For a visual overview, nvim-tree.lua gives me a file explorer panel, which I can quickly toggle with <leader>e. It's that familiar tree view that I find helpful for orienting myself in a new codebase.

But when it comes to finding things, telescope.nvim is my absolute go-to. Forget just finding files (<leader>ff); its live grep (<leader>fg) for searching through project content is incredibly fast and the previews are a lifesaver. It's one of those tools that, once you use it, you can't imagine going back.

A couple of smaller plugins also make a big difference in my day-to-day. Comment.nvim for quick commenting (<leader>/) is a simple timesaver. And which-key.nvim is fantastic – it subtly shows available keybindings after I hit my leader key, which has been great for learning my own mappings and discovering what's possible. These little things add up to a much smoother experience.

-- Some of my go-to mappings:
-- vim.keymap.set('n', '<leader>e', ':NvimTreeToggle<CR>')
-- vim.keymap.set('n', '<leader>ff', ':Telescope find_files<CR>')
-- Window navigation mappings like <C-h>, <C-l>, etc.

Preview:

terminal

Smarter Highlighting with Treesitter

I used to think syntax highlighting was just about colors. Then I found nvim-treesitter. Instead of just using regex, it actually parses my code into a syntax tree. The result? Far more accurate highlighting that truly understands the code's structure. This also paves the way for better indentation and potentially more advanced text objects down the line. I've set it to automatically install parsers for the languages I use most. It's a subtle upgrade that makes reading and understanding code just that little bit easier.

-- Enabling Treesitter for better highlighting and indent
require('nvim-treesitter.configs').setup {
  ensure_installed = { "lua", "python", "javascript", "html", "css" /* and others */ },
  auto_install = true,
  highlight = { enable = true },
  indent = { enable = true },
}

Final Thoughts: A Setup That Works For Me

This Neovim setup didn't just appear one day. It's been a journey of tweaking, experimenting, and figuring out what truly makes my coding life easier and more enjoyable. What started as a potentially intimidating editor has become a tool that feels molded to my hands. It's proof that with a bit of patience (and Lua!), even complex tools can be shaped into something personally productive.

Maybe Neovim doesn't entirely suck after all. With the right tweaks, it's pretty sharp.

Preview in the Ghostty terminal

terminal

Preview in Mac's default Terminal app.

terminal