NoVIMber

NoVIMber Notes


NoVIMber

Day 1

Forgive the pun in the title – I just can't resist.

Two weeks ago I ran into three different people who reminded me of the

"VIM tip of the day" e-mails that I used to send out. So for the month

of November I'm going to revive that tradition. Please forgive me if

some (or most) of these are going back over ground already covered in

previous tips of the day.

NoVIMber tip 1: buffers

VIM maintains a buffer for each file that you edit. If your session has

more than one file open, you can switch between buffers with the command:

:b<buffer number>

To get a list of the buffers you have open, type:

:buffers

To switch buffers, you can name the buffer directly:

:b2 (goes to buffer 2)

Or you can step through the buffers one at a time:

:bn (next buffer)

:bp (previous buffer)

You can load multiple files into buffers from the command line when you

invoke VIM:

vim foo.txt bar.txt baz.txt bash.txt

That will load the files foo.txt, bar.txt, baz.txt, and bash.txt into

VIM, each in their own buffer. foo.txt will be in buffer 1, bar.txt

will be in buffer 2, etc.

Happy VIMming.

Day 2

Buffers have been in VIM for a while, but there's a slightly more user-friendly feature that was recently introduced: tabs.

Tabs are available in both the terminal and GUI versions of VIM.  To create a new tab, type:

:tabnew

Presto – a new tab has opened.  This is basically the same thing as having multiple buffers open, but the tab listing at the top of the screen is a lot easier to recognize than keeping all of the buffers in your head.

To switch from one tab to the next, type:

:tabn

to switch to the next tab, or:

:tabp

to switch to the previous tab.  Or, if that's too many keystrokes, type:

gt

in normal mode (no : before the command) to go to the next tab.  To go to the previous tab, type:

gT

To open up a bunch of files in VIM with each one on its own tab, type:

vim -p file1 file2 file3

When you're done viewing/editing all these files, you can quit VIM completely by typing:

:qa

or

:wqa

The first quits all tabs, the second saves your changes first.

I'm new to using tabs myself, so hopefully I'll have more tab-related tips later this month.

Happy VIMming!

Day 3

VIM goes by many names.

You can invoke VIM on most systems with either "vi" or "vim". VIM's

name means "VI iMproved", and it is a clone of the original VI editor

created by Bill Joy. On most machines, "vi" is an alias for VIM and if

you invoke vi, it will start VIM in vi compatibility mode. This isn't

true on Rackspace's default RHEL 5 kicks – both VI and VIM are installed

side-by-side.

vi compatibility mode disables a lot of VIM's features, most notably

syntax highlighting. This is why I always type "vim" when starting the

editor.

There is another alias for VIM that is extremely useful: vimdiff. If

you need to compare to two (or more) versions of a file, type:

vimdiff <file1> <file2> <…>

It will open up a special instance of VIM with a vertical split for each

file. A special syntax highlighting mode will be invoked to display

differences between the files, and most of the matching content of each

file will be suppressed. It's a much more readable version of viewing

diffs than, say, "diff -u".

As with tabbed viewing, you can quit completely out of a vimdiff session

with:

:qa

vimdiff is not read-only, so you can edit the multiple splits if you

like and then save them with:

:w

Happy VIMming!

Day 4

VIM knows how to open files by URL, not just on the local system:

vim http://rackspace.com

vim ftp://ftp.microsoft.com/Softlib/README.TXT

vim scp://example.com/.plan

Opening a file over HTTP will download the web page and save a local copy in your temp directory as a read-only copy.  Opening it via FTP will prompt you for a username and password – in the example above, use 'ftp' or 'anonymous' and your e-mail address as the password.  Again, VIM will download the file to your temp directory, but with an FTP connection, if you edit the file and try to write it, VIM will attempt to write the file back to the remote server.  If you've got write access to the remote file this can be very useful.  SCP works the same way as FTP and can be handy if you've got key-based authentication set up with a remote server.

