From 5fed76b6c9c45aedc14b3b767a54d00e3c593913 Mon Sep 17 00:00:00 2001 From: nojaf Date: Sat, 3 Apr 2021 17:26:56 +0200 Subject: [PATCH] Initial commit for setting NewlinesAroundInnerMultilineExpressions. --- src/Fantomas.Tests/Fantomas.Tests.fsproj | 1 + ...NewlinesAroundInnerMultilineExpressions.fs | 245 ++++++++++++++++++ src/Fantomas/CodePrinter.fs | 9 +- src/Fantomas/Context.fs | 6 + src/Fantomas/FormatConfig.fs | 2 + 5 files changed, 259 insertions(+), 4 deletions(-) create mode 100644 src/Fantomas.Tests/NewlinesAroundInnerMultilineExpressions.fs diff --git a/src/Fantomas.Tests/Fantomas.Tests.fsproj b/src/Fantomas.Tests/Fantomas.Tests.fsproj index c6242bc4ff..0fab0d3623 100644 --- a/src/Fantomas.Tests/Fantomas.Tests.fsproj +++ b/src/Fantomas.Tests/Fantomas.Tests.fsproj @@ -85,6 +85,7 @@ + diff --git a/src/Fantomas.Tests/NewlinesAroundInnerMultilineExpressions.fs b/src/Fantomas.Tests/NewlinesAroundInnerMultilineExpressions.fs new file mode 100644 index 0000000000..3a4828dfc2 --- /dev/null +++ b/src/Fantomas.Tests/NewlinesAroundInnerMultilineExpressions.fs @@ -0,0 +1,245 @@ +module Fantomas.Tests.NewlinesAroundInnerMultilineExpressions + +open NUnit.Framework +open FsUnit +open Fantomas.Tests.TestHelper + +let config = + { config with + NewlinesAroundInnerMultilineExpressions = false } + +[] +let ``basic behavior`` () = + formatSourceString + false + """ +let topLevelFunction () = + let innerValue = 23 + let innerMultilineFunction () = + // some comment + printfn "foo" + () +""" + config + |> prepend newline + |> should + equal + """ +let topLevelFunction () = + let innerValue = 23 + let innerMultilineFunction () = + // some comment + printfn "foo" + () +""" + +[] +let ``existing newlines are preserved`` () = + formatSourceString + false + """ +let topLevelFunction () = + let innerValue = 23 + + let innerMultilineFunction () = + // some comment + printfn "foo" + () +""" + config + |> prepend newline + |> should + equal + """ +let topLevelFunction () = + let innerValue = 23 + + let innerMultilineFunction () = + // some comment + printfn "foo" + () +""" + +[] +let ``with sequential expressions`` () = + formatSourceString + false + """ +let topLevelFunction () = + printfn "Something to print" + try + nothing () + with + | ex -> + splash () + () +""" + config + |> prepend newline + |> should + equal + """ +let topLevelFunction () = + printfn "Something to print" + try + nothing () + with ex -> splash () + () +""" + +[] +let ``disable blank lines around multiline expressions inside let binding, 1370`` () = + formatSourceString + false + """ +let emit nodes = + let an = AssemblyName("a") + let ab = + AppDomain.CurrentDomain.DefineDynamicAssembly( + an, + AssemblyBuilderAccess.RunAndCollect + ) + let mb = ab.DefineDynamicModule("a") + let tb = mb.DefineType("Program") + nodes +""" + config + |> prepend newline + |> should + equal + """ +let emit nodes = + let an = AssemblyName("a") + let ab = + AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndCollect) + let mb = ab.DefineDynamicModule("a") + let tb = mb.DefineType("Program") + nodes +""" + +[] +let ``disable blank lines inside type constructor`` () = + formatSourceString + false + """ +type MNIST(path:string, ?urls:seq, ?train:bool, ?transform:Tensor->Tensor, ?targetTransform:Tensor->Tensor) = + inherit Dataset() + let path = Path.Combine(path, "mnist") |> Path.GetFullPath + let train = defaultArg train true + let transform = defaultArg transform (fun t -> (t - 0.1307) / 0.3081) + let targetTransform = defaultArg targetTransform id + let urls = List.ofSeq <| defaultArg urls (Seq.ofList + ["http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz"; + "http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz"; + "http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz"; + "http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz"]) + let files = [for url in urls do Path.Combine(path, Path.GetFileName(url))] + let filesProcessed = [for file in files do Path.ChangeExtension(file, ".tensor")] + let data, target = + Directory.CreateDirectory(path) |> ignore + let mutable data = dsharp.zero() + let mutable target = dsharp.zero() + if train then + if not (File.Exists(files.[0])) then download urls.[0] files.[0] + if not (File.Exists(files.[1])) then download urls.[1] files.[1] + if File.Exists(filesProcessed.[0]) then data <- dsharp.load(filesProcessed.[0]) else data <- MNIST.LoadMNISTImages(files.[0]); dsharp.save(data, filesProcessed.[0]) + if File.Exists(filesProcessed.[1]) then target <- dsharp.load(filesProcessed.[1]) else target <- MNIST.LoadMNISTLabels(files.[1]); dsharp.save(target, filesProcessed.[1]) + else + if not (File.Exists(files.[2])) then download urls.[2] files.[2] + if not (File.Exists(files.[3])) then download urls.[3] files.[3] + if File.Exists(filesProcessed.[2]) then data <- dsharp.load(filesProcessed.[2]) else data <- MNIST.LoadMNISTImages(files.[2]); dsharp.save(data, filesProcessed.[2]) + if File.Exists(filesProcessed.[3]) then target <- dsharp.load(filesProcessed.[3]) else target <- MNIST.LoadMNISTLabels(files.[3]); dsharp.save(target, filesProcessed.[3]) + data, target +""" + config + |> prepend newline + |> should + equal + """ +type MNIST + ( + path: string, + ?urls: seq, + ?train: bool, + ?transform: Tensor -> Tensor, + ?targetTransform: Tensor -> Tensor + ) = + inherit Dataset() + let path = + Path.Combine(path, "mnist") |> Path.GetFullPath + let train = defaultArg train true + let transform = + defaultArg transform (fun t -> (t - 0.1307) / 0.3081) + let targetTransform = defaultArg targetTransform id + let urls = + List.ofSeq + <| defaultArg + urls + (Seq.ofList [ "http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz" + "http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz" + "http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz" + "http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz" ]) + let files = + [ for url in urls do + Path.Combine(path, Path.GetFileName(url)) ] + let filesProcessed = + [ for file in files do + Path.ChangeExtension(file, ".tensor") ] + let data, target = + Directory.CreateDirectory(path) |> ignore + let mutable data = dsharp.zero () + let mutable target = dsharp.zero () + if train then + if not (File.Exists(files.[0])) then + download urls.[0] files.[0] + if not (File.Exists(files.[1])) then + download urls.[1] files.[1] + if File.Exists(filesProcessed.[0]) then + data <- dsharp.load (filesProcessed.[0]) + else + data <- MNIST.LoadMNISTImages(files.[0]) + dsharp.save (data, filesProcessed.[0]) + if File.Exists(filesProcessed.[1]) then + target <- dsharp.load (filesProcessed.[1]) + else + target <- MNIST.LoadMNISTLabels(files.[1]) + dsharp.save (target, filesProcessed.[1]) + else + if not (File.Exists(files.[2])) then + download urls.[2] files.[2] + if not (File.Exists(files.[3])) then + download urls.[3] files.[3] + if File.Exists(filesProcessed.[2]) then + data <- dsharp.load (filesProcessed.[2]) + else + data <- MNIST.LoadMNISTImages(files.[2]) + dsharp.save (data, filesProcessed.[2]) + if File.Exists(filesProcessed.[3]) then + target <- dsharp.load (filesProcessed.[3]) + else + target <- MNIST.LoadMNISTLabels(files.[3]) + dsharp.save (target, filesProcessed.[3]) + data, target +""" + +[] +let ``computation expressions`` () = + formatSourceString + false + """ +let comp = + eventually { for x in 1 .. 2 do + printfn " x = %d" x + return 3 + 4 }""" + config + |> prepend newline + |> should + equal + """ +let comp = + eventually { + for x in 1 .. 2 do + printfn " x = %d" x + return 3 + 4 + } +""" diff --git a/src/Fantomas/CodePrinter.fs b/src/Fantomas/CodePrinter.fs index d6cdc43c85..e291787f8d 100644 --- a/src/Fantomas/CodePrinter.fs +++ b/src/Fantomas/CodePrinter.fs @@ -1461,7 +1461,7 @@ and genExpr astContext synExpr ctx = let r = getRangeOfCompExprStatement ces let sepNln = getSepNln ces r ColMultilineItem(expr, sepNln, r)) - |> colWithNlnWhenItemIsMultiline + |> colWithNlnWhenItemIsMultilineBasedOnSetting | ArrayOrListOfSeqExpr (isArray, e) as alNode -> let astContext = { astContext with IsNakedRange = true } @@ -2077,7 +2077,8 @@ and genExpr astContext synExpr ctx = ) ] let items = letBindings bs @ synExpr e - atCurrentColumn (colWithNlnWhenItemIsMultiline items) ctx + + atCurrentColumn (colWithNlnWhenItemIsMultilineBasedOnSetting items) ctx // Could customize a bit if e is single line | TryWith (e, cs) -> @@ -2154,7 +2155,7 @@ and genExpr astContext synExpr ctx = ColMultilineItem(expr, sepNln, r)) - atCurrentColumn (colWithNlnWhenItemIsMultiline items) + atCurrentColumn (colWithNlnWhenItemIsMultilineBasedOnSetting items) // A generalization of IfThenElse | ElIf ((e1, e2, _, _, _) :: es, enOpt) -> @@ -4466,7 +4467,7 @@ and genMemberDefnList astContext nodes = :: (collectItems rest) collectItems nodes - |> colWithNlnWhenItemIsMultiline + |> colWithNlnWhenItemIsMultilineBasedOnSetting and genMemberDefn astContext node = match node with diff --git a/src/Fantomas/Context.fs b/src/Fantomas/Context.fs index 3e4d3dbf0d..39dfb5a99a 100644 --- a/src/Fantomas/Context.fs +++ b/src/Fantomas/Context.fs @@ -1507,6 +1507,12 @@ let internal colWithNlnWhenItemIsMultiline (items: ColMultilineItem list) = impl items +let internal colWithNlnWhenItemIsMultilineBasedOnSetting (items: ColMultilineItem list) (ctx: Context) = + if ctx.Config.NewlinesAroundInnerMultilineExpressions then + colWithNlnWhenItemIsMultiline items ctx + else + col sepNln items (fun (ColMultilineItem (expr, _, _)) -> expr) ctx + let internal genTriviaBeforeClausePipe (rangeOfClause: Range) ctx = (Map.tryFindOrEmptyList BAR ctx.TriviaTokenNodes) |> List.tryFind diff --git a/src/Fantomas/FormatConfig.fs b/src/Fantomas/FormatConfig.fs index 822f71868e..1d41944ee4 100644 --- a/src/Fantomas/FormatConfig.fs +++ b/src/Fantomas/FormatConfig.fs @@ -94,6 +94,7 @@ type FormatConfig = DisableElmishSyntax: bool EndOfLine: EndOfLineStyle KeepIndentInBranch: bool + NewlinesAroundInnerMultilineExpressions: bool /// Pretty printing based on ASTs only StrictMode: bool } @@ -134,4 +135,5 @@ type FormatConfig = DisableElmishSyntax = false EndOfLine = EndOfLineStyle.FromEnvironment KeepIndentInBranch = false + NewlinesAroundInnerMultilineExpressions = true StrictMode = false }