Tinkering with Vim

· software · geek ·
My vim setup

Once again, I have been tinkering about with my .vimrc and tweaking my settings. While I do still use Sublime Text as an editor, I find myself using Vim by choice much more often. Over the years I have been using Vim, I have swung from a very complex setup to a rather simpler one, as I have learned which of the ‘built-in’ features of Vim I like, and which I prefer to replace with plugins and custom settings. I made the same mistake as many do when starting with Vim, and tried to use other people’s .vimrc files in full, without understanding all the settings or knowing which I needed. Since then, I have stripped my .vimrc back to basics, and have built up customised settings and plugins much more carefully, as and when I needed them. I started another round of customisation this weekend, prompted by the latest Technical Difficulties podcast, and also some Thoughtbot posts, particularly this one on using one keyboard shortcut for navigating between both tmux and vim split windows. I’m pretty happy with my current setup, so I thought it might be interesting to document some of the tiny — but very useful — tweaks I’ve made, which make it such a comfortable environment in which to write and code.

First, I now only use Vim in a Terminal (I install Vim with Homebrew), not the MacVim GUI. Having the crutch of familiar Mac shortcuts in MacVim was useful when I was starting, but I don’t need them now, and with a full-screen iTerm window, tmux and airline which I use for both Vim and tmux, I feel fully comfortable in the terminal. Airline is fantastic, and I find that it helps not only to make Vim a bit prettier1, but also more functional. In the screen shot above, you can see that the active window containing the Markdown text of this post in progress has the ‘Insert’ mode label at the bottom highlighted in gold, and there is also a gold highlight on the bar at the top highlighting the fact that the current buffer has un-saved modifications. One of the trickiest things in Vim is remembering what mode you are in, and which window is active, and having these coloured indicators makes it much easier. It has different colours for Normal, Visual, Select and Paste mode, and once you have got used to it, seeing the colour out of the corner of your eye allows you to quickly orientate yourself. Airline can display a lot of other information (including the git branch you are editing), and I find it attractive and highly functional. Another thing that makes it easier to move around comfortably is the vim-tmux-navigator plugin, which I found out about via a Thoughtbot post. This makes it effortless to move between tmux and vim windows with the same keyboard shortcut (I use Ctrl-H/Ctrl-J/Ctrl-K/Ctrl-L to go to the window to the left, below, above and right, respectively) without worrying which window is which. This makes it much easier to open a small horizontal tmux window under your Vim windows in which to run quick commands, rather than using one of the many Vim plugins to allow you to run a Terminal in Vim.

I use a few other plugins that replicate the nicest features from Sublime Text and similar editors. The plugin ctrl-p allows you to use the shortcut Ctrl-P to fuzzily search for files under the current working directory (or the git repository if you are in a repository). You just type to filter the list, and quickly find the file you need. You can then open it in the current window, a new split window or a tab. Until recently, I also used NERDTree, which provides the equivalent of a directory tree of your current project in a window on the left, but I found it got in the way more often than not, and since I was using ctrl-p for most things, it wasn’t really necessary. If I do need to see the directory structure, I just open the root directory (or any subdirectory) in a Vim window, and explore it that way.

This weekend, I found myself a bit dissatisfied with the plugins I was using for syntax completion, and for automatically inserting snippets. I therefore switched to two plugins mentioned in the Technical Difficulties post I linked to earlier: YouCompleteMe and ultisnips. In many ways, they work in a similar way to other such plugins, but they are much more unobtrusive and useful. YouCompleteMe provides smart syntax completion for a range of languages: a list of completions pops up, and if you want to use one, you tab to select it then move on. If you don’t like any of the completions, you just keep typing and it goes away. It also autocompletes file paths intelligently, as well as listing ultisnips snippets. Ultisnips is difficult to describe concisely, but it allows you to define snippets of text that you can automatically insert in your document by typing a bit of text as a trigger, then hitting tab. In other words, it provides — but also extends — the same kind of snippet feature that TextMate pioneered. Complex snippets are possible by using tab stops to successively fill in parts of the structure, mirroring of text from one part to the other, and even shell or Python interpolation. For example, I have written a snippet to insert the front matter material you see at the top of the file in the screenshot, just by typing meta then hitting tab. My cursor ends up next to the Title: line and I can type my title. This is mirrored to the slug: line, but a snippet of Python transforms this as I type into a properly formatted URL slug (all lowercase with non-word characters replaced with dashes). The date is automatically inserted, and by hitting tab again, I end up on the Tags: line, ready to enter the tags. I had a bit of trouble getting both to work nicely together, because both use the tab keystroke. However, I eventually found the solution on StackOverflow. You need to install supertab, then include the following in your .vimrc:

" make YCM compatible with UltiSnips (using supertab)
let g:ycm_key_list_select_completion = ['<C-n>', '<Down>']
let g:ycm_key_list_previous_completion = ['<C-p>', '<Up>']
let g:SuperTabDefaultCompletionType = '<C-n>'

" better key bindings for UltiSnipsExpandTrigger
let g:UltiSnipsExpandTrigger = "<tab>"
let g:UltiSnipsJumpForwardTrigger = "<tab>"
let g:UltiSnipsJumpBackwardTrigger = "<s-tab>"

" this mapping Enter key to <C-y> to chose the current highlight item
" and close the selection list, same as other IDEs.
" CONFLICT with some plugins like tpope/Endwise
inoremap <expr> <CR> pumvisible() ? "\<C-y>" : "\<C-g>u\<CR>"

This way, tab then enter works for both, and you can jump to the next placeholder in snippets with tab as well.

Another little tweak I’ve made is to switch my <Leader> keystroke from comma or backslash to space. This sounds a bit mad, but if you have quite a few customisations (or use plugins that have custom commands prefixed by the <Leader> keystroke), then the space bar is easily accessible for either hand, and provides a big target to hit. In the same vein, I always found the commands for switching between buffers and tabs cumbersome, so I changed them to left/right and up/down respectively. I also recently discovered the relativenumber setting, which labels lines above and below the line containing the cursor relative to that line. This makes moving up or down using 12j and similar commands much easier, because you don’t have to count. The setting below gives you the best of both worlds by labelling the current (cursor) line with the absolute line number, and the other lines relatively:

set number relativenumber         " relative line numbers

Finally, when I find myself wanting to find a particular bit of text in one of the files in my project (equivalent to ‘Find in Project’ in GUI text editors), I use the_silver_searcher (installed via Homebrew) in combination with a vim plugin ag.vim. You search at the command line using :Ag text to search for, and it opens a Quickfix window listing all occurrences of that text in your files. You can navigate between the listings and open the files in windows, tabs or splits. It’s so fast and efficient, that I have set up ctrl-p to use it to index my files.

Vim is one of those deep, subtle tools that you never stop learning about, so I suspect that I will continue to tinker with it to adjust it to my needs. However, for now, I am really happy with my setup, and am using it for most of my text editing needs, which is actually most of my writing, since I use Markdown (via pandoc) to write almost everything where I have a choice.

  1. Which I freely admit I found an issue before. ↩︎