diff --git a/src/Fantomas.Core.Tests/Stroustrup/SynTypeDefnSimpleReprRecordTests.fs b/src/Fantomas.Core.Tests/Stroustrup/SynTypeDefnSimpleReprRecordTests.fs index e3f735644..0512022cb 100644 --- a/src/Fantomas.Core.Tests/Stroustrup/SynTypeDefnSimpleReprRecordTests.fs +++ b/src/Fantomas.Core.Tests/Stroustrup/SynTypeDefnSimpleReprRecordTests.fs @@ -360,3 +360,27 @@ type Event = Metadata: AssessmentMetadata } """ + +[] +let ``commented-out fields inside record type are indented at field level in Stroustrup mode, 2482`` () = + formatSourceString + """ +type UserInfo = { + UserId: int + AcsId: int + // Roles: Role list + // NetworkStatus: UserStatus +} + """ + config + |> prepend newline + |> should + equal + """ +type UserInfo = { + UserId: int + AcsId: int + // Roles: Role list + // NetworkStatus: UserStatus +} +""" diff --git a/src/Fantomas.Core.Tests/TypeDeclarationTests.fs b/src/Fantomas.Core.Tests/TypeDeclarationTests.fs index 92943e771..4d7ce059e 100644 --- a/src/Fantomas.Core.Tests/TypeDeclarationTests.fs +++ b/src/Fantomas.Core.Tests/TypeDeclarationTests.fs @@ -3692,3 +3692,29 @@ type X // oh dear 23 """ + +[] +let ``commented-out fields inside record type are indented at field level, 2482`` () = + formatSourceString + """ +type UserInfo = + { + UserId: int + AcsId: int + // Roles: Role list + // NetworkStatus: UserStatus + } + """ + config + |> prepend newline + |> should + equal + """ +type UserInfo = + { + UserId: int + AcsId: int + // Roles: Role list + // NetworkStatus: UserStatus + } +""" diff --git a/src/Fantomas.Core/CodePrinter.fs b/src/Fantomas.Core/CodePrinter.fs index f92edf16a..2a4d5fb99 100644 --- a/src/Fantomas.Core/CodePrinter.fs +++ b/src/Fantomas.Core/CodePrinter.fs @@ -3580,10 +3580,34 @@ let genTypeDefn (td: TypeDefn) = let multilineExpression (ctx: Context) = let genRecordFields = + let closingBrace = node.ClosingBrace + genSingleTextNode node.OpeningBrace - +> indentSepNlnUnindent (atCurrentColumn (col sepNln node.Fields genField)) + +> indent +> sepNln - +> genSingleTextNode node.ClosingBrace + +> atCurrentColumn (col sepNln node.Fields genField) + // Write any ContentBefore trivia (e.g., commented-out fields) inside the + // indent block so they align with the record fields rather than the braces. + +> enterNode closingBrace + +> unindent + +> (fun ctx -> + // After writing ContentBefore inside the indent block, the last trivia's + // trailing newline pre-commits a blank line at field-level indent. After + // unindent we fix that blank line to use brace-level indent so that the + // closing brace lands at the correct column. + match ctx.WriterModel.Lines with + | head :: rest when head.Trim() = "" -> + let targetIndent = ctx.WriterModel.Indent + + { ctx with + WriterModel = + { ctx.WriterModel with + Lines = String.replicate targetIndent " " :: rest + Column = targetIndent } } + | _ -> ctx) + +> sepNlnUnlessLastEventIsNewline + +> recordCursorNode (!-closingBrace.Text) closingBrace + +> leaveNode closingBrace let genMembers = onlyIf hasMembers (sepNln +> sepNlnBetweenTypeAndMembers typeDefnNode +> genMemberDefnList members)