Eliminating Repetitious Coding With Vim / ViEmu And Macros

Anyone that has been following me on twitter recently is probably aware that I’ve been trying to learn Vim and ViEmu for Visual Studio. It’s been a very slow, somewhat painful learning process, but I think it is finally starting to pay off. I won’t bore you with most of the details as you can find plenty of stories on people’s converting to vim, around the web. What I did want to share was that I just learned how to cut down on serious code repetition using vim’s macros.

 

The Code That Needs To Change

Here’s the code that I started with. It’s from the code behind of a view implementation in a Model-View-Presenter setup.

   1: public void SelectCategory(Lookup category)

   2: {

   3:     cboCategories.SelectedItem = category;

   4: }

   5:  

   6: public void SelectGroup(Lookup group)

   7: {

   8:     cboGroups.SelectedItem = group;

   9: }

  10:  

  11: public void SelectAssetType(Lookup assetType)

  12: {

  13:     cboTypes.SelectedItem = assetType;

  14: }

  15:  

  16: public void SelectProductCode(Lookup productCode)

  17: {

  18:     cboProductCodes.SelectedItem = productCode;

  19: }

Notice that each of these 4 methods is basically the same line of code – just applied to a different combobox, with a differen Lookup object being selected. It’s not exactly rocket science, here… pretty straight forward.

 

Bugs And Refactoring

There’s a bug in some of the surrounding code caused by the combobox “IndexChanged” events being fired every time I set the selected item with this code. Additionally, there are some visual artifacts that are semi-related to this code (due to this code running on the Compact Framework for Windows Mobile and Windows CE devices) and I want to clean them up.

To fix these issues, I need to call a “TearDownComboBoxEvents()” as the first line of each method, and then call “Application.DoEvents()” and “SetupComboBoxEvents()” as the last two lines of each method. Rather than re-type those three lines of code over and over again, I want to extract them into a method that each of the above methods will call, providing the correct combobox and item to the method. This code provides that functionality:

   1: private void SetSelectedItem(ComboBox comboBox, Lookup lookup)

   2: {

   3:     TeardownComboBoxEvents();

   4:     comboBox.SelectedItem = lookup;

   5:     Application.DoEvents();

   6:     SetupComboBoxEvents();

   7: }

 

Putting It All Together With A ViEmu Macro

Now that I have the method I want to call, I just need to make each of the Select methods from the first code snippet pass in the right combobox and lookup item. A few weeks ago… well, ok… yesterday morning… I would have manually modified each of these methods. This would involve re-typing “SetSelectedItem” 4 times (or at least copy & pasting it 4 times), deleting the “.SelectedItem = “ 4 times, adding a comma between the combobox name and the lookup variable 4 times, and inserting a closing parenthesis just in front of the closing semi-colon 4 times… all while using the arrow keys dozens of times to move my cursor around to make those changes.

That’s a lot of repetition and I really wanted to learn how to avoid it… so… in comes our new hero, Vim/ViEmu and macros! Here’s what I did to solve this with a macro. First, I set my cursor (in “Normal” mode) on the very first character of the “cboCategories” variable in line 3 of the first code snippet. I then recorded this macro:

qaiSetSelectedItem(<esc>2wc3w,<esc>$i)<esc>q

After recording that macro, I was able to place my cursor (again, in “Normal” mode) on the first character of each of the subsequent combobox variables in the other 3 Select methods and run the macro by typing:

@a

that’s right… 2 characters to replay the macro I just wrote. That’s 30+ keystrokes boiled down into 2 for all of the subsequent method call changes! I save 90+ keystrokes by recording this macro and replaying it against the other 3 lines that needed it. You want to talk about DRY code? Yeah, let’s talk about DRY code writing for a bit… :)

 

The resulting Code

Here’s the results of running this macro on the methods:

   1: public void SelectCategory(Lookup category)

   2: {

   3:     SetSelectedItem(cboCategories, category);

   4: }

   5:  

   6: public void SelectGroup(Lookup group)

   7: {

   8:     SetSelectedItem(cboGroups, group);

   9: }

  10:  

  11: public void SelectAssetType(Lookup assetType)

  12: {

  13:     SetSelectedItem(cboTypes, assetType);

  14: }

  15:  

  16: public void SelectProductCode(Lookup productCode)

  17: {

  18:     SetSelectedItem(cboProductCodes, productCode);

  19: }

  20:  

  21: private void SetSelectedItem(ComboBox comboBox, Lookup lookup)

  22: {

  23:     TeardownComboBoxEvents();

  24:     comboBox.SelectedItem = lookup;

  25:     Application.DoEvents();

  26:     SetupComboBoxEvents();

  27: }

It’s all correct… each method is calling SetSelectedItem with the right combobox and the right lookup object.

 

“That Was Easy”

This is quite possibly the most basic of useful macros that I could imagine… yet look how powerful it was. It prevented me from having to copy & paste and then change all the variable names to the correct ones, or re-type the same thing over and over again. I’m not even using anything more than some very basic movements in that macro: move 2 words, change 3 words, move to the end of the line… those are the only movements I’m using… no special cool extra awesome sauce here… just some simple ‘move my cursor a few paces’. Because the code I was working with had a regular pattern to it, I was able to easily craft a macro that accounted for the contextual differences in each of the methods that needed to be changed.

If you’re still not sold on the power of Vim/ViEmu… well… have fun with those 90+ extra keystrokes. I’ll keep my Vim/ViEmu, thankyouverymuch. :)


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in .NET, C#, Refactoring, Tools and Vendors, Vim. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Dustin Venegas

    I have grown pretty attached to ViEmu over the past couple of years.

    You might make a note that VS2010 doesn’t have a working version of ViEmu ready yet, but it should be coming soon. Once you’re used to vim, CTRL+Arrowing is a real bummer.

  • http://www.lostechies.com/members/derick.bailey/default.aspx derick.bailey

    @Dustin,

    check out VsVim for VS2010: http://github.com/jaredpar/VsVim

    it’s not quite as polished as viemu, but it’s very functional and free!

  • Harry

    You do not need ViEmu to do this. Why not just use the built in macro functionality in visual studio CTRL + SHIFT + R (Record Macro) and CTRL + SHIFT + P (Run macro). It is somewhat slow and might not be as smooth as ViEmu, but is works.