Tuesday, April 15, 2008

Using #region Directive With JavaScript Files in Visual Studio

Suppose how nice it would be to use #region directive when writing javascript code.

Javascript is becoming more and more complicated, and it is hard to scroll up and down every time we want to find needed function name and see what parameters it accepts.

I was so tired with this scrolling that started to search some alternative small IDE-s or highlighting text editors which would allow me to use collapsible regions in js files, but in this case I would lose javascript intellisense in VS 2008. I even thought about creating my own text editor plug-in for VS, but again - what about intellisense.

Earlier or later, I found one nice solution to the problem on Microsoft forums. Yes - it's so simple. The solution uses simple macros which parses current document and creates collapsible regions for

//#region

//#endregion

pairs.

So simple :)

Thanks to the author!

And because I don't not find it to be easily detectable in the internet, I decided to blog this.

 

Just do the following steps to support //#region directive:

1) Open Macro explorer:

image

2) Create new macro:

image

3) Name it "OutlineRegions":

image

4) Click "Edit" macro and paste the following VB code into it:

Option Strict Off
Option Explicit Off

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics
Imports System.Collections

Public Module JsMacros

    Sub OutlineRegions()
        Dim selection As EnvDTE.TextSelection = DTE.ActiveDocument.Selection

        Const REGION_START As String = "//#region"
        Const REGION_END As String = "//#endregion"

        selection.SelectAll()
        Dim text As String = selection.Text
        selection.StartOfDocument(True)

        Dim startIndex As Integer
        Dim endIndex As Integer
        Dim lastIndex As Integer = 0
        Dim startRegions As Stack = New Stack()

        Do
            startIndex = text.IndexOf(REGION_START, lastIndex)
            endIndex = text.IndexOf(REGION_END, lastIndex)

            If startIndex = -1 AndAlso endIndex = -1 Then
                Exit Do
            End If

            If startIndex <> -1 AndAlso startIndex < endIndex Then
                startRegions.Push(startIndex)
                lastIndex = startIndex + 1
            Else
                ' Outline region ...
                selection.MoveToLineAndOffset(CalcLineNumber(text, CInt(startRegions.Pop())), 1)
                selection.MoveToLineAndOffset(CalcLineNumber(text, endIndex) + 1, 1, True)
                selection.OutlineSection()

                lastIndex = endIndex + 1
            End If
        Loop

        selection.StartOfDocument()
    End Sub

    Private Function CalcLineNumber(ByVal text As String, ByVal index As Integer)
        Dim lineNumber As Integer = 1
        Dim i As Integer = 0

        While i < index
            If text.Chars(i) = vbCr Then
                lineNumber += 1
                i += 1
            End If

            i += 1
        End While

        Return lineNumber
    End Function

End Module

5) Save the macro and close the editor.

6) Now let's assign shortcut to the macro. Go to Tools->Options->Environment->Keyboard and search for your macro in "show commands containing" textbox:

image

7) now in textbox under the "Press shortcut keys" you can enter the desired shortcut. I use Ctrl+M+E. I don't know why - I just entered it first time and use it now :)

 

That's it, now if you write the following javascript code:

/// <reference name="MicrosoftAjax.debug.js" />
/// <reference name="MicrosoftAjaxTimer.debug.js" />
/// <reference name="MicrosoftAjaxWebForms.debug.js" />

// KWB.BaseWizard class constructor
//#region
Type.registerNamespace("KWB");
KWB.BaseWizard = function(field) {
    // call base constructor
    KWB.BaseWizard.initializeBase(this);
    this._state = null;
}
//#endregion

