In April, I posted a summary of the syntax for the code generation engine supplied with the DSL Tools March CTP.
As we've now released our May CTP based on Visual Studio 2005 Beta 2, it seems it's time to update that post for our new text templating syntax.
Note that the file extensions for templates have all changed in the May 2005 CTP.
Templates consist of some directives followed by a mixture of literal blocks and control blocks. Literal blocks are just plain text in the template that you want to pass straight through to the output. Control blocks are things with some kind of <# #> marker around them.
The content of these blocks in your template contributes to a class which the templating system generates. This class derives from the abstract class Microsoft.VisualStudio.TextTemplating.TextTransformation and overrides the abstract method TransformText which, when executed, writes out the desired output of the transformation of the template. If you do nothing else in your template, this method will write out all of the text in literal blocks by simply writing out the raw text using a simple WriteLine()-style statement. The base class provides this WriteLine method (in various flavors) as well as Error and Warning methods that you can use in your custom template code.
You can add three types of control block in this release:
<# #> - Regular control block
Embeds some control code in the TransformText method.
Regular control blocks affect the literal blocks that they surround by means of the flow of control within them. This happens because the regular blocks' code is written verbatim into the TransformText method. So if you have a regular block that begins a for loop that loops five times, then have a literal block, then have another regular block that closes the for loop, you'll get the contents of the literal block written into the final output text five times. You'd typically use some expression blocks inside this loop to do something interesting with the loop variable. You can put anything in a regular block that you can put in the body of an overriden virtual method.
<#= #> - Expression control block
Embeds the value of a C# or VB.Net expression.
The expression will automatically have .ToString() appended to it (with the template's culture, if provided).
<#+ #> - Class features control block
Embeds control code at the TextTransformation-derived class scope.
This block allows you to add new methods, fields, properties, embedded classes etc. to the class derived from TextTransformation. You can then use these from regular and expression control blocks.
Trying to write all of your control code inside one method can be tiresome if you have a big model to traverse - especially if the model has a recursive structure like a tree in it. Class features blocks allow you to add further methods to the class to make this sort of thing easier and to structure your control code well. You can add anything that you'd find contained within a class in a class features block.
Directives have two purposes,
a) they provide instructions to the templating engine,
b) they inject code into the TextTemplating-derived class that performs the transformation process.
Their syntax is:
<#@ directiveName parameter="Value" #>
There is also more rich form of this which is commonly used:
<#@ directiveName parameter1="Argument1[='Value1'][;Argument2[=Value2]]" parameter2="Argument1[=Value1][;Argument2[='Value2']]" #>
This latter form enables more complex parameter lists to be passed to a directive processor while still conforming to the simpler syntax.
There are a number of directives built-in to the engine. Additionally, custom directives are created to tailor the text templating process for a specific application. A good example of this tailoring is that we provide custom directive processors to read model files into memory and make their content available for manipulation by code in control blocks within templates.
<#@ template inherits="MyNamespace.MyBaseClass" language="C#" culture="en-US" debug="false" hostspecific="false" #>
Specifies transformation options for this template:
The inherits parameter specified the base class to use for the generated TextTransformation class. The default is Microsoft.VisualStudio.TextTemplating.TextTransformation. A custom base class "Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation" is provided with the DSL Tools that works together with custom directive processors to make it easy to read in and process model files. Custom base classes must themselves ultimately be derived from Microsoft.VisualStudio.TextTemplating.TextTransformation.
The language parameter specifies which programming language is used in code inside control blocks. The supported languages are "VB" and "C#", where "VB" denotes Visual Basic.Net.
The culture parameter specifies which .Net culture is used to format the values evaluated from from expression control blocks. The standard .Net "xx-XX" specifier must be used.
The debug parameter leaves the code generated dynamically for the transformation process on disk rather than working wholly in memory. This can aid in debugging complex template issues. This code can be found in the logged-in user's temporary directory (typically <drive>:\Documents and Settings\<username>\Local Settings\Temp).
The hostspecific parameter specifies whether the application hosting the Text Transformation engine should make a reference to itself available to template control code. This can be useful in circumstances where the code executing as part of the template is intended to work with only a single host and to make use of facilities provided by that host. Do not set this value to true if you wish your templates to execute in multiple hosting environments, for example, inside Visual Studio and from the command-line template processor. Setting this value to true will contribute a property called "Host" to the TextTransformation-derived class. DSL Tools users would not usually use this parameter, as they are using a set of hosts provided by the DSL Tools themselves.
<#@ output extension=".cs" #>
Specify the extension of the file that gets generated.
<#@ assembly name="System.Drawing.dll" #>
Reference the assembly in compilation of control blocks.
<#@ import namespace="System.Collections" #>
Import the namespace in compilation of control blocks. (i.e. a C# using statement)
For .dsldmt templates:
<#@ include file="FileToInclude.dsldmi" #>
Include the content of the file "FileToInclude.dsldmi" either from the same directory as the template containing the include directive, or from the TextTemplates directory under the DSL Tools install point.
<#@ model processor="DMDirectiveProcessor" requires="fileName='UtilitiesModel.dsldm'" provides="Model=Model" #>
This custom directive processor loads the given domain model into memory and provides a reference to its root object in the property "Model" on TextTransformation-derived class.
Modifying the provides clause to say "Model=OtherPropertyName" would instead provide a property called OtherPropertyName.
For .dslddt templates:
<#@ include file="FileToInclude.dslddi" #>
Include the content of the file "FileToInclude.dslddi" either from the same directory as the template containing the include directive, or from the TextTemplates directory under the DSL Tools install point.
<#@ definition processor="DDDirectiveProcessor" requires="fileName='..\\SimpleArchitectureChart.dsldd'" provides="Definition=Definition" #>
This custom directive processor loads the given designer definition into memory and provides a reference to its root object in the property "Definition" on the TextTransformation-derived class.
Modifying the provides clause to say "Definition=OtherPropertyName" would instead provide a property called OtherPropertyName.
Occasionally, it is necessary to escape the syntax of the text templates (for example, to create a template that itself generates another template for later transformation). The syntax to accomplish this is as follows:
Also, it may be necessary to escape a quotation character within a directive. This can be achieved with the following syntax:
<#@ directive argument="BeforeQuote\"AfterQuote" #>
Binding to Visual Studio
There are several programmatic ways to access the Text Templating engine. However, inside Visual Studio, the current method of choice is to use the established CustomTool mechanism.
On any file that you want treated as a text template, select it in the Solution Explorer and in the Properties Grid, modify the Custom Tool entry to say "TextTemplatingFileGenerator". The output of the template will then be rendered as a dependent file underneath the template file.
Running templates in batch mode
A batch-mode command-line processor for templates is provided. The executable is called VsTextTransform.exe.