Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion docs/Documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ fsharp_disable_elmish_syntax=false
fsharp_keep_indent_in_branch=false
fsharp_blank_lines_around_nested_multiline_expressions=true
fsharp_bar_before_discriminated_union_declaration=false
fsharp_keep_max_number_of_blank_lines=100
fsharp_strict_mode=false
```

Expand Down Expand Up @@ -1167,7 +1168,7 @@ let main argv =
### fsharp_blank_lines_around_nested_multiline_expressions

Surround **nested** multi-line expressions with blank lines.
Existing blank lines are always preserved (via trivia).
Existing blank lines are always preserved (via trivia), with exception when [fsharp_keep_max_number_of_blank_lines](#fsharp_keep_max_number_of_blank_lines) is used.
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.

Expand Down Expand Up @@ -1221,6 +1222,29 @@ type MyDU = Short of int
type MyDU = | Short of int
```

### fsharp_keep_max_number_of_blank_lines

Set maximal number of consecutive blank lines to keep from original source. It doesn't change number of new blank lines generated by Fantomas.
Default=100

`defaultConfig`

```fsharp
open Foo


let x = 42
```

`{ defaultConfig with KeepMaxNumberOfBlankLines = 1 }`

```fsharp
open Foo

let x = 42
```


### 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
1 change: 1 addition & 0 deletions src/Fantomas.Core.Tests/Fantomas.Core.Tests.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
<Compile Include="IndexSyntaxTests.fs" />
<Compile Include="InsertFinalNewlineTests.fs" />
<Compile Include="SingleExprTests.fs" />
<Compile Include="KeepMaxEmptyLinesTests.fs" />
<Compile Include="IgnoreFileTests.fs" />
<Compile Include="Ragnarok\SynBindingValueExpressionTests.fs" />
<Compile Include="Ragnarok\SynBindingFunctionExpressionTests.fs" />
Expand Down
109 changes: 109 additions & 0 deletions src/Fantomas.Core.Tests/KeepMaxEmptyLinesTests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
module Fantomas.Core.Tests.KeepMaxEmptyLinesTests

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

let checkFormat config source expected =
formatSourceString false source config
|> prepend newline
|> should equal expected

let config x =
{ config with KeepMaxNumberOfBlankLines = x }

[<Test>]
let ``reduce 2 empty lines to 1`` () =
checkFormat
(config 1)
"""
open Foo


let x = 42
"""
"""
open Foo

let x = 42
"""

[<Test>]
let ``reduce 3 empty lines to 2`` () =
checkFormat
(config 2)
"""
open Foo



let x = 42
"""
"""
open Foo


let x = 42
"""

[<Test>]
let ``reduce 3 empty lines to 1`` () =
checkFormat
(config 1)
"""
open Foo



let x = 42
"""
"""
open Foo

let x = 42
"""


[<Test>]
let ``only generated empty lines`` () =
checkFormat
(config 0)
"""
open Foo

open Goo

module M1 =

let x = 42
module M2 = let y = 42
"""
"""
open Foo
open Goo

module M1 =
let x = 42

module M2 =
let y = 42
"""

[<Test>]
let ``dont reduce empty lines in string`` () =
checkFormat
(config 1)
"
let x = \"\"\"


\"\"\"
"
"
let x =
\"\"\"


\"\"\"
"
5 changes: 3 additions & 2 deletions src/Fantomas.Core.Tests/TriviaTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ open Fantomas.Core
open Fantomas.Core.SourceParser
open Fantomas.Core.Tests.TestHelper
open Fantomas.Core.TriviaTypes
open Fantomas.Core.FormatConfig

let private toTrivia source =
let sourceText = CodeFormatterImpl.getSourceText source
let ast, _ = Fantomas.FCS.Parse.parseFile false sourceText []
Trivia.collectTrivia sourceText ast
Trivia.collectTrivia FormatConfig.Default sourceText ast

let private toTriviaWithDefines source =
let sourceText = CodeFormatterImpl.getSourceText source
Expand All @@ -23,7 +24,7 @@ let private toTriviaWithDefines source =
let defineCombinations = Defines.getDefineCombination hashDirectives

defineCombinations
|> List.map (fun dc -> dc, Trivia.collectTrivia sourceText ast)
|> List.map (fun dc -> dc, Trivia.collectTrivia FormatConfig.Default sourceText ast)
|> Map.ofList

