vim faster with maps

At myYearbook, we pack our JS and CSS files.  Much of this is automated now with Jenkins, but we still have legacy code that must be packed by hand.  And, at the same time, it’s generally wise to test your product with a packed file regardless.  I also try to make it a habit to phpcs my file as often as possible.  The goal here is to keep the file as tidy as possible, and not waiting for the end to fix everything.  Also, during the course of development, I might come across other little things I want to do, and I use vim to make things as easy as possible.

maps

I do this through maps.  I map is fairly simple to setup in vim.

:map ,cs <ESC>:w|:!phpcs --standard=myYearbook %:p

Typing that into a vim instance means I can type ‘,cs’ in normal mode, and vim will w my file to disk, then run phpcs using the myYearbook standard on the current file I’m working in.  Now, I use that often enough that I’ve added it to my .vimrc file.

map <Leader>cs <ESC>:w|:!phpcs --standard=myYearbook %:p

If you aren’t aware, <Leader> is set to ‘,’ using this bit of code in .vimrc:

let mapleader = ","

The comma is popular, but you can use whatever you want, really.

I can also pack my javascript and CSS files with similar ease using “,pj” and “,pc” (pack javascript, and pack css).

map <Leader>pj <ESC>:!jspack %:p > %:p:h/%:r:r.js
map <Leader>pc <ESC>:!csspack %:p > %:p:h/%:r:r.css

You might be wondering what the ‘%:p’ part is.  It’s actually part of the expand functionality of vim.  Basically, the important parts here to understand is that the % is the current file name.  The “:p” and “:r” parts are the modifiers.  In this case, “%:p” has us expand to the full path.  The “:h” modifier removes the last component.  So, “%:p:h” basically says “Give us the full path, and then remove the head.  The head in this case is the file name, so if the full path (“%:p”) is /Users/jasonlotito/test.php, “%:p:h” gives us “/Users/jasonlotito”.

“%:p:h/%:r:r.js” allows me to rename my file.  In our setup, unpacked files contain the extension “.unpack.”  By Simply using the “:r:r” modifiers, I strip off the “.js”, and then the “.unpack”, leaving me with just the file name.  So, if my javascript file was named Modifiers.unpack.js, I’d be left with Modifiers.  I prefix that with %:p:h/ which gives me the directory the file is in, and append “.css” to the path.

Being able to map commonly performed actions, especially to external tools, means I can stay in vim longer.  Sure, I’ll still background vim when I need to perform certain actions, but I’m more apt to start scripting repeated actions, and then mapping them.

Learning the vi language

I’m a long time user of vi (and I use vi interchangeably for both vi and vim), but it wasn’t until recently that I really started to understand the way vi works.  Oh, I could be productive in vi, but I wasn’t adept at learning vi.  I edit files in vi, I could open windows, I could move around, copy and paste, search and replace, and generally do the normal things you can do in other editors.  So when I had to open up vi, I didn’t freeze up and get lost.

Don’t Repeat Yourself

The problem here is two-fold.  First, I was looking for how to replicate actions I would perform in other editors. Saving a file, editing text, copy and paste, search and replace: all these things easily map to something you’d do in a traditional IDE.  You don’t replace a character in a traditional IDE.  You delete a character and enter a new one.  To copy and paste big blocks of text, you highlight that text with a mouse.  You navigate to different tabs with your mouse.  When you want to split your window, you probably have to do so with the menu.  You don’t append to a line.  You simply move your cursor and start typing.  You don’t jump to a character, and while you can, you rarely jump to a line.  You aren’t yanking lines, you don’t concern yourself with buffers, and you don’t repeat your actions.

Basically, an IDE more closely resembles a word processor for programming languages, whereas vi is a completely different beast (vi vi vi, editor of the beast, after all).

Therefore, the first thing I had to understand before really learning vi was I had to look past replacing what I did with an IDE, but rather, understand how to do things in vi.  And this is a fairly easy concept to understand once you learn one of the defining principles of using vi: if you have to keep pressing the same key to do something, you are probably doing it wrong.  Consider the basic movement keys: hjkl.  Using ‘j’ and ‘k’ to move more than one line should indicate to you there is a better way.  Moving to the top of the screen, the bottom, the middle, move up a page, half a page, or down.  These aren’t things you do in an IDE (you scroll), but in vi, that is an essential piece to the puzzle.

So, every time I wanted to do something, and I found myself repeating actions that seemed awkward, I’d search for a way to do it.

Find out more about noticing and unlearning vi anti-patterns with this excellent article from Tom Ryder.

Learn the Language

This leads us to the second thing I had to understand in order to really being learning vi.  You don’t learn vi by learning commands, you learn vi by learning a language.  Once you have a firm grasp of the language, you can start putting together your own commands.  Discovering new commands seems to become more intuitive.

Lets see this language in action.  Normally, if you want to delete a line, you’d type ‘dd’.  This deletes the line (and stores it away so you can paste it later if you want).  What if you want to delete more than one line?  You could repeat ‘dd’ on each line you wanted deleted.  But let’s say you want to delete the next 10 lines.    This is where the language comes in.  What you want is to delete 10 lines down.  So, you start with ‘d’, then enter 10, and finally, ‘j’ for:

d10j

This isn’t so much a command you need to remember.  Rather, it’s easier if you understand the language.  Deleting 5 lines up can be constructed the same way:

d5k

Once we learn how this language works, we can create our own commands

‘==’ will indent the current line.  We can follow the same pattern as delete to construct the following:

=5j

This properly indents the next 5 lines.  Of course, we can also do ‘gg=G’, which will move you to the first line, and then indent all lines until the last line.  We can do ‘ggdG’ as well, which will delete all the lines in the file.

The actual commands aren’t important.  Rather, it’s the language.  Once you understand how ‘d’ works, you can use the same language in other areas as well.

Want to copy the next five lines?  Just knowing that ‘yy’ will copy the current line, you could easily discern that ‘y5k’ will yank (copy) 5 lines up.

You can learn about speaking the vi language by reading an excellent article from Yan Pritzker.

Investment of time

Yes, learning vi will take time. It’s not something that will come naturally.  It’s a tool, and like any powerful tool, you have a lot to learn to truly start taking advantage of it.  It’s a professionals tool.  It’s a craftsman’s tool.  It’s something that, regardless of whatever else you might learn, will benefit you as long as you are programming.

Sure, you might enjoy your IDE, and I’m not here to suggest you drop your favorite tools.  Rather, it’s worth the investment to understand vi, it’s language, and how it works.  Even if you aren’t using it every single day, you’ll appreciate being able to open up the editor and using it without feeling constrained.

Other Resources