Introducing Visual Studio 2005 IntelliSense Code Snippets

Dynamic code generation has existed for quite a while. In fact, you'll find tools that can help developers generate tens of thousands of lines of code with just a click of a button. Some of these are even flexible enough to allow you to modify the tokens in the template—or even the templates themselves—for added control over the output of the code. (The Code Generation Network Web site has an extensive list of these tools, quite a few of which I have used in the past—some with great success.)

I have always wanted to have the ability to create code inline without loading an external tool, or loading a Visual Studio add-in. That is where code snippets come to the rescue. They are not as powerful as some of the generators, but they perform more work in the day-to-day coding that experienced developers do.

Visual Studio 2005 IntelliSense code snippets enable you to create your own IntelliSense snippets without leaving the Visual Studio IDE. This ability boosts productivity by allowing you to create and insert samples of code that you use regularly. It also allows custom code developers to provide snippet examples of their own libraries and APIs.

Table 1 shows the current list of included snippets as of this writing.

Table 1: List of Current Visual Studio 2005 IntelliSense Code Snippets

Name Description Valid Locations to Insert Snippet
#if Creates a #if directive and a #endif directive Anywhere
#region Creates a #region directive and a #endregion directive Anywhere
~ Creates a destructor for the containing class Inside a class
attribute Creates a declaration for a class that derives from Attribute Inside a namespace (including the global namespace), a class, or a struct
checked Creates a checked block Inside a method, an indexer, a property accessor, or an event accessor
class Creates a class declaration Inside a namespace (including the global namespace), a class, or a struct
ctor Creates a constructor for the containing class Inside a class
cw Creates a call to WriteLine Inside a method, an indexer, a property accessor, or an event accessor
do Creates a do while loop Inside a method, an indexer, a property accessor, or an event accessor
else Creates an else block Inside a method, an indexer, a property accessor, or an event accessor
enum Creates an enum declaration Inside a namespace (including the global namespace), a class, or a struct
equals Creates a method declaration that overrides the Equals method defined in the Object class Inside a class or a struct
exception Creates a declaration for a class that derives from an exception (Exception by default) Inside a namespace (including the global namespace), a class, or a struct
for Creates a for loop Inside a method, an indexer, a property accessor, or an event accessor
foreach Creates a foreach loop Inside a method, an indexer, a property accessor, or an event accessor
forr Creates a for loop that decrements the loop variable after each iteration Inside a method, an indexer, a property accessor, or an event accessor
if Creates an if block Inside a method, an indexer, a property accessor, or an event accessor
indexer Creates an indexer declaration Inside a class or a struct
interface Creates an interface declaration Inside a namespace (including the global namespace), a class, or a struct
invoke Creates a block that safely invokes an event Inside a method, an indexer, a property accessor, or an event accessor
iterator Creates an iterator Inside a class or a struct
iterindex Creates a "named" iterator and indexer pair by using a nested class Inside a class or a struct
lock Creates a lock block Inside a method, an indexer, a property accessor, or an event accessor
mbox Creates a call to System.Windows.Forms.MessageBox.Show (You may need to add a reference to System.Windows.Forms.dll.) Inside a method, an indexer, a property accessor, or an event accessor
namespace Creates a namespace declaration Inside a namespace (including the global namespace)
prop Creates a property declaration and a backing field Inside a class or a struct
propg Creates a property declaration with only a "get" accessor and a backing field Inside a class or a struct
sim Creates a static int Main method declaration Inside a class or a struct
struct Creates a struct declaration Inside a namespace (including the global namespace), a class, or a struct
svm Creates a static void Main method declaration Inside a class or a struct
switch Creates a switch block Inside a method, an indexer, a property accessor, or an event accessor
try Creates a try-catch block Inside a method, an indexer, a property accessor, or an event accessor
tryf Creates a try-finally block Inside a method, an indexer, a property accessor, or an event accessor
unchecked Creates an unchecked block Inside a method, an indexer, a property accessor, or an event accessor
unsafe Creates an unsafe block Inside a method, an indexer, a property accessor, or an event accessor
using Creates a using directive Inside a namespace (including the global namespace)
while Creates a while loop Inside a method, an indexer, a property accessor, or an event accessor

Take a Shallow Dive

To access code snippets, simply right-click in a code window and click on 'Insert Snippet', as shown in Figure 1.

Figure 1: Access Code Snippets

Depending on the type of file, you then will see the types of snippets that are available to you. This example presents a C# class file, so you see two options: Office Development and Visual C#, as shown in Figure 2.

