Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
[*.cs]
csharp_style_prefer_primary_constructors = false
dotnet_style_prefer_collection_expression = false
csharp_indent_braces = false
csharp_new_line_before_open_brace = all

# ReSharper properties
resharper_align_multiline_binary_expressions_chain = false
resharper_braces_for_foreach = required
resharper_braces_for_ifelse = required
resharper_braces_for_while = required
resharper_braces_redundant = true
resharper_csharp_keep_blank_lines_in_code = 1
resharper_csharp_keep_blank_lines_in_declarations = 1
resharper_csharp_wrap_before_binary_opsign = true
resharper_csharp_wrap_parameters_style = chop_if_long
resharper_max_attribute_length_for_same_line = 60
resharper_method_or_operator_body = expression_body
resharper_place_single_method_argument_lambda_on_same_line = false
resharper_wrap_after_declaration_lpar = true
resharper_wrap_after_invocation_lpar = true
resharper_wrap_chained_binary_expressions = chop_if_long

# Microsoft .NET properties
csharp_prefer_braces = true:none
6 changes: 6 additions & 0 deletions CodeMe.ScaffoldCS.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@
<s:Boolean x:Key="/Default/CodeStyle/CodeCleanup/CleanupOnSave/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=Cleanup_0020on_0020Save/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="Cleanup on Save"&gt;&lt;CSCodeStyleAttributes ArrangeVarStyle="True" ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" ArrangeAccessors="True" RemoveRedundantParentheses="True" AddMissingParentheses="True" ArrangeAttributes="True" ArrangeCodeBodyStyle="True" ArrangeTrailingCommas="True" ArrangeObjectCreation="True" ArrangeDefaultValue="True" ArrangeEmptyString="True" ArrangeNamespaces="True" ArrangeNullCheckingPattern="True" ArrangeBraces="True" /&gt;&lt;CSArrangeQualifiers&gt;True&lt;/CSArrangeQualifiers&gt;&lt;CSFixBuiltinTypeReferences&gt;True&lt;/CSFixBuiltinTypeReferences&gt;&lt;XMLReformatCode&gt;True&lt;/XMLReformatCode&gt;&lt;CSMakeFieldReadonly&gt;True&lt;/CSMakeFieldReadonly&gt;&lt;CSMakeAutoPropertyGetOnly&gt;True&lt;/CSMakeAutoPropertyGetOnly&gt;&lt;CSOptimizeUsings&gt;&lt;OptimizeUsings&gt;True&lt;/OptimizeUsings&gt;&lt;/CSOptimizeUsings&gt;&lt;CSShortenReferences&gt;True&lt;/CSShortenReferences&gt;&lt;CSReformatCode&gt;True&lt;/CSReformatCode&gt;&lt;CSharpFormatDocComments&gt;True&lt;/CSharpFormatDocComments&gt;&lt;CSharpReformatComments&gt;True&lt;/CSharpReformatComments&gt;&lt;XAMLCollapseEmptyTags&gt;False&lt;/XAMLCollapseEmptyTags&gt;&lt;RemoveCodeRedundancies&gt;True&lt;/RemoveCodeRedundancies&gt;&lt;/Profile&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_RAW_LITERAL_STRING/@EntryValue">DO_NOT_CHANGE</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INT_ALIGN_FIX_IN_ADJACENT/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/XmlDocFormatter/IndentTagContent/@EntryValue">ZeroIndent</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/XmlDocFormatter/TagSpaceBeforeHeaderEnd1/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=15b5b1f1_002D457c_002D4ca6_002Db278_002D5615aedc07d3/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="_" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EUnitTestFramework_002EMigrations_002EEnableDisabledProvidersMigration/@EntryIndexedValue">True</s:Boolean>

</wpf:ResourceDictionary>
2 changes: 2 additions & 0 deletions CodeMe.ScaffoldCS.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
<Project Path="env/env.csproj" />
</Folder>
<Folder Name="/src/">
<Project Path="src/CodeMe.ScaffoldCS.Templates/CodeMe.ScaffoldCS.Templates.csproj" />
<Project Path="src/CodeMe.ScaffoldCS/CodeMe.ScaffoldCS.csproj" />
</Folder>
<Folder Name="/tests/">
<Project Path="tests/CodeMe.ScaffoldCS.Templates.UnitTests/CodeMe.ScaffoldCS.Templates.UnitTests.csproj" Id="530fdd6f-e3f6-46b3-bdd8-110ee57c9ca7" />
<Project Path="tests/CodeMe.ScaffoldCS.UnitTests/CodeMe.ScaffoldCS.UnitTests.csproj" />
</Folder>
</Solution>
3 changes: 2 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="AwesomeAssertions" Version="9.5.0" />
<PackageVersion Include="CodeMe.Basics" Version="0.0.3" />
<PackageVersion Include="Microsoft.Testing.Extensions.TrxReport" Version="2.3.3" />
<PackageVersion Include="xunit.v3.mtp-v2" Version="3.2.2" />
<PackageVersion Include="xunit.v3.mtp-v2" Version="4.0.1" />
</ItemGroup>
</Project>
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,32 @@
# CodeMe.ScaffoldCS
Scaffolding framework inspired by CodegenCS

# Template issues

Have a good scenarios:
* Last line behavior (last line is empty)
* May be fixed if we keep endline in the current line and trim endline on close
(last line behavior)
* Will also fix inconsistency with delayed flush on MacOS ('\r' separator)
* Consider to split Template and advanced rendering logic. The goal is to have api that allows to add third-party rendering customisation
* Add api for column-level padding. Func to PaddedTemplatePart?
* Need both options.
* Split template / text writer options

