diff --git a/CodeBlocker.Test/CodeBlockerTests.cs b/CodeBlocker.Test/CodeBlockerTests.cs
index 6ae4b06..40f71af 100644
--- a/CodeBlocker.Test/CodeBlockerTests.cs
+++ b/CodeBlocker.Test/CodeBlockerTests.cs
@@ -71,6 +71,36 @@ public void NewLineShouldAddEmptyLine()
Assert.AreEqual(CodeBlocker.DefaultNewLineString, result);
}
+ [TestMethod]
+ public void NewLineAfterAPartialWriteKeepsTheNextLineIndented()
+ {
+ using CodeBlocker codeBlocker = CodeBlocker.Create();
+
+ codeBlocker.WriteLine("class C");
+ using (new Scope(codeBlocker))
+ {
+ codeBlocker.Write("int x = 1;");
+ codeBlocker.NewLine();
+ codeBlocker.WriteLine("int y = 2;");
+ }
+
+ Assert.AreEqual("class C\n{\n\tint x = 1;\n\tint y = 2;\n}\n", codeBlocker.ToString());
+ }
+
+ [TestMethod]
+ public void NewLineAtTheStartOfALineStillWritesNoIndentation()
+ {
+ using CodeBlocker codeBlocker = CodeBlocker.Create();
+
+ codeBlocker.Indent();
+ codeBlocker.Write("a");
+ codeBlocker.NewLine();
+ codeBlocker.NewLine();
+ codeBlocker.WriteLine("b");
+
+ Assert.AreEqual("\ta\n\n\tb\n", codeBlocker.ToString());
+ }
+
[TestMethod]
public void WriteLineWithIndentationShouldRespectIndentLevel()
{
diff --git a/CodeBlocker.Test/TemplateTests.cs b/CodeBlocker.Test/TemplateTests.cs
index ce27649..96b6150 100644
--- a/CodeBlocker.Test/TemplateTests.cs
+++ b/CodeBlocker.Test/TemplateTests.cs
@@ -356,6 +356,35 @@ public void AMultiLineExpressionBodyKeepsABlankLineWithoutIndentingIt()
Render(type));
}
+ [TestMethod]
+ public void AnExpressionBodyStartingWithABlankLineKeepsItsFirstLineOnTheDeclaration()
+ {
+ ClassTemplate type = new()
+ {
+ Name = "C",
+ Keywords = { "public" },
+ Members =
+ {
+ new PropertyTemplate
+ {
+ Type = "int",
+ Name = "X",
+ Keywords = { "public" },
+ ExpressionBodyFactory = codeBlocker =>
+ {
+ codeBlocker.NewLine();
+ codeBlocker.WriteLine("1 +");
+ codeBlocker.Write("2");
+ },
+ },
+ },
+ };
+
+ Assert.AreEqual(
+ "public class C\n{\n\tpublic int X => 1 +\n\t2;\n}\n",
+ Render(type));
+ }
+
[TestMethod]
public void AnEmptyExpressionBodyStillTerminatesTheDeclaration()
{
diff --git a/CodeBlocker/CodeBlocker.cs b/CodeBlocker/CodeBlocker.cs
index d27313c..0d3a873 100644
--- a/CodeBlocker/CodeBlocker.cs
+++ b/CodeBlocker/CodeBlocker.cs
@@ -30,6 +30,16 @@ public class CodeBlocker : IDisposable
private bool disposedValue;
private bool shouldDisposeWriter;
+ ///
+ /// Whether the current line has been started by and not yet terminated.
+ ///
+ ///
+ /// needs this: keeps a
+ /// blank line free of indentation, but it does not re-arm the writer's pending-tab flag, so using
+ /// it to end a line that is already under way would leave the next line at column zero.
+ ///
+ private bool isMidLine;
+
private IndentedTextWriter IndentedTextWriter { get; }
///
@@ -203,24 +213,57 @@ public static CodeBlocker Create(string indentString, string newLineString)
///
/// Write a line of code without indentation.
///
- public void NewLine() => IndentedTextWriter.WriteLineNoTabs(string.Empty);
+ ///
+ /// At the start of a line this writes a blank line with no indentation. After a partial
+ /// it ends that line instead, and the next line is indented as usual.
+ ///
+ public void NewLine()
+ {
+ if (isMidLine)
+ {
+ // Nothing is pending, so WriteLine() writes no tabs here, but it does re-arm them for
+ // whatever is written next.
+ IndentedTextWriter.WriteLine();
+ }
+ else
+ {
+ IndentedTextWriter.WriteLineNoTabs(string.Empty);
+ }
+
+ isMidLine = false;
+ }
///
/// Write a line of code with indentation.
///
/// The line of code to write.
- public void WriteLine(string line) => IndentedTextWriter.WriteLine(line);
+ public void WriteLine(string line)
+ {
+ IndentedTextWriter.WriteLine(line);
+ isMidLine = false;
+ }
///
/// Write a line of code with indentation.
///
- public void WriteLine() => IndentedTextWriter.WriteLine();
+ public void WriteLine()
+ {
+ IndentedTextWriter.WriteLine();
+ isMidLine = false;
+ }
///
/// Write a line of code with indentation.
///
/// The text to write.
- public void Write(string text) => IndentedTextWriter.Write(text);
+ public void Write(string text)
+ {
+ IndentedTextWriter.Write(text);
+ if (!string.IsNullOrEmpty(text))
+ {
+ isMidLine = true;
+ }
+ }
///
/// Increase the indentation level.
diff --git a/CodeBlocker/Templates/TemplateRendering.cs b/CodeBlocker/Templates/TemplateRendering.cs
index 533efac..f1e54ed 100644
--- a/CodeBlocker/Templates/TemplateRendering.cs
+++ b/CodeBlocker/Templates/TemplateRendering.cs
@@ -184,9 +184,7 @@ internal static void WriteConstraints(CodeBlocker codeBlocker, IReadOnlyCollecti
return;
}
- // Terminate the declaration line the constraints hang off. WriteLine() rather than
- // NewLine(): NewLine() writes through IndentedTextWriter.WriteLineNoTabs, which does not
- // re-arm the writer's pending-tab flag, so whatever came next would land at column zero.
+ // Terminate the declaration line the constraints hang off.
codeBlocker.WriteLine();
using IndentScope indent = new(codeBlocker);
@@ -271,6 +269,14 @@ internal static void WriteExpressionBody(CodeBlocker codeBlocker, Action ");
if (last < 0)
{
@@ -278,7 +284,7 @@ internal static void WriteExpressionBody(CodeBlocker codeBlocker, Action