Figure 2: Available Types of Snippets

The category you select displays a list of its available snippets. These snippets will vary; you add to them or modify the existing ones. The list in Figure 3 is from the Visual C# category.

Figure 3: Available Snippets in Visual C#

The snippet name that you select dictates the code that is injected into the code window and at which location. For this C# example, choose ctor, which is the snippet to create a default constructor for your class (see Figure 4).

Figure 4: The ctor Code Snippet Creates a Default Constructor for Your Class

Clicking on the label injects the code into the spot where your cursor was when you first right-clicked in the code window. Figure 5 shows the code.

Figure 5: The Injected ctor Code

Now you can explore the ctor.snippet file that is located in the folder C:\Program Files\Microsoft Visual Studio 8\VC#\Snippets\1033\Visual C#. Figure 6 shows this snippet file.

Figure 6: The ctor.snippet File

The file has only one code snippet defined, but it can have as many as defined in the schema. The title element will be displayed in the IntelliSense picker as well as in the Code Snippets Manager (see Figure 7). The manager also shows the other header elements; the Code Snippets Manager window displays the description, shortcut, snippet type, and the author.

Figure 7: Title and Header Elements in the Code Snippets Manager

Introducing Visual Studio 2005 IntelliSense Code Snippets

The Elements of a Snippet

You now are ready to learn what it takes to create a snippet. You'll find the snippet schema at snippetformat.xsd. CodeSnippets is the root element of the schema. It can contain one or more CodeSnippet child elements, each of which contains all the data for the snippet:

<CodeSnippets>
   <CodeSnippet>...</CodeSnippet>
   <CodeSnippet>...</CodeSnippet>
</CodeSnippets>

The CodeSnippet element contains two child elements, as well as an optional format attribute. The format attribute is a mechanism that enables you to version the snippet:

<CodeSnippet Format="1.0.1">
   <Header>...</Header>
   <Snippet>... </Snippet>
</CodeSnippet>

The Header element contains general information about the snippet, and each code snippet can contain only one. The child elements of the header are Title, Author, Description, HelpUrl, SnippetTypes, Keyword, and Shortcut:

<Header>
   <Title>...</Title>
   <Author>...</Author>
   <Description>... </Description>
   <HelpUrl>... </HelpUrl>
   <SnippetTypes>...</SnippetTypes>
   <Keywords>... </Keywords>
   <Shortcut>... </Shortcut>
</Header>

The following is the Header from the ctor.snippet file in this example:

<Header>
   <Title>ctor</Title>
   <Shortcut>ctor</Shortcut>
   <Description>Code snippet for constructor</Description>
   <Author>Microsoft Corporation</Author>
   <SnippetTypes>
      <SnippetType>Expansion</SnippetType>
   </SnippetTypes>
</Header>

Most of these elements are pretty self-explanatory. The HelpUrl is a pointer to a document that contains additional information about the snippet. SnippetTypes indicates to Visual Studio 2005 how to insert the code snippet into the code window:

<SnippetTypes>
   <SnippetType>... </SnippetType>
   <SnippetType>... </SnippetType>
<SnippetTypes>

If this value does not exist, code can be inserted into any file. The following are the valid SnippetType values:

  • SurroundsWith: Place the code snippet around a selected piece of code
  • Expansion: Insert the code snippet at the cursor
  • Refactoring: Use the code snippet during Visual C# refactoring (Refactoring cannot be used in custom code snippets.)

Because refactoring is not allowed in custom code snippets, that leaves SurroundsWith and Expansion. The main difference between the two is shown in the figures below. To use the SurroundsWith type, you must select the code or text block that you want to 'surround' with the snippet. Figures 8 and 9 show the before and after of the SurroundsWith type.

[Snip08.jpg]

Figure 8: Before the SurroundsWith Type

After selecting the code, you then can right-click and select the snippet. This example selects the region snippet.

[Snip09.jpg]

Figure 9: After the SurroundsWith Type

Selecting the #region snippet encases the code in #region and #endregion tags. Also note that the default substitution string MyRegion is highlighted. If you needed to make more replacements, you could simply tab to the next one. This feature speeds up the maintenance of the snippet. The expansion snippet, on the other hand, just inserts the code at the location of the cursor.

The Keywords elements allows one or more keyword elements to be defined so that Visual Studio and other providers can search and locate the snippet in a standard way:

<Keywords>
   <Keyword>... </Keyword>
   <Keyword>...</Keyword>
<Keywords>

