Making a Home out of vim

My relationship with vim started about 6 years ago when I decided Ubuntu was too "easy" and installed Arch Linux on my first laptop. I was drawn to vim for the same reason I was drawn to Arch. I was (and still am) attracted to difficulty with high payoff. Arch was the "harder" version of Linux because it didn't have a graphical install and you had to tweak a lot of settings yourself. These settings had to be tweaked with a terminal text editor and vim appeared to be the "hardest" one to learn because of its modes and commands. These difficulties were advertised as the cost of doing things the "better" way. The communities of both Arch and vim love to claim that once you learn their way you'll never go back.

Maybe I was naive to fall for this allure of doing things the "harder but better" way. Regardless, after this initial exposure to vim, I never could get away from it. I quickly moved on from Arch to more user friendly OS distributions (eventually reaching macOS with my new MacBook), but even after trying several other editors over the years I kept coming back to vim. Even when I used other editors and IDEs I would install plugins to get a similar modal feel to vim. Most recently I used Sublime Text 3 daily for months with a vi plugin, but eventually got annoyed because a couple of my favorite vim commands weren't supported. It was after that experience that I decided I should finally embrace vim whole-heartedly.

The Basics

I already had some basic settings in my vimrc file. Vim without any settings is pretty ugly in my opinion and the settings I already had helped make it just a little more usable. So the first thing I did was clean up the vimrc I already had and search for other ways to change the default behavior to something a little nicer. Here are a few of the key portions of the results.

Tabs → Spaces

I'm pretty firmly on the spaces side of the tabs vs spaces debate, but that's not the subject of this post. The point is I've gotten used to 2 space indentation which makes vim's default 8-space-wide tabs absolutely hideous to me.

filetype plugin indent on
set autoindent
set tabstop=2
set shiftwidth=2
set softtabstop=2
set expandtab
set smarttab

Besides expanding tabs to 2 spaces, the above also displays the tab character as 2 spaces wide, and tells vim to detect the file type and do auto-indentation.

Keeping vim's files out of my way

Vim creates a lot of files to help it do its thing. These include swap files, backup files, info files, and undo files. By default, a lot of these get put into whatever directory you're working in. This can crowd your directories and even your git repo if you don't gitignore everything correctly. Because of this, I like to keep all of vim's generated files in the ~/.vim/ directory. This is a simplified version of this stackoverflow answer.

" Put all files generated by vim in ~/.vim/ dir
if isdirectory($HOME . '/.vim/backup') == 0
  :silent !mkdir -p ~/.vim/backup >/dev/null 2>&1
endif
set backupdir=~/.vim/backup/
set backup

if isdirectory($HOME . '/.vim/swap') == 0
  :silent !mkdir -p ~/.vim/swap >/dev/null 2>&1
endif
set directory=~/.vim/swap//

set viminfo+=n~/.vim/viminfo

set undofile
if isdirectory($HOME . '/.vim/undo') == 0
  :silent !mkdir -p ~/.vim/undo > /dev/null 2>&1
endif
set undodir=~/.vim/undo//

Basic interaction

Despite being a vim proponent, I admit that I still use the mouse a lot, even within vim, so I always keep mouse interaction on. I also make sure backspace works like every other text editing program I have to interact with on a daily basis by allowing it to delete any character.

set mouse=a
set ttymouse=xterm2
set backspace=indent,eol,start

That extra mouse option is because I use vim inside tmux regularly, and resizing vim splits with the mouse doesn't work unless you set the ttymouse property correctly.

Plugins - A Whole New World

After getting some of the basic settings down I started exploring plugins. This is where vim stops looking like just a text editor, and starts behaving more like a fully featured writing environment.

With vim 8, simple package management is included so I didn't have to worry about choosing between Pathogen, Vundle, and Plug. I just jumped straight to vimawesome and started looking for plugins that I would use. Of course, I couldn't pass up the ever popular nerdtree and some git plugins. However, I like performing git actions from the cli, so I passed on fugitive in favor of plain informative git plugins.

