T4 templates - avoid empty lines from included files
Asked Answered
M

6

25

I am splitting T4 code in separate files for modularity and reuse but I am finding out that each file costs me an empty line in output. For example:

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".ttinclude" #>
<#@ Import Namespace="System.Collections.Generic" #>
<#@ Include file="Includes.tt" #>
namespace <#= NameSpace #>
{

If Includes.tt lists 3 other *.tt files, I get 3 blank lines before the namespace. As I am adding code and splitting it in separate *.tt files, this empty space keeps growing. In fact, I packed all the include files into a single Includes.tt, hoping that this will cost me just one empty line. It didn't. I still get one empty line per each file listed in Includes.tt. Is there a way of avoiding this?

Edit: assuming that I am not making just a dumb mistake (and I sincerely hope that I am), the problem is not as trivial as it may appear on the first sight:

a) Reuse and modularity via included T4 files is as old as T4 itself and was mentioned in latest MSDN Magazine article: "Managing Complexity in T4 Code-Generation Solutions".

b) If code is auto-generated, it doesn't mean that it is Ok for it to be badly formatted or poorly legible.

c) With the current solution, in my case, for each and every generated .cs file the reader would have to scroll for one empty page until she starts seeing some generated text. All because I have split my code generation between multiple included .tt files. That just doesn't seem right.

Mccabe answered 7/5, 2012 at 8:13 Comment(0)
M
17

Oh well, the solution turned out to be trivial, if somewhat unexpected : just put the include directives next to each other, instead of one below another :

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".ttinclude" #>
<#@ Import Namespace="System.Collections.Generic" #>
<#@ Include file="Usings.tt" #> <#@ Include file="PropertyTypeEnum.tt" #> <#@ Include.... 
Mccabe answered 8/5, 2012 at 2:4 Comment(4)
Hi Tony - this is a bit of a legacy from our early versions. We're now somewhat loathe to 'fix' it as that would break backwards compatibility for folks who've used the workaround. We've toyed with the idea of an opt-in flag, something like 'smarterParsing=true', but i"m not too keen to have to test two parsing codepaths at this point.Edp
The same trick works even with single Include - just make sure that there are no characters between closing tag of the include and the next instruction (be it literal or <# tag)Polio
The real reason is that every generated Template (it's cs code) has a \r\n in public virtual string TransformText() { this.Write(" \r\n");, so your answer is just working because the newline added by pressing return after each included template is omitted.Hanging
Is this a real issue though. I would have the T4 code more readable than the generated code, especially if its is just related to alan lines? or am I missing something?Gambrell
L
18

To add to Tony's answer: You can avoid the very long lines by adding the linebreaks within the T4 brackets like so:

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".ttinclude" #>
<#@ Import Namespace="System.Collections.Generic" #>
<#@ Include file="Usings.tt" 
#><#@ Include file="PropertyTypeEnum.tt" 
#><#@ Include....
#><#@ Include....
#><#@ Include....
#><#@ some other stuff 
Lam answered 8/11, 2013 at 14:2 Comment(1)
oooooh! that's what that is for. I learnt something new today. +1Pleasance
M
17

Oh well, the solution turned out to be trivial, if somewhat unexpected : just put the include directives next to each other, instead of one below another :

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".ttinclude" #>
<#@ Import Namespace="System.Collections.Generic" #>
<#@ Include file="Usings.tt" #> <#@ Include file="PropertyTypeEnum.tt" #> <#@ Include.... 
Mccabe answered 8/5, 2012 at 2:4 Comment(4)
Hi Tony - this is a bit of a legacy from our early versions. We're now somewhat loathe to 'fix' it as that would break backwards compatibility for folks who've used the workaround. We've toyed with the idea of an opt-in flag, something like 'smarterParsing=true', but i"m not too keen to have to test two parsing codepaths at this point.Edp
The same trick works even with single Include - just make sure that there are no characters between closing tag of the include and the next instruction (be it literal or <# tag)Polio
The real reason is that every generated Template (it's cs code) has a \r\n in public virtual string TransformText() { this.Write(" \r\n");, so your answer is just working because the newline added by pressing return after each included template is omitted.Hanging
Is this a real issue though. I would have the T4 code more readable than the generated code, especially if its is just related to alan lines? or am I missing something?Gambrell
W
15

This also works for me in VS 2013:

<#@ include file="Other.tt" #><##>

and so

<#@ include file="One.tt" #><##>
<#@ include file="Two.tt" #><##>
...

The <##> is just an empty control block. <# /* any code here */ #> works just as well.

Worrisome answered 27/9, 2014 at 16:28 Comment(0)
K
13

I had a more fundamental issue where each <#@ header line before <?xml caused its own blank line in the output, which caused the error:

error : Unexpected XML declaration.
        The XML declaration must be the first node in the document,
        and no white space characters are allowed to appear before it.
        Line 7, position 3.

After digging for a while I discovered the .tt file had Unix EOL.

When I switched to Windows EOL, the transform removed the blank lines.

Kerry answered 6/9, 2014 at 17:48 Comment(4)
Got this one today :) Thanks for writing the answer!Gigot
I pasted code with Unix EOL. Windows EOL don't generate empty lines from included files. Thanks!Halophyte
You made my day. Thanks.Craver
Wow, subtle behaviour, thanks heaps! A killer in plaintext email templates...Izolaiztaccihuatl
M
5

In my case the blank lines resulted from a trailing space after the closing tag of import statements.

Musso answered 1/9, 2016 at 12:7 Comment(2)
Encountered the blank line problem in July 2017 and trailing spaces on the import statement lines was the reason.Phospholipide
I can confirm that trailing space after closing import tags was the reason for blank lines in Visual Studio 2019 as well.Stentorian
M
1

For me the problem occured when using Unix line endings (LF). Using Windows line endings (CR LF) resolved my problem and may resolve yours.

Mobster answered 9/6, 2020 at 13:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.