If you've already got a VIM session running, you can open a remote file by typing:

:e http://rackspace.com

Day 5

VIM can recognize files by their type and apply syntax highlighting.  On most RedHat systems, if you type:

vim /etc/httpd/conf/httpd.conf

it will open up the httpd.conf file with syntax highlighting automatically.  Comments will be light blue, key words will be kind of teal, plain text will be black, quote-enclosed strings will be red, etc., etc.  Syntax highlighting can make syntax errors pop out immediately and it also makes code a whole lot more readable.

If syntax highlighting isn't working, two things may be wrong.  First, syntax highlighting may just be turned off.  You can control it with:

:syntax on

:syntax off

If syntax highlighting is turned on but isn't appearing correctly, VIM may not know what the type of the current file is.  You can tell it the file type explicitly with:

:se filetype=<type>

Common types are apache, php, mysql, python, perl, c, c++, etc., etc.

You can see what types are available on your local system by looking in the syntax directory under the VIM installation directory.  On my Ubuntu system the full path is /usr/share/vim/vim72/syntax.  Each file in this directory defines the syntax of a specific type of file.

If you start a new file without an extension, you'll have to manually set the file type before VIM can apply syntax highlighting.

Day 6

Because of the syntax files mentioned in yesterday's tip, VIM can not only apply syntax highlighting but it can also autoformat your code.

Consider the following JavaScript snippet, yanked from flickr.com:

fixMaxWidth = function(el) {

try {

el.runtimeStyle.behavior = 'none';

var mw = fixMaxWidth_getWidth(el);

var nmw = parseInt(mw,10) || 10000;

var cW = parseInt(el.offsetWidth);

var cH = parseInt(el.offsetHeight);

var ratio = (cH/cW);

if (el.offsetWidth>nmw) {

el.style.width = (nmw+'px');

if (!isNaN(cH) && cH) {

el.style.height = (Math.ceil(nmw*ratio)+'px');

}   

}   

} catch(e) {

// oh well

}

}

It's not especially complicated, but it can be made more readable with a couple of keystrokes.

Open up an empty file named test.js in VIM and paste in that code.  Then type the following:

gg

VG

That will go to the first line (gg), turn on block highlighting (V), and go to the last line (G).  The entire file is now highlighted.

Now just type:

=

That's all.  '=' applies formatting to the selected block of text based on the current file's type.  Unfortunately, VIM can't do this trick with HTML files out of the box.  More on that later.

Happy VIMming!

Day 7

You can match enclosures like (,),{,},[ and ] in VIM by positioning the cursor on the enclosure and typing %.  It's very handy for navigating around code.  But by default, VIM doesn't know how to match more complex enclosures like HTML tags.

Luckily, there's a script called matchit.vim that takes care of that.  Go to http://www.vim.org/scripts/script.php?script_id=39 for the download link and installation instructions.  Now when you're editing HTML or XML files, you can jump to the matching tag with %.

Note that for this to work, VIM must already know what the file type is.  If the file doesn't have an .xml or .html extension, type:

:se filetype=html

or

:se filetype=xml

to let VIM know that you're working in an HTML/XML file.

Happy VIMming!

Day 8

Fun with registers

VIM provides several registers that can make editing a lot easier.  A register is analagous to a clipboard, except that instead of just having one, you've got several.  There are twenty-six "normal" registers, each named after a letter of the alphabet, and a few "special" registers which might get dealt with in a later tip of the day.

The registers can hold an arbitrary amount of text for as long as you need.  To put text into a register, you use the standard "y" (yank), "x" (cut), or "d" (delete) commands, except that you name the register you're going to use before executing the command.

For example, to yank the current line into register a, type:

"a yy

The "a keystrokes let VIM know that you're referring to a specific register.  The yy keystrokes yank the current line into that register.

After executing that command, type:

:reg

