|
Contents
At ComponentScience, we heartily embrace the use of regions to logically separate our code into meaningful blocks. After doing it manually for a couple of years, I decided to write myself a little macro to make my life easier. After a little research, I found a couple of examples of how to manipulate Visual Studio's code editor. The result is the following macro that I use to regionify my code.
I have also included instructions on how to install it into Visual Studio and assign it to a hotkey. I use Alt+R because it wasn't used in the Visual Studio text editor, and it made sense to me.
You are welcome to use it all you want, give it to your friends and even claim to have written it yourself if you want.
Note: I only use this macro in C# files. If you want to use it in VB, then you need to uncomment the VB sections and comment out the C# sections. If anybody has any tips on how to modify the script to detect the language being used, let me know and I will modify the script accordingly. I'm sure there is an easy way, I just haven't researched it because I don't care. The VB parts do work in VB code though. I tested it that much.
Update: After posting this article on CodeProject, I got some feedback from readers about how to test for the language being used, make the padding better, and handle tabs as well as spaces. I have updated the macro accordingly.
Even more update!: The users on CodeProject have done a wonderful job of tweaking the macro! We now have a really nice regioning macro. I am very happy with the feedback I have gotten from the CodeProject community. Special thanks (in no particular order) goes to RussKie, simonech, Hrusikesh, ERobishaw, isler-j, and SvenRieke. These guys embody the spirit of cooperative development.
Sub MakeRegion()
Regions.MakeRegion()
End Sub
Public Class Regions
Shared Sub MakeRegion()
Dim rName As String = ""
Dim pad As String = ""
Dim junk As String
Dim count, i As Integer
Dim startpoint, endpoint, tmppoint As EditPoint
With DTE.ActiveDocument.Selection
startpoint = .TopPoint.CreateEditPoint()
endpoint = .BottomPoint.CreateEditPoint
End With
If startpoint.EqualTo(endpoint) Then
Exit Sub
End If
If Not startpoint.AtStartOfLine Then
startpoint.StartOfLine()
End If
rName = InputBox("Region Name:", "Pick a name", _
GetDesc(DTE.ActiveDocument.Selection.TopPoint.CreateEditPoint()))
DTE.UndoContext.Open("Insert A Region")
Try
junk = startpoint.GetText(startpoint.LineLength)
pad = String.Empty
For count = 0 To junk.Length - 1
If junk.Substring(count, 1).Equals(" ") Or _
junk.Substring(count, 1).Equals(vbTab) Then
pad += junk.Substring(count, 1)
Else
Exit For
End If
Next
If DTE.ActiveDocument.Language = "CSharp" Then
startpoint.Insert(String.Format("{0}#region {1}{2}", _
pad, rName, vbCrLf))
If endpoint.LineLength = 0 Then
endpoint.Insert(String.Format("{0}#endregion // {1}{2}", _
pad, rName, vbCrLf))
Else
endpoint.Insert(String.Format("{0}#endregion // {1}{2}", _
vbCrLf & pad, rName, vbCrLf))
End If
Else
startpoint.Insert(String.Format("{0}#Region ""{1}""{2}", _
pad, rName, vbCrLf))
If endpoint.LineLength = 0 Then
endpoint.Insert(String.Format("{0}#End Region '{1}{2}", _
pad, rName, vbCrLf))
Else
endpoint.Insert(String.Format("{0}#End Region ' {1}{2}", _
vbCrLf & pad, rName, vbCrLf))
End If
End If
Finally
DTE.UndoContext.Close()
End Try
End Sub
Private Shared Function GetDesc(ByVal startpoint As EditPoint) As String
Dim line As String = ""
Dim tmppoint As EditPoint
line = startpoint.GetText(startpoint.LineLength)
If (line.Length > 0) Then
line = line.TrimStart(" ", vbTab)
If DTE.ActiveDocument.Language = "CSharp" Then
If (line.StartsWith("///")) Then
tmppoint = startpoint
tmppoint.LineDown()
line = GetDesc(tmppoint)
ElseIf (line.StartsWith("//")) Then
line = line.TrimStart("//", " ")
End If
line = line.Replace("{", String.Empty)
End If
line = line.TrimEnd(" ", vbTab)
End If
Return line
End Function
End Class
To install the macro, open up Visual Studio and follow these directions...
- Open up the Macro Explorer by pressing Alt+F8.
- Right-click on your MyMacros icon and select "New Module".
- Give the new module a meaningful name and save it.
- Right-click on the new module and select "New Macro".
- Replace "
Sub Macro1()" through "End Sub" with the code above.
- Save the macro file.
To assign the new MakeRegion macro to Alt+R:
- In Visual Studio, Click "Tools | Options" from the menu.
- Open the "Environment" page and select "Keyboard".
- Click [Save As…] and save the default keyboard mapping with a meaningful name. (You can't modify the default keyboard mapping.)
- In the "Show Commands Containing:" field, type "MakeRegion".
- Select the new MakeRegion macro from the list.
- In the "Use new shortcut in:" field, select "Text Editor".
- In the "Press shortcut key(s):" field, press "Alt+R".
- Click the [Assign] button.
- Click the [OK] button.
You're done! Now, open up the text editor, select some text, and press [Alt+R]. It will take a few seconds to show up the first time it is run. When the dialog pops up, type the name of the region and press Enter.
Happy Regioning!
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 31 (Total in Forum: 31) (Refresh) | FirstPrevNext |
|
|
 |
|
|
If you're a C# developer, you owe it to yourself to buy Resharper.
You want a region? Highlight the code and hit ctrl-alt-j and select Region from the list.
Resharper is a definite productivity aid for me, although I'm not entirely pleased with the VS.NET 2k5 implementation of it (and I really dislike VS.NET 2k5, mostly because it's so dang buggy and crashes frequently).
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|

