From 58282653c1ce4bddee1e5d292affbd027782bbc5 Mon Sep 17 00:00:00 2001 From: Josh DeGraw <18509575+josh-degraw@users.noreply.github.com> Date: Thu, 2 Feb 2023 00:53:44 -0700 Subject: [PATCH] Extract setting for preference of newline placement for computation expressions (#2746) * Add new setting * Add test * Implement new setting * Add setting-specific tests to its own file * Fix an issue with applying to lambdas * Fix issue when applying to LetBang and AndBang * Fix all failing tests, some cleanup * Remove invalid tests, some more cleanup * Rename some helpers * temp * Cleanup, add test * Rename setting * Use local Fantomas.Core reference for Configuration.fsx. * Rename some things and fix assertion * Update docs * Simplify isStroustrupStyleExpr * Rename test file to match setting name. * Add additional test to highlight that settings don't affect each other. --------- Co-authored-by: nojaf --- docs/docs/end-users/Configuration.fsx | 20 + .../Fantomas.Core.Tests.fsproj | 1 + ...foreMultilineComputationExpressionTests.fs | 724 ++++++++++++++++++ .../DotIndexedSetExpressionTests.fs | 68 -- .../Stroustrup/DotSetExpressionTests.fs | 22 - .../Stroustrup/LambdaExpressionTests.fs | 116 --- .../Stroustrup/LetOrUseBangExpressionTests.fs | 29 - .../Stroustrup/LongIdentSetExpressionTests.fs | 22 - ...LineLambdaClosingNewlineExpressionTests.fs | 94 --- .../NamedArgumentExpressionTests.fs | 56 -- .../Stroustrup/SetExpressionTests.fs | 22 - .../SynBindingFunctionExpressionTests.fs | 46 -- ...ngFunctionWithReturnTypeExpressionTests.fs | 46 -- .../SynBindingValueExpressionTests.fs | 46 -- .../SynExprAndBangExpressionTests.fs | 32 - .../SynMatchClauseExpressionTests.fs | 51 -- .../YieldOrReturnBangExpressionTests.fs | 36 - .../YieldOrReturnExpressionTests.fs | 36 - src/Fantomas.Core/CodePrinter.fs | 10 +- src/Fantomas.Core/Context.fs | 23 +- src/Fantomas.Core/Context.fsi | 4 +- src/Fantomas.Core/FormatConfig.fs | 5 + .../EditorConfigurationTests.fs | 19 + 23 files changed, 786 insertions(+), 742 deletions(-) create mode 100644 src/Fantomas.Core.Tests/NewlineBeforeMultilineComputationExpressionTests.fs diff --git a/docs/docs/end-users/Configuration.fsx b/docs/docs/end-users/Configuration.fsx index 72501fc13e..a205f1f6f1 100644 --- a/docs/docs/end-users/Configuration.fsx +++ b/docs/docs/end-users/Configuration.fsx @@ -641,6 +641,26 @@ formatCode MultilineBracketStyle = Stroustrup } (*** include-output ***) +(** + + +Insert a newline before a computation expression that spans multiple lines + +Default = true +*) + +formatCode + """ + let something = + task { + let! thing = otherThing () + return 5 + } + """ + { FormatConfig.Default with + NewlineBeforeMultilineComputationExpression = false } +(*** include-output ***) + (** ## G-Research style diff --git a/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj b/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj index 8dd03d0334..0de852ccd3 100644 --- a/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj +++ b/src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj @@ -35,6 +35,7 @@ + diff --git a/src/Fantomas.Core.Tests/NewlineBeforeMultilineComputationExpressionTests.fs b/src/Fantomas.Core.Tests/NewlineBeforeMultilineComputationExpressionTests.fs new file mode 100644 index 0000000000..1d72f52339 --- /dev/null +++ b/src/Fantomas.Core.Tests/NewlineBeforeMultilineComputationExpressionTests.fs @@ -0,0 +1,724 @@ +module Fantomas.Core.Tests.NewlineBeforeMultilineComputationExpressionTests + +open NUnit.Framework +open FsUnit +open Fantomas.Core.Tests.TestHelper +open Fantomas.Core + +let config = + { config with + NewlineBeforeMultilineComputationExpression = false + MaxArrayOrListWidth = 40 } + +[] +let ``prefer computation expression name on same line`` () = + formatSourceString + false + """ +let t = + task { + let! thing = otherThing () + return 5 + } +""" + config + |> prepend newline + |> should + equal + """ +let t = task { + let! thing = otherThing () + return 5 +} +""" + +[] +let ``prefer computation expression name on same line handling short expression`` () = + formatSourceString + false + """ +let t = + task { + return () + } +""" + config + |> prepend newline + |> should + equal + """ +let t = task { return () } +""" + +[] +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 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 ``dotIndexedSet with computation expression`` () = + formatSourceString + false + """ +myMutable.[x] <- + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +myMutable.[x] <- task { + // some computation here + () +} +""" + +[] +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 ``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 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 ``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 ``lambda with computation expression`` () = + formatSourceString + false + """ +fun x -> + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +fun x -> task { + // some computation here + () +} +""" + +[] +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 ``longIdentSet with computation expression`` () = + formatSourceString + false + """ +myMutable <- + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +myMutable <- task { + // some computation here + () +} +""" + +[] +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 ``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 ``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 ``set with computation expression`` () = + formatSourceString + false + """ +myMutable[x] <- + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +myMutable[x] <- task { + // some computation here + () +} +""" + +[] +let ``synbinding function with computation expression`` () = + formatSourceString + false + """ +let x y = + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +let x y = task { + // some computation here + () +} +""" + +[] +let ``synbinding function with computation expression with return type`` () = + formatSourceString + false + """ +let x y: Task = + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +let x y : Task = task { + // some computation here + () +} +""" + +[] +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 computation expression with return type`` () = + 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 ``synbinding value with computation expression`` () = + formatSourceString + false + """ +let t = + task { + // some computation here + () + } +""" + config + |> prepend newline + |> should + equal + """ +let t = task { + // some computation here + () +} +""" + +[] +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 ``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 ``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 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 ``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 ``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 ``prefer computation expression name on same line, with trivia`` () = + formatSourceString + false + """ +let t = + // + task { + let! thing = otherThing () + return 5 + } +""" + config + |> prepend newline + |> should + equal + """ +let t = + // + task { + let! thing = otherThing () + return 5 + } +""" + +[] +let ``fsharp_multiline_bracket_style = stroustrup has not influence`` () = + formatSourceString + false + """ +fun _ -> task { // foo + () } +""" + { FormatConfig.Default with + MultilineBracketStyle = Stroustrup } + |> prepend newline + |> should + equal + """ +fun _ -> + task { // foo + () + } +""" diff --git a/src/Fantomas.Core.Tests/Stroustrup/DotIndexedSetExpressionTests.fs b/src/Fantomas.Core.Tests/Stroustrup/DotIndexedSetExpressionTests.fs index ea829c6124..8f881af18e 100644 --- a/src/Fantomas.Core.Tests/Stroustrup/DotIndexedSetExpressionTests.fs +++ b/src/Fantomas.Core.Tests/Stroustrup/DotIndexedSetExpressionTests.fs @@ -96,28 +96,6 @@ myMutable.[x] <- struct {| |} """ -[] -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 @@ -256,28 +234,6 @@ app().[x] <- struct {| |} """ -[] -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 @@ -426,30 +382,6 @@ app( |} """ -[] -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 diff --git a/src/Fantomas.Core.Tests/Stroustrup/DotSetExpressionTests.fs b/src/Fantomas.Core.Tests/Stroustrup/DotSetExpressionTests.fs index b95a5b7d45..db191b34db 100644 --- a/src/Fantomas.Core.Tests/Stroustrup/DotSetExpressionTests.fs +++ b/src/Fantomas.Core.Tests/Stroustrup/DotSetExpressionTests.fs @@ -119,28 +119,6 @@ App().foo <- struct {| |} """ -[] -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 diff --git a/src/Fantomas.Core.Tests/Stroustrup/LambdaExpressionTests.fs b/src/Fantomas.Core.Tests/Stroustrup/LambdaExpressionTests.fs index 887c056d32..d1c80fd6b3 100644 --- a/src/Fantomas.Core.Tests/Stroustrup/LambdaExpressionTests.fs +++ b/src/Fantomas.Core.Tests/Stroustrup/LambdaExpressionTests.fs @@ -96,28 +96,6 @@ fun x -> struct {| |} """ -[] -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 @@ -256,28 +234,6 @@ let ``paren lambda with anonymous record instance struct`` () = |}) """ -[] -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 @@ -416,28 +372,6 @@ List.map (fun x -> struct {| |}) """ -[] -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 @@ -588,31 +522,6 @@ List.map 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 @@ -773,31 +682,6 @@ Bar .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 diff --git a/src/Fantomas.Core.Tests/Stroustrup/LetOrUseBangExpressionTests.fs b/src/Fantomas.Core.Tests/Stroustrup/LetOrUseBangExpressionTests.fs index 9c1376e62d..6c2eee6a1b 100644 --- a/src/Fantomas.Core.Tests/Stroustrup/LetOrUseBangExpressionTests.fs +++ b/src/Fantomas.Core.Tests/Stroustrup/LetOrUseBangExpressionTests.fs @@ -131,35 +131,6 @@ opt { } """ -[] -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 diff --git a/src/Fantomas.Core.Tests/Stroustrup/LongIdentSetExpressionTests.fs b/src/Fantomas.Core.Tests/Stroustrup/LongIdentSetExpressionTests.fs index b8f4f287e9..f4b7386886 100644 --- a/src/Fantomas.Core.Tests/Stroustrup/LongIdentSetExpressionTests.fs +++ b/src/Fantomas.Core.Tests/Stroustrup/LongIdentSetExpressionTests.fs @@ -96,28 +96,6 @@ myMutable <- struct {| |} """ -[] -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 diff --git a/src/Fantomas.Core.Tests/Stroustrup/MultiLineLambdaClosingNewlineExpressionTests.fs b/src/Fantomas.Core.Tests/Stroustrup/MultiLineLambdaClosingNewlineExpressionTests.fs index 26a92441c8..6cd4f24c8d 100644 --- a/src/Fantomas.Core.Tests/Stroustrup/MultiLineLambdaClosingNewlineExpressionTests.fs +++ b/src/Fantomas.Core.Tests/Stroustrup/MultiLineLambdaClosingNewlineExpressionTests.fs @@ -97,28 +97,6 @@ let ``paren lambda with anonymous record instance struct`` () = |}) """ -[] -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 @@ -257,28 +235,6 @@ List.map (fun x -> struct {| |}) """ -[] -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 @@ -429,31 +385,6 @@ List.map 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 @@ -614,31 +545,6 @@ Bar .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 diff --git a/src/Fantomas.Core.Tests/Stroustrup/NamedArgumentExpressionTests.fs b/src/Fantomas.Core.Tests/Stroustrup/NamedArgumentExpressionTests.fs index 2e6a07ead7..e071d88ba6 100644 --- a/src/Fantomas.Core.Tests/Stroustrup/NamedArgumentExpressionTests.fs +++ b/src/Fantomas.Core.Tests/Stroustrup/NamedArgumentExpressionTests.fs @@ -125,34 +125,6 @@ let v = ) """ -[] -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 @@ -379,34 +351,6 @@ let v = ) """ -[] -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 diff --git a/src/Fantomas.Core.Tests/Stroustrup/SetExpressionTests.fs b/src/Fantomas.Core.Tests/Stroustrup/SetExpressionTests.fs index d175588d89..bfc83edf8d 100644 --- a/src/Fantomas.Core.Tests/Stroustrup/SetExpressionTests.fs +++ b/src/Fantomas.Core.Tests/Stroustrup/SetExpressionTests.fs @@ -96,28 +96,6 @@ myMutable[x] <- struct {| |} """ -[] -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 diff --git a/src/Fantomas.Core.Tests/Stroustrup/SynBindingFunctionExpressionTests.fs b/src/Fantomas.Core.Tests/Stroustrup/SynBindingFunctionExpressionTests.fs index 4bef1fbbe4..219ec5e8d6 100644 --- a/src/Fantomas.Core.Tests/Stroustrup/SynBindingFunctionExpressionTests.fs +++ b/src/Fantomas.Core.Tests/Stroustrup/SynBindingFunctionExpressionTests.fs @@ -73,28 +73,6 @@ let x y = {| |} """ -[] -let ``synbinding function with computation expression`` () = - formatSourceString - false - """ -let x y = - task { - // some computation here - () - } -""" - config - |> prepend newline - |> should - equal - """ -let x y = task { - // some computation here - () -} -""" - [] let ``synbinding function with list`` () = formatSourceString @@ -240,30 +218,6 @@ type Foo() = |} """ -[] -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 diff --git a/src/Fantomas.Core.Tests/Stroustrup/SynBindingFunctionWithReturnTypeExpressionTests.fs b/src/Fantomas.Core.Tests/Stroustrup/SynBindingFunctionWithReturnTypeExpressionTests.fs index 721d834f4c..19ff09f198 100644 --- a/src/Fantomas.Core.Tests/Stroustrup/SynBindingFunctionWithReturnTypeExpressionTests.fs +++ b/src/Fantomas.Core.Tests/Stroustrup/SynBindingFunctionWithReturnTypeExpressionTests.fs @@ -73,28 +73,6 @@ let x y : {| A: int; B: int; C: int |} = {| |} """ -[] -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 @@ -240,30 +218,6 @@ type Foo() = |} """ -[] -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 diff --git a/src/Fantomas.Core.Tests/Stroustrup/SynBindingValueExpressionTests.fs b/src/Fantomas.Core.Tests/Stroustrup/SynBindingValueExpressionTests.fs index 0f6eef956c..654c191c57 100644 --- a/src/Fantomas.Core.Tests/Stroustrup/SynBindingValueExpressionTests.fs +++ b/src/Fantomas.Core.Tests/Stroustrup/SynBindingValueExpressionTests.fs @@ -119,28 +119,6 @@ let x = struct {| |} """ -[] -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 - () -} -""" - [] let ``synbinding value with list`` () = formatSourceString @@ -313,30 +291,6 @@ type Foo() = |} """ -[] -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 diff --git a/src/Fantomas.Core.Tests/Stroustrup/SynExprAndBangExpressionTests.fs b/src/Fantomas.Core.Tests/Stroustrup/SynExprAndBangExpressionTests.fs index d74b31ded0..c3d0e79b21 100644 --- a/src/Fantomas.Core.Tests/Stroustrup/SynExprAndBangExpressionTests.fs +++ b/src/Fantomas.Core.Tests/Stroustrup/SynExprAndBangExpressionTests.fs @@ -143,38 +143,6 @@ opt { } """ -[] -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 diff --git a/src/Fantomas.Core.Tests/Stroustrup/SynMatchClauseExpressionTests.fs b/src/Fantomas.Core.Tests/Stroustrup/SynMatchClauseExpressionTests.fs index aa8b9ca295..959701005b 100644 --- a/src/Fantomas.Core.Tests/Stroustrup/SynMatchClauseExpressionTests.fs +++ b/src/Fantomas.Core.Tests/Stroustrup/SynMatchClauseExpressionTests.fs @@ -104,30 +104,6 @@ match x with |} """ -[] -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 @@ -324,33 +300,6 @@ with ex -> struct {| |} """ -[] -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 diff --git a/src/Fantomas.Core.Tests/Stroustrup/YieldOrReturnBangExpressionTests.fs b/src/Fantomas.Core.Tests/Stroustrup/YieldOrReturnBangExpressionTests.fs index 80e58f97fc..9c0c9f6cdc 100644 --- a/src/Fantomas.Core.Tests/Stroustrup/YieldOrReturnBangExpressionTests.fs +++ b/src/Fantomas.Core.Tests/Stroustrup/YieldOrReturnBangExpressionTests.fs @@ -157,42 +157,6 @@ myComp { } """ -[] -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 diff --git a/src/Fantomas.Core.Tests/Stroustrup/YieldOrReturnExpressionTests.fs b/src/Fantomas.Core.Tests/Stroustrup/YieldOrReturnExpressionTests.fs index 7a859b8610..114d7151ae 100644 --- a/src/Fantomas.Core.Tests/Stroustrup/YieldOrReturnExpressionTests.fs +++ b/src/Fantomas.Core.Tests/Stroustrup/YieldOrReturnExpressionTests.fs @@ -157,42 +157,6 @@ myComp { } """ -[] -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 diff --git a/src/Fantomas.Core/CodePrinter.fs b/src/Fantomas.Core/CodePrinter.fs index 8e792313b9..79f2ae9cbd 100644 --- a/src/Fantomas.Core/CodePrinter.fs +++ b/src/Fantomas.Core/CodePrinter.fs @@ -1364,7 +1364,7 @@ let genExpr (e: Expr) = clauseNode.WhenExpr +> sepSpace +> genSingleTextNodeWithSpaceSuffix sepSpace clauseNode.Arrow - +> autoIndentAndNlnExpressUnlessStroustrup genExpr clauseNode.BodyExpr + +> indentSepNlnUnindentExprUnlessStroustrup genExpr clauseNode.BodyExpr +> leaveNode clauseNode atCurrentColumn ( @@ -1812,7 +1812,7 @@ let genNamedArgumentExpr (node: ExprInfixAppNode) = genExpr node.LeftHandSide +> sepSpace +> genSingleTextNode node.Operator - +> autoIndentAndNlnExpressUnlessStroustrup (fun e -> sepSpace +> genExpr e) node.RightHandSide + +> indentSepNlnUnindentExprUnlessStroustrup (fun e -> sepSpace +> genExpr e) node.RightHandSide expressionFitsOnRestOfLine short long |> genNode node @@ -2673,7 +2673,7 @@ let genBinding (b: BindingNode) (ctx: Context) : Context = let short = sepSpace +> body let long = - autoIndentAndNlnExpressUnlessStroustrup (fun e -> sepSpace +> genExpr e) b.Expr + indentSepNlnUnindentExprUnlessStroustrup (fun e -> sepSpace +> genExpr e) b.Expr isShortExpression ctx.Config.MaxFunctionBindingWidth short long @@ -2762,7 +2762,9 @@ let genBinding (b: BindingNode) (ctx: Context) : Context = +> (fun ctx -> let prefix = afterLetKeyword +> sepSpace +> genValueName +> genReturnType let short = prefix +> genExpr b.Expr - let long = prefix +> autoIndentAndNlnExpressUnlessStroustrup genExpr b.Expr + + let long = prefix +> indentSepNlnUnindentExprUnlessStroustrup genExpr b.Expr + isShortExpression ctx.Config.MaxValueBindingWidth short long ctx) genNode b binding ctx diff --git a/src/Fantomas.Core/Context.fs b/src/Fantomas.Core/Context.fs index dd65d6dca3..0b88cad3dd 100644 --- a/src/Fantomas.Core/Context.fs +++ b/src/Fantomas.Core/Context.fs @@ -756,17 +756,14 @@ let isStroustrupStyleExpr (config: FormatConfig) (e: Expr) = let isStroustrupEnabled = config.MultilineBracketStyle = Stroustrup match e with - | Expr.Record node when isStroustrupEnabled -> + | Expr.Record node -> match node.Extra with | RecordNodeExtra.Inherit _ -> false | RecordNodeExtra.With _ - | RecordNodeExtra.None -> true - | Expr.AnonRecord _ when isStroustrupEnabled -> true - | Expr.NamedComputation node when isStroustrupEnabled -> - match node.Name with - | Expr.Ident _ -> true - | _ -> false - | Expr.ArrayOrList _ when isStroustrupEnabled -> true + | RecordNodeExtra.None -> isStroustrupEnabled + | Expr.AnonRecord _ + | Expr.ArrayOrList _ -> isStroustrupEnabled + | Expr.NamedComputation _ -> not config.NewlineBeforeMultilineComputationExpression | _ -> false let isStroustrupStyleType (config: FormatConfig) (t: Type) = @@ -935,7 +932,7 @@ let addParenIfAutoNln expr f = let expr = f expr expressionFitsOnRestOfLine expr (ifElse hasParenthesis (sepOpenT +> expr +> sepCloseT) expr) -let autoIndentAndNlnExpressUnlessStroustrup (f: Expr -> Context -> Context) (e: Expr) (ctx: Context) = +let indentSepNlnUnindentExprUnlessStroustrup f (e: Expr) (ctx: Context) = let shouldUseStroustrup = isStroustrupStyleExpr ctx.Config e && canSafelyUseStroustrup (Expr.Node e) @@ -944,7 +941,7 @@ let autoIndentAndNlnExpressUnlessStroustrup (f: Expr -> Context -> Context) (e: else indentSepNlnUnindent (f e) ctx -let autoIndentAndNlnTypeUnlessStroustrup (f: Type -> Context -> Context) (t: Type) (ctx: Context) = +let autoIndentAndNlnTypeUnlessStroustrup f (t: Type) (ctx: Context) = let shouldUseStroustrup = isStroustrupStyleType ctx.Config t && canSafelyUseStroustrup (Type.Node t) @@ -953,11 +950,7 @@ let autoIndentAndNlnTypeUnlessStroustrup (f: Type -> Context -> Context) (t: Typ else autoIndentAndNlnIfExpressionExceedsPageWidth (f t) ctx -let autoIndentAndNlnIfExpressionExceedsPageWidthUnlessStroustrup - (f: Expr -> Context -> Context) - (e: Expr) - (ctx: Context) - = +let autoIndentAndNlnIfExpressionExceedsPageWidthUnlessStroustrup f (e: Expr) (ctx: Context) = let isStroustrup = isStroustrupStyleExpr ctx.Config e && canSafelyUseStroustrup (Expr.Node e) diff --git a/src/Fantomas.Core/Context.fsi b/src/Fantomas.Core/Context.fsi index 0797c8daea..7bb4b8db3a 100644 --- a/src/Fantomas.Core/Context.fsi +++ b/src/Fantomas.Core/Context.fsi @@ -256,7 +256,9 @@ val sepNlnWhenWriteBeforeNewlineNotEmpty: (Context -> Context) val sepSpaceUnlessWriteBeforeNewlineNotEmpty: ctx: Context -> Context val autoIndentAndNlnWhenWriteBeforeNewlineNotEmpty: f: (Context -> Context) -> ctx: Context -> Context val addParenIfAutoNln: expr: Expr -> f: (Expr -> Context -> Context) -> (Context -> Context) -val autoIndentAndNlnExpressUnlessStroustrup: f: (Expr -> Context -> Context) -> e: Expr -> ctx: Context -> Context + +val indentSepNlnUnindentExprUnlessStroustrup: f: (Expr -> Context -> Context) -> e: Expr -> ctx: Context -> Context + val autoIndentAndNlnTypeUnlessStroustrup: f: (Type -> Context -> Context) -> t: Type -> ctx: Context -> Context val autoIndentAndNlnIfExpressionExceedsPageWidthUnlessStroustrup: diff --git a/src/Fantomas.Core/FormatConfig.fs b/src/Fantomas.Core/FormatConfig.fs index b62da15643..6dd33c14ac 100644 --- a/src/Fantomas.Core/FormatConfig.fs +++ b/src/Fantomas.Core/FormatConfig.fs @@ -218,6 +218,10 @@ type FormatConfig = [] KeepMaxNumberOfBlankLines: Num + [] + [] + NewlineBeforeMultilineComputationExpression: bool + [] [] [] @@ -261,4 +265,5 @@ type FormatConfig = BarBeforeDiscriminatedUnionDeclaration = false MultilineBracketStyle = Cramped KeepMaxNumberOfBlankLines = 100 + NewlineBeforeMultilineComputationExpression = true StrictMode = false } diff --git a/src/Fantomas.Tests/EditorConfigurationTests.fs b/src/Fantomas.Tests/EditorConfigurationTests.fs index 7eadffe4cb..1cde1e3b9a 100644 --- a/src/Fantomas.Tests/EditorConfigurationTests.fs +++ b/src/Fantomas.Tests/EditorConfigurationTests.fs @@ -503,3 +503,22 @@ fsharp_multiline_bracket_style = cramped let config = EditorConfig.readConfiguration fsharpFile.FSharpFile Assert.AreEqual(Cramped, config.MultilineBracketStyle) + +[] +let fsharp_prefer_computation_expression_name_on_same_line () = + let rootDir = tempName () + + let editorConfig = + """ +[*.fs] +fsharp_newline_before_multiline_computation_expression = false +""" + + use configFixture = + new ConfigurationFile(defaultConfig, rootDir, content = editorConfig) + + use fsharpFile = new FSharpFile(rootDir) + + let config = EditorConfig.readConfiguration fsharpFile.FSharpFile + + Assert.IsFalse config.NewlineBeforeMultilineComputationExpression