I am Sang
Learnings after 500 commits to my vimrc

Last winter, on a Saturday, I decided to tweak my vimrc. I'd been putting it off for a long time since I felt spending time on improving and cleaning up vimrc was too luxurious; it'd be fun, but it wouldn't pay back the invested time.

vimrc comic

This time I determined to do myself a favor and enjoy spending a day or two working on my vimrc.

I ended up spending more than three months and making around 500 commits to my vimrc, and I still work on it from time to time – I didn't intend it, but coincidentally it's precisely 500 commits when I try to publish this article.

500 commits

I've learned more than I'd learned in the past ten years during this time.

It was a fun and frustrating journey. I want to share what I've learned along the way and how happy I am now.

Table of Contents

What I have done

I started by deleting unused plugins and configurations, and then I looked for plugins to fix and improve a few things that were bothering me.

Once I got started working on it, I couldn't stop. Learning how things work and improving my daily workflows with the new knowledge was too fun and exciting.

Books

To better understand vim help pages and plugin documents, I started checking out books.

Especially, Learning the vi and Vim Editors was good to brush up on my vim skills, and The VimL Primer was helpful to learn vimscript.

I could access all the books freely thanks to the O'Reilly membership that my employer provides me.

I checked out chapters that interested me instead of reading cover to cover. Reading books with the membership feels like listening to music with a music streaming service instead of having to buy CDs.

vimrcs

I read a few awesome guys' vimrc, such as

I learned many things from the books and vimrcs, but I still often had to read help pages and Stack Overflow threads to achieve what I wanted.

vimscript

I learned that Vimscript is not that hard once you're good with vim.

When I learn a new programming language, I start writing tests with it. This method is called Test-Driven Learning.

Writing test code is an excellent way to learn a programming language because

  1. You learn the testing framework of a language in the early stage.
  2. You learn by writing working code.
  3. You have working documentation.

Vader is a vimscript testing framework that is written by Junegunn. This is my Test-Driven Learning project using Vader: Github project.

I wrote a vim plugin Mintabline to solve a problem that Neovim doesn't show the tabline properly for terminal buffers.

mintabline screenshot

I feel powerful after learning vimscript.

How to troubleshoot vim and plugins

I used to spend hours and days to find out the reason for a vim issue, but now It usually takes no more than 30 minutes using the methods that I'll introduce soon.

Knowing how to fix issues is the key to utilizing vim to its full power – which is valid for any other technology.

I used to keep my plugin list lean to avoid randomly happening errors and slowness; I often didn't know where I should start to troubleshoot a problem.

I've tried tens of plugins for the past few months and faced loads of issues; it sometimes took a few weeks to resolve.

Vim plugins are powerful since they can control vim without having to reside in a sandbox or container, but this makes it harder to debug an issue.

Showing error messages with :message

When you face an issue, the first thing you should do is to read error messages carefully, but an error message could quickly disappear when you do some actions in vim. In this case, you can use the :message command to bring the message back.

However, it's impossible to easily copy the message or have the result window open while troubleshooting. You can load messages into a buffer using this function to tackle this problem (source wiki).

function! TabMessage(cmd)
  redir => message
  silent execute a:cmd
  redir END
  if empty(message)
    echoerr "no output"
  else
    tabnew
    setlocal buftype=nofile bufhidden=wipe noswapfile nobuflisted nomodified
    silent put=message
  endif
endfunction

command! -nargs=+ -complete=command TabMessage call TabMessage(<q-args>)

Once you have the code in your vimrc you can open a buffer with messages like this:

:TabMessage message

or simply

:TabMessage mes

You can use this function not only for messages but also for any other commands. For example, you will get a buffer list in a new buffer when you run this:

:TabMessage ls

Binary search to find a problematic plugin or code

You can try a manual binary search when it's not possible to find the root cause by just reading error messages, which is usually the case.

With this approach, you can search for problematic code by commenting out plugins, functions, or options – half of the code at a time to make it efficient.

To make this task even easier, I've modularized my vimrc (code link).

vimrc diagram

I can quickly turn on and off a specific module with this structure.

These would be steps to debug:

  1. Disable modules or code by deleting or commenting out.
  2. Run vim (in a separate terminal or window).
  3. See if it's fixed.
  4. Go to Step 1 if it's not fixed.

This approach can be applied to any issue when there's no clue.

binary search in practice comic

git bisect to find a problematic commit

git bisect is another way to perform a binary search to pinpoint the cause of an issue.

It works like this:

# Start git bisect
$ git bisect start

# Tell Git that the current commit is bad
$ git bisect bad