to view the contents of the current registers.  You'll probably see a lot of stuff in several registers, but the one you're concerned with is "a.  You should see the text of the line you yanked there.

After getting text into a register, you can paste it back in the same manner, using the name of the register followed by the "p" (paste after) or "P" (paste before) commands:

"a p

So VIM basically gives you twenty-six clipboards to use for shuffling your text around.  This can be very useful for editing complex documents quickly.

When you use the yank, cut, or delete commands with a register, VIM will replace the contents of that register with the text effected by the command unless you use the upper-case name of the register.  If you say:

"A yy

then VIM will append the yanked text to the existing register rather than replace it.  Keep this in mind – "a and "A are NOT different registers; they're the same, it's just that the way you refer to the register changes they way your editing commands behave.

Happy VIMming!

Day 9

Where my cursor at?

VIM's syntax highlighting can be very cool, but sometimes all the colors

on the screen can make it difficult to track where your cursor actually

is. Usually this isn't a big deal – just wiggle the cursor around with

a bunch of jkjkjk keystrokes and you can find it – but VIM's got a

couple of settings that make it easy to home in on exactly where your

cursor is.

The first is cursorline. With cursorline turned on, VIM will

highlight the row of the file where your cursor is.

:se cursorline

To turn it off, type:

:se nocursorline

If that's not precise enough, you can get a bull's-eye view of the

cursor by also enabling cursorcolumn:

:se cursorcolumn

(To turn it off, use :se nocursorcolumn)

With both cursorline and cursorcolumn turned on, you have a cross-hair

view of the cursor. How cool is that? This may not be the most

practical feature in the world, but it looks kind of groovy.

Happy VIMming!

Day 10

You complete me

One of the central philosophies of VIM is to get more done with fewer keystrokes.  There are features built into VIM such as templates, macros, and completion that are designed to minimize the typing you have to do when working in structured files.  Because when you think about it, there are only so many keystrokes you are going to be able to type in your lifespan.  By saving these precious keystrokes, VIM can literally prolong your life.

Or something.

Basic completion in VIM works by searching through the file that you currently have open and matching words.  Let's say you're editing an Apache httpd.conf and you're setting up a new virtual host.  

<VirtualHost *:80>

ServerName example.com

ServerAlias www.example.com

DocumentRoot /var/www/html

</VirtualHost>

In a default httpd.conf, the word "VirtualHost" already appears, so you can save yourself some keystrokes by using <CTRL>+p to autocomplete the word VirtualHost when you start typing it:

<Virt<CTRL>p

So you're typing the string "<Virt" and then, while still in insert mode, the CTRL key followed by p.  <CTRL>+p searches backwards in the file for the Previous match to what you've started typing.  <CTRL>+n searches for the Next match to what you've started typing.  Unless you're working on a really huge file that doesn't contain a lot of instances of the word you're searching for, these two commands are analagous because the searches will wrap.

But <CTRL>+p and <CTRL>+n only match a single word – that is, a string of characters bounded by whitespace or other non-alphanumeric characters.  Let's get turbo-lazy and complete entire lines instead.

<V<CTRL>x<CTRL>l

<CTRL>+x puts you in a special autocomplete mode.  The next set of keystrokes tells VIM just how you want to autocomplete what you've started.  <CTRL>+l completes whole lines.  And in an httpd.conf file using name-based virtual hosting, there's a really good chance that there's already a VirtualHost definition that you can use.

Another handy autocomplete sequence is <CTRL>+x <CTRL>+f, which autocompletes file names in your current directory.  If you have a dictionary file, you can tell VIM about it with:

:se dictionary=/path/to/dictionary

and then use <CTRL>+x <CTRL>+k to autocomplete based on words in that file.

Type less and happy VIMming!

-David

Day 11

"m" marks the spot.

If you find your self jumping back and forth in different locations in a file, you might find using marks to be a performance booster.

When you have the cursor in a location that you plan to return to, drop a mark by typing:

ma