This macro is faster (less keystrokes) allows you to tweak it to do regions as you wish, and is free.
Plenty of reasons to use this macro rather than resharper.
Phillip H. Blanton www.ComponentScience.net Email: Phillip at that domain that you see one line above the line you are reading now.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Right, but have you used Resharper? I mean, sure this script is super customizable, but I've got better things to be doing than customizing a script. I just want to get my work done and then get out of the office
It does *way* more than just regions... If you were a java developer and were used to Idea, then Resharper makes the .net transition that much easier.
From a macros perspective: ctrl-n to open a class (from anywhere) alt-insert to insert: Constructor, Read Property, Write Property, Read/Write Property, Implement Interface Member, Override Inherited Member, Generate Delegating members ctrl-alt-j to Surround with: if, while, for, do..while, lock, #region, {}, try..catch, try..finally, cast. ctrl-d: dupe the current line/highlighted text (no copy/paste) ctrl-/: comment out a line/uncomment out a line alt-insert: add namespace using lines as needed for unknown types (this is a lifesaver)
Not to mention all the code completion differences and the vb like compile behind telling you immediately that code won't compile. This is the #1 best feature of R# IMO (and it's somewhat broken in 2k5 which bugs me to no end).
I think it would take a lot of work to write custom scripts/macros for all this. Resharper (esp. for vs.net2k3) is well worth the money and productivity enhancements.
Another benefit to a COTS component is that your entire development team can be standardized so that you only have to give one training class on the tool and everyone then talk the same "language."
There are some built in macros for some of this stuff in vs.net 2k5, but they don't work nearly as nicely (like the one for adding properties) IMO.
I'm not knocking the macro you wrote, but was just wanting to make sure your readers knew that there was a COTS tool that would do similar things + a lot more (for a cost of course).
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Public Module MakeTryCatch Sub MakeTryCatch() Regions.MakeTryCatch() End Sub
Public Class Regions ' MakeTryCatch inserts Try and Catch tags ' around selected text in the VS editor. Shared Sub MakeTryCatch() Dim rName As String = "" Dim pad As String = "" Dim junk As String Dim count, i As Integer Dim startpoint, endpoint, tmppoint As EditPoint
With DTE.ActiveDocument.Selection startpoint = .TopPoint.CreateEditPoint() endpoint = .BottomPoint.CreateEditPoint End With
If startpoint.EqualTo(endpoint) Then Exit Sub End If
'ELR: ADDED THIS, to move the startpoint to the start of the line 'so that the Pad function works correctly If Not startpoint.AtStartOfLine Then startpoint.StartOfLine() End If
rName = InputBox("MessageBox?: (S/N)", "Utiliza Mensaje de Exceptions", "N") ', _
DTE.UndoContext.Open("Insert A Region") Try junk = startpoint.GetText(startpoint.LineLength)
pad = String.Empty For count = 0 To junk.Length - 1 If junk.Substring(count, 1).Equals(" ") Or _ junk.Substring(count, 1).Equals(vbTab) Then pad += junk.Substring(count, 1) Else Exit For End If Next
'ELR: ADDED Test for Languages If DTE.ActiveDocument.Language = "CSharp" Then ' C Sharp Code startpoint.Insert(String.Format("{0}try {1}", pad, vbCrLf)) startpoint.Insert(String.Format("{0} {1}", pad & Chr(123), vbCrLf)) If endpoint.LineLength = 0 Then endpoint.Insert(String.Format("{0} {1}", pad & Chr(125), vbCrLf)) Else endpoint.Insert(String.Format("{0} {1}", vbCrLf & pad & Chr(125), vbCrLf)) End If endpoint.Insert(String.Format("{0}catch(Exception ex) {1}", pad, vbCrLf)) endpoint.Insert(String.Format("{0} {1}", pad & Chr(123), vbCrLf)) If (rName.ToUpper.Equals("S")) Then endpoint.Insert(String.Format("{0}MessageBox.Show(ex.Message); {1}", pad & vbTab, vbCrLf)) Else endpoint.Insert(String.Format("{0}throw ex; {1}", pad & vbTab, vbCrLf)) End If endpoint.Insert(String.Format("{0} {1}", pad & Chr(125), vbCrLf)) Else ' VB Code startpoint.Insert(String.Format("{0}Try {1}", pad, vbCrLf)) If endpoint.LineLength = 0 Then endpoint.Insert(String.Format("{0}Catch ex As Exception {1}", pad, vbCrLf)) Else endpoint.Insert(String.Format("{0}Catch ex As Exception {1}", vbCrLf & pad, vbCrLf)) End If If (rName.ToUpper.Equals("S")) Then endpoint.Insert(String.Format("{0}MsgBox(ex.toString) {1}", pad & vbTab, vbCrLf)) Else endpoint.Insert(String.Format("{0}Throw ex {1}", pad & vbTab, vbCrLf)) End If endpoint.Insert(String.Format("{0} {1}", pad & Chr(125), vbCrLf)) End If Finally DTE.UndoContext.Close() End Try
dmateoc
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Hi, Thanks for the nice macro! A small request: I prefer a space between #region and the first line of its content as well as between its last line and #endregion.
Like this:
#region blabla
[code]
#endregion
When I include an empty line before and after the code block in the selection, the macro should write the #(end)region with the padding of the code, not at the start of the line.
Can somebody help me to implement this behavior? I don't know how to do it in VB. Thanks.
Nico
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
This is pretty easy to do. Firstly I wold suggest that since you already have to select the method before pressing the keystroke to apply a region, then you can just select an extra line above and below the method.
The other way to do it would be to modify the script such that it adds the extra lines for you. Here is the relevant section...
'ELR: ADDED Test for Languages If DTE.ActiveDocument.Language = "CSharp" Then ' C Sharp Code startpoint.Insert(String.Format("{0}#region {1}{2}{2}", pad, rName, vbCrLf)) If endpoint.LineLength = 0 Then endpoint.Insert(String.Format("{2}{0}#endregion //{1}{2}", pad, rName, vbCrLf)) Else endpoint.Insert(String.Format("{2}{0}#endregion //{1}{2}", vbCrLf & pad, rName, vbCrLf)) End If Else ' VB Code
startpoint.Insert(String.Format("{0}#Region {1}{2}{2}", pad, rName, vbCrLf)) If endpoint.LineLength = 0 Then endpoint.Insert(String.Format("{2}{0}#End Region '{1}{2}", pad, rName, vbCrLf)) Else endpoint.Insert(String.Format("{2}{0}#End Region '{1}{2}", vbCrLf & pad, rName, vbCrLf)) End If End If
Phillip H. Blanton www.ComponentScience.net Email: Phillip at that domain that you see one line above the line you are reading now.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
one can continiously improve the script, so he's another small bit.
these days i find myself using p/invokes and attributes more often. to handle those you may want to add the following:
... ElseIf (line.StartsWith("[") Or line.EndsWith("]")) Then tmppoint = startpoint tmppoint.LineDown() line = GetDesc(tmppoint) ...
if you can be bothered you can check if it takes more than 1 line too :->
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
I really need to update the original article with the latest source. I am going to try to contact the Code Project people and see if there is an easy way for me to modify the article. For now, if you want to see the updated article, you can get it off of My blog.
Thanks for all the input guys. This is a heck of a lot of fun for me and it has resulted in a really cool macro that I am finding wonderfully useful.
I want to thank everyone who has tossed in their input.
Phillip H. Blanton www.ComponentScience.net Email: Phillip at that domain that you see one line above the line you are reading now.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hey evbd, I'm just a little bit confused by reading these posts. I noticed tht the author said tht he wasn't able 2 edit this document n then i saw so many more suggestions by other users as well. So, does anybody have the latest file with ALL snippets in it??
Thnxz in advance,
Blue Demon.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
there you go. that's what i have (I added SvenRieke's mod just for you but)
  