# Say, 100 commits ago it was good
$ git bisect good HEAD~100

# Git starts bisecting.
# Run vim and see if the current commit is good
# and tell Git.
$ git bisect good

# Run this until git pinpoints
# the problematic commit.
$ git bisect bad

# Finish git bisect:
$ git bisect reset

It takes only 7 trials for 100 commits (math.log(100, 2) ≈ 6.65).

I prefer this approach to the previous one since it requires less manual work, although I have to check out my Korean blog post about git bisect whenever I run it to recall the commands for each step.

Reading plugin documentation

Surprisingly, reading documentation often works. You can first check out the vim help document of the plugin and see if it has relevant information.

If the plugin doesn't have a help document, visit the GitHub page of the plugin and see if there are any related issues.

To quickly open the GitHub page of a Plug line in vimrc, I use a function and command similar to this:

function! s:open_plug_gh()
  let line = getline('.')
  let line = trim(line)
  let plug_regex = '\vPlug [''"](.{-})[''"].*'
  let path = substitute(line, plug_regex, '\1', '')
  let url = 'https://github.com/' .. path
  exec "!open '"..url.."'"
endfunction

nnoremap <Leader>op :call <SID>open_plug_gh()<CR><CR>

For example, if you run the function on the line below, vim will open the GitHub page of fzf.vim in the browser.

Plug 'junegunn/fzf.vim'

(Advanced) customizing plugin code

If you can't find any meaningful information from the documentation, you can check out the plugin's code. A vim package manager downloads plugin files into your machine, so it's easy to explore the files.

I have a mapping to find installed plugin files quickly with fzf since I do it often.

nnoremap <leader>fpl :FZF ~/.vim/plugged<CR>

You can try fixing the issue directly in the downloaded files and see if it's fixed by reloading plugins or rerunning vim.

Sometimes I had to fix issues only for my environment. For example, the vim-bbye plugin and the close-buffer plugin conflict, but I wanted to use both. I just forked vim-bbye and deleted the conflicting code.

Searching for help

Lastly, you can look for help in a few places.

I once struggled with an issue with Conjure. I thought asking and waiting for an answer would take too long, but it turned out that it was a quicker way to solve the issue.

Looking for a Discord community is another way. I use coc-metals for Scala and was able to get help from the Discord server.

There are fantastic plugin maintainers out there.

Stack Overflow can be helpful as well. Once I even found out the answer to my issue while writing a question.

Improved Productivity

I once made a joke saying that I'll reach a break-even point for the time investment that I made if I write code until 80. That's an exaggeration, but it'll take a long time if I only calculate the saved seconds to recover the time investment.

But, we automate not to save time but to save mental energy; I can try more things with the same time and energy, which reduces problem-solving time.

And, I'm going to write code until after 80 anyway.

Using vim as a File Manager with fzf and nvim-tree

I've tried file managers like ranger and lf, but I did not use them due to a few issues.

After I started using vim as a file manager with fzf and nvim-tree, I realized that this is the file manager that I've been looking for. I can move around and search for tens of projects easily.

nvim terminal as tmux

I haven't been using tmux or screen since they have conflicting keyboard shortcuts with command-line keyboard shortcuts.

When I needed to split a window and open a new session, I could do it with iTerm2 shortcuts. This approach has downsides, but worked okay for me.

With nvim, you can use terminals with customized mappings. Also, it's much easier to search, move around, and copy terminal outputs within nvim terminals.

Git

I've been using tig and the command-line git client with lots of shell aliases and functions.

I'm now using vim-fugitive with vim-rhubarb, git-messenger, gv, fzf (again), and vim-signify. It took a long time to set things up and get used to them, but now the old ways feel ancient.

Coding

These are plugins that I use to write code.

I didn't have many chances to write a large amount of code using vim after I set up these, but they are at least helpful in writing scripts and navigating codebases.

It wasn't always easy to set things up. I spent weeks learning, customizing, and troubleshooting when I started using coc-metals and conjure. I faced a Lua version issue when I tried using coc-lua. Nothing was free but they were worth it.

I've put the plugins for coding in a separate vimrc module (devplugins.vim) so that I can exclude them in the server environment.

Reflection

The most successful people do not have the most productive development environment.

Once I started working on this, I didn't want to do anything else. Sometimes I was obsessed with minor improvements that wouldn't affect my productivity. Still, I think I'm far from mastering vim, and there are tons of things that I can try to tweak my productivity.

I learned a lot even from the effort that didn't work out, but it's essential to know the cost I spend on improving productivity – if I want to be genuinely productive.

40 years

github stackoverflow twitter linkedin email rss