If you want your Vim line numbers to be relative and/or not relative at the correct times, I recommend installing the myusuf3/numbers.vim plugin.
When editing text in a Vim window, I use relative numbers to help me use motions across text relative to my cursor. However, when I have multiple windows open, relative numbers look pretty weird in windows that I am not currently editing. It would be nice for Vim to intelligently alternate between relativenumber and norelativenumber based on my Vim cursor location. Base Vim does not have this capability, so we have three options:
- Accept a suboptimal workflow
- Wrap our own solution in our .vimrc
- Find a Plugin
I lived with option 1 for a while, but eventually grew too annoyed. I then tried researching plugins, but thought I understood the problem well-enough to write my own solution. So I went straight to option 2 and tried wrapping my own solution.
Wrapping my own solution¶
The following code represents my original solution:
function! ToggleRelativeNumber() if &rnu set norelativenumber else set relativenumber endif endfunction function! RNUInsertEnter() if &rnu let w:line_number_state = 'rnu' set norelativenumber else let w:line_number_state = 'nornu' endif endfunction function! RNUInsertLeave() if w:line_number_state == 'rnu' set relativenumber else set norelativenumber let w:line_number_state = 'nornu' endif endfunction function! RNUWinEnter() if exists('w:line_number_state') if w:line_number_state == 'rnu' set relativenumber else set norelativenumber endif else set relativenumber let w:line_number_state = 'rnu' endif endfunction function! RNUWinLeave() if &rnu let w:line_number_state = 'rnu' else let w:line_number_state = 'nornu' endif set norelativenumber endfunction " autocmd that will set up the w:created variable autocmd VimEnter * autocmd WinEnter * let w:created=1 autocmd VimEnter * let w:created=1 set number relativenumber augroup rnu_nu autocmd! "Initial window settings autocmd WinEnter * if !exists('w:created') | \setlocal number relativenumber | \endif autocmd User Startified setlocal number relativenumber " Don't have relative numbers during insert mode autocmd InsertEnter * :call RNUInsertEnter() autocmd InsertLeave * :call RNUInsertLeave() " Set and unset relative numbers when buffer is active autocmd WinEnter * :call RNUWinEnter() autocmd WinLeave * :call RNUWinLeave() augroup end
The solution worked for most windows and tabs, most of the time.
The code is a bit involved and it takes a little time to explain to others.
- It relies on window-local variables (w:line_number_state, etc). These exacerbate Vim’s already-difficult state-management woes.
- Several global functions are defined
- There are some quirks I don’t fully understand around the creation of variables during Vim startup (hence lines 50 and 51).
Despite these mild downsides, I was pretty proud that the solution mostly worked. That is, until I wasn’t.
The back-breaking straw¶
My custom solution did not work appropriately with some of my plugins. Namely, it didn’t play well with majutsushi/tagbar, which I use frequently enough for this feature-dearth to become royally annoying. Therefore, after learning the ins-and-outs of window-specific variables and every Vim autocmd, I went back to the Plugin ecosystem to see if I’d missed anything…
The Game-Changing Plugin¶
Turns out a wonderful developer already solved this problem for me. Assuming you use junegunn/vim-plug to manage your plugins, place the following code in your .vimrc
call plug#begin('~/.vim/plugged') " Relative Numbering Plug 'myusuf3/numbers.vim' " Put the rest of your plugins below... call plug#end() " Now, exclude the plugins you don't want numbers to deal with let g:numbers_exclude = ['startify', 'gundo', 'vimshell']
This will give you a great editing experience. See below for a screencast:
Numbers.vim provides a usable line-numbering solution with minimal required configuration. I regret nothing about my bespoke journey, but I’m glad that Numbers.vim is my destination.