comments

Exploring Vim: Setting Up Your Vim To Be More Awesome At Vim, Or... The Very Basic Things You Need to Know About Configuring Vim

Before we proceed in our journey to vim awesomeness I thought it would be nice to get something out of the way as soon as possible so we don’t need to wedge it in uncomfortably in passing on every single one of the future articles in this series: How to setup, configure vim and keep it tidy, sharp and strong like a well oiled blade.

This is not going to be a thorough reference on how to configure vim but a swift, short and sweet guide to get you up to speed within minutes and on your way to learning and using vim more effectively.

A witcher never ever forgets to take care of his blade

Wallpaper from thewitcher.com plus a quote from the heartwarming reunion of Ciri and Geralt. Sorry I've just finished the Witcher 3, couldn't stop myself :D

How Do You Configure Vim?

You can configure vim in three ways:

  1. Using Ex commands in command line mode
  2. Using a vim configuration file (:h vimrc)
  3. Through a set of limited options provided via the terminal when running vim. (:h vim-arguments)

Ex commands are the subset of commands in command-line mode that are prefixed with :. For instance, try opening vim, type:

:colo elflord

and press ENTER. You’ll notice how when you type : whatever you write appears at the bottom of the screen within Vim (that’s where your commands appear when you’re in command-line mode). After pressing ENTER this ex command will configure your current session of vim and change the color scheme to the one used commonly by powerful elf lords.

Noticed how we used :colo instead of :colorscheme? You can use shorthand to refer to Ex comands and vim will do its best to fulfill your wishes, oh master.

How Can You Write Reusable Configurations?

You could potentially configure your vim session using one-off Ex commands but that would be a pain in the butt and wouldn’t be of much use for future sessions. Instead vim offers you the possibilily of putting all these Ex command configurations inside a file that is loaded whenever you start vim. The vimrc (:h vimrc) file:

" Sample vimrc file.
" This is a comment :D
set nocompatible           " disable backwards compatibility with vi
filetype plugin indent on  " enable filetype plugins and indent
syntax enable              " enable syntax highlighting

Notice how no commands are prepended with :? That’s because vim assumes that whatever you put inside your vimrc are ex commands.

There’s different types of options with diverse shapes and forms. Boolean options are quite common, like the one referenced via nocompatible above. You can modify them using the :set command in quite an interesting and novel way:

set compatible     " enable option
set nocompatible   " prepend 'no' to disable the option
set compatible!    " append ! to toggle the option
set compatible?    " find out whether the option is enabled
set compatible&    " reset to default vim option

You can use vim’s help to find more information about the available options and how to configure them. Try :h option-list to see a summary of all available options, and :h options for the full deal. The help is veeery nice and detailed. Test :h compatible to get a taste (note that this option only available in vim because neovim doesn’t even offer the option of backwards compatibility with vi, if you’re in neovim try :h 'filetype' instead):

A screenshot of vim's help for the compatible option

The One Thing You Should Know: How To Define Your Own Key Mappings!

One thing that you’ll find super useful early on is learning how to configure your own key mappings. If not to write your own mappings, at least to understand what the mapping ex command does when someone recommends you to put it in your vimrc file. You don’t need to grok this right away but you can get the gist of it and come back if you need it in the future.

The main commands used for mapping are map and noremap where map stands for mapping and noremap stands for non-recursive mapping. Let’s take a look at how they work and after that we’ll see what the recursive part means.

Let’s say that you’ve gone completely nuts and you want to remap the hjkl keys to the keys one keyboard row up. You would write something like this in your vimrc file:

map y h
map u j
map i k
map o l

Or alternatively type the ex command as :map y h. What this command does is create new custom key mappings so that whenever you type yuio vim will understand it as hjkl.

But vim has modes! In which modes do the key mappings above apply?

The map command is somewhat of a shortcut in the sense that it applies the mapping to three vim modes at once: the normal, visual and operator-pending modes. You can be more specific by providing the mode you want the mapping to apply to yourself. For instance:

" To make a mapping apply to a given mode, prepend it to the map command
" apply mapping only to visual mode
nmap y h
" apply mapping only to visual mode
vmap y h
" apply mapping only to insert mode
" (and now you can never insert the y letter again xD)
" (you're welcome! moahahaha!)
imap y h

Ok, so map does key mappings. Then what does noremap do? And what the heck are recursive and non recursive mappings?