That creates a mark named 'a' under the cursor.  Just like with registers, there are 26 named marks available (a-z).  There are also 26 marks (A-Z) which work across files.  To go to a mark once you've placed it, type:

'a

to jump to the line where the mark was placed, or:

`a

to jump to the line and column where the mark was placed.  If you've placed a mark with an uppercase name, then VIM will jump you to the mark even if it's in a file that is not currently open.

There is also a special default mark named ".".  It holds the location of the last edit made in the current file.  You can use "'." or "`." to jump to the last line edited or the last specific location edited.

Happy VIMming.

-David

Day 12

VIM supports syntax highlighting of a lot of different types of files, from C code to Apache configs. To make sure you're using the syntax highlighting, execute the following command:

:syntax on

If the highlighting doesn't appear, you may need to tell VIM what kind of file it is you're editing:

:se filetype=apache

Typing ":filetype" and hitting <ENTER> will tell you what type VIM thinks the file is currently.

All this is done automatically on most installations of VIM. So what if you log in to a server and the syntax highlighting is working, but you can't read it because of the colors?

Change the colorscheme. Type ":colorscheme " (note the space) and hit tab. VIM will cycle through the names of all the colorschemes currently installed. I kind of like 'desert' on most systems. Experiment and find one that works for you.

Day 13

This is one of the most flexible and powerful features of VIM: macros.

On day 8 I mentioned registers.  To recap: VIM provides 26 registers named a-z which can hold arbitrary text.  This text can include VIM commands.  When you are in command mode, typing q followed by the name of a register (a-z) will put you in to macro recording mode.  Once this starts, every keystroke you type will be recorded into the register that you named.

When working with large blocks of structured text, this is insanely productive.  When you're done typing the keystrokes that you need, hit <escape> to go back in to command mode and hit q again.  Now, all your keystrokes are in the register and ready for playback.

Type @+<register name> to play back the keystrokes.  VIM will play back exactly the commands you typed in while recording the macro, so if you need the cursor to drop to the next line, or if you need to search forward for some text, make sure that you end the macro with the appropriate keystrokes.

Since the macro is recorded to a register, the same rules of register use apply – if you want to append keystrokes to an existing macro that was recorded in register a, you can add more commands by typing qA (capital names append to registers).

Go crazy, and happy VIMming.

Day 14

This ain't your momma's undo

Like most modern applications, VIM has an undo/redo feature.  As you're typing along, you might realize that you've made a mistake and you want to undo it.  This is easy.  In command mode, type:

u

and VIM will undo your latest changes.  If you decided that you really did mean to make those changes, type:

<CTRL>+r

or

:redo

And the last change will be restored.

But VIM doesn't just store a linear stack of changes.  Often, the changes you make will cause branches in the document's change history, and VIM can help you navigate these changes.  If you type:

:undolist

You'll see a not-very-user-friendly list of information in three columns.  The first column is the change number, which is the branch's ID; the second is the number of changes that occurred in that branch, and the third is the time the branch was created.

The branch IDs are sequential, so if you remember the order in which changes were made, you can type:

:undo <ID>

to jump back to a specific branch.  But because the time stamps are included for each branch, you can also use the commands

:earlier

and

:later

:earlier and :later take an argument of minutes, seconds, or hours.  So if you made a change ten minutes ago and you want to revert to it, you can type:

:earlier 10m

And from there,

:later 5m

You can also use the following commands to scroll backwards and forwards through all change branches:

:g-

:g+

Happy VIMming!

Day 15

Seeing the Unseeable

This is why ninjas are scared of VIM – it allows you to see that which cannot be seen.  This is a trick that I learned when editing a lot of Python code in CORE.  As you may or may not know, in Python, whitespace is syntactically significant.  Indented lines are used to indicate the bodies of functions, classes, and loops.  Problems can arise when both spaces and tabs are used for indentation, because Python doesn't necessarily consider eight spaces to be the equivalent of two tabs, even though they may look the same to a human eye.

