CodeRush Plugin – Cleanup File and Namespaces - How does it work?

As promised in my last post, I’m going to explain just how the CleanupFileAndNamespaces plugin works.

To recap, this plugin creates a new Command (CleanupFileAndNamespaces) which will cause CodeRush to fire the “Organize Namespace References” refactoring followed by the “CleanupFile” command.

So how does it work?

Overview

This plugin consists of a single new command. When this command is triggered, it will perform a simple sequence of steps, which together will create the effect we are after.

The high-level steps are:

  1. Store current location
  2. Execute CleanupFile command
  3. Move caret to first using \ Imports directive
  4. Execute Optimize Namespace References refactoring
  5. Restore Caret location.

We’re going to look at 2 through 4 first and then revisit 1 and 5 together,

Execute the CleanupFile command

Executing an Command requires that we first know the name of the command we want to execute.


CommandListIn this case I know that the command I want is called CleanupFile.
However if I did not, the best place to check would be the Shortcuts options page.

The Options screen can be found via DevExpress\CodeRush\Options.
The Shortcuts page can be found at IDE\Shortcuts.

On the right of this page is a dropdown labelled Command.
This dropdown contains a list of all the Commands that CodeRush is aware of.

Remember from previous blog posts that everything about CodeRush is dynamic, and so if you create a new action (the internal name for a command), you’ll find that CodeRush will list that action in this dropdown as well.

We’d like to execute a command to cleanup the current file. Looking down through the list of commands, we soon come across several which are prefixed with the phrase Cleanup. They appear to work at a number of different levels (File, Folder, Project and Solution). We’ll pick CleanupFile for our plugin.


Once we know which Command we’d like to execute, we need to get a reference to it in code. Internally commands are known as Actions. So in order to get a reference to the CleanupFile action, we would use code like….

GetActionCleanupFile

Having got a reference to the action, we can execute it like so….

ActionExecuteCleanupFile

Now that we know how to execute an action, let’s move on to the slightly more complex task of executing a refactoring.

Position the Caret.

Refactorings are very context sensitive and are typically not available all of the time. In this case the caret must be placed on a using (or imports) directive, before it will be available to use.

In order to locate the first using\imports directive, we will use an ElementEnumerable object.

This class is created with a scope (the Active File) and a LanguageElement Type (NamespaceReference – The internal name for a using or imports directive).

ElementEnumerable

Then we ask this class to enumerate and provide us with the first matching Element it can find.

GetFirstNamespaceReference

We use FirstOrDefault(), because it will return a null if no appropriate element is found. This is a sensible precaution, since there may not be any NamespaceReferences in the current file.

Once we have a reference to the NamespaceReference, we can use it’s location as a destination to move to.

Actually moving the caret into position is a simple matter of …

MoveCaretToReference

Once in position, we will be able to get a reference to the Refactoring in a very similar manner to that of obtaining a reference to an action

Execute the Refactoring

Again we need to know the name of the refactoring that we’d like to execute. In most cases the name of the refactoring, is the same as the display name of the refactoring, so you can just copy the text that you’re used to seeing when you execute a refactoring from within CodeRush.

In this case the refactoring we want to execute  is “Organize Namespace References

We can get our reference like this…

GetRefactoringOptimizeNamespaceReferences

Refactorings are executed via their Execute method. however we must first check if the refactoring is available. Only once we have confirmed availability, can we execute the refactoring.

ExecuteRefactoring

Saving and restoring the caret location.

As you have seen, executing the ‘Optimize Namespace References’ refactoring, requires that we move the caret to a using\imports directive in order that it can function. Further, executing the CleanupFile action typically moves he caret to the end of the file which is processed. So no matter which way you look at it, the caret will not remain in its initial location.

We should really do something about this, so let’s store the location of the caret at the start and return it to this location at the end of our action.

We could capture the exact coordinates of the caret, but the we know the file is about to be altered. If anything above our caret’s initial position is removed, or added, then the stored position will be unlikely to make much sense afterwards.

