diff --git a/Src/CSharpier.Tests/DocUtilitiesTests.cs b/Src/CSharpier.Tests/DocUtilitiesTests.cs new file mode 100644 index 000000000..f74206b3e --- /dev/null +++ b/Src/CSharpier.Tests/DocUtilitiesTests.cs @@ -0,0 +1,164 @@ +using System.Collections.Generic; +using System.Linq; +using FluentAssertions; +using NUnit.Framework; + +namespace CSharpier.Tests +{ + public class DocUtilitiesTests + { + [Test] + public void RemoveInitialDoubleHardLine_Should_Handle_Empty_List() + { + var doc = new List(); + + DocUtilities.RemoveInitialDoubleHardLine(doc); + + doc.Should().BeEmpty(); + } + + [Test] + public void RemoveInitialDoubleHardLine_Should_Remove_Null() + { + var doc = new List { Docs.Null }; + + DocUtilities.RemoveInitialDoubleHardLine(doc); + + doc.Should().BeEmpty(); + } + + [Test] + public void RemoveInitialDoubleHardLine_Should_Not_Remove_Simple_HardLine() + { + var doc = new List { Docs.HardLine }; + + DocUtilities.RemoveInitialDoubleHardLine(doc); + + doc.Should().HaveCount(1); + } + + [Test] + public void RemoveInitialDoubleHardLine_Should_Remove_Simple_Double_HardLine() + { + var doc = new List { Docs.HardLine, Docs.HardLine }; + + DocUtilities.RemoveInitialDoubleHardLine(doc); + + doc.Should().HaveCount(1); + } + + [Test] + public void RemoveInitialDoubleHardLine_Should_Not_Remove_Concated_HardLine() + { + var concat = Docs.Concat(Docs.HardLine); + var doc = new List { concat }; + + DocUtilities.RemoveInitialDoubleHardLine(doc); + + concat.Parts.Should().BeEquivalentTo(Docs.HardLine); + } + + [Test] + public void RemoveInitialDoubleHardLine_Should_Remove_Concated_HardLine() + { + var concat = Docs.Concat(Docs.HardLine, Docs.HardLine); + var doc = new List { concat }; + + DocUtilities.RemoveInitialDoubleHardLine(doc); + + concat.Parts.Should().ContainSingle(); + } + + [Test] + public void RemoveInitialDoubleHardLine_Should_Not_Remove_Deep_Concated_HardLine() + { + var concat = Docs.Concat(Docs.HardLine); + var doc = new List { Docs.Concat(concat) }; + + DocUtilities.RemoveInitialDoubleHardLine(doc); + + concat.Parts.Should().BeEquivalentTo(Docs.HardLine); + } + + [Test] + public void RemoveInitialDoubleHardLine_Should_Remove_Deep_Concated_HardLine() + { + var concat = Docs.Concat(Docs.HardLine, Docs.HardLine); + var doc = new List { Docs.Concat(concat) }; + + DocUtilities.RemoveInitialDoubleHardLine(doc); + + concat.Parts.Should().ContainSingle(); + } + + [Test] + public void RemoveInitialDoubleHardLine_Should_Remove_Single_HardLine() + { + var concat = Docs.Concat( + Docs.HardLine, + Docs.HardLine, + Docs.HardLine + ); + var doc = new List { Docs.Concat(concat) }; + + DocUtilities.RemoveInitialDoubleHardLine(doc); + + concat.Parts.Should().HaveCount(2); + } + + [Test] + public void RemoveInitialDoubleHardLine_Should_Not_Remove_Indented_HardLine() + { + var indent = Docs.Indent(Docs.HardLine); + var doc = new List { indent }; + + DocUtilities.RemoveInitialDoubleHardLine(doc); + + indent.Contents.Should().BeEquivalentTo(Docs.HardLine); + } + + [Test] + public void RemoveInitialDoubleHardLine_Should_Remove_Indented_HardLine() + { + var indent = Docs.Indent(Docs.HardLine); + var doc = new List { Docs.HardLine, indent }; + + DocUtilities.RemoveInitialDoubleHardLine(doc); + + indent.Contents.Should().Be(Docs.Null); + } + + [Test] + public void RemoveInitialDoubleHardLine_Should_Not_Remove_Deep_Indented_HardLine() + { + var indent = Docs.Indent(Docs.HardLine); + var doc = new List { Docs.Indent(indent) }; + + DocUtilities.RemoveInitialDoubleHardLine(doc); + + indent.Contents.Should().BeEquivalentTo(Docs.HardLine); + } + + [Test] + public void RemoveInitialDoubleHardLine_Should_Remove_Grouped_Double_HardLine() + { + var contents = new List { Docs.HardLine, Docs.HardLine }; + var doc = Docs.Group(contents); + + DocUtilities.RemoveInitialDoubleHardLine(doc); + + contents.Should().ContainSingle(); + } + + [Test] + public void RemoveInitialDoubleHardLine_Should_Only_Remove_Initial_HardLines() + { + var doc = Docs.Concat("1", Docs.HardLine, Docs.HardLine); + + DocUtilities.RemoveInitialDoubleHardLine(doc); + + doc.Should() + .BeEquivalentTo(Docs.Concat("1", Docs.HardLine, Docs.HardLine)); + } + } +} diff --git a/Src/CSharpier.Tests/TestFiles/Comments/ClassComments.cst b/Src/CSharpier.Tests/TestFiles/Comments/ClassComments.cst index d236f5c4b..218dcfc5d 100644 --- a/Src/CSharpier.Tests/TestFiles/Comments/ClassComments.cst +++ b/Src/CSharpier.Tests/TestFiles/Comments/ClassComments.cst @@ -16,7 +16,6 @@ static // trailing class // trailing ClassName2 { } - // this public // is diff --git a/Src/CSharpier.Tests/TestFiles/EmptyLines/EmptyLines.cst b/Src/CSharpier.Tests/TestFiles/EmptyLines/EmptyLines.cst new file mode 100644 index 000000000..71fdd7555 --- /dev/null +++ b/Src/CSharpier.Tests/TestFiles/EmptyLines/EmptyLines.cst @@ -0,0 +1,35 @@ +namespace Namespace +{ + + public class RemovesLineBefore { } + + + public class RemovesDoubledLines { } + + public class RemoveTrailingLine { } + +} + +public class ClassName +{ + + public int RemoveLineBefore; + + + public int RemoveDoubleLines; + + public void MethodName() + { + + var removeLineBefore = 1; + + + var removeDoubleLines = 2; + + var removeTrailingLine = 3; + + } + + public int RemoveTrailingLine; + +} \ No newline at end of file diff --git a/Src/CSharpier.Tests/TestFiles/EmptyLines/EmptyLines.expected.cst b/Src/CSharpier.Tests/TestFiles/EmptyLines/EmptyLines.expected.cst new file mode 100644 index 000000000..74563a357 --- /dev/null +++ b/Src/CSharpier.Tests/TestFiles/EmptyLines/EmptyLines.expected.cst @@ -0,0 +1,26 @@ +namespace Namespace +{ + public class RemovesLineBefore { } + + public class RemovesDoubledLines { } + + public class RemoveTrailingLine { } +} + +public class ClassName +{ + public int RemoveLineBefore; + + public int RemoveDoubleLines; + + public void MethodName() + { + var removeLineBefore = 1; + + var removeDoubleLines = 2; + + var removeTrailingLine = 3; + } + + public int RemoveTrailingLine; +} diff --git a/Src/CSharpier.Tests/TestFiles/EmptyLines/_EmptyLineTests.cs b/Src/CSharpier.Tests/TestFiles/EmptyLines/_EmptyLineTests.cs new file mode 100644 index 000000000..3d9bac764 --- /dev/null +++ b/Src/CSharpier.Tests/TestFiles/EmptyLines/_EmptyLineTests.cs @@ -0,0 +1,14 @@ +using CSharpier.Tests.TestFileTests; +using NUnit.Framework; + +namespace CSharpier.Tests.TestFiles +{ + public class EmptyLineTests : BaseTest + { + [Test] + public void EmptyLines() + { + this.RunTest("EmptyLines", "EmptyLines"); + } + } +} diff --git a/Src/CSharpier/Doc.cs b/Src/CSharpier/Doc.cs index c86497e5b..105cf528c 100644 --- a/Src/CSharpier/Doc.cs +++ b/Src/CSharpier/Doc.cs @@ -5,12 +5,6 @@ namespace CSharpier { public class Doc { - public bool IsHardLine() - { - return this is Concat concat - && concat.Parts.FirstOrDefault() is LineDoc { Type: LineDoc.LineType.Hard } ; - } - public static implicit operator Doc(string value) { return new StringDoc(value); @@ -19,6 +13,18 @@ public bool IsHardLine() public static NullDoc Null { get; } = NullDoc.Instance; } + public class HardLine : Concat + { + public HardLine() + : base( + new List + { + new LineDoc { Type = LineDoc.LineType.Hard }, + new BreakParent() + } + ) { } + } + public class NullDoc : Doc { public static NullDoc Instance { get; } = new NullDoc(); @@ -80,21 +86,12 @@ public class ForceFlat : Doc, IHasContents public Doc Contents { get; set; } = Doc.Null; } + // should possibly be used by ternary operator public class Align : Doc, IHasContents { public Doc Contents { get; set; } = Doc.Null; } - public class Fill : Doc, IHasContents - { - public Doc Contents { get; set; } = Doc.Null; - } - - public class LineSuffix : Doc, IHasContents - { - public Doc Contents { get; set; } = Doc.Null; - } - public class LeadingComment : Doc { public CommentType Type { get; set; } diff --git a/Src/CSharpier/DocPrinter.cs b/Src/CSharpier/DocPrinter.cs index 705b3a299..8003148ba 100644 --- a/Src/CSharpier/DocPrinter.cs +++ b/Src/CSharpier/DocPrinter.cs @@ -8,6 +8,7 @@ namespace CSharpier // a big chunk of the code in here is ported from prettier. The names and layout of the file were // kept consistent with how they looked in prettier because not everything // was ported over and porting over more code would be easier if this file looked basically the same + // taken from prettier 2.2.1 or so public static class DocPrinter { private static Indent RootIndent() diff --git a/Src/CSharpier/DocTreePrinter.cs b/Src/CSharpier/DocTreePrinter.cs index c549a7875..1d49bb725 100644 --- a/Src/CSharpier/DocTreePrinter.cs +++ b/Src/CSharpier/DocTreePrinter.cs @@ -18,7 +18,7 @@ private static string PrintDocTree(Doc document, string indent) switch (document) { case NullDoc: - return indent + "Doc.Null"; + return indent + "Docs.Null"; case StringDoc stringDoc: return indent + "\"" + stringDoc.Value?.Replace( "\"", @@ -32,11 +32,11 @@ private static string PrintDocTree(Doc document, string indent) ) { return indent + (line.IsLiteral - ? "LiteralLine" - : "HardLine"); + ? "Docs.LiteralLine" + : "Docs.HardLine"); } - var result = indent + "Concat("; + var result = indent + "Docs.Concat("; if (concat.Parts.Count > 0) { result += Environment.NewLine; @@ -58,35 +58,35 @@ private static string PrintDocTree(Doc document, string indent) return result; case LineDoc lineDoc: return indent + (lineDoc.IsLiteral - ? "LiteralLine" + ? "Docs.LiteralLine" : lineDoc.Type == LineDoc.LineType.Normal - ? "Line" + ? "Docs.Line" : lineDoc.Type == LineDoc.LineType.Hard - ? "HardLine" - : "SoftLine"); + ? "Docs.HardLine" + : "Docs.SoftLine"); case BreakParent: return ""; case ForceFlat forceFlat: - return indent + "ForceFlat(" + Environment.NewLine + PrintDocTree( + return indent + "Docs.ForceFlat(" + Environment.NewLine + PrintDocTree( forceFlat.Contents, indent + " " ) + ")"; case IndentDoc indentDoc: - return indent + "Indent(" + Environment.NewLine + PrintDocTree( + return indent + "Docs.Indent(" + Environment.NewLine + PrintDocTree( indentDoc.Contents, indent + " " ) + ")"; case Group group: - return indent + "Group(" + Environment.NewLine + PrintDocTree( + return indent + "Docs.Group(" + Environment.NewLine + PrintDocTree( group.Contents, indent + " " ) + ")"; case LeadingComment leadingComment: - return $"{indent}LeadingComment(\"{leadingComment.Comment}\", CommentType.{(leadingComment.Type == CommentType.SingleLine ? "SingleLine" : "MultiLine")})"; + return $"{indent}Docs.LeadingComment(\"{leadingComment.Comment}\", CommentType.{(leadingComment.Type == CommentType.SingleLine ? "SingleLine" : "MultiLine")})"; case TrailingComment trailingComment: - return $"{indent}TrailingComment(\"{trailingComment.Comment}\", CommentType.{(trailingComment.Type == CommentType.SingleLine ? "SingleLine" : "MultiLine")})"; + return $"{indent}Docs.TrailingComment(\"{trailingComment.Comment}\", CommentType.{(trailingComment.Type == CommentType.SingleLine ? "SingleLine" : "MultiLine")})"; case SpaceIfNoPreviousComment: - return indent + "SpaceIfNoPreviousComment"; + return indent + "Docs.SpaceIfNoPreviousComment"; default: throw new Exception("Can't handle " + document); } diff --git a/Src/CSharpier/DocUtilities.cs b/Src/CSharpier/DocUtilities.cs new file mode 100644 index 000000000..08d6308ff --- /dev/null +++ b/Src/CSharpier/DocUtilities.cs @@ -0,0 +1,112 @@ +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; + +namespace CSharpier +{ + public static class DocUtilities + { + public static void RemoveInitialDoubleHardLine(List docs) + { + var removeNextHardLine = false; + RemoveInitialDoubleHardLine(docs, ref removeNextHardLine); + } + + private static void RemoveInitialDoubleHardLine( + List docs, + ref bool removeNextHardLine) + { + var x = 0; + while (x < docs.Count) + { + var doc = docs[x]; + + if (doc == Docs.Null) + { + docs.RemoveAt(x); + } + else if (doc is HardLine) + { + if (removeNextHardLine) + { + docs.RemoveAt(x); + return; + } + + removeNextHardLine = true; + } + else + { + RemoveInitialDoubleHardLine(doc, ref removeNextHardLine); + return; + } + + x++; + } + + return; + } + + + public static void RemoveInitialDoubleHardLine(Doc doc) + { + var removeNextHardLine = false; + RemoveInitialDoubleHardLine(doc, ref removeNextHardLine); + } + + private static void RemoveInitialDoubleHardLine( + Doc doc, + ref bool removeNextHardLine) + { + switch (doc) + { + case StringDoc: + return; + case IndentDoc indentDoc: + switch (indentDoc.Contents) + { + case HardLine: + if (removeNextHardLine) + { + indentDoc.Contents = Docs.Null; + return; + } + + removeNextHardLine = true; + return; + default: + RemoveInitialDoubleHardLine( + indentDoc.Contents, + ref removeNextHardLine + ); + return; + } + case Group group: + switch (group.Contents) + { + case HardLine: + if (removeNextHardLine) + { + group.Contents = Docs.Null; + return; + } + + removeNextHardLine = true; + return; + default: + RemoveInitialDoubleHardLine( + group.Contents, + ref removeNextHardLine + ); + return; + } + case Concat concat: + RemoveInitialDoubleHardLine( + concat.Parts, + ref removeNextHardLine + ); + return; + } + } + } +} diff --git a/Src/CSharpier/Docs.cs b/Src/CSharpier/Docs.cs new file mode 100644 index 000000000..14c4389f5 --- /dev/null +++ b/Src/CSharpier/Docs.cs @@ -0,0 +1,117 @@ +using System.Collections.Generic; +using System.Linq; + +namespace CSharpier +{ + public static class Docs + { + public static NullDoc Null { get; } = NullDoc.Instance; + + private static Doc BreakParent => new BreakParent(); + + // TODO 0 maybe all spaces should be this instead? but if we ditch leading/trailing comments, this won't work anymore + public static SpaceIfNoPreviousComment SpaceIfNoPreviousComment => + new(); + + public static HardLine HardLine => new(); + + // TODO all of the Line types can probably turn into proper classes, and be the same instance by type + public static Doc LiteralLine => + Concat( + new LineDoc { Type = LineDoc.LineType.Hard, IsLiteral = true }, + BreakParent + ); + + public static LineDoc Line => new() { Type = LineDoc.LineType.Normal }; + + public static LineDoc SoftLine => + new() { Type = LineDoc.LineType.Soft }; + + public static LeadingComment LeadingComment( + string comment, + CommentType commentType) + { + return new() { Type = commentType, Comment = comment }; + } + + public static TrailingComment TrailingComment( + string comment, + CommentType commentType) + { + return new() { Type = commentType, Comment = comment, }; + } + + public static Concat Concat(List parts) + { + return new(CleanParts(parts)); + } + + public static Concat Concat(params Doc[] parts) + { + return new(CleanParts(parts.ToList())); + } + + public static ForceFlat ForceFlat(params Doc[] contents) + { + return new() + { + Contents = contents.Length == 0 + ? contents[0] + : Concat(contents), + + }; + } + + public static Group Group(List contents) + { + return new() + { + Contents = contents.Count == 1 ? contents[0] : Concat(contents), + + }; + } + + public static Group Group(params Doc[] contents) + { + return new() + { + Contents = contents.Length == 1 + ? contents[0] + : Concat(contents), + + }; + } + + public static IndentDoc Indent(params Doc[] contents) + { + return new() + { + Contents = contents.Length == 1 ? contents[0] : Concat(contents) + }; + } + + // can be used to clean up the doc tree, ideally we would change our printing process + // to not have the deeply nested Concats, but that's a large change + // only allowed when in debug because it does slow things down a bit + private static List CleanParts(List parts) + { + return parts; +#if DEBUG + var newParts = new List(); + foreach (var doc in parts) + { + if (doc is Concat concat) + { + newParts.AddRange(CleanParts(concat.Parts)); + } + else if (doc != Docs.Null) + { + newParts.Add(doc); + } + } + return newParts; +#endif + return parts; + } + } +} diff --git a/Src/CSharpier/Printer.cs b/Src/CSharpier/Printer.cs index a7e56a174..e9a61d339 100644 --- a/Src/CSharpier/Printer.cs +++ b/Src/CSharpier/Printer.cs @@ -10,83 +10,33 @@ namespace CSharpier // https://devblogs.microsoft.com/dotnet/introducing-c-source-generators/ public partial class Printer { - private static Doc BreakParent => new BreakParent(); - - // TODO 0 maybe all spaces should be this instead? public static Doc SpaceIfNoPreviousComment => - new SpaceIfNoPreviousComment(); - public static Doc HardLine => - Concat(new LineDoc { Type = LineDoc.LineType.Hard }, BreakParent); - public static Doc LiteralLine => - Concat( - new LineDoc { Type = LineDoc.LineType.Hard, IsLiteral = true }, - BreakParent - ); - public static Doc Line => - new LineDoc { Type = LineDoc.LineType.Normal }; - public static Doc SoftLine => - new LineDoc { Type = LineDoc.LineType.Soft }; + Docs.SpaceIfNoPreviousComment; + + public static Doc HardLine => Docs.HardLine; + + public static Doc LiteralLine => Docs.LiteralLine; + + public static Doc Line => Docs.Line; + + public static Doc SoftLine => Docs.SoftLine; public static Doc LeadingComment( string comment, - CommentType commentType) - { - return new LeadingComment { Type = commentType, Comment = comment }; - } + CommentType commentType) => + Docs.LeadingComment(comment, commentType); public static Doc TrailingComment( string comment, - CommentType commentType) - { - return new TrailingComment - { - Type = commentType, - Comment = comment, + CommentType commentType) => + Docs.TrailingComment(comment, commentType); - }; - } - - public static Doc Concat(Parts parts) - { - return new Concat(CleanParts(parts)); - } - - public static Doc Concat(params Doc[] parts) - { - return new Concat(CleanParts(parts)); - } - - public static List CleanParts(IEnumerable parts) - { - return parts.ToList(); -#if DEBUG - var newParts = new List(); - foreach (var doc in parts) - { - if (doc is Concat concat) - { - newParts.AddRange(CleanParts(concat.Parts)); - } - else if (doc != null) - { - newParts.Add(doc); - } - } - return newParts; -#endif - return parts.ToList(); - } + public static Doc Concat(Parts parts) => Docs.Concat(parts.ToArray()); - public static Doc ForceFlat(params Doc[] contents) - { - return new ForceFlat - { - Contents = contents.Length == 0 - ? contents[0] - : Concat(contents), + public static Doc Concat(params Doc[] parts) => Docs.Concat(parts); - }; - } + public static Doc ForceFlat(params Doc[] contents) => + Docs.ForceFlat(contents); public static Doc Join(Doc separator, IEnumerable array) { @@ -112,33 +62,16 @@ public static Doc Join(Doc separator, IEnumerable array) return Concat(parts); } - public static Doc Group(Parts parts) - { - return new Group - { - Contents = parts.Count == 1 ? parts[0] : Concat(parts), + public static Doc Group(Parts parts) => Docs.Group(parts.ToArray()); - }; - } + public static Doc Group(List contents) => Docs.Group(contents); - public static Doc Group(params Doc[] contents) - { - return new Group - { - Contents = contents.Length == 1 - ? contents[0] - : Concat(contents), + public static Doc Group(params Doc[] contents) => Docs.Group(contents); - }; - } + public static Doc Indent(Parts parts) => Docs.Indent(parts.ToArray()); - public static Doc Indent(params Doc[] contents) - { - return new IndentDoc - { - Contents = contents.Length == 1 ? contents[0] : Concat(contents) - }; - } + public static Doc Indent(params Doc[] contents) => + Docs.Indent(contents); private Doc PrintSeparatedSyntaxList( SeparatedSyntaxList list, diff --git a/Src/CSharpier/Printer/BlockSyntax.cs b/Src/CSharpier/Printer/BlockSyntax.cs index da4e65777..5dc0136ce 100644 --- a/Src/CSharpier/Printer/BlockSyntax.cs +++ b/Src/CSharpier/Printer/BlockSyntax.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -17,34 +18,31 @@ private Doc PrintBlockSyntax(BlockSyntax node) ? Line : HardLine; - var parts = new Parts( + var parts = new List + { Line, this.PrintSyntaxToken(node.OpenBraceToken) - ); + }; if (node.Statements.Count > 0) { - parts.Push( - Concat( - Indent( - statementSeparator, - Join( - statementSeparator, - node.Statements.Select(this.Print) - ) - ), - statementSeparator - ) + var innerParts = Indent( + statementSeparator, + Join(statementSeparator, node.Statements.Select(this.Print)) ); + + DocUtilities.RemoveInitialDoubleHardLine(innerParts); + + parts.Add(Concat(innerParts, statementSeparator)); } - parts.Push( + parts.Add( this.PrintSyntaxToken( node.CloseBraceToken, null, node.Statements.Count == 0 ? " " : Doc.Null ) ); - return Group(Concat(parts)); + return Group(parts); } } } diff --git a/Src/CSharpier/Printer/NamespaceDeclarationSyntax.cs b/Src/CSharpier/Printer/NamespaceDeclarationSyntax.cs index 6de229f0e..62af4d6d6 100644 --- a/Src/CSharpier/Printer/NamespaceDeclarationSyntax.cs +++ b/Src/CSharpier/Printer/NamespaceDeclarationSyntax.cs @@ -8,12 +8,14 @@ public partial class Printer private Doc PrintNamespaceDeclarationSyntax( NamespaceDeclarationSyntax node) { - var parts = new Parts(); - parts.Push(this.PrintExtraNewLines(node)); - parts.Push(this.PrintAttributeLists(node, node.AttributeLists)); - parts.Push(this.PrintModifiers(node.Modifiers)); - parts.Push(this.PrintSyntaxToken(node.NamespaceKeyword), " "); - parts.Push(this.Print(node.Name)); + var parts = new Parts( + this.PrintExtraNewLines(node), + this.PrintAttributeLists(node, node.AttributeLists), + this.PrintModifiers(node.Modifiers), + this.PrintSyntaxToken(node.NamespaceKeyword), + " ", + this.Print(node.Name) + ); var innerParts = new Parts(); var hasMembers = node.Members.Count > 0; @@ -59,12 +61,13 @@ public partial class Printer innerParts.Push(" "); } + DocUtilities.RemoveInitialDoubleHardLine(innerParts); parts.Push( Group( Line, this.PrintSyntaxToken(node.OpenBraceToken), - Indent(Concat(innerParts)), + Indent(innerParts), hasMembers || hasUsing || hasExterns ? HardLine : Doc.Null, this.PrintSyntaxToken(node.CloseBraceToken), this.PrintSyntaxToken(node.SemicolonToken) diff --git a/Src/CSharpier/PrinterHelpers/BaseTypeDeclarationSyntax.cs b/Src/CSharpier/PrinterHelpers/BaseTypeDeclarationSyntax.cs index 36de716a6..686087139 100644 --- a/Src/CSharpier/PrinterHelpers/BaseTypeDeclarationSyntax.cs +++ b/Src/CSharpier/PrinterHelpers/BaseTypeDeclarationSyntax.cs @@ -111,6 +111,8 @@ public partial class Printer if (hasMembers) { + DocUtilities.RemoveInitialDoubleHardLine(members); + parts.Push( HardLine, this.PrintSyntaxToken(node.OpenBraceToken), diff --git a/Src/CSharpier/PrinterHelpers/SyntaxTrivia.cs b/Src/CSharpier/PrinterHelpers/SyntaxTrivia.cs index 71a63435e..dd1c6567b 100644 --- a/Src/CSharpier/PrinterHelpers/SyntaxTrivia.cs +++ b/Src/CSharpier/PrinterHelpers/SyntaxTrivia.cs @@ -16,6 +16,8 @@ private Doc PrintExtraNewLines(CSharpSyntaxNode node) if (leadingTrivia.Kind() == SyntaxKind.EndOfLineTrivia) { parts.Push(HardLine); + // ensures we only print a single new line + break; } else if (leadingTrivia.Kind() != SyntaxKind.WhitespaceTrivia) { @@ -187,7 +189,7 @@ private Doc PrintLeadingTrivia(SyntaxToken syntaxToken) } } - if (skipLastHardline && parts.Any() && parts.Last().IsHardLine()) + if (skipLastHardline && parts.Any() && parts.Last() is HardLine) { parts.RemoveAt(parts.Count - 1); }