From 9ad6857da50d59e9734b881a4e4976811fc6c657 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 27 Mar 2023 16:22:54 +0200 Subject: [PATCH 1/5] Indent cramped record field body if indent_size is low. --- CHANGELOG.md | 5 + .../AlignedMultilineBracketStyleTests.fs | 39 +++++ .../CrampedMultilineBracketStyleTests.fs | 142 +++++++++++++++++- .../Fantomas.Core.Tests.fsproj | 1 + .../Stroustrup/RecordInstanceTests.fs | 46 ++++++ src/Fantomas.Core/CodePrinter.fs | 55 +++++-- 6 files changed, 274 insertions(+), 14 deletions(-) create mode 100644 src/Fantomas.Core.Tests/Stroustrup/RecordInstanceTests.fs diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b78b2047e..2f22272a52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## [Unreleased] + +### Fixed +* Nested multiline record with indent_size = 2. [#2801](https://github.com/fsprojects/fantomas/issues/2801) + ## [6.0.0-alpha-007] - 2023-03-27 ### Changed diff --git a/src/Fantomas.Core.Tests/AlignedMultilineBracketStyleTests.fs b/src/Fantomas.Core.Tests/AlignedMultilineBracketStyleTests.fs index 8752786b19..1aed588631 100644 --- a/src/Fantomas.Core.Tests/AlignedMultilineBracketStyleTests.fs +++ b/src/Fantomas.Core.Tests/AlignedMultilineBracketStyleTests.fs @@ -1593,3 +1593,42 @@ struct // 1 // 5 |} // 6 """ + +[] +let ``multiline field body expression where indent_size = 2`` () = + formatSourceString + false + """ +let handlerFormattedRangeDoc (lines: NamedText, formatted: string, range: FormatSelectionRange) = + let range = + { Start = + { Line = range.StartLine - 1 + Character = range.StartColumn } + End = + { Line = range.EndLine - 1 + Character = range.EndColumn } } + + [| { Range = range; NewText = formatted } |] +""" + { config with IndentSize = 2 } + |> prepend newline + |> should + equal + """ +let handlerFormattedRangeDoc (lines : NamedText, formatted : string, range : FormatSelectionRange) = + let range = + { + Start = + { + Line = range.StartLine - 1 + Character = range.StartColumn + } + End = + { + Line = range.EndLine - 1 + Character = range.EndColumn + } + } + + [| { Range = range ; NewText = formatted } |] +""" diff --git a/src/Fantomas.Core.Tests/CrampedMultilineBracketStyleTests.fs b/src/Fantomas.Core.Tests/CrampedMultilineBracketStyleTests.fs index 4d22cff4e6..ea7900779f 100644 --- a/src/Fantomas.Core.Tests/CrampedMultilineBracketStyleTests.fs +++ b/src/Fantomas.Core.Tests/CrampedMultilineBracketStyleTests.fs @@ -1742,8 +1742,8 @@ let ``record with comments above field, indent 2`` () = equal """ { Foo = - // bar - someValue } + // bar + someValue } """ [] @@ -1799,8 +1799,8 @@ let ``anonymous record with multiline field, indent 2`` () = equal """ {| Foo = - // meh - someValue |} + // meh + someValue |} """ [] @@ -2280,3 +2280,137 @@ let a = // test2 |} """ + +[] +let ``multiline field body expression where indent_size = 2, 2801`` () = + formatSourceString + false + """ +let handlerFormattedRangeDoc (lines: NamedText, formatted: string, range: FormatSelectionRange) = + let range = + { Start = + { Line = range.StartLine - 1 + Character = range.StartColumn } + End = + { Line = range.EndLine - 1 + Character = range.EndColumn } } + + [| { Range = range; NewText = formatted } |] +""" + { config with IndentSize = 2 } + |> prepend newline + |> should + equal + """ +let handlerFormattedRangeDoc (lines: NamedText, formatted: string, range: FormatSelectionRange) = + let range = + { Start = + { Line = range.StartLine - 1 + Character = range.StartColumn } + End = + { Line = range.EndLine - 1 + Character = range.EndColumn } } + + [| { Range = range; NewText = formatted } |] +""" + +[] +let ``multiline field body expression where indent_size = 2, anonymous record`` () = + formatSourceString + false + """ +let handlerFormattedRangeDoc (lines: NamedText, formatted: string, range: FormatSelectionRange) = + let range = + {| Start = + { Line = range.StartLine - 1 + Character = range.StartColumn } + End = + { Line = range.EndLine - 1 + Character = range.EndColumn } |} + + [| { Range = range; NewText = formatted } |] +""" + { config with IndentSize = 2 } + |> prepend newline + |> should + equal + """ +let handlerFormattedRangeDoc (lines: NamedText, formatted: string, range: FormatSelectionRange) = + let range = + {| Start = + { Line = range.StartLine - 1 + Character = range.StartColumn } + End = + { Line = range.EndLine - 1 + Character = range.EndColumn } |} + + [| { Range = range; NewText = formatted } |] +""" + +[] +let ``multiline field body expression where indent_size = 2, update record`` () = + formatSourceString + false + """ +let handlerFormattedRangeDoc (lines: NamedText, formatted: string, range: FormatSelectionRange) = + let range = + { x with + Start = + { Line = range.StartLine - 1 + Character = range.StartColumn } + End = + { Line = range.EndLine - 1 + Character = range.EndColumn } } + + [| { Range = range; NewText = formatted } |] +""" + { config with IndentSize = 2 } + |> prepend newline + |> should + equal + """ +let handlerFormattedRangeDoc (lines: NamedText, formatted: string, range: FormatSelectionRange) = + let range = + { x with + Start = + { Line = range.StartLine - 1 + Character = range.StartColumn } + End = + { Line = range.EndLine - 1 + Character = range.EndColumn } } + + [| { Range = range; NewText = formatted } |] +""" + +let ``multiline field body expression where indent_size = 2, inherit record`` () = + formatSourceString + false + """ +let handlerFormattedRangeDoc (lines: NamedText, formatted: string, range: FormatSelectionRange) = + let range = + { inherit Foo() + Start = + { Line = range.StartLine - 1 + Character = range.StartColumn } + End = + { Line = range.EndLine - 1 + Character = range.EndColumn } } + [| { Range = range; NewText = formatted } |] +""" + { config with IndentSize = 2 } + |> prepend newline + |> should + equal + """ +let handlerFormattedRangeDoc (lines: NamedText, formatted: string, range: FormatSelectionRange) = + let range = + { inherit Foo() + Start = + { Line = range.StartLine - 1 + Character = range.StartColumn } + End = + { Line = range.EndLine - 1 + Character = range.EndColumn } } + + [| { Range = range; NewText = formatted } |] +""" diff --git a/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj b/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj index b0cb713268..f025909343 100644 --- a/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj +++ b/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj @@ -110,6 +110,7 @@ + diff --git a/src/Fantomas.Core.Tests/Stroustrup/RecordInstanceTests.fs b/src/Fantomas.Core.Tests/Stroustrup/RecordInstanceTests.fs new file mode 100644 index 0000000000..7d59783b58 --- /dev/null +++ b/src/Fantomas.Core.Tests/Stroustrup/RecordInstanceTests.fs @@ -0,0 +1,46 @@ +module Fantomas.Core.Tests.Stroustrup.RecordInstanceTests + +open NUnit.Framework +open FsUnit +open Fantomas.Core.Tests.TestHelper +open Fantomas.Core + +let config = + { config with + MultilineBracketStyle = Stroustrup } + +[] +let ``multiline field body expression where indent_size = 2`` () = + formatSourceString + false + """ +let handlerFormattedRangeDoc (lines: NamedText, formatted: string, range: FormatSelectionRange) = + let range = + { Start = + { Line = range.StartLine - 1 + Character = range.StartColumn } + End = + { Line = range.EndLine - 1 + Character = range.EndColumn } } + + [| { Range = range; NewText = formatted } |] +""" + { config with IndentSize = 2 } + |> prepend newline + |> should + equal + """ +let handlerFormattedRangeDoc (lines: NamedText, formatted: string, range: FormatSelectionRange) = + let range = { + Start = { + Line = range.StartLine - 1 + Character = range.StartColumn + } + End = { + Line = range.EndLine - 1 + Character = range.EndColumn + } + } + + [| { Range = range; NewText = formatted } |] +""" diff --git a/src/Fantomas.Core/CodePrinter.fs b/src/Fantomas.Core/CodePrinter.fs index 1e9711bf94..e74db54d99 100644 --- a/src/Fantomas.Core/CodePrinter.fs +++ b/src/Fantomas.Core/CodePrinter.fs @@ -420,7 +420,8 @@ let genExpr (e: Expr) = node let genMultilineInheritRecordExpr = - let fieldsExpr = genMultilineRecordFieldsExpr node + let fieldsExpr genRecordField = + genMultilineRecordFieldsExpr genRecordField node let genInheritInfo = (genSingleTextNode node.InheritConstructor.InheritKeyword @@ -430,7 +431,7 @@ let genExpr (e: Expr) = let genMultilineAlignBrackets = genSingleTextNode node.OpeningBrace - +> indentSepNlnUnindent (genInheritInfo +> fieldsExpr) + +> indentSepNlnUnindent (genInheritInfo +> fieldsExpr genRecordFieldNameAligned) +> sepNln +> genSingleTextNode node.ClosingBrace @@ -439,7 +440,7 @@ let genExpr (e: Expr) = +> addSpaceIfSpaceAroundDelimiter +> atCurrentColumn ( genInheritInfo - +> fieldsExpr + +> fieldsExpr genRecordFieldNameAligned +> addSpaceIfSpaceAroundDelimiter +> genSingleTextNode node.ClosingBrace ) @@ -1567,7 +1568,29 @@ let genMultilineRecordCopyExpr (addAdditionalIndent: bool) fieldsExpr copyExpr = +> onlyIf addAdditionalIndent unindent +> unindent -let genRecordFieldName (node: RecordFieldNode) = +/// Special case for record fields in Cramped mode. +/// The caller should have already verified that the settings do indeed specify Cramped. +let genRecordFieldNameCramped (alreadyIndentedFurther: bool) (node: RecordFieldNode) = + atCurrentColumn ( + enterNode node + +> genIdentListNode node.FieldName + +> sepSpace + +> genSingleTextNode node.Equals + ) + +> (fun ctx -> + // See: https://github.com/fsprojects/fantomas/issues/2801 + let addAdditionIndent = not alreadyIndentedFurther && ctx.Config.IndentSize < 3 + + let genBodyExpr e = + if addAdditionIndent then + sepSpaceOrDoubleIndentAndNlnIfExpressionExceedsPageWidth (genExpr e) + else + sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidth (genExpr e) + + genBodyExpr node.Expr ctx) + +> leaveNode node + +let genRecordFieldNameAligned (node: RecordFieldNode) = atCurrentColumn ( enterNode node +> genIdentListNode node.FieldName @@ -1577,8 +1600,11 @@ let genRecordFieldName (node: RecordFieldNode) = +> sepSpaceOrIndentAndNlnIfExpressionExceedsPageWidthUnlessStroustrup genExpr node.Expr +> leaveNode node -let genMultilineRecordFieldsExpr (node: ExprRecordBaseNode) = - col sepNln node.Fields genRecordFieldName +let genMultilineRecordFieldsExpr + (genRecordField: RecordFieldNode -> Context -> Context) + (node: ExprRecordBaseNode) + : Context -> Context = + col sepNln node.Fields genRecordField /// /// Print a (anonymous) record with additional information as a single line. @@ -1589,7 +1615,13 @@ let genSmallRecordBaseExpr genExtra (node: ExprRecordBaseNode) = genSingleTextNode node.OpeningBrace +> addSpaceIfSpaceAroundDelimiter +> genExtra - +> col sepSemi node.Fields genRecordFieldName + +> col sepSemi node.Fields (fun rf -> + genIdentListNode rf.FieldName + +> sepSpace + +> genSingleTextNode rf.Equals + +> sepSpace + +> genExpr rf.Expr + |> genNode rf) //genRecordFieldNameAligned +> addSpaceIfSpaceAroundDelimiter +> genSingleTextNode node.ClosingBrace @@ -1622,7 +1654,7 @@ let genMultilineRecord (node: ExprRecordNode) (ctx: Context) = openBraceLength) let genMultilineAlignBrackets = - let fieldsExpr = genMultilineRecordFieldsExpr node + let fieldsExpr = genMultilineRecordFieldsExpr genRecordFieldNameAligned node match node.CopyInfo with | Some ci -> @@ -1653,7 +1685,10 @@ let genMultilineRecord (node: ExprRecordNode) (ctx: Context) = // Regular record || ctx.Config.IndentSize < 3 - genMultilineRecordCopyExpr additionalIndent (genMultilineRecordFieldsExpr node) we + genMultilineRecordCopyExpr + additionalIndent + (genMultilineRecordFieldsExpr (genRecordFieldNameCramped additionalIndent) node) + we | None -> fun (ctx: Context) -> col @@ -1663,7 +1698,7 @@ let genMultilineRecord (node: ExprRecordNode) (ctx: Context) = // Add spaces to ensure the record field (incl trivia) starts at the right column. addFixedSpaces targetColumn // Potential indentations will be in relation to the opening curly brace. - +> genRecordFieldName e) + +> genRecordFieldNameCramped false e) ctx match node.CopyInfo with From c30f66a6c07e029c7ebc3e3b83296d1d7daa4518 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 27 Mar 2023 18:52:12 +0200 Subject: [PATCH 2/5] Correct range of inherit keyword and inherit expression. --- .../CrampedMultilineBracketStyleTests.fs | 37 +++++++++++++++++++ src/Fantomas.Core/ASTTransformer.fs | 3 +- src/Fantomas.Core/CodePrinter.fs | 6 +-- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/Fantomas.Core.Tests/CrampedMultilineBracketStyleTests.fs b/src/Fantomas.Core.Tests/CrampedMultilineBracketStyleTests.fs index ea7900779f..0e4ef81157 100644 --- a/src/Fantomas.Core.Tests/CrampedMultilineBracketStyleTests.fs +++ b/src/Fantomas.Core.Tests/CrampedMultilineBracketStyleTests.fs @@ -2414,3 +2414,40 @@ let handlerFormattedRangeDoc (lines: NamedText, formatted: string, range: Format [| { Range = range; NewText = formatted } |] """ + +[] +let ``trivia after opening brace in inherit expression, 2803`` () = + formatSourceString + false + """ +let range = + { // foo + // bar + inherit // reason + Foo() + X = y + Z = + someReallyLongExpressionThatIsLongerThanTheLineLength + aLongArgument + // + anotherLongArgument + fooBar } +""" + config + |> prepend newline + |> should + equal + """ +let range = + { // foo + // bar + inherit // reason + Foo() + X = y + Z = + someReallyLongExpressionThatIsLongerThanTheLineLength + aLongArgument + // + anotherLongArgument + fooBar } +""" diff --git a/src/Fantomas.Core/ASTTransformer.fs b/src/Fantomas.Core/ASTTransformer.fs index 5d0bcb954a..2ef8dc517a 100644 --- a/src/Fantomas.Core/ASTTransformer.fs +++ b/src/Fantomas.Core/ASTTransformer.fs @@ -222,6 +222,7 @@ let mkOpenAndCloseForArrayOrList isArray range = let mkInheritConstructor (creationAide: CreationAide) (t: SynType) (e: SynExpr) (mInherit: range) (m: range) = let inheritNode = stn "inherit" mInherit + let m = unionRanges mInherit m match e with | SynExpr.Const(constant = SynConst.Unit; range = StartEndRange 1 (mOpen, unitRange, mClose)) -> @@ -962,7 +963,7 @@ let mkExpr (creationAide: CreationAide) (e: SynExpr) : Expr = match baseInfo, copyInfo with | Some _, Some _ -> failwith "Unexpected that both baseInfo and copyInfo are present in SynExpr.Record" - | Some(t, e, mInherit, _, m), None -> + | Some(t, e, m, _, mInherit), None -> let inheritCtor = mkInheritConstructor creationAide t e mInherit m ExprInheritRecordNode(stn "{" mOpen, inheritCtor, fieldNodes, stn "}" mClose, exprRange) diff --git a/src/Fantomas.Core/CodePrinter.fs b/src/Fantomas.Core/CodePrinter.fs index e74db54d99..18de5dfa50 100644 --- a/src/Fantomas.Core/CodePrinter.fs +++ b/src/Fantomas.Core/CodePrinter.fs @@ -436,10 +436,10 @@ let genExpr (e: Expr) = +> genSingleTextNode node.ClosingBrace let genMultilineCramped = - genSingleTextNode node.OpeningBrace - +> addSpaceIfSpaceAroundDelimiter + genSingleTextNodeSuffixDelimiter node.OpeningBrace +> atCurrentColumn ( - genInheritInfo + sepNlnWhenWriteBeforeNewlineNotEmpty + +> genInheritInfo +> fieldsExpr genRecordFieldNameAligned +> addSpaceIfSpaceAroundDelimiter +> genSingleTextNode node.ClosingBrace From 9a32b0404b5aef593e35a8fcae117d9bd8d40ec3 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 27 Mar 2023 19:00:44 +0200 Subject: [PATCH 3/5] Correctly indent multiline fields in inherit expression. --- src/Fantomas.Core/CodePrinter.fs | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/Fantomas.Core/CodePrinter.fs b/src/Fantomas.Core/CodePrinter.fs index 18de5dfa50..1ec6ffee3c 100644 --- a/src/Fantomas.Core/CodePrinter.fs +++ b/src/Fantomas.Core/CodePrinter.fs @@ -435,15 +435,27 @@ let genExpr (e: Expr) = +> sepNln +> genSingleTextNode node.ClosingBrace - let genMultilineCramped = - genSingleTextNodeSuffixDelimiter node.OpeningBrace - +> atCurrentColumn ( - sepNlnWhenWriteBeforeNewlineNotEmpty - +> genInheritInfo - +> fieldsExpr genRecordFieldNameAligned - +> addSpaceIfSpaceAroundDelimiter - +> genSingleTextNode node.ClosingBrace - ) + let genMultilineCramped (ctx: Context) = + // This is the column each field should start on. + let targetColumn = + let openBraceLength = node.OpeningBrace.Text.Length + + ctx.Column + + (if ctx.Config.SpaceAroundDelimiter then + openBraceLength + 1 + else + openBraceLength) + + (genSingleTextNodeSuffixDelimiter node.OpeningBrace + +> atCurrentColumn genInheritInfo + +> col sepNln node.Fields (fun e -> + // Add spaces to ensure the record field (incl trivia) starts at the right column. + addFixedSpaces targetColumn + // Potential indentations will be in relation to the opening curly brace. + +> genRecordFieldNameCramped false e) + +> addSpaceIfSpaceAroundDelimiter + +> genSingleTextNode node.ClosingBrace) + ctx ifAlignOrStroustrupBrackets genMultilineAlignBrackets genMultilineCramped From 42035818d123afa2600f163b0297d075b73c290c Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 27 Mar 2023 19:02:26 +0200 Subject: [PATCH 4/5] Add changelog entry. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f22272a52..8abf49b00b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Fixed * Nested multiline record with indent_size = 2. [#2801](https://github.com/fsprojects/fantomas/issues/2801) +* Idempotency problem when comment after opening brace in inherit record. [#2803](https://github.com/fsprojects/fantomas/issues/2803) ## [6.0.0-alpha-007] - 2023-03-27 From fa5a8c80107dcc5df9d3dd85b6ff325b94617843 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 27 Mar 2023 21:18:46 +0200 Subject: [PATCH 5/5] Add new version. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8abf49b00b..979f30120f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [Unreleased] +## [6.0.0-alpha-008] - 2023-03-27 ### Fixed * Nested multiline record with indent_size = 2. [#2801](https://github.com/fsprojects/fantomas/issues/2801)