views:

1648

answers:

4

How can you implement regions a.k.a. code collapse for JavaScript in Visual Studio?

If there are hundreds of lines in javascript, it'll be more understandable using code folding with regions as in vb/C#.

#region My Code

#endregion
A: 

Hundreds of lines of code source in a single file (no matter what language) is a bad thing. Regions are evil. Try splitting the code into multiple files.

Darin Dimitrov
Splitting JavaScript files isn't always a good idea because the more files you have the more requests a browser has to do to get the complete code for your application which can slow down page loading.
Benedikt Eger
I only suggested splitting **source** code files so that they are more readable. In release mode techniques should be used for combining and compressing these js to address the problem of multiple queries.
Darin Dimitrov
I don't know whether splitting into multiple files makes the browser perform less, but this answer definately does not answer the question. He wants to know how to use regions, not an answer on why you shouldn't use regions. If "why should I not use regions" was the question, then this answer would be appropriate.
0A0D
Benedikt Eger, you can combine the output before sending it to the client, but you should still structure the source in multiple files.
troethom
Roboto, I think a beauty of Stack Overflow is that you can get your assumptions challenged. We don't always need concrete answers as much as we need advice.
troethom
I thought that suggesting alternative technique which one thinks better for the particular problem was also part of helping the OP.
Darin Dimitrov
I don't think it is helping if you don't answer the question.
0A0D
I answered the question the way I think appropriate: don't use regions, split and organize your source code (only personal opinion).
Darin Dimitrov
Darin, of course you're right that splitting the files into different source files doesn't mean these files have to be delivered to the browser. But the way you put it in your answer suggests doing so because more often than not JavaScript source files are delivered to the browser the way they were programmed (and not combined and compacted).
Benedikt Eger
+4  A: 

Blog entry here explains it and this MSDN question.

You have to use Visual Studio 2003/2005/2008 Macros.

Copy + Paste from Blog entry for fidelity sake:

  1. Open Macro Explorer
  2. Create a New Macro
  3. Name it "OutlineRegions"
  4. Click Edit macro and paste the following VB code:

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
  1. Save the Macro and Close the Editor
  2. Now let's assign shortcut to the macro. Go to Tools->Options->Environment->Keyboard and search for your macro in "show commands containing" textbox
  3. 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 :)
0A0D
This one is useful and the important point to note from the site's comments is "You must check the name of the module in the above code with the name of your new Macro. both names must match!"
Prasad
Does this work on VS2010? I can't get to. The Macro doesn't show up when searching for it.
Mr. Flibble
@Mr. Flibble: Not Sure.. I only have VS2005.
0A0D
@Changeling OK. I've asked in a new question here: http://stackoverflow.com/questions/2923177/regions-code-collapse-in-javascript-in-visual-studio-2010
Mr. Flibble
+5  A: 

Thanks to Roboto for a great answer. I've had good luck with it. Darin Dimitrov also makes a good argument about limiting the complexity of your JS files. Still, I do find occasions where collapsing functions to their definitions makes browsing through a file much easier.

Regarding #region in general, this SO Question covers it quite well.

I have made a few modifications to the Macro to support more advanced code collapse. This method allows you to put a description after the //#region keyword ala C# and shows it in the code as shown:

Example code:

//#region InputHandler
var InputHandler = {
    inputMode: 'simple', //simple or advanced

    //#region filterKeys
    filterKeys: function(e) {
        var doSomething = true;
        if (doSomething) {
            alert('something');
        }
    },
    //#endregion filterKeys

    //#region handleInput
    handleInput: function(input, specialKeys) {
        //blah blah blah
    }
    //#endregion handleInput

};
//#endregion InputHandler

Looks like this:

alt text

And this expanded:

alt text

Updated Macro:

Option Explicit On
Option Strict On

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports System.Diagnostics
Imports System.Collections.Generic

Public Module JsMacros


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

        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 New Stack(Of Integer)

        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 ...
                Dim tempStartIndex As Integer = CInt(startRegions.Pop())
                selection.MoveToLineAndOffset(CalcLineNumber(text, tempStartIndex), CalcLineOffset(text, tempStartIndex))
                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) As Integer
        Dim lineNumber As Integer = 1
        Dim i As Integer = 0

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

            If text.Chars(i) = vbCr Then
                lineNumber += 1
                i += 1
                If text.Chars(i) = vbLf Then
                    i += 1 'Swallow the next vbLf
                End If
            End If

            i += 1
        End While

        Return lineNumber
    End Function

    Private Function CalcLineOffset(ByVal text As String, ByVal index As Integer) As Integer
        Dim offset As Integer = 1
        Dim i As Integer = index - 1

        'Count backwards from //#region to the previous line counting the white spaces
        Dim whiteSpaces = 1
        While i >= 0
            Dim chr As Char = text.Chars(i)
            If chr = vbCr Or chr = vbLf Then
                whiteSpaces = offset
                Exit While
            End If
            i -= 1
            offset += 1
        End While

        'Count forwards from //#region to the end of the region line
        i = index
        offset = 0
        Do
            Dim chr As Char = text.Chars(i)
            If chr = vbCr Or chr = vbLf Then
                Return whiteSpaces + offset
            End If
            offset += 1
            i += 1
        Loop

        Return whiteSpaces
    End Function

End Module
Michael La Voie
not working in vs-2010
Praveen Prasad
VS 2010 has an updated extensions framework and someone was nice enough to create a code-folding plugin called "Visual Studio 2010 JavaScript Outlining" here: http://jsoutlining.codeplex.com/
Michael La Voie
A: 

great, tnks to both!!

jrg