The Groundbreaking Vim Experience

Eduardo Rodrigues
12 min readApr 22, 2023
A screenshot of my current Neovim setup

It is April 20th as I am writing this and it has been exactly 300 days since I ditched VS Code for Vim! It was not a time milestone I was actually looking for, but rather a coincidence with the day I feel like showing up to my Medium again.

I actually didn’t stick with Vim. One month later I moved to NeoVim, which is basically a more elegant fork of Vim.

The first commits on my nvim configs repository.

From the Awkward Mousing to the “Constraint” Keyboard

Probably most people — myself included — first find it really odd for someone to stop relying on their mouse… Why would you abandon the simplicity of moving your cursor to click, select and drag all you want to having to memorize all those random keystrokes?

While using VS Code, although I had all those outline visualization, tabs, basic Git operations, nice extensions like GitLens; just to name a feel. But I never felt I was managing to do what I want.

Fixing a simple issue in VS Code with keyboard and mouse.
Fixing a simple typo by letting the keyboard go, picking the mouse, selecting the word I wanted to fix and then going back to the keyboard to type again. Very tiring!

I am sure you got some flashbacks right there too. It happens all the time when you are editing your files. Sure, you could have made it much faster with regular key binds — Ctrl-ArrowLeft until you reach the word, Ctrl-Shift-ArrowLeft to select your text and start typing again — but let’s be honest, when you have the option to just use your mouse that is right next to you, that’s going to be your first instinct.

For me, it felt clunky. I always felt awkward when I did that, and I didn’t knew why because I thought that it simply is what it is… Until it’s not!

The Voluntary Restriction

When you first startup your Vim session, you will be veeeery slow. You can’t use your mouse, the key bindings are strange, got to keep track of which mode you’re in and what you can do in each of them…

There is much to learn there yet, so let’s give it a fair shot. Once you understand the semantics of the actions you can take, everything starts feeling natural.

