Pieter Müller
Pieter Müller

Reputation: 4693

Inserting T4 generated code as if it's a snippet

I'm looking for a way to quickly and routinely add my signature and the date to the top of new code files in Visual Studio.

There are some tutorials on using Macros to do this, but apparently Macros are no longer supported in VS2012.

I can define the header as a code snippet and insert the snippet, but snippets don't support getting the current date.

I can generate the correct text with the following T4 template:

<#@ template debug="false" hostspecific="false" language="C#" #>

// <author>Pieter Müller</author>
// <date><#=DateTime.Now.ToString("yyyy-MM-dd")#></date>

<#@ output extension=".cs" #>

This gives me the following result, which is perfect:

// <author>Pieter Müller</author>
// <date>2012-10-30</date>

The question is, is there a way for me to quickly and routinely insert this code into new code files, either automatically or manually using something similiar to Insert Snippet or a shortcut key?

If you don't have an answer, but you do have a good idea on generating the signature headers I need, please leave a comment. Thanks!

Upvotes: 2

Views: 1574

Answers (2)

Pieter M&#252;ller
Pieter M&#252;ller

Reputation: 4693

I hate to be answering my own question, but I did come up with a way to have T4 templates as snippets, although its Hack Level is over 9000. It works by writing a T4 template that generates a snippet, which it then automatically copies to the Visual Studio snippet folder.

  • Add a Text Template item to your project.

  • Set it up to build a snippet, that in turn builds the code you want to insert. For the example in my question, the snippet XML that you want to generate with the T4 template looks like this:

    <?xml version="1.0" encoding="utf-8"?>
    <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
      <CodeSnippet Format="1.0.0">
        <Header>
          <SnippetTypes>
            <SnippetType>Expansion</SnippetType>
          </SnippetTypes>
          <Title>DateHeaderSnippet</Title>
          <Author>user</Author>
        </Header>
        <Snippet>
          <Code Language="csharp">
            <![CDATA[//    <author>Pieter Muller</author>
    //    <date>{Today's Date}</date>]]>
          </Code>
        </Snippet>
      </CodeSnippet>
    </CodeSnippets>
    
    • To generate the above XML with a T4 template, we can insert the XML almost verbatim, with two changes. Firstly, this line:

      <?xml version="1.0" encoding="utf-8"?>
      

      must be inside a manual WriteLine statement, or the <?xml tag will confuse the T4 template processor:

      <# WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); #>
      
    • And secondly, we want to use the T4 processing to inject today's date into the snippet XML, so we change:

              <![CDATA[//    <author>Pieter Muller</author>
      //    <date>{Today's Date}</date>]]>
      

      to:

              <![CDATA[//    <author>Pieter Muller2</author>
      //    <date><#=DateTime.Now.ToString("yyyy-MM-dd")#></date>]]>
      
  • We also add some very hacky code to the end of the T4 template, that mannually reads the output file and writes it to a snippet file. The hacky part of this is that we have to specify absolute paths. The complete T4 code looks like this:

    <#@ template debug="false" hostspecific="false" language="C#" #>
    <#@ output extension=".txt" #>
    <# WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>"); #>
    <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
      <CodeSnippet Format="1.0.0">
        <Header>
          <SnippetTypes>
            <SnippetType>Expansion</SnippetType>
          </SnippetTypes>
          <Title>DateHeaderSnippet</Title>
          <Author>user</Author>
        </Header>
        <Snippet>
          <Code Language="csharp">
            <![CDATA[//    <author>Pieter Muller2</author>
    //    <date><#=DateTime.Now.ToString("yyyy-MM-dd")#></date>]]>
          </Code>
        </Snippet>
      </CodeSnippet>
    </CodeSnippets>
    <#    
        System.IO.StreamReader sr = new System.IO.StreamReader(@"C:\Users\Pieter\Documents\Visual Studio 2010\Projects\tmp\tmp\TextTemplateToWriteHeaderTemplate.txt");
        string sourceText = sr.ReadToEnd();
        sr.Close();
    
        System.IO.StreamWriter sw = new System.IO.StreamWriter(@"C:\Users\Pieter\Documents\Visual Studio 2010\Code Snippets\Visual C#\My Code Snippets\tryout.snippet");    
        sw.WriteLine(sourceText);    
        sw.Close();    
    #>
    
  • You'll have to compile the T4 template twice - the first run generates the snippet code, and the second run writes the previous run's output to the snippet folder. To do this, right click on the template in the Solution Explorer and click Run Custom Tool.

  • Now you can right click anywhere in code, select Insert Snippet... and select the generated snippet from the My Code Snippets group. The result:

    //    <author>Pieter Muller2</author>
    //    <date>2012-11-09</date>
    

I know this is way too much trouble to go through just to insert a simple author and date header, but hopefully someone else can use this technique for something more grandiose. You can put pretty much generate any kind of dynamic snippet this way.

Upvotes: 3

Ilya Ivanov
Ilya Ivanov

Reputation: 23626

Hope you are using ReSharper, which has powerful templates. I've implemented your example using very simple configuration for template variables enter image description here

Now if I enter 'hd' and press tab this macro I will receive next result: enter image description here enter image description here

Upvotes: 2

Related Questions