bling.github.io

This blog has relocated to bling.github.io.

Monday, February 11, 2013

Writing Macros with Vim

First, let’s start with a Javascript function:
function foo(hello, world,
             how, are,
             you) {
}
Now let’s convert that to the following:
function foo(parameters) {
    var hello = parameters.hello;
    var world = parameters.world;
    var how = parameters.how;
    var are = parameters.are;
    var you = parameters.you;
}
Here are the macros I used to do this:
let @r='di(iparameters^[/\{^M2o^[kpg`[v`]Jgv:s/\s//g^M0:try|exe "norm! @q"|endtry^MA;^[V:s/,/;\r/g^Mv``='
let @q='ywivar ^[pa = parameters.^[f,^[l@q'
Note that if you copy paste the above into your vimrc it will not work. The ^[ and ^M found are actually single characters, not two. To input this properly you will need to chord it in input mode with <Ctrl-V>. So for <Esc> you would chord <Ctrl+V><Ctrl+[>

So, when I’m inside the parameters of the function, I can hit @r and it will perform the refactoring. Now let’s break it down step by step.

@q The first macro


This is a recursive macro which takes something like a,b,c and turns it into var a = p.a,var b = p.b,var c = p.c. Let’s see how that’s done.
  1. yw i var <Esc> p Yanks the word and enter insert mode, type var, exit insert mode and paste the just yanked word.
  2. a = parameters. Append and fill in parameters.
  3. <Esc> f, l Exit insert mode, first the next ,
  4. l @q Adjust the cursor position and recursively call itself.
Recursive macros terminate when the first error occurs. In this macro, that error is when there are no more commas left.

@r The second macro


The is the macro that should be invoked, and references the @q macro.
  1. di( Deletes everything inside the brackets.
  2. i parameters Enter insert mode and type parameters.
  3. <Esc> /{ <CR> Leaves insert mode and finds the next brace.
  4. 2o <Esc> k p Creates two empty lines and pastes what we deleted into the first line.
  5. g`[v`] J Visually select what we just pasted and join them all into a single line.
  6. gv :s/\s//g <CR> Reselect the visually and delete all whitespace.
  7. 0 Move to the beginning of the line.
  8. :try|exe "norm! @q"|endtry <CR> Macros will terminate on the first error, even if referencing another macro. Wrapping the other macro with try|endtry swallows the error and lets the current macro continue.
  9. A; <Esc> Append ; to the end of the line.
  10. V :s/,/;\r/g <CR> Visually select the line, replace with carriage returns.
  11. v=` ` Visually select from the current cursor position back to where it was originally was, and format.
Now is this the best way to do it? Probably not. I would not be surprised if someone was able to do it with less keystrokes or a single macro.  But hey, it was fun learning experience, and ultimately I turned all of that into two keystrokes that can be reused many times.

I posted this on vimgolf so let’s see how other people solved the same refactoring!

Sunday, February 10, 2013

Love Affair with Vim

It wasn't too long ago when I was a full-time C# developer and my environment was Visual Studio eight hours a day.  Then, I became a web developer over night cold turkey writing Javascript and CSS.  It's one of the benefits of working for a consulting company.

You might think what does that have to do with the title of this post?  Well, originally my plan was to write a blog post contrasting on the differences between Javascript and C#, as well as the development environments and deployment platforms.  But really, what I really wanted to write about was Vim.

Moving from Visual Studio to Vim was a progression through different editors and environments.  The first thing I used to write Javascript was Webstorm.  Over time I realized that you didn't really need an IDE to write Javascript/CSS.  Then, I used Sublime Text for a little bit.  But ultimately, I settled on Vim, and stayed there.

My stubbornness turned out to be beneficial when I was learning Vim because the first month was absolutely painful.  I remapped all of my arrows keys to do nothing to force myself to use hjkl.  Eventually I got the hang of it, and now I definitely have the muscle memory that makes me much more productive when editing (and reading) text.

By default Vim is just a text editor.  But I work on a project, so like most lazy people I searched for prepackaged plugins and came across two popular distributions: spf13 and janus.  When I installed them, it was like someone took over Vim and made it change into a completely different beast.  I didn't know how to use it anymore.

I took a step back.  I forgot where I got this advice, but I think anyone using Vim needs to do this: start your own vimrc from scratch.

I took a look at all the settings that spf13 and janus changed.  I copied them to my vimrc one by one, and also :helping each setting so that I knew exactly what it changed.  I must say, Vim's documentation is some of the best and most comprehensive of any tool I've worked with.  It was incredibly helpful in my progression.

Then, I did the same thing for plugins.  And the nice thing was that most plugins followed the Vim pattern of having good documentation.  After installing fooplugin, I just :help fooplugin and I got all the information I needed to know about the plugin.

I became obsessed with optimizing my vimrc, and trying out different plugins on a daily basis.  And because I was very adamant with trying one plugin at a time, I got to know them very well.  I knew about how to turn certain settings on and off, how to configure their bindings, and more importantly, how it interacted with all of the other plugins I have already installed.  Over time my vimrc became a full blown distribution in its own right, highly customized to my personal work habits.

However, even though I recommend that anyone interested in taking their Vim skills to the next level should do this discovery that I have done, there are certainly classes of plugins that I deem to be must-have for any Vim user and I wanted to highlight them here.

Plugin Management

First things first you will need one plugin to rule them all!  Pathogen changed the way people install plugins by utilizing git submodules.  This has the pros and cons of git submodules, i.e. they track a specific version of the external git repository, so if plugin authors decide to rewrite everything new users trying out your distribution will not be in for a nasty surprise.

However, this rarely happens and usually you just want the latest version.  Vundle takes the management one step further and will automatically grab source code from Github for you (as well as automatically updating everything to the latest version).

The last one and least known is neobundle, which enhances Vundle even further and allows you to specify installation steps like compiling something.

Fuzzy File Searching

This was the major game changer for me and changed the way I worked.  Naturally, proper Vim technique forces your hands to be on the home row, which makes reaching for the mouse (or even the arrow keys) to be inefficient.  Therefore, the fastest way to open a file is usually to type its name.

CommandT (written in Ruby) is noticeably much faster than CtrlP (pure VimScript), but CtrlP has a lot more features.  There's also FuzzyFinder, which I have not tried.

Autocomplete and Snippets

There are various contenders here.  Generally, you'll find that people fall into two camps.


Snipmate is an older implementation of snippets which is getting replaced with UltiSnips.  Supertab gives you an easy way to trigger omnicompletion with (you guessed it) tab, and AutoComplPop is for automatically showing the popup as you type.

Neocomplcache is a very powerful completion plugin.  It runs a little slower than SuperTab because it does a lot more, but I find the performance acceptable so that's what I'm using.  And I choose neosnippet over the others simply because it's by the same author and thus has better integration (e.g. available snippets will appear in the list).

And of course, a good collection of snippets like honza's collection.

And that's it!

What?!  No file browser?  No buffer manager?  Yes, I have all of those installed as well.  In fact, I have over 50 plugins installed in total.  But in my opinion, they are not killer features.  I can live without them.  But if I didn't have fuzzy searching or completion/snippets, I would feel a little too naked.

Out of the box Vim has some interesting defaults, mainly for backwards compatibility with Vi, but I think it's safe to say that anyone who uses Vim seriously will have a custom vimrc.  If you're just starting out and don't know what to change, sensible is a good set of defaults.

Vim has changed my work habits dramatically.  I think and dream Vim.  I install Vim plugins in my browsers.  And every day, she still teaches me new tricks.  It's quite exhilarating!

If you've read until this point you might be interested in the full set of plugins that I'm using.  If so, head over to my project page!