Thursday, August 06, 2009

New CodeRush Plugin: CR_MethodPreview

The other night I saw a tweet by Neal Culiner (@NCSoftware) regarding a plugin he’d like to see developed. 

Shortly there was a response was a tweet by Matthew MacSuga (@csharpbydesign). He mentioned that he’s asked for something like this a while back.

What they’re after, is a way to preview the code of a method, without having to visit that method.

I feel a little guilty because I remember Matthew mentioning this a while back. I think I started a debate at the time on "what should trigger the functionality” and we (well probably I) got bogged down in the details. Sorry Matthew :(

This time I just thought .. “Sod This” - (Wasting time that is, not talking to Matthew and Neal) - “Let’s just get something out there, and we’ll see where it leads afterward”.

So after a quick vote on the name of said plugin (Where Neal suggested the name and we all agreed :D) I was off to build a new plugin.

Where to start?

So I created a basic plugin and dropped an action in place. (For details please see a previous post)

From here I needed 2 things:

  • A function to determine which method to preview.
  • A function to actually do the preview.

There are some complexities in the original brief that I didn’t feel comfortable with initially.

  • “Select method based on method call under cursor”.
    • I have elected to use caret position in this first version.
  • “Hold a key down to see Preview”
    • I have elected to use a toggleable action in this first version.

Which Method?

So the first thing to do is to work out which method to display a preview for.

Some Terminology:
Given the sample…

    Public Sub Method1() 
Call Method2()
End Sub


  • “Method2” is known as the MethodReferenceExpression


  • “Call Method2()” is the MethodCall.



I would like this plugin to function from either of these 2 locations, so I need to return the declaration of the method to which either refers.



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

    Private Function GetMethod(ByVal Element As LanguageElement) As Method


        Dim Method As Method = Nothing


        Select Case Element.ElementType


            Case LanguageElementType.MethodCall


                Method = TryCast(Element, MethodCall).GetDeclaration


            Case LanguageElementType.MethodReferenceExpression


                Method = TryCast(Element, MethodReferenceExpression).GetDeclaration


        End Select


        Return Method


    End Function


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



To this method, I can pass CodeRush.Source.GetNodeAt(CodeRush.Caret.SourcePoint)



Later I can replace this with something which passes the element under the cursor, and I won’t have to change much at all.



Next we need to determine the code behind the Method in question.

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


Dim TheCode as String = CodeRush.CodeMod.GenerateCode(Method)


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


And now we have the code we’d like to render in our preview window. So lets crack on and create the preview itself.




The Preview Window



Building a preview window is easy… (Isn’t everything with the DXCore? :P)



The following function accepts the code and a location for the preview and builds the preview accordingly. It also places the preview on screen.



(The code to hide the preview has been omitted here but is even simpler.)



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

Private mPreviewWindow As CodePreviewWindow





Private Sub ShowCodePreview(ByVal Code As String, ByVal insertionPoint As SourcePoint)


    mPreviewWindow = New CodePreviewWindow(CodeRush.Documents.ActiveTextView, insertionPoint)


    mPreviewWindow.AddCode(Code)


    mPreviewWindow.ShowPreview()


End Sub


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





And so things come together in the main ToggleMethodPreview_Execute() as…





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


Private mShowingPreview As Boolean = False





Private Sub ToggleMethodPreview_Execute(ByVal ea As DevExpress.CodeRush.Core.ExecuteEventArgs) Handles ToggleMethodPreview.Execute


    If mShowingPreview Then


        Call HideCodePreview()


    Else


        Dim Method As Method = GetMethod(CodeRush.Source.GetNodeAt(CodeRush.Caret.SourcePoint))


        If Not Method Is Nothing Then


            Call ShowMethodPreview(Method, CodeRush.Caret.SourcePoint)


            mShowingPreview = True


        End If


    End If


End Sub


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



Summary



That’s pretty much all there is to it.



To use this plugin, simply bind a key to the “ToggleMethodPreview” action and activate it when your caret is in a suitable location.



For this plugin I wrote all of 42 lines of code including signatures.



Proof once again, as if you needed it, that the DXCore makes plugin writing ridiculously easy.



So now we have a first draft of “CR_MethodPreview”… go play… see what you think… And we’ll see where it goes from there.



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

For more DevExpress news, check out their Facebook page


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


5 comments:

Saif Khan said...

There might be a possibility here for a plugin, no?

http://stackoverflow.com/questions/1273085/attribute-to-add-to-an-interface-for-the-default-concrete-class

Rory said...

Indeed. :) I have asked for a little more info and made an offer :)

Saif Khan said...

you da man!

Mark said...

Visual Studio has the "Code Definition Window" for this for in C#. I've be wanting the same thing for VB. And this plug-in does it. Thanks!

Rory said...

You're quite welcome. :)