See what I did there? I jumped to the word I wanted and changed it to another that shows more excitement! For the sake of curiosity, those are the steps it took after typing the whole line:

  • <C-[> — Go to NORMAL mode;
  • Fb — Find a character (b) before the cursor in the current line;
  • ciw — Change inside word (basically erasing it and going into INSERT);
  • amazing — What I wanted to type.

At this point you might argue that this is too much to think about, and I don’t disagree with you. Vim is something you have to want to learn for it to become usable, and this is a great drawback for many people.

Learning To Learn

I have a couple of personal experiences with learning very specific things out of curiosity, but let’s talk about simple typing. No, I am not talking about no special keyboard layout, or hotkeys. Just typing in a regular QWERTY keyboard.

Do It Right, Then Do It Fast

Back in 2020, I used to type at 38 words per minute (wpm), which is slightly under the average — 40 wpm. It bothered me a lot. I wanted to type fast… Just for the sake of typing fast.

With that in mind, I started practicing at keybr.com.

My actual account. This is not a sponsor.

It’s been a while since the last time I did a session, but I tried a quick speed test just to see if I am still in form.

Not bad at all!

Kind of an improvement for someone who was under the average, right? But it wasn’t as quick as you might think, it actually took me over 4300 sessions across two months of consistent training.

My progress at keybr.com going from 38 words per minutes to 100.

And how did I get there? The secret was to do it slowly on purpose.

But you wanted to go fast! Why go slow on purpose???

Well, imaginary reader I made up in my head, the section title says it all: you gotta do it right before doing it fast.

Analyzing the graph above, you can see my typing speed rapidly increases over the first 500-or-so sessions and then slowly improves over the course of the remaining ~3800 following.

From the moment I learned to type the right way — carefully positioning my fingers in the keyboard’s home row and using each finger for the appropriate key — I drastically speed up my moves, and than the rest is basically getting confident enough, which then became fast naturally.

I wouldn’t get anywhere near that if I didn’t watch my steps — I would burn myself out trying to improve upon the wrong practices. But why am I telling you all this when this article is about Vi-like editors?

Let’s See What’s That Vim Thing…

Trust the Process and You Won’t Be Let Down

When I picked up Vim, I did the same practices. I read a bunch of articles like FreeCodeCamp’s beginner’s guide and had all sorts of cheatsheets by my side.

On the first two weeks, I didn’t have the confidence to integrate it on my job’s workflow. I would just end my shift, pick a random file in my projects folders and start typing random non-sense on a buffer just to get the hang of it.

Doing random movement in a file. Deletions, selections, anything about Vim’s bindings

This phase was filled with tutorials, plugin experimentation, remaps and all sort of stuff. I was getting to know what I liked about it!

Respect the Learning Curve

Trying to dive into Vim at once would just overwhelm a person. After those first two weeks I started feeling excited about making it my full-time editor — but I knew it was too early.

What I did instead was integrating it in my workflow when doing small tweaks in files or so. Changing a version of a package? No problem!

Upgrading a NPM package with Vim.

For us that already got stuck on Vim in the past: I embraced those situations and started writing my commit messages this way.

Using git commit without a message flag, so I would enter a Vim session automatically to write a message there.

Those steps are great at getting you comfortable with Vim’s Mode system.

Could There Be Something Better Than Vim?

As you might have guessed, Vim did become my main text-editor at the time. VS Code was secondary for when I really needed speed — by that time I still wasn’t getting those speed buffs.

Vim is a really old text-editor, which is another issue for many people who think about adopting it. I would always get some weird problems on whitespaces. Vim’s syntax highlight implementation is not as up-to-date as it could be too.

Well, I kinda spoiled that part in the beginning but… Let’s talk about NeoVim!

A Much Better Starting Point

NeoVim fixed everything wrong with Vim without losing its charm. It has Treesitter for syntax highlighting, configs and plugins written in Lua, and has a more open-source approach when compared to Vim’s maintenance, which resulted in a much more accelerated overall improvement.

The Bloat Versus The Minimal

NeoVim has many distros like LunarVim or LazyVim. For many it is a great starting point, as it aims to feel like a fully-featured IDE or an extension-loaded VS Code.

LunarVim
LunarVim workspace example.

I don’t know if this is a hot take or not, but I think it is a bad idea to start with those. They usually enable mouse out of the box and assign common bindings like <C-s> to save as well. Sounds great in theory, but in the end you are just stuck with old habits again.

We expect new things to work the way we are used to. This is essentially what these distros try to do for you. This is what most people transitioning from VS Code or IDEs do when setting a NeoVim configuration.

I am not saying I was free from it. Even though I never liked those fully-featured distros, in my first setting an NeoVim configuration I would put NvimTree on the left while a terminal instance would be fixed at the bottom.

It didn’t take much longer for me to get rid of both those permanent panels. More recently — after about 6 months into Neovim — it clicked: I wanted to get rid of all the bloat in my screen.

Descend Into A Minimalist NeoVim Configuration

There are a couple of great reasons to choose a more minimalist approach to your configurations.

If you look into my Neovim’s configurations Git history, you can observe two things:

  1. I tweak it a lot;
  2. I have been removing tons of plugins.

In 300 days I got to use a huge variation of plugins. Barbar, nvim-tree, FTerm, nvim-autopairs, are some that make it to the list.

Even my custom remaps have changed a lot. I used to have jk and kj in Insert mode maps to escape. I also used to like <A-<> and <A->> to navigate between tabs. I removed it all. But why?

Embracing NeoVim as (Vim) is

The comfort of replicating already known experiences was preventing me from really getting to know the Vim bindings.

I’ve been keeping my configurations as close to Vim’s default behavior as possible. Escaping using Esc or <C-[ is reliable. Tabs — when I use them — are fine to navigate with gt and gT.

All those plugins I mentioned — amazing ones, for the record — got removed as well. Did I really needed to have all my opened buffers in tabs on the top of my screen? Did I really need a pinned file tree?

We all learned to like those things. But they are useless. For me it only makes sense to avoid those now. I am getting to know Netrw — Vim’s builtin file explorer — and I love it. Tabs became my way to keep track of different workspaces at once.

Obviously, not everything has to be default. Take a look at my packer file:

return require('packer').startup(function(use)
-- Packer manages itself
use 'wbthomason/packer.nvim'

use 'nvim-lua/plenary.nvim'

use 'nvim-lua/popup.nvim'
use 'kyazdani42/nvim-web-devicons'

-- Indentation markers
use 'lukas-reineke/indent-blankline.nvim'

-- Git wrapper
use 'tpope/vim-fugitive'
-- Git changes on sign column
use 'lewis6991/gitsigns.nvim'

-- Treesitter language parser
use { 'nvim-treesitter/nvim-treesitter', run = ':TSUpdate' }
-- Shows the context of the currently visible buffer contents
use 'nvim-treesitter/nvim-treesitter-context'

use 'ThePrimeagen/harpoon'

-- Undo history tree
use 'mbbill/undotree'

-- Fuzzy finder
use { 'nvim-telescope/telescope.nvim', tag = '0.1.x' }
use { 'nvim-telescope/telescope-fzf-native.nvim', run = 'make' }

-- Status line
use 'nvim-lualine/lualine.nvim'

-- Omni theme
use { 'getomni/neovim', as = 'omni' }

-- LSP
use {
'VonHeikemen/lsp-zero.nvim',
branch = 'v2.x',
requires = {
-- LSP Support
{ 'neovim/nvim-lspconfig' }, -- Required
{
'williamboman/mason.nvim',
run = function()
pcall(vim.cmd, 'MasonUpdate')
end,
},
{ 'williamboman/mason-lspconfig.nvim' },
{ 'jose-elias-alvarez/null-ls.nvim' }, -- For ESLint
{ 'simrat39/rust-tools.nvim' }, -- For Rust
{ 'simrat39/symbols-outline.nvim' },

-- Autocompletion
{ 'hrsh7th/nvim-cmp' },
{ 'hrsh7th/cmp-nvim-lsp' },
{ 'L3MON4D3/LuaSnip' },
},
}
end)

I have my fair share of plugins. For navigating between buffers I don’t want to loose, Harpoon is my companion. Telescope to find very specific files is amazing. LSP Zero concentrates all my language-related plugins in one place.

Most of them are Add-on plugins. Not replacements to existing Vim functionality. None of them do crazy implementations to the regular Vim workflow. Not even autopairs made the cut for me, I’d rather do the pairing myself than allowing plugins to do that for me.

Another thing I like about my setup is that I keep my NeoVim and Vim settings really close to each other. What I mean is that .vimrc is where I actually do my basic settings and remaps for both of them, and simply source it from nvim/init.vim file.

Why Keep It So Simple?

Until now I only showed you my Vim and Neovim setups. I didn’t even have VS Code installed in my personal machine. On my full-time job though, things are a bit different.

Imagine you are a Junior developer who just got into your first job, and your superior opens up Vim to teach you something. My job requires me to teach concepts and implementations to my coworkers. Often it requires showing them code examples.

You would miss everything he says until you understand what is happening, because it is confusing for those who are not used to it. For that, I use VS Code.

But here is the catch: I use VSCodeVim extension, so I actually can be in the comfort of my Vim bindings. Those extensions are pretty basic implementations of Vim, but they mostly do the job. If I have all crazy remaps in my setup, I would get lost upon going into VS Code.

I didn’t thought of that initially, so much so that I lost count of how many times I typed jk to exit Insert mode just to realize I didn’t have this binding in here.

Writing in VS Code with Vim extension on, but miss typing a binding that does not exist.
jk remap is actually awful. Try to write a Dijkstra map implementation with those on…

Many other tools support Vim bindings — Obsidian is another great tool with that option — , but having to figure out how to do remaps for everything is not something I would like to deal with. The default bindings are great, but each has its own learning curve.

A New Way of Thinking

I am Brazilian, so English is my second language. Learning Vim feels like learning a new language. At the beginner level you try to associate the meaning of the words of the new language compared to yours.

So “hello” means “olá”, and “you” means “você”…

After a lot of lessons, it becomes a separate thing. Instead of being associations in your brain you simply think in that new language. I often learn new words and stuff in English. There will be words that I cannot tell immediately what are their equivalents in Portuguese, simply because it doesn’t matter right away.

You don’t think about your mouse while writing software anymore. Instead. Relative lines start making sense, and all your desired changes come in mind in semantic keystrokes:

  • ci< — Change inside angle brackets (<>);
  • va{V — Selecting an entire function;
  • f(;di( — Delete all content inside the second () in current line.

I didn’t memorize all those commands. In fact, I didn’t have to search to write the examples for you. I actually learned what all the components in them mean.

It is not much different from learning programming. When you get to learn JavaScript, you copy all those complicated words, just to understand what they all do way later.

After some struggle, it becomes natural. You won’t be searching “How to insert an item in an array.” You’ve done this before, you know how arrays work, and the .push method naturally comes in mind.

Final Thoughts

I ended up talking more about Vim in general than NeoVim — which I actually use. I just wanted to bring to you the Vim experience as a whole. If you are going to stick with Vim, NeoVim, or even a JetBrains IDE with Vim extension is totally up to you.

Learning Vim made coding exponentially enjoyable to me. I love figuring out new efficient ways to do things — much like learning new combos in a fighting game. The satisfaction is priceless.

If you are willing to join the Vim cult, I highly recommend starting by guides like Learn Vim The Smart Way. Read, practice, search for more content. It was very worth to me, and I think it just might be for you as well.

Feel free to see the configurations I use as well:

Thanks for passing by, and happy coding!

--

--