Using Vim as a Python IDE ========================= :date: 2013-04-15 17:53 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_. Forewords --------- 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. .. _Pathogen: https://github.com/tpope/vim-pathogen 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: .. code-block:: bash mkdir -p ~/.vim/bundle ~/.vim/autoload curl -Sso ~/.vim/autoload/pathogen.vim \ https://raw.github.com/tpope/vim-pathogen/master/autoload/pathogen.vim .. _Installing: https://github.com/tpope/vim-pathogen#installation and adding the following line at the top of your ``.vimrc``: .. code-block:: vimrc execute pathogen#infect() 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. .. _Molokai: https://github.com/tomasr/molokai .. _Solarized: https://github.com/altercation/vim-colors-solarized 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 ```` key to the ``NERDTreeToogle`` function to quickly toggle the drawer on and off: .. _NERDTree: https://github.com/scrooloose/nerdtree .. code-block:: vim nnoremap :NERDTreeToggle 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 ```` 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 ```` to open it. .. _Ctrlp: https://github.com/kien/ctrlp.vim In addition to the default ```` 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 ````: .. code-block:: vim nnoremap :CtrlPBuffer | 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. .. _session feature: http://vimdoc.sourceforge.net/htmldoc/usr_21.html#21.4 .. _sessionman: https://github.com/vim-scripts/sessionman.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. .. _buffers and windows sections: http://vimdoc.sourceforge.net/htmldoc/windows.html#buffers Code writing ------------ 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 ```` key to the ``TagbarToggle`` command to toggle the drawer: .. code-block:: vim nnoremap :RainbowParenthesesToggleAll 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 ```` tag and realize that you want to turn it into a ``
`` 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 ```` key to toggle the rainbow colors on and off: .. code-block:: vim nnoremap :RainbowParenthesesToggleAll .. _RainbowParentheses: https://github.com/kien/rainbow_parentheses.vim .. _Surround: https://github.com/tpope/vim-surround .. _TagBar: https://github.com/majutsushi/tagbar Other plugins worth mentioning: NERDCommenter_, Easymotion_. .. _NERDCommenter: https://github.com/scrooloose/nerdcommenter .. _Easymotion: https://github.com/Lokaltog/vim-easymotion 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. .. _python-mode: https://github.com/klen/python-mode 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``: .. code-block:: vim set foldlevelstart=99 nnoremap za nnoremap zA vnoremap 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: .. code-block:: vim 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: .. code-block:: vim let g:pymode_rope_vim_completion = 0 .. _jedi-vim: https://github.com/davidhalter/jedi-vim .. _pylint: http://www.logilab.org/857 .. _here: https://github.com/klen/python-mode#id21 | 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 ``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 ```` 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. .. _vim-ipython: https://github.com/ivanov/vim-ipython Conclusion ---------- Here are the commands to install all the plugins mentioned in this article: .. code-block:: bash # 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``: .. code-block:: vim 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 za nnoremap zA vnoremap zA nnoremap :NERDTreeToggle nnoremap :CtrlPBuffer nnoremap :RainbowParenthesesToggleAll nnoremap :RainbowParenthesesToggleAll let g:pymode_lint_write = 0