We could also bind the stored coordinates to the code, which would allow them to be adjusted up and down in these cases. however if methods are reordered this will still likely leave us in a strange location.

So what to do? Should we give up and just leave the caret at the top or bottom of the file?

Of course not.

As luck would have it, the latest version of CodeRush provides us with a new subsystem for exactly this sort of situation.

The new NavigationServices subsystem provides us with the means to capture our current location in terms of our place within the hierarchy of code elements.

We get the current location and store it with…

GetStartAddress

Once we are done with our modifications, we can restore the relative position of the caret with…

ResolveAddress

Our New Action

So now that we have all of the constituent parts of our plugin, we need a way to trigger their execution.

There are several options available to us: Refactoring, CodeProvider, Command etc.

Whilst one of the pieces used is a Refactoring, the combined effect is not.

One characteristic of Refactorings and CodeProviders is that they present themselves contextually through the CodeRush SmartTag menu. This allows the Refactorings and CodeProviders to indicate when they are available.

Our function would theoretically be available from any position in any C# or VB.net file. This means that it would show up all the time. This in turn would reduce the effectiveness of the SmartTagMenu. Therefore I decided not to implement the new functionality in either of these ways.

Instead I chose to implement a new Action. If you recall, an Action is the internal name for a Command. These commands\actions are bindable to shortcut keys

I created and registered the Action with the following code:

CleanupFileAndNamespacesRegistrationGeneric2

This is pretty much boilerplate stuff aside from the indicated customizations. The first of these is the Name of the new action. This is the value you will look for in the commands drop down on the shortcuts option page. The second of these is a reference to the method to execute when the action is triggered.

Final steps

The final steps are pretty simple.

Implement the CleanupFileAndNamespaces_Execute function using all the code from the first half of this post.

Then, lastly, be sure to call registerCleanupFileAndNamespace method from within your plugin’s InitializePlugIn method otherwise all of that lovely code, will never run at all. With that, we have all the elements we need and our action is complete.

The full sourcecode for this plugin is available on github, as is the binary version

New CodeRush Plugin – Cleanup File and Namespaces

This plugin wraps up 2 existing tasks (The ‘CleanupFile’ command and the ‘Optimize Namespace References’) in to a single new command ‘CleanupFileAndNamespaces’.

In order to use this plugin:

Step 0 – Requirements

This plugin requires version 13.2 of CodeRush and a non-express version of Visual Studio version 2010 or higher.
If you have a current CodeRush subscription, you can download the latest version through our download centre.
If not, you can download a 30 day trial of all of our .Net products, including CodeRush.

Step 1 – Download

This plugin is hosted on GitHub and is available as either VSIX or as Sourcecode

VISX_CleanupFileAndNamespaceCleanupFileAndNamespacesSourceCode

Step 2- Install

If you have downloaded the source, you will have to compile the plugin yourself, and then install from the VISX which the compile process creates.

Once you have the VISX, (via download or compilation) simply double click it, and follow the prompts.

CleanupFileAndNamespacesInstaller

Step 3 - Configuration

All that is necessary to configure this plugin, is to assign a key to the new ‘CleanupFileandNamespaces’ command.

This is done via the Shortcuts options page.

  • To open the options screen either choose DevExpress\CodeRush\Options from the main menu, or use the Ctrl+Shift+Alt+O shortcut.
    To locate the shortcuts options page, locate the IDE\Shortcuts item in the tree on the left, or use the ShortcutsPageIcon icon in the upper right of the options screen.
  • CleanupFileAndNamespacesNewShortcut  Create a new shortcut by right clicking in an appropriate folder and choosing ‘New Keyboard Shortcut’ or ‘New Mouse Shortcut’.
  • CleanupFileAndNamespacesShortcutKeysThen choose a suitable key or mouse combination based on your preferences and previous choice. I usually pick Ctrl+T for testing purposes.

 

 

