History Report a problem
Article Edit this page Discussion

Vim as a refactoring tool and some examples in C sharp

From Vim Tips Wiki

Jump to: navigation, search
 

Tip 589Previous TipNext Tip

Created: October 16, 2003 Complexity: intermediate Author: Klaus Horsten Minimum version: 6.0 Karma: 225/77 Imported from: Tip#589


You can use Vim as a refactoring tool. The advantages are:

  1. You automate repetitive writing tasks.
  2. You learn refactoring.

You can expect much from a refactoring tool but if you have a look at the commercial refactoring tools there is much (not all!) Vim can do too.

I give you three examples, all in C#.

Contents

[edit] Example 1: The Extract Method refactoring

Sphagetti code example:

public string CreateMenu(string startMenu,string file)
{
     string strOutput = "";
     int i = 0;
     ArrayList startArray = new ArrayList();
     string strVariable = "";
     string strTemp = "";
     XmlDocument XMLDoc = new XmlDocument();
     try {
         XMLDoc.Load(file);
     }
     catch (Exception e) {
     strOutput = e.GetBaseException().ToString();
     return strOutput;
}
XmlNodeList nodeList = XMLDoc.DocumentElement.ChildNodes;
...

Imagine 50 lines of code here.

Use the extract method refactoring to make a composed method.

I use a Vim function (see below) to build the exracted method.

I highlight the code part I want to extract and press \em (for extract method).

A dialog appears and asks me how to name the new method.

I type in "GetXmlDocumentFrom" and do get this:

// = GetXmlDocumentFrom();
private GetXmlDocumentFrom()
{
    XmlDocument XMLDoc = new XmlDocument();
    try {
        XMLDoc.Load(file);
    }
    catch (Exception e)
    {
        strOutput = e.GetBaseException().ToString();
        return strOutput;
    }
    // return ;
}

Now I have time to think what parameters the method needs and what to return.

I end up with the following function and remove it from the original function:

private XmlDocument GetXmlDocumentFrom(string XmlFile)
{
    XmlDocument XMLDoc = new XmlDocument();
    string strOutput = "";
    try
    {
        XMLDoc.Load(XmlFile);
    }
    catch (Exception e)
    {
        strOutput = e.GetBaseException().ToString();
        ErrorMessage(strOutput);
    }
    return XMLDoc;
}

In the original code I put two lines.

XmlDocument XMLDoc = new XmlDocument();
XMLDoc = GetXmlDocumentFrom(XmlFile);

So I reduced the original code for 8 lines and made it clearer what the code does.

I do this with the rest of the code again and again.

Since the class gets bloated because of the many new methods I later will use the Extract Class refactoring to put this method in an own XmlDocument-class.

This has the advantage that our new function is also available for other similar purposes.

I will create the new class also with the help of Vim, the actual extracting of the method into the new class is just a matter of copy & paste.

Here is the Vim code:

vmap \em :call ExtractMethod()<cr>
function! ExtractMethod() range
  let name = inputdialog("Name of new method:")
  '<
  exe "normal! O\<bs>private " . name ."()\<cr>{\<esc>"
  '>
  exe "normal! oreturn ;\<cr>}\<esc>k"
  s/return/\/\/ return/ge
  normal! j%
  normal! kf(
  exe "normal! yyPi// = \<esc>wdwA;\<esc>"
  normal! ==
  normal! j0w
endfunction

[edit] Example 2: The Self Encapsulate Field refactoring

I have heard a programmer who just uses Visual Studio (nothing against Visual Studio, it's a great tool!) say: "I do not use properties. It's too much work." He just uses fields instead.

With Vim it is no problem to write a property, that is, to use the Self Encapsulate Field refactoring.

I write a name e.g. Name press CTRL-C CTRL-P CTRL-S (create property with string). Voila, the new property appears in just a second:

private string m_Name;
public string Name
{
    get
    {
        return m_Name;
    }
    set
    {
        m_Name = value;
    }
}

Here are the Vim mappings and the underlying function:

"Create property
imap <C-c><C-p><C-s> <esc>:call CreateProperty("string")<cr>a
imap <C-c><C-p><C-i> <esc>:call CreateProperty("int")<cr>a
function! CreateProperty(type)
  exe "normal bim_\<esc>b\"yywiprivate ".a:type." \<esc>A;\<cr>public ".a:type.
        \ " \<esc>\"ypb2xea\<cr>{\<esc>oget\<cr>{\<cr>return " .
        \ "\<esc>\"ypa;\<cr>}\<cr>set\<cr>{\<cr>\<tab>\<esc>\"yPa = value;\<cr>}\<cr>}\<cr>\<esc>"
  normal! 12k2wi
endfunction

You can combine Visual Studio and Vim. You can work in Visual Studio and load the file in Vim for refactoring. I have made a menu entry in Visual Studio that loads the actual file I am writing in Vim (cf. VimTip580).

[edit] Example 3: The Replace Conditional with Polymorphism refactoring

Imagine a switch and you want to replace it with an abstract class and some concrete classes which inherit from this parent class.

You may think "Why should I replace this switch? It's too much work. Writing all these classes ..."

With Vim it's just a question of a few seconds.

To build the abstract class I type, say Fruit.

Then I press CTRL-C CTRL-A CTRL-C (create abstract class) and get

public abstract class Fruit
{
    public abstract void |();
}
                         | is the cursor position

Now I fill in the methods.

public abstract class Fruit
{
    public abstract void Taste();
    public abstract void Color();
    public abstract string GetSize();
}

Now I go on the first letter of Fruit and type CTRL-C CTRL-C CTRL-C (create concrete class).

A dialog appears and asks me for the new name of the concrete class. I type in Apple and get

public class Apple : Fruit
{
    public override void Taste()
    {
    }
    public override void Color()
    {
    }
    public override string GetSize()
    {
    }
}

I continue doing so with all the child classes of the abstract class.

In this way I get code templates that I can implement now.

Here are my mappings and the underlying funtion.

"Create abstract class
imap <C-c><C-a><C-c> <esc>bipublic abstract class <esc>A<cr>{<cr>public abstract void X();<cr>}<esc>:?X<cr>0fXs
"Create concrete class
map <C-c><C-c><C-c> :silent! call ImplementAbstractClass()<cr>
function! ImplementAbstractClass() range
  exe "normal \<esc>\"yyw"
  /{
  normal "xy%
  normal %o
  exe "normal! \<esc>o"
  let name = inputdialog("Name of new method:")
  exe "normal! ipublic class " .name." : \<esc>\"yp\"xp"
  exe "normal! }O}\<esc>=="
  normal %v%
  normal! gv
  '<,'>s/abstract/override/g
  normal! gv
  '<,'>s/;/\r{\r}\r/g
  normal! ==
  normal %kdd%k
endfunction

[edit] Comments

 

These are amazing! I never thought of doing this, but I have to say your tips are quite amazing! I have not begun to use hints 1 and 2 religiously, especially when I have to dig around through code that others have written! Thank you!!


Here is a variation

imap <C-c><C-p> <esc>:call CreateProperty()<cr>a
function! CreateProperty()
  exe "normal bim_\<esc>b\"yyybiprivate \<esc>A;\<cr>\<esc>\"ypw\"xyw\<esc>2xbipublic \<esc>$a\<cr>{\<esc>oget\<cr>{\<cr>return \<esc>\"xpa;\<cr>}\<cr>set\<cr>{\<cr>\<tab>\<esc>\"xPa = value;\<cr>}\<cr>}\<cr>\<esc>"
  normal 12k2wi
endfunction

This will create a property from a <type> <Field Name>. This alleviates the need for multiple mappings for each data type in the vimrc file

So if you want to create a property from Rectangle Box just press <C-c><C-p> and you get

private Rectangle m_Box;
public Rectangle Box
{
    get
    {
        return m_Box;
    }
    set
    {
        m_Box = value;
    }
}

I am still trying to get rid of some extra spaces in property name but I hope this helps


Rate this article:

Share this article:

Hubs Highlights International Sites Wikia messages
Entertainment
Gaming
Cartoons & Comics
Science Fiction
Hobbies
Sports
See all...
Grand Theft Auto
Doctor Who
Legend of Zelda Wiki
Terminator Wiki
Everquest II Wiki
Mystery Science Theater 3000
German
Spanish
Chinese
Japanese
More...
Wikia is hiring for several open positions
Send this article to a friend
"Vim as a refactoring tool and some examples in C sharp"
 
 
Hi!

I thought you'd like this page from Wikia!

http://vim.wikia.com

Come check it out!
Send confirmation