I always see Vim as a tool that offers a marginal return on investment: Maybe it will save one or two hours one time in a year, but software development is never really about saving time while coding. We spend more time about reading than writing, besides countless hours spent debugging, testing, planning, discussing, polishing. So I thought, why bother? Why bother learning all those unintuitive keybindings, cryptic configurations, and leaving all those modern user-friendly features that I already mastered in VSCode/IntelliJ/Sublime Text? I know and use a lot keyboard shortcuts in VSCode anyway, why would make my life harder? I can spend my precious time learning something new and useful instead.
But, there is also always another feeling: the fear of missing out. When I was working a repetitive and unchallenging project, I felt like it is a good time to try something new. My main motivation was being able to stop using mouse for everything. This comes from a place of laziness, rather than productivity. The path of least resistance so to speak.
I started with Neovim VSCode plugin to avoid being too revolutionary. This was not my first attempt to try Vim, so I knew I needed pass beyond replacing my arrow key movements with hjkl. I needed to be able to internalize the movements and selections and commands. So I mainly focused on grasping the main philosophy of key movements:
d (delete), y (yank), c (change), p (paste)w (word), $ (end of line), 0 (start of the line), gg (top of file), G (end of file), f (find character), t (till character), i (inside), a (around)As I started to feel like I'm depending less and less on hjkl, something unexpected happened: My brain was started to talk to me in Vim commands. For instance:
delete inside "yank around 'change till .This was a major breakthrough. Suddenly I was on the Vim train, going full speed ahead.
I've also faced a dilemma at start to how to configure my Neovim setup. It is by far the most intimidating part of the adoption. There are a lot of out of the box solutions that are very good, but choosing one meant that I would struggle greatly when I want to scratch my own itch. My solution is a single file configuration which consists of 3 sections:
Here is some part of my global settings section:
vim.opt.scrolloff = 8 -- minimal number of screen lines to keep above and below the cursor
vim.opt.number = true -- show line numbers
vim.opt.relativenumber = true -- show relative line numbers
vim.opt.tabstop = 2 -- number of spaces to a TAB counts for
vim.opt.softtabstop = 2 -- number of spaces a tab counts for while performing editing operations
vim.opt.shiftwidth = 2 -- number of spaces a use for each step of indent
vim.opt.expandtab = true -- expand tabs into spaces
vim.opt.smartindent = true -- better autoindenting
vim.opt.cursorline = true -- adds a highlight to the current line
vim.opt.virtualedit = "block" -- allow cursor to move where there is no text in visual block mode
vim.opt.cmdheight = 0 -- hide the command line when it is not active
vim.g.mapleader = ' ' -- set leader key to space
vim.opt.termguicolors = true -- enable 24-bit RGB colors
vim.opt.pumheight = 10 -- Sets the number of items in the popup menu
vim.opt.diffopt = "internal,filler,closeoff,indent-heuristic,linematch:60,algorithm:histogram" -- better diff algorithm
vim.diagnostic.config({ virtual_lines = { current_line = true } }) -- show virtual lines for diagnostics
Certainly, using Neovim in VSCode felt like the best of both worlds. The plugin ecosystem of VSCode was unbeatable, and Vim style word editing was very powerful. But I hit a wall when I wanted to go all in with the keyboard movements. It became tricky to switch between terminal, git view, explorer view. It is possible to set keybindings in neovim to trigger VSCode commands, but somethings were not possible. This intermediary state was good while it lasted, but it was time to leave all behind.
Moving to Neovim as my main IDE is no different than moving to a new flat. I quickly realized that I needed these things, to stop feeling like I'm wasting my time:
Very quickly I realized that most of these features are not built-in, and the plugins are the only 'reasonable' way to achieve these functionalities.
Here is the rough list of plugins that I use to add the features I need:
neovim/nvim-lspconfig: Helps to easily configure language servers. This gives you all ability to show diagnostics, go to definition, show references, hover for documentation etc.
williamboman/mason.nvim: Easily install LSP servers, linter, and formatters. None of the LSP servers are bundled, so you need to install them in your machine. Mason makes it very trivial to install and list all available tools. You can even configure to auto install some of them when you are on a new machine.
nvim-treesitter/nvim-treesitter: Treesitter is what makes Neovim very powerful. It builds an AST (abstract syntax tree) of your code, which highlights code based on syntax, and helps you treat the part of the code as native objects so that you can have a keybinding to change inside a function, copy a definition, yank a if block. This brings you endless possibilities.
nvim-treesitter/nvim-treesitter-context: VSCode has a feature that applies a sticky header to the top of the editor if you are inside a function or class or any other contextual block. To have that in Neovim, this plugin is a must.
folke/ts-comments.nvim: Adds ability to comment out code blocks.
echasnovski/mini.ai: Simplify all treesitter objects manipulations. Define your own AST objects and manipulate them with ease.
echasnovski/mini.surround: Replace, add, delete a surrounding character like quotes, tags, brackets.
L3MON4D3/LuaSnip: Do you have VSCode snippets? Just port them using this plugin. Lua snippets are quite hard to write and read, so I stick to VSCode standard.
chrisgrieser/nvim-spider: Annoyed that your camelCase variables are treated as a single word? Here is how to change this behavior.
lewis6991/gitsigns.nvim: Annotates the modified/added/deleted/staged lines of code in the gutter.
folke/which-key.nvim: You kind of know how a keybinding starts but don't know what's the next key supposed to be? This lifesaver plugin displays the all possible options and teaches you about all other keybinding combinations. If this plugin did not exist, I am not sure if I would have been so adamant about Neovim.
nvim-lualine/lualine.nvim: Allows you to configure the bottom of a window to show information you care about the current buffer: Number of changed lines, current line/column number, file type, git branch etc.
folke/snacks.nvim: This plugin pack includes a file picker and other small utilities which enables you to program your DX the way you want. Amongst all the file pickers, this has the most sane defaults. And it is very easy to extend using its well documented API.
webhooked/kanso.nvim: My choice of theme. The killer feature for me that it supports both light and dark mode based on system preferences if you are using a terminal that supports it (like Ghostty or Kitty).
nvim-neo-tree/neo-tree.nvim: Are you missing a file explorer? Do you find the native way of renaming or moving a file tedious? This plugin checks all the boxes for me.
folke/trouble.nvim: Creates a list for diagnostics and references. Very useful if you have adopted edit-compile-run cycle.
saghen/blink.cmp: Autocomplete plugin that does not make you scream into the void.
nvim-pack/nvim-spectre: A search and replace plugin that works in a directory. If you are not a huge fan of using rg and sed in terminal for that purpose, and you want a more visual approach with a preview, this is a must have.
github/copilot.vim: It brings in-file code suggestion using GitHub Copilot.
CopilotC-Nvim/CopilotChat.nvim: Chat with Copilot inside Neovim. Have a conversation with the chatbot and share relevant buffers or context with the LLM.
Along the way, I also noticed that some habits I have must be changed and they cannot coexist in a Neovim universe. For instance, rendering markdown preview is not as straightforward inside of terminal. For that, I built my own app to render a markdown file a browser window (livemarkdown).
Any Emmet tool I've tried so far is also not as good as the native VSCode implementation, so I've stopped using Emmet as well.
In the wake of all advancement in AI agents, I must admit, the gains from learning Neovim is diminishing. I spent less time on writing code manually, and I can rely the agents to do the refactors, which was a selling point for me to learn the Vim way.
But this journey helped me prepare to better collaboration with AI agents. With the existence of these tools, I think the part of the automation that was seen impossible became possible. Text as an intermediary has became so powerful, even when it does not follow a strict structure. Therefore being able to manipulate text, and treating code or requirements as part of the production line-like manufacturing, unlocks a new skill that complements AI agents very well.
Besides, writing code is only a small part of software development, and knowing Vim will not make you a better developer at the end of the day. VSCode, IntelliJ, or Cursor are very good IDEs that do the job well.
My biggest takeaway is that, using Neovim helped me understand the Vim philosophy better and I saw how revolutionary it can be to have a programmable IDE. You can find my configuration here, but hope you find your own way, and build your own IDE that fits you the best.