Imports EnvDTE Imports System.Diagnostics
Public Class Regions
' MakeRegion inserts #region and #endregion tags ' around selected text in the VS editor. Shared Sub MakeRegion() Dim rName As String = "" Dim pad As String = "" Dim junk As String Dim count, i As Integer Dim startpoint, endpoint, tmppoint As EditPoint
With DTE.ActiveDocument.Selection startpoint = .TopPoint.CreateEditPoint() endpoint = .BottomPoint.CreateEditPoint End With
If startpoint.EqualTo(endpoint) Then Exit Sub End If
'ELR: ADDED THIS, to move the startpoint to the start of the line 'so that the Pad function works correctly If Not startpoint.AtStartOfLine Then startpoint.StartOfLine() End If
'IV 2004-12-13: rName = InputBox("Region Name:") rName = InputBox("Region Name:", "Pick a name", GetDesc(DTE.ActiveDocument.Selection.TopPoint.CreateEditPoint()))
DTE.UndoContext.Open("Insert A Region") Try junk = startpoint.GetText(startpoint.LineLength)
pad = String.Empty For count = 0 To junk.Length - 1 If junk.Substring(count, 1).Equals(" ") Or _ junk.Substring(count, 1).Equals(vbTab) Then pad += junk.Substring(count, 1) Else Exit For End If Next
'ELR: ADDED Test for Languages If DTE.ActiveDocument.Language = "CSharp" Then ' C Sharp Code startpoint.Insert(String.Format("{0}#region {1}{2}", pad, rName, vbCrLf)) If endpoint.LineLength = 0 Then endpoint.Insert(String.Format("{0}#endregion // {1}{2}", pad, rName, vbCrLf)) Else endpoint.Insert(String.Format("{0}#endregion // {1}{2}", vbCrLf & pad, rName, vbCrLf))
End If Else ' VB Code startpoint.Insert(String.Format("{0}#Region ""{1}""{2}", pad, rName, vbCrLf)) If endpoint.LineLength = 0 Then endpoint.Insert(String.Format("{0}#End Region '{1}{2}", pad, rName, vbCrLf)) Else endpoint.Insert(String.Format("{0}#End Region ' {1}{2}", vbCrLf & pad, rName, vbCrLf)) End If End If Finally DTE.UndoContext.Close() End Try End Sub
' IV: Get the description from the 1st line of code in the region ' i.e. ignore c# comment tags (///) or take 1st line of the comments (//) ' Requires adjustments for VB and other langs Private Shared Function GetDesc(ByVal startpoint As EditPoint) As String Dim line As String = "" Dim tmppoint As EditPoint
line = startpoint.GetText(startpoint.LineLength) If (line.Length > 0) Then line = line.TrimStart(" ", vbTab) If DTE.ActiveDocument.Language = "CSharp" Then If (line.StartsWith("///")) Then tmppoint = startpoint tmppoint.LineDown() line = GetDesc(tmppoint) ElseIf (line.StartsWith("//")) Then line = line.TrimStart("//", " ") End If line = line.Replace("{", String.Empty) End If line = line.TrimEnd(" ", vbTab) End If Return line End Function
End Class
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
There is a buglet in your posting. The following line...
rName = rName = InputBox("Region Name:", "Pick a ... snip
is returning either TRUE or FALSE depending on the contents of the input box. This results in every region being named TRUE or FALSE.
Here is the full source code for the macro. If you have followed the directions in the original article, then you will need to replace the stuff in between the
Public Module
and...
End Module
with this...
Sub MakeRegion() Regions.MakeRegion() End Sub
Public Class Regions ' MakeRegion inserts #region and #endregion tags ' around selected text in the VS editor. Shared Sub MakeRegion() Dim rName As String = "" Dim pad As String = "" Dim junk As String Dim count, i As Integer Dim startpoint, endpoint, tmppoint As EditPoint
With DTE.ActiveDocument.Selection startpoint = .TopPoint.CreateEditPoint() endpoint = .BottomPoint.CreateEditPoint End With
If startpoint.EqualTo(endpoint) Then Exit Sub End If
'ELR: ADDED THIS, to move the startpoint to the start of the line 'so that the Pad function works correctly If Not startpoint.AtStartOfLine Then startpoint.StartOfLine() End If
'IV 2004-12-13: rName = InputBox("Region Name:") rName = InputBox("Region Name:", "Pick a name", GetDesc(DTE.ActiveDocument.Selection.TopPoint.CreateEditPoint()))
DTE.UndoContext.Open("Insert A Region") Try junk = startpoint.GetText(startpoint.LineLength)
pad = String.Empty For count = 0 To junk.Length - 1 If junk.Substring(count, 1).Equals(" ") Or _ junk.Substring(count, 1).Equals(vbTab) Then pad += junk.Substring(count, 1) Else Exit For End If Next
'ELR: ADDED Test for Languages If DTE.ActiveDocument.Language = "CSharp" Then ' C Sharp Code startpoint.Insert(String.Format("{0}#region {1}{2}", pad, rName, vbCrLf)) If endpoint.LineLength = 0 Then endpoint.Insert(String.Format("{0}#endregion // {1}{2}", pad, rName, vbCrLf)) Else endpoint.Insert(String.Format("{0}#endregion // {1}{2}", vbCrLf & pad, rName, vbCrLf))
End If Else ' VB Code startpoint.Insert(String.Format("{0}#Region ""{1}""{2}", pad, rName, vbCrLf)) If endpoint.LineLength = 0 Then endpoint.Insert(String.Format("{0}#End Region '{1}{2}", pad, rName, vbCrLf)) Else endpoint.Insert(String.Format("{0}#End Region ' {1}{2}", vbCrLf & pad, rName, vbCrLf)) End If End If Finally DTE.UndoContext.Close() End Try End Sub
' IV: Get the description from the 1st line of code in the region ' i.e. ignore c# comment tags (///) or take 1st line of the comments (//) ' Requires adjustments for VB and other langs Private Shared Function GetDesc(ByVal startpoint As EditPoint) As String Dim line As String = "" Dim tmppoint As EditPoint
line = startpoint.GetText(startpoint.LineLength) If (line.Length > 0) Then line = line.TrimStart(" ", vbTab) If DTE.ActiveDocument.Language = "CSharp" Then If (line.StartsWith("///")) Then tmppoint = startpoint tmppoint.LineDown() line = GetDesc(tmppoint) ElseIf (line.StartsWith("//")) Then line = line.TrimStart("//", " ") End If line = line.Replace("{", String.Empty) End If line = line.TrimEnd(" ", vbTab) End If Return line End Function
End Class
Phillip H. Blanton www.ComponentScience.net Email: Phillip at that domain that you see one line above the line you are reading now.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi there, good example. 
I've made a little variation for I didn't like typing extra stuff in the inputbox and prefer the macro to pick the 1st line of the region (i.e. name of the funcion). It may be useful for some.
... 'IV 2004-12-13: rName = InputBox("Region Name:") rName = GetDesc(DTE.ActiveDocument.Selection.TopPoint.CreateEditPoint()) ...
Private Shared Function GetDesc(ByVal startpoint As EditPoint) As String Dim line As String = "" Dim tmppoint As EditPoint
line = startpoint.GetText(startpoint.LineLength) If (line.Length > 0) Then line = line.TrimStart(" ", vbTab) If DTE.ActiveDocument.Language = "CSharp" Then ' ignore comments block If (line.StartsWith("///")) Then tmppoint = startpoint tmppoint.LineDown() line = GetDesc(tmppoint) ' comments block, strip // and use the rest ElseIf (line.StartsWith("//")) Then line = line.TrimStart("//", " ") End If line = line.Replace("{", String.Empty) End If line = line.TrimEnd(" ", vbTab) End If Return line End Function
One point of interest thou - there's no way of getting the newly created region collapsed, is there?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Nice macro, and I like this variation. But I added the code like this to be more flexible:
rName = InputBox("Region Name:", "Pick a name", GetDesc(DTE.ActiveDocument.Selection.TopPoint.CreateEditPoint()))
So it still opens the input box, but fills the textbox with the first line of the selected code. So you can change it or just press enter to use it.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
if I select my code till the latest } the #endregion is written on the same line as the }, while to work correctly it should have been written after a vbCrLf. 2 solutions: 1 - always add a vbCrLf (so if someone select till the line after the code than it will add one more cr) 2 - verify if the last selected char is a cr: if it is not than add a vbCrLf, otherwise it's ok this way
Simone
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I made solution number 2: If DTE.ActiveDocument.Language = "CSharp" Then ' C Sharp Code startpoint.Insert(String.Format("{0}#region {1}{2}", pad, rName, vbCrLf)) if endpoint.LineLength=0 then endpoint.Insert(String.Format("{0}#endregion // {1}{2}", pad, rName, vbCrLf)) Else endpoint.Insert(String.Format("{0}#endregion // {1}{2}", vbCrLf & pad, rName, vbCrLf)) End If Else ' VB Code startpoint.Insert(String.Format("{0}#Region ""{1}""{2}", pad, rName, vbCrLf)) If endpoint.LineLength = 0 Then endpoint.Insert(String.Format("{0}#End Region '{1}{2}", pad, rName, vbCrLf)) Else endpoint.Insert(String.Format("{0}#End Region ' {1}{2}", vbCrLf & pad, rName, vbCrLf)) End If End If
Simone
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I know of that issue, but I prefer to select the code using the Shift key and the down arrow, or dragging my mouse from the beginning of the top line down to just below the last mine, that way I don't get the extra blank line before #endregion.
Your solution fixes it for everyone though, so that is great!
Thanks!
I just gotta say, I am loving how much better this little macro has gotten in the last week. This is definitely a fun way to work.
Phillip H. Blanton www.ComponentScience.net Email: Phillip at that domain that you see one line above the line you are reading now.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
| | |