And finally comes the Shortcut key, a unique feature that allows you to just type the shortcut into the code window and then press the tab key. This works great with expansion snippets.

You can now look at the Snippet element, which defines the code for the snippet:

<Snippet>
   <References>... </References>
   <Imports>... </Imports>
   <Declarations>... </Declarations>
   <Code>...</Code>
</Snippet>

The following is the snippet node from the example ctor.snippet:

<Snippet>
   <Declarations>
      <Literal Editable="false">
         <ID>classname</ID>
         <ToolTip>Class name</ToolTip>
         <Function>ClassName()</Function>
         <Default>ClassNamePlaceholder</Default>
      </Literal>
   </Declarations>
   <Code Language="csharp"><![CDATA[public $classname$ ()
   {
      $end$
   }]]>
   </Code>
</Snippet>

The References element is valid only in Visual Basic snippets. This optional element contains information about references to other libraries that may be used in the snippet. It has two child elements: Assembly is the location of the dll, and Url is a link to more information about the assembly:

<References>
   <Reference>
      <Assembly>System.Data.dll</Assembly>
      <Url>msdn.microsoft.com</Url>
   </Reference>
   <Reference>
      <Assembly>... </Assembly>
      <Url>... </Url>
   </Reference>
</References>

The Imports element contains information about the namespaces that will be used in the code snippet. It has the same effect as using the import inside your code. The only child element of the Imports element is the namespace:

<Imports>
   <Import>
      <Namespace>System</Namespace>
   </Import>
   <Import>
      <Namespace>System.Data</Namespace>
   </Import>
<Imports>

The Declarations element is where you define variables that act as replacements within the code element of the snippet. Literal and Object are the two kinds of replacements. Literal replacements take the form of know types, such as string, numbers, or dates. Object replacements are defined outside the snippet. The following is an example of both:

<Declarations>
   <Literal Editable="false">
      <ID>classname</ID>
      <ToolTip>Class name</ToolTip>
      <Function>ClassName()</Function>
      <Default>ClassNamePlaceholder</Default>
   </Literal>
   <Object>
      <ID>SqlConnection</ID>
      <Type>System.Data.SqlClient.SqlConnection</Type>
      <ToolTip>Replace with a connection object in your
               application.</ToolTip>
      <Default>dcConnection</Default>
   </Object>
</Declarations>

The attribute on the Literal element, Editable, determines whether or not you can edit the value of the literal once it is inserted. The default is True. The following are the other element descriptions:

  • Default (Required element): Specifies the literal's default value when you insert the code snippet. A Literal element must contain exactly one Default element.
  • Function (Optional element): Specifies a function to execute when the literal receives focus in Visual Studio. A Literal element may contain zero or one Function element.
  • ID (Required element): Specifies a unique identifier for the literal. A Literal element must contain exactly one ID element in a Literal element.
  • Tooltip (Optional element): Describes the expected value and usage of the literal. A Literal element may contain zero or one Tooltip elements.

The Function element has four functions available for pre-processing, and they can aid in returning some pretty interesting results. They are GenerateSwitchCases(EnumerationLiteral), ClassName(), SimpleTypeName(TypeName), and CallBase(Parameter). They each provide a unique result, which is worth exploring in greater detail. (My next article will dive deep into snippet functions.)

You now can look at the code element, which is where you will put your actual code, with the replacement variables to output your desired text. The code element has three attributes and no child elements. The attributes are kind, delimiter, and language. The delimiter, by default, is $. This character delimits literal and object variables in the snippet code text. The Language attribute, which is required, can be any of the following:

  • VB: Identifies a Visual Basic code snippet
  • CSharp: Identifies a Visual C# code snippet
  • VJSharp: Identifies a Visual J# code snippet
  • XML: Identifies an XML code snippet

This identifies the code snippet's language. The actual code element is text data that is surrounded by CDATA, so that it is taken as a literal string inside the element. The following is the code element from the ctor.snippet:

<Code Language="csharp"><![CDATA[public $classname$ ()
   {
      $end$
   }]]>
</Code>

So, if you look at the output of the snippet, you can pretty easily follow along with what the IDE is generating and why:

public Test()
{
}
  1. The attribute language specifies that it is C#.
  2. The code element begins with the CDATA escape, and then the word public.
  3. The replacement variable $classname$ is the result of the function ClassName, and then comes the two parentheses after the class name. As you can see, the placement is in the same location, based on the location of the cursor. This will also be affected by the options that are set in Visual Studio 2005 for C# formatting.
  4. The next line has the open bracket, followed by $end$ on the next line, and then the closing bracket. The $end$ is one of a set of predefined Literals variables. It is used to indicate the end of a line or statement. When the user presses ENTER to finish editing the code snippet fields, this variable determines where to move the caret (^).

