Skip to content

Commit

Permalink
Merge pull request #10 from BastianBlokland/feature/bracket-mode
Browse files Browse the repository at this point in the history
Same line curly-brackets.
  • Loading branch information
BastianBlokland authored Jul 6, 2019
2 parents 49b4b27 + aa19599 commit 40308ac
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 27 deletions.
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>
<!-- Major.Minor adjust manually -->
<PropertyGroup>
<VersionPrefix>2.0</VersionPrefix>
<VersionPrefix>2.1</VersionPrefix>
</PropertyGroup>

<!-- Automatically set suffix info based on environment args (if availble) -->
Expand Down
12 changes: 10 additions & 2 deletions src/EnumGenerator.Cli/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public Application(ILogger<Application> logger)
/// <param name="indentSize">When indenting with spaces this controls how many</param>
/// <param name="newlineMode">Mode to use when adding newlines to text</param>
/// <param name="storageType">Storage type for the exported enum</param>
/// <param name="curlyBracketMode">Mode to use when writing curly-brackets</param>
/// <returns>Exit code</returns>
public int Run(
string inputFile,
Expand All @@ -69,7 +70,8 @@ public int Run(
CodeBuilder.IndentMode indentMode,
int indentSize,
CodeBuilder.NewlineMode newlineMode,
Core.Exporter.StorageType storageType)
Core.Exporter.StorageType storageType,
Core.Exporter.CurlyBracketMode curlyBracketMode)
{
if (string.IsNullOrEmpty(inputFile))
throw new ArgumentException($"Invalid path: '{inputFile}'", nameof(inputFile));
Expand Down Expand Up @@ -125,7 +127,13 @@ public int Run(
string csharp = null;
try
{
csharp = enumDefinition.Export(enumNamespace, indentMode, indentSize, newlineMode, storageType);
csharp = enumDefinition.Export(
enumNamespace,
indentMode,
indentSize,
newlineMode,
storageType,
curlyBracketMode);
}
catch (Exception e)
{
Expand Down
3 changes: 2 additions & 1 deletion src/EnumGenerator.Cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ public static int MainWithOptions(ProgramOptions options)
options.IndentMode,
options.IndentSize,
options.NewlineMode,
options.StorageType);
options.StorageType,
options.CurlyBracketMode);
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/EnumGenerator.Cli/ProgramOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ public static IEnumerable<Example> Examples
[Option("storagetype", Required = false, Default = Core.Exporter.StorageType.Implicit, HelpText = "Underlying storage type for the exported enum")]
public Core.Exporter.StorageType StorageType { get; set; }

/// <summary>Mode to use when writing curly-brackets</summary>
[Option("curlybracket", Required = false, Default = Core.Exporter.CurlyBracketMode.NewLine, HelpText = "Which curlybracket-mode to use")]
public Core.Exporter.CurlyBracketMode CurlyBracketMode { get; set; }

/// <summary>Switch to enable verbose logging</summary>
[Option('v', "verbose", Required = false, HelpText = "Enable verbose output")]
public bool Verbose { get; set; }
Expand Down
59 changes: 44 additions & 15 deletions src/EnumGenerator.Core/Exporter/CSharpExporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ public static class CSharpExporter
/// <param name="spaceIndentSize">When indenting with spaces this controls how many</param>
/// <param name="newlineMode">Mode to use for ending lines</param>
/// <param name="storageType">Underlying enum storage-type to use</param>
/// <param name="curlyBracketMode">Mode to use when writing curly brackets</param>
/// <returns>String containing the genenerated c# sourcecode</returns>
public static string Export(
this EnumDefinition enumDefinition,
string @namespace = null,
CodeBuilder.IndentMode indentMode = CodeBuilder.IndentMode.Spaces,
int spaceIndentSize = 4,
CodeBuilder.NewlineMode newlineMode = CodeBuilder.NewlineMode.Unix,
StorageType storageType = StorageType.Implicit)
StorageType storageType = StorageType.Implicit,
CurlyBracketMode curlyBracketMode = CurlyBracketMode.NewLine)
{
if (enumDefinition == null)
throw new ArgumentNullException(nameof(enumDefinition));
Expand All @@ -44,51 +46,63 @@ public static string Export(

var builder = new CodeBuilder(indentMode, spaceIndentSize, newlineMode);
builder.AddHeader();
builder.WriteEmptyLine();
builder.WriteEndLine();
builder.WriteLine("using System.CodeDom.Compiler;");
builder.WriteEmptyLine();
builder.WriteEndLine();

if (string.IsNullOrEmpty(@namespace))
builder.AddEnum(enumDefinition, storageType);
{
builder.AddEnum(enumDefinition, storageType, curlyBracketMode);
}
else
builder.AddNamespace(@namespace, b => b.AddEnum(enumDefinition, storageType));
{
builder.AddNamespace(
@namespace,
b => b.AddEnum(enumDefinition, storageType, curlyBracketMode),
curlyBracketMode);
}

return builder.Build();
}

private static void AddNamespace(
this CodeBuilder builder,
string @namespace,
Action<CodeBuilder> addContent)
Action<CodeBuilder> addContent,
CurlyBracketMode curlyBracketMode)
{
if (!IdentifierValidator.ValidateNamespace(@namespace))
throw new InvalidNamespaceException(@namespace);

builder.WriteLine($"namespace {@namespace}");
builder.StartScope();
builder.Write($"namespace {@namespace}");
builder.StartScope(curlyBracketMode);

addContent?.Invoke(builder);

builder.EndScope();
}