CleanupFileAndNamespacesCommand Next choose the ‘CleanupFileAndNamespaces‘ command from the commands dropdown.

Finally you should set the context of this command to make it only available when you are within a .vb or .cs file. CleanupFileAndNamespacesContext

Finally click OK to accept your changes.

Create a new shortcut and assign it to the the ‘CleanupFileAndNamespaces’ command.

Step 4 – Usage

  • Place your caret in any .cs or .vb file. and invoke using the configured shortcut. CodeRush will run the ‘Optimize Namespace References’ refactoring and follow that by running any configured Code Clean operations.

For example:

The following is a fresh C# Library project, with a single unused variable declared.

SimpleClassLibraryWithUnusedDeclaration

Assuming that you have the default settings for Code Cleanup, and you trigger CleanupFileAndNamespaces from this start position, CodeRush will remove the unused using directive and the unused declaration:

SimpleClassLibraryWithUnusedDeclarationAfterCleanup

This simple plugin links together 2 often used features so that they can operate as one.

In my next post I’ll explain how this plugin works in detail.

Custom Navigation within XML files

The request

A customer came to me and said:

“So I’ve got some XML files which hold a sort of DSL which I use to configure my application. There are elements in this DSL which have id attributes, and other elements which have ref attributes. As you might expect, within my DSL, the ref attributes are references to the id attributes.

Is there anything in CodeRush to help my navigate easily among these id and ref attributes where their values match?”

My plugin-sense started tingling….

I immediately thought of our awesome Tab to Next Reference feature, and figured we could probably extend it to work in this new scenario.