[<Test>]
Expand Down
2 changes: 1 addition & 1 deletion src/Fantomas.Core/Context.fs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ type internal Context =
static member Create config (source: ISourceText option) (defineCombination: DefineCombination) (ast: ParsedInput) =
let trivia, sourceText =
match source with
| Some source when not config.StrictMode -> Trivia.collectTrivia source ast, Some source
| Some source when not config.StrictMode -> Trivia.collectTrivia config source ast, Some source
| _ -> [], None

let triviaByNodes =
Expand Down
5 changes: 5 additions & 0 deletions src/Fantomas.Core/FormatConfig.fs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ type FormatConfig =
[<DisplayName("Ragnarok")>]
Ragnarok: bool

[<Category("Convention")>]
[<DisplayName("Maximum number of consecutive blank lines to keep")>]
KeepMaxNumberOfBlankLines: Num

[<Category("Convention")>]
[<DisplayName("Strict mode")>]
[<Description("Pretty printing based on ASTs only.\nPlease do not use this setting for formatting hand written code!")>]
Expand Down Expand Up @@ -268,4 +272,5 @@ type FormatConfig =
BlankLinesAroundNestedMultilineExpressions = true
BarBeforeDiscriminatedUnionDeclaration = false
Ragnarok = false
KeepMaxNumberOfBlankLines = 100
StrictMode = false }
19 changes: 12 additions & 7 deletions src/Fantomas.Core/Trivia.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ open Fantomas.Core.ISourceTextExtensions
open Fantomas.Core.SourceParser
open Fantomas.Core.AstTransformer
open Fantomas.Core.TriviaTypes
open Fantomas.Core.FormatConfig

let inline isMainNodeFor nodeType (node: TriviaNodeAssigner) = nodeType = node.Type

Expand Down Expand Up @@ -289,6 +290,7 @@ let internal collectTriviaFromCodeComments (source: ISourceText) (codeComments:
{ Item = item; Range = r })

let internal collectTriviaFromBlankLines
(config: FormatConfig)
(source: ISourceText)
(triviaNodes: TriviaNodeAssigner list)
(codeComments: CommentTrivia list)
Expand Down Expand Up @@ -326,29 +328,32 @@ let internal collectTriviaFromBlankLines

let max = source.GetLineCount() - 1

[ 0..max ]
|> List.choose (fun idx ->
(0, [ 0..max ])
||> List.chooseState (fun count idx ->
if ignoreLines.Contains(idx + 1) then
None
0, None
else
let line = source.GetLineString(idx)

if String.isNotNullOrWhitespace line then
None
0, None
else
let range =
let p = Position.mkPos (idx + 1) 0
Range.mkFileIndexRange fileIndex p p

Some { Item = Newline; Range = range })
if count < config.KeepMaxNumberOfBlankLines then
(count + 1), Some { Item = Newline; Range = range }
else
count, None)

(*
1. Collect TriviaNode from tokens and AST
2. Collect TriviaContent from tokens
3. Merge trivias with triviaNodes
4. genTrivia should use ranges to identify what extra content should be added from what triviaNode
*)
let collectTrivia (source: ISourceText) (ast: ParsedInput) : TriviaNode list =
let collectTrivia (config: FormatConfig) (source: ISourceText) (ast: ParsedInput) : TriviaNode list =
let triviaNodesFromAST, directives, codeComments =
match ast with
| ParsedInput.ImplFile (ParsedImplFileInput (hds, mns, directives, codeComments)) ->
Expand All @@ -363,7 +368,7 @@ let collectTrivia (source: ISourceText) (ast: ParsedInput) : TriviaNode list =
let trivia =
[ yield! collectTriviaFromDirectives source directives
yield! collectTriviaFromCodeComments source codeComments
yield! collectTriviaFromBlankLines source triviaNodes codeComments ]
yield! collectTriviaFromBlankLines config source triviaNodes codeComments ]
|> List.sortBy (fun n -> n.Range.Start.Line, n.Range.Start.Column)

let startOfSourceCode = 1
Expand Down
9 changes: 9 additions & 0 deletions src/Fantomas.Core/Utils.fs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,15 @@ module List =
s <- s'
r)

let chooseState f state l =
let mutable s = state

l
|> List.choose (fun x ->
let s', r = f s x
s <- s'
r)

let isNotEmpty l = (List.isEmpty >> not) l

let moreThanOne =
Expand Down