Sunday, January 25, 2015

Vi Vies with Vim and Vigor (Or, There's No Place Like Home) - Vim, Part 0

This is the first in a series of articles about using Vim.  If you write code or analyze data, but don't use Vim yet, then you should read this, because Vim gives you super-powers.

Before I get to details, a word about the title.  I spent a summer at my grandmother's house, where she taught me to touch-type on a typewriter in her basement.  One of the sentences I had to type over and over again, presumably to learn to reach the letter 'v' without leaving the home row, was:
Vi Vies with Vim and Vigor
You see, my grandmother was a hardcore UNIX hacker, and she knew that to prepare me to use Vi, she needed to teach me to touch-type.  I am infinitely thankful for this.

In this first installation I'll talk about how to make Vim comfortable: some unique ways to get around, how to copy and paste, the repeat / undo / redo operations.  But I'm going to start off with:

Getting Some

Incredibly, you can get Vim for Windows:

Yes, Virginia -- there is a Santa Claus.

If you're on Linux, use your package manager.  I'm mostly going to use gVim (the GUI version of Vim), though it doesn't make a lick of difference in terms of functionality.

Getting Started

If you never have, take 15 minutes out of your life to run through vimtutor.  It's in the Vim install directory.  You don't have to get to the end (I never did).  If you're already ready already, then read on.

Getting Around (Motions)

Aside from h,j,k,l (left, down, up, and right, respectively), Vim offers other motions:

ggmove to top of file
Gbottom of file
H or Ltop or bottom of window
/whatevermove to next instance of whatever (i.e., search)
*move to next instance of whatever is under cursor
:3move to third line
wmove to the next word
b or emove to beginning or end of word, or next word in the corresponding direction
( or )move to beginning or end of sentence
{ or }move to beginning or end of paragraph
gj"go" down one wrapped line
n or Nmove to next or previous search match
%matching parenthesis, brace, or bracket

These are just a few that I find interesting and useful.  The most interesting things that can be done with motions, though, are edits.

Motion Sickness

Motions can do some pretty cool stuff.  For example, >} will indent all the contiguous lines below the cursor until an empty line is encountered, dn will delete until the next occurrence of the last search, and ggyG will copy the entire buffer.

Although not strictly "motions" per se, there are other selection techniques.  For times when you don't know exactly what you want to select for a particular edit, you can use the v command to enter visual select mode, then move the cursor around as much as you want.  Hit Esc to cancel the selection, or use y to yank (copy) it or d to delete it.

You can also select the word, sentence, or paragraph your cursor is in the middle of, with the aw, as, and ap selections.  For instance:

caw"change a word", moving the cursor to the beginning of that word
ci"change everything in the quotes surrounding the cursor (shout-out to huf for sharing that one)
das"delete a sentence", removing everything between the last and next period
yap"yank (copy) a paragraph"

Where does stuff go when you copy or delete it?


When you yank (y) or delete (d) text, it is automatically saved for you to paste (p) again.  The place where it is saved is like a clipboard that only Vim can see, and it is called a register (specifically, the unnamed register).  In Vim, registers are named memory locations into which data can be copied (where you specify the register with the " command modifier) and macros recorded (where you specify the register with the q command).  So, you can copy one line -- "ayy -- and then copy another -- "byy -- without losing either copy.  Paste them by typing "ap and "bp respectively.  Deletion works the same way, and there is a "black hole" register named _ (underscore) that allows you to delete stuff without clobbering something you just copied to the unnamed register.  So, you can copy a line into the unnamed register -- yy -- and delete a line into the black hole register -- "_dd -- and then paste the line you originally copied -- p.

Vim has help on all its commands.  For instance, I typed :help "_ to figure out what the "_ register was called, and I found this:

There are nine types of registers:   *registers* *E354*
1. The unnamed register ""
2. 10 numbered registers "0 to "9
3. The small delete register "-
4. 26 named registers "a to "z or "A to "Z
5. four read-only registers ":, "., "% and "#
6. the expression register "=
7. The selection and drop registers "*, "+ and "~ 
8. The black hole register "_
9. Last search pattern register "/

I've already mentioned the unnamed register (1) that is used by default, the named registers (4) that you can choose when to use, and the black hole register (8) that you can use to avoid overwriting the last copy or delete that you did.  The only other one I use is the clipboard register, "+ which I can use to transition into a whole new section...

Sneaking Stuff Into Vim

To finish off the discussion of registers and start the discussion of getting data into Vim, here's the "+ register.  Supposing you've copied something in another app, you can type "+p to paste it in Vim.  Likewise, if you want to copy a paragraph to the clipboard in Vim, you can type "+yap and then paste it into any other application.  You can also :read files into your buffer by name, or execute !!commands to get their output into Vim.

Doing it... Over and Over Again

Suppose you want to do it again.  And again.  And again.  You use . (dot) for that.  For instance, I've got a list of servers that I need to surround in quotes and make comma-separated for some sort of configuration file.  Here's what I'll do:

  • Go to the first line and line insert a quote at the beginning - I"<Esc> 
  • Go to each line and repeatj. (note the trailing dot)
  • Go to the beginning - gg 
  • Append a quote and a comma to the first line - a",<Esc> 
  • Again, go to each line and repeatj. (again, note the trailing dot)
  • For the finale, I'll go to the top, visually select to the bottom, and join all - ggvGJ 
Because I'm an exhibitionist, I took a grainy, low-quality video of me "doing it over and over again" -- inserting quotes and commas, that is:

Undo and Redo

An editor wouldn't be complete without undo and redo.  Undo is obvious: hit u to undo something.  Redo is less obvious (and requires pinky contortions): hit <CTRL>-R to redo something that was undone.

Sometimes I need to undo a few times to see what you did.  And sometimes I use this to undo everything and progressively redo changes when I've totally botched something in my code.  You just want to save the latest to a backup in case you make the mistake of making a change (thus obliterating the redo buffer) before you fast-forward all the way to the idiotic assumption that caused all your pain in the first place.  The procedure usually goes something like this:

  • Add a thousand lines of "great" code and re-factor the hell out of my project
  • Compile, test, and cry because it used to work
  • Save my "brilliant" changes - :w backupfile 
  • Undo everything - 99999u 
  • Repeatedly redo in order to review changes and catch my mistake - <CTRL>-R 
  • Replay all the other (good) changes so I can go back to line 269 and add a $#@*! semicolon - 99999<CTRL>-R 


So there's part one.  Part two is forthcoming, and will include more slick stuff -- hackin' up binaries, scripting, writing shellcode...  Stay tuned.

No comments:

Post a Comment