Waits for grooming:
* Value handling customizations. Interceptors?
* We need a really good scenario for it. With naive implementation interceptors will slow down each write operation so lets keep it on hold.
* Review behaviors for `// {SummaryWithNewLineAtTheEnd} something` render scenario. Something like NextLineIndentation or EnforceIndentation() maybe?
* Shall we append indentation on whitespace-only lines?
* Do we need "append indentation on empty lines" option?
* Add support for alignment arg for multiline values?
* Need a good scenario for this. We have auto-indentation for this
* Multiline value nahdling.
* Add option for Template to disable multiline indentation. Add .RenderLiteral() / .RenderMultiline()
* Or just add .RenderLiteral() and no option

Delayed:
* Docs are missing
* No XML comments

# Metamodel issues
9 changes: 9 additions & 0 deletions docs/TemplateRender.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Summary

Render logic is based on c# [interpolated dtring handler](https://learn.microsoft.com/en-us/dotnet/csharp/advanced-topics/performance/interpolated-string-handler) feature.

Also, we use ambient template context (based on [ScopedAsyncLocal&lt;T&gt;](https://github.com/ig-sinicyn/CodeMe/tree/master/docs/Basics/AsyncLocal)) to ease passing of the current writer to the nested parts.

We do support conditional evaluation by IIF/IF-ELSE-ENDIF macro.

We do support conditional line trim by RL (RemoveLine macro)
14 changes: 14 additions & 0 deletions src/CodeMe.ScaffoldCS.Templates/CodeMe.ScaffoldCS.Templates.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">


<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Description>Template render engine inspired by CodegenCS</Description>
<PackageTags>Scaffolld;Template;Codegen;Code Generation</PackageTags>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CodeMe.Basics" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace CodeMe.ScaffoldCS.Templates.Infrastructure;

internal static class CharSpanExtensions
{
public static int NextIndexOfAny(
this ReadOnlySpan<char> span,
int startIndex,
char value0,
char value1)
{
var index = span[startIndex..].IndexOfAny(value0, value1);
return index < 0 ? index : startIndex + index;
}

public static bool IsMultiline(this ReadOnlySpan<char> span)
{
var index = span.IndexOfAny('\r', '\n');
return index >= 0;
}
}
16 changes: 16 additions & 0 deletions src/CodeMe.ScaffoldCS.Templates/Internals/AmbientTemplate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using CodeMe.Basics.Threading;

namespace CodeMe.ScaffoldCS.Templates.Internals;

public static class AmbientTemplate
{
private static readonly ScopedAsyncLocal<Template> _templateStack = new();

internal static IDisposable BeginTemplateScope(Template context) => _templateStack.BeginScope(context);

public static Template Current => _templateStack.Current
?? throw new InvalidOperationException(
$"There is no ambient template. Call {nameof(Template)}.{nameof(Template.BeginAmbientScope)} to enable ambient templates");

public static Template? CurrentOrDefault => _templateStack.Current;
}
9 changes: 9 additions & 0 deletions src/CodeMe.ScaffoldCS.Templates/Internals/ConditionBranch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace CodeMe.ScaffoldCS.Templates.Internals;

public enum ConditionBranch
{
None,
IfBranch,
ElseIfBranch,
ElseBranch
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace CodeMe.ScaffoldCS.Templates.Internals;

public interface IControlTemplateSymbol : ITemplateSymbol
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace CodeMe.ScaffoldCS.Templates.Internals;

public interface ITemplateScope
{
void DisposeIfSame(Template caller);
}
24 changes: 24 additions & 0 deletions src/CodeMe.ScaffoldCS.Templates/Internals/ITemplatePart.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace CodeMe.ScaffoldCS.Templates.Internals;

public interface ITemplatePart : ITemplateScope
{
void AppendLiteral(string? value);

void AppendFormatted<T>(T? value);

void AppendFormatted<T>(T? value, int alignment);

void AppendFormatted<T>(T? value, int alignment, string? format);

void AppendFormatted<T>(T? value, string? format);

void AppendFormatted(string? value);

void AppendFormatted(string? value, int alignment);

void AppendFormatted(Action<Template> callback);

void AppendFormatted(Func<TemplatePart> callback);

void AppendFormatted<T>(IEnumerable<T> values);
}
6 changes: 6 additions & 0 deletions src/CodeMe.ScaffoldCS.Templates/Internals/ITemplateSymbol.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace CodeMe.ScaffoldCS.Templates.Internals;

public interface ITemplateSymbol
{
void Render(Template template);
}
12 changes: 12 additions & 0 deletions src/CodeMe.ScaffoldCS.Templates/Output/CurrentLineHandlingMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace CodeMe.ScaffoldCS.Templates.Output;

public enum CurrentLineHandlingMode
{
Normal,

IgnoreIfEmpty,

IgnoreIfWhiteSpace,

Ignore
}
14 changes: 14 additions & 0 deletions src/CodeMe.ScaffoldCS.Templates/Output/CurrentLineState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace CodeMe.ScaffoldCS.Templates.Output;

internal enum CurrentLineState
{
Empty,

ValueAppended,

CrAppended,

LfAppended,

Closed
}
14 changes: 14 additions & 0 deletions src/CodeMe.ScaffoldCS.Templates/Output/IndentationFormat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace CodeMe.ScaffoldCS.Templates.Output;

public enum IndentationFormat
{
CurrentLine,

CurrentLineWhitespace,

CurrentIndentation,

IncreasedIndentation,

Empty
}
12 changes: 12 additions & 0 deletions src/CodeMe.ScaffoldCS.Templates/Output/NewLineFormat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace CodeMe.ScaffoldCS.Templates.Output;

public enum NewLineFormat
{
Auto,

CrLf,

Lf,

Cr
}
Loading
Loading