Why I use VIM

Why I use VIM

For the TL;DR crowd: VIM is a great editor - and only programmable editors can truly be called "great". See... how I edit C or C++ with VIM.

how I edit Python code with VIM and incrementally test each function.

Then check out my VIM settings and read the installation instructions. VIM is a great editor - and only programmable editors can truly be called "great". See...

(March 2012)I've been programming for a living, for the better part of the last two decades - and in my experience as a programmer,. A large part of my life passes working inside it - and the more I "invest" in learning it, the faster I code.

In what follows, I will try to explain why learning VIM has proven very beneficial to me. You can also read this to see why VI/VIM can vastly improve your efficiency in editing files... or this post to see why vim is indeed an "improved" vi.

(Caveat: I am not a VIM expert - even though I've worked with VIM for decades, I am only using a small part of its functionality, and only rarely do I write a function inside my .vimrc . Mostly I just stand on the shoulders of giants. I only wrote this post because I keep seeing people "wow"-ed by the things I do within VIM - and wanted to share the marvelous things this gem of an editor can do. To any real VIM experts out there: I'd be grateful if you could review my setup and tell me the things I am doing wrong...).

Working remotely

Programmable editors - VIM plugins

In my work, I increasingly find myself doing things remotely - i.e. working over network links. By using VIM, I have a significant advantage: I can edit anything I want over e.g. SSH connections, with minimal bandwidth/latency requirements. To that end, whatever machine I am working on, I will always install an SSH server ( even under Windows ) - and I can then edit stuff remotely, using VIM. To really understand the efficiency of this, try using any GUI over a slow VPN connection (e.g. using VNC or RemoteDesktop) - you will soon begin to appreciate a fast, console-based editor.Almost all professional editors are "tweakable" - e.g. they allow you to configure keyboard shortcuts. But that's not what I mean with "programmable editor"; I am referring to editors that allow you to; only a handful fit this description.

If a large community of coders is using this customization facility for their professional endeavours... then there is a good chance that the things they build will apply to you, too. For VIM, there are almost 4000 custom VIM scripts, tailored to their creators' specific needs. Let's look at some of these, and how I am using them.

Auto-completion / language-aware navigation

Some of the things I can do when I work with C or C++ code.

Some people still think that if you use a "spartan" editor like VIM, you lose all the auto-completion magic and language-aware navigation that modern IDEs offer. That is simply not true:

Executive summary for C/C++ coders:

Add clang complete to your installed VIM plugins, and install libclang in your machine. If your build process has "exotic" macros defined or needs "special" include flags, just add them in a .clang_complete file (which this VIM plugin reads).

file (which this VIM plugin reads). Become root and install your favourite tags tool - e.g. exuberant ctags. Then setup your "constant" tags database, e.g. for /usr/include: # cd /usr/include # ctags -R . If you want to exclude stuff you don't navigate with tags, and/or want to minimize the size of your tags database, you can exclude folders - e.g. to exclude Boost... # cd /usr/include # ctags -R --exclude=boost/\* . Your own C/C++ code must automatically update its tags database, so use a rule like this in your Makefile: tags: ctags -R --c++-kinds=+p --fields=+iaS --extra=+q . ...and you can then tell your VIM to always use the "constant" tags, alongside any other ctags database you use (e.g. the one that your Makefile updates during your builds): $ cat .vimrc ... set tags+=/usr/include/tags ... Notice how we therefore re-use tags databases amongst all the projects we work on in this machine. This can be applied to more than just /usr/include ; you can create individual tags databases for each library or code folder of your own, and only pay the price of creating the tags when something changes in them.