So when you have a file open in VIM and you want to view non-printing characters, you can turn on list mode to see non-printing characters:

:se list

With list mode enabled, tabs will appear as ^I, carriage returns will appear as ^M, etc.  To turn list mode off, type:

:se nolist

If you see a character and you're not sure what it is, you can use another couple of tricks to view the ASCII value of the character.  Put your cursor on top of it and type:

ga

(Think "get ASCII").  If you're editing a UTF-8 file, the command is:

g8

Then you can look up the value at http://www.asciitable.com/ or http://www.utf8-chartable.de/ to see what it is.  (Unless you've memorized the ASCII and UTF-8 tables, in which case you're probably an emacs user and not interested in these VIM tips anyway.)

Happy VIMming!

Day 16

VIM has a bunch of built-in event handlers which can be used to automate certain tasks.  These are known as autocommands.  You can define actions that get executed whenever one of these autocommands is fired to do things like read in a template file or write a note to a log file.  In today's tip, I'm going to show you how to use template files for certain file types.

Let's say you write a lot of HTML code, and you always find yourself creating the following structure:

<HTML>

    <HEAD><TITLE></TITLE></HEAD>

    <BODY>

    </BODY>

</HTML>

Instead of having to type that every single time you create a new .html file, you can write that structure into a template file.  In your home directory, there should be a .vim directory.  If there isn't go ahead and create one, then create a directory called templates and write your template file under the name html.tpl.

Now, add the following line to your .vimrc:

:autocmd BufNewFile *.html 0r ~/.vim/templates/html.tpl

That line tells VIM that you're defining a new autocommand that is to be executed when the BufNewFile action is triggered.  BufNewFile gets triggered every time a new file is created in vim.  In this case, if the new file's name matches the pattern "*.html", it's going to read in the contents of ~/.vim/templates.html.tpl.  So now, if you type:

vim brandnewfile.html

VIM is going to create the new file and read in the contents of your HTML template.

One note about this tip – I have no idea what the 0 in "0r" is for.  If anyone knows why the zero is needed, please let me know.

Happy VIMming!

Day 17

Plugin madness

VIM ships with a number of plugins, which are scripts that enhance VIM's basic functionality.  You'll find the plugins that shipped with your copy of VIM in $VIMRUNTIME/plugin.

