Fork me on GitHub (March 2012)

Why I use VIM

For the TL;DR crowd: VIM is a great editor - and only programmable editors can truly be called "great". See...
I've been programming for a living, for the better part of the last two decades - and in my experience as a programmer, the editor I used really mattered. 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

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.

Programmable editors - VIM plugins

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 actually code (and therefore customize) significant parts of their behaviour; 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 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:
 
Working with C or C++ code.

Executive summary for C/C++ coders:

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>
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:
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>
Whenever I find myself doing something over and over, I eventually automate it; using a key combination that allows me to do it instantly.

Using functions

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>
A function is defined, called ReadMan. 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
VIM (like other programmable editors) allows you to configure it via a text-based configuration file (.vimrc). 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.

Plugin maintenance

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

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 /etc/apache/httpd.conf?

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:

Using screen/VIM to mini-SLIME in 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

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.


profile for ttsiodras at Stack Overflow, Q&A for professional and enthusiast programmers
GitHub member ttsiodras
 
Index
 
 
CV
 
 
Updated: Sat Oct 8 12:33:59 2022