From ad211bf048cbc749c9cd06ac42fbf475e0758620 Mon Sep 17 00:00:00 2001 From: Bela VanderVoort Date: Mon, 30 Jan 2023 17:36:01 -0600 Subject: [PATCH] Progress towards properly indenting regions closes #812 --- Src/CSharpier.Tests/CSharpier.Tests.csproj | 18 +++--- .../FormattingTests/TestFiles/Directives.cst | 22 ------- .../TestFiles/Directives_Regions.cst | 43 +++++++++++++ .../TestFiles/MemberLines.expected.cst | 4 +- Src/CSharpier/DocPrinter/DocPrinter.cs | 10 +++- Src/CSharpier/DocTypes/Doc.cs | 3 + Src/CSharpier/DocTypes/IndentDoc.cs | 1 + Src/CSharpier/SyntaxPrinter/Token.cs | 60 +++++++++++++------ 8 files changed, 110 insertions(+), 51 deletions(-) create mode 100644 Src/CSharpier.Tests/FormattingTests/TestFiles/Directives_Regions.cst diff --git a/Src/CSharpier.Tests/CSharpier.Tests.csproj b/Src/CSharpier.Tests/CSharpier.Tests.csproj index 21867ef58..f73a005bb 100644 --- a/Src/CSharpier.Tests/CSharpier.Tests.csproj +++ b/Src/CSharpier.Tests/CSharpier.Tests.csproj @@ -5,19 +5,19 @@ true - - - - - + + + + + - - - + + + - + diff --git a/Src/CSharpier.Tests/FormattingTests/TestFiles/Directives.cst b/Src/CSharpier.Tests/FormattingTests/TestFiles/Directives.cst index 585865acc..80034b34d 100644 --- a/Src/CSharpier.Tests/FormattingTests/TestFiles/Directives.cst +++ b/Src/CSharpier.Tests/FormattingTests/TestFiles/Directives.cst @@ -11,19 +11,11 @@ #endif #undef foo #line 6 -#region Region -using static System.Linq.Enumerable; - -#endregion class ClassName { } public class ClassName { - #region Region - private int x; // trailing comment here shouldn't give extra indent to the endregion after it - #endregion - public bool SomeProperty => #if !DEBUG someValue @@ -62,14 +54,6 @@ namespace Namespace } } -#region Region - - #region Nested -class ClassName { } - #endregion Nested - -#endregion - #if DIRECTIVES_AROUND_MODIFIERS_BREAK_CORRECTLY public #else @@ -79,12 +63,6 @@ static class ConditionallyPublic { } class EdgeCases { - string RegionsIndentAndNewLineProperly = - #region one - @"using System;" - #endregion one - ; - void MethodWithNestedIfsDoesNotGetExtraLineBreak() { #if DEBUG diff --git a/Src/CSharpier.Tests/FormattingTests/TestFiles/Directives_Regions.cst b/Src/CSharpier.Tests/FormattingTests/TestFiles/Directives_Regions.cst new file mode 100644 index 000000000..3c51bc035 --- /dev/null +++ b/Src/CSharpier.Tests/FormattingTests/TestFiles/Directives_Regions.cst @@ -0,0 +1,43 @@ +public class ClassName +{ + #region Region + public int LongUglyMethod() => 42; + #endregion +} + +public class ClassName +{ + #region Region + public int LongUglyMethod() => 42; + + #endregion +} + +#region class +public class ClassName +{ + #region method + public void Method() + { + #region content + #endregion + } + #endregion +} +#endregion + +public class ClassName +{ + #region Region + private int x; // trailing comment here shouldn't give extra indent to the endregion after it + #endregion + + private int y; + + // TODO is this a real thing? + string RegionsIndentAndNewLineProperly = + #region one + @"using System;" + #endregion one + ; +} diff --git a/Src/CSharpier.Tests/FormattingTests/TestFiles/MemberLines.expected.cst b/Src/CSharpier.Tests/FormattingTests/TestFiles/MemberLines.expected.cst index af49adbfa..0fdcbbb01 100644 --- a/Src/CSharpier.Tests/FormattingTests/TestFiles/MemberLines.expected.cst +++ b/Src/CSharpier.Tests/FormattingTests/TestFiles/MemberLines.expected.cst @@ -150,11 +150,11 @@ public class ClassName public class ClassName { -#region RegionWithSpaceBeforeAndAfterMethod + #region RegionWithSpaceBeforeAndAfterMethod void SomeMethod() { } -#endregion + #endregion void SomeMethod() { } } diff --git a/Src/CSharpier/DocPrinter/DocPrinter.cs b/Src/CSharpier/DocPrinter/DocPrinter.cs index 9406406d8..c9046e478 100644 --- a/Src/CSharpier/DocPrinter/DocPrinter.cs +++ b/Src/CSharpier/DocPrinter/DocPrinter.cs @@ -87,7 +87,15 @@ private void ProcessNextCommand() } else if (doc is IndentDoc indentDoc) { - this.Push(indentDoc.Contents, mode, this.Indenter.IncreaseIndent(indent)); + var nextIndent = this.Indenter.IncreaseIndent(indent); + + if (indentDoc.EnsureIndent) + { + this.Output.TrimTrailingWhitespace(); + this.Output.Append(nextIndent.Value); + } + + this.Push(indentDoc.Contents, mode, nextIndent); } else if (doc is Trim) { diff --git a/Src/CSharpier/DocTypes/Doc.cs b/Src/CSharpier/DocTypes/Doc.cs index 7916bd46c..6e00b01b3 100644 --- a/Src/CSharpier/DocTypes/Doc.cs +++ b/Src/CSharpier/DocTypes/Doc.cs @@ -114,6 +114,9 @@ public static Group GroupWithId(string groupId, params Doc[] contents) public static IndentDoc Indent(List contents) => new() { Contents = Concat(contents) }; + public static IndentDoc EnsureIndent(params Doc[] contents) => + new() { Contents = Concat(contents), EnsureIndent = true }; + public static Doc IndentIf(bool condition, Doc contents) { return condition ? Indent(contents) : contents; diff --git a/Src/CSharpier/DocTypes/IndentDoc.cs b/Src/CSharpier/DocTypes/IndentDoc.cs index 7979aa1bb..09a933c0d 100644 --- a/Src/CSharpier/DocTypes/IndentDoc.cs +++ b/Src/CSharpier/DocTypes/IndentDoc.cs @@ -3,4 +3,5 @@ namespace CSharpier.DocTypes; internal class IndentDoc : Doc, IHasContents { public Doc Contents { get; set; } = Null; + public bool EnsureIndent { get; set; } } diff --git a/Src/CSharpier/SyntaxPrinter/Token.cs b/Src/CSharpier/SyntaxPrinter/Token.cs index 3334ad6e0..32f24dd9c 100644 --- a/Src/CSharpier/SyntaxPrinter/Token.cs +++ b/Src/CSharpier/SyntaxPrinter/Token.cs @@ -92,20 +92,53 @@ public static Doc PrintLeadingTrivia(SyntaxToken syntaxToken, FormattingContext { var isClosingBrace = syntaxToken.RawSyntaxKind() == SyntaxKind.CloseBraceToken; + var printedTrivia = PrivatePrintLeadingTrivia( + syntaxToken.LeadingTrivia, + context, + skipLastHardline: isClosingBrace + ); + + if (syntaxToken.RawSyntaxKind() != SyntaxKind.CloseBraceToken) + { + return printedTrivia; + } + Doc extraNewLines = Doc.Null; - if (isClosingBrace && syntaxToken.LeadingTrivia.Any(o => o.IsDirective || o.IsComment())) + if (syntaxToken.LeadingTrivia.Any(o => o.IsDirective || o.IsComment())) { extraNewLines = ExtraNewLines.Print(syntaxToken.LeadingTrivia); } - var printedTrivia = PrivatePrintLeadingTrivia( - syntaxToken.LeadingTrivia, - context, - skipLastHardline: isClosingBrace - ); + if ( + syntaxToken.LeadingTrivia.Any( + o => o.RawSyntaxKind() is SyntaxKind.EndRegionDirectiveTrivia + ) + && syntaxToken.LeadingTrivia.All( + o => + o.RawSyntaxKind() + is SyntaxKind.EndOfLineTrivia + or SyntaxKind.WhitespaceTrivia + or SyntaxKind.EndRegionDirectiveTrivia + ) + ) + { + var docs = new List { extraNewLines }; + foreach ( + var trivia in syntaxToken.LeadingTrivia.Where( + o => o.RawSyntaxKind() is SyntaxKind.EndRegionDirectiveTrivia + ) + ) + { + docs.Add(trivia.ToFullString().TrimEnd('\n', '\r')); + docs.Add(Doc.HardLine); + } + docs.RemoveAt(docs.Count - 1); - return isClosingBrace && (printedTrivia != Doc.Null || extraNewLines != Doc.Null) + return Doc.Concat(Doc.EnsureIndent(Doc.Concat(docs)), Doc.HardLine); + } + + return printedTrivia != Doc.Null || extraNewLines != Doc.Null ? Doc.Concat( extraNewLines, Doc.IndentIf(printedTrivia != Doc.Null, printedTrivia), @@ -189,21 +222,14 @@ void AddLeadingComment(CommentType commentType) else if (IsDirective(kind) || IsRegion(kind)) { var triviaText = trivia.ToString(); - if ( - IsRegion(kind) - && x > 0 - && leadingTrivia[x - 1].RawSyntaxKind() == SyntaxKind.WhitespaceTrivia - ) - { - triviaText = leadingTrivia[x - 1] + triviaText; - } docs.Add( // adding two of these to ensure we get a new line when a directive follows a trailing comment Doc.HardLineIfNoPreviousLineSkipBreakIfFirstInGroup, Doc.HardLineIfNoPreviousLineSkipBreakIfFirstInGroup, - Doc.Trim, - Doc.Directive(triviaText), + IsRegion(kind) + ? Doc.Indent(triviaText) + : Doc.Concat(Doc.Trim, Doc.Directive(triviaText)), Doc.HardLineSkipBreakIfFirstInGroup );