// KWB.BaseWizard Class Body
//#region
KWB.BaseWizard.prototype = {
    // Sys.Component Overrides
    //#region
    dispose : function () {
        this._state = null;
        this._stateField = null;
        this.lastClicked = null;
        Sys.Application.remove_load(this.appLoad);
        KWB.BaseWizard.callBaseMethod(this, 'dispose');
    },
    
    initialize : function() {
        KWB.BaseWizard.callBaseMethod(this, 'initialize');
    },
    //#endregion
    
    // Properties
    //#region
    get_state : function() {
        return this._state;
    },
    
    set_state : function(value) {
        this._state = value;
    },
    //#endregion
    
    // Methods
    //#region
    getNext : function(current) {
        /// <summary>
        /// Override. Called when 'next' is called. Determines next frame to display
        /// </summary>
        /// <param name="current">current SelectedIndex</param>
        return current + 1;
    },
    
    getPrevious : function(current) {
        /// <summary>
        /// Override. Called when 'previous' is called. Determines previous frame to display
        /// </summary>
        /// <param name="current">current SelectedIndex</param>
        return current - 1;
    },
    
    finish : function() {
        /// <summary>
        /// Override. Called when 'finish' is pressed
        /// </summary>
        return true;
    },
    //#endregion
    
    // Event handlers
    //#region
    nextClick : function() {
        //TODO: add contents later
    }
    //#endregion
};
KWB.BaseWizard.registerClass('KWB.BaseWizard', Sys.Component);
//#endregion

// WizardStepType enumeration
//#region
KWB.WSType = function(){};
KWB.WSType.prototype = 
{
        Server  : 1, 
        Client  : 2,
        Service : 4 
}
KWB.WSType.registerEnum("KWB.WSType", false);
//#endregion

if(typeof(Sys) !== "undefined")Sys.Application.notifyScriptLoaded();

Now click Ctrl+M+E and you will see:

image

 

Veeery handy !

 

This is possible in VS because actually you can outline and collapse any selection you like manually, this work in most editors for VS.

If you are interested about that shortcuts see Text Manipulation Shortcut Keys, Visual C# Scheme . The shortcuts starting with Ctrl+M are the ones that manipulate test outlining and toggling.

 

Check out my previous post related to js files in AJAX scenario, and see how we can remove unnecessary white spaces and comment blocks from them for use in production:

Auto generate release scripts for web application using T4 template

 

Hope this helps.

Technorati Tags:

kick it on DotNetKicks.com

43 comments:

Anonymous said...

Thanks this is great
Thanks for passing this on
I searched for regions and js in google and found your post
I am using ExtJs in VS2008 and had about 400 lines of js that was becoming difficult to manage

Andy

Unknown said...

Hmm... I'm using VS 2008 and this doesn't seem to work for me. The macro runs but nothing ever gets collapsed...

Any ideas..??

Kirill Chilingarashvili said...

Hi Jason,
I use this macro in VS 2008 and it works ok,
try to repeat steps described in the article again,
hope this helps.
Kirill

Unknown said...

Thank you very much!!! This is a precious help for the ExtJS developers using VS2008.

Jason:
You must check the name of the module in the above code with the name of your new Macro. both names must match!

Unknown said...

Nice, but you still have to manually type the comments //#region, //#endregion. I would really like to be able to outline large javascript files without typing the region comments.

Also, beware that you must have a empty line after the last //#endregion comment or the macro will produce an error stating 'Value does not fall within the expected range'.

Kirill Chilingarashvili said...

seeker,
Yes it does make sence if you need to outline the region only once,
while using //#region comment directive you are stating the regions which are checked into source control with code itself,
it means any developer working with the code can download it from source server, press shortcut buttons in editor and that's it - the js file is outlined into logical groups.

Regards,
Kirill

Unknown said...

Thanks Kirill.

I will use your method going forward. I had just inherited a 4300 line Javascript file and it sure would've been nice to click a button and wham, everything is outlined. At least the next guy to get this file can do that after I comment it.

Unknown said...

Thanks again Kirill! I've been using you're comment method now for almost two weeks. It's a huge help.

Unknown said...

Much obliged,

really useful and quick to set up.

Anonymous said...

Was about to give up on VS2008 and JS. Thank-you!

Anonymous said...

very helpful..

thanks..

Anonymous said...

If you look at the previous page you'll see my post about how to collapse the code without having to put in region lines. I've made some major changes to it since the original post (updates to have it use regular exp to find the funtion lines). If I get some time I might post the new code as it is much nicer than my original post

--lkspencer

Unknown said...

Thank you very much for this!

Anonymous said...

This is fantastic, thanks for pointing it out.

Anonymous said...

Made my day!

Mohan Joshi said...

Fantastic work dear!!

