Skip to content

Commit 3bad64a

Browse files
committed
Documentation and Unit Test to show how to break into debugger (debugging templates)
1 parent 44ed289 commit 3bad64a

File tree

5 files changed

+58
-2
lines changed

5 files changed

+58
-2
lines changed

README.md

+10
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,16 @@ class MyTemplate
10531053
}
10541054
```
10551055
1056+
## Debugging Support
1057+
1058+
It's possible to debug templates using Visual Studio.
1059+
To break into the debugger inside markup mode (interpolated string) you just have to interpolate `BREAKIF(true)`.
1060+
To break into the debugger inside programmatic mode (method) you just have to call `System.Diagnostics.Debugger.Break()` and disable `Tools - Debugging - General - Enable Just My Code`.
1061+
See example in
1062+
[Debugging.cs Unit Test](https://github.com/CodegenCS/CodegenCS/tree/master/src/Tools/Tests/Templates/0090-Debugging.cs).
1063+
1064+
1065+
10561066
# Learn More
10571067
10581068
- [CodegenTextWriter documentation](https://github.com/CodegenCS/CodegenCS/tree/master/docs/CodegenTextWriter.md)

src/Core/CodegenCS/Symbols.cs

+8
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,15 @@ public static Func<FormattableString> IIF(bool condition, Func<FormattableString
8888
//https://ttl255.com/jinja2-tutorial-part-3-whitespace-control/
8989

9090
#region Debugging
91+
// If you're debugging through visual studio (e.g. Unit Tests, or any other code going through CodegenTextWriter)
92+
// it can be difficult to debug through CodegenTextWriter because it writes interpolated strings element-by-element
93+
// If you want to brea in the debugger at any specific point inside an interpolated string (markup mode)
94+
// all you have to do is interpolate BREAKIF(true)
9195
public static Action BREAKIF(bool condition) => () => { if (condition) { System.Diagnostics.Debugger.Break(); } };
96+
97+
// If you want to break from inside a method in your template (programmatic mode)
98+
// then you can just use System.Diagnostics.Debugger.Break() and make sure you
99+
// disable "Tools - Debugging - General - Enable Just My Code", in order to break and see the template source code
92100
#endregion
93101
}
94102
}

src/Tools/TemplateBuilder/RoslynCompiler.cs

+8-2
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ public async Task<CompileResult> CompileAsync(string[] sources, string targetFil
230230
using (var dllStream = new MemoryStream())
231231
using (var pdbStream = new MemoryStream())
232232
{
233-
var emitResult = compilation.Emit(dllStream, pdbStream);
233+
var emitResult = compilation.Emit(dllStream, pdbStream); // roslyn throws a lot of exceptions, so "break on all exceptions" is not nice at this line
234234

235235
//TODO: combine all errors into a single statement,
236236
// since Powershell ISE stops at first stderr message when $ErrorActionPreference = "Stop"
@@ -343,7 +343,13 @@ void AddMissingUsings(List<SyntaxTree> trees)
343343
if (Regex.IsMatch(templateSource, @"(?<!\.)\bInvocationContext\b"))
344344
AddMissingUsing(ref rootNode, "System.CommandLine.Invocation");
345345

346-
if (Regex.IsMatch(templateSource, @"(?<!\.)\bIF\(\b") || Regex.IsMatch(templateSource, @"(?<!\.)\bIIF\(\b"))
346+
if (Regex.IsMatch(templateSource, @"(?<!\.)\bIF\(\b") ||
347+
Regex.IsMatch(templateSource, @"(?<!\.)\bIIF\(\b") ||
348+
Regex.IsMatch(templateSource, @"(?<!\.)\bBREAKIF\(\b") ||
349+
Regex.IsMatch(templateSource, @"(?<!\.)\bTLW\(\b") ||
350+
Regex.IsMatch(templateSource, @"(?<!\.)\bTTW\(\b") ||
351+
Regex.IsMatch(templateSource, @"(?<!\.)\bCOMMENT\(\b") ||
352+
Regex.IsMatch(templateSource, @"(?<!\.)\bRAW\(\b"))
347353
AddMissingUsing(ref rootNode, "CodegenCS.Symbols", true);
348354

349355
if (Regex.IsMatch(templateSource, @"(?<!\.)\bPREVIOUS_COLOR\b") || Regex.IsMatch(templateSource, @"(?<!\.)\bPREVIOUS_BACKGROUND_COLOR\b"))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// If you run TemplateBuildTests this is the only unit test that should break into the debugger
2+
// It's possible to break both inside MARKUP mode (interpolating a symbol) or in PROGRAMMATIC mode
3+
class MyTemplate
4+
{
5+
string[] groceries = new string[] { "Milk", "Eggs", "Diet Coke" };
6+
7+
// If you run this template using Visual Studio Unit Tests
8+
// it will break into the debugger when it reaches the BREAKIF(true)
9+
FormattableString Main() => $$"""
10+
I have to buy:
11+
{{BREAKIF(true)}}{{groceries}}
12+
Will write some more stuff
13+
{{MethodWithBreak}}
14+
""";
15+
16+
// If you want to break from inside a method in your template (programmatic mode)
17+
// then you can just use System.Diagnostics.Debugger.Break() and make sure you
18+
// disable "Tools - Debugging - General - Enable Just My Code", in order to break and see the template source code (because it's invoked using reflection so it's considered external code)
19+
void MethodWithBreak(ICodegenOutputFile file)
20+
{
21+
file.WriteLine("writing something here");
22+
System.Diagnostics.Debugger.Break();
23+
file.WriteLine("last part");
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
I have to buy:
2+
Milk
3+
Eggs
4+
Diet Coke
5+
Will write some more stuff
6+
writing something here
7+
last part

0 commit comments

Comments
 (0)