Create the project

  • File… New Project
  • Choose Language (C# in this case)
  • DXCore\Standard Plug-in

    Choose a name for your project (I chose CR_XMLNav)

    The Coding

    First I used a template to add some boilerplate code. (Bold text shows custom changes)


    private void registerXMLRefSearch()
    {
        var XMLRefSearch = new DevExpress.CodeRush.Core.SearchProvider();
        ((System.ComponentModel.
    ISupportInitialize)(XMLRefSearch)).BeginInit();
        XMLRefSearch.Description =
    "XMLRefSearch";
        XMLRefSearch.ProviderName =
    "XMLRefSearch"; // Needs to be Unique
        XMLRefSearch.Register = true;
        XMLRefSearch.UseForNavigation =
    true;
        XMLRefSearch.CheckAvailability += XMLRefSearch_CheckAvailability;
        XMLRefSearch.SearchReferences += XMLRefSearch_SearchReferences;
        ((System.ComponentModel.
    ISupportInitialize)(XMLRefSearch)).EndInit();
    }

    private void XMLRefSearch_CheckAvailability(object sender, CheckSearchAvailabilityEventArgs ea)
    {
    }

    private
    void XMLRefSearch_SearchReferences(Object Sender, DevExpress.CodeRush.Core.SearchEventArgs ea)
    {
    }


    Then I fleshed out the CheckAvailability routine:


    private void XMLRefSearch_CheckAvailability(object sender, CheckSearchAvailabilityEventArgs ea)
    {
        // Get Active LanguageElement
        var Element = CodeRush.Documents.ActiveTextDocument.GetNodeAt(CodeRush.Caret.Line, CodeRush.Caret.Offset);

        if
    (Element == null)
            return;

        if
    (!(Element is XmlAttribute))
            return;

        // Allow search to start if Attribute
        ea.Available = new string[] { "id", "ref" }.Contains(((XmlAttribute)Element).Name);
    }


    Essentially this routine looks to see if the caret is on a LanguageElement of type XmlAttribute whose name matches either id or ref.

    If it finds that this is the case, our searchProvider is made available, and processing continues with the XMLRefSearch_SearchReferences routine.


    private void XMLRefSearch_SearchReferences(Object Sender, DevExpress.CodeRush.Core.SearchEventArgs ea)
    {
        // Store Value of initial XmlAttribute
        TextDocument activeDoc = CodeRush.Documents.ActiveTextDocument;
        string StartValue = ((XmlAttribute)activeDoc.GetNodeAt(CodeRush.Caret.Line, CodeRush.Caret.Offset)).Value;

       
    // Iterate LanguageElements in solution
        SolutionElement activeSolution = CodeRush.Source.ActiveSolution;
        foreach (ProjectElement project in activeSolution.AllProjects)
        {
            foreach (SourceFile sourceFile in project.AllFiles)
            {
                SourceFile activeFile = CodeRush.Source.ActiveSourceFile;
                ElementEnumerable Enumerator = new ElementEnumerable(sourceFile, new XMLAttributeFilter(StartValue), true);
                foreach (XmlAttribute CurrentAttribute in Enumerator
                {
                    ea.AddRange(
    new FileSourceRange(CurrentAttribute.FileNode, CurrentAttribute.ValueRange));
                }
            }
        }
    }

    This code iterates through your solution (projects files etc) looking for appropriate XmlAttributes. The key to this little piece of code is this line here:
    ElementEnumerable Enumerator = new ElementEnumerable(sourceFile, new XMLAttributeFilter(StartValue), true
    );


    This creates an object capable of enumerating through the code looking for things which match a very specific set of criteria.

    The specifics of what will match are handled by our last piece of code.


    public class XMLAttributeFilter : IElementFilter
    {
        private readonly string
    _startValue;
        public XMLAttributeFilter(string
    StartValue)
        {
            _startValue = StartValue;
        }
        public bool Apply(IElement
    element)
        {
            // Skip if null 
            if (element == null
    )
                return false
    ;

           
    // Skip if not XmlAttribute
            if (!(element is XmlAttribute
    ))
                return false
    ;
            XmlAttribute CurrentAttribute = (XmlAttribute
    )element;

           
    // Skip attribute if it doesn't have the correct name.
            if (CurrentAttribute.Name != "id" && CurrentAttribute.Name != "ref"
    )
                return false
    ;

           
    // Skip the attribute if it doesn't have the same value as start point.
            if
    (CurrentAttribute.Value != _startValue)
                return false


            return
    true
    ;
        }
        public bool SkipChildren(IElement
    element)
        {
            return false
    ;
        }
    }   

    Each LanguageElement is checked and passed over if it fails any single check.

    • In this way we pass a list of all valid items on to the Tab to Next Reference feature which then allows us to seamlessly tab through all the references.

    • CR_XMLNav

    • Summary
    • This sort of technique is, as you can see, very simple to apply. I’m sure you can think of many similar occasions when you’ve wished you could jump between related bits of configuration. Well now you have the ability to do just that.

    The full version of this plugin is hosted up on GitHub.com for those who are interested.

    How to generate a Simple ToString() implementation with CodeRush templates

    A customer recently asked:

    Does CodeRush have a quick way to auto-implement ToString()?
    If it outputted each prop Name & value it would be great.

    Never one to shirk a challenge, I quickly set about finding the quickest way to allow a user to generate a ToString() method which
    would provide the requisite information.

    The approach I took this time, was that of Templates. Note: This task could certainly have been achieved with a plugin, but it’s
    quicker and arguably more efficient to use Templates in this case, so that’s the route I chose to take.

    For a generic primer on how to create CodeRush templates see my earlier post: CodeRush Templates - Creation Basics

    Structure

    The solution to this is to create 3 templates. An Iterating Template, An Item Template and a Delimiting Template

    • The Iterating Template: This is triggered by the user, and controls the iteration of the properties.
    • The Item Template: This represents the text that is emitted for each property encountered.
    • The Separation Template: This is used to determine text that sits between invocations of the item template.

    Specifics

    The Iterating Template

    As indicated this template is the one which is called directly by the user and as such should carry a sensible name. I’m not so great at naming so I chose to call mine ToStringPropertyMethod

    It will therefore be invoked whenever the user types ToStringPropertyMethod and hits the spacebar (or tab if you’re in Friction free mode)

    The body of this template is:

    -------------------------------------------------------------

    public override string ToString()
    {
    return «ForEach(Property,PropertyEach,,PropertySeparator)»;
    }

    -------------------------------------------------------------

    The basic structure of this will look familiar. The signature is that of the standard ToString() override, and the braces are those present in any method in order to denote the start and end of that method.


    What will be less familiar is the code within the chevrons (« and »)

    This code is a TextCommand which is interpreted by CodeRush, rather than emitted directly into your code.

    This TextCommand is called 'ForEach' and it takes up to 5 parameters. In this instance we only need 3 of these.

    • 'Property' specifies that we are interested in iterating through any properties of the current class.
    • 'PropertyEach' is the name of the template to expand for each property found.
    • 'PropertySeparator' is the name of the template to be expanded between any 2 calls to PropertyEach

    The other 2 params are unused in this case but control templates expanded at the start and end of the sequence.

    As you can see, this template depends on the existance of both PropertyEach and PropertySeperator.

    The expansion of the PropertySeperator Template is predictably a simple + sequence thus:

    -------------------------------------------------------------

     +

    -------------------------------------------------------------


    The content of the PropertyEach template is a little more complicated:

    -------------------------------------------------------------

    "«?Get(itemName)»: " + «?Get(itemName)».ToString()

    -------------------------------------------------------------

    This represets the building of some code which will itself emit a string representative of the property being iterated.

    The bit you may be less familiar with is «?Get(itemName)». It is a StringProvider which provides access to strings setup by previous uses of the «?Set» StringProvider.


    In this case, each time the «?ForEach» StringProvider  finds a new Property, it sets itemName to the name of that Property. This gives us a handy way to access that information and emit it into out code.

    If you put all of this together and Expand the ToStringPropertyMethod template from within the following class...

    -------------------------------------------------------------

        public class Example
        {
            public string PropertyName1 { get; set; }
            public string PropertyName2 { get; set; }
            public string PropertyName3 { get; set; }
        }
    -------------------------------------------------------------

    ...you get the following result...

    -------------------------------------------------------------

        public class Example
        {
            public string PropertyName1 { get; set; }
            public string PropertyName2 { get; set; }
            public override string ToString()
            {
                return "PropertyName1: " + PropertyName1.ToString() + "PropertyName2: " + PropertyName2.ToString();
            }

        }
    -------------------------------------------------------------


    Summary

    As you can see, this code will emit the name and value of each property of the class when called.

    Obviously the formatting could be improved, but I think you can see the potential demonstrated here.

    What about generating XML or JSON based strings.

    These, of course, are left as an exercise for the reader. :)





    New CodeRush Plugin: CR_JumpToNamedMVCView

    So a customer came to me with plugin request:

    Customer: “I typically invoke my MVC razor views, by name, from within my controllers. Is there a plugin which can help me navigate to these views from the invocation?”

    Me: “Not right now, No. Let me see what I can do”. *Challenge Accepted"*

    And so I set off to create a new plugin to assist with this type of navigation.

    A few hours later, the result is CR_JumpToNamedMVCView. A simple plugin which adds a single item (Named MVC View) to our Navigation SmartMenu (Ctrl+Alt+N)

    Consider a very simple MVC CustomerController class.

    JumpToNamedMVCViewCustomerControllerFull

    The idea here is that you’re coding or reading through your controller and need to navigate to the view which you will be returning from a given action.

    With this new plugin, you can now…

    • Place your caret on the name of the view… (in this case “List”)
    • Press Ctrl+Alt+N

    JumpToNamedMVCViewCustomerControllerJumpToView

    • Select Named MVC View

    JumpToNamedMVCViewCustomerListView

    …and Voila! CodeRush delivers you to the view specified in the original call.

    See this plugin’s Community Wiki page for even more detail, including how to assign this action to F12 for a more ‘Goto Definition’ approach

    Hopefully this simple plugin will make your MVC coding, that little bit easier.

    So now let’s see what develops.

    More Posts