From a62219de8c3000f714e00a6e72db35f30d8cf665 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 13 Dec 2021 09:18:38 +0100 Subject: [PATCH 01/33] Bare minimal changes for one test case. --- src/Fantomas.Tests/RecordTests.fs | 22 ++++++++++++++++++++++ src/Fantomas/CodePrinter.fs | 18 +++++++++++++----- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/Fantomas.Tests/RecordTests.fs b/src/Fantomas.Tests/RecordTests.fs index f3bb07693a..d22280970e 100644 --- a/src/Fantomas.Tests/RecordTests.fs +++ b/src/Fantomas.Tests/RecordTests.fs @@ -2020,3 +2020,25 @@ let a = {| Foo = // 2 |} """ + +[] +let ``foobar `` () = + formatSourceString + false + """ +let x = + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + { config with MultilineBlockBracketsOnSameColumn = true } + |> prepend newline + |> should + equal + """ +let x = { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +} +""" diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 319aef4372..b70c115718 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -3025,7 +3025,7 @@ and genMultilineRecordInstanceAlignBrackets +> unindent +> ifElseCtx lastWriteEventIsNewline sepNone sepNln +> genTriviaFor SynExpr_Record_ClosingBrace closingBrace sepCloseSFixed) - |> atCurrentColumnIndent + //|> atCurrentColumnIndent and genMultilineAnonRecord (isStruct: bool) fields copyInfo (astContext: ASTContext) = let recordExpr = @@ -5337,11 +5337,19 @@ and genSynBindingValue let short = prefix +> genExprKeepIndentInBranch astContext e let long = + let isRecord = + match e with + | SynExpr.Record _ -> true + | _ -> false + prefix - +> indent - +> sepNln - +> genExprKeepIndentInBranch astContext e - +> unindent + +> ifElse + isRecord + (genExprKeepIndentInBranch astContext e) + (indent + +> sepNln + +> genExprKeepIndentInBranch astContext e + +> unindent) isShortExpression ctx.Config.MaxValueBindingWidth short long ctx) From 13de66a51a8a77ea8d244147437c32894b31cc11 Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 14 Dec 2021 10:10:04 +0100 Subject: [PATCH 02/33] Initial draft of ragnarok feature. --- docs/ragnarok.md | 342 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 342 insertions(+) create mode 100644 docs/ragnarok.md diff --git a/docs/ragnarok.md b/docs/ragnarok.md new file mode 100644 index 0000000000..cd80fbcf9f --- /dev/null +++ b/docs/ragnarok.md @@ -0,0 +1,342 @@ +# The Ragnarok Feature + +I'm not sure who this document is for right now. These some thoughts and some research about a certain feature that people want in Fantomas. +The feature is about how the code is printed back to source and is a variation on what the style guide advices today. + +I will go in great lengths why this is feature does not bring much value to the overall mission of Fantomas. +Why I consider it inconsistent and why the implementation is far from trivial. +Throughout this document there will be a negative tone toward this and for the initial draft I'm ok with this. +Again, there are no plans to publish this as is. + +## Introduction + +The feature has been request multiple times: +- https://github.com/fsprojects/fantomas/issues/1408 +- https://github.com/fsprojects/fantomas/issues/1225 +- https://github.com/fsprojects/fantomas/issues/453 (in comments) + +The gist is that some multiline expressions should start on the same line to save some space: + +```fsharp +let v = { + X = x + Y = y +} +``` + +The style guides deal with this by putting the entire expression on the next line: + +```fsharp +let v = + { X = x + Y = y } + +// or + +let v = + { + X = x + Y = y + } +``` + +## The inconsistency + +When you dissect the initial sample in AST you get something like: + +```fsharp +ImplFile + (ParsedImplFileInput + ("tmp.fsx", true, QualifiedNameOfFile Tmp$fsx, [], [], + [SynModuleOrNamespace + ([Tmp], false, AnonModule, + [Let + (false, + [SynBinding + (None, Normal, false, false, [], + PreXmlDoc ((1,4), FSharp.Compiler.Xml.XmlDocCollector), + SynValData + (None, SynValInfo ([], SynArgInfo ([], false, None)), None), + Named (v, false, None, tmp.fsx (1,4--1,5)), None, + Record + (None, None, + [((LongIdentWithDots ([X], []), true), Some (Ident x), + Some (tmp.fsx (2,10--3,4), None)); + ((LongIdentWithDots ([Y], []), true), Some (Ident y), None)], + tmp.fsx (1,8--4,1)), tmp.fsx (1,4--1,5), + Yes tmp.fsx (1,0--4,1))], tmp.fsx (1,0--4,1))], PreXmlDocEmpty, + [], None, tmp.fsx (1,0--4,1))], (true, true))) +``` + +or simplified: + +`SynBinding(pat = pat; expr = expr)` + +The `pat` represents the `v` and the `expr` everything after the equals sign. +In Fantomas we adhere to a simple rule, we tried an put everything on one line `let v = { X = ...` and if that crossed a certain threshold (based on a setting), we put the expression on the next line indented. + +Now the ask for the ragnarok setting, is to not do this for a handful of [SynExpr](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html). +There are about 65 union cases for `SynExpr` and for maybe 5 cases, people want to deviate from our currently consistent behavior. + +Of course, the thing is that the formatting of these `SynExpr` depends on the context of where the nodes are in. +Example: + +```fsharp +let v = { + X = x + Y = y +} + +// versus + +let vlist = [ + { X = x + Y = y } + // or + { + X = x + Y = y + } +] +``` + +If `SynExpr.Record` is the `expr` in a `SynBinding`, if would not require a newline after the `=` to start. +If it is part of `SynExpr.ArrayOrListComputed`, it would be following the default rules I guess. +Point is that, the combination of two syntax nodes would lead to a different style and that will occur all over the SyntaxTree. + +## The subjectivity + +As a long term Fantomas user, over time you stop caring about how the code looks like. You accept what is does and letting go of past habits leads to a world of freedom. +People that do not use Fantomas, cannot cope with the fact that the formatted code does differ from their original source. +That is the idea thought, you follow a style guide and your code looks like how the rest of the world does it. + +In any case, as a maintainer, I'm always caught in between giving the people what they want and giving them what they need. +The point I'm trying to make is that there is no right or wrong in the style of code. If you prefer your own handwriting that is fine, but using a typewriter works just as well to bring your story. + +So, asking for a new style without any solid arguments really is a hard sell. People mentioned that this is a popular style and all that jazz but never bring up any numbers. +Nor, do they understand the technical nature of what their preferred style implies. +And lastly, not a single person has engaged the discussion in the MS style guide. This really rubs me the wrong way. +People want something, don't have a solid case, are clueless and don't put in the proper legwork to get somewhere. + +## Scope + +There are many syntax nodes in play for this feature. +Most people only list one example when they ask for this feature, but the realm of the SyntaxTree can be a quite large one. + +### SynExpr + +The `SynExpr` I believe that should be included in this would be: + +- [SynExpr.Record](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#Record) +- [SynExpr.AnonRecd](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#AnonRecd) +- [SynExpr.ComputationExpr](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#ComputationExpr) +- [SynExpr.ArrayOrListComputed](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#ArrayOrListComputed) + +I'm not sure that this list is completed. +Some people might also include [SynExpr.MatchLambda](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#MatchLambda). +And I also wonder about tuples, [SynExpr.Tuple](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#Tuple). + +Note that depending on the information stored in these nodes, they are formatted somewhat differently. + +### SynBinding + +SynBinding is used for let bindings and members: + +```fsharp +let x a b = async { + return a + b +} + +type Foo() = + member this.Bar = {| + bar with X = x + |} +``` + +### LetOrUseBang / YieldOrReturn + +Note that not every time the `let` keyword is used, it leads to a `SynBinding`. +[LetBang](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#LetOrUseBang) for example has a different way of storing information. + +```fsharp +async { + let! a = { + X = x + } +``` + +Perhaps [YieldOrReturn](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#YieldOrReturn) should also be considered to apply this style: + +```fsharp +myComp { + yield { + X = y + } + return { + Y = y + } +} +``` + +and did you know that [YieldReturnFrom](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#YieldOrReturnFrom) is also a thing. + +```fsharp +myComp { + yield! { + X = y + } + return! { + Y = y + } +} +``` + +### LongIdentSet + +[LongIdentSet](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#LongIdentSet) + +```fsharp +myMutable <- { + X = x +} +``` + +### DotIndexedSet + +[DotIndexedSet](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#DotIndexedSet) + +```fsharp +myMutable.[x] <- { + X = x +} +``` + +### Set + +[Set](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#Set) + +```fsharp +myMutable[x] <- { + X = x +} +``` + +New F# 6 syntax. + +### DotSet + +[DotSet](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#DotSet) + +```fsharp +myMutable().foo <- { + X = x +} +``` + +### Lambda + +[Lambda](https://fsprojects.github.io/fantomas-tools/#/ast?data=N4KABGBEAmCmBmBLAdrAzpAXFSAacUiaAYmolmPAIYA2as%2BEkAxgPZwWTwCuyYAHmAC0APjBU0AT2TMwwADoAneXwhhFsAC7dFffkpUBfSCENA) + +```fsharp +fun x -> async { + return x +} +``` + +This is an interesting one as there are quite some rules to format lambda in Fantomas. +There is the raw lambda as you see it above but it is often capture in more elaborate patterns: + +```fsharp +myTasks +|> List.map (fun p -> task { + return p +} +|> Task.WhenAll +``` + +### SynMatchClause + +Used as part of [SynExpr.Match](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#Match) and [SynExpr.MatchBang](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#MatchBang). +[SynMatchClause](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synmatchclause.html). + +```fsharp +match v with +| () -> async { + return FooBar() +} +``` + +### App + +Another very interesting case, where do you draw the line with [SynExpr.App](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#App) + +```fsharp +let v = + foo [ + a + b + c + ] +``` + +This is partially already implemented in the Elmish settings. +However, there are again a lot of possibilities there: + +```fsharp +let v = + foo "string" [ + a + b + c + ] +``` + +this is currently not supported. +When do you draw the line and go over to: + +```fsharp +let v = + foo + "string" + [ a + b + c ] +``` + +? + +### Record type + +- Types +- Anon +- Signature files + +### Patterns + +## Implementation + +## The twist + +Even though this whole thing is a bad idea, like a really bad one, I might be open to it in the future. +There are two things I still wish to achieve in the Fantomas project: +- A better Syntax tree: improvements on the compiler side to simplify Fantomas +- Parallel formatting: formatting certain syntax tree nodes in parallel to speed up things for large files. + +After that, I'm willing to open to what the community wants out of this project. +I might even agreed to the ragnarok feature under very strict conditions. +These obviously would be that the feature is not breaking any existing tests and is not impacting anything else whatsoever. + +I'm also pretty much not going to do this implementation myself unless I'm properly paid for it. +Again, I don't care and this is a bad idea.## The twist + +Even though this whole thing is a bad idea, like a really bad one, I might be open to it in the future. +There are two things I still wish to achieve in the Fantomas project: +- A better Syntax tree: improvements on the compiler side to simplify Fantomas +- Parallel formatting: formatting certain syntax tree nodes in parallel to speed up things for large files. + +After that, I'm willing to open to what the community wants out of this project. +I might even agreed to the ragnarok feature under very strict conditions. +These obviously would be that the feature is not breaking any existing tests and is not impacting anything else whatsoever. + +I'm also pretty much not going to do this implementation myself unless I'm properly paid for it. +Again, I don't care and this is a bad idea. \ No newline at end of file From 7e85edf3d624be3a3431acf8dd79db590a036317 Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 14 Dec 2021 15:05:33 +0100 Subject: [PATCH 03/33] Add more syntax node where the case occurs. --- docs/ragnarok.md | 215 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 193 insertions(+), 22 deletions(-) diff --git a/docs/ragnarok.md b/docs/ragnarok.md index cd80fbcf9f..44c07f86bb 100644 --- a/docs/ragnarok.md +++ b/docs/ragnarok.md @@ -106,7 +106,7 @@ Point is that, the combination of two syntax nodes would lead to a different sty ## The subjectivity -As a long term Fantomas user, over time you stop caring about how the code looks like. You accept what is does and letting go of past habits leads to a world of freedom. +As a long term Fantomas user, over time you stop caring about how the code looks like. You accept what is does and letting go of your past habits leads to a world of freedom. People that do not use Fantomas, cannot cope with the fact that the formatted code does differ from their original source. That is the idea thought, you follow a style guide and your code looks like how the rest of the world does it. @@ -138,6 +138,17 @@ And I also wonder about tuples, [SynExpr.Tuple](https://fsharp.github.io/fsharp- Note that depending on the information stored in these nodes, they are formatted somewhat differently. +### SynPat + +The `SynPat` cases might be: +- [SynPat.Record](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synpat.html#Record) +- [SynPat.ArrayOrList](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synpat.html#ArrayOrList) + +### SynType + +The `SynType` cases might be: +- [SynType.AnonRecd](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-syntype.html#AnonRecd) + ### SynBinding SynBinding is used for let bindings and members: @@ -150,10 +161,10 @@ let x a b = async { type Foo() = member this.Bar = {| bar with X = x - |} + |} // this is quite interesting how the closing brace is indented. ``` -### LetOrUseBang / YieldOrReturn +### LetOrUseBang Note that not every time the `let` keyword is used, it leads to a `SynBinding`. [LetBang](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#LetOrUseBang) for example has a different way of storing information. @@ -165,7 +176,9 @@ async { } ``` -Perhaps [YieldOrReturn](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#YieldOrReturn) should also be considered to apply this style: +### YieldOrReturn + +[YieldOrReturn](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#YieldOrReturn) ```fsharp myComp { @@ -178,7 +191,9 @@ myComp { } ``` -and did you know that [YieldReturnFrom](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#YieldOrReturnFrom) is also a thing. +### YieldReturnFrom + +[YieldReturnFrom](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#YieldOrReturnFrom) ```fsharp myComp { @@ -191,6 +206,20 @@ myComp { } ``` +### SynExprAndBang + +[SynExprAndBang](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexprandbang.html) + +```fsharp +async { + let! x = y + and! z = async { + return! meh + } + () +} +``` + ### LongIdentSet [LongIdentSet](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#LongIdentSet) @@ -250,7 +279,7 @@ There is the raw lambda as you see it above but it is often capture in more elab myTasks |> List.map (fun p -> task { return p -} +}) |> Task.WhenAll ``` @@ -266,6 +295,15 @@ match v with } ``` +Keep in mind that [SynExpr.TryWith](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#TryWith) has this as well: + +```fsharp +try x with +| ex -> async { + () +} +``` + ### App Another very interesting case, where do you draw the line with [SynExpr.App](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#App) @@ -305,36 +343,169 @@ let v = ? -### Record type +#### Named arguments + +Another interesting edge case is named arguments inside applications: + +```fsharp +let v = + SomeConstructor(v = [ + A + B + C + ]) +``` + +Note that the AST for `v = [ ... ]` is something like + +```fsharp +App + (NonAtomic, false, + App + (NonAtomic, true, Ident op_Equality, Ident v, + tmp.fsx (2,20--2,23)), + ArrayOrListComputed + (false, + Sequential + (SuppressNeither, true, Ident A, + Sequential + (SuppressNeither, true, Ident B, Ident C, + tmp.fsx (4,8--5,9)), tmp.fsx (3,8--5,9)), + tmp.fsx (2,24--6,5)), tmp.fsx (2,20--6,5)), +tmp.fsx (2,19--2,20), Some tmp.fsx (6,5--6,6), +tmp.fsx (2,19--6,6) +``` + +so this is hard to detect in the first place. + +### SynExprRecordField + +[SynExprRecordField](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexprrecordfield.html) + +```fsharp +let v = { + X = { + Y = y + } +} +``` + +### Fields in AnonRecords + +[recordFields in AnonRecd](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#AnonRecd) + +```fsharp +let v = {| + X = {| + Y = y + |} +|} +``` -- Types -- Anon -- Signature files +### SynTypeDefnSimpleRepr.Record -### Patterns +[SynTypeDefnSimpleRepr.Record](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-syntypedefnsimplerepr.html#Record) + +```fsharp +type V = { + X :int + Y: int +} +``` + +Note, access modifiers: + +```fsharp +type V = internal { + X :int + Y: int +} +``` + +Members need the `with` keyword: + +```fsharp +type V = { + X :int + Y: int +} with + member this.XY = X + Y +``` + +The current style does not use the `with` keyword, here is would be a requirement. + +This is also being used in [SynTypeDefnSigRepr.Simple](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-syntypedefnsigrepr.html). + +```fsharp +namespace Meh + +type V = { + X :int + Y: int +} with + member XY : int +``` + +### TypeAbbrev + +[SynType.AnonRecd](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-syntype.html#AnonRecd) in [SynTypeDefnSimpleRepr.TypeAbbrev](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-syntypedefnsimplerepr.html#TypeAbbrev). + +```fsharp +type V = {| + x :int +|} +``` + +### SynArgPats.NamePatPairs + +[SynArgPats.NamePatPairs](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synargpats.html#NamePatPairs) + +```fsharp +match x with +| Foo(x = { + Y = y + }) -> + () +``` + +### SynPat.Record + +[fieldPats in SynPat.Record](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synpat.html#Record) + +```fsharp +match x with +| { Y = { + X = y + }} -> + () + +// no idea if this looks ok but you get the idea, after the `Y =` you have the scenario. +``` + +### Even more nodes + +I'm quite certain that the list above is not complete. ## Implementation -## The twist +The impact will be huge in CodePrinter, there are numerous locations where some clever helper function will need to be called in order not to newline. +I do believe that not placing the newline will not be the only thing that is required to make all these examples work. +Having an entirely new implementation for all the impacted nodes is also not recommended. -Even though this whole thing is a bad idea, like a really bad one, I might be open to it in the future. -There are two things I still wish to achieve in the Fantomas project: -- A better Syntax tree: improvements on the compiler side to simplify Fantomas -- Parallel formatting: formatting certain syntax tree nodes in parallel to speed up things for large files. +Some re-use might be possible on the record side by turning on [fsharp_multiline_block_brackets_on_same_column](https://github.com/fsprojects/fantomas/blob/master/docs/Documentation.md#fsharp_multiline_block_brackets_on_same_column). +However, by doing this, a new precedent will be introduced. Two settings need to be combined in order for a valid code to be outputted. +This is unseen for the tool. -After that, I'm willing to open to what the community wants out of this project. -I might even agreed to the ragnarok feature under very strict conditions. -These obviously would be that the feature is not breaking any existing tests and is not impacting anything else whatsoever. +And no battle plan survives first contact. Even if everything above is implemented and it produces no warnings whatsoever, the will more definitely be a case that pops up once this is released in the wild. -I'm also pretty much not going to do this implementation myself unless I'm properly paid for it. -Again, I don't care and this is a bad idea.## The twist +## The twist Even though this whole thing is a bad idea, like a really bad one, I might be open to it in the future. There are two things I still wish to achieve in the Fantomas project: - A better Syntax tree: improvements on the compiler side to simplify Fantomas - Parallel formatting: formatting certain syntax tree nodes in parallel to speed up things for large files. -After that, I'm willing to open to what the community wants out of this project. +After that, I'm willing to open a bit to what the community wants out of this project. I might even agreed to the ragnarok feature under very strict conditions. These obviously would be that the feature is not breaking any existing tests and is not impacting anything else whatsoever. From b31f7be48e93eea1897256e92cbe78842e209502 Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 16 Dec 2021 14:47:52 +0100 Subject: [PATCH 04/33] Maybe multiline strings? --- docs/ragnarok.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/ragnarok.md b/docs/ragnarok.md index 44c07f86bb..18a8001405 100644 --- a/docs/ragnarok.md +++ b/docs/ragnarok.md @@ -136,6 +136,16 @@ I'm not sure that this list is completed. Some people might also include [SynExpr.MatchLambda](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#MatchLambda). And I also wonder about tuples, [SynExpr.Tuple](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#Tuple). +Maybe multiline strings ([SynConst.String](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synconst.html#String) in [SynExpr.Const](https://fsharp.github.io/fsharp-compiler-docs/reference/fsharp-compiler-syntax-synexpr.html#Const)) should also be included: + +```fsharp +let json = """ +{ + "foo":"bar" +} +""" +``` + Note that depending on the information stored in these nodes, they are formatted somewhat differently. ### SynPat From eb39ca159e12aff063ad41e33415d94bf89f2d03 Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 17 Dec 2021 12:04:05 +0100 Subject: [PATCH 05/33] Highlight additional cases in SynBinding. --- docs/ragnarok.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/ragnarok.md b/docs/ragnarok.md index 18a8001405..cf150df86e 100644 --- a/docs/ragnarok.md +++ b/docs/ragnarok.md @@ -174,6 +174,24 @@ type Foo() = |} // this is quite interesting how the closing brace is indented. ``` +Fantomas has different rules depending on the details of the SynBinding. + +```fsharp +let a = { + X = x +} + +// different code path in CodePrinter +let b c = { + X = x +} + +// also a different code path in CodePrinter +let d e : MyRecord = { + X = x +} +``` + ### LetOrUseBang Note that not every time the `let` keyword is used, it leads to a `SynBinding`. From afacd3ac464df33ccd233ee3bf94fa4b12c38bb1 Mon Sep 17 00:00:00 2001 From: nojaf Date: Sun, 19 Dec 2021 18:19:13 +0100 Subject: [PATCH 06/33] Add new setting for ragnarok mode. Take anonymous records in SynBinding into account. --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 1 + src/Fantomas.Tests/RagnarokTests.fs | 99 ++++++++++++++++++++++++ src/Fantomas/CodePrinter.fs | 16 +--- src/Fantomas/Context.fs | 5 ++ src/Fantomas/FormatConfig.fs | 5 ++ src/Fantomas/SourceParser.fs | 6 ++ 6 files changed, 118 insertions(+), 14 deletions(-) create mode 100644 src/Fantomas.Tests/RagnarokTests.fs diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index a93bd910ea..1408a1021a 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -92,6 +92,7 @@ + diff --git a/src/Fantomas.Tests/RagnarokTests.fs b/src/Fantomas.Tests/RagnarokTests.fs new file mode 100644 index 0000000000..3880261280 --- /dev/null +++ b/src/Fantomas.Tests/RagnarokTests.fs @@ -0,0 +1,99 @@ +module Fantomas.Tests.RagnarokTests + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } + +[] +let ``synbinding value with record instance `` () = + formatSourceString + false + """ +let x = + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + config + |> prepend newline + |> should + equal + """ +let x = { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +} +""" + +[] +let ``synbinding function with record instance `` () = + formatSourceString + false + """ +let x y = + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + config + |> prepend newline + |> should + equal + """ +let x y = { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +} +""" + +[] +let ``synbinding value with anonymous record instance `` () = + formatSourceString + false + """ +let x = + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +let x = {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``synbinding value with anonymous record instance struct`` () = + formatSourceString + false + """ +let x = + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +let x = struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" \ No newline at end of file diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index b70c115718..295d900a79 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -3025,7 +3025,6 @@ and genMultilineRecordInstanceAlignBrackets +> unindent +> ifElseCtx lastWriteEventIsNewline sepNone sepNln +> genTriviaFor SynExpr_Record_ClosingBrace closingBrace sepCloseSFixed) - //|> atCurrentColumnIndent and genMultilineAnonRecord (isStruct: bool) fields copyInfo (astContext: ASTContext) = let recordExpr = @@ -3101,7 +3100,7 @@ and genMultilineAnonRecordAlignBrackets (isStruct: bool) fields copyInfo astCont +> sepCloseAnonRecdFixed ifElse isStruct !- "struct " sepNone - +> atCurrentColumnIndent genAnonRecord + +> genAnonRecord and genObjExpr t eio withKeyword bd members ims range (astContext: ASTContext) = // Check the role of the second part of eio @@ -5337,19 +5336,8 @@ and genSynBindingValue let short = prefix +> genExprKeepIndentInBranch astContext e let long = - let isRecord = - match e with - | SynExpr.Record _ -> true - | _ -> false - prefix - +> ifElse - isRecord - (genExprKeepIndentInBranch astContext e) - (indent - +> sepNln - +> genExprKeepIndentInBranch astContext e - +> unindent) + +> autoIndentAndNlnExpressUnlessRagnarok (genExprKeepIndentInBranch astContext) e isShortExpression ctx.Config.MaxValueBindingWidth short long ctx) diff --git a/src/Fantomas/Context.fs b/src/Fantomas/Context.fs index 476c8ffb6b..60b17d5bf8 100644 --- a/src/Fantomas/Context.fs +++ b/src/Fantomas/Context.fs @@ -1311,6 +1311,11 @@ let internal addExtraNewlineIfLeadingWasMultiline leading sepNlnConsideringTrivi +> onlyIf ml sepNlnConsideringTriviaContentBefore +> continuation) +let internal autoIndentAndNlnExpressUnlessRagnarok (f: SynExpr -> Context -> Context) (e: SynExpr) (ctx: Context) = + match e with + | SourceParser.RagnarokExpr e when ctx.Config.Ragnarok -> f e ctx + | _ -> (indent +> sepNln +> f e +> unindent) ctx + type internal ColMultilineItem = | ColMultilineItem of // current expression diff --git a/src/Fantomas/FormatConfig.fs b/src/Fantomas/FormatConfig.fs index b34d600534..d0715bfebb 100644 --- a/src/Fantomas/FormatConfig.fs +++ b/src/Fantomas/FormatConfig.fs @@ -218,6 +218,10 @@ type FormatConfig = [] BarBeforeDiscriminatedUnionDeclaration: bool + [] + [] + Ragnarok: bool + [] [] [] @@ -263,4 +267,5 @@ type FormatConfig = KeepIndentInBranch = false BlankLinesAroundNestedMultilineExpressions = true BarBeforeDiscriminatedUnionDeclaration = false + Ragnarok = false StrictMode = false } diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index 412d1c553c..3c0267b677 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -1857,3 +1857,9 @@ let (|KeepIndentIfThenElse|_|) (e: SynExpr) = else None | _ -> None + +let (|RagnarokExpr|_|) (e: SynExpr) = + match e with + | SynExpr.Record _ + | SynExpr.AnonRecd _ -> Some e + | _ -> None From 1c55145d55139d5491acaf4fdcef9f7bc98fa063 Mon Sep 17 00:00:00 2001 From: nojaf Date: Sun, 19 Dec 2021 19:40:25 +0100 Subject: [PATCH 07/33] Separate test case into multiple files. Implement SynBindingFunction and Expressions. --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 2 + .../SynBindingFunctionExpressionTests.fs | 72 +++++++++++++++++++ .../SynBindingValueExpressionTests.fs} | 24 +------ src/Fantomas/CodePrinter.fs | 7 +- 4 files changed, 81 insertions(+), 24 deletions(-) create mode 100644 src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs rename src/Fantomas.Tests/{RagnarokTests.fs => Ragnarok/SynBindingValueExpressionTests.fs} (76%) diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index 1408a1021a..1a891d15d5 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -93,6 +93,8 @@ + + diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs new file mode 100644 index 0000000000..2118809390 --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs @@ -0,0 +1,72 @@ +module Fantomas.Tests.Ragnarok.SynBindingFunctionExpressionTests + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } + +[] +let ``synbinding function with record instance `` () = + formatSourceString + false + """ +let x y = + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + config + |> prepend newline + |> should + equal + """ +let x y = { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +} +""" + +// TODO: conclude on what should happen here +// This one feels very weird to have `= {` because the pattern is already multiline + +[] +let ``multiline pattern in synbinding, record as expression`` () = + formatSourceString + false + """ +let private addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + { config with MaxLineLength = 80 } + |> prepend newline + |> should + equal + """ +let private addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + { + A = longTypeName + B = someOtherVariable + C = ziggyBarX + } +""" \ No newline at end of file diff --git a/src/Fantomas.Tests/RagnarokTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs similarity index 76% rename from src/Fantomas.Tests/RagnarokTests.fs rename to src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs index 3880261280..1d968283fc 100644 --- a/src/Fantomas.Tests/RagnarokTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs @@ -1,4 +1,4 @@ -module Fantomas.Tests.RagnarokTests +module Fantomas.Tests.Ragnarok.SynBindingValueExpressionTests open NUnit.Framework open FsUnit @@ -31,28 +31,6 @@ let x = { } """ -[] -let ``synbinding function with record instance `` () = - formatSourceString - false - """ -let x y = - { A = longTypeName - B = someOtherVariable - C = ziggyBarX } -""" - config - |> prepend newline - |> should - equal - """ -let x y = { - A = longTypeName - B = someOtherVariable - C = ziggyBarX -} -""" - [] let ``synbinding value with anonymous record instance `` () = formatSourceString diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 295d900a79..3f39827f7c 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -5108,7 +5108,12 @@ and genSynBindingFunction if isMultiline then (indent +> sepNln +> body +> unindent) else - sepSpaceIfShortExpressionOrAddIndentAndNewline ctx.Config.MaxFunctionBindingWidth body + let short = sepSpace +> body + + let long = + autoIndentAndNlnExpressUnlessRagnarok (fun e -> sepSpace +> genExprKeepIndentInBranch astContext e) e + + isShortExpression ctx.Config.MaxFunctionBindingWidth short long (genPreXmlDoc px +> genAttrIsFirstChild From ced9698d53a2d1ff0ea17d25a77999764f53ac55 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 20 Dec 2021 13:50:49 +0100 Subject: [PATCH 08/33] Add support for computation expressions. --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 1 + .../SynBindingFunctionExpressionTests.fs | 42 ++---- ...ndingFunctionLongPatternExpressionTests.fs | 124 ++++++++++++++++++ .../SynBindingValueExpressionTests.fs | 24 +++- src/Fantomas/SourceParser.fs | 4 +- 5 files changed, 163 insertions(+), 32 deletions(-) create mode 100644 src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index 1a891d15d5..87aac1e0aa 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -95,6 +95,7 @@ + diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs index 2118809390..fcaa2db059 100644 --- a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs @@ -31,42 +31,24 @@ let x y = { } """ -// TODO: conclude on what should happen here -// This one feels very weird to have `= {` because the pattern is already multiline - [] -let ``multiline pattern in synbinding, record as expression`` () = +let ``synbinding function with computation expression`` () = formatSourceString false """ -let private addTaskToScheduler - (scheduler: IScheduler) - taskName - taskCron - prio - (task: unit -> unit) - groupName - = - { A = longTypeName - B = someOtherVariable - C = ziggyBarX } +let x y = + task { + // some computation here + () + } """ - { config with MaxLineLength = 80 } + config |> prepend newline |> should equal """ -let private addTaskToScheduler - (scheduler: IScheduler) - taskName - taskCron - prio - (task: unit -> unit) - groupName - = - { - A = longTypeName - B = someOtherVariable - C = ziggyBarX - } -""" \ No newline at end of file +let x y = task { + // some computation here + () +} +""" diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs new file mode 100644 index 0000000000..1862bafc29 --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs @@ -0,0 +1,124 @@ +module Fantomas.Tests.Ragnarok.SynBindingFunctionLongPatternExpressionTests + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } + +// TODO: conclude on what should happen here +// This one feels very weird to have `= {` because the pattern is already multiline + +[] +let ``synbinding function with record`` () = + formatSourceString + false + """ +let private addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + { config with MaxLineLength = 80 } + |> prepend newline + |> should + equal + """ +let private addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + { + A = longTypeName + B = someOtherVariable + C = ziggyBarX + } +""" + +[] +let ``synbinding function with anonymous record`` () = + formatSourceString + false + """ +let private addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + { config with MaxLineLength = 80 } + |> prepend newline + |> should + equal + """ +let private addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} +""" + +[] +let ``synbinding function with computation expression`` () = + formatSourceString + false + """ +let private addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + task { + // some computation here + () + } +""" + { config with MaxLineLength = 80 } + |> prepend newline + |> should + equal + """ +let private addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + task { + // some computation here + () + } +""" \ No newline at end of file diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs index 1d968283fc..948f1f4b63 100644 --- a/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs @@ -74,4 +74,26 @@ let x = struct {| B = someOtherVariable C = ziggyBarX |} -""" \ No newline at end of file +""" + +[] +let ``synbinding value with computation expression`` () = + formatSourceString + false + """ +let t = + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +let t = task { + // some computation here + () +} +""" diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index 3c0267b677..7c102fc366 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -1861,5 +1861,7 @@ let (|KeepIndentIfThenElse|_|) (e: SynExpr) = let (|RagnarokExpr|_|) (e: SynExpr) = match e with | SynExpr.Record _ - | SynExpr.AnonRecd _ -> Some e + | SynExpr.AnonRecd _ + // task { ... } + | SynExpr.App (ExprAtomicFlag.NonAtomic, false, SynExpr.Ident _, SynExpr.ComputationExpr _, _) -> Some e | _ -> None From b57d54e0415fb372fbfcaadd559ec1b017f3e1ce Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 20 Dec 2021 14:29:39 +0100 Subject: [PATCH 09/33] Add support for Array/List in SynBinding value/function. --- .../SynBindingFunctionExpressionTests.fs | 74 ++++++++++++++++ ...ndingFunctionLongPatternExpressionTests.fs | 88 +++++++++++++++++-- .../SynBindingValueExpressionTests.fs | 79 +++++++++++++++++ src/Fantomas/SourceParser.fs | 3 +- 4 files changed, 238 insertions(+), 6 deletions(-) diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs index fcaa2db059..44d719744d 100644 --- a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs @@ -31,6 +31,28 @@ let x y = { } """ +[] +let ``synbinding function with anonymous record instance `` () = + formatSourceString + false + """ +let x y = + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +let x y = {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + [] let ``synbinding function with computation expression`` () = formatSourceString @@ -52,3 +74,55 @@ let x y = task { () } """ + +[] +let ``synbinding value with list`` () = + formatSourceString + false + """ +let x y = + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +let x y = [ + itemOne + itemTwo + itemThree + itemFour + itemFive +] +""" + +[] +let ``synbinding value with array`` () = + formatSourceString + false + """ +let x y = + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +let x y = [| + itemOne + itemTwo + itemThree + itemFour + itemFive +|] +""" diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs index 1862bafc29..69df8504dd 100644 --- a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs @@ -6,12 +6,12 @@ open Fantomas.Tests.TestHelper let config = { config with + MaxLineLength = 80 MultilineBlockBracketsOnSameColumn = true Ragnarok = true } // TODO: conclude on what should happen here // This one feels very weird to have `= {` because the pattern is already multiline - [] let ``synbinding function with record`` () = formatSourceString @@ -29,7 +29,7 @@ let private addTaskToScheduler B = someOtherVariable C = ziggyBarX } """ - { config with MaxLineLength = 80 } + config |> prepend newline |> should equal @@ -66,7 +66,7 @@ let private addTaskToScheduler B = someOtherVariable C = ziggyBarX |} """ - { config with MaxLineLength = 80 } + config |> prepend newline |> should equal @@ -104,7 +104,7 @@ let private addTaskToScheduler () } """ - { config with MaxLineLength = 80 } + config |> prepend newline |> should equal @@ -121,4 +121,82 @@ let private addTaskToScheduler // some computation here () } -""" \ No newline at end of file +""" + +[] +let ``synbinding value with list`` () = + formatSourceString + false + """ +let private addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +let private addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + +[] +let ``synbinding value with array`` () = + formatSourceString + false + """ +let private addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +let private addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs index 948f1f4b63..af03ac88ff 100644 --- a/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs @@ -97,3 +97,82 @@ let t = task { () } """ + +[] +let ``synbinding value with list`` () = + formatSourceString + false + """ +let t = + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +let t = [ + itemOne + itemTwo + itemThree + itemFour + itemFive +] +""" + +[] +let ``synbinding value with array`` () = + formatSourceString + false + """ +let t = + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +let t = [| + itemOne + itemTwo + itemThree + itemFour + itemFive +|] +""" + +[] +let ``nested synbinding value with record`` () = + formatSourceString + false + """ +let outer = + let inner = + { + X = someGreatXValue + Y = someRatherSmallYValue + } + () +""" + config + |> prepend newline + |> should + equal + """ +let outer = + let inner = { + X = someGreatXValue + Y = someRatherSmallYValue + } + + () +""" diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index 7c102fc366..3054e87bac 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -1863,5 +1863,6 @@ let (|RagnarokExpr|_|) (e: SynExpr) = | SynExpr.Record _ | SynExpr.AnonRecd _ // task { ... } - | SynExpr.App (ExprAtomicFlag.NonAtomic, false, SynExpr.Ident _, SynExpr.ComputationExpr _, _) -> Some e + | SynExpr.App (ExprAtomicFlag.NonAtomic, false, SynExpr.Ident _, SynExpr.ComputationExpr _, _) + | ArrayOrList _ -> Some e | _ -> None From b4625c9e541770a61f89a6edca89f9d8d55bd300 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 20 Dec 2021 17:33:42 +0100 Subject: [PATCH 10/33] Exclude update records. --- .../SynBindingFunctionExpressionTests.fs | 23 ++++++- ...ndingFunctionLongPatternExpressionTests.fs | 61 +++++++++++++++---- .../SynBindingValueExpressionTests.fs | 19 ++++++ src/Fantomas/SourceParser.fs | 2 + 4 files changed, 91 insertions(+), 14 deletions(-) diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs index 44d719744d..f9f38d5f3e 100644 --- a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs @@ -76,7 +76,7 @@ let x y = task { """ [] -let ``synbinding value with list`` () = +let ``synbinding function with list`` () = formatSourceString false """ @@ -102,7 +102,7 @@ let x y = [ """ [] -let ``synbinding value with array`` () = +let ``synbinding function with array`` () = formatSourceString false """ @@ -126,3 +126,22 @@ let x y = [| itemFive |] """ + +[] +let ``synbinding function with update record`` () = + formatSourceString + false + """ +let x y = + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +let x y = + { astContext with + IsInsideMatchClausePattern = true + } +""" diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs index 69df8504dd..2a281607c5 100644 --- a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs @@ -124,7 +124,7 @@ let private addTaskToScheduler """ [] -let ``synbinding value with list`` () = +let ``synbinding function with list`` () = formatSourceString false """ @@ -155,15 +155,17 @@ let private addTaskToScheduler (task: unit -> unit) groupName = - [ itemOne - itemTwo - itemThree - itemFour - itemFive ] + [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] """ [] -let ``synbinding value with array`` () = +let ``synbinding function with array`` () = formatSourceString false """ @@ -194,9 +196,44 @@ let private addTaskToScheduler (task: unit -> unit) groupName = - [| itemOne - itemTwo - itemThree - itemFour - itemFive |] + [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |] +""" + +[] +let ``synbinding function with update record`` () = + formatSourceString + false + """ +let private addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +let private addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + { astContext with + IsInsideMatchClausePattern = true + } """ diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs index af03ac88ff..b9b42dbafa 100644 --- a/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs @@ -176,3 +176,22 @@ let outer = () """ + +[] +let ``synbinding value with update record`` () = + formatSourceString + false + """ +let astCtx = + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +let astCtx = + { astContext with + IsInsideMatchClausePattern = true + } +""" diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index 3054e87bac..a27b6f8d6c 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -1860,6 +1860,8 @@ let (|KeepIndentIfThenElse|_|) (e: SynExpr) = let (|RagnarokExpr|_|) (e: SynExpr) = match e with + // { foo with Bar = bar } + | SynExpr.Record(copyInfo = Some _) -> None | SynExpr.Record _ | SynExpr.AnonRecd _ // task { ... } From 7c3edabbf5bd1f5f70da7b89680f8fd9ef27cb8e Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 20 Dec 2021 21:33:34 +0100 Subject: [PATCH 11/33] Synbinding function with return type. --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 1 + ...ngFunctionWithReturnTypeExpressionTests.fs | 147 ++++++++++++++++++ src/Fantomas/CodePrinter.fs | 7 +- 3 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 src/Fantomas.Tests/Ragnarok/SynBindingFunctionWithReturnTypeExpressionTests.fs diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index 87aac1e0aa..9b52f11156 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -96,6 +96,7 @@ + diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionWithReturnTypeExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionWithReturnTypeExpressionTests.fs new file mode 100644 index 0000000000..e0ace9155c --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionWithReturnTypeExpressionTests.fs @@ -0,0 +1,147 @@ +module Fantomas.Tests.Ragnarok.SynBindingFunctionWithReturnTypeExpressionTests + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } + +[] +let ``synbinding function with record instance `` () = + formatSourceString + false + """ +let x y : MyRecord = + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + config + |> prepend newline + |> should + equal + """ +let x y : MyRecord = { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +} +""" + +[] +let ``synbinding function with anonymous record instance `` () = + formatSourceString + false + """ +let x y : {| A:int; B:int; C:int |} = + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +let x y : {| A: int; B: int; C: int |} = {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``synbinding function with computation expression`` () = + formatSourceString + false + """ +let x y: Task = + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +let x y : Task = task { + // some computation here + () +} +""" + +[] +let ``synbinding function with list`` () = + formatSourceString + false + """ +let x y : int list = + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +let x y : int list = [ + itemOne + itemTwo + itemThree + itemFour + itemFive +] +""" + +[] +let ``synbinding function with array`` () = + formatSourceString + false + """ +let x y : int array = + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +let x y : int array = [| + itemOne + itemTwo + itemThree + itemFour + itemFive +|] +""" + +[] +let ``synbinding function with update record`` () = + formatSourceString + false + """ +let x y : MyRecord = + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +let x y : MyRecord = + { astContext with + IsInsideMatchClausePattern = true + } +""" diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 3f39827f7c..09d620ae62 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -5221,7 +5221,12 @@ and genSynBindingFunctionWithReturnType if isMultiline then (indent +> sepNln +> body +> unindent) else - sepSpaceIfShortExpressionOrAddIndentAndNewline ctx.Config.MaxFunctionBindingWidth body + let short = sepSpace +> body + + let long = + autoIndentAndNlnExpressUnlessRagnarok (fun e -> sepSpace +> genExprKeepIndentInBranch astContext e) e + + isShortExpression ctx.Config.MaxFunctionBindingWidth short long (genPreXmlDoc px +> genAttrIsFirstChild From df8dbf552080eacfd6e49af36bb0bdded7aeb375 Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 21 Dec 2021 11:55:17 +0100 Subject: [PATCH 12/33] Add additional tests for type members. --- .../SynBindingFunctionExpressionTests.fs | 185 +++++++++- ...ndingFunctionLongPatternExpressionTests.fs | 321 ++++++++++++++++-- ...ngFunctionWithReturnTypeExpressionTests.fs | 185 +++++++++- .../SynBindingValueExpressionTests.fs | 185 +++++++++- 4 files changed, 837 insertions(+), 39 deletions(-) diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs index f9f38d5f3e..dd77e85de5 100644 --- a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs @@ -31,6 +31,25 @@ let x y = { } """ +[] +let ``synbinding function with update record`` () = + formatSourceString + false + """ +let x y = + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +let x y = + { astContext with + IsInsideMatchClausePattern = true + } +""" + [] let ``synbinding function with anonymous record instance `` () = formatSourceString @@ -128,20 +147,174 @@ let x y = [| """ [] -let ``synbinding function with update record`` () = +let ``type member function with record instance`` () = formatSourceString false """ -let x y = - { astContext with IsInsideMatchClausePattern = true } +type Foo() = + member this.Bar x = + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } """ config |> prepend newline |> should equal """ -let x y = - { astContext with - IsInsideMatchClausePattern = true +type Foo() = + member this.Bar x = { + A = longTypeName + B = someOtherVariable + C = ziggyBarX + } +""" + +[] +let ``type member function with update record`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar x = { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar x = + { astContext with + IsInsideMatchClausePattern = true + } +""" + +[] +let ``type member function with anonymous record instance`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar x = + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar x = {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} +""" + +[] +let ``type member function with anonymous record instance struct`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar x = + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar x = struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} +""" + +[] +let ``type member function with computation expression`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar x = + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar x = task { + // some computation here + () } """ + +[] +let ``type member function with list`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar x = + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar x = [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] +""" + +[] +let ``type member function with array`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar x = + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar x = [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |] +""" diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs index 2a281607c5..255d9f8211 100644 --- a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs @@ -49,6 +49,40 @@ let private addTaskToScheduler } """ +[] +let ``synbinding function with update record`` () = + formatSourceString + false + """ +let private addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +let private addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + { astContext with + IsInsideMatchClausePattern = true + } +""" + + [] let ``synbinding function with anonymous record`` () = formatSourceString @@ -205,35 +239,280 @@ let private addTaskToScheduler |] """ + [] -let ``synbinding function with update record`` () = +let ``type member function with record instance`` () = formatSourceString false """ -let private addTaskToScheduler - (scheduler: IScheduler) - taskName - taskCron - prio - (task: unit -> unit) - groupName - = - { astContext with IsInsideMatchClausePattern = true } +type Foo() = + member this.addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } """ config |> prepend newline |> should equal """ -let private addTaskToScheduler - (scheduler: IScheduler) - taskName - taskCron - prio - (task: unit -> unit) - groupName - = - { astContext with - IsInsideMatchClausePattern = true - } +type Foo() = + member this.addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + { + A = longTypeName + B = someOtherVariable + C = ziggyBarX + } +""" + +[] +let ``type member function with update record`` () = + formatSourceString + false + """ +type Foo() = + member this.addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + { astContext with + IsInsideMatchClausePattern = true + } +""" + +[] +let ``type member function with anonymous record instance`` () = + formatSourceString + false + """ +type Foo() = + member this.addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} +""" + +[] +let ``type member function with anonymous record instance struct`` () = + formatSourceString + false + """ +type Foo() = + member this.addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} +""" + +[] +let ``type member function with computation expression`` () = + formatSourceString + false + """ +type Foo() = + member this.addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + task { + // some computation here + () + } +""" + +[] +let ``type member function with list`` () = + formatSourceString + false + """ +type Foo() = + member this.addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] +""" + +[] +let ``type member function with array`` () = + formatSourceString + false + """ +type Foo() = + member this.addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.addTaskToScheduler + (scheduler: IScheduler) + taskName + taskCron + prio + (task: unit -> unit) + groupName + = + [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |] """ diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionWithReturnTypeExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionWithReturnTypeExpressionTests.fs index e0ace9155c..c4167d2557 100644 --- a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionWithReturnTypeExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionWithReturnTypeExpressionTests.fs @@ -31,6 +31,25 @@ let x y : MyRecord = { } """ +[] +let ``synbinding function with update record`` () = + formatSourceString + false + """ +let x y : MyRecord = + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +let x y : MyRecord = + { astContext with + IsInsideMatchClausePattern = true + } +""" + [] let ``synbinding function with anonymous record instance `` () = formatSourceString @@ -128,20 +147,174 @@ let x y : int array = [| """ [] -let ``synbinding function with update record`` () = +let ``type member function with record instance`` () = formatSourceString false """ -let x y : MyRecord = - { astContext with IsInsideMatchClausePattern = true } +type Foo() = + member this.Bar x : MyRecord = + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } """ config |> prepend newline |> should equal """ -let x y : MyRecord = - { astContext with - IsInsideMatchClausePattern = true +type Foo() = + member this.Bar x : MyRecord = { + A = longTypeName + B = someOtherVariable + C = ziggyBarX + } +""" + +[] +let ``type member function with update record`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar x : MyRecord = { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar x : MyRecord = + { astContext with + IsInsideMatchClausePattern = true + } +""" + +[] +let ``type member function with anonymous record instance`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar x : {| A:int; B:int; C:int |} = + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar x : {| A: int; B: int; C: int |} = {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} +""" + +[] +let ``type member function with anonymous record instance struct`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar x : {| A:int; B:int; C:int |} = + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar x : {| A: int; B: int; C: int |} = struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} +""" + +[] +let ``type member function with computation expression`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar x : Task = + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar x : Task = task { + // some computation here + () } """ + +[] +let ``type member function with list`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar x : int list = + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar x : int list = [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] +""" + +[] +let ``type member function with array`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar x : int array = + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar x : int array = [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |] +""" diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs index b9b42dbafa..2fdc0cd280 100644 --- a/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs @@ -31,6 +31,25 @@ let x = { } """ +[] +let ``synbinding value with update record`` () = + formatSourceString + false + """ +let astCtx = + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +let astCtx = + { astContext with + IsInsideMatchClausePattern = true + } +""" + [] let ``synbinding value with anonymous record instance `` () = formatSourceString @@ -178,20 +197,174 @@ let outer = """ [] -let ``synbinding value with update record`` () = +let ``type member value with record instance`` () = formatSourceString false """ -let astCtx = - { astContext with IsInsideMatchClausePattern = true } +type Foo() = + member this.Bar = + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } """ config |> prepend newline |> should equal """ -let astCtx = - { astContext with - IsInsideMatchClausePattern = true +type Foo() = + member this.Bar = { + A = longTypeName + B = someOtherVariable + C = ziggyBarX } """ + +[] +let ``type member value with update record`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar = { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar = + { astContext with + IsInsideMatchClausePattern = true + } +""" + +[] +let ``type member value with anonymous record instance`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar = + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar = {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} +""" + +[] +let ``type member value with anonymous record instance struct`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar = + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar = struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} +""" + +[] +let ``type member value with computation expression`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar = + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar = task { + // some computation here + () + } +""" + +[] +let ``type member value with list`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar = + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar = [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] +""" + +[] +let ``type member value with array`` () = + formatSourceString + false + """ +type Foo() = + member this.Bar = + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +type Foo() = + member this.Bar = [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |] +""" From ec08f64bf0df3c049756e84f69a8d8c25afe032d Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 21 Dec 2021 17:48:12 +0100 Subject: [PATCH 13/33] Add LetOrUseBang with Expression. --- docs/ragnarok.md | 5 +- src/Fantomas.Tests/Fantomas.Tests.fsproj | 2 +- .../Ragnarok/LetOrUseBangExpression.fs | 226 ++++++++++++++++++ .../SynBindingValueExpressionTests.fs | 2 +- src/Fantomas/CodePrinter.fs | 2 +- src/Fantomas/Context.fs | 9 + 6 files changed, 242 insertions(+), 4 deletions(-) create mode 100644 src/Fantomas.Tests/Ragnarok/LetOrUseBangExpression.fs diff --git a/docs/ragnarok.md b/docs/ragnarok.md index cf150df86e..8dc0b151d2 100644 --- a/docs/ragnarok.md +++ b/docs/ragnarok.md @@ -1,12 +1,13 @@ # The Ragnarok Feature -I'm not sure who this document is for right now. These some thoughts and some research about a certain feature that people want in Fantomas. +I'm not sure who this document is for right now. These are some thoughts and some research about a certain feature that people want in Fantomas. The feature is about how the code is printed back to source and is a variation on what the style guide advices today. I will go in great lengths why this is feature does not bring much value to the overall mission of Fantomas. Why I consider it inconsistent and why the implementation is far from trivial. Throughout this document there will be a negative tone toward this and for the initial draft I'm ok with this. Again, there are no plans to publish this as is. +Oh and typos all over the place. ## Introduction @@ -202,6 +203,8 @@ async { let! a = { X = x } + () +} ``` ### YieldOrReturn diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index 9b52f11156..338e6b0662 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -92,11 +92,11 @@ - + diff --git a/src/Fantomas.Tests/Ragnarok/LetOrUseBangExpression.fs b/src/Fantomas.Tests/Ragnarok/LetOrUseBangExpression.fs new file mode 100644 index 0000000000..8fb28373ac --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/LetOrUseBangExpression.fs @@ -0,0 +1,226 @@ +module Fantomas.Tests.Ragnarok.LetOrUseBangExpression + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } + +[] +let ``letOrUseBang with record instance`` () = + formatSourceString + false + """ +opt { + let! foo = + { X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree } + + () +} +""" + config + |> prepend newline + |> should + equal + """ +opt { + let! foo = { + X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree + } + + () +} +""" + +[] +let ``letOrUseBang with update record`` () = + formatSourceString + false + """ +opt { + let! foo = + { bar with X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree } + + () +} +""" + config + |> prepend newline + |> should + equal + """ +opt { + let! foo = + { bar with + X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree + } + + () +} +""" + +[] +let ``letOrUseBang with anonymous record instance`` () = + formatSourceString + false + """ +opt { + let! foo = + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} + + () +} +""" + config + |> prepend newline + |> should + equal + """ +opt { + let! foo = {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} + + () +} +""" + +[] +let ``letOrUseBang with anonymous record instance struct`` () = + formatSourceString + false + """ +opt { + let! foo = + struct {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} + + () +} +""" + config + |> prepend newline + |> should + equal + """ +opt { + let! foo = struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} + + () +} +""" + +[] +let ``letOrUseBang with computation expression`` () = + formatSourceString + false + """ +task { + let! meh = + task { + // comment + return 42 + } + () +} +""" + config + |> prepend newline + |> should + equal + """ +task { + let! meh = task { + // comment + return 42 + } + + () +} +""" + +[] +let ``letOrUseBang with list`` () = + formatSourceString + false + """ +collect { + let! items = + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] + return items +} +""" + config + |> prepend newline + |> should + equal + """ +collect { + let! items = [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] + + return items +} +""" + +[] +let ``letOrUseBang with array`` () = + formatSourceString + false + """ +collect { + let! items = + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] + return items +} +""" + config + |> prepend newline + |> should + equal + """ +collect { + let! items = [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |] + + return items +} +""" \ No newline at end of file diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs index 2fdc0cd280..98c2c7f923 100644 --- a/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs @@ -51,7 +51,7 @@ let astCtx = """ [] -let ``synbinding value with anonymous record instance `` () = +let ``synbinding value with anonymous record instance`` () = formatSourceString false """ diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 09d620ae62..a2af5957f8 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -1477,7 +1477,7 @@ and genExpr astContext synExpr ctx = +> genPat astContext pat +> genEq SynExpr_LetOrUseBang_Equals equalsRange +> sepSpace - +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext expr) + +> autoIndentAndNlnIfExpressionExceedsPageWidthUnlessRagnarok (genExpr astContext) expr | AndBangStatement (pat, equalsRange, expr, range) -> !- "and! " +> genPat astContext pat diff --git a/src/Fantomas/Context.fs b/src/Fantomas/Context.fs index 60b17d5bf8..93eca3d725 100644 --- a/src/Fantomas/Context.fs +++ b/src/Fantomas/Context.fs @@ -1316,6 +1316,15 @@ let internal autoIndentAndNlnExpressUnlessRagnarok (f: SynExpr -> Context -> Con | SourceParser.RagnarokExpr e when ctx.Config.Ragnarok -> f e ctx | _ -> (indent +> sepNln +> f e +> unindent) ctx +let internal autoIndentAndNlnIfExpressionExceedsPageWidthUnlessRagnarok + (f: SynExpr -> Context -> Context) + (e: SynExpr) + (ctx: Context) + = + match e with + | SourceParser.RagnarokExpr e when ctx.Config.Ragnarok -> f e ctx + | _ -> autoIndentAndNlnIfExpressionExceedsPageWidth (f e) ctx + type internal ColMultilineItem = | ColMultilineItem of // current expression From 0fc3d997476cef89241223b94a8e6cdc663917ac Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 21 Dec 2021 18:52:04 +0100 Subject: [PATCH 14/33] Add YieldOrReturn with Expression. --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 1 + .../Ragnarok/YieldOrReturnExpression.fs | 281 ++++++++++++++++++ src/Fantomas/CodePrinter.fs | 12 +- 3 files changed, 293 insertions(+), 1 deletion(-) create mode 100644 src/Fantomas.Tests/Ragnarok/YieldOrReturnExpression.fs diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index 338e6b0662..1667b75094 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -97,6 +97,7 @@ + diff --git a/src/Fantomas.Tests/Ragnarok/YieldOrReturnExpression.fs b/src/Fantomas.Tests/Ragnarok/YieldOrReturnExpression.fs new file mode 100644 index 0000000000..7050ec3e82 --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/YieldOrReturnExpression.fs @@ -0,0 +1,281 @@ +module Fantomas.Tests.Ragnarok.YieldOrReturnExpression + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } + +[] +let ``yieldOrReturn with record instance`` () = + formatSourceString + false + """ +myComp { + yield + { X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree } + return + { X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree } +} +""" + config + |> prepend newline + |> should + equal + """ +myComp { + yield { + X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree + } + + return { + X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree + } +} +""" + +[] +let ``yieldOrReturn with update record`` () = + formatSourceString + false + """ +myComp { + yield + { bar with X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree } + return + { bar with X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree } +} +""" + config + |> prepend newline + |> should + equal + """ +myComp { + yield + { bar with + X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree + } + + return + { bar with + X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree + } +} +""" + +[] +let ``yieldOrReturn with anonymous record instance`` () = + formatSourceString + false + """ +myComp { + yield + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} + return + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +} +""" + config + |> prepend newline + |> should + equal + """ +myComp { + yield {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} + + return {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} +} +""" + +[] +let ``yieldOrReturn with anonymous record instance struct`` () = + formatSourceString + false + """ +myComp { + yield + struct {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} + return + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +} +""" + config + |> prepend newline + |> should + equal + """ +myComp { + yield struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} + + return struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} +} +""" + +[] +let ``yieldOrReturn with computation expression`` () = + formatSourceString + false + """ +myComp { + yield + seq { + // meh + return 0 .. 2 + } + return + seq { + // meh + return 0 .. 2 + } +} +""" + config + |> prepend newline + |> should + equal + """ +myComp { + yield seq { + // meh + return 0..2 + } + + return seq { + // meh + return 0..2 + } +} +""" + +[] +let ``yieldOrReturn with list`` () = + formatSourceString + false + """ +myComp { + yield + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] + return + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +} +""" + config + |> prepend newline + |> should + equal + """ +myComp { + yield [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] + + return [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] +} +""" + +[] +let ``yieldOrReturn with array`` () = + formatSourceString + false + """ +myComp { + yield + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] + return + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +} +""" + config + |> prepend newline + |> should + equal + """ +myComp { + yield [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |] + + return [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |] +} +""" \ No newline at end of file diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index a2af5957f8..42bebdb23f 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -1220,6 +1220,15 @@ and genExpr astContext synExpr ctx = +> ifElse isInfixExpr genInfixExpr genNonInfixExpr | SingleExpr (kind, e) -> + let mapping = + (match kind with + | YieldFrom _ + | Yield _ + | Return _ + | ReturnFrom _ + | Do _ + | DoBang _ -> autoIndentAndNlnIfExpressionExceedsPageWidthUnlessRagnarok (genExpr astContext) e + | _ -> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e)) match kind with | InferredDowncast downcastKeyword -> genTriviaFor SynExpr_InferredDowncast_Downcast downcastKeyword !- "downcast " @@ -1236,7 +1245,8 @@ and genExpr astContext synExpr ctx = | Do doKeyword -> genTriviaFor SynExpr_Do_Do doKeyword !- "do " | DoBang doBangKeyword -> genTriviaFor SynExpr_DoBang_DoBang doBangKeyword !- "do! " | Fixed fixedKeyword -> genTriviaFor SynExpr_Fixed_Fixed fixedKeyword !- "fixed " - +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e) + +> mapping + | ConstExpr (c, r) -> genConst c r | NullExpr -> !- "null" // Not sure about the role of e1 From 6d81bf52506852ef517425cffc43dd881c13d540 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 22 Dec 2021 08:32:55 +0100 Subject: [PATCH 15/33] Add YieldOrReturnBang with Expression. --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 1 + .../Ragnarok/YieldOrReturnBangExpression.fs | 281 ++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100644 src/Fantomas.Tests/Ragnarok/YieldOrReturnBangExpression.fs diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index 1667b75094..2c8ae2ca54 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -98,6 +98,7 @@ + diff --git a/src/Fantomas.Tests/Ragnarok/YieldOrReturnBangExpression.fs b/src/Fantomas.Tests/Ragnarok/YieldOrReturnBangExpression.fs new file mode 100644 index 0000000000..487af7242a --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/YieldOrReturnBangExpression.fs @@ -0,0 +1,281 @@ +module Fantomas.Tests.Ragnarok.YieldOrReturnBangExpression + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } + +[] +let ``yieldOrReturnBang with record instance`` () = + formatSourceString + false + """ +myComp { + yield! + { X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree } + return! + { X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree } +} +""" + config + |> prepend newline + |> should + equal + """ +myComp { + yield! { + X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree + } + + return! { + X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree + } +} +""" + +[] +let ``yieldOrReturnBang with update record`` () = + formatSourceString + false + """ +myComp { + yield! + { bar with X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree } + return! + { bar with X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree } +} +""" + config + |> prepend newline + |> should + equal + """ +myComp { + yield! + { bar with + X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree + } + + return! + { bar with + X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree + } +} +""" + +[] +let ``yieldOrReturnBang with anonymous record instance`` () = + formatSourceString + false + """ +myComp { + yield! + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} + return! + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +} +""" + config + |> prepend newline + |> should + equal + """ +myComp { + yield! {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} + + return! {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} +} +""" + +[] +let ``yieldOrReturnBang with anonymous record instance struct`` () = + formatSourceString + false + """ +myComp { + yield! + struct {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} + return! + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +} +""" + config + |> prepend newline + |> should + equal + """ +myComp { + yield! struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} + + return! struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} +} +""" + +[] +let ``yieldOrReturnBang with computation expression`` () = + formatSourceString + false + """ +myComp { + yield! + seq { + // meh + return 0 .. 2 + } + return! + seq { + // meh + return 0 .. 2 + } +} +""" + config + |> prepend newline + |> should + equal + """ +myComp { + yield! seq { + // meh + return 0..2 + } + + return! seq { + // meh + return 0..2 + } +} +""" + +[] +let ``yieldOrReturnBang with list`` () = + formatSourceString + false + """ +myComp { + yield! + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] + return! + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +} +""" + config + |> prepend newline + |> should + equal + """ +myComp { + yield! [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] + + return! [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] +} +""" + +[] +let ``yieldOrReturnBang with array`` () = + formatSourceString + false + """ +myComp { + yield! + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] + return! + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +} +""" + config + |> prepend newline + |> should + equal + """ +myComp { + yield! [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |] + + return! [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |] +} +""" From fc2d40dde7ec13a31d554405cb6cb3588acf43ed Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 22 Dec 2021 08:41:20 +0100 Subject: [PATCH 16/33] Add SynExprAndBang with Expression. --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 1 + .../Ragnarok/SynExprAndBangExpression.fs | 248 ++++++++++++++++++ src/Fantomas/CodePrinter.fs | 2 +- 3 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 src/Fantomas.Tests/Ragnarok/SynExprAndBangExpression.fs diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index 2c8ae2ca54..7d6ce7753e 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -99,6 +99,7 @@ + diff --git a/src/Fantomas.Tests/Ragnarok/SynExprAndBangExpression.fs b/src/Fantomas.Tests/Ragnarok/SynExprAndBangExpression.fs new file mode 100644 index 0000000000..8fdd790f70 --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/SynExprAndBangExpression.fs @@ -0,0 +1,248 @@ +module Fantomas.Tests.Ragnarok.SynExprAndBangExpression + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } + +[] +let ``andBang with record instance`` () = + formatSourceString + false + """ +opt { + let! abc = def () + and! foo = + { X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree } + + () +} +""" + config + |> prepend newline + |> should + equal + """ +opt { + let! abc = def () + + and! foo = { + X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree + } + + () +} +""" + +[] +let ``andBang with update record`` () = + formatSourceString + false + """ +opt { + let! abc = def () + and! foo = + { bar with X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree } + + () +} +""" + config + |> prepend newline + |> should + equal + """ +opt { + let! abc = def () + + and! foo = + { bar with + X = xFieldValueOne + Y = yFieldValueTwo + Z = zFieldValueThree + } + + () +} +""" + +[] +let ``andBang with anonymous record instance`` () = + formatSourceString + false + """ +opt { + let! abc = def () + and! foo = + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} + + () +} +""" + config + |> prepend newline + |> should + equal + """ +opt { + let! abc = def () + + and! foo = {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} + + () +} +""" + +[] +let ``andBang with anonymous record instance struct`` () = + formatSourceString + false + """ +opt { + let! abc = def () + and! foo = + struct {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} + + () +} +""" + config + |> prepend newline + |> should + equal + """ +opt { + let! abc = def () + + and! foo = struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} + + () +} +""" + +[] +let ``andBang with computation expression`` () = + formatSourceString + false + """ +task { + let! abc = def () + and! meh = + task { + // comment + return 42 + } + () +} +""" + config + |> prepend newline + |> should + equal + """ +task { + let! abc = def () + + and! meh = task { + // comment + return 42 + } + + () +} +""" + +[] +let ``andBang with list`` () = + formatSourceString + false + """ +collect { + let! abc = def () + and! items = + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] + return items +} +""" + config + |> prepend newline + |> should + equal + """ +collect { + let! abc = def () + + and! items = [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] + + return items +} +""" + +[] +let ``andBang with array`` () = + formatSourceString + false + """ +collect { + let! abc = def () + + and! items = + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] + return items +} +""" + config + |> prepend newline + |> should + equal + """ +collect { + let! abc = def () + + and! items = [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |] + + return items +} +""" diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 42bebdb23f..e8b8257293 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -1493,7 +1493,7 @@ and genExpr astContext synExpr ctx = +> genPat astContext pat +> genEq SynExprAndBang_Equals (Some equalsRange) +> sepSpace - +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext expr) + +> autoIndentAndNlnIfExpressionExceedsPageWidthUnlessRagnarok (genExpr astContext) expr |> genTriviaFor SynExprAndBang_ range | OtherStatement expr -> genExpr astContext expr From 1218fa05683f192ce382541940dc786551338621 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 22 Dec 2021 08:41:34 +0100 Subject: [PATCH 17/33] Format test files. --- src/Fantomas.Tests/Ragnarok/LetOrUseBangExpression.fs | 2 +- src/Fantomas.Tests/Ragnarok/YieldOrReturnExpression.fs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Fantomas.Tests/Ragnarok/LetOrUseBangExpression.fs b/src/Fantomas.Tests/Ragnarok/LetOrUseBangExpression.fs index 8fb28373ac..8dd1f0ecac 100644 --- a/src/Fantomas.Tests/Ragnarok/LetOrUseBangExpression.fs +++ b/src/Fantomas.Tests/Ragnarok/LetOrUseBangExpression.fs @@ -223,4 +223,4 @@ collect { return items } -""" \ No newline at end of file +""" diff --git a/src/Fantomas.Tests/Ragnarok/YieldOrReturnExpression.fs b/src/Fantomas.Tests/Ragnarok/YieldOrReturnExpression.fs index 7050ec3e82..880256b1f3 100644 --- a/src/Fantomas.Tests/Ragnarok/YieldOrReturnExpression.fs +++ b/src/Fantomas.Tests/Ragnarok/YieldOrReturnExpression.fs @@ -278,4 +278,4 @@ myComp { itemFive |] } -""" \ No newline at end of file +""" From 82a4522f96cf4911b5d9e70c75b7053bffd3ef28 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 22 Dec 2021 08:44:32 +0100 Subject: [PATCH 18/33] Add tests suffix --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 8 ++++---- ...seBangExpression.fs => LetOrUseBangExpressionTests.fs} | 2 +- ...BangExpression.fs => SynExprAndBangExpressionTests.fs} | 2 +- ...gExpression.fs => YieldOrReturnBangExpressionTests.fs} | 2 +- ...eturnExpression.fs => YieldOrReturnExpressionTests.fs} | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) rename src/Fantomas.Tests/Ragnarok/{LetOrUseBangExpression.fs => LetOrUseBangExpressionTests.fs} (98%) rename src/Fantomas.Tests/Ragnarok/{SynExprAndBangExpression.fs => SynExprAndBangExpressionTests.fs} (98%) rename src/Fantomas.Tests/Ragnarok/{YieldOrReturnBangExpression.fs => YieldOrReturnBangExpressionTests.fs} (98%) rename src/Fantomas.Tests/Ragnarok/{YieldOrReturnExpression.fs => YieldOrReturnExpressionTests.fs} (98%) diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index 7d6ce7753e..c4221ca0c2 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -96,10 +96,10 @@ - - - - + + + + diff --git a/src/Fantomas.Tests/Ragnarok/LetOrUseBangExpression.fs b/src/Fantomas.Tests/Ragnarok/LetOrUseBangExpressionTests.fs similarity index 98% rename from src/Fantomas.Tests/Ragnarok/LetOrUseBangExpression.fs rename to src/Fantomas.Tests/Ragnarok/LetOrUseBangExpressionTests.fs index 8dd1f0ecac..2612abd9eb 100644 --- a/src/Fantomas.Tests/Ragnarok/LetOrUseBangExpression.fs +++ b/src/Fantomas.Tests/Ragnarok/LetOrUseBangExpressionTests.fs @@ -1,4 +1,4 @@ -module Fantomas.Tests.Ragnarok.LetOrUseBangExpression +module Fantomas.Tests.Ragnarok.LetOrUseBangExpressionTests open NUnit.Framework open FsUnit diff --git a/src/Fantomas.Tests/Ragnarok/SynExprAndBangExpression.fs b/src/Fantomas.Tests/Ragnarok/SynExprAndBangExpressionTests.fs similarity index 98% rename from src/Fantomas.Tests/Ragnarok/SynExprAndBangExpression.fs rename to src/Fantomas.Tests/Ragnarok/SynExprAndBangExpressionTests.fs index 8fdd790f70..37f5f16bdb 100644 --- a/src/Fantomas.Tests/Ragnarok/SynExprAndBangExpression.fs +++ b/src/Fantomas.Tests/Ragnarok/SynExprAndBangExpressionTests.fs @@ -1,4 +1,4 @@ -module Fantomas.Tests.Ragnarok.SynExprAndBangExpression +module Fantomas.Tests.Ragnarok.SynExprAndBangExpressionTests open NUnit.Framework open FsUnit diff --git a/src/Fantomas.Tests/Ragnarok/YieldOrReturnBangExpression.fs b/src/Fantomas.Tests/Ragnarok/YieldOrReturnBangExpressionTests.fs similarity index 98% rename from src/Fantomas.Tests/Ragnarok/YieldOrReturnBangExpression.fs rename to src/Fantomas.Tests/Ragnarok/YieldOrReturnBangExpressionTests.fs index 487af7242a..80f57ca901 100644 --- a/src/Fantomas.Tests/Ragnarok/YieldOrReturnBangExpression.fs +++ b/src/Fantomas.Tests/Ragnarok/YieldOrReturnBangExpressionTests.fs @@ -1,4 +1,4 @@ -module Fantomas.Tests.Ragnarok.YieldOrReturnBangExpression +module Fantomas.Tests.Ragnarok.YieldOrReturnBangExpressionTests open NUnit.Framework open FsUnit diff --git a/src/Fantomas.Tests/Ragnarok/YieldOrReturnExpression.fs b/src/Fantomas.Tests/Ragnarok/YieldOrReturnExpressionTests.fs similarity index 98% rename from src/Fantomas.Tests/Ragnarok/YieldOrReturnExpression.fs rename to src/Fantomas.Tests/Ragnarok/YieldOrReturnExpressionTests.fs index 880256b1f3..6550811f2d 100644 --- a/src/Fantomas.Tests/Ragnarok/YieldOrReturnExpression.fs +++ b/src/Fantomas.Tests/Ragnarok/YieldOrReturnExpressionTests.fs @@ -1,4 +1,4 @@ -module Fantomas.Tests.Ragnarok.YieldOrReturnExpression +module Fantomas.Tests.Ragnarok.YieldOrReturnExpressionTests open NUnit.Framework open FsUnit From d8c04683580d160cc1b9cc542922e23712468d40 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 22 Dec 2021 08:54:22 +0100 Subject: [PATCH 19/33] Add LongIdentSetExpression with Expression. --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 1 + .../Ragnarok/LongIdentSetExpressionTests.fs | 171 ++++++++++++++++++ src/Fantomas/CodePrinter.fs | 2 +- 3 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 src/Fantomas.Tests/Ragnarok/LongIdentSetExpressionTests.fs diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index c4221ca0c2..2ff4aa4440 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -100,6 +100,7 @@ + diff --git a/src/Fantomas.Tests/Ragnarok/LongIdentSetExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/LongIdentSetExpressionTests.fs new file mode 100644 index 0000000000..b6b10152b1 --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/LongIdentSetExpressionTests.fs @@ -0,0 +1,171 @@ +module Fantomas.Tests.Ragnarok.LongIdentSetExpressionTests + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } + + +[] +let ``longIdentSet with record instance `` () = + formatSourceString + false + """ +myMutable <- + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + config + |> prepend newline + |> should + equal + """ +myMutable <- { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +} +""" + +[] +let ``longIdentSet with update record`` () = + formatSourceString + false + """ +myMutable <- + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +myMutable <- + { astContext with + IsInsideMatchClausePattern = true + } +""" + +[] +let ``longIdentSet with anonymous record instance`` () = + formatSourceString + false + """ +myMutable <- + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +myMutable <- {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``longIdentSet with anonymous record instance struct`` () = + formatSourceString + false + """ +myMutable <- + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +myMutable <- struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``longIdentSet with computation expression`` () = + formatSourceString + false + """ +myMutable <- + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +myMutable <- task { + // some computation here + () +} +""" + +[] +let ``longIdentSet with list`` () = + formatSourceString + false + """ +myMutable <- + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +myMutable <- [ + itemOne + itemTwo + itemThree + itemFour + itemFive +] +""" + +[] +let ``longIdentSet with array`` () = + formatSourceString + false + """ +myMutable <- + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +myMutable <- [| + itemOne + itemTwo + itemThree + itemFour + itemFive +|] +""" diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index e8b8257293..bdd5714ef9 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -2410,7 +2410,7 @@ and genExpr astContext synExpr ctx = +> opt id lastRange (leaveNodeFor Ident_) | LongIdentSet (s, e, _) -> !-(sprintf "%s <- " s) - +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e) + +> autoIndentAndNlnIfExpressionExceedsPageWidthUnlessRagnarok (genExpr astContext) e | DotIndexedGet (App (e, [ ConstExpr (SynConst.Unit, _) as ux ]), indexArgs) -> genExpr astContext e +> genExpr astContext ux From 0ab0e3437497e488b0d5b7f447aad4bba62d53e4 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 22 Dec 2021 09:13:47 +0100 Subject: [PATCH 20/33] Add DotIndexedSet with Expression. --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 1 + .../Ragnarok/DotIndexedSetExpressionTests.fs | 506 ++++++++++++++++++ src/Fantomas/CodePrinter.fs | 6 +- 3 files changed, 510 insertions(+), 3 deletions(-) create mode 100644 src/Fantomas.Tests/Ragnarok/DotIndexedSetExpressionTests.fs diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index 2ff4aa4440..00cae2296e 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -101,6 +101,7 @@ + diff --git a/src/Fantomas.Tests/Ragnarok/DotIndexedSetExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/DotIndexedSetExpressionTests.fs new file mode 100644 index 0000000000..7a63e89504 --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/DotIndexedSetExpressionTests.fs @@ -0,0 +1,506 @@ +module Fantomas.Tests.Ragnarok.DotIndexedSetExpressionTests + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } + +[] +let ``dotIndexedSet with record instance `` () = + formatSourceString + false + """ +myMutable.[x] <- + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + config + |> prepend newline + |> should + equal + """ +myMutable.[x] <- { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +} +""" + +[] +let ``dotIndexedSet with update record`` () = + formatSourceString + false + """ +myMutable.[x] <- + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +myMutable.[x] <- + { astContext with + IsInsideMatchClausePattern = true + } +""" + +[] +let ``dotIndexedSet with anonymous record instance`` () = + formatSourceString + false + """ +myMutable.[x] <- + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +myMutable.[x] <- {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``dotIndexedSet with anonymous record instance struct`` () = + formatSourceString + false + """ +myMutable.[x] <- + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +myMutable.[x] <- struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``dotIndexedSet with computation expression`` () = + formatSourceString + false + """ +myMutable.[x] <- + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +myMutable.[x] <- task { + // some computation here + () +} +""" + +[] +let ``dotIndexedSet with list`` () = + formatSourceString + false + """ +myMutable.[x] <- + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +myMutable.[x] <- [ + itemOne + itemTwo + itemThree + itemFour + itemFive +] +""" + +[] +let ``dotIndexedSet with array`` () = + formatSourceString + false + """ +myMutable.[x] <- + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +myMutable.[x] <- [| + itemOne + itemTwo + itemThree + itemFour + itemFive +|] +""" + +[] +let ``application unit dotIndexedSet with record instance `` () = + formatSourceString + false + """ +app().[x] <- + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + config + |> prepend newline + |> should + equal + """ +app().[x] <- { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +} +""" + +[] +let ``application unit dotIndexedSet with update record`` () = + formatSourceString + false + """ +app().[x] <- + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +app().[x] <- + { astContext with + IsInsideMatchClausePattern = true + } +""" + +[] +let ``application unit dotIndexedSet with anonymous record instance`` () = + formatSourceString + false + """ +app().[x] <- + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +app().[x] <- {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``application unit dotIndexedSet with anonymous record instance struct`` () = + formatSourceString + false + """ +app().[x] <- + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +app().[x] <- struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``application unit dotIndexedSet with computation expression`` () = + formatSourceString + false + """ +app().[x] <- + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +app().[x] <- task { + // some computation here + () +} +""" + +[] +let ``application unit dotIndexedSet with list`` () = + formatSourceString + false + """ +app().[x] <- + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +app().[x] <- [ + itemOne + itemTwo + itemThree + itemFour + itemFive +] +""" + +[] +let ``application unit dotIndexedSet with array`` () = + formatSourceString + false + """ +app().[x] <- + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +app().[x] <- [| + itemOne + itemTwo + itemThree + itemFour + itemFive +|] +""" + +// See https://github.com/fsprojects/fantomas/issues/1999 + +[] +let ``application parenthesis expr dotIndexedSet with record instance `` () = + formatSourceString + false + """ +app(meh).[x] <- + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + config + |> prepend newline + |> should + equal + """ +app( + meh +).[x] <- { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +} +""" + +[] +let ``application parenthesis expr dotIndexedSet with update record`` () = + formatSourceString + false + """ +app(meh).[x] <- + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +app( + meh +).[x] <- + { astContext with + IsInsideMatchClausePattern = true + } +""" + +[] +let ``application parenthesis expr dotIndexedSet with anonymous record instance`` () = + formatSourceString + false + """ +app(meh).[x] <- + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +app( + meh +).[x] <- {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``application parenthesis expr dotIndexedSet with anonymous record instance struct`` () = + formatSourceString + false + """ +app(meh).[x] <- + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +app( + meh +).[x] <- struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``application parenthesis expr dotIndexedSet with computation expression`` () = + formatSourceString + false + """ +app(meh).[x] <- + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +app( + meh +).[x] <- task { + // some computation here + () +} +""" + +[] +let ``application parenthesis expr dotIndexedSet with list`` () = + formatSourceString + false + """ +app(meh).[x] <- + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +app( + meh +).[x] <- [ + itemOne + itemTwo + itemThree + itemFour + itemFive +] +""" + +[] +let ``application parenthesis expr dotIndexedSet with array`` () = + formatSourceString + false + """ +app(meh).[x] <- + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +app( + meh +).[x] <- [| + itemOne + itemTwo + itemThree + itemFour + itemFive +|] +""" diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index bdd5714ef9..768bee6b8b 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -2452,7 +2452,7 @@ and genExpr astContext synExpr ctx = (appExpr +> idx +> genExpr astContext valueExpr) (appExpr +> idx - +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext valueExpr)) + +> autoIndentAndNlnIfExpressionExceedsPageWidthUnlessRagnarok (genExpr astContext) valueExpr) | DotIndexedSet (AppSingleParenArg (a, px), indexArgs, valueExpr) -> let short = genExpr astContext a +> genExpr astContext px @@ -2471,14 +2471,14 @@ and genExpr astContext synExpr ctx = (short +> idx +> genExpr astContext valueExpr) (long +> idx - +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext valueExpr)) + +> autoIndentAndNlnIfExpressionExceedsPageWidthUnlessRagnarok (genExpr astContext) valueExpr) | DotIndexedSet (objectExpr, indexArgs, valueExpr) -> addParenIfAutoNln objectExpr (genExpr astContext) -- ".[" +> genExpr astContext indexArgs -- "] <- " - +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext valueExpr) + +> autoIndentAndNlnIfExpressionExceedsPageWidthUnlessRagnarok (genExpr astContext) valueExpr | NamedIndexedPropertySet (ident, e1, e2) -> !-ident +> genExpr astContext e1 -- " <- " +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e2) From ad9c42076e37aeabef5fc2c4d98a0ddf5861ac62 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 22 Dec 2021 09:17:10 +0100 Subject: [PATCH 21/33] Add Set with Expression. --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 1 + .../Ragnarok/SetExpressionTests.fs | 170 ++++++++++++++++++ src/Fantomas/CodePrinter.fs | 2 +- 3 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 src/Fantomas.Tests/Ragnarok/SetExpressionTests.fs diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index 00cae2296e..c95e84594e 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -102,6 +102,7 @@ + diff --git a/src/Fantomas.Tests/Ragnarok/SetExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SetExpressionTests.fs new file mode 100644 index 0000000000..8252c0d60a --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/SetExpressionTests.fs @@ -0,0 +1,170 @@ +module Fantomas.Tests.Ragnarok.SetExpressionTests + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } + +[] +let ``set with record instance `` () = + formatSourceString + false + """ +myMutable[x] <- + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + config + |> prepend newline + |> should + equal + """ +myMutable[x] <- { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +} +""" + +[] +let ``set with update record`` () = + formatSourceString + false + """ +myMutable[x] <- + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +myMutable[x] <- + { astContext with + IsInsideMatchClausePattern = true + } +""" + +[] +let ``set with anonymous record instance`` () = + formatSourceString + false + """ +myMutable[x] <- + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +myMutable[x] <- {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``set with anonymous record instance struct`` () = + formatSourceString + false + """ +myMutable[x] <- + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +myMutable[x] <- struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``set with computation expression`` () = + formatSourceString + false + """ +myMutable[x] <- + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +myMutable[x] <- task { + // some computation here + () +} +""" + +[] +let ``set with list`` () = + formatSourceString + false + """ +myMutable[x] <- + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +myMutable[x] <- [ + itemOne + itemTwo + itemThree + itemFour + itemFive +] +""" + +[] +let ``set with array`` () = + formatSourceString + false + """ +myMutable[x] <- + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +myMutable[x] <- [| + itemOne + itemTwo + itemThree + itemFour + itemFive +|] +""" diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 768bee6b8b..12c6032743 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -2509,7 +2509,7 @@ and genExpr astContext synExpr ctx = | SynExpr.Set (e1, e2, _) -> addParenIfAutoNln e1 (genExpr astContext) -- sprintf " <- " - +> genExpr astContext e2 + +> autoIndentAndNlnExpressUnlessRagnarok (genExpr astContext) e2 | ParsingError r -> raise From 5a79dfcd2d9b16031748e1c87302062649d2b0a9 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 22 Dec 2021 09:31:35 +0100 Subject: [PATCH 22/33] Add DotSet with Expression. --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 1 + .../Ragnarok/DotSetExpressionTests.fs | 170 ++++++++++++++++++ src/Fantomas/CodePrinter.fs | 2 +- 3 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 src/Fantomas.Tests/Ragnarok/DotSetExpressionTests.fs diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index c95e84594e..30236cd14d 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -103,6 +103,7 @@ + diff --git a/src/Fantomas.Tests/Ragnarok/DotSetExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/DotSetExpressionTests.fs new file mode 100644 index 0000000000..26ab5c2d9f --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/DotSetExpressionTests.fs @@ -0,0 +1,170 @@ +module Fantomas.Tests.Ragnarok.DotSetExpressionTests + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } + +[] +let ``dotSet with record instance `` () = + formatSourceString + false + """ +App().foo <- + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + config + |> prepend newline + |> should + equal + """ +App().foo <- { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +} +""" + +[] +let ``dotSet with update record`` () = + formatSourceString + false + """ +App().foo <- + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +App().foo <- + { astContext with + IsInsideMatchClausePattern = true + } +""" + +[] +let ``dotSet with anonymous record instance`` () = + formatSourceString + false + """ +App().foo <- + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +App().foo <- {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``dotSet with anonymous record instance struct`` () = + formatSourceString + false + """ +App().foo <- + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +App().foo <- struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``dotSet with computation expression`` () = + formatSourceString + false + """ +App().foo <- + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +App().foo <- task { + // some computation here + () +} +""" + +[] +let ``dotSet with list`` () = + formatSourceString + false + """ +App().foo <- + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +App().foo <- [ + itemOne + itemTwo + itemThree + itemFour + itemFive +] +""" + +[] +let ``dotSet with array`` () = + formatSourceString + false + """ +App().foo <- + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +App().foo <- [| + itemOne + itemTwo + itemThree + itemFour + itemFive +|] +""" diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 12c6032743..5424524359 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -2504,7 +2504,7 @@ and genExpr astContext synExpr ctx = | DotSet (e1, s, e2) -> addParenIfAutoNln e1 (genExpr astContext) -- sprintf ".%s <- " s - +> genExpr astContext e2 + +> autoIndentAndNlnExpressUnlessRagnarok (genExpr astContext) e2 | SynExpr.Set (e1, e2, _) -> addParenIfAutoNln e1 (genExpr astContext) From d4ae69ea98603ea443f45664d675172d749a69c5 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 22 Dec 2021 11:08:20 +0100 Subject: [PATCH 23/33] Add Lambda with Expression. --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 2 + .../Ragnarok/LambdaExpressionTests.fs | 856 ++++++++++++++++++ .../Ragnarok/LongIdentSetExpressionTests.fs | 1 - ...LineLambdaClosingNewlineExpressionTests.fs | 728 +++++++++++++++ src/Fantomas/CodePrinter.fs | 47 +- 5 files changed, 1614 insertions(+), 20 deletions(-) create mode 100644 src/Fantomas.Tests/Ragnarok/LambdaExpressionTests.fs create mode 100644 src/Fantomas.Tests/Ragnarok/MultiLineLambdaClosingNewlineExpressionTests.fs diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index 30236cd14d..5d05d8e972 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -104,6 +104,8 @@ + + diff --git a/src/Fantomas.Tests/Ragnarok/LambdaExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/LambdaExpressionTests.fs new file mode 100644 index 0000000000..d4f81815c8 --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/LambdaExpressionTests.fs @@ -0,0 +1,856 @@ +module Fantomas.Tests.Ragnarok.LambdaExpressionTests + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } + +[] +let ``lambda with record instance `` () = + formatSourceString + false + """ +fun x -> + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + config + |> prepend newline + |> should + equal + """ +fun x -> { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +} +""" + +[] +let ``lambda with update record`` () = + formatSourceString + false + """ +fun x -> + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +fun x -> + { astContext with + IsInsideMatchClausePattern = true + } +""" + +[] +let ``lambda with anonymous record instance`` () = + formatSourceString + false + """ +fun x -> + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +fun x -> {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``lambda with anonymous record instance struct`` () = + formatSourceString + false + """ +fun x -> + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +fun x -> struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``lambda with computation expression`` () = + formatSourceString + false + """ +fun x -> + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +fun x -> task { + // some computation here + () +} +""" + +[] +let ``lambda with list`` () = + formatSourceString + false + """ +fun x -> + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +fun x -> [ + itemOne + itemTwo + itemThree + itemFour + itemFive +] +""" + +[] +let ``lambda with array`` () = + formatSourceString + false + """ +fun x -> + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +fun x -> [| + itemOne + itemTwo + itemThree + itemFour + itemFive +|] +""" + +[] +let ``paren lambda with record instance `` () = + formatSourceString + false + """ +(fun x -> + { A = longTypeName + B = someOtherVariable + C = ziggyBarX }) +""" + config + |> prepend newline + |> should + equal + """ +(fun x -> { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +}) +""" + +[] +let ``paren lambda with update record`` () = + formatSourceString + false + """ +(fun x -> + { astContext with IsInsideMatchClausePattern = true }) +""" + config + |> prepend newline + |> should + equal + """ +(fun x -> + { astContext with + IsInsideMatchClausePattern = true + }) +""" + +[] +let ``paren lambda with anonymous record instance`` () = + formatSourceString + false + """ +(fun x -> + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |}) +""" + config + |> prepend newline + |> should + equal + """ +(fun x -> {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|}) +""" + +[] +let ``paren lambda with anonymous record instance struct`` () = + formatSourceString + false + """ +(fun x -> + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |}) +""" + config + |> prepend newline + |> should + equal + """ +(fun x -> struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|}) +""" + +[] +let ``paren lambda with computation expression`` () = + formatSourceString + false + """ +(fun x -> + task { + // some computation here + () + }) +""" + config + |> prepend newline + |> should + equal + """ +(fun x -> task { + // some computation here + () +}) +""" + +[] +let ``paren lambda with list`` () = + formatSourceString + false + """ +(fun x -> + [ itemOne + itemTwo + itemThree + itemFour + itemFive ]) +""" + config + |> prepend newline + |> should + equal + """ +(fun x -> [ + itemOne + itemTwo + itemThree + itemFour + itemFive +]) +""" + +[] +let ``paren lambda with array`` () = + formatSourceString + false + """ +(fun x -> + [| itemOne + itemTwo + itemThree + itemFour + itemFive |]) +""" + config + |> prepend newline + |> should + equal + """ +(fun x -> [| + itemOne + itemTwo + itemThree + itemFour + itemFive +|]) +""" + +[] +let ``app paren lambda with record instance `` () = + formatSourceString + false + """ +List.map (fun x -> + { A = longTypeName + B = someOtherVariable + C = ziggyBarX }) +""" + config + |> prepend newline + |> should + equal + """ +List.map (fun x -> { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +}) +""" + +[] +let ``app paren lambda with update record`` () = + formatSourceString + false + """ +List.map (fun x -> + { astContext with IsInsideMatchClausePattern = true }) +""" + config + |> prepend newline + |> should + equal + """ +List.map (fun x -> + { astContext with + IsInsideMatchClausePattern = true + }) +""" + +[] +let ``app paren lambda with anonymous record instance`` () = + formatSourceString + false + """ +List.map (fun x -> + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |}) +""" + config + |> prepend newline + |> should + equal + """ +List.map (fun x -> {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|}) +""" + +[] +let ``app paren lambda with anonymous record instance struct`` () = + formatSourceString + false + """ +List.map (fun x -> + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |}) +""" + config + |> prepend newline + |> should + equal + """ +List.map (fun x -> struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|}) +""" + +[] +let ``app paren lambda with computation expression`` () = + formatSourceString + false + """ +List.map (fun x -> + task { + // some computation here + () + }) +""" + config + |> prepend newline + |> should + equal + """ +List.map (fun x -> task { + // some computation here + () +}) +""" + +[] +let ``app paren lambda with list`` () = + formatSourceString + false + """ +List.map (fun x -> + [ itemOne + itemTwo + itemThree + itemFour + itemFive ]) +""" + config + |> prepend newline + |> should + equal + """ +List.map (fun x -> [ + itemOne + itemTwo + itemThree + itemFour + itemFive +]) +""" + +[] +let ``app paren lambda with array`` () = + formatSourceString + false + """ +List.map (fun x -> + [| itemOne + itemTwo + itemThree + itemFour + itemFive |]) +""" + config + |> prepend newline + |> should + equal + """ +List.map (fun x -> [| + itemOne + itemTwo + itemThree + itemFour + itemFive +|]) +""" + +[] +let ``app paren lambda with record instance and other args`` () = + formatSourceString + false + """ +List.map (fun x -> + { A = longTypeName + B = someOtherVariable + C = ziggyBarX }) b c +""" + config + |> prepend newline + |> should + equal + """ +List.map + (fun x -> { + A = longTypeName + B = someOtherVariable + C = ziggyBarX + }) + b + c +""" + +[] +let ``app paren lambda with update record and other args`` () = + formatSourceString + false + """ +List.map (fun x -> + { astContext with IsInsideMatchClausePattern = true }) b c +""" + { config with MaxLineLength = 60 } + |> prepend newline + |> should + equal + """ +List.map + (fun x -> + { astContext with + IsInsideMatchClausePattern = true + }) + b + c +""" + +[] +let ``app paren lambda with anonymous record instance and other args`` () = + formatSourceString + false + """ +List.map (fun x -> + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |}) b c +""" + config + |> prepend newline + |> should + equal + """ +List.map + (fun x -> {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |}) + b + c +""" + +[] +let ``app paren lambda with anonymous record instance struct and other args`` () = + formatSourceString + false + """ +List.map (fun x -> + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |}) b c +""" + config + |> prepend newline + |> should + equal + """ +List.map + (fun x -> struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |}) + b + c +""" + +[] +let ``app paren lambda with computation expression and other args`` () = + formatSourceString + false + """ +List.map (fun x -> + task { + // some computation here + () + }) b c +""" + config + |> prepend newline + |> should + equal + """ +List.map + (fun x -> task { + // some computation here + () + }) + b + c +""" + +[] +let ``app paren lambda with list and other args`` () = + formatSourceString + false + """ +List.map (fun x -> + [ itemOne + itemTwo + itemThree + itemFour + itemFive ]) b c +""" + config + |> prepend newline + |> should + equal + """ +List.map + (fun x -> [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ]) + b + c +""" + +[] +let ``app paren lambda with array and other args`` () = + formatSourceString + false + """ +List.map (fun x -> + [| itemOne + itemTwo + itemThree + itemFour + itemFive |]) b c +""" + config + |> prepend newline + |> should + equal + """ +List.map + (fun x -> [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |]) + b + c +""" + +[] +let ``dotGetApp with lambda with record instance`` () = + formatSourceString + false + """ +Bar.Foo(fun x -> { A = longTypeName + B = someOtherVariable + C = ziggyBarX + D = evenMoreZigBarry }).Bar() +""" + config + |> prepend newline + |> should + equal + """ +Bar + .Foo(fun x -> { + A = longTypeName + B = someOtherVariable + C = ziggyBarX + D = evenMoreZigBarry + }) + .Bar() +""" + +[] +let ``dotGetApp with lambda with update record`` () = + formatSourceString + false + """ +Bar.Foo(fun x -> { other with + A = longTypeName + B = someOtherVariable + C = ziggyBarX + D = evenMoreZigBarry }).Bar() +""" + { config with MaxLineLength = 60 } + |> prepend newline + |> should + equal + """ +Bar + .Foo(fun x -> + { other with + A = longTypeName + B = someOtherVariable + C = ziggyBarX + D = evenMoreZigBarry + }) + .Bar() +""" + +[] +let ``dotGetApp with lambda with anonymous record instance`` () = + formatSourceString + false + """ +Bar.Foo(fun x -> + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |}).Bar() +""" + config + |> prepend newline + |> should + equal + """ +Bar + .Foo(fun x -> {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |}) + .Bar() +""" + +[] +let ``dotGetApp with lambda with anonymous record instance struct`` () = + formatSourceString + false + """ +Bar + .Foo(fun x -> + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |}).Bar() +""" + config + |> prepend newline + |> should + equal + """ +Bar + .Foo(fun x -> struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |}) + .Bar() +""" + +[] +let ``dotGetApp with lambda with computation expression`` () = + formatSourceString + false + """ +Bar + .Foo(fun x -> + task { + // some computation here + () + }).Bar() +""" + config + |> prepend newline + |> should + equal + """ +Bar + .Foo(fun x -> task { + // some computation here + () + }) + .Bar() +""" + +[] +let ``dotGetApp with lambda with list`` () = + formatSourceString + false + """ +Bar + .Foo(fun x -> + [ itemOne + itemTwo + itemThree + itemFour + itemFive ]).Bar() +""" + config + |> prepend newline + |> should + equal + """ +Bar + .Foo(fun x -> [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ]) + .Bar() +""" + +[] +let ``dotGetApp with lambda with array`` () = + formatSourceString + false + """ +Bar + .Foo(fun x -> + [| itemOne + itemTwo + itemThree + itemFour + itemFive |]).Bar() +""" + config + |> prepend newline + |> should + equal + """ +Bar + .Foo(fun x -> [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |]) + .Bar() +""" diff --git a/src/Fantomas.Tests/Ragnarok/LongIdentSetExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/LongIdentSetExpressionTests.fs index b6b10152b1..1f58422468 100644 --- a/src/Fantomas.Tests/Ragnarok/LongIdentSetExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/LongIdentSetExpressionTests.fs @@ -9,7 +9,6 @@ let config = MultilineBlockBracketsOnSameColumn = true Ragnarok = true } - [] let ``longIdentSet with record instance `` () = formatSourceString diff --git a/src/Fantomas.Tests/Ragnarok/MultiLineLambdaClosingNewlineExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/MultiLineLambdaClosingNewlineExpressionTests.fs new file mode 100644 index 0000000000..ac090367e2 --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/MultiLineLambdaClosingNewlineExpressionTests.fs @@ -0,0 +1,728 @@ +module Fantomas.Tests.Ragnarok.MultiLineLambdaClosingNewlineExpressionTests + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + MultiLineLambdaClosingNewline = true + Ragnarok = true } + +// TODO: figure out what should happen when you mix MultiLineLambdaClosingNewline and Ragnarok +// From a technical point of view, this is correct behavior but having `})` at the end seems sensible as well. + +[] +let ``paren lambda with record instance`` () = + formatSourceString + false + """ +(fun x -> + { A = longTypeName + B = someOtherVariable + C = ziggyBarX }) +""" + config + |> prepend newline + |> should + equal + """ +(fun x -> { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +} +) +""" + +[] +let ``paren lambda with update record`` () = + formatSourceString + false + """ +(fun x -> + { astContext with IsInsideMatchClausePattern = true }) +""" + config + |> prepend newline + |> should + equal + """ +(fun x -> + { astContext with + IsInsideMatchClausePattern = true + } +) +""" + +[] +let ``paren lambda with anonymous record instance`` () = + formatSourceString + false + """ +(fun x -> + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |}) +""" + config + |> prepend newline + |> should + equal + """ +(fun x -> {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +) +""" + +[] +let ``paren lambda with anonymous record instance struct`` () = + formatSourceString + false + """ +(fun x -> + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |}) +""" + config + |> prepend newline + |> should + equal + """ +(fun x -> struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +) +""" + +[] +let ``paren lambda with computation expression`` () = + formatSourceString + false + """ +(fun x -> + task { + // some computation here + () + }) +""" + config + |> prepend newline + |> should + equal + """ +(fun x -> task { + // some computation here + () +} +) +""" + +[] +let ``paren lambda with list`` () = + formatSourceString + false + """ +(fun x -> + [ itemOne + itemTwo + itemThree + itemFour + itemFive ]) +""" + config + |> prepend newline + |> should + equal + """ +(fun x -> [ + itemOne + itemTwo + itemThree + itemFour + itemFive +] +) +""" + +[] +let ``paren lambda with array`` () = + formatSourceString + false + """ +(fun x -> + [| itemOne + itemTwo + itemThree + itemFour + itemFive |]) +""" + config + |> prepend newline + |> should + equal + """ +(fun x -> [| + itemOne + itemTwo + itemThree + itemFour + itemFive +|] +) +""" + +[] +let ``app paren lambda with record instance `` () = + formatSourceString + false + """ +List.map (fun x -> + { A = longTypeName + B = someOtherVariable + C = ziggyBarX }) +""" + config + |> prepend newline + |> should + equal + """ +List.map (fun x -> { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +} +) +""" + +[] +let ``app paren lambda with update record`` () = + formatSourceString + false + """ +List.map (fun x -> + { astContext with IsInsideMatchClausePattern = true }) +""" + config + |> prepend newline + |> should + equal + """ +List.map (fun x -> + { astContext with + IsInsideMatchClausePattern = true + } +) +""" + +[] +let ``app paren lambda with anonymous record instance`` () = + formatSourceString + false + """ +List.map (fun x -> + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |}) +""" + config + |> prepend newline + |> should + equal + """ +List.map (fun x -> {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +) +""" + +[] +let ``app paren lambda with anonymous record instance struct`` () = + formatSourceString + false + """ +List.map (fun x -> + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |}) +""" + config + |> prepend newline + |> should + equal + """ +List.map (fun x -> struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +) +""" + +[] +let ``app paren lambda with computation expression`` () = + formatSourceString + false + """ +List.map (fun x -> + task { + // some computation here + () + }) +""" + config + |> prepend newline + |> should + equal + """ +List.map (fun x -> task { + // some computation here + () +} +) +""" + +[] +let ``app paren lambda with list`` () = + formatSourceString + false + """ +List.map (fun x -> + [ itemOne + itemTwo + itemThree + itemFour + itemFive ]) +""" + config + |> prepend newline + |> should + equal + """ +List.map (fun x -> [ + itemOne + itemTwo + itemThree + itemFour + itemFive +] +) +""" + +[] +let ``app paren lambda with array`` () = + formatSourceString + false + """ +List.map (fun x -> + [| itemOne + itemTwo + itemThree + itemFour + itemFive |]) +""" + config + |> prepend newline + |> should + equal + """ +List.map (fun x -> [| + itemOne + itemTwo + itemThree + itemFour + itemFive +|] +) +""" + +[] +let ``app paren lambda with record instance and other args`` () = + formatSourceString + false + """ +List.map (fun x -> + { A = longTypeName + B = someOtherVariable + C = ziggyBarX }) b c +""" + config + |> prepend newline + |> should + equal + """ +List.map + (fun x -> { + A = longTypeName + B = someOtherVariable + C = ziggyBarX + } + ) + b + c +""" + +[] +let ``app paren lambda with update record and other args`` () = + formatSourceString + false + """ +List.map (fun x -> + { astContext with IsInsideMatchClausePattern = true }) b c +""" + { config with MaxLineLength = 60 } + |> prepend newline + |> should + equal + """ +List.map + (fun x -> + { astContext with + IsInsideMatchClausePattern = true + } + ) + b + c +""" + +[] +let ``app paren lambda with anonymous record instance and other args`` () = + formatSourceString + false + """ +List.map (fun x -> + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |}) b c +""" + config + |> prepend newline + |> should + equal + """ +List.map + (fun x -> {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} + ) + b + c +""" + +[] +let ``app paren lambda with anonymous record instance struct and other args`` () = + formatSourceString + false + """ +List.map (fun x -> + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |}) b c +""" + config + |> prepend newline + |> should + equal + """ +List.map + (fun x -> struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} + ) + b + c +""" + +[] +let ``app paren lambda with computation expression and other args`` () = + formatSourceString + false + """ +List.map (fun x -> + task { + // some computation here + () + }) b c +""" + config + |> prepend newline + |> should + equal + """ +List.map + (fun x -> task { + // some computation here + () + } + ) + b + c +""" + +[] +let ``app paren lambda with list and other args`` () = + formatSourceString + false + """ +List.map (fun x -> + [ itemOne + itemTwo + itemThree + itemFour + itemFive ]) b c +""" + config + |> prepend newline + |> should + equal + """ +List.map + (fun x -> [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] + ) + b + c +""" + +[] +let ``app paren lambda with array and other args`` () = + formatSourceString + false + """ +List.map (fun x -> + [| itemOne + itemTwo + itemThree + itemFour + itemFive |]) b c +""" + config + |> prepend newline + |> should + equal + """ +List.map + (fun x -> [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |] + ) + b + c +""" + +[] +let ``dotGetApp with lambda with record instance`` () = + formatSourceString + false + """ +Bar.Foo(fun x -> { A = longTypeName + B = someOtherVariable + C = ziggyBarX + D = evenMoreZigBarry }).Bar() +""" + config + |> prepend newline + |> should + equal + """ +Bar + .Foo(fun x -> { + A = longTypeName + B = someOtherVariable + C = ziggyBarX + D = evenMoreZigBarry + } + ) + .Bar() +""" + +[] +let ``dotGetApp with lambda with update record`` () = + formatSourceString + false + """ +Bar.Foo(fun x -> { other with + A = longTypeName + B = someOtherVariable + C = ziggyBarX + D = evenMoreZigBarry }).Bar() +""" + { config with MaxLineLength = 60 } + |> prepend newline + |> should + equal + """ +Bar + .Foo(fun x -> + { other with + A = longTypeName + B = someOtherVariable + C = ziggyBarX + D = evenMoreZigBarry + } + ) + .Bar() +""" + +[] +let ``dotGetApp with lambda with anonymous record instance`` () = + formatSourceString + false + """ +Bar.Foo(fun x -> + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |}).Bar() +""" + config + |> prepend newline + |> should + equal + """ +Bar + .Foo(fun x -> {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} + ) + .Bar() +""" + +[] +let ``dotGetApp with lambda with anonymous record instance struct`` () = + formatSourceString + false + """ +Bar + .Foo(fun x -> + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |}).Bar() +""" + config + |> prepend newline + |> should + equal + """ +Bar + .Foo(fun x -> struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} + ) + .Bar() +""" + +[] +let ``dotGetApp with lambda with computation expression`` () = + formatSourceString + false + """ +Bar + .Foo(fun x -> + task { + // some computation here + () + }).Bar() +""" + config + |> prepend newline + |> should + equal + """ +Bar + .Foo(fun x -> task { + // some computation here + () + } + ) + .Bar() +""" + +[] +let ``dotGetApp with lambda with list`` () = + formatSourceString + false + """ +Bar + .Foo(fun x -> + [ itemOne + itemTwo + itemThree + itemFour + itemFive ]).Bar() +""" + config + |> prepend newline + |> should + equal + """ +Bar + .Foo(fun x -> [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] + ) + .Bar() +""" + +[] +let ``dotGetApp with lambda with array`` () = + formatSourceString + false + """ +Bar + .Foo(fun x -> + [| itemOne + itemTwo + itemThree + itemFour + itemFive |]).Bar() +""" + config + |> prepend newline + |> should + equal + """ +Bar + .Foo(fun x -> [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |] + ) + .Bar() +""" diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 5424524359..12771483a9 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -1525,9 +1525,9 @@ and genExpr astContext synExpr ctx = | JoinIn (e1, e2) -> genExpr astContext e1 -- " in " +> genExpr astContext e2 - | Paren (lpr, Lambda (pats, arrowRange, expr, lambdaRange), rpr, _pr) -> + | Paren (lpr, Lambda (pats, arrowRange, expr, lambdaRange), rpr, pr) -> fun (ctx: Context) -> - let body = genExprKeepIndentInBranch astContext expr + let body = genExprKeepIndentInBranch astContext let expr = let triviaOfLambda f (ctx: Context) = @@ -1543,18 +1543,22 @@ and genExpr astContext synExpr ctx = +> (fun ctx -> if not ctx.Config.MultiLineLambdaClosingNewline then genLambdaArrowWithTrivia - (body - +> triviaOfLambda printContentAfter - +> sepNlnWhenWriteBeforeNewlineNotEmpty id - +> sepCloseTFor rpr) + (fun e -> + body e + +> triviaOfLambda printContentAfter + +> sepNlnWhenWriteBeforeNewlineNotEmpty id + +> sepCloseTFor rpr) + expr arrowRange ctx else leadingExpressionIsMultiline (genLambdaArrowWithTrivia - (body - +> triviaOfLambda printContentAfter - +> sepNlnWhenWriteBeforeNewlineNotEmpty id) + (fun e -> + body e + +> triviaOfLambda printContentAfter + +> sepNlnWhenWriteBeforeNewlineNotEmpty id) + expr arrowRange) (fun isMultiline -> onlyIf isMultiline sepNln +> sepCloseTFor rpr) ctx) @@ -1571,7 +1575,7 @@ and genExpr astContext synExpr ctx = sepArrow |> genTriviaFor SynExpr_Lambda_Arrow arrowRange) arrowRange - +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext expr) + +> autoIndentAndNlnIfExpressionExceedsPageWidthUnlessRagnarok (genExpr astContext) expr ) | MatchLambda (keywordRange, cs) -> (!- "function " @@ -2050,7 +2054,8 @@ and genExpr astContext synExpr ctx = +> (!- "fun " +> col sepSpace pats (genPat astContext) +> genLambdaArrowWithTrivia - (genExprKeepIndentInBranch astContext bodyExpr) + (genExprKeepIndentInBranch astContext) + bodyExpr arrowRange |> genTriviaFor SynExpr_Lambda range) +> sepNln @@ -2127,7 +2132,7 @@ and genExpr astContext synExpr ctx = +> (sepOpenTFor lpr +> (!- "fun " +> col sepSpace pats (genPat astContext) - +> genLambdaArrowWithTrivia (genExprKeepIndentInBranch astContext body) arrowRange + +> genLambdaArrowWithTrivia (genExprKeepIndentInBranch astContext) body arrowRange |> genTriviaFor SynExpr_Lambda lambdaRange) +> sepNlnWhenWriteBeforeNewlineNotEmpty sepNone +> sepCloseTFor rpr @@ -2142,7 +2147,7 @@ and genExpr astContext synExpr ctx = +> (sepOpenTFor lpr +> (!- "fun " +> col sepSpace pats (genPat astContext) - +> genLambdaArrowWithTrivia (genExprKeepIndentInBranch astContext body) arrowRange + +> genLambdaArrowWithTrivia (genExprKeepIndentInBranch astContext) body arrowRange |> genTriviaFor SynExpr_Lambda lambdaRange) +> sepCloseTFor rpr |> genTriviaFor SynExpr_Paren pr) @@ -2881,7 +2886,7 @@ and genMultilineFunctionApplicationArguments astContext argExpr = (sepOpenTFor lpr +> (!- "fun " +> col sepSpace pats (genPat astContext) - +> genLambdaArrowWithTrivia (genExprKeepIndentInBranch astContext body) arrowRange + +> genLambdaArrowWithTrivia (genExprKeepIndentInBranch astContext) body arrowRange |> genTriviaFor SynExpr_Lambda range) +> sepNln +> sepCloseTFor rpr) @@ -3252,7 +3257,7 @@ and genApp astContext e es ctx = leadingExpressionIsMultiline (sepOpenTFor lpr -- "fun " +> pats - +> genLambdaArrowWithTrivia (genExprKeepIndentInBranch astContext bodyExpr) arrowRange) + +> genLambdaArrowWithTrivia (genExprKeepIndentInBranch astContext) bodyExpr arrowRange) (fun isMultiline -> onlyIf isMultiline sepNln +> sepCloseTFor rpr) |> genTriviaFor SynExpr_Paren pr @@ -3298,7 +3303,7 @@ and genLambdaMultiLineClosingNewline leadingExpressionIsMultiline (sepOpenTFor lpr -- "fun " +> col sepSpace pats (genPat astContext) - +> genLambdaArrowWithTrivia (genExprKeepIndentInBranch astContext bodyExpr) arrowRange + +> genLambdaArrowWithTrivia (genExprKeepIndentInBranch astContext) bodyExpr arrowRange |> genTriviaFor SynExpr_Lambda lambdaRange) (fun isMultiline -> onlyIf isMultiline sepNln +> sepCloseTFor rpr) |> genTriviaFor SynExpr_Paren pr @@ -5690,7 +5695,11 @@ and genTriviaForOption (mainNodeName: FsAstType) (range: range option) f ctx = | None -> ctx | Some range -> genTriviaFor mainNodeName range f ctx -and genLambdaArrowWithTrivia (bodyExpr: Context -> Context) (arrowRange: Range option) = +and genLambdaArrowWithTrivia + (bodyExpr: SynExpr -> Context -> Context) + (body: SynExpr) + (arrowRange: Range option) + : Context -> Context = optSingle (fun arrowRange -> sepArrow @@ -5698,9 +5707,9 @@ and genLambdaArrowWithTrivia (bodyExpr: Context -> Context) (arrowRange: Range o arrowRange +> (fun ctx -> if String.isNotNullOrEmpty ctx.WriterModel.WriteBeforeNewline then - (indent +> sepNln +> bodyExpr +> unindent) ctx + (indent +> sepNln +> (bodyExpr body) +> unindent) ctx else - (autoIndentAndNlnIfExpressionExceedsPageWidth bodyExpr) ctx) + autoIndentAndNlnIfExpressionExceedsPageWidthUnlessRagnarok bodyExpr body ctx) and infixOperatorFromTrivia range fallback (ctx: Context) = // by specs, section 3.4 https://fsharp.org/specs/language-spec/4.1/FSharpSpec-4.1-latest.pdf#page=24&zoom=auto,-137,312 From 732640d89a052697a880ea7f50f949841e9a8ef8 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 22 Dec 2021 11:36:44 +0100 Subject: [PATCH 24/33] Add SynMatchClause with Expression. --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 2 + .../KeepIndentInBranchExpressionTests.fs | 188 ++++++++ .../Ragnarok/SynMatchClauseExpressionTests.fs | 421 ++++++++++++++++++ src/Fantomas/CodePrinter.fs | 2 +- 4 files changed, 612 insertions(+), 1 deletion(-) create mode 100644 src/Fantomas.Tests/Ragnarok/KeepIndentInBranchExpressionTests.fs create mode 100644 src/Fantomas.Tests/Ragnarok/SynMatchClauseExpressionTests.fs diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index 5d05d8e972..c9de2a24b5 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -106,6 +106,8 @@ + + diff --git a/src/Fantomas.Tests/Ragnarok/KeepIndentInBranchExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/KeepIndentInBranchExpressionTests.fs new file mode 100644 index 0000000000..125cd116b1 --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/KeepIndentInBranchExpressionTests.fs @@ -0,0 +1,188 @@ +module Fantomas.Tests.Ragnarok.KeepIndentInBranchExpressionTests + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + KeepIndentInBranch = true + Ragnarok = true } + +// There currently is no conflict with this setting, but I'm guessing the case was never brought up. +// I would conclude that will never clash. + +[] +let ``synMatchClause in match expression with record instance `` () = + formatSourceString + false + """ +match x with +| _ -> + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + config + |> prepend newline + |> should + equal + """ +match x with +| _ -> { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +} +""" + +[] +let ``synMatchClause in match expression with update record`` () = + formatSourceString + false + """ +match x with +| _ -> + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +match x with +| _ -> + { astContext with + IsInsideMatchClausePattern = true + } +""" + +[] +let ``synMatchClause in match expression with anonymous record instance`` () = + formatSourceString + false + """ +match x with +| _ -> + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +match x with +| _ -> {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``synMatchClause in match expression with anonymous record instance struct`` () = + formatSourceString + false + """ +match x with +| _ -> + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +match x with +| _ -> struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``synMatchClause in match expression with computation expression`` () = + formatSourceString + false + """ +match x with +| _ -> + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +match x with +| _ -> task { + // some computation here + () +} +""" + +[] +let ``synMatchClause in match expression with list`` () = + formatSourceString + false + """ +match x with +| _ -> + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +match x with +| _ -> [ + itemOne + itemTwo + itemThree + itemFour + itemFive +] +""" + +[] +let ``synMatchClause in match expression with array`` () = + formatSourceString + false + """ +match x with +| _ -> + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +match x with +| _ -> [| + itemOne + itemTwo + itemThree + itemFour + itemFive +|] +""" diff --git a/src/Fantomas.Tests/Ragnarok/SynMatchClauseExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynMatchClauseExpressionTests.fs new file mode 100644 index 0000000000..d2a9989f29 --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/SynMatchClauseExpressionTests.fs @@ -0,0 +1,421 @@ +module Fantomas.Tests.Ragnarok.SynMatchClauseExpressionTests + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } + +[] +let ``synMatchClause in match expression with record instance `` () = + formatSourceString + false + """ +match x with +| _ -> + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + config + |> prepend newline + |> should + equal + """ +match x with +| _ -> { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +} +""" + +[] +let ``synMatchClause in match expression with update record`` () = + formatSourceString + false + """ +match x with +| _ -> + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +match x with +| _ -> + { astContext with + IsInsideMatchClausePattern = true + } +""" + +[] +let ``synMatchClause in match expression with anonymous record instance`` () = + formatSourceString + false + """ +match x with +| _ -> + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +match x with +| _ -> {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``synMatchClause in match expression with anonymous record instance struct`` () = + formatSourceString + false + """ +match x with +| _ -> + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +match x with +| _ -> struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``synMatchClause in match expression with computation expression`` () = + formatSourceString + false + """ +match x with +| _ -> + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +match x with +| _ -> task { + // some computation here + () +} +""" + +[] +let ``synMatchClause in match expression with list`` () = + formatSourceString + false + """ +match x with +| _ -> + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +match x with +| _ -> [ + itemOne + itemTwo + itemThree + itemFour + itemFive +] +""" + +[] +let ``synMatchClause in match expression with array`` () = + formatSourceString + false + """ +match x with +| _ -> + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +match x with +| _ -> [| + itemOne + itemTwo + itemThree + itemFour + itemFive +|] +""" + +// TODO: Here, I again feel this is fitting not to have ragnarok. +// Similar to long patterns in synbinding functions. + +[] +let ``synMatchClause in match expression with long when expression with record instance `` () = + formatSourceString + false + """ +match x with +| _ when (try + somethingDangerous () + true + with | ex -> false) + -> + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + config + |> prepend newline + |> should + equal + """ +match x with +| _ when + (try + somethingDangerous () + true + with + | ex -> false) + -> + { + A = longTypeName + B = someOtherVariable + C = ziggyBarX + } +""" + + +[] +let ``synMatchClause in try/with expression with record instance `` () = + formatSourceString + false + """ +try + foo() +with ex -> + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } +""" + config + |> prepend newline + |> should + equal + """ +try + foo () +with +| ex -> { + A = longTypeName + B = someOtherVariable + C = ziggyBarX +} +""" + +[] +let ``synMatchClause in try/with expression with update record`` () = + formatSourceString + false + """ +try + foo() +with ex -> + { astContext with IsInsideMatchClausePattern = true } +""" + config + |> prepend newline + |> should + equal + """ +try + foo () +with +| ex -> + { astContext with + IsInsideMatchClausePattern = true + } +""" + +[] +let ``synMatchClause in try/with expression with anonymous record instance`` () = + formatSourceString + false + """ +try + foo() +with ex -> + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +try + foo () +with +| ex -> {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``synMatchClause in try/with expression with anonymous record instance struct`` () = + formatSourceString + false + """ +try + foo() +with ex -> + struct + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} +""" + config + |> prepend newline + |> should + equal + """ +try + foo () +with +| ex -> struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX +|} +""" + +[] +let ``synMatchClause in try/with expression with computation expression`` () = + formatSourceString + false + """ +try + foo() +with +| ex -> + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +try + foo () +with +| ex -> task { + // some computation here + () +} +""" + +[] +let ``synMatchClause in try/with expression with list`` () = + formatSourceString + false + """ +try + foo () +with +| ex -> + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] +""" + config + |> prepend newline + |> should + equal + """ +try + foo () +with +| ex -> [ + itemOne + itemTwo + itemThree + itemFour + itemFive +] +""" + +[] +let ``synMatchClause in try/with expression with array`` () = + formatSourceString + false + """ +try + foo () +with +| ex -> + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] +""" + config + |> prepend newline + |> should + equal + """ +try + foo () +with +| ex -> [| + itemOne + itemTwo + itemThree + itemFour + itemFive +|] +""" diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 12771483a9..dd66b3ae40 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -4575,7 +4575,7 @@ and genClause astContext hasBar (Clause (p, eo, arrowRange, e) as ce) = sepArrow |> genTriviaFor SynMatchClause_Arrow arrowRange) arrowRange - +> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e)) + +> autoIndentAndNlnIfExpressionExceedsPageWidthUnlessRagnarok (genExpr astContext) e) ctx) (onlyIf hasBar sepBar +> patAndBody From 97e50b535a7badf0ab7a2918596f934d43ec2f43 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 22 Dec 2021 12:11:13 +0100 Subject: [PATCH 25/33] Add SynTypeDefnSimpleRepr.Record NOTE: TESTS FAIL --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 1 + .../SynTypeDefnSimpleReprRecordTests.fs | 84 +++++++++++++++++++ src/Fantomas.Tests/RecordTests.fs | 22 ----- src/Fantomas/CodePrinter.fs | 26 +++++- src/Fantomas/Context.fs | 7 ++ 5 files changed, 117 insertions(+), 23 deletions(-) create mode 100644 src/Fantomas.Tests/Ragnarok/SynTypeDefnSimpleReprRecordTests.fs diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index c9de2a24b5..f115db5038 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -108,6 +108,7 @@ + diff --git a/src/Fantomas.Tests/Ragnarok/SynTypeDefnSimpleReprRecordTests.fs b/src/Fantomas.Tests/Ragnarok/SynTypeDefnSimpleReprRecordTests.fs new file mode 100644 index 0000000000..b648b86857 --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/SynTypeDefnSimpleReprRecordTests.fs @@ -0,0 +1,84 @@ +module Fantomas.Tests.Ragnarok.SynTypeDefnSimpleReprRecordTests + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } + +[] +let ``record type definition`` () = + formatSourceString + false + """ +type V = + { X: SomeFieldType + Y: OhSomethingElse + Z: ALongTypeName } +""" + config + |> prepend newline + |> should + equal + """ +type V = { + X: SomeFieldType + Y: OhSomethingElse + Z: ALongTypeName +} +""" + +[] +[] +let ``record type definition with comment after equals`` () = + formatSourceString + false + """ +type V = // comment + { X: SomeFieldType + Y: OhSomethingElse + Z: ALongTypeName } +""" + config + |> prepend newline + |> should + equal + """ +type V = // comment + { + X: SomeFieldType + Y: OhSomethingElse + Z: ALongTypeName + } +""" + +// TODO: I feel like ragnarok should not work when there are members involved +// Having members would require the `with` keyword which is not recommended by the style guide: https://docs.microsoft.com/en-us/dotnet/fsharp/style-guide/formatting#formatting-record-declarations + +[] +let ``record type definition with members`` () = + formatSourceString + false + """ +type V = + { X: SomeFieldType + Y: OhSomethingElse + Z: ALongTypeName } + member this.Coordinate = (this.X, this.Y, this.Z) +""" + config + |> prepend newline + |> should + equal + """ +type V = + { + X: SomeFieldType + Y: OhSomethingElse + Z: ALongTypeName + } + member this.Coordinate = (this.X, this.Y, this.Z) +""" diff --git a/src/Fantomas.Tests/RecordTests.fs b/src/Fantomas.Tests/RecordTests.fs index d22280970e..f3bb07693a 100644 --- a/src/Fantomas.Tests/RecordTests.fs +++ b/src/Fantomas.Tests/RecordTests.fs @@ -2020,25 +2020,3 @@ let a = {| Foo = // 2 |} """ - -[] -let ``foobar `` () = - formatSourceString - false - """ -let x = - { A = longTypeName - B = someOtherVariable - C = ziggyBarX } -""" - { config with MultilineBlockBracketsOnSameColumn = true } - |> prepend newline - |> should - equal - """ -let x = { - A = longTypeName - B = someOtherVariable - C = ziggyBarX -} -""" diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index dd66b3ae40..fdee90eba8 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -3626,7 +3626,6 @@ and genTypeDefn fs closingBrace) (genMultilineSimpleRecordTypeDefn astContext openingBrace withKeyword ms ao' fs closingBrace) - let bodyExpr ctx = let size = getRecordSize ctx fs @@ -3644,6 +3643,31 @@ and genTypeDefn +> indent +> genTriviaFor SynTypeDefnSimpleRepr_Record tdr.Range bodyExpr +> unindent + // TODO: +// let bodyExpr size ctx = +// if (List.isEmpty ms) then +// (isSmallExpression size smallExpression multilineExpression +// +> leaveNodeFor SynTypeDefnSimpleRepr_Record tdr.Range // this will only print something when there is trivia after } in the short expression +// // Yet it cannot be part of the short expression otherwise the multiline expression would be triggered unwillingly. +// ) +// ctx +// else +// multilineExpression ctx + +// let genTypeDefinition (ctx: Context) = +// let size = getRecordSize ctx fs +// +// let short = +// enterNodeFor SynTypeDefnSimpleRepr_Record tdr.Range +// +> bodyExpr size +// +> leaveNodeFor SynTypeDefnSimpleRepr_Record tdr.Range +// +// if ctx.Config.Ragnarok && ms.IsEmpty then +// (sepSpace +> short) ctx +// else +// isSmallExpression size short (indent +> sepNln +> short +> unindent) ctx +// +// typeName +> sepEq +> genTypeDefinition | Simple TDSRNone -> typeName | Simple (TDSRTypeAbbrev t) -> diff --git a/src/Fantomas/Context.fs b/src/Fantomas/Context.fs index 93eca3d725..998a2c565a 100644 --- a/src/Fantomas/Context.fs +++ b/src/Fantomas/Context.fs @@ -631,6 +631,8 @@ let internal getRecordSize ctx fields = let internal ifElse b (f1: Context -> Context) f2 (ctx: Context) = if b then f1 ctx else f2 ctx let internal ifElseCtx cond (f1: Context -> Context) f2 (ctx: Context) = if cond ctx then f1 ctx else f2 ctx +let internal ifRagnarokElse = ifElseCtx (fun ctx -> ctx.Config.Ragnarok) +let internal ifRagnarok (f1: Context -> Context) = ifElseCtx (fun ctx -> ctx.Config.Ragnarok) f1 id /// apply f only when cond is true let internal onlyIf cond f ctx = if cond then f ctx else ctx @@ -679,6 +681,11 @@ let internal sepNlnUnlessLastEventIsNewline (ctx: Context) = ctx else sepNln ctx +let internal sepNlnUnlessLastEventIsNewlineOrRagnarok (ctx: Context) = + if lastWriteEventIsNewline ctx || ctx.Config.Ragnarok then + ctx + else + sepNln ctx let internal sepStar = !- " * " let internal sepStarFixed = !- "* " From 4e44ef836ea20890aa0cd2d50725220bdea2206c Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 22 Dec 2021 12:23:24 +0100 Subject: [PATCH 26/33] Add SynTypeDefnSigRepr.Simple --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 1 + .../Ragnarok/SynTypeDefnSigReprSimpleTests.fs | 96 +++++++++++++++++++ src/Fantomas/CodePrinter.fs | 81 +++++++--------- 3 files changed, 129 insertions(+), 49 deletions(-) create mode 100644 src/Fantomas.Tests/Ragnarok/SynTypeDefnSigReprSimpleTests.fs diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index f115db5038..11e6337b22 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -109,6 +109,7 @@ + diff --git a/src/Fantomas.Tests/Ragnarok/SynTypeDefnSigReprSimpleTests.fs b/src/Fantomas.Tests/Ragnarok/SynTypeDefnSigReprSimpleTests.fs new file mode 100644 index 0000000000..797cb10ce7 --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/SynTypeDefnSigReprSimpleTests.fs @@ -0,0 +1,96 @@ +module Fantomas.Tests.Ragnarok.SynTypeDefnSigReprSimpleTests + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } + +[] +let ``record type definition`` () = + formatSourceString + true + """ +namespace Foo + +type V = + { X: SomeFieldType + Y: OhSomethingElse + Z: ALongTypeName } +""" + config + |> prepend newline + |> should + equal + """ +namespace Foo + +type V = { + X: SomeFieldType + Y: OhSomethingElse + Z: ALongTypeName +} +""" + +[] +[] +let ``record type definition with comment after equals`` () = + formatSourceString + true + """ +namespace Foo + +type V = // comment + { X: SomeFieldType + Y: OhSomethingElse + Z: ALongTypeName } +""" + config + |> prepend newline + |> should + equal + """ +namespace Foo + +type V = // comment + { + X: SomeFieldType + Y: OhSomethingElse + Z: ALongTypeName + } +""" + +// TODO: I feel like ragnarok should not work when there are members involved +// Having members would require the `with` keyword which is not recommended by the style guide: https://docs.microsoft.com/en-us/dotnet/fsharp/style-guide/formatting#formatting-record-declarations + +[] +let ``record type definition with members`` () = + formatSourceString + true + """ +namespace Foo + +type V = + { X: SomeFieldType + Y: OhSomethingElse + Z: ALongTypeName } + member Coordinate : SomeFieldType * OhSomethingElse * ALongTypeName +""" + config + |> prepend newline + |> should + equal + """ +namespace Foo + +type V = + { + X: SomeFieldType + Y: OhSomethingElse + Z: ALongTypeName + } + member Coordinate: SomeFieldType * OhSomethingElse * ALongTypeName +""" diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index fdee90eba8..5924530873 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -3626,9 +3626,7 @@ and genTypeDefn fs closingBrace) (genMultilineSimpleRecordTypeDefn astContext openingBrace withKeyword ms ao' fs closingBrace) - let bodyExpr ctx = - let size = getRecordSize ctx fs - + let bodyExpr size ctx = if (List.isEmpty ms) then (isSmallExpression size smallExpression multilineExpression +> leaveNodeFor SynTypeDefnSimpleRepr_Record tdr.Range // this will only print something when there is trivia after } in the short expression @@ -3638,36 +3636,20 @@ and genTypeDefn else multilineExpression ctx - typeName - +> genEq SynTypeDefn_Equals equalsRange - +> indent - +> genTriviaFor SynTypeDefnSimpleRepr_Record tdr.Range bodyExpr - +> unindent - // TODO: -// let bodyExpr size ctx = -// if (List.isEmpty ms) then -// (isSmallExpression size smallExpression multilineExpression -// +> leaveNodeFor SynTypeDefnSimpleRepr_Record tdr.Range // this will only print something when there is trivia after } in the short expression -// // Yet it cannot be part of the short expression otherwise the multiline expression would be triggered unwillingly. -// ) -// ctx -// else -// multilineExpression ctx - -// let genTypeDefinition (ctx: Context) = -// let size = getRecordSize ctx fs -// -// let short = -// enterNodeFor SynTypeDefnSimpleRepr_Record tdr.Range -// +> bodyExpr size -// +> leaveNodeFor SynTypeDefnSimpleRepr_Record tdr.Range -// -// if ctx.Config.Ragnarok && ms.IsEmpty then -// (sepSpace +> short) ctx -// else -// isSmallExpression size short (indent +> sepNln +> short +> unindent) ctx -// -// typeName +> sepEq +> genTypeDefinition + let genTypeDefinition (ctx: Context) = + let size = getRecordSize ctx fs + + let short = + enterNodeFor SynTypeDefnSimpleRepr_Record tdr.Range + +> bodyExpr size + +> leaveNodeFor SynTypeDefnSimpleRepr_Record tdr.Range + + if ctx.Config.Ragnarok && ms.IsEmpty then + (sepSpace +> short) ctx + else + isSmallExpression size short (indent +> sepNln +> short +> unindent) ctx + + typeName +> sepEq +> genTypeDefinition | Simple TDSRNone -> typeName | Simple (TDSRTypeAbbrev t) -> @@ -3944,9 +3926,7 @@ and genSigTypeDefn (genSigSimpleRecordAlignBrackets astContext openingBrace withKeyword ms ao' fs closingBrace) (genSigSimpleRecord astContext openingBrace withKeyword ms ao' fs closingBrace) - let bodyExpr ctx = - let size = getRecordSize ctx fs - + let bodyExpr size ctx = if (List.isEmpty ms) then (isSmallExpression size smallExpression multilineExpression +> leaveNodeFor SynTypeDefnSimpleRepr_Record tdr.Range // this will only print something when there is trivia after } in the short expression @@ -3956,11 +3936,20 @@ and genSigTypeDefn else multilineExpression ctx - typeName - +> genEq SynTypeDefnSig_Equals equalsRange - +> indent - +> genTriviaFor SynTypeDefnSimpleRepr_Record tdr.Range bodyExpr - +> unindent + let genTypeDefinition (ctx: Context) = + let size = getRecordSize ctx fs + + let short = + enterNodeFor SynTypeDefnSimpleRepr_Record tdr.Range + +> bodyExpr size + +> leaveNodeFor SynTypeDefnSimpleRepr_Record tdr.Range + + if ctx.Config.Ragnarok && ms.IsEmpty then + (sepSpace +> short) ctx + else + isSmallExpression size short (indent +> sepNln +> short +> unindent) ctx + + typeName +> sepEq +> genTypeDefinition | SigSimple TDSRNone -> let genMembers = @@ -4047,10 +4036,7 @@ and genSigTypeDefn |> genTriviaFor SynTypeDefnSig_ fullRange and genSigSimpleRecord astContext openingBrace withKeyword ms ao' fs closingBrace = - // the typeName is already printed - sepNlnUnlessLastEventIsNewline - +> opt (indent +> sepNln) ao' genAccess - +> enterNodeFor SynTypeDefnSimpleRepr_Record_OpeningBrace openingBrace + opt (indent +> sepNln) ao' genAccess +> sepOpenS +> atCurrentColumn ( leaveNodeFor SynTypeDefnSimpleRepr_Record_OpeningBrace openingBrace @@ -4063,10 +4049,7 @@ and genSigSimpleRecord astContext openingBrace withKeyword ms ao' fs closingBrac +> colPre sepNln sepNln ms (genMemberSig astContext) and genSigSimpleRecordAlignBrackets astContext openingBrace withKeyword ms ao' fs closingBrace = - // the typeName is already printed - sepNlnUnlessLastEventIsNewline - +> opt (indent +> sepNln) ao' genAccess - +> enterNodeFor SynTypeDefnSimpleRepr_Record_OpeningBrace openingBrace + opt (indent +> sepNln) ao' genAccess +> sepOpenSFixed +> indent +> sepNln From 2442960ef672a7bbfc83dc513212de92b4c7cc52 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 22 Dec 2021 12:34:30 +0100 Subject: [PATCH 27/33] Use correct helper function for Set and DotSet. --- src/Fantomas/CodePrinter.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 5924530873..0a387c8843 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -2509,12 +2509,12 @@ and genExpr astContext synExpr ctx = | DotSet (e1, s, e2) -> addParenIfAutoNln e1 (genExpr astContext) -- sprintf ".%s <- " s - +> autoIndentAndNlnExpressUnlessRagnarok (genExpr astContext) e2 + +> autoIndentAndNlnIfExpressionExceedsPageWidthUnlessRagnarok (genExpr astContext) e2 | SynExpr.Set (e1, e2, _) -> addParenIfAutoNln e1 (genExpr astContext) -- sprintf " <- " - +> autoIndentAndNlnExpressUnlessRagnarok (genExpr astContext) e2 + +> autoIndentAndNlnIfExpressionExceedsPageWidthUnlessRagnarok (genExpr astContext) e2 | ParsingError r -> raise From 4da94a73dc105eb62f4380e75934035f74bbcfcf Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 22 Dec 2021 15:08:43 +0100 Subject: [PATCH 28/33] Work around edge case where match clause body needs to be further indented. --- ...ineBetweenTypeDefinitionAndMembersTests.fs | 2 +- .../Ragnarok/SynMatchClauseExpressionTests.fs | 33 ++++++++++ src/Fantomas/CodePrinter.fs | 63 +++++++++++++++---- src/Fantomas/SourceParser.fs | 10 +++ 4 files changed, 95 insertions(+), 13 deletions(-) diff --git a/src/Fantomas.Tests/NewlineBetweenTypeDefinitionAndMembersTests.fs b/src/Fantomas.Tests/NewlineBetweenTypeDefinitionAndMembersTests.fs index 4c5d6fbb60..dd11023b13 100644 --- a/src/Fantomas.Tests/NewlineBetweenTypeDefinitionAndMembersTests.fs +++ b/src/Fantomas.Tests/NewlineBetweenTypeDefinitionAndMembersTests.fs @@ -62,7 +62,7 @@ let ``no extra newline after record type with no members`` () = To : float Name: string } """ - config + { config with MaxRecordWidth = 39 } |> prepend newline |> should equal diff --git a/src/Fantomas.Tests/Ragnarok/SynMatchClauseExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynMatchClauseExpressionTests.fs index d2a9989f29..edfb8572a6 100644 --- a/src/Fantomas.Tests/Ragnarok/SynMatchClauseExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynMatchClauseExpressionTests.fs @@ -419,3 +419,36 @@ with itemFive |] """ + +[] +let ``multiple clauses with lists`` () = + formatSourceString + false + """ +match x with +| SynMemberDefn.ImplicitCtor (_, attrs, ctorArgs, _, _xmlDoc, range) -> + [ yield mkNode SynMemberDefn_ImplicitCtor range + yield! (visitSynAttributeLists attrs) + yield! visitSynSimplePats ctorArgs ] +| SynMemberDefn.ImplicitInherit (inheritType, inheritArgs, _, range) -> + [ yield mkNode SynMemberDefn_ImplicitInherit range + yield! visitSynType inheritType + yield! visitSynExpr inheritArgs ] +""" + config + |> prepend newline + |> should + equal + """ +match x with +| SynMemberDefn.ImplicitCtor (_, attrs, ctorArgs, _, _xmlDoc, range) -> [ + yield mkNode SynMemberDefn_ImplicitCtor range + yield! (visitSynAttributeLists attrs) + yield! visitSynSimplePats ctorArgs + ] +| SynMemberDefn.ImplicitInherit (inheritType, inheritArgs, _, range) -> [ + yield mkNode SynMemberDefn_ImplicitInherit range + yield! visitSynType inheritType + yield! visitSynExpr inheritArgs + ] +""" diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 0a387c8843..65bd170bf8 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -2234,7 +2234,11 @@ and genExpr astContext synExpr ctx = +> genTriviaFor SynExpr_TryWith_With withKeyword (!- "with") +> indentOnWith +> sepNln - +> col sepNln cs (genClause astContext true) + +> (fun ctx -> + let hasMultipleClausesWhereOneHasRagnarok = + hasMultipleClausesWhereOneHasRagnarok ctx.Config.Ragnarok cs + + col sepNln cs (genClause astContext true hasMultipleClausesWhereOneHasRagnarok) ctx) +> unindentOnWith ) @@ -4540,8 +4544,15 @@ and genInterfaceImpl astContext (InterfaceImpl (t, withKeywordRange, bs, members +> genMemberDefnList astContext members +> unindent -and genClause astContext hasBar (Clause (p, eo, arrowRange, e) as ce) = - let astCtx = { astContext with IsInsideMatchClausePattern = true } +and genClause + (astContext: ASTContext) + (hasBar: bool) + (hasMultipleClausesWhereOneHasRagnarok: bool) + (Clause (p, eo, arrowRange, e) as ce) + = + let astCtx = + { astContext with + IsInsideMatchClausePattern = true } let patAndBody = genPat astCtx p @@ -4585,11 +4596,31 @@ and genClause astContext hasBar (Clause (p, eo, arrowRange, e) as ce) = +> autoIndentAndNlnIfExpressionExceedsPageWidthUnlessRagnarok (genExpr astContext) e) ctx) - (onlyIf hasBar sepBar +> patAndBody - |> genTriviaFor SynMatchClause_ ce.Range) + (onlyIf hasBar sepBar + +> (fun ctx -> + if hasMultipleClausesWhereOneHasRagnarok then + // avoid edge case + (* + match x with + | y -> [ + 1 + 2 + 3 + ] + | z -> [ + 4 + 5 + 6 + ] + *) + // ] and | cannot align, otherwise you get a parser error + atCurrentColumn patAndBody ctx + else + patAndBody ctx) + |> genTriviaFor SynMatchClause_ ce.Range) -and genClauses astContext cs = - col sepNln cs (genClause astContext true) +and genClauses astContext cs (ctx: Context) = + col sepNln cs (genClause astContext true (hasMultipleClausesWhereOneHasRagnarok ctx.Config.Ragnarok cs)) ctx /// Each multiline member definition has a pre and post new line. and genMemberDefnList astContext nodes = @@ -5453,11 +5484,19 @@ and genKeepIndentMatch withRange ) +> sepNln - +> coli sepNln clauses (fun idx -> - if idx < lastClauseIndex then - genClause astContext true - else - genLastClauseKeepIdent astContext) + +> (fun ctx -> + let hasMultipleClausesWhereOneHasRagnarok = + hasMultipleClausesWhereOneHasRagnarok ctx.Config.Ragnarok clauses + + coli + sepNln + clauses + (fun idx -> + if idx < lastClauseIndex then + genClause astContext true hasMultipleClausesWhereOneHasRagnarok + else + genLastClauseKeepIdent astContext) + ctx) |> genTriviaFor triviaType range and genLastClauseKeepIdent (astContext: ASTContext) (Clause (pat, whenExpr, arrowRange, expr)) = diff --git a/src/Fantomas/SourceParser.fs b/src/Fantomas/SourceParser.fs index a27b6f8d6c..31ad76fa61 100644 --- a/src/Fantomas/SourceParser.fs +++ b/src/Fantomas/SourceParser.fs @@ -1868,3 +1868,13 @@ let (|RagnarokExpr|_|) (e: SynExpr) = | SynExpr.App (ExprAtomicFlag.NonAtomic, false, SynExpr.Ident _, SynExpr.ComputationExpr _, _) | ArrayOrList _ -> Some e | _ -> None + +let hasMultipleClausesWhereOneHasRagnarok (ragnarokEnabled) (cs: SynMatchClause list) : bool = + ragnarokEnabled + && List.moreThanOne cs + && List.exists + (fun (SynMatchClause (resultExpr = e)) -> + match e with + | RagnarokExpr _ -> true + | _ -> false) + cs From 09f04d81b3c102a1229f9a6a66a0e9653015aa39 Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 23 Dec 2021 10:53:33 +0100 Subject: [PATCH 29/33] Add named arguments in application and new expressions. --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 1 + .../Ragnarok/NamedArgumentExpressionTests.fs | 518 ++++++++++++++++++ src/Fantomas/CodePrinter.fs | 5 +- 3 files changed, 520 insertions(+), 4 deletions(-) create mode 100644 src/Fantomas.Tests/Ragnarok/NamedArgumentExpressionTests.fs diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index 11e6337b22..b6f3e4ebb3 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -110,6 +110,7 @@ + diff --git a/src/Fantomas.Tests/Ragnarok/NamedArgumentExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/NamedArgumentExpressionTests.fs new file mode 100644 index 0000000000..bda740b56b --- /dev/null +++ b/src/Fantomas.Tests/Ragnarok/NamedArgumentExpressionTests.fs @@ -0,0 +1,518 @@ +module Fantomas.Tests.Ragnarok.NamedArgumentExpressionTests + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } + +[] +let ``synExprApp with named argument with record instance`` () = + formatSourceString + false + """ +let v = + SomeConstructor( + v = + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } + ) +""" + config + |> prepend newline + |> should + equal + """ +let v = + SomeConstructor( + v = { + A = longTypeName + B = someOtherVariable + C = ziggyBarX + } + ) +""" + +[] +let ``synExprApp with named argument with update record`` () = + formatSourceString + false + """ +let v = + SomeConstructor( + v = + { astContext with IsInsideMatchClausePattern = true + A = longTypeName + B = someOtherVariable + C = ziggyBarX } + ) +""" + config + |> prepend newline + |> should + equal + """ +let v = + SomeConstructor( + v = + { astContext with + IsInsideMatchClausePattern = true + A = longTypeName + B = someOtherVariable + C = ziggyBarX + } + ) +""" + +[] +let ``synExprApp with named argument with anonymous record instance`` () = + formatSourceString + false + """ +let v = + SomeConstructor( + v = + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} + ) +""" + config + |> prepend newline + |> should + equal + """ +let v = + SomeConstructor( + v = {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} + ) +""" + +[] +let ``synExprApp with named argument with anonymous record instance struct`` () = + formatSourceString + false + """ +let v = + SomeConstructor( + v = + struct {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} + ) +""" + config + |> prepend newline + |> should + equal + """ +let v = + SomeConstructor( + v = struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} + ) +""" + +[] +let ``synExprApp with named argument with computation expression`` () = + formatSourceString + false + """ +let v = + SomeConstructor( + v = + task { + // some computation here + () + } + ) +""" + config + |> prepend newline + |> should + equal + """ +let v = + SomeConstructor( + v = task { + // some computation here + () + } + ) +""" + +[] +let ``synExprApp with named argument with list`` () = + formatSourceString + false + """ +let v = + SomeConstructor( + v = + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] + ) +""" + config + |> prepend newline + |> should + equal + """ +let v = + SomeConstructor( + v = [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] + ) +""" + +[] +let ``synExprApp with named argument with array`` () = + formatSourceString + false + """ +let v = + SomeConstructor( + v = + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] + ) +""" + config + |> prepend newline + |> should + equal + """ +let v = + SomeConstructor( + v = [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |] + ) +""" + +[] +let ``synExprApp with multiple named arguments`` () = + formatSourceString + false + """ +let v = + SomeConstructor( + x = + [| itemOne + itemTwo + itemThree + itemFour + itemFive |], + y = + [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] + ) +""" + config + |> prepend newline + |> should + equal + """ +let v = + SomeConstructor( + x = [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |], + y = [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] + ) +""" + +[] +let ``synExprNew with named argument with record instance`` () = + formatSourceString + false + """ +let v = + new FooBar( + v = + { A = longTypeName + B = someOtherVariable + C = ziggyBarX } + ) +""" + config + |> prepend newline + |> should + equal + """ +let v = + new FooBar( + v = { + A = longTypeName + B = someOtherVariable + C = ziggyBarX + } + ) +""" + +[] +let ``synExprNew with named argument with update record`` () = + formatSourceString + false + """ +let v = + new FooBar( + v = + { astContext with IsInsideMatchClausePattern = true + A = longTypeName + B = someOtherVariable + C = ziggyBarX } + ) +""" + config + |> prepend newline + |> should + equal + """ +let v = + new FooBar( + v = + { astContext with + IsInsideMatchClausePattern = true + A = longTypeName + B = someOtherVariable + C = ziggyBarX + } + ) +""" + +[] +let ``synExprNew with named argument with anonymous record instance`` () = + formatSourceString + false + """ +let v = + new FooBar( + v = + {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} + ) +""" + config + |> prepend newline + |> should + equal + """ +let v = + new FooBar( + v = {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} + ) +""" + +[] +let ``synExprNew with named argument with anonymous record instance struct`` () = + formatSourceString + false + """ +let v = + new FooBar( + v = + struct {| A = longTypeName + B = someOtherVariable + C = ziggyBarX |} + ) +""" + config + |> prepend newline + |> should + equal + """ +let v = + new FooBar( + v = struct {| + A = longTypeName + B = someOtherVariable + C = ziggyBarX + |} + ) +""" + +[] +let ``synExprNew with named argument with computation expression`` () = + formatSourceString + false + """ +let v = + new FooBar( + v = + task { + // some computation here + () + } + ) +""" + config + |> prepend newline + |> should + equal + """ +let v = + new FooBar( + v = task { + // some computation here + () + } + ) +""" + +[] +let ``synExprNew with named argument with list`` () = + formatSourceString + false + """ +let v = + new FooBar( + v = + [ itemOne + itemTwo + itemThree + itemFour + itemFive ] + ) +""" + config + |> prepend newline + |> should + equal + """ +let v = + new FooBar( + v = [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] + ) +""" + +[] +let ``synExprNew with named argument with array`` () = + formatSourceString + false + """ +let v = + new FooBar( + v = + [| itemOne + itemTwo + itemThree + itemFour + itemFive |] + ) +""" + config + |> prepend newline + |> should + equal + """ +let v = + new FooBar( + v = [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |] + ) +""" + +[] +let ``synExprNew with multiple named arguments`` () = + formatSourceString + false + """ +let v = + new FooBar( + x = + [| itemOne + itemTwo + itemThree + itemFour + itemFive |], + y = + [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] + ) +""" + config + |> prepend newline + |> should + equal + """ +let v = + new FooBar( + x = [| + itemOne + itemTwo + itemThree + itemFour + itemFive + |], + y = [ + itemOne + itemTwo + itemThree + itemFour + itemFive + ] + ) +""" diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index 65bd170bf8..fbebf2a2de 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -1003,10 +1003,7 @@ and genNamedArgumentExpr (astContext: ASTContext) operatorExpr e1 e2 appRange = genExpr astContext e1 +> sepSpace +> genInfixOperator "=" operatorExpr - +> indent - +> sepNln - +> genExpr astContext e2 - +> unindent + +> autoIndentAndNlnExpressUnlessRagnarok (fun e -> sepSpace +> genExpr astContext e) e2 expressionFitsOnRestOfLine short long |> genTriviaFor SynExpr_App appRange From 99b7eda4299676b6125f5ce033bc32d5bc7ee7a5 Mon Sep 17 00:00:00 2001 From: Josh DeGraw Date: Mon, 7 Mar 2022 10:32:57 -0700 Subject: [PATCH 30/33] Fix leftover issue --- src/Fantomas/CodePrinter.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index fbebf2a2de..a45bdaa48e 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -3650,7 +3650,7 @@ and genTypeDefn else isSmallExpression size short (indent +> sepNln +> short +> unindent) ctx - typeName +> sepEq +> genTypeDefinition + typeName +> genEq SynTypeDefn_Equals equalsRange +> genTypeDefinition | Simple TDSRNone -> typeName | Simple (TDSRTypeAbbrev t) -> From 6796d5dc12ef06f38ff7035ff56657f41851573f Mon Sep 17 00:00:00 2001 From: Josh DeGraw Date: Thu, 17 Mar 2022 17:31:40 -0600 Subject: [PATCH 31/33] Add TODO comment --- src/Fantomas.Tests/Ragnarok/SynTypeDefnSimpleReprRecordTests.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Fantomas.Tests/Ragnarok/SynTypeDefnSimpleReprRecordTests.fs b/src/Fantomas.Tests/Ragnarok/SynTypeDefnSimpleReprRecordTests.fs index b648b86857..6b8e138712 100644 --- a/src/Fantomas.Tests/Ragnarok/SynTypeDefnSimpleReprRecordTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynTypeDefnSimpleReprRecordTests.fs @@ -9,6 +9,7 @@ let config = MultilineBlockBracketsOnSameColumn = true Ragnarok = true } +//TODO: This test is still failing [] let ``record type definition`` () = formatSourceString From f6b3121c2ec772b4096eab7bfed52db0d5405212 Mon Sep 17 00:00:00 2001 From: Josh DeGraw Date: Fri, 18 Mar 2022 10:30:20 -0600 Subject: [PATCH 32/33] Fix failing test --- .../SynTypeDefnSimpleReprRecordTests.fs | 5 +- src/Fantomas/CodePrinter.fs | 49 ++++++++++--------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Fantomas.Tests/Ragnarok/SynTypeDefnSimpleReprRecordTests.fs b/src/Fantomas.Tests/Ragnarok/SynTypeDefnSimpleReprRecordTests.fs index 6b8e138712..f491ad8254 100644 --- a/src/Fantomas.Tests/Ragnarok/SynTypeDefnSimpleReprRecordTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynTypeDefnSimpleReprRecordTests.fs @@ -6,10 +6,9 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } -//TODO: This test is still failing [] let ``record type definition`` () = formatSourceString diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index a45bdaa48e..bce34b7ded 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -1217,15 +1217,16 @@ and genExpr astContext synExpr ctx = +> ifElse isInfixExpr genInfixExpr genNonInfixExpr | SingleExpr (kind, e) -> - let mapping = + let mapping = (match kind with - | YieldFrom _ - | Yield _ - | Return _ - | ReturnFrom _ - | Do _ - | DoBang _ -> autoIndentAndNlnIfExpressionExceedsPageWidthUnlessRagnarok (genExpr astContext) e - | _ -> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e)) + | YieldFrom _ + | Yield _ + | Return _ + | ReturnFrom _ + | Do _ + | DoBang _ -> autoIndentAndNlnIfExpressionExceedsPageWidthUnlessRagnarok (genExpr astContext) e + | _ -> autoIndentAndNlnIfExpressionExceedsPageWidth (genExpr astContext e)) + match kind with | InferredDowncast downcastKeyword -> genTriviaFor SynExpr_InferredDowncast_Downcast downcastKeyword !- "downcast " @@ -1242,7 +1243,7 @@ and genExpr astContext synExpr ctx = | Do doKeyword -> genTriviaFor SynExpr_Do_Do doKeyword !- "do " | DoBang doBangKeyword -> genTriviaFor SynExpr_DoBang_DoBang doBangKeyword !- "do! " | Fixed fixedKeyword -> genTriviaFor SynExpr_Fixed_Fixed fixedKeyword !- "fixed " - +> mapping + +> mapping | ConstExpr (c, r) -> genConst c r | NullExpr -> !- "null" @@ -3627,6 +3628,7 @@ and genTypeDefn fs closingBrace) (genMultilineSimpleRecordTypeDefn astContext openingBrace withKeyword ms ao' fs closingBrace) + let bodyExpr size ctx = if (List.isEmpty ms) then (isSmallExpression size smallExpression multilineExpression @@ -3650,7 +3652,9 @@ and genTypeDefn else isSmallExpression size short (indent +> sepNln +> short +> unindent) ctx - typeName +> genEq SynTypeDefn_Equals equalsRange +> genTypeDefinition + typeName + +> genEq SynTypeDefn_Equals equalsRange + +> genTypeDefinition | Simple TDSRNone -> typeName | Simple (TDSRTypeAbbrev t) -> @@ -3812,8 +3816,7 @@ and genMultilineSimpleRecordTypeDefn astContext openingBrace withKeyword ms ao' and genMultilineSimpleRecordTypeDefnAlignBrackets astContext openingBrace withKeyword ms ao' fs closingBrace = // the typeName is already printed - sepNlnUnlessLastEventIsNewline - +> opt (indent +> sepNln) ao' genAccess + opt (indent +> sepNln) ao' genAccess +> enterNodeFor SynTypeDefnSimpleRepr_Record_OpeningBrace openingBrace +> sepOpenSFixed +> indent @@ -4547,9 +4550,7 @@ and genClause (hasMultipleClausesWhereOneHasRagnarok: bool) (Clause (p, eo, arrowRange, e) as ce) = - let astCtx = - { astContext with - IsInsideMatchClausePattern = true } + let astCtx = { astContext with IsInsideMatchClausePattern = true } let patAndBody = genPat astCtx p @@ -4594,10 +4595,10 @@ and genClause ctx) (onlyIf hasBar sepBar - +> (fun ctx -> - if hasMultipleClausesWhereOneHasRagnarok then - // avoid edge case - (* + +> (fun ctx -> + if hasMultipleClausesWhereOneHasRagnarok then + // avoid edge case + (* match x with | y -> [ 1 @@ -4610,11 +4611,11 @@ and genClause 6 ] *) - // ] and | cannot align, otherwise you get a parser error - atCurrentColumn patAndBody ctx - else - patAndBody ctx) - |> genTriviaFor SynMatchClause_ ce.Range) + // ] and | cannot align, otherwise you get a parser error + atCurrentColumn patAndBody ctx + else + patAndBody ctx) + |> genTriviaFor SynMatchClause_ ce.Range) and genClauses astContext cs (ctx: Context) = col sepNln cs (genClause astContext true (hasMultipleClausesWhereOneHasRagnarok ctx.Config.Ragnarok cs)) ctx From b63cd7dab078ac392dc5fed80a6417157274bfee Mon Sep 17 00:00:00 2001 From: Josh DeGraw Date: Fri, 18 Mar 2022 10:32:29 -0600 Subject: [PATCH 33/33] Format files --- src/Fantomas.Tests/Ragnarok/DotIndexedSetExpressionTests.fs | 4 ++-- src/Fantomas.Tests/Ragnarok/DotSetExpressionTests.fs | 4 ++-- .../Ragnarok/KeepIndentInBranchExpressionTests.fs | 6 +++--- src/Fantomas.Tests/Ragnarok/LambdaExpressionTests.fs | 4 ++-- src/Fantomas.Tests/Ragnarok/LetOrUseBangExpressionTests.fs | 4 ++-- src/Fantomas.Tests/Ragnarok/LongIdentSetExpressionTests.fs | 4 ++-- .../MultiLineLambdaClosingNewlineExpressionTests.fs | 6 +++--- src/Fantomas.Tests/Ragnarok/NamedArgumentExpressionTests.fs | 4 ++-- src/Fantomas.Tests/Ragnarok/SetExpressionTests.fs | 4 ++-- .../Ragnarok/SynBindingFunctionExpressionTests.fs | 4 ++-- .../SynBindingFunctionLongPatternExpressionTests.fs | 6 +++--- .../SynBindingFunctionWithReturnTypeExpressionTests.fs | 4 ++-- .../Ragnarok/SynBindingValueExpressionTests.fs | 4 ++-- .../Ragnarok/SynExprAndBangExpressionTests.fs | 4 ++-- .../Ragnarok/SynMatchClauseExpressionTests.fs | 4 ++-- .../Ragnarok/SynTypeDefnSigReprSimpleTests.fs | 4 ++-- .../Ragnarok/YieldOrReturnBangExpressionTests.fs | 4 ++-- src/Fantomas.Tests/Ragnarok/YieldOrReturnExpressionTests.fs | 4 ++-- src/Fantomas/Context.fs | 5 ++++- 19 files changed, 43 insertions(+), 40 deletions(-) diff --git a/src/Fantomas.Tests/Ragnarok/DotIndexedSetExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/DotIndexedSetExpressionTests.fs index 7a63e89504..8a119b484b 100644 --- a/src/Fantomas.Tests/Ragnarok/DotIndexedSetExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/DotIndexedSetExpressionTests.fs @@ -6,8 +6,8 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } [] let ``dotIndexedSet with record instance `` () = diff --git a/src/Fantomas.Tests/Ragnarok/DotSetExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/DotSetExpressionTests.fs index 26ab5c2d9f..d2d03783d0 100644 --- a/src/Fantomas.Tests/Ragnarok/DotSetExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/DotSetExpressionTests.fs @@ -6,8 +6,8 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } [] let ``dotSet with record instance `` () = diff --git a/src/Fantomas.Tests/Ragnarok/KeepIndentInBranchExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/KeepIndentInBranchExpressionTests.fs index 125cd116b1..418bfe17c6 100644 --- a/src/Fantomas.Tests/Ragnarok/KeepIndentInBranchExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/KeepIndentInBranchExpressionTests.fs @@ -6,9 +6,9 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - KeepIndentInBranch = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + KeepIndentInBranch = true + Ragnarok = true } // There currently is no conflict with this setting, but I'm guessing the case was never brought up. // I would conclude that will never clash. diff --git a/src/Fantomas.Tests/Ragnarok/LambdaExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/LambdaExpressionTests.fs index d4f81815c8..73b3ee97b4 100644 --- a/src/Fantomas.Tests/Ragnarok/LambdaExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/LambdaExpressionTests.fs @@ -6,8 +6,8 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } [] let ``lambda with record instance `` () = diff --git a/src/Fantomas.Tests/Ragnarok/LetOrUseBangExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/LetOrUseBangExpressionTests.fs index 2612abd9eb..dfea4679d6 100644 --- a/src/Fantomas.Tests/Ragnarok/LetOrUseBangExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/LetOrUseBangExpressionTests.fs @@ -6,8 +6,8 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } [] let ``letOrUseBang with record instance`` () = diff --git a/src/Fantomas.Tests/Ragnarok/LongIdentSetExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/LongIdentSetExpressionTests.fs index 1f58422468..4d403f96f5 100644 --- a/src/Fantomas.Tests/Ragnarok/LongIdentSetExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/LongIdentSetExpressionTests.fs @@ -6,8 +6,8 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } [] let ``longIdentSet with record instance `` () = diff --git a/src/Fantomas.Tests/Ragnarok/MultiLineLambdaClosingNewlineExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/MultiLineLambdaClosingNewlineExpressionTests.fs index ac090367e2..85dfe5983a 100644 --- a/src/Fantomas.Tests/Ragnarok/MultiLineLambdaClosingNewlineExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/MultiLineLambdaClosingNewlineExpressionTests.fs @@ -6,9 +6,9 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - MultiLineLambdaClosingNewline = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + MultiLineLambdaClosingNewline = true + Ragnarok = true } // TODO: figure out what should happen when you mix MultiLineLambdaClosingNewline and Ragnarok // From a technical point of view, this is correct behavior but having `})` at the end seems sensible as well. diff --git a/src/Fantomas.Tests/Ragnarok/NamedArgumentExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/NamedArgumentExpressionTests.fs index bda740b56b..7d61fc2fa9 100644 --- a/src/Fantomas.Tests/Ragnarok/NamedArgumentExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/NamedArgumentExpressionTests.fs @@ -6,8 +6,8 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } [] let ``synExprApp with named argument with record instance`` () = diff --git a/src/Fantomas.Tests/Ragnarok/SetExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SetExpressionTests.fs index 8252c0d60a..39fe7c888f 100644 --- a/src/Fantomas.Tests/Ragnarok/SetExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SetExpressionTests.fs @@ -6,8 +6,8 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } [] let ``set with record instance `` () = diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs index dd77e85de5..a64a94476e 100644 --- a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionExpressionTests.fs @@ -6,8 +6,8 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } [] let ``synbinding function with record instance `` () = diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs index 255d9f8211..0fd8034c34 100644 --- a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionLongPatternExpressionTests.fs @@ -6,9 +6,9 @@ open Fantomas.Tests.TestHelper let config = { config with - MaxLineLength = 80 - MultilineBlockBracketsOnSameColumn = true - Ragnarok = true } + MaxLineLength = 80 + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } // TODO: conclude on what should happen here // This one feels very weird to have `= {` because the pattern is already multiline diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionWithReturnTypeExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionWithReturnTypeExpressionTests.fs index c4167d2557..fc32ac78db 100644 --- a/src/Fantomas.Tests/Ragnarok/SynBindingFunctionWithReturnTypeExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingFunctionWithReturnTypeExpressionTests.fs @@ -6,8 +6,8 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } [] let ``synbinding function with record instance `` () = diff --git a/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs index 98c2c7f923..ab455d6e2e 100644 --- a/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynBindingValueExpressionTests.fs @@ -6,8 +6,8 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } [] let ``synbinding value with record instance `` () = diff --git a/src/Fantomas.Tests/Ragnarok/SynExprAndBangExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynExprAndBangExpressionTests.fs index 37f5f16bdb..e57ecc9ca8 100644 --- a/src/Fantomas.Tests/Ragnarok/SynExprAndBangExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynExprAndBangExpressionTests.fs @@ -6,8 +6,8 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } [] let ``andBang with record instance`` () = diff --git a/src/Fantomas.Tests/Ragnarok/SynMatchClauseExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/SynMatchClauseExpressionTests.fs index edfb8572a6..c77b39c7f1 100644 --- a/src/Fantomas.Tests/Ragnarok/SynMatchClauseExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynMatchClauseExpressionTests.fs @@ -6,8 +6,8 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } [] let ``synMatchClause in match expression with record instance `` () = diff --git a/src/Fantomas.Tests/Ragnarok/SynTypeDefnSigReprSimpleTests.fs b/src/Fantomas.Tests/Ragnarok/SynTypeDefnSigReprSimpleTests.fs index 797cb10ce7..4bca70defd 100644 --- a/src/Fantomas.Tests/Ragnarok/SynTypeDefnSigReprSimpleTests.fs +++ b/src/Fantomas.Tests/Ragnarok/SynTypeDefnSigReprSimpleTests.fs @@ -6,8 +6,8 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } [] let ``record type definition`` () = diff --git a/src/Fantomas.Tests/Ragnarok/YieldOrReturnBangExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/YieldOrReturnBangExpressionTests.fs index 80f57ca901..e0e3427fd9 100644 --- a/src/Fantomas.Tests/Ragnarok/YieldOrReturnBangExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/YieldOrReturnBangExpressionTests.fs @@ -6,8 +6,8 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } [] let ``yieldOrReturnBang with record instance`` () = diff --git a/src/Fantomas.Tests/Ragnarok/YieldOrReturnExpressionTests.fs b/src/Fantomas.Tests/Ragnarok/YieldOrReturnExpressionTests.fs index 6550811f2d..7818f6827c 100644 --- a/src/Fantomas.Tests/Ragnarok/YieldOrReturnExpressionTests.fs +++ b/src/Fantomas.Tests/Ragnarok/YieldOrReturnExpressionTests.fs @@ -6,8 +6,8 @@ open Fantomas.Tests.TestHelper let config = { config with - MultilineBlockBracketsOnSameColumn = true - Ragnarok = true } + MultilineBlockBracketsOnSameColumn = true + Ragnarok = true } [] let ``yieldOrReturn with record instance`` () = diff --git a/src/Fantomas/Context.fs b/src/Fantomas/Context.fs index 998a2c565a..bdd76e1d2a 100644 --- a/src/Fantomas/Context.fs +++ b/src/Fantomas/Context.fs @@ -632,7 +632,9 @@ let internal ifElse b (f1: Context -> Context) f2 (ctx: Context) = if b then f1 let internal ifElseCtx cond (f1: Context -> Context) f2 (ctx: Context) = if cond ctx then f1 ctx else f2 ctx let internal ifRagnarokElse = ifElseCtx (fun ctx -> ctx.Config.Ragnarok) -let internal ifRagnarok (f1: Context -> Context) = ifElseCtx (fun ctx -> ctx.Config.Ragnarok) f1 id + +let internal ifRagnarok (f1: Context -> Context) = + ifElseCtx (fun ctx -> ctx.Config.Ragnarok) f1 id /// apply f only when cond is true let internal onlyIf cond f ctx = if cond then f ctx else ctx @@ -681,6 +683,7 @@ let internal sepNlnUnlessLastEventIsNewline (ctx: Context) = ctx else sepNln ctx + let internal sepNlnUnlessLastEventIsNewlineOrRagnarok (ctx: Context) = if lastWriteEventIsNewline ctx || ctx.Config.Ragnarok then ctx