(Sub-tip: don't know where VIM is installed?  In vim, type ":echo $VIMRUNTIME".)

We talked about syntax highlighting in an earlier tip.  Syntax highlighting is great and it makes code more readable, but if you take your text file that's all fancy in VIM and publish it on a web page somewhere, it goes back to dreary black text.

But it doesn't have to.  With a syntax-highlighted file open, type:

ggVG

(that highlights the entire file)

:TOhtml

(that creates an HTML document of your highlighted file)

Cool, huh?

Another fun pair of plugins are gzip.vim and tarPlugin.vim.  These are great because you don't have to do anything to activate them – just use VIM to open a .gz or .tar file (or, for that matter, a .tar.gz file).  VIM will uncompress your gzipped file on the fly and re-compress it when you're done editing it.  If you're opening up a .tar file, VIM will give you a list of the files in the tarball.

Happy VIMming!

Day 18

VIM scripts

We went over creating VIM macros in a previous tip.  If you save your macros to a file, you can have VIM run the macro against a file, effectively creating a batch mode for executing VIM macros.

Let's say that, for whatever reason, you want to convert a file to all lower case.  Create a file called lower.vim and put in the following lines:

ggVGu

:wq!

Make sure there are carriage returns at the end of each line.  Those commands will jump to the first line (gg), turn on visual highlighting mode (V), then jump to the last line (G).  The 'u' command at the end of the first line will translate all highlighted characters to lower case.  Then the next line writes and quits the file.

Now you can apply this script to any file with:

vim -s lower.vim /path/to/file

Maybe you want to translate all your XML files under the current directory to lower case.  In that case, you can combine VIM with 'find' to do some quick batch processing:

find . -type f -name \*.xml -exec vim -s lower.vim {} \;

Note that when you use VIM in this way, VIM does not operate in the background.  An instance of VIM is started for each file being processed, and the commands in the script file are run like a macro.  If your script file makes a lot of complicated changes, this can be really amusing to watch.  I run this on my computer at home instead of having a fireplace.

Happy VIMming!

Day 19

g wiz!

VIM's got a lot of helpful commands that start with g.  Not sure why g, of all letters, but there you are.

One that I find really helpful when running through Apache configurations is gf.  If you put your cursor over the path to a file and type:

gf

VIM will open up the file that's under your cursor.  So, given a vhost like the following:

<VirtualHost *:80>

    DocumentRoot /var/www/html

    ServerName example.com

</VirtualHost>

If you put your cursor over /var/www/html and type gf, VIM will open up a directory listing of that directory.  Or, if you've piped the output of httpd -S to a file and you put your cursor over the path to a particular virtual host's configuration file, you can open it up in the same way.  Note that if you've updated the current file and it hasn't been written to disk yet, VIM will complain that the current file hasn't been saved yet and gf will fail.

Another handy use of g is when you're editing a file with wrapped lines.  Ever find yourself on a line that is wrapped, and you want to make a change that's right below the cursor, so you type j or hit the down arrow, but the cursor skips right past what you want and goes to the next line?  Don't you just HATE that?  Well, if you type gj or g<down arrow> instead, the cursor will move according to displayed lines, not logical lines.  Much better.

Finally, my favorite stupid VIM trick.  g?  will ROT-13 text.  Use the ggVG sequence to highlight your entire file.  Then type:

g?

And presto – every alphabetic character is shifted 13 places to the right in the alphabet.  Quick and easy obfuscation.

Happy Thanksgiving and happy VIMming.

Day 20

Thanks everyone for reading along.  I hope you've enjoyed reading these tips as much as I've enjoyed writing them.

For the last installment, I wanted to share a very cool feature in VIM that I am just beginning to learn how to use.  VIM provides support for Perl, Python and Ruby so that you can use these languages to create functions in VIM.

I'm most familiar with Python myself, so here are a couple of examples.  In VIM, try the following:

:python print "Hello world"

You'll see 'Hello world' show up in the status line at the bottom of the screen.  Cool, but not all that handy (though you can use this as a quick calculator, e.g. :py print 256 * 8 ).

To actually get Python to do something interesting with the contents of your editor, you can define a VIM function that uses Python to do the heavy lifting.

Here's how:

:function! PySort()

python << EOF

import vim

b = vim.buffers[0]

x = b[:]

x.sort()

b[:] = x

EOF

endfunction

The :function! line begins a function definition.  VIM has its own internal scripting language, which is swell and all, but if you already have familiarity with one of the other supported languages, you can use that language to get a jump start on seriously tricking out VIM.

The line:

python << EOF

tells VIM that we're defining a block of Python code.  The block will end with the line "EOF".  The enclosed lines are pure Python.

First, we import the vim module:

import vim

Now we have access to that module's components, like the buffers[] list.  Just like in normal Python, buffers[] is zero-indexed, so buffers[0] is the first buffer.

Next, we copy the contents of b as a list into the variable x:

x = b[:]

Then we sort that list alphabetically:

x.sort()

Then we replace the current buffer with the sorted context of x:

b[:] = x

And voila – you can now sort the current buffer alphabetically by calling the PySort() function:

:call PySort()

This is just a trivial example, but hopefully it gives you some ideas of what can be done with Python (or Perl, or Ruby) inside of VIM.

Thank you all for reading.  Anyone interested in exploring any of the topics discussed in this or previous tips should feel free to e-mail me.  Or better yet, come by my desk with food.

Happy VIMming!