If you want to exclude stuff you don't navigate with tags, and/or want to minimize the size of your tags database, you can exclude folders - e.g. to exclude Boost... Your own C/C++ code must automatically update its tags database, so use a rule like this in your Makefile: ...and you can then tell your VIM to always use the "constant" tags, alongside any other ctags database you use (e.g. the one that your Makefile updates during your builds): Notice how we therefore re-use tags databases amongst all the projects we work on in this machine. This can be applied to more than just ; you can create individual tags databases for each library or code folder of your own, and only pay the price of creating the tags when something changes in them. Learn to use Makefiles - and build your code with a simple " :make ". VIM will guide you to whatever compilation errors you have; just use " :cn " and " :cp " to navigate amongst compilation errors.

Automating repetitive tasks

In the video, you saw me using NERDTree - a "file manager" plugin from within VIM. But, to toggle that window, you need to escape into command mode, and type ':NERDTreeToggle'. Isn't that too much typing?

Indeed it is, so you map it to something you can easily use via your .vimrc :

" " maps NERDTree to F10 " map <silent> <F10> :NERDTreeToggle<CR> map! <silent> <F10> <ESC>:NERDTreeToggle<CR>

This tells VIM that in both command mode and insert mode, when you hit F10, you want the NERDTree file manager to appear/disappear.

Similarly, when I search for something ( /whatever ), I want the search results to be highlighted (in yellow) - but after finding what I want, I no longer want to see the highlights - so I map "Ctrl-L" to clear them up:

se hlsearch " Ctrl-L clears the highlight from the last search noremap <C-l> :nohlsearch<CR><C-l> noremap! <C-l> <ESC>:nohlsearch<CR><C-l>

noremap <silent> <C-Down> <C-W>j noremap <silent> <C-Up> <C-W>k noremap <silent> <C-Left> <C-W>h noremap <silent> <C-Right> <C-W>l noremap <silent> <C-F12> :bd!<CR>

Using functions

I use VIM "split" Windows - and I don't like navigating amongst them with Ctrl-w h/j/k/l. I want to use Ctrl+cursorsKeys. I also want to instantly close any window with Ctrl-F12:Whenever I find myself doing something over and over, I eventually automate it; using a key combination that allows me to do it instantly.This can be far more complex than just keyboard shortcuts.

Say I want manpages displayed inside my editor, so I can copy/paste "stuff" out of there easily:

" " Smart in-line manpages with 'K' in command mode " fun! ReadMan() " Assign current word under cursor to a script variable: let s:man_word = expand('<cword>') " Open a new window: :wincmd n " Read in the manpage for man_word (col -b is for formatting): :exe ":r!man " . s:man_word . " | col -b" " Goto first line... :goto " and delete it: :delete " finally set file type to 'man': :set filetype=man " lines set to 20 :resize 20 endfun " Map the K key to the ReadMan function: noremap K :call ReadMan()<CR>

ReadMan

A function is defined, called. It reads the current word under the cursor, and then invokes a series of commands that create a new window and read the relevant manpage inside it. This function is then mapped to 'K'.

The power that comes from this kind of customizing can provide immense productivity gains. Imagine reading outputs of custom commands you build yourself, and then have VIM act on their results - storing variables, calling functions, whatever.

Update: mgedmin from Reddit was kind enough to suggest some improvements in ReadMan , and to also point out that as an example it is fine, but functionality-wise it is no longer necessary - VIM already includes this functionality via :runtime ftplugin/man.vim followed by :Man whatever .

Identical customized environment everywhere you work

You might argue: "this customization you just did - the 'F10' invoking NERDTree, the 'Ctrl-L' clearing search highlights, etc - you are the only VIM user doing it, so when you go to another machine, you have a problem, no?"

Actually, I don't; whenever I work with a new machine, I just do this:

bash$ cd bash$ git clone https://github.com/ttsiodras/dotvim .vim bash$ cd .vim bash$ git submodule init bash$ git submodule update bash$ cd .. bash$ ln -s .vim/.vimrc

.vimrc

Plugin maintenance