Time to Make Your Own

Now, you can create a real simple snippet that you can use in your own code. Because all of your code should have documentation, create a file header snippet that you can tailor to your own needs. Then, you can extend it with another snippet for when you make changes to the file.

Figure 10 shows the output you want to get with your code snippet.

[Snip10.jpg]

Figure 10: Desired Output from Your Code Snippet

I have defined four Literal variables that will replace strings in the above template. Classname will be the prefix to the file name. The Author will be replaced by the $author$ Literal variable. The $date$ variable will replace the create date and the history date, and the $company$ Literal will replace Developer.com. Figure 11 shows the final XML snippet file.

[Snip11.jpg]

Figure 11: The Final XML Snippet File

You can use this new snippet with just a few clicks of the mouse. Start by loading the Snippet Manager (see Figure 12).

[Snip12.jpg]

Figure 12: Load the Snippet Manager

Highlight "My Code Snippets" and click the Import button. Navigate to the location where you saved the header.snippet file and select open (see Figure 13).

[Snip13.jpg]

Figure 13: Navigate to the header.snippet File and Select Open

Introducing Visual Studio 2005 IntelliSense Code Snippets

On the left side of the dialog window, click the checkbox next to "My Code Snippets" and click the Finish button (see Figure 14).

[Snip14.jpg]

Figure 14: Click the Checkbox Next to "My Code Snippets" and Click Finish

You now can open the "My Code Snippets" node and highlight the c3header snippet (see Figure 15). This will show some of the general attributes that you assigned to the snippet in the XML file.

[Snip15.jpg]

Figure 15: Open the "My Code Snippets" Node and Highlight the c3header Snippet

Now, you can go to a C# class file and test out your new snippet. Figure 16 shows the output.

[Snip16.jpg]

Figure 16: Output from Testing Out Your New Snippet

It may not seem like a lot, but the fact that you can type the shortcut and insert your own header is only the beginning of what you will be able to do.

Even though that was not a lot of steps, the fact that you dealt with raw XML might be a little more than you want to handle. So, the next two sections show you how I mass-produce my snippets, as well as an open source project that allows you to create and test your snippets.

Snippet Macro

I found myself creating code snippets for a lot of the same methods that I was overriding. So, I created a Visual Studio Macro to create a snippet out of the code that I selected. Download the macro and the test project. Load the macro in Visual Studio, and then highlight the code out of which you want to create a snippet (see Figure 17).

[Snip17.jpg]

Figure 17: Highlight the Code Out of Which You Want to Create a Snippet

From the macro explorer, double-click the CreateSnippet macro (see Figure 18).

[Snip18.jpg]

Figure 18: Double Click the CreateSnippet Macro

The screen will wiggle, and then you will have the output in a new file in the solution explorer. The file content from what you selected above will look like Figure 19.

[Snip19.jpg]

Figure 19: The File Content from Your Selections

It's still a little raw, but you should be able to create your own templates to help generate snippets pretty quickly.

Visual Basic Code Snippet Editor

The open source project I mentioned at the end of the previous section is the Visual Basic Code Snippet Editor, a tool that enables you to create, edit, and test your code snippets. Take the time to download the Visual Studio 2005 edition from the GotDotNet Workspace. The enhancements from the Beta 2 version are well worth it. It is still not completed, but the team working on this is doing a great job. Figure 20 shows a screen shot.

[Snip20.jpg]

Figure 20: Screenshot of Visual Basic Code Snippet Editor

Your Own Snippet Library

Take the Visual Basic Code Snippet Editor for a spin and try some of the tips in this article and the Visual Studio 2005 BOL. You will have a nice library of your own snippets in no time. I hope this tutorial gets you to explore the new features of IntelliSense code snippet technology in Visual Studio 2005.



About the Author

Patrick Gallucci

Patrick Gallucci is a Senior Consultant in the Communications Sector at Microsoft. He has more than thirteen years experience in information technology. Patrick's area of focus is developing operational efficiencies using development tools and technologies such as .NET, SQL Server, BizTalk Server, Content Management Server, and Commerce Server. His certifications include MCSE, MCDBA, and MCT. Patrick is a recent instructor of MSF Design, Microsoft C#, ASP.NET, and other .NET classes.

Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds