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...).
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.
Executive summary for C/C++ coders:
# 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.
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.
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.
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/.vimrcVIM (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.
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!
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.
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:
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 , "'") ... endfunctionThe 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:
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.
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.
Index | CV | Updated: Sat Oct 8 12:33:59 2022 |