C# 2.0 has Surround With command that enables you to wrap the selected code inside a if, for, foreach, while, #if (and a few mode) blocks. Some of the options are virtually useless - for example, I'd never wrap a piece of code in a class, interface, or enum block - but all in all it's a very handy command. Actually, it is so convenient that I decided to create a set of Visual Studio macros that add the same functionality to Visual Basic (both 2003 and 2005 editions) and C# 2003.
To install and use the macros listed below, add the following module to the Macro IDE, go back to Visual Studio, select a piece of code, open the WrappingMacros element in the Macro Explorer window, and double-click the macro you want to apply. In some cases, after applying the macro you'll also need to edit the generated code, for example to insert a condition in the If statement or the name of the #region you've created. Also, if you are working with C# you should manually reformat the selected code (by typing Ctrl+K, Ctrl+F), because for some reason the Edit.FormatSelection command works only in Visual Basic.
Even better, you should associate the macros you like most with a keyboard shortcut, so that you can apply the macro without opening the Macro Explorer window. If you need to list which shortcuts are available, have a look at yesterday's post.
Imports System
Imports EnvDTE
Public
Module WrappinglMacros
' --------------------------------------------------------------------
' Wrap the selected code inside IF, TRY, etc.
' --------------------------------------------------------------------
Public Sub WrapIf()
WrapCode("WrapIf", "If True Then\n$sel$End If\n", "if ( true )\n{\n\t$sel$}\n")
End Sub
Public Sub WrapIfElse()
WrapCode("WrapIfElse", "If True Then\n$sel$Else\n\nEnd If\n", "if ( true )\n{\n\t$sel$}\nelse\n{\n}\n")
End Sub
Public Sub WrapTryCatch()
WrapCode("WrapTryCatch", "Try\n$sel$Catch ex As Exception\n\nEnd Try", _
"try\n{\n$sel$}\ncatch (Exception ex)\n{\n}\n")
End Sub
Public Sub WrapTryFinally()
WrapCode("WrapTryFinally", "Try\n$sel$Finally\n\nEnd Try", "try\n{\n$sel$}\nfinally\n{\n}\n")
End Sub
Public Sub WrapTryCatchFinally()
WrapCode("WrapTryCatchFinally", "Try\n$sel$Catch ex As Exception\n\nFinally\n\nEnd Try", _
"try\n{\n$sel$}\ncatch (Exception ex)\n{\n}\nfinally\n{\n}\n")
End Sub
Public Sub WrapRegion()
WrapCode("WrapRegion", "#Region ""RegionName""\n\n$sel$\n#End Region", _
"#region RegionaName\n\n$sel$\n#endregion")
End Sub
Public Sub WrapSharpIf()
WrapCode("WrapSharpIf", "#IF True Then\n\n$sel$\n#End If", "#if true\n\n$sel$\n#endif")
End Sub
Public Sub WrapFor()
WrapCode("WrapFor", "For index As Integer = startIndex To endIndex\n$sel$Next", _
"for (int index = startIndex; i <= endIndex; index++)\n{\n$sel$}\n")
End Sub
Public Sub WrapForEach()
WrapCode("WrapForEach", "For Each obj As Object In collection\n$sel$Next", _
"foreach (object obj in collection)\n{\n$sel$}\n")
End Sub
Public Sub WrapWhile()
WrapCode("WrapWhile", "Do While True\n$sel$Loop", "while (true)\n{\n$sel$}\n")
End Sub
Public Sub WrapDoWhile()
WrapCode("WrapDoWhile", "Do\n$sel$Loop While True", "do\n{\n$sel$} while ( true );\n")
End Sub
Public Sub WrapNamespace()
WrapCode("WrapNamespace", "Namespace NamespaceName\n$sel$End Namespace", _
"namespace NamespaceName\n{\n$sel$} // end of namespace")
End Sub
Public Sub WrapSelect()
WrapCode("WrapSelect", "Select Case expression\nCase 0\n$sel$Case 1\nCase Else\nEnd Select\n", _
"switch ( expression )\n{\n\tcase 0:\n\t\tbreak;\n\tcase 1:\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n}\n")
End Sub
Public Sub WrapSyncLock()
WrapCode("WrapIf", "SyncLock lockObject\n$sel$End SyncLock\n", "lock ( lockObject )\n{\n\t$sel$}\n")
End Sub
' Helper method that replaces the selection with the specified templated text.
' The template can include $sel$ (the selected code) and escape sequences such as \r\n, \t
Private Sub WrapCode(ByVal cmdName As String, ByVal vbTemplate As String, ByVal csTemplate As String)
' Determine the current language by looking at the extension of the current document.
Dim doc As Document = DTE.ActiveDocument
If doc Is Nothing Then Exit Sub
Dim docName As String = doc.Name.ToLower()
Dim sel As TextSelection = DirectCast(DTE.ActiveDocument.Selection, TextSelection)
If sel Is Nothing Then Exit Sub
' Open an undo context.
DTE.UndoContext.Open(cmdName)
' Retrieve the selected text, append a newline if necessary.
Dim selText As String = sel.Text
If Not selText.EndsWith(ControlChars.NewLine) Then selText &= ControlChars.NewLine
' Wrap the selected text, using either the VB or the C# command
Dim template As String
If docName.EndsWith(".vb") Then
template = vbTemplate
ElseIf docName.EndsWith(".cs") Then
template = csTemplate
End If
' Replace CR-LF, tabs, and the selected text
Dim newText As String = Regex.Unescape(template).Replace("$sel$", selText)
' Reselect the text just added and format it. (Doesn't work in C#.)
Dim ep As EditPoint = sel.TopPoint.CreateEditPoint()
sel.Text = newText
sel.MoveToPoint(ep, True)
DTE.ExecuteCommand("Edit.FormatSelection")
' Close the undo context.
DTE.UndoContext.Close()
End Sub
End
Module