Next I found youcompleteme, which adds lots of code completion and exploration commands. Combining youcompleteme with tmux and some plugins to integrate vim and tmux, I practically have an IDE!

Here is the list of plugins I use almost every day.

I'm also still exploring other useful plugins. I'm currently deciding if lightline or something similar is useful, and would like to try out a fuzzy search plugin next!

(Somewhat) Original Features

These might not be totally original, but I came up with these on my own rather than using a plugin or taking a vimscript snippet from someone online.

Profiles

I use vim to code, but I also use vim to write. This presents a dilemma, because I don't want code completion enabled when I'm writing a blog post, and I don't want spell check on when I'm writing javascript.

Furthermore, I recently read about the importance of latency while typing and know that more plugins and settings will likely lead to ever so slightly higher latency. If I load all my plugins and settings at startup when all I need to do is some simple editing, then I'm degrading my typing experience without benefit.

To combat both of the above problems, I have split my vim settings and plugins into "profiles". These "profiles" manifest themselves as separate vim files that enable specific options and plugins. My primary vimrc only has the basics, and some custom commands for sourcing the profile settings.

command Dev source ~/.vim/dev.vimrc
command Prose source ~/.vim/prose.vimrc

This is imperfect, because it's a one way street. There isn't an easy way to undo all the settings in the dev.vimrc file, for example. I don't find myself needing that functionality, though, so I'm pretty happy with the solution.

To support this, I keep all my plugins in the opt plugin folder so that they aren't loaded at startup.

Personal spellcheck dictionary in git

I mentioned above that I also use vim for prose and like to use vim's built in spellcheck. The wordlist that comes with vim doesn't include a lot of domain specific words that I like to use though, like "tmux", so I keep my vim dictionary file in git along with my settings.

Vim uses two files for words you add to your dictionary. One is a plaintext file which can be tracked easily with git, but the other is binary. The binary file is generated from the plaintext file and is what vim actually parses when spellchecking. So, I only want to keep the plaintext one in version control, but need vim to auto-generate the binary one if it doesn't exist yet. This is not built in as far as I know, but the following snippet does the trick (for en_us spellings).

if filereadable($HOME . '/.vim/spell/en.utf-8.add.spl') == 0
  silent mkspell! ~/.vim/spell/en.utf-8.add
endif

The above checks if the binary file (.spl) exists yet, and if it doesn't, generates it from the plaintext file. This assumes the plaintext file exists in that location, but that will always be true if I use my .vim git repo.

Positional tmux pane commands with vmux

I like to put my vim session inside a tmux pane and have two more tmux panes below my vim session. One is usually for running code, and the other is usually for managing the git repo. I usually end up repeating several of the same commands in these two other panes so I found a way (using the vmux plugin) to send these commands without leaving vim.

During my thorough reading (read: light skim) of the vmux readme, I didn't find a way to send commands to other tmux panes based on their position, only by their name. I didn't want to make assumptions about the naming of my tmux windows and panes in my vimrc though, so I started messing around with the plugin. During my experimentation I found out that vmux does support positional pane selection, it just wasn't documented. Check out the below:

nnoremap <leader>r :VmuxSendPrimary bottom-left up<enter>
nnoremap <leader>gs :VmuxSendSecondary bottom-right git space status<enter>

The "Primary" and "Secondary" in the above commands don't actually matter. The above settings define shortcuts that allow me to repeat the previous command in the bottom left pane, and check my git status in the bottom right pane easily without leaving vim. I've used the former several times when making last minute edits to this blog post, to re-upload the html to my s3 bucket.

Wrapping Up

I love improving processes, especially the ones that directly benefit me. Just because I wrote a post about my vim setup doesn't mean I'm done optimizing it. Due to the massive community support, I expect the vim experience will only get better in the years to come and I plan to take advantage of it.

I'm keeping all of my vim files in a git repo and using submodules for plugins. I wasn't able to include everything in this blog post, so if you want to see the whole thing, check it out on github. Feel free to use parts of it yourself.