About one year ago, I have switched to using Vim as my main text and code editor. Before that, I was using Emacs, but never really mastered it to the point where I could consider myself proficient. After having heard a lot about the steep learning curve of Vim, I was surprised to find myself picking it up rather quickly: I like the fact that shortcuts are structured similarly to natural languages. People often mention how combining action and motion instructions in Vim is similar to constructing a sentence in a natural language, which I find an accurate comparison.
Vim really shines when it comes to quickly editing a few files from the command line, but even though I am not a heavy coder, I found the default configuration a bit insufficient for bigger projects involving editing multiple related files. Here is how I gradually tweaked my Vim configuration to copy some behaviors commonly found in IDEs. While some of these tweaks are general and can be applied to any language, others are specific to Python, the language I use most of the time.
This article assumes that you already have a basic knowledge of Vim and its configuration. If you do not want to read my comments and prefer to stick to the bare configuration steps, you can jump straight to the Conclusion.
First and foremost, you should make sure that you have Pathogen installed. This amazing script allows you to handle your Vim plugins separately: each plugin becomes a subdirectory of the .vim/bundle folder (this can be changed to somewhere else) in which you put all the plugin files instead of spreading them over the default directory structure. Most of the plugins I will recommend here are available on GitHub, so cloning their repositories inside your .vim/bundle folder is all you need to install them.
This is particularly useful if you use Git to handle your Vim configuration (and more generally your dotfiles), because you can treat each Vim plugin as a submodule of your main repository, allowing for easy updates.
Installing Pathogen is as easy running:
mkdir -p ~/.vim/bundle ~/.vim/autoload curl -Sso ~/.vim/autoload/pathogen.vim \ https://raw.github.com/tpope/vim-pathogen/master/autoload/pathogen.vim
and adding the following line at the top of your .vimrc:
Also, as a general recommendation, make sure that you have a color theme that match your tastes. Because I find dark themes more easy on the eyes, I went for Molokai. Solarized is a common choice among light themes lovers.
File and project management
When working on a project involving more than one file, being able to quickly navigate through its files is key. NERDTree is a nice plugin which replaces the default Vim file browser and adds a file-tree drawer on the left of Vim's interface. I bind the <F1> key to the NERDTreeToogle function to quickly toggle the drawer on and off:
nnoremap <F1> :NERDTreeToggle<cr>
I find the NERDTree plugin very useful when discovering a project, to quickly grasp how the files are organized. However, to quickly open new files and switch to open buffers, there is a much more powerful solution, I name the CtrlP plugin. This plugin adds commands to search through files, buffers, tags, etc. in a fuzzy way. Let's say you want to open a file, pressing <Ctrl-p> followed by a few letters of this file's path (they don't need to be contiguous) will give you a list of all the files matching these letters. The list gets further filtered as you keep typing. When the file you are looking for reaches the bottom of the list, you simply press <Enter> to open it.
In addition to the default <Ctrl-p> shortcut to open new files, I like to have a shortcut to launch the buffer finding command to search through open buffers. Here I bind it to <Ctrl-b>:
nnoremap <c-b> :CtrlPBuffer<cr>
Vim has a very nice built-in session feature: you can save the current state of your Vim instance (open buffers, windows layout, cursor positions, paste registers, jumps, macros, etc.) in a session file. The sessionman plugin is a simple wrapper around this feature, and takes care of storing all your session files in the same directory. This is achieved by using the SessionSave command which asks you for a simple name to identify the session. Call the SessionOpen command with the same name to re-open the session. Also, if you are working inside a previously saved session, the plugin automatically saves the current state in the same session file when quitting Vim.
Finally, I would also recommend reading the buffers and windows sections of Vim's help. Having a good understanding of buffers and windows, splits, etc. can help you being more productive when working on multiple files.
There are many plugins to help you writing code more efficiently. Here are some that I find particularly helpful.
TagBar: to display a list of the current file's tags (when programming, these are the functions, classes, global variables defined in the file) in a drawer on the right of Vim's interface. This allows you to have a clear view of the file content and to quickly jump to another location. I bind the <F2> key to the TagbarToggle command to toggle the drawer:
nnoremap <F2> :TagbarToggle<cr>
note that this plugin requires that you have a ctags implementation installed on your computer.
Surround: gives you new motion commands to manipulate surrounding parentheses, brackets and html tags. For example, let's say you are currently editing some HTML code, you are inside a <span> tag and realize that you want to turn it into a <div> tag. With this plugin this can be achieved by typing csttdiv, where cst means change surrounding tag, the second t means replace it with another tag, and div is simply the name of the replacing tag.
RainbowParentheses: to color parentheses, brackets, etc. according to their nesting level. This is quite helpful to quickly check the well-balancedness of a complex expression. I bind the <F3> key to toggle the rainbow colors on and off:
nnoremap <F3> :RainbowParenthesesToggleAll<cr>
Python specific configuration
Python being a very popular language, there is a large ecosystem of tools to help Python developers checking, formatting, refactoring and doing static analysis of their code. If you do not want to spend too much time understanding and installing all these tools, a coherent sample of them has been bundled into the python-mode plugin.
I find the default configuration very reasonable. Here is a selected list of the features you will get by installing this plugin:
python-aware motions: M for the current method, C for the current class. For example, daM will delete the current method.
python-aware code folding. I don't like to have all my code folded when I open a file so I set the foldlevelstart to 99. I also set simpler shortcuts to toggle code-folding. Here is the related section of my .vimrc:
set foldlevelstart=99 nnoremap <Space> za nnoremap <S-Space> zA vnoremap <S-Space> zA
code completion/analysis/refactoring with Rope. The most useful shortcuts are described here. See :help ropevim.txt for more advanced commands.
pylint checking of your code. By default, pylint is run on your files every time you save them. I find this quite cumbersome so I disabled it with:
let g:pymode_lint_write = 0
and prefer to run it manually with the PyLint command.
Also, note that Python being a dynamic and weakly-typed language, it is hard to get good auto-completion. I have read some good things about jedi-vim auto-completion. If you want to try it out, you simply need to install this plugin after disabling rope's auto-completion:
let g:pymode_rope_vim_completion = 0
A nice thing about Python being an interpreted language is that it allows you to quickly test a snippet, update the definition of a function into an already loaded environment, etc. The python-mode plugin gives you the <Leader>r shortcut to run the current file through Python, but if you want something more fine-grained, I recommend the vim-ipython plugin. This plugin is still very rudimentary, but it already gives you the ability to send Python code to a running IPython kernel. Here is how I use it:
- launch a terminal window and put it side-to-side with my Vim window
- launch an IPython console in the terminal window with the ipython console command (this will also launch an IPython kernel)
- run the :IPython command inside my Vim window to connect to the running IPython kernel
- whenever I want to send some code (e.g. a function) and make it available to the IPython instance, I select it (e.g with vaM) and use the <Ctrl-s> shortcut.
One thing which is crucially missing is getting feedback from IPython back to Vim: for example, displaying error messages if the sent code is faulty or displaying python's output on the code execution.
Here are the commands to install all the plugins mentioned in this article:
# if using Pathogen, run these commands in ~/.vim/bundle git clone https://github.com/scrooloose/nerdtree.git git clone https://github.com/klen/python-mode.git git clone https://github.com/kien/ctrlp.vim.git git clone https://github.com/kien/rainbow_parentheses.vim.git git clone https://github.com/majutsushi/tagbar.git git clone https://github.com/vim-scripts/sessionman.vim.git git clone https://github.com/tpope/vim-surround.git git clone https://github.com/ivanov/vim-ipython.git git clone https://github.com/tomasr/molokai.git
And the options to put in your .vimrc:
execute pathogen#infect() filetype plugin indent on syntax on " you probably want more options here, see for example this excellent article " http://stevelosh.com/blog/2010/09/coming-home-to-vim/ set foldlevelstart=99 nnoremap <Space> za nnoremap <S-Space> zA vnoremap <S-Space> zA nnoremap <F1> :NERDTreeToggle<cr> nnoremap <c-b> :CtrlPBuffer<cr> nnoremap <F2> :TagbarToggle<cr> nnoremap <F3> :RainbowParenthesesToggleAll<cr> let g:pymode_lint_write = 0