Vim - not just for cleaning house

So its been a long time since I first tried Vim the editor (not to be confused with the cleaning product) and even longer since I started using 'vi' on Unix. Now that I have the basics down, and some of the not so basics, I really miss it when I have to use something else for any great amount of time.

I'm using it right now. OS X Yosemite, full screen terminal, and vim. Happy.

However I think to really get the most out of it you need to use it near constantly. After all you don't want to fall back down that steep learning curve!

Here are some of my favourite Vim tricks on Linux or Mac:

The indenting from the previous code maintainer is either non existent, or worse.

I strike this in older PHP code that I maintain. Four key-presses:

vim
gg=G

Meaning go to the start of the file, re-indent, to the end of the file. Works like a charm. However if you are using source control / versioning like git, you will want to do a separate commit. Otherwise seeing your later edits will be like looking for a particular tree in a far away forest!

Get a list of files, edit, run a command on each.

This is really handy for all sorts of things, and very powerful. For example you want to remove a bunch of files quickly and there is no easy way to use wildcards.

bash
ls | vim -

Now you have a list of files in vim. What you've done is pipe the listing to vim, which has been given the special filename of '-' which means 'stdin' i.e. the data being piped. Delete the files you don't want to do anything to, using general vim commands. So for example you end up with:

vim
file1.ext
file2.ext
file6.ext

Now:

vim
:%s/\(.*\)/rm \1/g

Meaning, for every line [%] substitute [s], matching and storing a pattern which matches the whole line [\(.*\)], with 'rm' and the stored pattern just found [\1]. You should end up with something like:

vim
rm file1.ext
rm file2.ext
rm file6.ext

So how do you run these? We 'filter' each line through an external program. Namely 'bash'.

vim
:%!bash

The % means all lines, the ! means filter, and bash means bash. Depending on if the 'rm' command on your system outputs anything, you may get each line replaced by lines saying 'file deleted' or possibly even nothing at all.

So thats nice you're thinking. A lot of effort for just deleting some files. OK, here is a better example. Your using git source control. Your removing files you don't want anymore, and forget to use 'git rm' instead of 'rm'. And you have done HEAPS of them over the course of a day. Also because they are already deleted, bash completion will not help you out a bit either.

bash
git ls-files --deleted | vim -
vim
:%s/\(.*\)/git rm \1/g
:%!bash
:q!
bash
git commit -m 'Eating files, nom nom nom.'

Another advantage of this technique is that you can see each file, and after the substitute each command you're about to run, allowing you a moment to reflect and think 'hang on, no, don't really want to do that.'

You have started editing a file but don't have permissions to save it.

So you open a configuration file to check something, see something wrong and change it. But you did not open it as a superuser. Damn it. Now you either have to do it all again, or save it somewhere else, and then copy it back.

But there is a way...

vim
:w !sudo tee %

There are several layers of magic happening here. The [!] is the 'run a command' thing again, like the above we did with bash. However here it is combined with the 'write' command, so Vim writes the file to the 'stdin' of the command line given. We use 'sudo' to escalate privileges to supercharged levels and run the 'tee' command. The tee command outputs anything it receives on 'stdin' to 'stdout' and also to any files you give it on the command line. This is where the [%] comes in, which in this case, Vim replaces with the current file name.