Skip to content

Commit

Permalink
Feature BlankLinesAroundNestedMultilineExpressions (#1587)
Browse files Browse the repository at this point in the history
* Initial commit for setting NewlinesAroundInnerMultilineExpressions.

* Add support for combination with KeepIndentInBranch setting.

* Rename setting to BlankLinesAroundNestedMultilineExpressions and add documentation.
  • Loading branch information
nojaf committed Apr 5, 2021
1 parent cdee1f9 commit 494693e
Show file tree
Hide file tree
Showing 7 changed files with 362 additions and 16 deletions.
43 changes: 43 additions & 0 deletions docs/Documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ fsharp_alternative_long_member_definitions=false
fsharp_multi_line_lambda_closing_newline=false
fsharp_disable_elmish_syntax=false
fsharp_keep_indent_in_branch=false
fsharp_blank_lines_around_nested_multiline_expressions=true
fsharp_strict_mode=false
```

Expand Down Expand Up @@ -1060,6 +1061,48 @@ let main argv =
0
```

### fsharp_blank_lines_around_nested_multiline_expressions

Surround **nested** multi-line expressions with blank lines.
Existing blank lines are always preserved (via trivia).
Top level expressions will always follow the [2020 blank lines revision](https://github.com/fsprojects/fantomas/blob/master/docs/FormattingConventions.md#2020-revision) principle.
Default = true.

`defaultConfig`

```fsharp
let topLevelFunction () =
printfn "Something to print"
try
nothing ()
with
| ex ->
splash ()
()
let secondTopLevelFunction () =
// ...
()
```

`{ defaultConfig with BlankLinesAroundNestedMultilineExpressions = false }`

```fsharp
let topLevelFunction () =
printfn "Something to print"
try
nothing ()
with
| ex ->
splash ()
()
let secondTopLevelFunction () =
// ...
()
```

### fsharp_strict_mode

If being set, pretty printing is only done via ASTs. Compiler directives, inline comments and block comments will be ignored.
Expand Down
245 changes: 245 additions & 0 deletions src/Fantomas.Tests/BlankLinesAroundNestedMultilineExpressions.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
module Fantomas.Tests.BlankLinesAroundNestedMultilineExpressions

open NUnit.Framework
open FsUnit
open Fantomas.Tests.TestHelper

let config =
{ config with
BlankLinesAroundNestedMultilineExpressions = false }

[<Test>]
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"
()
"""

[<Test>]
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"
()
"""

[<Test>]
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 ()
()
"""

[<Test>]
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
"""

[<Test>]
let ``disable blank lines inside type constructor`` () =
formatSourceString
false
"""
type MNIST(path:string, ?urls:seq<string>, ?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<string>,
?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
"""

[<Test>]
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
}
"""
1 change: 1 addition & 0 deletions src/Fantomas.Tests/Fantomas.Tests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
<Compile Include="DotIndexedSetTests.fs" />
<Compile Include="MultilineFunctionApplicationsInConditionExpressionsTests.fs" />
<Compile Include="KeepIndentInBranch.fs" />
<Compile Include="BlankLinesAroundNestedMultilineExpressions.fs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Fantomas.Extras\Fantomas.Extras.fsproj" />
Expand Down
48 changes: 48 additions & 0 deletions src/Fantomas.Tests/KeepIndentInBranch.fs
Original file line number Diff line number Diff line change
Expand Up @@ -859,3 +859,51 @@ module Foo =
Thing.execute bar baz (thing, instructions)
0
"""

[<Test>]
let ``in combination with NewlinesAroundInnerMultilineExpressions`` () =
formatSourceString
false
"""
module Foo =
let main (args: _) =
let thing1 = ()
printfn ""
if hasInstructions () then
printfn ""
2
else
log.LogInformation("")
match Something.foo args with
| DryRunMode.Dry ->
printfn ""
0
| DryRunMode.Wet ->
Thing.execute bar baz (thing, instructions)
0
"""
{ config with
BlankLinesAroundNestedMultilineExpressions = false }
|> prepend newline
|> should
equal
"""
module Foo =
let main (args: _) =
let thing1 = ()
printfn ""
if hasInstructions () then
printfn ""
2
else
log.LogInformation("")
match Something.foo args with
| DryRunMode.Dry ->
printfn ""
0
| DryRunMode.Wet ->
Thing.execute bar baz (thing, instructions)
0
"""
Loading

0 comments on commit 494693e

Please sign in to comment.