Extending with Macros


Before I discuss the CommenTater macro and the other macros in the Wintellect.VSMacros project (which you can find in the .\Macros directory with the book's source code), you'll need to load it into the Macro Explorer window in Visual Studio. Macros are a per-user setting, so the WintellectToolsInstall.MSI does not install them. To add the Wintellect.VSMacros file to your IDE, first open the Macro Explorer (on the View menu, select Other Windows, and then select Macro Explorer, or press Alt+F8 with the default keyboard settings), right-click the Macros item in the tree list, select Load Macro Project from the context menu, and then select .\Macros\Wintellect.VSMacros.

I also want to spend a little bit of time discussing a few key things about macros and some of the issues you'll encounter. The biggest point I want to make is that even if you think you have the coolest add-in idea in the world and can't wait to get started, you need to spend a lot of time writing macros before you jump into building add-ins. Because macros access all the same objects and properties as add-ins, they provide the best opportunity to learn about the ins and outs of the Visual Studio object model. As you'll see later in the chapter, the object model has numerous quirks, and getting add-ins working is sometimes problematic. Macros are much easier to write and debug, so you'll want to use them first to prototype.

Before finding the Macro option on the Tools menu, you should spend some time reading the documentation about macros and the object model. Macros themselves are discussed in the Visual Studio 2005 documentation by searching for Visual Studio Macros. You can find the all-important object model by searching for Automation Object Model Chart in the Help.

After perusing the documentation for a while to see what the various objects are, start recording macros so that you can see some of the objects in action. Keep in mind that recording works primarily on the code editors (including the Find/Replace dialog boxes), Solution Explorer, and window activation. You won't be able to record things such as building up a Web form or Windows form with controls. Also make sure to take a look at the macro samples provided by Microsoft, which are automatically loaded into the Macro Explorer as part of the Samples macro project. The macro samples are good examples of how to use the object model to solve problems. The MakeAddinFromMacroProj macro (in the MakeAddin macro project) is one of my personal favorites because it takes a macro and converts it to an add-in. It shows the power we now have at our fingertips with Visual Studio.

Another favorite module is the Debugger module because it shows you almost everything you can do with the Debugger object. For more tricks with the Debugger object, go to Jim Griesmer's blog entry at http://blogs.msdn.com/jimgries/archive/2005/12/12/501492.aspx. He's a developer on the debugger team at Microsoft, and he shows you his favorite debugger macros, which are worth adding to your collection.

There are two ways to execute macros: by double-clicking the macro function name in the Macro Explorer and by using the Command window. If you start typing macro, the Command window's IntelliSense pop-up window, shown in Figure 7-1, will allow you to choose the macro to run.

Figure 7-1. Command window's IntelliSense pop-up window executing a macro


If you're really into using the Command window to run macros or any of the other built-in commands, the built-in alias command allows you to redefine shorter text commands so that you don't have to type something like this every time you want to run a macro:

Macros.Wintellect.CommenTater.AddNoCommentTasksForSolution


To alias the previous example to something shorter, use the following command in the Command window:

alias CTforSLN Macros.Wintellect.CommenTater.AddNoCommentTasksForSolution


You also can remove aliases by passing a /d in front of the defined alias.

Macro Parameters

One fact that's not very clear from the Macro Explorer window and the Command window's IntelliSense pop-up window is that the only macros shown in both windows are macros that don't take any parameters. That makes sense in Macro Explorer because it would be pretty difficult to pass parameters when you're double-clicking an item. However, if you're using the Command window, you probably do want to pass some form of parameter. The trick is to declare the macro subroutine as taking a single optional string parameter, as in the following:

Sub ParamMacro(Optional ByVal theParam As String = "")


While looking at this declaration, you're probably wondering how you'd pass multiple parameters to the macro. It turns out that when you pass parameters, the macro environment in Visual Studio treats parameters as a single string, and it's up to you to chop up the string to extract individual parameters. The good news is that it takes a simple bit of regular expression knowledge to do your own parsing. Even better news is that I've already done the work, so you need just to copy my code.

In Wintellect.VSMacros, the Utilities module contains a function, SplitParameters, which treats commas as parameter delimiters and returns the individual parameters as a string array. When you look at the function, you'll see that a regular expression, written by Michael Ash, does all the heavy lifting. I found that regular expression at the wonderful RegExLib.com Web site, which is a great resource for anything related to regular expressions.

In the Utilities module, you'll also find some convenient wrappers I created around the Command window and Output window objects. These make showing the results of macros much easier than manually manipulating those windows. As you look through the macros in Wintellect.VSMacros, you'll see them used all over the place.

Debugging Macros

Since VSA is just Visual Studio in a slightly different form, all the debugging tricks except the C#-specific items I talked about in Chapter 5, "Power Debugging," also apply to debugging macros. However, one of the first things you'll notice about both macro and add-in development is that the Visual Studio IDE swallows exceptions like crazy. Although it makes sense for the IDE not to allow any exceptions to percolate up and crash the IDE, the IDE swallows so many unhandled exceptions, you might not even realize you're causing exceptions. When I developed my first macros, I sat for 20 minutes wondering why I could never seem to hit a breakpoint I set.

What I end up doing to ensure that there are no surprises is to open the Exceptions dialog box in the Macro IDE, select the Common Language Runtime Exceptions node in the Exceptions tree control, and then select the Thrown check box. This will set the macro debugger to stop on any exception. Figure 7-2 shows the proper settings. This will probably cause you to stop in the debugger a lot more, but at least you won't have any surprises when it comes to your code.

Figure 7-2. Setting the Exceptions dialog box to stop on all exceptions


One thing I've also noticed about debugging macros is that even when you set the Exceptions dialog box to stop on all exceptions, it might not. The trick to getting the macro debugger to start working correctly is to set a breakpoint somewhere in your code after you've set the Exceptions dialog box settings.

Code Elements

One of the most amazing aspects of Visual Studio is that all the programming constructs for source files can be accessed easily through the object model. The fact that we can now simply add, change, or remove items such as methods in all languages supported by Visual Studio without having to do the parsing ourselves opens up huge opportunities for all sorts of unique tools that might never have been created because parsing is so hard. Every time I use the code elements to manipulate the code in a file, I'm amazed at how cool this capability really is.

To show you how easy it is to access and utilize the code elements, I created a macro, shown in Listing 7-1, that dumps the code elements out of the active document. What's not obvious is that the code works for any language supported by Visual Studio. The output reports the name of the code element along with its code element type. The type indicates if the code element is a method, variable, et cetera. You can find this macro with this book's sample code in the Wintellect.VSMacros, Examples module along with its supporting module, Utilities.

Listing 7-1. DumpActiveDocCodeElements macro

[View full width]

' Dumps all the code elements for the open document of a project. Public Sub DumpActiveDocCodeElements() ' Where the output goes. Note that the OutputPane class comes ' from the Utilities macro project. Dim ow As OutputPane = New OutputPane("Open Doc Code Elements") ' Clear the output pane. ow.Clear() ' See if there's a document open. Dim doc As Document = DTE.ActiveDocument If (doc Is Nothing) Then ow.WriteLine("No open document") Exit Sub End If ' Get the code model for the doc. You have to get the project ' item to diddle down to the code elements Dim fileMod As FileCodeModel = Doc .ProjectItem.FileCodeModel If (fileMod IsNot Nothing) Then DumpElements(ow, fileMod.CodeElements, 0) Else ow.WriteLine("Unable to get the FileCodeModel!") End If End Sub Private Sub DumpElements(ByVal ow As OutputPane, _ ByVal elements As CodeElements, _ ByVal indentLevel As Integer) Dim currentElement As CodeElement2 For Each currentElement In elements Dim i As Integer = 0 While (i < indentLevel) ow.OutPane.OutputString(" ") i = i + 1 End While ' If there's an exception accessing the FullName property, ' it's probably an unnamed parameter. Dim name As String Try name = currentElement.FullName Catch e As COMException name = "'Empty Name'" End Try Dim kind As vsCMElement2 = CType (currentElement.Kind, vsCMElement2) ow.WriteLine(Name + "(" + currentElement .Kind.ToString() + ")") Dim childElements As CodeElements = Nothing childElements = currentElement.Children If (Not (childElements Is Nothing)) Then If (childElements.Count > 0) Then DumpElements(ow, childElements, indentLevel + 1) End If End If Next End Sub



CommenTater: The Cure for the Common Potato?

As you could tell from discussion of the custom Code Analysis/FxCop rules I provide as part of the book's source code, I have a fetish about making sure my XML documentation comments are on all public items in an assembly and are up to date. One of my favorite features in Visual Studio is that typing /// or ''' above a construct automatically inserts the appropriate documentation comments for an item, depending on the language. There are two very important reasons you should always fill out XML documentation comments. The first is that doing so enforces a consistent commenting standard across teams and, well, the .NET programming universe. The second is that the IDE IntelliSense automatically picks up any specified <summary> and <param> tags, which is a great help to others using your code because it gives them much more valuable information about the item. If the code is in the project, you don't have to do anything to get the benefits of using documentation comments. If you're providing a binary-only solution, the documentation comments can be gathered into an XML file at compile time, so you can still provide the cool summary tips to users. All you need to do is have the resultant XML file in the same directory as the binary, and Visual Studio automatically picks up the comments to show in the IntelliSense tips. By the way, the Object Browser will also use the XML file for its display.

I encourage you to read about all the XML documentation comment tags in the Visual Studio documentation so that you can do the best job possible documenting your code. It's very easy to create the files by setting the /DOC option to the C# and Visual Basic .NET compilers, and you'll want to do so for every configuration you build. To manually turn on the /DOC switch for non-ASP.NET C# projects, select the Build tab in the project properties, and then in the Output section, select the XML documentation file check box. The default is to put the file in your Output path, which is hard-coded initially. That means if you change your Output path, Visual Studio will continue writing your XML documentation file to the original directory. Fortunately, all you need to do is clear and reselect the XML documentation file check box to apply the latest output path. Figure 7-3 shows the Output section filled out.

Figure 7-3. Setting the XML documentation file for C# projects


As usual, Visual Basic non-ASP.NET projects are slightly different. In the project properties, click the Compile tab and select the Generate XML Documentation File check box. Visual Basic does the right thing and always puts the XML documentation file in the same directory where the assembly builds. If the prospect of manually setting the documentation file for every configuration in your projects sounds tedious, you'll want to use SettingsMaster to do all the work for you.

Since documentation comments are so important, I wanted some way of automatically adding them to my C# and Visual Basic .NET code. While Roland Weigelt's outstanding GhostDoc add-in (http://www.roland-weigelt.de/ghostdoc/) is excellent for automating one method's comments at a time, I wanted a tool that would look for all methods I'd forgotten to document and add comments so I could find where they were missing. As I was thinking about how I would show the user all the missing comments, I stumbled across a very nice feature of the Task List window in the IDE. If you set the Task List window combo box to Comments, any comments in your code that contain "TODO" automatically show up in the window. In fact, if you go to the Options dialog box from the Tools menu, select Environment, and then select the Task List property page, you'll see that HACK, MISSING, and UNDONE are other tokens that the IDE will look for in your comments. You can also add your own tokens, such as FIX, UPDATE, and WHO_IS_THE_IDIOT_THAT_WROTE_THIS (spaces cannot be used in the tokens). My idea was to have either a macro or an add-in that would add any missing documentation comments and use "TODO" in the comments so that I could easily go through and ensure that all the documentation comments were properly filled out. The result was CommenTater. The following shows a method that's been processed by CommenTater:

/// <summary> /// TODO - Add Test function summary comment /// </summary> /// <remarks> /// TODO - Add Test function remarks comment /// </remarks> /// <param name="x"> /// TODO - Add x parameter comment /// </param> /// <param name="y"> /// TODO - Add y parameter comment /// </param> /// <returns> /// TODO - Add return comment /// </returns> public static int Test ( Int32 x , Int32 y ) {    return ( x ) ; }


While the idea of showing the TODO items in the Task List is an excellent one, there's a small problem with C# with Visual Studio 2005: the TODO items don't show up. Prior versions of Visual Studio had this working with C#, and it works with Visual Basic in Visual Studio 2005. I hope that this will be fixed in a service pack release because it's a very useful feature.

Visual Studio makes iterating the code elements in a source file trivial, so I was pretty excited because I thought that all I'd have to do was wind through the code elements, grab any lines above the method or property, and if the documentation comment wasn't present, poke in the documentation comment for that method or property. That's when I discovered that the code elements all come with a property named DocComment that returns the actual documentation comment for the item. I immediately tipped my hat to the developers for thinking ahead and really making the code elements useful. Now all I needed to do was set the DocComment property to the value I wanted, and life was good.

Once you have the book's macros open, double click Wintellect, right-click the CommentTater module, and then select Edit to bring it up in the macro editor. The source code for the macro is too large to include in the book pages, but consider looking at the file as I discuss the ideas behind its implementation. My main idea was to create two functions, AddNoCommentTasksForSelectedProjects and CurrentSourceFileAddNoCommentTasks. You can tell from the names what level the functions were to work on. For the most part, the basic algorithm looks relatively similar to the examples in Listing 7-1 in that I just iterate through all the code elements and manipulate the DocComment property for each code element type.

The first issue I ran into was what I considered a design flaw in the code element object model. The DocComment property is not a common property on the CodeElement class, which can be substituted as a base for any general code element. So I had to jump through the hoops necessary to convert the generic CodeElement object into the actual type based on the Kind property. That's why the RecurseCodeElements function has the big Select. . . Case statement in it.

The second problem I ran into was completely self-inflicted. For some reason, it never dawned on me that the DocComment property for a code construct needed to be treated as a fully formed XML fragment. I'd build up the documentation comment string I wanted, and when I'd try to assign it to the DocComment property, an ArgumentException would be thrown. I was quite confused because it looked like the DocComment property was both readable and writable, but it was acting as if it were only readable. For some bizarre reason, I had a brain cramp and didn't realize that the reason for the exception was that I wasn't properly bracketing my documentation comment XML with the necessary <doc></doc> element. Of course, thinking that the DocComment property was read-only, I implemented all doc comment updating using text insertion. After my brain cramp fixed itself, I realized that I needed just to set a properly formed XML string into the DocComment and let Visual Studio take care of all insertions. The last oddity I want to mention about DocComment properties is that C# DocComment properties always show the <doc></doc> root when you look at the string, but Visual Basic .NET DocComment properties do not.

Listing 7-2 shows the ProcessFunctionComment, and you can see that I take advantage of the XML classes in the Microsoft .NET Framework library to do the hard work required to get the information out of the existing documentation comment string, allowing me to build up a new version. The ProcessFunctionComment function might reorder your documentation comments; I had to pick an order for putting the individual nodes in the file. Additionally, I format the comments as I like to see them, so CommenTater might change your careful formatting of your documentation comments, but it won't lose any information.

Listing 7-2. ProcessFunctionComment from CommenTater

[View full width]

' Does all the work to take an existing function comment and ensure ' that everything in it is correct. This might reorder your ' comments, so you might want to change it. Private Sub ProcessFunctionComment(ByVal func As CodeFunction) Debug.Assert("" <> func.DocComment, """"" <> Func.DocComment") ' Holds the original doc comment. Dim xmlDocOrig As New XmlDocument ' I LOVE THIS! By setting PreserveWhitespace to true, the ' XmlDocument class will keep most of the formatting... xmlDocOrig.PreserveWhitespace = True ' This is annoying. Since Visual Basic does not properly put on ' the <doc> root element, I've got to add it so LoadXml works. Dim xmlString As String = func.DocComment If (func.Language = CodeModelLanguageConstants.vsCMLanguageVB) Then Dim sb As StringBuilder = New StringBuilder() sb.AppendFormat("<doc>{0}</doc>", xmlString) xmlString = sb.ToString() End If ' Speaking of inconsistencies... Even though I keep all formatting ' of any inner XML, setting a C# DocComment property will strip out ' empty CRLF lines. Visual Basic preserves all formatting. xmlDocOrig.LoadXml(xmlString) Dim rawXML As New StringBuilder ' The function name properly formatted for XML. Dim FName As String = ProperlyXMLizeFuncName (func.Name) ' Get the summary node. Dim node As XmlNode Dim nodes As XmlNodeList = xmlDocOrig .GetElementsByTagName("summary") If (0 = nodes.Count) Then rawXML.Append(SimpleSummaryComment(func, FName, "function")) Else rawXML.AppendFormat("<summary>{0}", vbCrLf) For Each node In nodes rawXML.AppendFormat("{0}{1}", node .InnerXml.Trim(), vbCrLf) Next rawXML.AppendFormat("</summary>{0}", vbCrLf) End If ' Get the remarks node. nodes = xmlDocOrig.GetElementsByTagName ("remarks") If (nodes.Count > 0) Then rawXML.AppendFormat("<remarks>{0}", vbCrLf) For Each node In nodes rawXML.AppendFormat("{0}{1}", node .InnerXml.Trim(), vbCrLf) Next rawXML.AppendFormat("</remarks>{0}", vbCrLf) ElseIf (True = addRemarksToFunctions) Then rawXML.AppendFormat("<remarks>{0}TODO - Add {1} function " + _ "remarks comment{0}</remarks>", _ vbCrLf, FName) End If ' Get any parameters described in the doc comments. nodes = xmlDocOrig.GetElementsByTagName("param") ' Does the function have parameters? If (0 <> func.Parameters.Count) Then ' Slap any existing doc comment params into a hash table with ' the parameter name as the key. Dim existHash As New Hashtable For Each node In nodes Dim paramName As String Dim paramText As String paramName = node.Attributes("name") .InnerXml paramText = node.InnerText.Trim() existHash.Add(paramName, paramText) Next ' Loop through the parameters. Dim elem As CodeElement For Each elem In func.Parameters ' Is this one in the hash of previous filled-in params? If (True = existHash.ContainsKey (elem.Name)) Then rawXML.AppendFormat("<param name=""{0}"">{1}{2}{1}" + _ "</param>{1}", _ elem.Name, _ vbCrLf, _ existHash (elem.Name)) ' Get rid of this key. existHash.Remove(elem.Name) Else ' A new parameter was added. rawXML.AppendFormat("<param name=""{0}"">{1}TODO - Add " + _ "{0} parameter comment{1}</param>{1}", _ elem.Name, vbCrLf) End If Next ' If there is anything left in the hash table, a param ' was either removed or renamed. I'll add the remaining ' with TODOs so the user can do the manual deletion. If (existHash.Count > 0) Then Dim keyStr As String For Each keyStr In existHash.Keys Dim desc As Object = existHash (keyStr) rawXML.AppendFormat("<param name=""{0}"">{1}{2}{1}{3}" + _ "{1}</param>{1}", _ keyStr, _ vbCrLf, _ desc, _ "TODO - Remove param tag") Next End If End If ' Take care of returns if necessary. If ("" <> func.Type.AsFullName) Then nodes = xmlDocOrig.GetElementsByTagName ("returns") ' Do any returns nodes, but only if there's an actual return value. If (0 = nodes.Count) Then If (String.IsNullOrEmpty(func.Type .AsFullName) = False) And _ (String.Compare(func.Type .AsFullName, "System.Void") <> 0) Then rawXML.AppendFormat("<returns>{0 }TODO - Add return comment" + _ "{0}</returns>", _ vbCrLf) End If Else rawXML.AppendFormat("<returns>{0}", vbCrLf) For Each node In nodes rawXML.AppendFormat("{0}{1}", node.InnerXml.Trim(), vbCrLf) Next rawXML.Append("</returns>") End If End If ' Copy existing examples nodes, if any. nodes = xmlDocOrig.GetElementsByTagName ("example") If (nodes.Count > 0) Then rawXML.AppendFormat("<example>{0}", vbCrLf) For Each node In nodes rawXML.AppendFormat("{0}{1}", node .InnerXml.Trim(), vbCrLf) Next rawXML.AppendFormat("</example>{0}", vbCrLf) End If ' Copy existing permission nodes, if any. nodes = xmlDocOrig.GetElementsByTagName ("permission") If (nodes.Count > 0) Then For Each node In nodes rawXML.AppendFormat("<permission cref=""{0}"">{1}", _ node.Attributes ("cref").InnerText, _ vbCrLf) rawXML.AppendFormat("{0}{1}", node .InnerXml.Trim(), vbCrLf) rawXML.AppendFormat("</permission>{0 }", vbCrLf) Next End If ' Finally exceptions. nodes = xmlDocOrig.GetElementsByTagName ("exception") If (nodes.Count > 0) Then For Each node In nodes rawXML.AppendFormat("<exception cref=""{0}"">{1}", _ node.Attributes ("cref").InnerText, _ vbCrLf) rawXML.AppendFormat("{0}{1}", node .InnerXml.Trim(), vbCrLf) rawXML.AppendFormat("</exception>{0} ", vbCrLf) Next End If func.DocComment = FinishOffDocComment(func, rawXML.ToString()) End Sub



Once I had everything working with documentation comment updating, I thought it'd be a good idea to go ahead and implement the code necessary to handle an undo context. That way you could do a single Ctrl+Z and restore all changes to CommenTater in case of a bug. In prior versions of Visual Studio, there was a bug in the undo contexts if I sent them globally, so all changes the macro made could be undone in a single operation. Fortunately, the developers fixed that bug so that I can offer a global undo. If you like the idea of having the individual change undo, you can set the individualUndo field near the top of the file to True.

Another tweak I had to make to the macro moving from Visual Studio .NET 2003 to Visual Studio 2005 was to revamp the project enumeration. Prior versions of Visual Studio did not allow project folders, so my macro was finding files only that were at the top level. Since there's an arbitrary number of folder levels, I needed just to do the recursion looking for all project items that have a non-empty FileCodeModel property. If you do have to enumerate project items, make sure to look at the ListProj macro in the Samples.VSMacros file because that will show you exactly what you'll need to do.

In addition to the individualUndo field I mentioned earlier, there are two other option fields that you may want to change. By default, the CommenTater macros put comments only on those items that are public in an assembly. If you want to have missing documentation comments applied to all methods, set the visibleOnly field at the top of the file to False. The final option field to change the output is the addRemarksToFunctions field. As you can see from the name, if it's set to True, all methods will be checked for a <remarks>. . .</remarks> section in the comment, and if one is not there, the macro will add it with a TODO.

CommenTater is a macro I use all the time, and I think you'll find it useful for your development. As with any code, there's always room for improvement. One feature I'd like to integrate into the code is automatic <exception>. . .</exception> documentation generation. Since the CodeElements don't go into methods, you'd have to do some parsing on the actual text of the method or property. That sounds like a job for a regular expression and the good news is that Tony Chow already produced them in an MSDN Magazine article (http://msdn.microsoft.com/msdnmag/issues/05/07/XMLComments/default.aspx). Another feature that may take a little more work would be one that allows users to specify the formatting they want for their XML documentation comments. Whereas I like mine with the element markers and inner text all on separate lines, others may not like that. If you have any other feature suggestions, don't hesitate to send them to me because I will definitely consider them.

More Macros for You

As you look through Wintellect.VSMacros, you'll see numerous other modules, which contain macros you'll find useful in your daily development. In Chapter 5's "Advanced Breakpoints and How to Use Them" section, I mentioned the BreakPointHelper module, which contains two macros, SetBreakpointsOnDocMethods and RemoveBreakpointsOnDocMethods. Those macros run though the code elements in the active document, set a breakpoint at the entry point for each method and property in the file, and remove them, respectively. These macros take advantage of the BreakPoint.Tag property to identify the breakpoints set by the SetBreakpointsOnDocMethods macro so that the RemoveBreakpointsOnDocMethods macro removes only those breakpoints. That way none of your existing breakpoints are removed by using these macros.

Also in Chapter 5, I discussed the TracePointMacros module in the "Tracepoints" section. The macros in that module show you how to work around the major limitation of Tracepoint breakpoints by faking out the IDE to think it is stopping on a breakpoint but using another thread to tell the debugger to continue execution.

The revision marks in the Visual Studio editor are wonderful because a small yellow bar next to a line indicates a line that's changed but that you haven't saved. A small green bar is a line that's changed but you have saved. Unfortunately, there's no way for you to have the editor clear out those bars so you can see changes between two points. What you have to do is close the editor window and reopen it. The problem there is that when you reopen the window, the cursor does not go back to the last place you were editing in the document but to the first line and column. Because there are many times when you want to look at code changes in isolation, The RevMarks module contains a single macro, ClearRevMarks, which saves your current location and selection in the file, closes the source window, reopens it, and puts the cursor and selection back. When I initially started to write the macro, I thought it would be a ten-line quickie, but things are not always so simple in Visual Studio. You can see the trials and tribulations I went through by looking at the macro's code.

The Keys module was born out of my frustration looking for the keystroke bound to a particular command. The Options dialog box, Environment node, Keyboard property page is fine for binding a command to a keystroke, but it's worthless for easily finding keystrokes that perform different commands in different editors or contexts. The first macro, EnumerateAllCommands, lists all the commands in the IDE in alphabetical order along with the keystrokes that are bound to them. Because various tools in the IDE may implement identically named commands, such as Edit.Breakline, the keystroke bindings are shown prefixed with the tool they are bound to. For example, the following shows that the Edit.Breakline command has four different bindings as the tool is shown to the left of the :: characters.

Edit.BreakLine (Windows Forms Designer::Enter |                 Text Editor::Shift+Enter |                 Text Editor::Enter |                 Report Designer::Enter)


The two other macros in the Keys module, EnumerateBindingsByCommand and EnumerateKeyboardBoundCommands are similar in that they show only commands bound to keystrokes. The EnumerateBindingsByCommand dumps out the list sorted by keystrokes, and EnumerateKeyboardBoundCommands shows the output sorted by command. As a real keyboard maven, I've learned a huge number of new keystrokes by looking at the output of these two macros. In my case, my carpel tunnel syndrome is exacerbated by mouse usage, so the more I can keep my fingers on the keyboard in Visual Studio, the healthier I am.

We all want Visual Studio to run as fast as possible, and a blog entry by Roland Weigelt at http://weblogs.asp.net/rweigelt/archive/2006/05/16/446536.aspx showed a macro, ToggleCSharpNavigationBar, that toggles the navigation bar on top of the C# editor on and off. Roland mentioned that he's discovered that turning off the navigation bar, which are the two combo boxes on top of the editor window that allow you to navigate classes and methods in a file, speed up the editor for him. Although I haven't done any actual performance tests, it feels faster for me. Because I never use the navigation bars, turning them off was no big deal for me. Roland graciously allowed me to include his macro in the NavigationBar module.

Two other modules, SelectedSearch and FormatToHtml, are courtesy of Jeff Atwood, of the outstanding CodingHorror.com blog fame, which is mandatory to add to your blog subscription list. In his Google Search VS.NET macro entry (http://www.codinghorror.com/blog/archives/000428.html) is a great macro that uses Google to search for the selected text in a source code window or in the Output window. Because the MSDN Library for Visual Studio 2005 search is extremely slow and not very good, Jeff's excellent macro, SearchGoogleForSelectedText, makes looking up something much more bearable. I added two macros to the SelectedSearch module, SearchGoogleMicrosoftForSelectedText, which searches the Microsoft-related section of Google for the selected text, and SearchMsnForSelectedText, which searches MSN for the selected text. I've bound these to my Alt+G and Alt+M for instant search happiness.

If you've ever pasted code from the Visual Studio editor into Microsoft Word, an HTML editor, or your blog, you know that instead of getting HTML as you would expect, you get some ugly Rich Text Format. Jeff wanted nice clean HTML, so he wrote some excellent macros to put pristine HTML on the clipboard (http://www.codinghorror.com/blog/archives/000429.html). For most code, you'll use the Modern and ModernText macros because those produce HTML with <div> and <span> elements. If you're working with an environment that doesn't have those codes, use the Legacy and LegacyText macros. To someone like me who puts tons of code into documents, these macros are worth their weight in gold. I also appreciate Jeff's permission to allow me to include them with the book's source code.

While I use Jeff's macros, I should also mention that many people are very happy with Colin Coller's CopySourceAsHtml (CSAH) add-in, which you can download from http://www.jtleigh.com/people/colin/software/CopySourceAsHtml/. The CSAH add-in offers support for background colors, line numbering settings, and syntax highlighting. It also comes with full source code and is an excellent example of how to write a good add-in.




Debugging Microsoft  .NET 2.0 Applications
Debugging Microsoft .NET 2.0 Applications
ISBN: 0735622027
EAN: 2147483647
Year: 2006
Pages: 99
Authors: John Robbins

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net