private static void AddEnum(this CodeBuilder builder, EnumDefinition enumDefinition, StorageType storageType)
private static void AddEnum(
this CodeBuilder builder,
EnumDefinition enumDefinition,
StorageType storageType,
CurlyBracketMode curlyBracketMode)
{
var assemblyName = typeof(CSharpExporter).Assembly.GetName();
if (!string.IsNullOrEmpty(enumDefinition.Comment))
builder.AddSummary(enumDefinition.Comment);
builder.WriteLine($"[GeneratedCode(\"{assemblyName.Name}\", \"{assemblyName.Version}\")]");
if (storageType == StorageType.Implicit)
builder.WriteLine($"public enum {enumDefinition.Identifier}");
builder.Write($"public enum {enumDefinition.Identifier}");
else
builder.WriteLine($"public enum {enumDefinition.Identifier} : {storageType.GetKeyword()}");
builder.StartScope();
builder.Write($"public enum {enumDefinition.Identifier} : {storageType.GetKeyword()}");
builder.StartScope(curlyBracketMode);

var first = true;
foreach (var entry in enumDefinition.Entries)
{
if (!first)
builder.WriteEmptyLine();
builder.WriteEndLine();
first = false;

if (!string.IsNullOrEmpty(entry.Comment))
Expand All @@ -99,9 +113,24 @@ private static void AddEnum(this CodeBuilder builder, EnumDefinition enumDefinit
builder.EndScope();
}

private static void StartScope(this CodeBuilder builder)
private static void StartScope(this CodeBuilder builder, CurlyBracketMode curlyBracketMode)
{
builder.WriteLine("{");
switch (curlyBracketMode)
{
case CurlyBracketMode.NewLine:
if (builder.IsLineActive)
builder.WriteEndLine();
builder.WriteLine("{");
break;

case CurlyBracketMode.SameLine:
if (!builder.IsNewLine && !builder.IsSpace)
builder.WriteSpace();
builder.Append("{");
builder.WriteEndLine();
break;
}

builder.BeginIndent();
}

Expand Down
18 changes: 18 additions & 0 deletions src/EnumGenerator.Core/Exporter/CurlyBracketMode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace EnumGenerator.Core.Exporter
{
/// <summary>
/// Mode to use when writing curly brackets.
/// </summary>
public enum CurlyBracketMode
{
/// <summary>
/// Opening curly-brackets should be placed on a new line.
/// </summary>
NewLine = 0,

/// <summary>
/// Opening curly-brackets should be placed on the same line.
/// </summary>
SameLine = 1
}
}
49 changes: 43 additions & 6 deletions src/EnumGenerator.Core/Utilities/CodeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,21 @@ public enum NewlineMode
/// </summary>
public int CurrentIndent => this.currentIndent;

/// <summary>
/// Is the current character a space.
/// </summary>
public bool IsSpace => this.builder.EndsWith(" ");

/// <summary>
/// Is the current line empty.
/// </summary>
public bool IsNewLine => this.builder.EndsWith(this.newline);

/// <summary>
/// Is there already content on the current line.
/// </summary>
public bool IsLineActive => !this.builder.EndsWith(this.newline);

/// <summary>
/// Indent one level deeper.
/// </summary>
Expand All @@ -83,12 +98,26 @@ public void EndIndent()
}

/// <summary>
/// Write a line.
/// Write text and end the line.
/// </summary>
/// <param name="text">Content to write</param>
/// <param name="additionalIndent">Additional level to indent this content</param>
/// <param name="prefix">Optional prefix to write before the indent</param>
public void WriteLine(string text, int additionalIndent = 0, string prefix = null)
{
this.Write(text, additionalIndent, prefix);

// End the line.
this.WriteEndLine();
}

/// <summary>
/// Write text.
/// </summary>
/// <param name="text">Content to write</param>
/// <param name="additionalIndent">Additional level to indent this content</param>
/// <param name="prefix">Optional prefix to write before the indent</param>
public void Write(string text, int additionalIndent = 0, string prefix = null)
{
if (string.IsNullOrEmpty(text))
throw new ArgumentException($"Invalid line: '{text}'", nameof(text));
Expand All @@ -101,17 +130,25 @@ public void WriteLine(string text, int additionalIndent = 0, string prefix = nul
for (int i = 0; i < (this.currentIndent + additionalIndent); i++)
this.builder.Append(this.indent);

// Write the line.
// Write the text.
this.builder.Append(text);

// End the line.
this.builder.Append(this.newline);
}

/// <summary>
/// Append text to the current line.
/// </summary>
/// <param name="text">Text to append</param>
public void Append(string text) => this.builder.Append(text);

/// <summary>
/// Write a space character.
/// </summary>
public void WriteSpace() => this.builder.Append(' ');

/// <summary>
/// Write a empty line.
/// </summary>
public void WriteEmptyLine() => this.builder.Append(this.newline);
public void WriteEndLine() => this.builder.Append(this.newline);

/// <summary>
/// Create a string from the current state of the builder.
Expand Down
27 changes: 27 additions & 0 deletions src/EnumGenerator.Core/Utilities/StringBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Text;

namespace EnumGenerator.Core.Utilities
{
/// <summary>
/// Utility extensions for <see cref="StringBuilder"/>.
/// </summary>
public static class StringBuilderExtensions
{
/// <summary>
/// Check if given <see cref="StringBuilder"/> ends with given text.
/// </summary>
/// <param name="stringBuilder">Builder to check</param>
/// <param name="text">Text to check for</param>
/// <returns>'True' if builder ends with given text, otherwise 'False'.</returns>
public static bool EndsWith(this StringBuilder stringBuilder, string text)
{
var length = text.Length;
if (stringBuilder.Length < length)
return false;

var end = stringBuilder.ToString(stringBuilder.Length - length, length);
return end.Equals(text, StringComparison.OrdinalIgnoreCase);
}
}
}
35 changes: 33 additions & 2 deletions src/EnumGenerator.Tests/Exporter/CSharpExporterTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using Xunit;

using EnumGenerator.Core.Builder;
Expand All @@ -9,7 +8,7 @@ namespace EnumGenerator.Tests.Builder
{
public sealed class CSharpExporterTests
{
private const string Version = "2.0.0.0";
private const string Version = "2.1.0.0";

[Fact]
public void ThrowsIfExportedWithInvalidNamespace() => Assert.Throws<InvalidNamespaceException>(() =>
Expand Down Expand Up @@ -253,6 +252,38 @@ public enum TestEnum : byte
B = 2,
}}
",
actual: export);
}

[Fact]
public void SameLineCurlyBracketsAreExported()
{
var builder = new EnumBuilder("TestEnum");
builder.PushEntry("A", 1);
builder.PushEntry("B", 2);
var enumDef = builder.Build();

var export = enumDef.Export(@namespace: "Test", curlyBracketMode: CurlyBracketMode.SameLine);

Assert.Equal(
expected:
$@"//------------------------------------------------------------------------------
// <auto-generated>
// Generated by: EnumGenerator.Core - {Version}
// </auto-generated>
//------------------------------------------------------------------------------
using System.CodeDom.Compiler;
namespace Test {{
[GeneratedCode(""EnumGenerator.Core"", ""{Version}"")]
public enum TestEnum {{
A = 1,
B = 2,
}}
}}
",
actual: export);
}
Expand Down

0 comments on commit 40308ac

Please sign in to comment.