Thanks a lot.... It works in vs05 and vs08 both..

A Booth said...

May I suggest you edit the Macro to enable the text on the #region line to be visible?

Change: -
' Outline region ...
selection.MoveToLineAndOffset(CalcLineNumber(text, CInt(startRegions.Pop())), 1)

To: -
' Outline region ...
selection.MoveToLineAndOffset(CalcLineNumber(text, CInt(startRegions.Pop())), text.Length)

This will enable collapsed sections to read: -
[+]//#region Region Description [...]

Which has greater readability than: -
[+][...]

A useful macro. Thanks for presenting it.

Richard Binnington said...

This is awesome! Thank you very much

Anonymous said...

assert(Your.KungFu == STRONG );

Wiggles said...

Thx a lot for helping me to clean up my js-files ;).

Great work, greetings from Austria.

Anonymous said...

awesome! thanks!

Manish Mistry said...

Nie script.

I got the "Stack Empty" Error.

I noticed that I used to have
//#region automation part
//#endregion automation part

this macro didnot like anything after word region on the same line. I removed and standardised to
//#region
//#endregion

and works like a charm!

Thanks hips!

Anonymous said...

Anyone having a problem with this in VS2010?

Unknown said...

Good work. I added this to collapse regions of HTML/ASPX pages too.
Sub OutlineRegions()
Const REGION_START As String = "//#region"
Const REGION_END As String = "//#endregion"
OutlineRegionsSub(REGION_START, REGION_END)
End Sub

Sub OutlineRegionsHTML()
Const REGION_START As String = "<!--#region-->"
Const REGION_END As String = "<!--#endregion-->"
OutlineRegionsSub(REGION_START, REGION_END)
End Sub

Sub OutlineRegionsSub(ByVal REGION_START As String, ByVal REGION_END As String)
...

Unknown said...

I can't get this to work in VS2010 RC. The macro isn't erroring when I run it, but I'm getting no collapsing.

Tamma said...

this is really cool stuff, really i liked very much. I implemented for VS2008

Tal said...

Nice!

velio said...

Thanks, really great.
Kizmar, it works in VS2010 too.
Just don't forget to import the System.Collections namespace like:

Imports System.Collections

Best regards

JGarces said...

Muchas gracias!
Nice Post!

Esto es de mucha utilidad.

Esto es de mucha ayuda para las personas que trabajan con .Net y quieran agregar regiones a traves de #region y #endregion en JavaScript

Saludos!

Unknown said...

Hi, Im using ur tooltip.when i click my menu tab im getting javascript error.delete this.get_element().htIFrame; this is error.Plz answer me.its urgent

eman.ref3at said...

Hello Kiril,
Thank you for this job.
It is very useful.
I wonder if it possible to remove this collapse.
when i want to change place of //#region .
Because, it is still there. Thank you.

Kirill Chilingarashvili said...

Hi Eman,

What if you try to close the file and open / run macro again?

I think this should work.

(cannot test as dont have environment setup for this)

Regards,
Kirill

Sean said...

Flippin' sweet! Thanks!

Oleg said...

Hi guys!
You may be interested to have js code outlining as addin for VS2008?

Here it goes...
JsOutline

Any comments appreciated!

Chandra Murali said...

Thanks a lot for this... It worked really well in VS2010.

MikeMcHaney said...

I could kiss you! - But instead I will just leave you a positive comment. This worked great for me and is a welcome feature with long winded js files.

Amit said...

Great article...

Really helped...

Thank you very much...

God bless you...

Keep sharing such things...

Unknown said...

Great post

Can i ask if you have a script that can expand all regions

thanks :)

Sameep said...

Works Great.. Really Cool Thanks

Anonymous said...

It is a pity that MS have removed macros from 2012 but not given us this functionality.
Apparently they removed it as it was not being widely used. So instead of leaving it and not updating it, they removed it entirely. Thank you Microsoft :p

Anonymous said...

Just found this for Visual Studio 2012:

/*#region RegionName*/
css goes here
/*#endregion*/

:)

Murillo said...

If I do want use this on vs2012 to apply regions to any type file? It's possible?

Anonymous said...

I just made it work!!! Great job!!!

Thanks!