diff --git a/Example.Shared/Example.Shared.csproj b/Example.Shared/Example.Shared.csproj
index 40a196f..f727333 100644
--- a/Example.Shared/Example.Shared.csproj
+++ b/Example.Shared/Example.Shared.csproj
@@ -7,10 +7,14 @@
-
+
+
+
+
+
diff --git a/mROA.Codegen/Tools/DefineTemplateSection.cs b/mROA.Codegen/Tools/DefineTemplateSection.cs
new file mode 100644
index 0000000..31eadb7
--- /dev/null
+++ b/mROA.Codegen/Tools/DefineTemplateSection.cs
@@ -0,0 +1,30 @@
+namespace mROA.CodegenTools
+{
+ public class DefineTemplateSection : ITagged
+ {
+ public DefineTemplateSection(string storedText, string tag, TemplateDocument context)
+ {
+ StoredText = storedText;
+ Tag = tag;
+ Context = context;
+ }
+
+ public string StoredText { get; }
+ public TemplateDocument Context { get; set; }
+
+ public string Tag { get; }
+
+ public int TargetLength => StoredText.Length;
+
+ public object Clone()
+ {
+ return new DefineTemplateSection(StoredText, Tag, Context);
+ }
+
+
+ public override string ToString()
+ {
+ return StoredText;
+ }
+ }
+}
\ No newline at end of file
diff --git a/mROA.Codegen/Tools/ITemplateSection.cs b/mROA.Codegen/Tools/ITemplateSection.cs
new file mode 100644
index 0000000..cf7d34c
--- /dev/null
+++ b/mROA.Codegen/Tools/ITemplateSection.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace mROA.CodegenTools
+{
+ public interface ITemplateSection : ICloneable
+ {
+ TemplateDocument Context { get; set; }
+ int TargetLength { get; }
+ }
+
+ public interface IBaking
+ {
+ string Bake();
+ }
+
+ public interface ITagged : ITemplateSection
+ {
+ string Tag { get; }
+ }
+}
\ No newline at end of file
diff --git a/mROA.Codegen/Tools/InnerTemplateSection.cs b/mROA.Codegen/Tools/InnerTemplateSection.cs
new file mode 100644
index 0000000..1a6d5f7
--- /dev/null
+++ b/mROA.Codegen/Tools/InnerTemplateSection.cs
@@ -0,0 +1,24 @@
+namespace mROA.CodegenTools
+{
+ public class InnerTemplateSection : ITemplateSection, ITagged
+ {
+ public InnerTemplateSection(string tag, TemplateDocument innerTemplate, TemplateDocument context)
+ {
+ Tag = tag;
+ Context = context;
+ InnerTemplate = innerTemplate;
+ }
+
+ public TemplateDocument InnerTemplate { get; }
+
+ public string Tag { get; }
+
+ public TemplateDocument Context { get; set; }
+ public int TargetLength => 0;
+
+ public object Clone()
+ {
+ return new InnerTemplateSection(Tag, InnerTemplate, Context);
+ }
+ }
+}
\ No newline at end of file
diff --git a/mROA.Codegen/Tools/InsertTemplateSection.cs b/mROA.Codegen/Tools/InsertTemplateSection.cs
new file mode 100644
index 0000000..e47cd50
--- /dev/null
+++ b/mROA.Codegen/Tools/InsertTemplateSection.cs
@@ -0,0 +1,86 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace mROA.CodegenTools
+{
+ public class InsertTemplateSection : ITagged, IBaking
+ {
+ public readonly List Parameters;
+ private object _insertedValue;
+
+ public InsertTemplateSection(string tag, TemplateDocument context, params string[] parameters)
+ {
+ Tag = tag;
+ Parameters = parameters.ToList();
+ Context = context;
+ }
+
+ public string Bake()
+ {
+ switch (_insertedValue)
+ {
+ case null:
+ return string.Empty;
+ case string s:
+ return s;
+ default:
+ return ((ITemplateSection)_insertedValue).ToString();
+ }
+ }
+
+ public string Tag { get; private set; }
+
+ public TemplateDocument Context { get; set; }
+
+
+ public int TargetLength => 0;
+
+ public object Clone()
+ {
+ return new InsertTemplateSection(Tag, Context, Parameters.ToArray());
+ }
+
+ private bool IsInserted(object value)
+ {
+ if (Parameters.IndexOf("r") == -1) return false;
+
+ ProduceInserted(value);
+
+ return true;
+ }
+
+ private void ProduceInserted(object value)
+ {
+ var currentIndex = Context.Parts.IndexOf(this);
+ var clone = (InsertTemplateSection)MemberwiseClone();
+ clone.Tag += "+";
+
+ clone._insertedValue = value;
+
+ Context.Parts.Insert(currentIndex, clone);
+
+ InsertSeparator(currentIndex + 1);
+ }
+
+ private void InsertSeparator(int currentIndex)
+ {
+ var sepIndex = Parameters.IndexOf("sep");
+ if (sepIndex == -1)
+ return;
+
+ Context.Parts.Insert(currentIndex,
+ new LiteralTemplateSection(Context[Parameters[sepIndex + 1]].ToString(), Context));
+ }
+
+
+ public void Setup(object value)
+ {
+ if (!(value is string) && !(value is ITemplateSection))
+ return;
+ if (IsInserted(value))
+ return;
+
+ _insertedValue = value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/mROA.Codegen/Tools/LinkTemplateSection.cs b/mROA.Codegen/Tools/LinkTemplateSection.cs
new file mode 100644
index 0000000..45f58c6
--- /dev/null
+++ b/mROA.Codegen/Tools/LinkTemplateSection.cs
@@ -0,0 +1,39 @@
+namespace mROA.CodegenTools
+{
+ public class LinkTemplateSection : ITemplateSection, IBaking
+ {
+ public LinkTemplateSection(string linkedTag, TemplateDocument context)
+ {
+ LinkedTag = linkedTag;
+ Context = context;
+ }
+
+ public string LinkedTag { get; }
+
+ public string Bake()
+ {
+ return Context[LinkedTag]?.ToString();
+ }
+
+ public TemplateDocument Context { get; set; }
+
+ public int TargetLength
+ {
+ get
+ {
+ var attached = Context[LinkedTag];
+ return attached?.TargetLength ?? 0;
+ }
+ }
+
+ public object Clone()
+ {
+ return new LinkTemplateSection(LinkedTag, Context);
+ }
+
+ public override string ToString()
+ {
+ return $"{nameof(LinkedTag)}: {LinkedTag}";
+ }
+ }
+}
\ No newline at end of file
diff --git a/mROA.Codegen/Tools/LiteralTemplateSection.cs b/mROA.Codegen/Tools/LiteralTemplateSection.cs
new file mode 100644
index 0000000..45c2dec
--- /dev/null
+++ b/mROA.Codegen/Tools/LiteralTemplateSection.cs
@@ -0,0 +1,31 @@
+namespace mROA.CodegenTools
+{
+ public class LiteralTemplateSection : ITemplateSection, IBaking
+ {
+ private readonly string _internalText;
+
+ public LiteralTemplateSection(string internalText, TemplateDocument context)
+ {
+ _internalText = internalText;
+ Context = context;
+ }
+
+ public string Bake()
+ {
+ return ToString();
+ }
+
+ public TemplateDocument Context { get; set; }
+ public int TargetLength => _internalText.Length;
+
+ public object Clone()
+ {
+ return new LiteralTemplateSection(_internalText, Context);
+ }
+
+ public override string ToString()
+ {
+ return _internalText;
+ }
+ }
+}
\ No newline at end of file
diff --git a/mROA.Codegen/Tools/ProgrammableTextSection.cs b/mROA.Codegen/Tools/ProgrammableTextSection.cs
new file mode 100644
index 0000000..0e34391
--- /dev/null
+++ b/mROA.Codegen/Tools/ProgrammableTextSection.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace mROA.CodegenTools
+{
+ public class ProgrammableTextSection : ITemplateSection, IBaking
+ {
+ private readonly Func