map defines recursive mappings. When vim tries to make sense of a recursive mapping, it will take a look at the characters you type and expand them recursively as it finds new mappings. In the example above, when you type y vim will take a look at h and try to determine if there’s any other mapping for h. If there is, it will expand that mapping. If there isn’t (like in our example) it will just use h. Don’t get it yet? Don’t worry! Recursion is always hard to wrap our heads around. Take a look at this example below which is more illustrative of the recursivity of these mappings and easier to understand:

" normally h means *left* and l means *right*
" this maps h to *right* instead of *left*
map h l
" this maps y to h.
" Normally that would mean that y would map to *right*
" However, this is recursive mapping, h will expand to l
" And therefore y will mean *right*
map y h

So how could we change the h mapping while keeping the original behavior of h so that we can map it to y? That’s where non recursive mappings come in. Non recursive mappings allows us to have vim bind keys to default vim key bindings. Or in other words, non recursive mappings ignore all other mappings and just do what you explicitly tell them to do. (They are not recursively expanded):

" this still maps h to *right* instead of *left*
map h l
" this maps y to h non-recursively
" which means that vim uses *h* default behavior which is *left*
noremap y h

" so h now gets the new meaning of *right*
" and y means *left*

When to use recursive and non recursive mappings? 99% of the times you want to use non-recursive mappings. Non-recursive mappings guarantee that a given mapping will get the precise behavior you want as they are completely unaffected by other mappings. A newly installed plugin can change a mapping, you yourself can change the meaning of a mapping, in any of these scenarios your non-recursive mapping will be unaffected. Using a recursive mapping can feel like someone pulled the rug from under you if it suddenly stops working as you expect it to work. Even worse it can also create an endless loop. What’s the 1% left? I honestly can’t think of a use case where I would want to use normal mappings. If you do please write a comment!

You are not limited to map just one key to another key. You can create more complex mappings like so:

" This mapping comments a line in JavaScript
map c I//<Space><ESC>=<CR>
" It means, drop into insert mode at the beginning of the current line
" then add a couple of forward slashes (//) and go back to normal mode
" then adjust the indentation of the current line

Or even map keys to ex commands:

" Mapping C-r to refreshing your vimrc configuration
map r :source $MYVIMRC<CR>
" Don't do this though. r is replace character in vim
" You'll probably replace characters far often than you
" refresh your vim config file

Here’s a real world mapping from the vim-surround plugin for your enjoyment. If you have the patience and drive try to understand what it does and what the strange characters such as <silent>, <Plug>, etc… mean. If you’re not one for exercises, then move along to the next paragraph!

" Used for changing the surrounding characters or tags of a bit of text
nnoremap <silent> <Plug>Csurround  :<C-U>call <SID>changesurround()<CR>

Now let’s wrap this mapping thing up! The map command without a second argument let’s you see whether there are any mappings tied to a given key sequence. Using map without arguments at all will show you all custom mappings available. You can combine it with verbose as in :verbose map to see the file that last modified a mapping. Note that only custom mappings will be shown by this command. If you want to check for vim’s built-in mappings you’ll need to use :h index (this is useful when you want to make sure that you’re not overwriting some vim built-in functionality).

Finally you can use the unmap command to remove mappings. It works in a similar way to map and noremap as you can make it apply to specific modes using alternative commands like nunmap, iunmap, etc.

You can find more information about the mapping and the map commands using vim’s help :h mapping or :h map-commands

Defining Your Own Commands

Vim comes with loads of commands but you can also create your own. This is a command that refreshes your vim configuration:

" User-defined commands must start with a capital letter
command! RefreshConfig source $MYVIMRC

Put it in your vimrc and you’ll be able to use it like any other ex command: :RefreshConfig. Why use a command instead of a custom key mapping?

I like to create custom commands for stuff that I use often but not that often that it should have its own key mapping. With a custom command I get the convenience of tab completion and they’re easier to remember, yet they don’t clog down my key bindings which I reserve for things that I do very often when writing and editing code.

Just like with map, executing :command without arguments will list all user-defined commands available, and executing :command {cmd} with a single argument {cmd} will list all user-defined commands that start with {cmd}.

To find more information about custom commands take a look at :h user-commands (also :h 40.2 which has a getting started guide for user-defined commands).

The Leader Key