VIM (like other programmable editors) allows you to configure it via a text-based configuration file (). By placing this file under source-control in a public repository (mine is in GitHub) I can consistently reproduce my own, customized editing environment, tailored to my needs - in ALL machines I work on.So I packaged a bunch of plugins in my GitHub account. But these are live, evolving creatures. Their authors may have fixed bugs since I copied them - am I stuck in whatever version I originally copied?

No - thanks to Pathogen. Did you notice the Git submodule commands executed above? They use Git to fetch the latest versions of whatever plugins I am using ( git submodule update ). I am always up-to-date!

Coding is not just about editing code

/etc/apache/httpd.conf

Even if you love your IDE, and you think it does all you ever wanted - you will soon find out that you need to edit things that are *not* code; configuration files, READMEs, notes, mails, commit messages, etc. How will you edit them? You will spawn your takes-10-seconds-to-launch IDE just to edit an .ini file? Or

The point I am trying to make here, is that by investing in learning and customizing an editor like VIM, I can then put that power to use regardless of where I am and what I am editing. I have that power with me, "everywhere I go" - i.e. no matter what files I am working on.

"Power... Unlimited power!"

Sith-Lord-pun aside, if this section doesn't convince you, nothing will.

Let's say you discover for the first time a REPL-enabled language. REPL means 'Read'-'Evaluate'-'Print'-'Loop'. It refers to all these dynamically-typed languages that offer an interpreter (LISP, Python, Ruby, etc) - an environment that reads individual statements that you write, then evaluates them, and then prints the results.

You try the environment for the first time:

