From 4f92ef70456a29d271bde7742375e1fb9317f7e1 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Sun, 29 Oct 2023 15:39:55 +0100 Subject: [PATCH 1/7] Update Fantomas rules per the now supported `fsharp_multiline_bracket_style` and the like --- src/.editorconfig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/.editorconfig b/src/.editorconfig index 8a8b2c98..3ac96717 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -260,6 +260,10 @@ fsharp_bar_before_discriminated_union_declaration=false # To work reliably, fsharp_multiline_block_brackets_on_same_column must be "true" fsharp_experimental_stroustrup_style=true +# above setting is for Fantomas 5.x. The new version uses these two +fsharp_multiline_bracket_style = stroustrup +fsharp_newline_before_multiline_computation_expression = false + # from docs: Please do not use this setting for formatting hand written code! # default false -fsharp_strict_mode=false +fsharp_strict_mode=false \ No newline at end of file From ee902f4357a9a5d06136934b69d46ab5260f5f59 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Sun, 29 Oct 2023 15:41:00 +0100 Subject: [PATCH 2/7] Reformat all source files --- .../TaskSeq.Let.Tests.fs | 2 +- src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs | 1 + src/FSharp.Control.TaskSeq/TaskSeqBuilder.fsi | 3 +++ src/FSharp.Control.TaskSeq/TaskSeqInternal.fs | 6 ++--- src/FSharp.Control.TaskSeq/Utils.fs | 27 +++++++++---------- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Let.Tests.fs b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Let.Tests.fs index ebdeb0eb..5ebd14bd 100644 --- a/src/FSharp.Control.TaskSeq.Test/TaskSeq.Let.Tests.fs +++ b/src/FSharp.Control.TaskSeq.Test/TaskSeq.Let.Tests.fs @@ -127,7 +127,7 @@ let ``CE taskSeq: use 'let!' with all kinds of overloads at once`` () = return value } - let! b = // eq 2 + let! b = // eq 2 task { do! Task.Delay 50 do value <- value + 1 diff --git a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs index 67107111..42f5769c 100644 --- a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs +++ b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs @@ -80,6 +80,7 @@ type TaskSeqStateMachineData<'T>() = member data.PushDispose(disposer: unit -> Task) = if isNull data.disposalStack then data.disposalStack <- ResizeArray() + data.disposalStack.Add disposer member data.PopDispose() = diff --git a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fsi b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fsi index b7b22590..420353c4 100644 --- a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fsi +++ b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fsi @@ -134,8 +134,10 @@ type TaskSeqBuilder = member inline TryFinally: body: ResumableTSC<'T> * compensationAction: (unit -> unit) -> ResumableTSC<'T> member inline TryFinallyAsync: body: ResumableTSC<'T> * compensationAction: (unit -> Task) -> ResumableTSC<'T> member inline TryWith: body: ResumableTSC<'T> * catch: (exn -> ResumableTSC<'T>) -> ResumableTSC<'T> + member inline Using: disp: 'Disp * body: ('Disp -> ResumableTSC<'T>) -> ResumableTSC<'T> when 'Disp :> IAsyncDisposable + member inline While: condition: (unit -> bool) * body: ResumableTSC<'T> -> ResumableTSC<'T> /// Used by `For`. F# currently doesn't support `while!`, so this cannot be called directly from the CE member inline WhileAsync: condition: (unit -> ValueTask) * body: ResumableTSC<'T> -> ResumableTSC<'T> @@ -179,6 +181,7 @@ module MediumPriority = // NOTE: syntax with '#Disposable' won't work properly in FSI member inline Using: dispensation: 'Disp * body: ('Disp -> ResumableTSC<'T>) -> ResumableTSC<'T> when 'Disp :> IDisposable + member inline For: sequence: seq<'TElement> * body: ('TElement -> ResumableTSC<'T>) -> ResumableTSC<'T> member inline YieldFrom: source: seq<'T> -> ResumableTSC<'T> member inline For: source: #taskSeq<'TElement> * body: ('TElement -> ResumableTSC<'T>) -> ResumableTSC<'T> diff --git a/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs b/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs index 87fc44af..a194c836 100644 --- a/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs +++ b/src/FSharp.Control.TaskSeq/TaskSeqInternal.fs @@ -120,7 +120,7 @@ module internal TaskSeqInternal = i <- i + 1 // update before moving: we are counting, not indexing go <- step - | Some (Predicate predicate) -> + | Some(Predicate predicate) -> while go do if predicate e.Current then i <- i + 1 @@ -128,7 +128,7 @@ module internal TaskSeqInternal = let! step = e.MoveNextAsync() go <- step - | Some (PredicateAsync predicate) -> + | Some(PredicateAsync predicate) -> while go do match! predicate e.Current with | true -> i <- i + 1 @@ -197,7 +197,7 @@ module internal TaskSeqInternal = // multiple threads access the same item through the same enumerator (which is // bad practice, but hey, who're we to judge). if isNull value then - value <- Lazy<_>.Create (fun () -> init i) + value <- Lazy<_>.Create(fun () -> init i) yield value.Force() value <- Unchecked.defaultof<_> diff --git a/src/FSharp.Control.TaskSeq/Utils.fs b/src/FSharp.Control.TaskSeq/Utils.fs index 63274ed4..58956610 100644 --- a/src/FSharp.Control.TaskSeq/Utils.fs +++ b/src/FSharp.Control.TaskSeq/Utils.fs @@ -74,18 +74,16 @@ module Task = :> Task /// Map a Task<'T> - let inline map mapper (task: Task<'T>) : Task<'U> = - TaskBuilder.task { - let! result = task - return mapper result - } + let inline map mapper (task: Task<'T>) : Task<'U> = TaskBuilder.task { + let! result = task + return mapper result + } /// Bind a Task<'T> - let inline bind binder (task: Task<'T>) : Task<'U> = - TaskBuilder.task { - let! t = task - return! binder t - } + let inline bind binder (task: Task<'T>) : Task<'U> = TaskBuilder.task { + let! t = task + return! binder t + } /// Create a task from a value let inline fromResult (value: 'U) : Task<'U> = TaskBuilder.task { return value } @@ -107,11 +105,10 @@ module Async = } /// Map an Async<'T> - let inline map mapper (async: Async<'T>) : Async<'U> = - ExtraTopLevelOperators.async { - let! result = async - return mapper result - } + let inline map mapper (async: Async<'T>) : Async<'U> = ExtraTopLevelOperators.async { + let! result = async + return mapper result + } /// Bind an Async<'T> let inline bind binder (task: Async<'T>) : Async<'U> = ExtraTopLevelOperators.async { return! binder task } From f8353c32a2751f1148c839bdd4ec52d9bf27eb75 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Sun, 29 Oct 2023 15:41:35 +0100 Subject: [PATCH 3/7] Support a larger default line length (todo: may need to tweak this with the other line lengths) --- src/.editorconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/.editorconfig b/src/.editorconfig index 3ac96717..27ae7b0c 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -68,7 +68,7 @@ indent_size=4 # line length before it gets broken down into multiple lines # default 120 -max_line_length=120 +max_line_length=140 # Either crlf | lf, default is system-dependent (when not specified at all) # end_of_line=crlf @@ -180,7 +180,7 @@ fsharp_array_or_list_multiline_formatter=character_width # maximum with of a value binding, does not include keyword "let" # default 80 -fsharp_max_value_binding_width=100 +fsharp_max_value_binding_width=140 # maximum width for function and member binding (rh-side) # default 40 From c6a6a36a97d2b4b63b01dd346e843da873fea355 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Sun, 29 Oct 2023 15:42:38 +0100 Subject: [PATCH 4/7] Reformat all source files with the new rules --- src/FSharp.Control.TaskSeq.Test/Nunit.Extensions.fs | 12 ++---------- src/FSharp.Control.TaskSeq.Test/TestUtils.fs | 8 ++------ src/FSharp.Control.TaskSeq/TaskExtensions.fs | 6 +----- src/FSharp.Control.TaskSeq/TaskSeq.fs | 5 +---- src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs | 6 +----- 5 files changed, 7 insertions(+), 30 deletions(-) diff --git a/src/FSharp.Control.TaskSeq.Test/Nunit.Extensions.fs b/src/FSharp.Control.TaskSeq.Test/Nunit.Extensions.fs index 5fc1ccf4..834afe02 100644 --- a/src/FSharp.Control.TaskSeq.Test/Nunit.Extensions.fs +++ b/src/FSharp.Control.TaskSeq.Test/Nunit.Extensions.fs @@ -22,11 +22,7 @@ module ExtraCustomMatchers = let private baseResultTypeTest value = match value with | null -> - EqualException.ForMismatchedValues( - "Result type", - "", - "Value or None is never Result.Ok or Result.Error" - ) + EqualException.ForMismatchedValues("Result type", "", "Value or None is never Result.Ok or Result.Error") |> raise | _ -> @@ -53,11 +49,7 @@ module ExtraCustomMatchers = | "None" -> None | _ -> raise - <| EqualException.ForMismatchedValues( - "Option type", - ty.Name, - "Unexpected field name for F# option type" - ) + <| EqualException.ForMismatchedValues("Option type", ty.Name, "Unexpected field name for F# option type") else EqualException.ForMismatchedValues("Option type", ty.Name, "Type must be Option<_>") |> raise diff --git a/src/FSharp.Control.TaskSeq.Test/TestUtils.fs b/src/FSharp.Control.TaskSeq.Test/TestUtils.fs index 36244708..e97f3658 100644 --- a/src/FSharp.Control.TaskSeq.Test/TestUtils.fs +++ b/src/FSharp.Control.TaskSeq.Test/TestUtils.fs @@ -87,9 +87,7 @@ type DummyTaskFactory(µsecMin: int64<µs>, µsecMax: int64<µs>) = let rnd = Random() let rnd () = rnd.NextInt64(int64 µsecMin, int64 µsecMax) * 1L<µs> - let runTaskDelayed () = backgroundTask { - return! DelayHelper.delayTask µsecMin µsecMax (fun _ -> Interlocked.Increment &x) - } + let runTaskDelayed () = backgroundTask { return! DelayHelper.delayTask µsecMin µsecMax (fun _ -> Interlocked.Increment &x) } let runTaskDelayedImmutable i = backgroundTask { return! DelayHelper.delayTask µsecMin µsecMax (fun _ -> i + 1) } @@ -513,9 +511,7 @@ module TestUtils = yield! taskSeq { yield! taskSeq { yield! taskSeq { - yield! taskSeq { - yield! taskSeq { yield! taskSeq { yield! taskSeq { yield! nestedTaskSeq } } } - } + yield! taskSeq { yield! taskSeq { yield! taskSeq { yield! taskSeq { yield! nestedTaskSeq } } } } } } } diff --git a/src/FSharp.Control.TaskSeq/TaskExtensions.fs b/src/FSharp.Control.TaskSeq/TaskExtensions.fs index b168f358..dc592f97 100644 --- a/src/FSharp.Control.TaskSeq/TaskExtensions.fs +++ b/src/FSharp.Control.TaskSeq/TaskExtensions.fs @@ -19,11 +19,7 @@ module TaskExtensions = /// Used by `For`. F# currently doesn't support `while!`, so this cannot be called directly from the task CE /// This code is mostly a copy of TaskSeq.WhileAsync. - member inline _.WhileAsync - ( - [] condition: unit -> ValueTask, - body: TaskCode<_, unit> - ) : TaskCode<_, _> = + member inline _.WhileAsync([] condition: unit -> ValueTask, body: TaskCode<_, unit>) : TaskCode<_, _> = let mutable condition_res = true // note that this While itself has both a dynamic and static implementation diff --git a/src/FSharp.Control.TaskSeq/TaskSeq.fs b/src/FSharp.Control.TaskSeq/TaskSeq.fs index 689deda0..78f156e9 100644 --- a/src/FSharp.Control.TaskSeq/TaskSeq.fs +++ b/src/FSharp.Control.TaskSeq/TaskSeq.fs @@ -265,10 +265,7 @@ module TaskSeq = let exactlyOne source = Internal.tryExactlyOne source - |> Task.map ( - Option.defaultWith (fun () -> - invalidArg (nameof source) "The input sequence contains more than one element.") - ) + |> Task.map (Option.defaultWith (fun () -> invalidArg (nameof source) "The input sequence contains more than one element.")) let indexed (source: taskSeq<'T>) = Internal.checkNonNull (nameof source) source diff --git a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs index 42f5769c..a61d72d1 100644 --- a/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs +++ b/src/FSharp.Control.TaskSeq/TaskSeqBuilder.fs @@ -390,11 +390,7 @@ type TaskSeqBuilder() = ResumableCode.Combine(task1, task2) /// Used by `For`. F# currently doesn't support `while!`, so this cannot be called directly from the CE - member inline _.WhileAsync - ( - [] condition: unit -> ValueTask, - body: ResumableTSC<'T> - ) : ResumableTSC<'T> = + member inline _.WhileAsync([] condition: unit -> ValueTask, body: ResumableTSC<'T>) : ResumableTSC<'T> = let mutable condition_res = true ResumableCode.While( From d25f72642b8941ad257d129108b297110ecd9523 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Sun, 29 Oct 2023 16:03:46 +0100 Subject: [PATCH 5/7] Require successful formatting in the CI pipeline --- .github/workflows/build.yaml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 6bf63d49..c9037c45 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -3,6 +3,25 @@ name: ci-build on: [pull_request] jobs: + verify_formatting: + runs-on: ubuntu-latest + name: Verify code formatting + + steps: + - name: checkout-code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: setup-dotnet + uses: actions/setup-dotnet@v3 + + - name: tool restore + run: dotnet tool restore + + - name: validate formatting + run: dotnet fantomas . --check + build: name: Build runs-on: windows-latest @@ -12,9 +31,11 @@ jobs: uses: actions/checkout@v3 with: fetch-depth: 0 + # setup dotnet based on global.json - name: setup-dotnet uses: actions/setup-dotnet@v3 + # build it, test it, pack it - name: Run dotnet build (release) # see issue #105 From c83607d4b828c2f7558bb1bb5e013d6b79e01782 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Sun, 29 Oct 2023 16:04:39 +0100 Subject: [PATCH 6/7] Ensure the CI Fantomas check properly fails (this commit deliberately fails CI) --- src/.editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/.editorconfig b/src/.editorconfig index 27ae7b0c..4a66a537 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -68,7 +68,7 @@ indent_size=4 # line length before it gets broken down into multiple lines # default 120 -max_line_length=140 +max_line_length=100 # Either crlf | lf, default is system-dependent (when not specified at all) # end_of_line=crlf From 1f5999293febe902294c401d5b2007a48ff62b49 Mon Sep 17 00:00:00 2001 From: Abel Braaksma Date: Sun, 29 Oct 2023 16:54:24 +0100 Subject: [PATCH 7/7] Revert "Ensure the CI Fantomas check properly fails (this commit deliberately fails CI)" This reverts commit c83607d4b828c2f7558bb1bb5e013d6b79e01782. --- src/.editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/.editorconfig b/src/.editorconfig index 4a66a537..27ae7b0c 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -68,7 +68,7 @@ indent_size=4 # line length before it gets broken down into multiple lines # default 120 -max_line_length=100 +max_line_length=140 # Either crlf | lf, default is system-dependent (when not specified at all) # end_of_line=crlf