As you go customizing vim to fit your needs and installing plugins you may run out of space for mapping custom key bindings. The leader key offers you a new namespace specifically reserved for user-defined bindings to unleash mayhem and destruction when you type <Leader><custom key sequence>. By default the leader key is assigned to backslash \\ which can be tricky to type. Often vim users will map that key to a different one more easily reachable. You can map it to a different key using the following command:

let mapleader = ","

Vim users often map the leader key to ,. If you want to do that, be aware that this shadows a default key binding which is quite useful in vim: repeat a character search backwards, that is, the opposite of ;. I prefer to map my leader key to <Space> which is always below my right thumb and doesn’t break any built-in vim functionality (as far as I know):

" I have no clue why the first \ is needed
" in the line below but if I just map <Space>
" it doesn't work on my Mac
let mapleader = "\<Space>";

You can use the leader key in your your own mappings referring to it as <Leader>:

" remap J (join line) to go down 5 lines for faster movement
nnoremap J 5j

" but now I broke J (join line) which is quite nice if you write
" a lot of prose like I do (blog posts, books and such)
" So I remap it to <Leader>j
nnoremap <Leader>j J

Extending Vim With Plugins

In addition to using your vimrc to customize and extend vim, vim supports third-party (oftentimes community driven and developed) plugins that extend it with new and awesome functionality. Unfortunately, vim doesn’t come with a nicely integrated plugin brower/installer and there is no standard plugin manager. Instead, what you do is use one of the most common plugin managers that are available in the vim ecosystem: vim-pathogen, Vundle.vim or vim-plug are the most used ones.

I use minpac (cause Drew Neil told me to) and I’ve used vim-pathogen and Vundle.vim in the past. For my simple use case, which is to use plugins that are hosted on GitHub repos I haven’t experienced any difference from any of these options. So you can choose whichever you want.

All of these plugin managers follow the same principles to extend vim:

  1. Install plugin manager (which is a vim plugin in itself)
  2. Add it to your vimrc
  3. Add list of plugins you want to install in a declarative way in your vimrc. You’ll use the DSL defined by your plugin of choice
  4. Use plugin commands to install, update and remove plugins
  5. Installing plugins typically consists in cloning git repos inside vim plugin folders

This is an example from my vimrc:

" Package manager minpac
" Initialize package manager
packadd minpac
call minpac#init()

" have minpac manage minpac :D
" use opt so that we can load the plugin via packadd before any other plugin
call minpac#add('k-takata/minpac', {'type': 'opt'})
"""""""" Add other plugins here:
" Colorschemes
call minpac#add('KeitaNakamura/neodark.vim')
call minpac#add('tomasr/molokai')
call minpac#add('Lokaltog/vim-distinguished')
call minpac#add('fenetikm/falcon')
call minpac#add('haishanh/night-owl.vim')
call minpac#add('rakr/vim-one')

" Editing
call minpac#add('tpope/vim-repeat')       " Enable repeating supported plugin maps with .
call minpac#add('tpope/vim-unimpaired')   " pairs of handy bracket mappings
call minpac#add('tpope/vim-surround')     " Quoting parenthesing made simple
call minpac#add('scrooloose/nerdcommenter') " Comments

" Customize UI
call minpac#add('itchyny/lightline.vim')  " Custom Status line

" File system
call minpac#add('junegunn/fzf')            " fuzzy file search
call minpac#add('junegunn/fzf.vim')        " fuzzy file search
call minpac#add('scrooloose/nerdtree')     " File tree explorer
call minpac#add('tpope/vim-projectionist') " Semantic based navigation configurable per project
call minpac#add('mhinz/vim-grepper')       " Search files

" etc...

So, choose whichever one you fancy the most and peruse the archives of vimawesome.org for plugins to tailor vim to the type of applications you usually develop. I have some notes on useful plugins in my wiki (although it’s very much a WIP) and you’re welcome to take a sneak peek in my current vimrc on GitHub.

Keeping Your vimrc In Check

And one last piece of advice which as a good hypocrite I haven’t yet implemented myself. A good idea to keep your vimrc in check is to break it down into smaller bits (just like with software modularization FTW). You can create context specific vim configuration files and load them into your vimrc using the source command:

" my vim config broken down
source plugins.vim
source navigation-mappings.vim
source editing-mappings.vim
source javascript.vim
" etc, etc...

This also gives you the ability to have some of these files removed from the vimrc and loaded only on demand when they are necessary.

And that is all for today! See you again soon! Have a wonderful day ahead!