bash$ python Python 2.7.2 (default, Jan 31 2012, 13:26:35) [GCC 4.6.2 20120120 (prerelease)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> def factorial(n): ... return 1 if n<2 else n*factorial(n-1) ... >>> print factorial(20) 2432902008176640000 >>> print factorial(200) 788657867364790503552363213932185062295135977687173263294742533244359449 963403342920304284011984623904177212138919638830257642790242637105061926 624952829931113462857270763317237396988943922445621451664240254033291864 131227428294853277524242407573903240321257405579568660226031904170324062 351700858796178922222789623703897374720000000000000000000000000000000000 000000000000000 >>>

Cool, it works... How nice, to have an interpreter! You suddenly realize how easily one can tinker with these dynamic languages. No edit-compile-run cycle. Fast. Easy.

But... you miss your editor. You want to be able to write the code in it, using all the customized power you have gathered there over the years - and then somehow "magically" transport functions (not complete files!) across to the interpreter. How can you do that? How can you incrementally build your code base, testing each function as you go along?

You may be lucky enough, to be working with languages/tool that already offer this [1]. Usually, however, this is not the case. You could ask the company that builds your favourite IDE for this feature, but the time and money it will take to implement prohibit it. Instead, you combine the power of the tools you already have, by being a programmer that is not limited to a single company's IDE - here's how:

The screen tool allows one to create standalone command line sessions. It also allows creation of "windows" inside them, e.g. have VIM run in one window, and Python run in another.

tool allows one to create standalone command line sessions. It also allows creation of "windows" inside them, e.g. have VIM run in one window, and Python run in another. More importantly, screen allows you to copy text into a screen session, via the "screen -S sessionName -p windowName -X stuff" command. You can therefore 'paste' anything you want inside a screen "window".

allows you to copy text into a screen session, via the "screen -S sessionName -p windowName -X stuff" command. You can therefore 'paste' anything you want inside a screen "window". If we can somehow automatically "gather" the text of a function, we can send it across to another screen window by just spawning "screen ... -X stuff ...".

Why don't we add this gathering stage as a VIM function? And then have it send the data across to the "window" running the python interpreter?

Using screen and VIM to implement mini-SLIME for Python.

Here's how I did it for my Python work:

" " A function I hacked that sends individual Python classes or Python functions " to a screen window that is running the Python interpreter... " function! SelectClassOrFunction () let s:currLine = getline(line('.')) if s:currLine =~ '^def\|^class' " If the cursor line is a function/class start line, " save its number let s:beginLineNumber = line('.') elseif s:currLine =~ '^[a-zA-Z]' " If the cursor line begins with something else, " we must be on something like a global assignment let s:beginLineNumber = line('.') let s:endLineNumber = line('.') :exe ":" . s:beginLineNumber . "," . s:endLineNumber . "y r" :call Send_to_Screen(@r) return else " we are inside something, so search backwards " for function/class beginning, and save its number let s:beginLineNumber = search('^def\|^class', 'bnW') if !s:beginLineNumber let s:beginLineNumber = 1 endif endif " Now search for the first line that starts with something " (function, class, global, etc) and save it let s:endLineNumber = search('^[a-zA-Z@]', 'nW') if !s:endLineNumber let s:endLineNumber = line('$') else let s:endLineNumber = s:endLineNumber-1 endif " Finally pass the range to the screen session running a REPL :exe ":" . s:beginLineNumber . "," . s:endLineNumber . "y r" :call Send_to_Screen(@r) endfunction nmap <silent> <C-c><C-c> :call SelectClassOrFunction()<CR><CR> function Send_to_Screen(text) ... echo system("screen -S PythonSession -p 0 -X stuff '" . text , "'") ... endfunction

we have to search for a def or class definition at the beginning of a line. And that's what we do - we use VIM's language to describe searching backwards from the cursor position, looking for the ^def\|^class regular expression - and store the line we find as s:beginLineNumber .

or definition at the beginning of a line. And that's what we do - we use VIM's language to describe searching backwards from the cursor position, looking for the regular expression - and store the line we find as . If we don't find it, we just use 1 (i.e. we will copy from the begining of the file).

We do the same thing to find the next class/function beginning, and mark that as s:endLineNumber .

. If we don't find it, we just use the last line (i.e. we will copy until the end of the file)

We now yank (i.e. "copy") all the lines from s:beginLineNumber to s:endLineNumber into register "r

to into register And spawn "screen" with the '-X stuff' parameter - to paste the text in the Python interpreter (Or use the SLIME plugin which I slightly customized to automatically target the Python window).

The algorithm is quite simple: When the user hits the "magic key combo" we need to identify the function or class that our cursor is in, and send it across. For Python, this is easy:That's all. It's not bullet-proof, but it only took 20min to write and test, since I could already base my efforts on the VIM slime plugin. And most importantly, I will have this in my arsenal from now on, for any REPL-enabled language - where I will just have to modify the "find the function borders" algorithm.

I hope that you can now see how it pays to have a programmable editor... Whatever functionality you want, you can easily implement it inside it - especially if you adhere to the UNIX mentality, i.e. you use tools that do one thing and do it well. In this case, the screen tool allowed us to paste data in another window by a simple spawning - which we easily do inside VIM, by calling system .

Executive summary

Be a man, use a programmable editor like VIM! :‑)

If you code for a living, it will more than make up for your investment - it will make you far more productive that any single IDE can ever hope to.

Acknowledgments: Far too many to mention. Plugins, ideas, SLIMEy things, etc, are all gifts from the Gods. I must, however, express my gratitude to the man that showed me the path: Hartmut Brandt, a FreeBSD committer who I was lucky enough to work with, 17 years ago. Hartmut introduced me to the wonderful things that VIM can do. Wherever you are, harti: I remain forever grateful :‑)

[1] Gasp! An Emacs link in a VIM article! Where's my helmet? :‑) Joking aside, I think that both VIM *and* Emacs are amazing - and that any aspiring programmer stands to gain much by learning at least one of them.

If you liked this article, you'll probably also appreciate this one

Back to index My CV Last update on: Sat Mar 16 08:45:21 2019

The comments on this website require the use of JavaScript. Perhaps your browser isn't JavaScript capable or the script is not being run for another reason. If you're interested in reading the comments or leaving a comment behind please try again with a different browser or from a different connection.