diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 46f03f417..4a9d31988 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -9,7 +9,7 @@ ] }, "paket": { - "version": "7.2.0-alpha001", + "version": "7.2.1", "commands": [ "paket" ] @@ -33,4 +33,4 @@ ] } } -} \ No newline at end of file +} diff --git a/paket.dependencies b/paket.dependencies index 0fcc7d399..cda9daa8b 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -1,24 +1,26 @@ -version 7.2.0-alpha001 +version 7.2.1 -framework: netstandard2.0, net6.0, net7.0 +framework: netstandard2.0, netstandard2.1, net6.0, net7.0 source https://api.nuget.org/v3/index.json # this is the FCS nightly feed, re-enable at your own risk! #source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json #source: ./libs storage: none +strategy: min +lowest_matching: true -nuget Fantomas.Client -nuget FSharp.Compiler.Service -nuget Ionide.ProjInfo -nuget Ionide.ProjInfo.FCS -nuget Ionide.ProjInfo.ProjectSystem -nuget Ionide.ProjInfo.Sln -nuget Microsoft.Build copy_local:false -nuget Microsoft.Build.Framework copy_local:false -nuget Microsoft.Build.Utilities.Core copy_local:false -nuget Microsoft.Build.Tasks.Core copy_local: false +nuget Fantomas.Client >= 0.9 +nuget FSharp.Compiler.Service >= 43.7.200 +nuget Ionide.ProjInfo >= 0.61.3 +nuget Ionide.ProjInfo.FCS >= 0.61.3 +nuget Ionide.ProjInfo.ProjectSystem >= 0.61.3 +nuget Ionide.ProjInfo.Sln >= 0.61.3 +nuget Microsoft.Build >= 17.2 copy_local:false +nuget Microsoft.Build.Framework >= 17.4 copy_local:false +nuget Microsoft.Build.Utilities.Core >= 17.4 copy_local:false +nuget Microsoft.Build.Tasks.Core >= 17.4 copy_local: false nuget Nuget.Frameworks copy_local: false nuget FSharp.Analyzers.SDK nuget ICSharpCode.Decompiler @@ -34,7 +36,8 @@ nuget Serilog.Sinks.Async nuget Destructurama.FSharp nuget FSharp.UMX nuget FSharp.Formatting -nuget FsToolkit.ErrorHandling +nuget FsToolkit.ErrorHandling.TaskResult framework: netstandard2.1 ,net6.0, net7.0 +nuget IcedTasks nuget FSharpx.Async nuget CliWrap nuget System.CommandLine prerelease @@ -49,9 +52,12 @@ nuget Expecto.Diff nuget YoloDev.Expecto.TestSdk nuget AltCover nuget GitHubActionsTestLogger -nuget Ionide.LanguageServerProtocol +nuget Ionide.LanguageServerProtocol >= 0.4.12 nuget Microsoft.Extensions.Caching.Memory -nuget OpenTelemetry.Exporter.OpenTelemetryProtocol +nuget OpenTelemetry.Exporter.OpenTelemetryProtocol >= 1.3.2 + + + group Build source https://api.nuget.org/v3/index.json diff --git a/paket.lock b/paket.lock index c828ae149..b10707200 100644 --- a/paket.lock +++ b/paket.lock @@ -1,13 +1,15 @@ STORAGE: NONE -RESTRICTION: || (== net6.0) (== net7.0) (== netstandard2.0) +STRATEGY: MIN +LOWEST_MATCHING: TRUE +RESTRICTION: || (== net6.0) (== net7.0) (== netstandard2.0) (== netstandard2.1) NUGET remote: https://api.nuget.org/v3/index.json altcover (8.3.838) CliWrap (3.4.4) - Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) - System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) - System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) - System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) + Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net461)) + System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net461)) + System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net461)) + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net461)) Destructurama.FSharp (1.2) FSharp.Core (>= 4.3.4) Serilog (>= 2.0 < 3.0) @@ -28,12 +30,12 @@ NUGET FSharp.Core (>= 5.0.1) SemanticVersioning (>= 2.0.2) StreamJsonRpc (>= 2.8.28) - FParsec (1.1.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) + FParsec (1.1.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) FSharp.Core (>= 4.3.4) FSharp.Analyzers.SDK (0.11) - FSharp.Compiler.Service (>= 41.0.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) - FSharp.Core (>= 6.0.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) - McMaster.NETCore.Plugins (>= 1.4) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) + FSharp.Compiler.Service (>= 41.0.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) + FSharp.Core (>= 6.0.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) + McMaster.NETCore.Plugins (>= 1.4) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) FSharp.Compiler.Service (43.7.200) FSharp.Core (7.0.200) System.Buffers (>= 4.5.1) @@ -46,7 +48,7 @@ NUGET FSharp.Control.AsyncSeq (3.2.1) FSharp.Core (>= 4.7.2) Microsoft.Bcl.AsyncInterfaces (>= 5.0) - FSharp.Control.Reactive (5.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) + FSharp.Control.Reactive (5.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) FSharp.Core (>= 4.7.2) System.Reactive (>= 5.0 < 6.0) FSharp.Core (7.0.200) - content: none @@ -54,44 +56,49 @@ NUGET FSharp.Core (>= 4.7) System.Reflection.Emit.Lightweight (>= 4.6) FSharp.Formatting (14.0.1) - FSharp.Compiler.Service (>= 40.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netstandard2.1)) + FSharp.Compiler.Service (>= 40.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netstandard2.1)) (== netstandard2.1) FSharp.UMX (1.1) FSharp.Core (>= 4.3.4) FSharpLint.Core (0.21.2) - FParsec (>= 1.1.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) - FSharp.Compiler.Service (>= 40.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) - FSharp.Core (>= 5.0.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) - Ionide.ProjInfo (>= 0.53.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) - Ionide.ProjInfo.FCS (>= 0.53.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) - Ionide.ProjInfo.ProjectSystem (>= 0.53.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) - Microsoft.Build (>= 16.10) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) - Microsoft.Build.Framework (>= 16.10) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) - Microsoft.Build.Locator (>= 1.4.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) - Microsoft.Build.Tasks.Core (>= 16.10) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) - Microsoft.Build.Utilities.Core (>= 16.10) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) - Newtonsoft.Json (>= 13.0.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) + FParsec (>= 1.1.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) + FSharp.Compiler.Service (>= 40.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) + FSharp.Core (>= 5.0.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) + Ionide.ProjInfo (>= 0.53.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) + Ionide.ProjInfo.FCS (>= 0.53.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) + Ionide.ProjInfo.ProjectSystem (>= 0.53.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) + Microsoft.Build (>= 16.10) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) + Microsoft.Build.Framework (>= 16.10) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) + Microsoft.Build.Locator (>= 1.4.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) + Microsoft.Build.Tasks.Core (>= 16.10) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) + Microsoft.Build.Utilities.Core (>= 16.10) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) + Newtonsoft.Json (>= 13.0.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) FSharpx.Async (1.14.1) FSharp.Control.AsyncSeq (>= 2.0.21) FSharp.Core (>= 4.6.2) - FsToolkit.ErrorHandling (2.13) - FSharp.Core (>= 4.7.2) + FsToolkit.ErrorHandling (4.4) - restriction: || (== net6.0) (== net7.0) (== netstandard2.1) + FSharp.Core (>= 7.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netstandard2.1)) (== netstandard2.1) + FsToolkit.ErrorHandling.TaskResult (4.4) - restriction: || (== net6.0) (== net7.0) (== netstandard2.1) + FsToolkit.ErrorHandling (>= 4.4) GitHubActionsTestLogger (2.0.1) Microsoft.TestPlatform.ObjectModel (>= 17.2) Google.Protobuf (3.22) - System.Memory (>= 4.5.3) - restriction: || (&& (== net6.0) (>= net45)) (&& (== net6.0) (< net5.0)) (&& (== net6.0) (< netstandard2.0)) (&& (== net7.0) (>= net45)) (&& (== net7.0) (< net5.0)) (&& (== net7.0) (< netstandard2.0)) (== netstandard2.0) - System.Runtime.CompilerServices.Unsafe (>= 4.5.2) - restriction: || (&& (== net6.0) (< net5.0)) (&& (== net7.0) (< net5.0)) (== netstandard2.0) - Grpc (2.46.6) - restriction: || (&& (== net6.0) (>= net462)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net462)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) + System.Memory (>= 4.5.3) - restriction: || (&& (== net6.0) (>= net45)) (&& (== net6.0) (< net5.0)) (&& (== net6.0) (< netstandard2.0)) (&& (== net7.0) (>= net45)) (&& (== net7.0) (< net5.0)) (&& (== net7.0) (< netstandard2.0)) (== netstandard2.0) (== netstandard2.1) + System.Runtime.CompilerServices.Unsafe (>= 4.5.2) - restriction: || (&& (== net6.0) (< net5.0)) (&& (== net7.0) (< net5.0)) (== netstandard2.0) (== netstandard2.1) + Grpc (2.46.6) - restriction: || (&& (== net6.0) (>= net462)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net462)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net462)) Grpc.Core (>= 2.46.6) - Grpc.Core (2.46.6) - restriction: || (&& (== net6.0) (>= net45)) (&& (== net6.0) (>= net462)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net45)) (&& (== net7.0) (>= net462)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) + Grpc.Core (2.46.6) - restriction: || (&& (== net6.0) (>= net45)) (&& (== net6.0) (>= net462)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net45)) (&& (== net7.0) (>= net462)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net462)) Grpc.Core.Api (>= 2.46.6) System.Memory (>= 4.5.3) Grpc.Core.Api (2.51) System.Memory (>= 4.5.3) - Grpc.Net.Client (2.51) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netstandard2.1)) + Grpc.Net.Client (2.51) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netstandard2.1)) (== netstandard2.1) Grpc.Net.Common (>= 2.51) Microsoft.Extensions.Logging.Abstractions (>= 3.0.3) - Grpc.Net.Common (2.51) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netstandard2.1)) + System.Diagnostics.DiagnosticSource (>= 4.5.1) - restriction: || (&& (== net6.0) (< net5.0)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (< net5.0)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) (== netstandard2.1) + Grpc.Net.Common (2.51) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netstandard2.1)) (== netstandard2.1) Grpc.Core.Api (>= 2.51) + IcedTasks (0.5.3) + FSharp.Core (>= 7.0) ICSharpCode.Decompiler (7.2.1.6856) Microsoft.Win32.Registry (>= 5.0) System.Collections.Immutable (>= 5.0) @@ -102,58 +109,58 @@ NUGET Newtonsoft.Json (>= 13.0.1) StreamJsonRpc (>= 2.10.44) Ionide.ProjInfo (0.61.3) - FSharp.Core (>= 6.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) - Ionide.ProjInfo.Sln (>= 0.61.3) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) - Microsoft.Build (>= 17.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) - Microsoft.Build.Framework (>= 17.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) - SemanticVersioning (>= 2.0.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) + FSharp.Core (>= 6.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Ionide.ProjInfo.Sln (>= 0.61.3) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Microsoft.Build (>= 17.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Microsoft.Build.Framework (>= 17.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + SemanticVersioning (>= 2.0.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) Ionide.ProjInfo.FCS (0.61.3) - FSharp.Compiler.Service (>= 41.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) - FSharp.Core (>= 6.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) - Ionide.ProjInfo (>= 0.61.3) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) + FSharp.Compiler.Service (>= 41.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + FSharp.Core (>= 6.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Ionide.ProjInfo (>= 0.61.3) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) Ionide.ProjInfo.ProjectSystem (0.61.3) - FSharp.Compiler.Service (>= 41.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) - FSharp.Control.Reactive (>= 5.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) - FSharp.Core (>= 6.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) - Ionide.ProjInfo (>= 0.61.3) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) - Ionide.ProjInfo.FCS (>= 0.61.3) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) - Ionide.ProjInfo.Sln (>= 0.61.3) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) - Newtonsoft.Json (>= 13.0.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) + FSharp.Compiler.Service (>= 41.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + FSharp.Control.Reactive (>= 5.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + FSharp.Core (>= 6.0.5) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Ionide.ProjInfo (>= 0.61.3) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Ionide.ProjInfo.FCS (>= 0.61.3) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Ionide.ProjInfo.Sln (>= 0.61.3) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + Newtonsoft.Json (>= 13.0.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) Ionide.ProjInfo.Sln (0.61.3) - McMaster.NETCore.Plugins (1.4) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) - Microsoft.DotNet.PlatformAbstractions (>= 3.1.6) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp2.1)) - Microsoft.Extensions.DependencyModel (>= 5.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp2.1)) + McMaster.NETCore.Plugins (1.4) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) + Microsoft.DotNet.PlatformAbstractions (>= 3.1.6) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp2.1)) (&& (== netstandard2.1) (>= netcoreapp2.1)) + Microsoft.Extensions.DependencyModel (>= 5.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp2.1)) (&& (== netstandard2.1) (>= netcoreapp2.1)) MessagePack (2.4.35) MessagePack.Annotations (>= 2.4.35) - Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) + Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) (== netstandard2.1) Microsoft.NET.StringTools (>= 1.0) - System.Collections.Immutable (>= 1.7.1) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) - System.Reflection.Emit (>= 4.7) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) - System.Reflection.Emit.Lightweight (>= 4.7) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) - System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) + System.Collections.Immutable (>= 1.7.1) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) (== netstandard2.1) + System.Reflection.Emit (>= 4.7) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) (== netstandard2.1) + System.Reflection.Emit.Lightweight (>= 4.7) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) (== netstandard2.1) + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) (== netstandard2.1) MessagePack.Annotations (2.4.35) Microsoft.Bcl.AsyncInterfaces (6.0) - System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net461)) Microsoft.Build (17.2) - copy_local: false - Microsoft.Build.Framework (>= 17.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) - Microsoft.NET.StringTools (>= 1.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) - Microsoft.Win32.Registry (>= 4.3) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) - System.Collections.Immutable (>= 5.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) - System.Configuration.ConfigurationManager (>= 4.7) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) - System.Reflection.Metadata (>= 1.6) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) - System.Security.Principal.Windows (>= 4.7) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) - System.Text.Encoding.CodePages (>= 4.0.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) - System.Text.Json (>= 6.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) - System.Threading.Tasks.Dataflow (>= 6.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) + Microsoft.Build.Framework (>= 17.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net472)) (&& (== netstandard2.1) (>= net6.0)) + Microsoft.NET.StringTools (>= 1.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net472)) (&& (== netstandard2.1) (>= net6.0)) + Microsoft.Win32.Registry (>= 4.3) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + System.Collections.Immutable (>= 5.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net472)) (&& (== netstandard2.1) (>= net6.0)) + System.Configuration.ConfigurationManager (>= 4.7) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net472)) (&& (== netstandard2.1) (>= net6.0)) + System.Reflection.Metadata (>= 1.6) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + System.Security.Principal.Windows (>= 4.7) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + System.Text.Encoding.CodePages (>= 4.0.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) + System.Text.Json (>= 6.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net472)) (&& (== netstandard2.1) (>= net6.0)) + System.Threading.Tasks.Dataflow (>= 6.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net472)) (&& (== netstandard2.1) (>= net6.0)) Microsoft.Build.Framework (17.4) - copy_local: false - Microsoft.Win32.Registry (>= 5.0) - restriction: || (== net6.0) (== netstandard2.0) + Microsoft.Win32.Registry (>= 5.0) - restriction: || (== net6.0) (== netstandard2.0) (== netstandard2.1) System.Security.Permissions (>= 6.0) - Microsoft.Build.Locator (1.5.3) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) + Microsoft.Build.Locator (1.5.3) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) Microsoft.Build.Tasks.Core (17.4) - copy_local: false Microsoft.Build.Framework (>= 17.4) Microsoft.Build.Utilities.Core (>= 17.4) Microsoft.NET.StringTools (>= 17.4) - Microsoft.Win32.Registry (>= 5.0) - restriction: || (== net6.0) (== netstandard2.0) + Microsoft.Win32.Registry (>= 5.0) - restriction: || (== net6.0) (== netstandard2.0) (== netstandard2.1) System.CodeDom (>= 6.0) System.Collections.Immutable (>= 6.0) System.Reflection.Metadata (>= 6.0) @@ -166,13 +173,13 @@ NUGET Microsoft.Build.Utilities.Core (17.4) - copy_local: false Microsoft.Build.Framework (>= 17.4) Microsoft.NET.StringTools (>= 17.4) - Microsoft.Win32.Registry (>= 5.0) - restriction: || (== net6.0) (== netstandard2.0) + Microsoft.Win32.Registry (>= 5.0) - restriction: || (== net6.0) (== netstandard2.0) (== netstandard2.1) System.Collections.Immutable (>= 6.0) System.Configuration.ConfigurationManager (>= 6.0) - System.Security.Permissions (>= 6.0) - restriction: || (== net6.0) (== netstandard2.0) - System.Text.Encoding.CodePages (>= 6.0) - restriction: || (== net6.0) (== netstandard2.0) - Microsoft.CodeCoverage (17.4.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net462)) (&& (== netstandard2.0) (>= netcoreapp3.1)) - Microsoft.DotNet.PlatformAbstractions (3.1.6) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) + System.Security.Permissions (>= 6.0) - restriction: || (== net6.0) (== netstandard2.0) (== netstandard2.1) + System.Text.Encoding.CodePages (>= 6.0) - restriction: || (== net6.0) (== netstandard2.0) (== netstandard2.1) + Microsoft.CodeCoverage (17.4.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net462)) (&& (== netstandard2.0) (>= netcoreapp3.1)) (&& (== netstandard2.1) (>= net462)) (&& (== netstandard2.1) (>= netcoreapp3.1)) + Microsoft.DotNet.PlatformAbstractions (3.1.6) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) Microsoft.Extensions.Caching.Abstractions (6.0) Microsoft.Extensions.Primitives (>= 6.0) Microsoft.Extensions.Caching.Memory (6.0.1) @@ -189,29 +196,29 @@ NUGET Microsoft.Extensions.Configuration.Binder (6.0) Microsoft.Extensions.Configuration.Abstractions (>= 6.0) Microsoft.Extensions.DependencyInjection (6.0.1) - Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) + Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net461)) Microsoft.Extensions.DependencyInjection.Abstractions (>= 6.0) System.Runtime.CompilerServices.Unsafe (>= 6.0) - System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net461)) Microsoft.Extensions.DependencyInjection.Abstractions (6.0) - Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) - System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) - Microsoft.Extensions.DependencyModel (6.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) + Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net461)) + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net461)) + Microsoft.Extensions.DependencyModel (6.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net5.0)) (&& (== netstandard2.1) (>= net5.0)) System.Buffers (>= 4.5.1) System.Memory (>= 4.5.4) System.Runtime.CompilerServices.Unsafe (>= 6.0) System.Text.Encodings.Web (>= 6.0) System.Text.Json (>= 6.0) Microsoft.Extensions.Logging (6.0) - Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) + Microsoft.Bcl.AsyncInterfaces (>= 6.0) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net461)) Microsoft.Extensions.DependencyInjection (>= 6.0) Microsoft.Extensions.DependencyInjection.Abstractions (>= 6.0) Microsoft.Extensions.Logging.Abstractions (>= 6.0) Microsoft.Extensions.Options (>= 6.0) System.Diagnostics.DiagnosticSource (>= 6.0) Microsoft.Extensions.Logging.Abstractions (6.0.2) - System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) - System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) + System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) (== netstandard2.1) + System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) (== netstandard2.1) Microsoft.Extensions.Logging.Configuration (6.0) Microsoft.Extensions.Configuration (>= 6.0) Microsoft.Extensions.Configuration.Abstractions (>= 6.0) @@ -232,14 +239,14 @@ NUGET Microsoft.Extensions.Options (>= 6.0) Microsoft.Extensions.Primitives (>= 6.0) Microsoft.Extensions.Primitives (6.0) - System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) + System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) (== netstandard2.1) System.Runtime.CompilerServices.Unsafe (>= 6.0) Microsoft.NET.StringTools (17.4) - copy_local: false System.Memory (>= 4.5.5) System.Runtime.CompilerServices.Unsafe (>= 6.0) Microsoft.NET.Test.Sdk (17.4.1) - Microsoft.CodeCoverage (>= 17.4.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net462)) (&& (== netstandard2.0) (>= netcoreapp3.1)) - Microsoft.TestPlatform.TestHost (>= 17.4.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) + Microsoft.CodeCoverage (>= 17.4.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net462)) (&& (== netstandard2.0) (>= netcoreapp3.1)) (&& (== netstandard2.1) (>= net462)) (&& (== netstandard2.1) (>= netcoreapp3.1)) + Microsoft.TestPlatform.TestHost (>= 17.4.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) (&& (== netstandard2.1) (>= netcoreapp3.1)) Microsoft.NETFramework.ReferenceAssemblies (1.0.3) Microsoft.SourceLink.AzureRepos.Git (1.1.1) - copy_local: true Microsoft.Build.Tasks.Git (>= 1.1.1) @@ -257,9 +264,9 @@ NUGET Microsoft.TestPlatform.ObjectModel (17.4.1) NuGet.Frameworks (>= 5.11) System.Reflection.Metadata (>= 1.6) - Microsoft.TestPlatform.TestHost (17.4.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) - Microsoft.TestPlatform.ObjectModel (>= 17.4.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) - Newtonsoft.Json (>= 13.0.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) + Microsoft.TestPlatform.TestHost (17.4.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) (&& (== netstandard2.1) (>= netcoreapp3.1)) + Microsoft.TestPlatform.ObjectModel (>= 17.4.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) (&& (== netstandard2.1) (>= netcoreapp3.1)) + Newtonsoft.Json (>= 13.0.1) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) (&& (== netstandard2.1) (>= netcoreapp3.1)) Microsoft.VisualStudio.Threading (17.3.44) Microsoft.Bcl.AsyncInterfaces (>= 6.0) Microsoft.VisualStudio.Threading.Analyzers (>= 17.3.44) @@ -269,11 +276,11 @@ NUGET Microsoft.VisualStudio.Threading.Analyzers (17.3.44) Microsoft.VisualStudio.Validation (17.0.64) Microsoft.Win32.Registry (5.0) - System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= monoandroid) (< netstandard1.3)) (&& (== net6.0) (>= monotouch)) (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (>= xamarinios)) (&& (== net6.0) (>= xamarinmac)) (&& (== net6.0) (>= xamarintvos)) (&& (== net6.0) (>= xamarinwatchos)) (&& (== net7.0) (>= monoandroid) (< netstandard1.3)) (&& (== net7.0) (>= monotouch)) (&& (== net7.0) (< netcoreapp2.0)) (&& (== net7.0) (>= xamarinios)) (&& (== net7.0) (>= xamarinmac)) (&& (== net7.0) (>= xamarintvos)) (&& (== net7.0) (>= xamarinwatchos)) (== netstandard2.0) - System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (< netcoreapp2.1)) (&& (== net6.0) (>= uap10.1)) (&& (== net7.0) (< netcoreapp2.0)) (&& (== net7.0) (< netcoreapp2.1)) (&& (== net7.0) (>= uap10.1)) (== netstandard2.0) + System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= monoandroid) (< netstandard1.3)) (&& (== net6.0) (>= monotouch)) (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (>= xamarinios)) (&& (== net6.0) (>= xamarinmac)) (&& (== net6.0) (>= xamarintvos)) (&& (== net6.0) (>= xamarinwatchos)) (&& (== net7.0) (>= monoandroid) (< netstandard1.3)) (&& (== net7.0) (>= monotouch)) (&& (== net7.0) (< netcoreapp2.0)) (&& (== net7.0) (>= xamarinios)) (&& (== net7.0) (>= xamarinmac)) (&& (== net7.0) (>= xamarintvos)) (&& (== net7.0) (>= xamarinwatchos)) (== netstandard2.0) (== netstandard2.1) + System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (< netcoreapp2.1)) (&& (== net6.0) (>= uap10.1)) (&& (== net7.0) (< netcoreapp2.0)) (&& (== net7.0) (< netcoreapp2.1)) (&& (== net7.0) (>= uap10.1)) (== netstandard2.0) (== netstandard2.1) System.Security.AccessControl (>= 5.0) System.Security.Principal.Windows (>= 5.0) - Microsoft.Win32.SystemEvents (6.0.1) - copy_local: false, restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) + Microsoft.Win32.SystemEvents (6.0.1) - copy_local: false, restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) (&& (== netstandard2.1) (>= netcoreapp3.1)) Mono.Cecil (0.11.4) Nerdbank.Streams (2.8.61) Microsoft.Bcl.AsyncInterfaces (>= 5.0) @@ -294,8 +301,8 @@ NUGET System.Reflection.Emit.Lightweight (>= 4.7) OpenTelemetry.Exporter.OpenTelemetryProtocol (1.3.2) Google.Protobuf (>= 3.19.4 < 4.0) - Grpc (>= 2.44 < 3.0) - restriction: || (&& (== net6.0) (>= net462)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net462)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) - Grpc.Net.Client (>= 2.43 < 3.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netstandard2.1)) + Grpc (>= 2.44 < 3.0) - restriction: || (&& (== net6.0) (>= net462)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (>= net462)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) (&& (== netstandard2.1) (>= net462)) + Grpc.Net.Client (>= 2.43 < 3.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netstandard2.1)) (== netstandard2.1) OpenTelemetry (>= 1.3.2) SemanticVersioning (2.0.2) Serilog (2.11) @@ -318,77 +325,77 @@ NUGET System.Buffers (4.5.1) System.CodeDom (6.0) - copy_local: false System.Collections.Immutable (6.0) - System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) + System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) (== netstandard2.1) System.Runtime.CompilerServices.Unsafe (>= 6.0) System.CommandLine (2.0.0-beta4.22272.1) - System.Memory (>= 4.5.4) - restriction: || (&& (== net7.0) (< net6.0)) (== netstandard2.0) + System.Memory (>= 4.5.4) - restriction: || (&& (== net7.0) (< net6.0)) (== netstandard2.0) (== netstandard2.1) System.ComponentModel.Annotations (5.0) - restriction: || (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) System.Configuration.ConfigurationManager (6.0) System.Security.Cryptography.ProtectedData (>= 6.0) System.Security.Permissions (>= 6.0) System.Diagnostics.DiagnosticSource (6.0) - System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< net5.0)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net5.0)) (== netstandard2.0) + System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< net5.0)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net5.0)) (== netstandard2.0) (== netstandard2.1) System.Runtime.CompilerServices.Unsafe (>= 6.0) - System.Drawing.Common (6.0) - copy_local: false, restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) - Microsoft.Win32.SystemEvents (>= 6.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) + System.Drawing.Common (6.0) - copy_local: false, restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) (&& (== netstandard2.1) (>= netcoreapp3.1)) + Microsoft.Win32.SystemEvents (>= 6.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) (&& (== netstandard2.1) (>= netcoreapp3.1)) System.Formats.Asn1 (6.0) - copy_local: false - System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) - System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) + System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) (== netstandard2.1) + System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) (== netstandard2.1) System.IO.Pipelines (6.0.3) - System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) - System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) - System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) + System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) (== netstandard2.1) + System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) (== netstandard2.1) + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) (== netstandard2.1) System.Memory (4.5.5) - System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= monotouch)) (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (< netstandard1.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= xamarinios)) (&& (== net6.0) (>= xamarinmac)) (&& (== net6.0) (>= xamarintvos)) (&& (== net6.0) (>= xamarinwatchos)) (&& (== net7.0) (>= monotouch)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netcoreapp2.0)) (&& (== net7.0) (< netstandard1.1)) (&& (== net7.0) (< netstandard2.0)) (&& (== net7.0) (>= xamarinios)) (&& (== net7.0) (>= xamarinmac)) (&& (== net7.0) (>= xamarintvos)) (&& (== net7.0) (>= xamarinwatchos)) (== netstandard2.0) - System.Numerics.Vectors (>= 4.4) - restriction: || (&& (== net6.0) (< netcoreapp2.0)) (&& (== net7.0) (< netcoreapp2.0)) (== netstandard2.0) - System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (== net6.0) (>= monotouch)) (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (< netcoreapp2.1)) (&& (== net6.0) (< netstandard1.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= uap10.1)) (&& (== net6.0) (>= xamarinios)) (&& (== net6.0) (>= xamarinmac)) (&& (== net6.0) (>= xamarintvos)) (&& (== net6.0) (>= xamarinwatchos)) (&& (== net7.0) (>= monotouch)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netcoreapp2.0)) (&& (== net7.0) (< netcoreapp2.1)) (&& (== net7.0) (< netstandard1.1)) (&& (== net7.0) (< netstandard2.0)) (&& (== net7.0) (>= uap10.1)) (&& (== net7.0) (>= xamarinios)) (&& (== net7.0) (>= xamarinmac)) (&& (== net7.0) (>= xamarintvos)) (&& (== net7.0) (>= xamarinwatchos)) (== netstandard2.0) - System.Numerics.Vectors (4.5) - restriction: || (&& (== net6.0) (< netcoreapp2.0)) (&& (== net7.0) (< netcoreapp2.0)) (== netstandard2.0) - System.Reactive (5.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) + System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= monotouch)) (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (< netstandard1.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= xamarinios)) (&& (== net6.0) (>= xamarinmac)) (&& (== net6.0) (>= xamarintvos)) (&& (== net6.0) (>= xamarinwatchos)) (&& (== net7.0) (>= monotouch)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netcoreapp2.0)) (&& (== net7.0) (< netstandard1.1)) (&& (== net7.0) (< netstandard2.0)) (&& (== net7.0) (>= xamarinios)) (&& (== net7.0) (>= xamarinmac)) (&& (== net7.0) (>= xamarintvos)) (&& (== net7.0) (>= xamarinwatchos)) (== netstandard2.0) (== netstandard2.1) + System.Numerics.Vectors (>= 4.4) - restriction: || (&& (== net6.0) (< netcoreapp2.0)) (&& (== net7.0) (< netcoreapp2.0)) (== netstandard2.0) (== netstandard2.1) + System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (== net6.0) (>= monotouch)) (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (< netcoreapp2.1)) (&& (== net6.0) (< netstandard1.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= uap10.1)) (&& (== net6.0) (>= xamarinios)) (&& (== net6.0) (>= xamarinmac)) (&& (== net6.0) (>= xamarintvos)) (&& (== net6.0) (>= xamarinwatchos)) (&& (== net7.0) (>= monotouch)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netcoreapp2.0)) (&& (== net7.0) (< netcoreapp2.1)) (&& (== net7.0) (< netstandard1.1)) (&& (== net7.0) (< netstandard2.0)) (&& (== net7.0) (>= uap10.1)) (&& (== net7.0) (>= xamarinios)) (&& (== net7.0) (>= xamarinmac)) (&& (== net7.0) (>= xamarintvos)) (&& (== net7.0) (>= xamarinwatchos)) (== netstandard2.0) (== netstandard2.1) + System.Numerics.Vectors (4.5) - restriction: || (&& (== net6.0) (< netcoreapp2.0)) (&& (== net7.0) (< netcoreapp2.0)) (== netstandard2.0) (== netstandard2.1) + System.Reactive (5.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net6.0)) System.Reflection.Emit (4.7) - System.Reflection.Emit.ILGeneration (>= 4.7) - restriction: || (&& (== net6.0) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net6.0) (< netstandard1.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= uap10.1)) (&& (== net7.0) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net7.0) (< netstandard1.1)) (&& (== net7.0) (< netstandard2.0)) (&& (== net7.0) (>= uap10.1)) (== netstandard2.0) - System.Reflection.Emit.ILGeneration (4.7) - restriction: || (&& (== net6.0) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net6.0) (< netstandard1.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= uap10.1)) (&& (== net7.0) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net7.0) (< netstandard1.1)) (&& (== net7.0) (< netstandard2.0)) (&& (== net7.0) (>= uap10.1)) (== netstandard2.0) + System.Reflection.Emit.ILGeneration (>= 4.7) - restriction: || (&& (== net6.0) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net6.0) (< netstandard1.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= uap10.1)) (&& (== net7.0) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net7.0) (< netstandard1.1)) (&& (== net7.0) (< netstandard2.0)) (&& (== net7.0) (>= uap10.1)) (== netstandard2.0) (&& (== netstandard2.1) (< netstandard1.1)) (&& (== netstandard2.1) (< netstandard2.0)) (&& (== netstandard2.1) (>= uap10.1)) + System.Reflection.Emit.ILGeneration (4.7) - restriction: || (&& (== net6.0) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net6.0) (< netstandard1.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= uap10.1)) (&& (== net7.0) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net7.0) (< netstandard1.1)) (&& (== net7.0) (< netstandard2.0)) (&& (== net7.0) (>= uap10.1)) (== netstandard2.0) (&& (== netstandard2.1) (< netstandard1.1)) (&& (== netstandard2.1) (< netstandard2.0)) (&& (== netstandard2.1) (>= uap10.1)) System.Reflection.Emit.Lightweight (4.7) - System.Reflection.Emit.ILGeneration (>= 4.7) - restriction: || (&& (== net6.0) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (< portable-net45+wp8)) (&& (== net6.0) (>= uap10.1)) (&& (== net7.0) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net7.0) (< netstandard2.0)) (&& (== net7.0) (< portable-net45+wp8)) (&& (== net7.0) (>= uap10.1)) (== netstandard2.0) + System.Reflection.Emit.ILGeneration (>= 4.7) - restriction: || (&& (== net6.0) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (< portable-net45+wp8)) (&& (== net6.0) (>= uap10.1)) (&& (== net7.0) (< netcoreapp2.0) (< netstandard2.1)) (&& (== net7.0) (< netstandard2.0)) (&& (== net7.0) (< portable-net45+wp8)) (&& (== net7.0) (>= uap10.1)) (== netstandard2.0) (&& (== netstandard2.1) (< netstandard2.0)) (&& (== netstandard2.1) (< portable-net45+wp8)) (&& (== netstandard2.1) (>= uap10.1)) System.Reflection.Metadata (6.0.1) System.Collections.Immutable (>= 6.0) System.Resources.Extensions (6.0) - copy_local: false - System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) + System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) (== netstandard2.1) System.Runtime.CompilerServices.Unsafe (6.0) System.Security.AccessControl (6.0) - copy_local: false - System.Security.Principal.Windows (>= 5.0) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) - System.Security.Cryptography.Cng (5.0) - copy_local: false, restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (< net6.0)) (&& (== net7.0) (< netcoreapp3.1)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) + System.Security.Principal.Windows (>= 5.0) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< net6.0)) (== netstandard2.0) (== netstandard2.1) + System.Security.Cryptography.Cng (5.0) - copy_local: false, restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (< net6.0)) (&& (== net7.0) (< netcoreapp3.1)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) (== netstandard2.1) System.Security.Cryptography.Pkcs (6.0.1) - copy_local: false System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) System.Formats.Asn1 (>= 6.0) System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) - System.Security.Cryptography.Cng (>= 5.0) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (< net6.0)) (&& (== net7.0) (< netcoreapp3.1)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) + System.Security.Cryptography.Cng (>= 5.0) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard2.1)) (&& (== net7.0) (< net6.0)) (&& (== net7.0) (< netcoreapp3.1)) (&& (== net7.0) (< netstandard2.1)) (== netstandard2.0) (== netstandard2.1) System.Security.Cryptography.ProtectedData (6.0) - System.Memory (>= 4.5.4) - restriction: || (&& (== net7.0) (< net6.0)) (== netstandard2.0) + System.Memory (>= 4.5.4) - restriction: || (&& (== net7.0) (< net6.0)) (== netstandard2.0) (== netstandard2.1) System.Security.Cryptography.Xml (6.0.1) - copy_local: false - System.Memory (>= 4.5.4) - restriction: || (&& (== net7.0) (< net6.0)) (== netstandard2.0) + System.Memory (>= 4.5.4) - restriction: || (&& (== net7.0) (< net6.0)) (== netstandard2.0) (== netstandard2.1) System.Security.AccessControl (>= 6.0) System.Security.Cryptography.Pkcs (>= 6.0.1) System.Security.Permissions (6.0) - copy_local: false System.Security.AccessControl (>= 6.0) - System.Windows.Extensions (>= 6.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) + System.Windows.Extensions (>= 6.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) (&& (== netstandard2.1) (>= netcoreapp3.1)) System.Security.Principal.Windows (5.0) - copy_local: false System.Text.Encoding.CodePages (6.0) - copy_local: false - System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) + System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netcoreapp3.1)) (== netstandard2.0) (== netstandard2.1) System.Runtime.CompilerServices.Unsafe (>= 6.0) - System.Text.Encodings.Web (6.0) - copy_local: false, restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) + System.Text.Encodings.Web (6.0) - copy_local: false, restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net472)) (&& (== netstandard2.1) (>= net6.0)) System.Runtime.CompilerServices.Unsafe (>= 6.0) - System.Text.Json (6.0.5) - copy_local: false, restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) + System.Text.Json (6.0.5) - copy_local: false, restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) (&& (== netstandard2.1) (>= net472)) (&& (== netstandard2.1) (>= net6.0)) System.Runtime.CompilerServices.Unsafe (>= 6.0) System.Text.Encodings.Web (>= 6.0) System.Threading.Tasks.Dataflow (6.0) - copy_local: false System.Threading.Tasks.Extensions (4.5.4) - System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp2.1)) (&& (== net6.0) (< netstandard1.0)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= wp8)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netcoreapp2.1)) (&& (== net7.0) (< netstandard1.0)) (&& (== net7.0) (< netstandard2.0)) (&& (== net7.0) (>= wp8)) (== netstandard2.0) - System.Windows.Extensions (6.0) - copy_local: false, restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) - System.Drawing.Common (>= 6.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) + System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (== net6.0) (>= net461)) (&& (== net6.0) (< netcoreapp2.1)) (&& (== net6.0) (< netstandard1.0)) (&& (== net6.0) (< netstandard2.0)) (&& (== net6.0) (>= wp8)) (&& (== net7.0) (>= net461)) (&& (== net7.0) (< netcoreapp2.1)) (&& (== net7.0) (< netstandard1.0)) (&& (== net7.0) (< netstandard2.0)) (&& (== net7.0) (>= wp8)) (== netstandard2.0) (== netstandard2.1) + System.Windows.Extensions (6.0) - copy_local: false, restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) (&& (== netstandard2.1) (>= netcoreapp3.1)) + System.Drawing.Common (>= 6.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) (&& (== netstandard2.1) (>= netcoreapp3.1)) YoloDev.Expecto.TestSdk (0.13.3) - Expecto (>= 9.0 < 10.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) - FSharp.Core (>= 4.6.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) - System.Collections.Immutable (>= 6.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) + Expecto (>= 9.0 < 10.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) (&& (== netstandard2.1) (>= netcoreapp3.1)) + FSharp.Core (>= 4.6.2) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) (&& (== netstandard2.1) (>= netcoreapp3.1)) + System.Collections.Immutable (>= 6.0) - restriction: || (== net6.0) (== net7.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) (&& (== netstandard2.1) (>= netcoreapp3.1)) GROUP Build STORAGE: NONE diff --git a/src/FsAutoComplete.Core/AbstractClassStubGenerator.fs b/src/FsAutoComplete.Core/AbstractClassStubGenerator.fs index 1d6efbf4d..6b6fc134a 100644 --- a/src/FsAutoComplete.Core/AbstractClassStubGenerator.fs +++ b/src/FsAutoComplete.Core/AbstractClassStubGenerator.fs @@ -6,6 +6,7 @@ open FSharp.Compiler.Syntax open FSharp.Compiler.Symbols open FSharp.Compiler.Tokenization open FsAutoComplete.Logging +open FsToolkit.ErrorHandling type AbstractClassData = @@ -122,26 +123,29 @@ let inferStartColumn (abstractClassData: AbstractClassData) (indentSize: int) = - match getMemberNameAndRanges abstractClassData with - | (_, range) :: _ -> getLineIdent (lines.GetLineString(range.StartLine - 1)) - | [] -> - match abstractClassData with - | AbstractClassData.ExplicitImpl _ -> - // 'interface ISomething with' is often in a new line, we use the indentation of that line - getLineIdent lineStr + indentSize - | AbstractClassData.ObjExpr(_, _, newExprRange) -> - match codeGenServer.TokenizeLine(doc.FullName, pos.Line) with - | Some tokens -> - tokens - |> List.tryPick (fun (t: FSharpTokenInfo) -> - if t.CharClass = FSharpTokenCharKind.Keyword && t.TokenName = "NEW" then - // We round to nearest so the generated code will align on the indentation guides - findGreaterMultiple (t.LeftColumn + indentSize) indentSize |> Some - else - None) - // There is no reference point, we indent the content at the start column of the interface - |> Option.defaultValue newExprRange.StartColumn - | None -> newExprRange.StartColumn + async { + match getMemberNameAndRanges abstractClassData with + | (_, range) :: _ -> return getLineIdent (lines.GetLineString(range.StartLine - 1)) + | [] -> + match abstractClassData with + | AbstractClassData.ExplicitImpl _ -> + // 'interface ISomething with' is often in a new line, we use the indentation of that line + return getLineIdent lineStr + indentSize + | AbstractClassData.ObjExpr(_, _, newExprRange) -> + match! codeGenServer.TokenizeLine(doc.FullName, pos.Line) with + | Some tokens -> + return + tokens + |> List.tryPick (fun (t: FSharpTokenInfo) -> + if t.CharClass = FSharpTokenCharKind.Keyword && t.TokenName = "NEW" then + // We round to nearest so the generated code will align on the indentation guides + findGreaterMultiple (t.LeftColumn + indentSize) indentSize |> Some + else + None) + // There is no reference point, we indent the content at the start column of the interface + |> Option.defaultValue newExprRange.StartColumn + | None -> return newExprRange.StartColumn + } /// Try to write any missing members of the given abstract type at the given location. /// If the destination type isn't an abstract class, or if there are no missing members to implement, @@ -154,7 +158,7 @@ let writeAbstractClassStub (lineStr: string) (abstractClassData: AbstractClassData) = - asyncMaybe { + asyncOption { let pos = Position.mkPos abstractClassData.AbstractTypeIdentRange.Start.Line @@ -164,7 +168,7 @@ let writeAbstractClassStub let! usage = usages let! (displayContext, entity) = - asyncMaybe { + asyncOption { // need the enclosing entity because we're always looking at a ctor, which isn't an Entity, but a MemberOrFunctionOrValue match usage.Symbol with | :? FSharpMemberOrFunctionOrValue as v -> @@ -177,19 +181,22 @@ let writeAbstractClassStub } let getMemberByLocation (name, range: Range) = - asyncMaybe { + asyncOption { let pos = Position.fromZ (range.StartLine - 1) (range.StartColumn + 1) return! checkResultForFile.GetCheckResults.GetSymbolUseAtLocation(pos.Line, pos.Column, lineStr, []) } let insertInfo = - match codeGenServer.TokenizeLine(doc.FullName, pos.Line) with - | Some tokens -> - match abstractClassData with - | AbstractClassData.ObjExpr _ -> - findLastPositionOfWithKeyword tokens entity pos (getAbstractClassIdentifier abstractClassData) - | AbstractClassData.ExplicitImpl(_, _, safeInsertPosition) -> Some(false, safeInsertPosition) - | None -> None + asyncOption { + let! tokens = codeGenServer.TokenizeLine(doc.FullName, pos.Line) + + return + match abstractClassData with + | AbstractClassData.ObjExpr _ -> + findLastPositionOfWithKeyword tokens entity pos (getAbstractClassIdentifier abstractClassData) + | AbstractClassData.ExplicitImpl(_, _, safeInsertPosition) -> Some(false, safeInsertPosition) + + } let desiredMemberNamesWithRanges = getMemberNameAndRanges abstractClassData @@ -197,31 +204,35 @@ let writeAbstractClassStub getImplementedMemberSignatures getMemberByLocation displayContext desiredMemberNamesWithRanges |> Async.map Some - let generatedString = - let formattedString = - formatMembersAt - (inferStartColumn codeGenServer pos doc lines lineStr abstractClassData 4) // 4 here correspond to the indent size - 4 // Should we make it a setting from the IDE ? - abstractClassData.TypeParameters - "$objectIdent" - "$methodBody" - displayContext - implementedSignatures - entity - getAbstractNonVirtualMembers - true // Always generate the verbose version of the code - - // If we are in a object expression, we remove the last new line, so the `}` stay on the same line - match abstractClassData with - | AbstractClassData.ExplicitImpl _ -> formattedString - | AbstractClassData.ObjExpr _ -> formattedString.TrimEnd('\n') + let! generatedString = + async { + let! start = (inferStartColumn codeGenServer pos doc lines lineStr abstractClassData 4) // 4 here correspond to the indent size + + let formattedString = + formatMembersAt + start + 4 // Should we make it a setting from the IDE ? + abstractClassData.TypeParameters + "$objectIdent" + "$methodBody" + displayContext + implementedSignatures + entity + getAbstractNonVirtualMembers + true // Always generate the verbose version of the code + + // If we are in a object expression, we remove the last new line, so the `}` stay on the same line + match abstractClassData with + | AbstractClassData.ExplicitImpl _ -> return formattedString + | AbstractClassData.ObjExpr _ -> return formattedString.TrimEnd('\n') + } // If generatedString is empty it means nothing is missing to the abstract class // So we return None, in order to not show a "Falsy Hint" if System.String.IsNullOrEmpty generatedString then return! None else - match insertInfo with + match! insertInfo with | Some(shouldAppendWith, insertPosition) -> if shouldAppendWith then return! Some(insertPosition, " with" + generatedString) diff --git a/src/FsAutoComplete.Core/AdaptiveExtensions.fs b/src/FsAutoComplete.Core/AdaptiveExtensions.fs index 2758a5d95..06cfc0dbf 100644 --- a/src/FsAutoComplete.Core/AdaptiveExtensions.fs +++ b/src/FsAutoComplete.Core/AdaptiveExtensions.fs @@ -3,6 +3,9 @@ namespace FsAutoComplete.Adaptive open System open FSharp.Data.Adaptive open FSharp.Data.Traceable +open System.Threading.Tasks +open IcedTasks +open System.Threading [] module AdaptiveExtensions = @@ -107,9 +110,14 @@ module AVal = /// Creates an observable with the given object and will be executed whenever the object gets marked out-of-date. Note that it does not trigger when the object is currently out-of-date. /// /// The aval to get out-of-date information from. - /// An observable - let onWeakMarking (aval: #aval<_>) = - Observable.Create(fun (obs: IObserver) -> aval.AddWeakMarkingCallback(obs.OnNext)) + let onOutOfDateWeak (aval: #aval<_>) = + Observable.Create(fun (obs: IObserver<_>) -> aval.AddWeakMarkingCallback(fun _ -> obs.OnNext aval)) + + + /// Creates an observable on the aval that will be executed whenever the avals value changed. + /// The aval to get out-of-date information from. + let onValueChangedWeak (aval: #aval<_>) = + Observable.Create(fun (obs: IObserver<_>) -> aval.AddCallback(obs.OnNext)) module ASet = /// Creates an amap with the keys from the set and the values given by mapping and @@ -288,3 +296,524 @@ module AMap = >> HashMap.map (fun _ v -> AVal.constant v |> AVal.mapWithAdditionalDependenies (id)) batchRecalcDirty mapping map + +/// +/// A task creator that caches the task and cancels it when no longer needed. +/// +/// +/// Since the task can be references multiple times in the dependency graph, it is important to cancel it only after there are no more references to it. +/// +type internal RefCountingTaskCreator<'a>(create: CancellationToken -> Task<'a>) = + + let mutable refCount = 0 + let mutable cache: option> = None + let mutable cancel: CancellationTokenSource = null + + /// Decrements the reference count and cancels the CancellationTokenSource if there are no more references. + member private x.RemoveRef() = + lock x (fun () -> + if refCount = 1 then + refCount <- 0 + cancel.Cancel() + cancel.Dispose() + cancel <- null + cache <- None + else + refCount <- refCount - 1) + + /// Creates a new task based on the creation function from the constructor. If a task has already been created, returns a cached version of the inflight task. + member x.New() = + lock x (fun () -> + match cache with + | Some cache -> + refCount <- refCount + 1 + AdaptiveCancellableTask(x.RemoveRef, cache) + | None -> + cancel <- new CancellationTokenSource() + let task = create cancel.Token + cache <- Some task + refCount <- refCount + 1 + AdaptiveCancellableTask(x.RemoveRef, task)) + +/// +/// Represents a task that can be cancelled. +/// +/// +/// Upon cancellation, it will run the cancel function passed in and set cancellation for the task completion source. +/// +and AdaptiveCancellableTask<'a>(cancel: unit -> unit, real: Task<'a>) = + let cts = new CancellationTokenSource() + + let output = + if real.IsCompleted then + real + else + let tcs = new TaskCompletionSource<'a>() + + let s = cts.Token.Register(fun () -> tcs.TrySetCanceled() |> ignore) + + real.ContinueWith(fun (t: Task<'a>) -> + s.Dispose() + + if t.IsFaulted then tcs.TrySetException(t.Exception) + elif t.IsCanceled then tcs.TrySetCanceled() + else tcs.TrySetResult(t.Result)) + |> ignore + + tcs.Task + + /// Will run the cancel function passed into the constructor and set the output Task to cancelled state. + member x.Cancel() = + cancel () + cts.Cancel() + + /// The output of the passed in task to the constructor. + /// + member x.Task = output + +type asyncaval<'a> = + inherit IAdaptiveObject + abstract GetValue: AdaptiveToken -> AdaptiveCancellableTask<'a> + +module CancellableTask = + /// Converts AdaptiveCancellableTask to a CancellableTask. + let inline ofAdaptiveCancellableTask (ct: AdaptiveCancellableTask<_>) = + fun (ctok: CancellationToken) -> + task { + use _ = ctok.Register(fun () -> ct.Cancel()) + return! ct.Task + } + +module Async = + /// Converts AdaptiveCancellableTask to an Async. + let inline ofAdaptiveCancellableTask (ct: AdaptiveCancellableTask<_>) = + async { + let! ctok = Async.CancellationToken + use _ = ctok.Register(fun () -> ct.Cancel()) + return! ct.Task |> Async.AwaitTask + } + +[] +module Extensions = + + type IcedTasks.CancellableTasks.CancellableTaskBuilderBase with + + /// Allows implicit conversion of a AdaptiveCancellableTask to a CancellableTask in a cancellableTask CE. + member inline x.Source(ct: AdaptiveCancellableTask<_>) = + fun ctok -> (CancellableTask.ofAdaptiveCancellableTask ct ctok).GetAwaiter() + + +module AsyncAVal = + + /// + /// Evaluates the given adaptive value and returns a Task containing the value. + /// This should not be used inside the adaptive evaluation + /// of other AdaptiveObjects since it does not track dependencies. + /// + /// + /// This follows Task semantics and is already running. + /// + let force (value: asyncaval<_>) = value.GetValue(AdaptiveToken.Top) + + /// + /// Evaluates the given adaptive value and returns an Async containing the value. + /// This should not be used inside the adaptive evaluation + /// of other AdaptiveObjects since it does not track dependencies. + /// + /// + /// This follows Async semantics and is not already running. + /// + let forceAsync (value: asyncaval<_>) = + async { + let ct = value.GetValue(AdaptiveToken.Top) + return! Async.ofAdaptiveCancellableTask ct + } + + /// + /// Evaluates the given adaptive value and returns a CancellableTask containing the value. + /// This should not be used inside the adaptive evaluation + /// of other AdaptiveObjects since it does not track dependencies. + /// + /// + /// This follows CancellableTask semantics and is not already running. + /// + let forceCancellableTask (value: asyncaval<_>) = + cancellableTask { + let ct = value.GetValue(AdaptiveToken.Top) + return! ct + } + + /// A constant value that results in a Task. + type ConstantVal<'a>(value: AdaptiveCancellableTask<'a>) = + inherit ConstantObject() + + new(value: Task<'a>) = ConstantVal<'a>(AdaptiveCancellableTask(id, value)) + + interface asyncaval<'a> with + member x.GetValue _ = value + + /// + /// Base class for standard Async Adaptive Values. + /// + [] + type AbstractVal<'a>() = + inherit AdaptiveObject() + abstract Compute: AdaptiveToken -> AdaptiveCancellableTask<'a> + + member x.GetValue token = x.EvaluateAlways token x.Compute + + interface asyncaval<'a> with + member x.GetValue t = x.GetValue t + + /// + /// Creates a constant async adaptive value always holding the given value. + /// + let constant (value: 'a) = + ConstantVal(Task.FromResult value) :> asyncaval<_> + + /// + /// Creates a constant async adaptive value always holding the task. + /// + let ofTask (value: Task<'a>) = ConstantVal(value) :> asyncaval<_> + + let ofCancellableTask (value: CancellableTask<'a>) = + ConstantVal( + let cts = new CancellationTokenSource() + + let cancel () = + cts.Cancel() + cts.Dispose() + + let real = + task { + try + return! value cts.Token + finally + cts.Dispose() + } + + AdaptiveCancellableTask(cancel, real) + ) + :> asyncaval<_> + + + let ofAsync (value: Async<'a>) = + ConstantVal( + let cts = new CancellationTokenSource() + + let cancel () = + cts.Cancel() + cts.Dispose() + + let real = + task { + try + return! Async.StartImmediateAsTask(value, cts.Token) + finally + cts.Dispose() + } + + AdaptiveCancellableTask(cancel, real) + ) + :> asyncaval<_> + + + /// + /// Creates an async adaptive value evaluation the given value. + /// + let ofAVal (value: aval<'a>) = + if value.IsConstant then + ConstantVal(Task.FromResult(AVal.force value)) :> asyncaval<_> + else + { new AbstractVal<'a>() with + member x.Compute t = + let real = Task.FromResult(value.GetValue t) + AdaptiveCancellableTask(id, real) } + :> asyncaval<_> + + + /// + /// Returns a new async adaptive value that adaptively applies the mapping fun tion to the given + /// adaptive inputs. + /// + let map (mapping: 'a -> CancellationToken -> Task<'b>) (input: asyncaval<'a>) = + let mutable cache: option> = None + + { new AbstractVal<'b>() with + member x.Compute t = + if x.OutOfDate || Option.isNone cache then + let ref = + RefCountingTaskCreator( + cancellableTask { + let! ct = CancellableTask.getCancellationToken () + let it = input.GetValue t + let s = ct.Register(fun () -> it.Cancel()) + + try + let! i = it + return! mapping i + finally + s.Dispose() + } + ) + + cache <- Some ref + ref.New() + else + cache.Value.New() } + :> asyncaval<_> + + + /// + /// Returns a new async adaptive value that adaptively applies the mapping fun tion to the given + /// adaptive inputs. + /// + let mapAsync (mapping: 'a -> Async<'b>) (input: asyncaval<'a>) = + let mutable cache: option> = None + + { new AbstractVal<'b>() with + member x.Compute t = + if x.OutOfDate || Option.isNone cache then + let ref = + RefCountingTaskCreator( + cancellableTask { + let! ct = CancellableTask.getCancellationToken () + let it = input.GetValue t + let s = ct.Register(fun () -> it.Cancel()) + + try + let! i = it + return! mapping i + finally + s.Dispose() + } + ) + + cache <- Some ref + ref.New() + else + cache.Value.New() } + :> asyncaval<_> + + + /// + /// Returns a new async adaptive value that adaptively applies the mapping fun tion to the given + /// adaptive inputs. + /// + let mapSync (mapping: 'a -> CancellationToken -> 'b) (input: asyncaval<'a>) = + map (fun a ct -> Task.FromResult(mapping a ct)) input + + /// + /// Returns a new async adaptive value that adaptively applies the mapping function to the given + /// adaptive inputs. + /// + let map2 (mapping: 'a -> 'b -> CancellationToken -> Task<'c>) (ca: asyncaval<'a>) (cb: asyncaval<'b>) = + let mutable cache: option> = None + + { new AbstractVal<'c>() with + member x.Compute t = + if x.OutOfDate || Option.isNone cache then + let ref = + RefCountingTaskCreator( + cancellableTask { + let ta = ca.GetValue t + let tb = cb.GetValue t + + let! ct = CancellableTask.getCancellationToken () + + let s = + ct.Register(fun () -> + ta.Cancel() + tb.Cancel()) + + try + let! va = ta + let! vb = tb + return! mapping va vb + finally + s.Dispose() + } + ) + + cache <- Some ref + ref.New() + else + cache.Value.New() } + :> asyncaval<_> + + /// Returns a new async adaptive value that adaptively applies the mapping function to the given + /// input and adaptively depends on the resulting adaptive value. + /// The resulting adaptive value will hold the latest value of the asyncaval<_> returned by mapping. + let bind (mapping: 'a -> CancellationToken -> asyncaval<'b>) (value: asyncaval<'a>) = + let mutable cache: option<_> = None + let mutable innerCache: option<_> = None + let mutable inputChanged = 0 + let inners: ref>> = ref HashSet.empty + + { new AbstractVal<'b>() with + + override x.InputChangedObject(_, o) = + if System.Object.ReferenceEquals(o, value) then + inputChanged <- 1 + + lock inners (fun () -> + for i in inners.Value do + i.Outputs.Remove x |> ignore + + inners.Value <- HashSet.empty) + + member x.Compute t = + if x.OutOfDate then + if Interlocked.Exchange(&inputChanged, 0) = 1 || Option.isNone cache then + let outerTask = + RefCountingTaskCreator( + cancellableTask { + let it = value.GetValue t + let! ct = CancellableTask.getCancellationToken () + let s = ct.Register(fun () -> it.Cancel()) + + try + let! i = it + let inner = mapping i ct + return inner + finally + s.Dispose() + } + ) + + cache <- Some outerTask + + let outerTask = cache.Value + + let ref = + RefCountingTaskCreator( + cancellableTask { + let innerCellTask = outerTask.New() + + let! ct = CancellableTask.getCancellationToken () + let s = ct.Register(fun () -> innerCellTask.Cancel()) + + try + let! inner = innerCellTask + let innerTask = inner.GetValue t + lock inners (fun () -> inners.Value <- HashSet.add inner inners.Value) + + let s2 = + ct.Register(fun () -> + innerTask.Cancel() + lock inners (fun () -> inners.Value <- HashSet.remove inner inners.Value) + inner.Outputs.Remove x |> ignore) + + try + let! innerValue = innerTask + return innerValue + finally + s2.Dispose() + finally + s.Dispose() + } + ) + + innerCache <- Some ref + + ref.New() + else + innerCache.Value.New() + + } + :> asyncaval<_> + + + /// Returns a new async adaptive value that adaptively applies the mapping function to the given + /// optional adaptive inputs. + let mapOption f (value: asyncaval<'a option>) : asyncaval<'b option> = + mapSync (fun data ctok -> data |> Option.map (fun d -> f d ctok)) value + +type AsyncAValBuilder() = + + member inline x.MergeSources(v1: asyncaval<'T1>, v2: asyncaval<'T2>) = + (v1, v2) + ||> AsyncAVal.map2 (fun a b ctok -> + if ctok.IsCancellationRequested then + Task.FromCanceled<_>(ctok) + else + Task.FromResult(a, b)) + + + // member inline x.MergeSources3(v1 : aval<'T1>, v2 : aval<'T2>, v3 : aval<'T3>) = + // AVal.map3 (fun a b c -> a,b,c) v1 v2 v3 + + member inline x.BindReturn(value: asyncaval<'T1>, [] mapping: 'T1 -> CancellationToken -> Task<'T2>) = + AsyncAVal.map mapping value + + member inline x.BindReturn(value: asyncaval<'T1>, [] mapping: 'T1 -> Async<'T2>) = + AsyncAVal.mapAsync mapping value + + member inline x.BindReturn(value: asyncaval<'T1>, [] mapping: 'T1 -> Task<'T2>) = + AsyncAVal.map (fun data _ -> mapping data) value + + member inline x.Bind(value: asyncaval<'T1>, [] mapping: 'T1 -> CancellationToken -> asyncaval<'T2>) = + AsyncAVal.bind (mapping) value + + member inline x.Bind(value: asyncaval<'T1>, [] mapping: 'T1 -> asyncaval<'T2>) = + AsyncAVal.bind (fun data _ -> mapping data) value + + member inline x.Return(value: 'T) = AsyncAVal.constant value + + member inline x.ReturnFrom(value: asyncaval<'T>) = value + + member inline x.Source(value: asyncaval<'T>) = value + +[] +module AsyncAValBuilderExtensions = + let asyncAVal = AsyncAValBuilder() + + type AsyncAValBuilder with + + member inline x.Source(value: aval<'T>) = AsyncAVal.ofAVal value + member inline x.Source(value: Task<'T>) = AsyncAVal.ofTask value + + member inline x.BindReturn(value: asyncaval<'T1>, [] mapping: 'T1 -> CancellationToken -> 'T2) = + AsyncAVal.mapSync (fun data ctok -> mapping data ctok) value + + member inline x.BindReturn(value: asyncaval<'T1>, [] mapping: 'T1 -> 'T2) = + AsyncAVal.mapSync (fun data ctok -> mapping data) value + +module AMapAsync = + + /// + /// Adaptively maps over the given map lifting the value in the map to be an asyncaval. + /// + let mapAVal + (mapper: 'Key -> 'InValue -> CancellationToken -> asyncaval<'OutValue>) + (map: #amap<'Key, #aval<'InValue>>) + : amap<'Key, asyncaval<'OutValue>> = + map |> AMap.map (fun k v -> v |> AsyncAVal.ofAVal |> AsyncAVal.bind (mapper k)) + + /// + /// Adaptively maps over the given map. + /// + let mapAsyncAVal + (mapper: 'Key -> 'InValue -> CancellationToken -> asyncaval<'OutValue>) + (map: #amap<'Key, #asyncaval<'InValue>>) + : amap<'Key, asyncaval<'OutValue>> = + map |> AMap.map (fun k v -> v |> AsyncAVal.bind (mapper k)) + + /// Adaptively looks up the given key in the map and binds the value to be easily worked with. Note that this operation should not be used extensively since its resulting aval will be re-evaluated upon every change of the map. + let tryFindA (key: 'Key) (map: amap<'Key, #asyncaval<'Value>>) = + asyncAVal { + match! AMap.tryFind key map with + | Some v -> + let! v2 = v + return Some v2 + | None -> return None + } + + + /// Adaptively looks up the given key in the map and flattens the value to be easily worked with. Note that this operation should not be used extensively since its resulting aval will be re-evaluated upon every change of the map. + let tryFindAndFlatten (key: 'Key) (map: amap<'Key, asyncaval>>) = + asyncAVal { + match! AMap.tryFind key map with + | Some x -> return! x + | None -> return None + } diff --git a/src/FsAutoComplete.Core/CodeGeneration.fs b/src/FsAutoComplete.Core/CodeGeneration.fs index 8769a8d14..2963343f7 100644 --- a/src/FsAutoComplete.Core/CodeGeneration.fs +++ b/src/FsAutoComplete.Core/CodeGeneration.fs @@ -19,18 +19,18 @@ type Line0 type Line1 type ICodeGenerationService = - abstract TokenizeLine: string * int -> option> - abstract GetSymbolAtPosition: string * Position -> option + abstract TokenizeLine: string * int -> Async>> + abstract GetSymbolAtPosition: string * Position -> Async> abstract GetSymbolAndUseAtPositionOfKind: string * Position * SymbolKind -> Async>> - abstract ParseFileInProject: string -> option + abstract ParseFileInProject: string -> Async> type CodeGenerationService(checker: FSharpCompilerServiceChecker, state: State) = interface ICodeGenerationService with override x.TokenizeLine(fileName, i) = - option { + asyncOption { let! text = state.TryGetFileSource fileName |> Option.ofResult try @@ -41,13 +41,16 @@ type CodeGenerationService(checker: FSharpCompilerServiceChecker, state: State) } override x.GetSymbolAtPosition(fileName, pos: Position) = - match state.TryGetFileCheckerOptionsWithLinesAndLineStr(fileName, pos) with - | ResultOrString.Error _ -> None - | ResultOrString.Ok(opts, lines, line) -> - try - Lexer.getSymbol pos.Line pos.Column line SymbolLookupKind.Fuzzy [||] - with _ -> - None + asyncOption { + return! + match state.TryGetFileCheckerOptionsWithLinesAndLineStr(fileName, pos) with + | ResultOrString.Error _ -> None + | ResultOrString.Ok(opts, lines, line) -> + try + Lexer.getSymbol pos.Line pos.Column line SymbolLookupKind.Fuzzy [||] + with _ -> + None + } override x.GetSymbolAndUseAtPositionOfKind(fileName, pos: Position, kind) = asyncMaybe { @@ -65,14 +68,17 @@ type CodeGenerationService(checker: FSharpCompilerServiceChecker, state: State) } override x.ParseFileInProject(fileName) = - match state.TryGetFileCheckerOptionsWithLines fileName with - | ResultOrString.Error _ -> None - | ResultOrString.Ok(opts, text) -> - try - checker.TryGetRecentCheckResultsForFile(fileName, opts, text) - |> Option.map (fun n -> n.GetParseResults) - with _ -> - None + async { + match state.TryGetFileCheckerOptionsWithLines fileName with + | ResultOrString.Error _ -> return None + | ResultOrString.Ok(opts, text) -> + try + return + checker.TryGetRecentCheckResultsForFile(fileName, opts, text) + |> Option.map (fun n -> n.GetParseResults) + with _ -> + return None + } module CodeGenerationUtils = open FSharp.Compiler.Syntax.PrettyNaming @@ -121,49 +127,54 @@ module CodeGenerationUtils = (document: Document) (predicate: FSharpTokenInfo -> bool) = - // Normalize range - // NOTE: FCS compiler sometimes returns an invalid range. In particular, the - // range end limit can exceed the end limit of the document - let range = - if range.EndLine > document.LineCount then - let newEndLine = document.LineCount - let newEndColumn = document.GetLineText1(document.LineCount).Length - let newEndPos = Position.mkPos newEndLine newEndColumn - - Range.mkRange range.FileName range.Start newEndPos - else - range + async { + // Normalize range + // NOTE: FCS compiler sometimes returns an invalid range. In particular, the + // range end limit can exceed the end limit of the document + let range = + if range.EndLine > document.LineCount then + let newEndLine = document.LineCount + let newEndColumn = document.GetLineText1(document.LineCount).Length + let newEndPos = Position.mkPos newEndLine newEndColumn + + Range.mkRange range.FileName range.Start newEndPos + else + range + + let! lineIdxAndTokenSeq = + seq { + let lines = + if range.StartLine = range.EndLine then + [ range.StartLine ] + else + [ range.StartLine .. range.EndLine ] + + for lineIdx in lines do + yield + codeGenService.TokenizeLine(document.FullName, lineIdx) + |> AsyncOption.map (List.map (fun tokenInfo -> lineIdx * 1, tokenInfo)) + + } + |> Async.parallel75 + |> Async.map (Array.Parallel.choose id) + + let lineIdxAndTokenSeq = lineIdxAndTokenSeq |> Array.collect (List.toArray) - let lineIdxAndTokenSeq = - seq { - let lines = + return + lineIdxAndTokenSeq + |> Seq.tryFind (fun (line1, tokenInfo) -> if range.StartLine = range.EndLine then - [ range.StartLine ] + tokenInfo.LeftColumn >= range.StartColumn + && tokenInfo.RightColumn < range.EndColumn + && predicate tokenInfo + elif range.StartLine = int line1 then + tokenInfo.LeftColumn >= range.StartColumn && predicate tokenInfo + elif int line1 = range.EndLine then + tokenInfo.RightColumn < range.EndColumn && predicate tokenInfo else - [ range.StartLine .. range.EndLine ] - - for lineIdx in lines do - match - codeGenService.TokenizeLine(document.FullName, lineIdx) - |> Option.map (List.map (fun tokenInfo -> lineIdx * 1, tokenInfo)) - with - | Some xs -> yield! xs - | None -> () - } - - lineIdxAndTokenSeq - |> Seq.tryFind (fun (line1, tokenInfo) -> - if range.StartLine = range.EndLine then - tokenInfo.LeftColumn >= range.StartColumn - && tokenInfo.RightColumn < range.EndColumn - && predicate tokenInfo - elif range.StartLine = int line1 then - tokenInfo.LeftColumn >= range.StartColumn && predicate tokenInfo - elif int line1 = range.EndLine then - tokenInfo.RightColumn < range.EndColumn && predicate tokenInfo - else - predicate tokenInfo) - |> Option.map (fun (line1, tokenInfo) -> tokenInfo, (Position.fromZ (int line1 - 1) tokenInfo.LeftColumn)) + predicate tokenInfo) + |> Option.map (fun (line1, tokenInfo) -> tokenInfo, (Position.fromZ (int line1 - 1) tokenInfo.LeftColumn)) + } /// Represent environment where a captured identifier should be renamed type NamesWithIndices = Map> diff --git a/src/FsAutoComplete.Core/Commands.fs b/src/FsAutoComplete.Core/Commands.fs index e894cfee4..e41c9911f 100644 --- a/src/FsAutoComplete.Core/Commands.fs +++ b/src/FsAutoComplete.Core/Commands.fs @@ -397,7 +397,7 @@ module Commands = } let formatSelection - (tryGetFileCheckerOptionsWithLines: _ -> Result) + (tryGetFileCheckerOptionsWithLines: _ -> Async>) (formatSelectionAsync: _ -> System.Threading.Tasks.Task) (file: string) (rangeToFormat: FormatSelectionRange) @@ -454,7 +454,7 @@ module Commands = } let formatDocument - (tryGetFileCheckerOptionsWithLines: _ -> Result) + (tryGetFileCheckerOptionsWithLines: _ -> Async>) (formatDocumentAsync: _ -> System.Threading.Tasks.Task) (file: string) : Async> = @@ -531,11 +531,12 @@ module Commands = if fsym.IsPrivateToFile then return CoreResponse.Res(LocationResponse.Use(sym, filterSymbols usages)) else if fsym.IsInternalToProject then - let opts = getProjectOptions tyRes.FileName + let! opts = getProjectOptions tyRes.FileName let! symbols = getUsesOfSymbol (tyRes.FileName, [ UMX.untag tyRes.FileName, opts ], sym.Symbol) return CoreResponse.Res(LocationResponse.Use(sym, filterSymbols symbols)) else - let! symbols = getUsesOfSymbol (tyRes.FileName, getAllProjects (), sym.Symbol) + let! projs = getAllProjects () + let! symbols = getUsesOfSymbol (tyRes.FileName, projs, sym.Symbol) let symbols = filterSymbols symbols return CoreResponse.Res(LocationResponse.Use(sym, filterSymbols symbols)) | Error e -> return CoreResponse.ErrorRes e @@ -617,8 +618,8 @@ module Commands = |> AsyncResult.foldResult id (fun _ -> [||]) - let pipelineHints (tryGetFileSource: _ -> Result) (tyRes: ParseAndCheckResults) = - result { + let pipelineHints (tryGetFileSource: _ -> Async>) (tyRes: ParseAndCheckResults) = + asyncResult { // Debug.waitForDebuggerAttached "AdaptiveServer" let! contents = tryGetFileSource tyRes.FileName @@ -677,7 +678,7 @@ module Commands = return CoreResponse.Res hints } - |> Result.fold id (fun _ -> CoreResponse.InfoRes "Couldn't find file content") + |> AsyncResult.bimap id (fun _ -> CoreResponse.InfoRes "Couldn't find file content") let calculateNamespaceInsert currentAst @@ -760,11 +761,11 @@ module Commands = /// * When exact ranges are required /// -> for "Rename" let symbolUseWorkspace - (getDeclarationLocation: FSharpSymbolUse * NamedText -> SymbolDeclarationLocation option) + (getDeclarationLocation: FSharpSymbolUse * NamedText -> Async) (findReferencesForSymbolInFile: (string * FSharpProjectOptions * FSharpSymbol) -> Async) - (tryGetFileSource: string -> ResultOrString) - (tryGetProjectOptionsForFsproj: string -> FSharpProjectOptions option) - (getAllProjectOptions: unit -> FSharpProjectOptions seq) + (tryGetFileSource: string -> Async>) + (tryGetProjectOptionsForFsproj: string -> Async) + (getAllProjectOptions: unit -> Async) (includeDeclarations: bool) (includeBackticks: bool) (errorOnFailureToFixRange: bool) @@ -797,7 +798,7 @@ module Commands = |> Seq.toArray |> Ok - let declLoc = getDeclarationLocation (symbolUse, text) + let! declLoc = getDeclarationLocation (symbolUse, text) match declLoc with // local symbol -> all uses are inside `text` @@ -819,32 +820,46 @@ module Commands = return (symbol, ranges) | scope -> - let projectsToCheck = - match scope with - | Some(SymbolDeclarationLocation.Projects(projects (*isLocalForProject=*) , true)) -> projects - | Some(SymbolDeclarationLocation.Projects(projects (*isLocalForProject=*) , false)) -> - [ for project in projects do - yield project - - yield! - project.ReferencedProjects - |> Array.choose (fun p -> UMX.tag p.OutputFile |> tryGetProjectOptionsForFsproj) ] - |> List.distinctBy (fun x -> x.ProjectFileName) - | _ (*None*) -> - // symbol is declared external -> look through all F# projects - // (each script (including untitled) has its own project -> scripts get checked too. But only once they are loaded (-> inside `state`)) - getAllProjectOptions () - |> Seq.distinctBy (fun x -> x.ProjectFileName) - |> Seq.toList + let projectsToCheck: Async = + async { + match scope with + | Some(SymbolDeclarationLocation.Projects(projects (*isLocalForProject=*) , true)) -> return projects + | Some(SymbolDeclarationLocation.Projects(projects (*isLocalForProject=*) , false)) -> + let output = ResizeArray<_>() + + let! resolvedProjects = + [ for project in projects do + yield Async.singleton (Some project) + + yield! + project.ReferencedProjects + |> Array.map (fun p -> UMX.tag p.OutputFile |> tryGetProjectOptionsForFsproj) ] + |> Async.parallel75 + + + return + resolvedProjects + |> Array.choose id + |> Array.toList + |> List.distinctBy (fun x -> x.ProjectFileName) + | _ (*None*) -> + // symbol is declared external -> look through all F# projects + // (each script (including untitled) has its own project -> scripts get checked too. But only once they are loaded (-> inside `state`)) + let! allOptions = getAllProjectOptions () + return allOptions |> Seq.distinctBy (fun x -> x.ProjectFileName) |> Seq.toList + } let tryAdjustRanges (file: string, ranges: Range[]) = - match tryGetFileSource file with - | Error _ when errorOnFailureToFixRange -> Error $"Cannot get source of '{file}'" - | Error _ -> Ok ranges - | Ok text -> - tryAdjustRanges (text, ranges) - // Note: `Error` only possible when `errorOnFailureToFixRange` - |> Result.mapError (fun _ -> $"Cannot adjust ranges in file '{file}'") + async { + match! tryGetFileSource file with + | Error _ when errorOnFailureToFixRange -> return Error $"Cannot get source of '{file}'" + | Error _ -> return Ok ranges + | Ok text -> + return + tryAdjustRanges (text, ranges) + // Note: `Error` only possible when `errorOnFailureToFixRange` + |> Result.mapError (fun _ -> $"Cannot adjust ranges in file '{file}'") + } let isDeclLocation = if includeDeclarations then @@ -879,7 +894,7 @@ module Commands = if references |> Array.isEmpty then return Ok() else - let ranges = tryAdjustRanges (file, references) + let! ranges = tryAdjustRanges (file, references) match ranges with | Error msg when errorOnFailureToFixRange -> return Error msg @@ -917,16 +932,19 @@ module Commands = | Error err -> return Some err } ] - |> Async.Choice - |> Async.map (function - | None -> Ok() - | Some err -> Error err) + |> Async.parallel75 + |> Async.Ignore<_> + // |> Async.map (function + // | None -> Ok() + // | Some err -> Error err) - do! iterProjects projectsToCheck + let! projects = projectsToCheck + do! iterProjects projects return (symbol, dict) } + /// Puts `newName` into backticks if necessary. /// /// @@ -972,7 +990,7 @@ module Commands = /// Rename for Active Pattern Cases is disabled: /// `SymbolUseWorkspace` returns ranges for ALL Cases of that Active Pattern instead of just the single case let renameSymbolRange - (getDeclarationLocation: FSharpSymbolUse * NamedText -> SymbolDeclarationLocation option) + (getDeclarationLocation: FSharpSymbolUse * NamedText -> Async) (includeBackticks: bool) pos lineStr @@ -987,7 +1005,7 @@ module Commands = let! _ = // None: external symbol -> not under our control -> cannot rename getDeclarationLocation (symbolUse, text) - |> Result.ofOption (fun _ -> "Must be declared inside current workspace, but is external.") + |> AsyncResult.ofOption (fun _ -> "Must be declared inside current workspace, but is external.") do! match symbolUse with @@ -2014,8 +2032,8 @@ type Commands(checker: FSharpCompilerServiceChecker, state: State, hasAnalyzers: SymbolLocation.getDeclarationLocation ( symbolUse, text, - state.GetProjectOptions, - state.ProjectController.ProjectsThatContainFile, + state.GetProjectOptions >> Async.singleton, + state.ProjectController.ProjectsThatContainFile >> Async.singleton, state.ProjectController.GetDependentProjectsOfProjects ) @@ -2048,13 +2066,15 @@ type Commands(checker: FSharpCompilerServiceChecker, state: State, hasAnalyzers: return usages |> Seq.map (fun u -> u.Range) } - let tryGetFileSource symbolFile = state.TryGetFileSource symbolFile + let tryGetFileSource symbolFile = + state.TryGetFileSource symbolFile |> Async.singleton let tryGetProjectOptionsForFsproj (fsprojPath: string) = state.ProjectController.GetProjectOptionsForFsproj(UMX.untag fsprojPath) + |> Async.singleton let getAllProjectOptions () = - state.ProjectController.ProjectOptions |> Seq.map snd + state.ProjectController.ProjectOptions |> Seq.map snd |> Async.singleton return! Commands.symbolUseWorkspace @@ -2086,13 +2106,14 @@ type Commands(checker: FSharpCompilerServiceChecker, state: State, hasAnalyzers: } member x.SymbolImplementationProject (tyRes: ParseAndCheckResults) (pos: Position) lineStr = - let getProjectOptions filePath = state.GetProjectOptions' filePath + let getProjectOptions filePath = + state.GetProjectOptions' filePath |> Async.singleton let getUsesOfSymbol (filePath, opts, sym: FSharpSymbol) = checker.GetUsesOfSymbol(filePath, opts, sym) let getAllProjects () = - state.FSharpProjectOptions |> Seq.toList + state.FSharpProjectOptions |> Seq.toList |> Async.singleton Commands.symbolImplementationProject getProjectOptions getUsesOfSymbol getAllProjects tyRes pos lineStr |> x.AsCancellable tyRes.FileName @@ -2319,7 +2340,7 @@ type Commands(checker: FSharpCompilerServiceChecker, state: State, hasAnalyzers: member x.FormatDocument(file: string) : Async> = let tryGetFileCheckerOptionsWithLines file = - x.TryGetFileCheckerOptionsWithLines file |> Result.map snd + x.TryGetFileCheckerOptionsWithLines file |> Result.map snd |> Async.singleton let formatDocumentAsync x = fantomasService.FormatDocumentAsync x Commands.formatDocument tryGetFileCheckerOptionsWithLines formatDocumentAsync file @@ -2330,7 +2351,7 @@ type Commands(checker: FSharpCompilerServiceChecker, state: State, hasAnalyzers: rangeToFormat: FormatSelectionRange ) : Async> = let tryGetFileCheckerOptionsWithLines file = - x.TryGetFileCheckerOptionsWithLines file |> Result.map snd + x.TryGetFileCheckerOptionsWithLines file |> Result.map snd |> Async.singleton let formatSelectionAsync x = fantomasService.FormatSelectionAsync x Commands.formatSelection tryGetFileCheckerOptionsWithLines formatSelectionAsync file rangeToFormat @@ -2381,7 +2402,7 @@ type Commands(checker: FSharpCompilerServiceChecker, state: State, hasAnalyzers: static member InlineValues(contents: NamedText, tyRes: ParseAndCheckResults) = Commands.inlineValues contents tyRes member __.PipelineHints(tyRes: ParseAndCheckResults) = - Commands.pipelineHints state.TryGetFileSource tyRes + Commands.pipelineHints (state.TryGetFileSource >> Async.singleton) tyRes interface IDisposable with member x.Dispose() = diff --git a/src/FsAutoComplete.Core/CompilerServiceInterface.fs b/src/FsAutoComplete.Core/CompilerServiceInterface.fs index 0a918b424..7f4bc9299 100644 --- a/src/FsAutoComplete.Core/CompilerServiceInterface.fs +++ b/src/FsAutoComplete.Core/CompilerServiceInterface.fs @@ -165,6 +165,8 @@ type FSharpCompilerServiceChecker(hasAnalyzers, typecheckCacheSize) = let allFlags = Array.append [| "--targetprofile:mscorlib" |] fsiAdditionalArguments + do! Async.SwitchToNewThread() + let! (opts, errors) = checker.GetProjectOptionsFromScript( UMX.untag file, @@ -190,6 +192,8 @@ type FSharpCompilerServiceChecker(hasAnalyzers, typecheckCacheSize) = let allFlags = Array.append [| "--targetprofile:netstandard" |] fsiAdditionalArguments + do! Async.SwitchToNewThread() + let! (opts, errors) = checker.GetProjectOptionsFromScript( UMX.untag file, @@ -252,12 +256,21 @@ type FSharpCompilerServiceChecker(hasAnalyzers, typecheckCacheSize) = checker.InvalidateAll() checker.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients() - member __.ParseFile(fn: string, source, fpo) = + /// Parses a source code for a file and caches the results. Returns an AST that can be traversed for various features. + /// The path for the file. The file name is used as a module name for implicit top level modules (e.g. in scripts). + /// The source to be parsed. + /// Parsing options for the project or script. + /// + member __.ParseFile(filePath: string, source: ISourceText, options: FSharpParsingOptions) = async { - checkerLogger.info (Log.setMessage "ParseFile - {file}" >> Log.addContextDestructured "file" fn) + checkerLogger.info ( + Log.setMessage "ParseFile - {file}" + >> Log.addContextDestructured "file" filePath + ) - let path = UMX.untag fn - return! checker.ParseFile(path, source, fpo) + let path = UMX.untag filePath + do! Async.SwitchToNewThread() + return! checker.ParseFile(path, source, options) } /// Parse and check a source code file, returning a handle to the results @@ -286,6 +299,7 @@ type FSharpCompilerServiceChecker(hasAnalyzers, typecheckCacheSize) = let path = UMX.untag filePath try + do! Async.SwitchToNewThread() let! (p, c) = checker.ParseAndCheckFileInProject(path, version, source, options, userOpName = opName) let parseErrors = p.Diagnostics |> Array.map (fun p -> p.Message) @@ -380,6 +394,8 @@ type FSharpCompilerServiceChecker(hasAnalyzers, typecheckCacheSize) = >> Log.addContextDestructured "file" file ) + do! Async.SwitchToNewThread() + match FSharpCompilerServiceChecker.GetDependingProjects file options with | None -> return [||] | Some(opts, []) -> @@ -391,28 +407,35 @@ type FSharpCompilerServiceChecker(hasAnalyzers, typecheckCacheSize) = opts :: dependentProjects |> List.map (fun (opts) -> async { + do! Async.SwitchToNewThread() let opts = clearProjectReferences opts let! res = checker.ParseAndCheckProject opts return res.GetUsesOfSymbol symbol }) - |> Async.Parallel + |> Async.parallel75 return res |> Array.concat } member _.FindReferencesForSymbolInFile(file, project, symbol) = - checkerLogger.info ( - Log.setMessage "FindReferencesForSymbolInFile - {file}" - >> Log.addContextDestructured "file" file - ) + async { + checkerLogger.info ( + Log.setMessage "FindReferencesForSymbolInFile - {file}" + >> Log.addContextDestructured "file" file + ) - checker.FindBackgroundReferencesInFile( - file, - project, - symbol, - canInvalidateProject = false, - userOpName = "find references" - ) + do! Async.SwitchToNewThread() + + return! + checker.FindBackgroundReferencesInFile( + file, + project, + symbol, + canInvalidateProject = false, + // fastCheck = true, + userOpName = "find references" + ) + } member __.GetDeclarations(fileName: string, source, options, version) = async { @@ -421,6 +444,7 @@ type FSharpCompilerServiceChecker(hasAnalyzers, typecheckCacheSize) = >> Log.addContextDestructured "file" fileName ) + do! Async.SwitchToNewThread() let! parseResult = checker.ParseFile(UMX.untag fileName, source, options) return parseResult.GetNavigationItems().Declarations } diff --git a/src/FsAutoComplete.Core/RecordStubGenerator.fs b/src/FsAutoComplete.Core/RecordStubGenerator.fs index ee88d0435..258204472 100644 --- a/src/FsAutoComplete.Core/RecordStubGenerator.fs +++ b/src/FsAutoComplete.Core/RecordStubGenerator.fs @@ -7,6 +7,7 @@ open FSharp.Compiler.Text open System.Diagnostics open FsAutoComplete.CodeGenerationUtils open FSharp.Compiler.Symbols +open FsToolkit.ErrorHandling // Algorithm // [x] Make sure '}' is the last token of the expression @@ -220,7 +221,7 @@ let tryFindRecordExprInBufferAtPos (codeGenService: ICodeGenerationService) (pos let checkThatRecordExprEndsWithRBrace (codeGenService: ICodeGenerationService) (document: Document) (expr: RecordExpr) = - maybe { + asyncOption { let! rangeWhereToLookForEnclosingRBrace = match expr.FieldExprList with | [] -> Some expr.Expr.Range @@ -247,13 +248,15 @@ let checkThatRecordExprEndsWithRBrace (codeGenService: ICodeGenerationService) ( tryFindTokenLPosInRange codeGenService rangeWhereToLookForEnclosingRBrace document (fun tokenInfo -> tokenInfo.TokenName = "RBRACE") } - |> Option.isSome + |> Async.map Option.isSome let tryFindStubInsertionParamsAtPos (codeGenService: ICodeGenerationService) (pos: Position) (document: Document) = - asyncMaybe { + asyncOption { let! recordExpression = tryFindRecordExprInBufferAtPos codeGenService pos document - if checkThatRecordExprEndsWithRBrace codeGenService document recordExpression then + let! endsWithBrace = checkThatRecordExprEndsWithRBrace codeGenService document recordExpression + + if endsWithBrace then let! insertionPos = RecordStubsInsertionParams.TryCreateFromRecordExpression recordExpression return recordExpression, insertionPos else diff --git a/src/FsAutoComplete.Core/SymbolLocation.fs b/src/FsAutoComplete.Core/SymbolLocation.fs index 9ad9e76b8..b6f9701bc 100644 --- a/src/FsAutoComplete.Core/SymbolLocation.fs +++ b/src/FsAutoComplete.Core/SymbolLocation.fs @@ -4,6 +4,7 @@ open FSharp.Compiler.EditorServices open FSharp.Compiler.CodeAnalysis open System.IO open FSharp.UMX +open FsToolkit.ErrorHandling [] type SymbolDeclarationLocation = @@ -15,27 +16,27 @@ let getDeclarationLocation symbolUse: FSharpSymbolUse, currentDocument: NamedText, getProjectOptions, - projectsThatContainFile, + projectsThatContainFile: string -> Async, getDependentProjectsOfProjects // state: State - ) : SymbolDeclarationLocation option = + ) : Async> = + asyncOption { - // `symbolUse.IsPrivateToFile` throws exception when no `DeclarationLocation` - if - symbolUse.Symbol.DeclarationLocation |> Option.isSome - && symbolUse.IsPrivateToFile - then - Some SymbolDeclarationLocation.CurrentDocument - else - let isSymbolLocalForProject = symbolUse.Symbol.IsInternalToProject + // `symbolUse.IsPrivateToFile` throws exception when no `DeclarationLocation` + if + symbolUse.Symbol.DeclarationLocation |> Option.isSome + && symbolUse.IsPrivateToFile + then + return SymbolDeclarationLocation.CurrentDocument + else + let isSymbolLocalForProject = symbolUse.Symbol.IsInternalToProject - let declarationLocation = - match symbolUse.Symbol.ImplementationLocation with - | Some x -> Some x - | None -> symbolUse.Symbol.DeclarationLocation + let declarationLocation = + match symbolUse.Symbol.ImplementationLocation with + | Some x -> Some x + | None -> symbolUse.Symbol.DeclarationLocation - match declarationLocation with - | Some loc -> + let! loc = declarationLocation let isScript = isAScript loc.FileName // sometimes the source file locations start with a capital, despite all of our efforts. let normalizedPath = @@ -48,22 +49,24 @@ let getDeclarationLocation let taggedFilePath = UMX.tag normalizedPath if isScript && taggedFilePath = currentDocument.FileName then - Some SymbolDeclarationLocation.CurrentDocument + return SymbolDeclarationLocation.CurrentDocument elif isScript then // The standalone script might include other files via '#load' // These files appear in project options and the standalone file // should be treated as an individual project - getProjectOptions (taggedFilePath) - |> Option.map (fun p -> SymbolDeclarationLocation.Projects([ p ], isSymbolLocalForProject)) + return! + getProjectOptions (taggedFilePath) + |> AsyncOption.map (fun p -> SymbolDeclarationLocation.Projects([ p ], isSymbolLocalForProject)) else - match projectsThatContainFile (taggedFilePath) with - | [] -> None + match! projectsThatContainFile (taggedFilePath) with + | [] -> return! None | projectsThatContainFile -> let projectsThatDependOnContainingProjects = getDependentProjectsOfProjects projectsThatContainFile match projectsThatDependOnContainingProjects with - | [] -> Some(SymbolDeclarationLocation.Projects(projectsThatContainFile, isSymbolLocalForProject)) + | [] -> return (SymbolDeclarationLocation.Projects(projectsThatContainFile, isSymbolLocalForProject)) | projects -> - Some(SymbolDeclarationLocation.Projects(projectsThatContainFile @ projects, isSymbolLocalForProject)) - | None -> None + return (SymbolDeclarationLocation.Projects(projectsThatContainFile @ projects, isSymbolLocalForProject)) + + } diff --git a/src/FsAutoComplete.Core/UnionPatternMatchCaseGenerator.fs b/src/FsAutoComplete.Core/UnionPatternMatchCaseGenerator.fs index 33611cc07..4680c7df2 100644 --- a/src/FsAutoComplete.Core/UnionPatternMatchCaseGenerator.fs +++ b/src/FsAutoComplete.Core/UnionPatternMatchCaseGenerator.fs @@ -385,90 +385,93 @@ let tryFindBarTokenLPosInRange (codeGenService: ICodeGenerationService) (range: tryFindTokenLPosInRange codeGenService range document (fun tokenInfo -> tokenInfo.TokenName = "BAR") let tryFindInsertionParams (codeGenService: ICodeGenerationService) document (patMatchExpr: PatternMatchExpr) = - match List.rev patMatchExpr.Clauses with - | [] -> - // Not possible normally - None - - | last :: _ -> - // Interesting cases: - // - // (1) - // match x with - // | Case1 -> () | Case2 -> () - // - // - // - // (2) - // match x with - // Case1 -> () | Case2 -> () - // - // - // (3) - // match x with - // | Case1 -> () - // | Case2 -> () - // - // - // (4) - // match x with - // | Case1 -> () - // | - // Case2 -> () - // - // - // (5) - // match x with | Case1 -> () | Case2 -> () - // - - // To know the indentation column, - // We want to find the first clause of the clauses that are on the same last line - // All clause f(i) start at line l(i) - // We want to 'f(k)' such that k = min { i >= k such that l(i) = l(k) } - // And l(k) = max { l(i) } - - // TODO: report this bug: - // when renaming it like this: ``list of (clause, line index)`` - // FSI interactive bugs: - // error FS0192: internal error: binding null type in envBindTypeRef: list of (clause, line index) - let clauseAndLineIdxList = - [ for clause in patMatchExpr.Clauses do - yield clause, clause.Range.StartLine ] - - // Get first of the clauses that are on the same last line - let lastLineIdx = - clauseAndLineIdxList |> List.map (fun (_, lineIdx) -> lineIdx) |> Seq.last - - let firstClauseOnLastLine = - clauseAndLineIdxList - |> List.find (fun (_, lineIdx) -> lineIdx = lastLineIdx) - |> fst - - // Find if this clause has a pipe before it on the same line as itself - let possibleBarLocationRange = - // Special case (5): - // 'match-with'/'function' is on the same line as the first clause - // on the last line - if patMatchExpr.MatchWithOrFunctionRange.EndLine = firstClauseOnLastLine.Range.StartLine then - Range.unionRanges patMatchExpr.MatchWithOrFunctionRange.EndRange firstClauseOnLastLine.Range.StartRange - else - let clause = firstClauseOnLastLine - let start = Position.mkPos clause.Range.StartLine 0 - Range.mkRange clause.Range.FileName start clause.Range.Start - - let barTokenOpt = - tryFindBarTokenLPosInRange codeGenService possibleBarLocationRange document - - match barTokenOpt with - | Some(_, barTokenLPos) -> - { IndentColumn = barTokenLPos.Column - InsertionPos = last.Range.End } - |> Some - - | None -> - { IndentColumn = firstClauseOnLastLine.Range.StartColumn - InsertionPos = last.Range.End } - |> Some + async { + match List.rev patMatchExpr.Clauses with + | [] -> + // Not possible normally + return None + + | last :: _ -> + // Interesting cases: + // + // (1) + // match x with + // | Case1 -> () | Case2 -> () + // + // + // + // (2) + // match x with + // Case1 -> () | Case2 -> () + // + // + // (3) + // match x with + // | Case1 -> () + // | Case2 -> () + // + // + // (4) + // match x with + // | Case1 -> () + // | + // Case2 -> () + // + // + // (5) + // match x with | Case1 -> () | Case2 -> () + // + + // To know the indentation column, + // We want to find the first clause of the clauses that are on the same last line + // All clause f(i) start at line l(i) + // We want to 'f(k)' such that k = min { i >= k such that l(i) = l(k) } + // And l(k) = max { l(i) } + + // TODO: report this bug: + // when renaming it like this: ``list of (clause, line index)`` + // FSI interactive bugs: + // error FS0192: internal error: binding null type in envBindTypeRef: list of (clause, line index) + let clauseAndLineIdxList = + [ for clause in patMatchExpr.Clauses do + yield clause, clause.Range.StartLine ] + + // Get first of the clauses that are on the same last line + let lastLineIdx = + clauseAndLineIdxList |> List.map (fun (_, lineIdx) -> lineIdx) |> Seq.last + + let firstClauseOnLastLine = + clauseAndLineIdxList + |> List.find (fun (_, lineIdx) -> lineIdx = lastLineIdx) + |> fst + + // Find if this clause has a pipe before it on the same line as itself + let possibleBarLocationRange = + // Special case (5): + // 'match-with'/'function' is on the same line as the first clause + // on the last line + if patMatchExpr.MatchWithOrFunctionRange.EndLine = firstClauseOnLastLine.Range.StartLine then + Range.unionRanges patMatchExpr.MatchWithOrFunctionRange.EndRange firstClauseOnLastLine.Range.StartRange + else + let clause = firstClauseOnLastLine + let start = Position.mkPos clause.Range.StartLine 0 + Range.mkRange clause.Range.FileName start clause.Range.Start + + let! barTokenOpt = tryFindBarTokenLPosInRange codeGenService possibleBarLocationRange document + + match barTokenOpt with + | Some(_, barTokenLPos) -> + return + { IndentColumn = barTokenLPos.Column + InsertionPos = last.Range.End } + |> Some + + | None -> + return + { IndentColumn = firstClauseOnLastLine.Range.StartColumn + InsertionPos = last.Range.End } + |> Some + } let checkThatPatternMatchExprEndsWithCompleteClause (expr: PatternMatchExpr) = diff --git a/src/FsAutoComplete.Core/Utils.fs b/src/FsAutoComplete.Core/Utils.fs index b333a9b51..c055d8772 100644 --- a/src/FsAutoComplete.Core/Utils.fs +++ b/src/FsAutoComplete.Core/Utils.fs @@ -222,6 +222,14 @@ module Async = // Start the workflow using a provided cancellation token Async.StartWithContinuations(work, cont, econt, ccont, cancellationToken = cancellationToken)) + /// Creates an asynchronous computation that executes all the given asynchronous computations, using 75% of the Environment.ProcessorCount + /// A sequence of distinct computations to be parallelized. + let parallel75 computations = + let maxConcurrency = + Math.Max(1.0, Math.Floor((float System.Environment.ProcessorCount) * 0.75)) + + Async.Parallel(computations, int maxConcurrency) + [] module Array = /// Async implementation of Array.map. @@ -903,6 +911,9 @@ module Tracing = let fsacActivitySource = new ActivitySource(serviceName, Version.info().Version) + let recordException (e: exn) (trace: Activity) = + trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + /// /// StreamJsonRpcTracingStrategy participates in and propagates trace context in vs-streamjsonrpc /// diff --git a/src/FsAutoComplete.Core/paket.references b/src/FsAutoComplete.Core/paket.references index 6512c0971..f05099119 100644 --- a/src/FsAutoComplete.Core/paket.references +++ b/src/FsAutoComplete.Core/paket.references @@ -5,9 +5,10 @@ ICSharpCode.Decompiler Microsoft.SourceLink.GitHub System.Configuration.ConfigurationManager FSharp.UMX -FsToolkit.ErrorHandling +FsToolkit.ErrorHandling.TaskResult Fantomas.Client FSharp.Data.Adaptive +IcedTasks Ionide.ProjInfo.ProjectSystem System.Reflection.Metadata diff --git a/src/FsAutoComplete/CodeFixes.fs b/src/FsAutoComplete/CodeFixes.fs index 378b0e289..05026d058 100644 --- a/src/FsAutoComplete/CodeFixes.fs +++ b/src/FsAutoComplete/CodeFixes.fs @@ -17,18 +17,20 @@ type FcsPos = FSharp.Compiler.Text.Position module LspTypes = Ionide.LanguageServerProtocol.Types module Types = + type IsEnabled = unit -> bool - type GetRangeText = string -> LspTypes.Range -> ResultOrString - type GetFileLines = string -> ResultOrString - type GetLineText = NamedText -> LspTypes.Range -> Result + type GetRangeText = string -> LspTypes.Range -> Async> + type GetFileLines = string -> Async> + type GetLineText = NamedText -> LspTypes.Range -> Async> type GetParseResultsForFile = string -> FSharp.Compiler.Text.Position -> Async> - type GetProjectOptionsForFile = string -> ResultOrString + type GetProjectOptionsForFile = + string -> Async> [] type FixKind = @@ -48,10 +50,20 @@ module Types = type CodeAction with static member OfFix getFileVersion clientCapabilities (fix: Fix) = - let filePath = fix.File.GetFilePath() |> Utils.normalizePath - let fileVersion = getFileVersion filePath - - CodeAction.OfDiagnostic fix.File fileVersion fix.Title fix.SourceDiagnostic fix.Edits fix.Kind clientCapabilities + async { + let filePath = fix.File.GetFilePath() |> Utils.normalizePath + let! fileVersion = getFileVersion filePath + + return + CodeAction.OfDiagnostic + fix.File + fileVersion + fix.Title + fix.SourceDiagnostic + fix.Edits + fix.Kind + clientCapabilities + } static member OfDiagnostic (fileUri) diff --git a/src/FsAutoComplete/CodeFixes/ChangeDowncastToUpcast.fs b/src/FsAutoComplete/CodeFixes/ChangeDowncastToUpcast.fs index d5ae2e7b9..88442fec5 100644 --- a/src/FsAutoComplete/CodeFixes/ChangeDowncastToUpcast.fs +++ b/src/FsAutoComplete/CodeFixes/ChangeDowncastToUpcast.fs @@ -12,31 +12,35 @@ let titleUpcastFunction = "Use 'upcast' function" /// a codefix that replaces unsafe casts with safe casts let fix (getRangeText: GetRangeText) : CodeFix = Run.ifDiagnosticByCode (Set.ofList [ "3198" ]) (fun diagnostic codeActionParams -> - match getRangeText (codeActionParams.TextDocument.GetFilePath() |> Utils.normalizePath) diagnostic.Range with - | Ok expressionText -> - let isDowncastOperator = expressionText.Contains(":?>") - let isDowncastKeyword = expressionText.Contains("downcast") + async { + match! getRangeText (codeActionParams.TextDocument.GetFilePath() |> Utils.normalizePath) diagnostic.Range with + | Ok expressionText -> + let isDowncastOperator = expressionText.Contains(":?>") + let isDowncastKeyword = expressionText.Contains("downcast") - match isDowncastOperator, isDowncastKeyword with - // must be either/or here, cannot be both - | true, true -> AsyncResult.retn [] - | false, false -> AsyncResult.retn [] - | true, false -> - AsyncResult.retn - [ { File = codeActionParams.TextDocument - SourceDiagnostic = Some diagnostic - Title = titleUpcastOperator - Edits = - [| { Range = diagnostic.Range - NewText = expressionText.Replace(":?>", ":>") } |] - Kind = FixKind.Refactor } ] - | false, true -> - AsyncResult.retn - [ { File = codeActionParams.TextDocument - SourceDiagnostic = Some diagnostic - Title = titleUpcastFunction - Edits = - [| { Range = diagnostic.Range - NewText = expressionText.Replace("downcast", "upcast") } |] - Kind = FixKind.Refactor } ] - | Error _ -> AsyncResult.retn []) + match isDowncastOperator, isDowncastKeyword with + // must be either/or here, cannot be both + | true, true -> return! AsyncResult.retn [] + | false, false -> return! AsyncResult.retn [] + | true, false -> + return! + AsyncResult.retn + [ { File = codeActionParams.TextDocument + SourceDiagnostic = Some diagnostic + Title = titleUpcastOperator + Edits = + [| { Range = diagnostic.Range + NewText = expressionText.Replace(":?>", ":>") } |] + Kind = FixKind.Refactor } ] + | false, true -> + return! + AsyncResult.retn + [ { File = codeActionParams.TextDocument + SourceDiagnostic = Some diagnostic + Title = titleUpcastFunction + Edits = + [| { Range = diagnostic.Range + NewText = expressionText.Replace("downcast", "upcast") } |] + Kind = FixKind.Refactor } ] + | Error _ -> return! AsyncResult.retn [] + }) diff --git a/src/FsAutoComplete/LspHelpers.fs b/src/FsAutoComplete/LspHelpers.fs index 824dae84e..dd9c024a0 100644 --- a/src/FsAutoComplete/LspHelpers.fs +++ b/src/FsAutoComplete/LspHelpers.fs @@ -172,7 +172,7 @@ module Conversions = not keep topLevel.Nested - |> Array.choose (fun n -> if shouldKeep n then Some(map n) else None) + |> Array.Parallel.choose (fun n -> if shouldKeep n then Some(map n) else None) let getLine (lines: string[]) (pos: Lsp.Position) = lines.[pos.Line] diff --git a/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs b/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs index 6d70414f2..34bc06534 100644 --- a/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs +++ b/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs @@ -39,6 +39,7 @@ open FSharp.Compiler.CodeAnalysis open FsAutoComplete.LspHelpers open FsAutoComplete.UnionPatternMatchCaseGenerator open System.Collections.Concurrent +open System.Diagnostics [] type WorkspaceChosen = @@ -56,6 +57,8 @@ type AdaptiveWorkspaceChosen = type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FSharpLspClient) = + let logger = LogProvider.getLoggerFor () + let thisType = typeof let disposables = new Disposables.CompositeDisposable() @@ -64,9 +67,6 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let config = cval FSharpConfig.Default - - let analyzersEnabled = config |> AVal.map (fun c -> c.EnableAnalyzers) - let checker = config |> AVal.map (fun c -> c.EnableAnalyzers, c.Fsac.CachedTypeCheckCount) @@ -79,7 +79,11 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let mutable traceNotifications: ProgressListener option = None - let replaceTraceNotification shouldTrace traceNamespaces = + /// Toggles trace notifications on or off. + /// Determines if tracing should occur + /// The namespaces to start tracing + /// + let toggleTraceNotification shouldTrace traceNamespaces = traceNotifications |> Option.iter dispose if shouldTrace then @@ -87,86 +91,107 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar else traceNotifications <- None - let mutableConfigChanges = + /// Sets tje FSI arguments on the FSharpCompilerServiceChecker + /// + /// Compiler tool locations + /// Any extra parameters to pass to FSI + let setFSIArgs + (checker: FSharpCompilerServiceChecker) + (fsiCompilerToolLocations: string array) + (fsiExtraParameters: seq) + = let toCompilerToolArgument (path: string) = sprintf "--compilertool:%s" path - aval { - let! config = config - and! checker = checker - and! rootPath = rootPath + checker.SetFSIAdditionalArguments + [| yield! fsiCompilerToolLocations |> Array.map toCompilerToolArgument + yield! fsiExtraParameters |] - replaceTraceNotification config.Notifications.Trace config.Notifications.TraceNamespaces + /// Loads F# Analyzers from the configured directories + /// The FSharpConfig + /// The RootPath + /// + let loadAnalyzers (config: FSharpConfig) (rootPath: string option) = + if config.EnableAnalyzers then + Loggers.analyzers.info (Log.setMessageI $"Using analyzer roots of {config.AnalyzersPath:roots}") - checker.SetFSIAdditionalArguments - [| yield! config.FSICompilerToolLocations |> Array.map toCompilerToolArgument - yield! config.FSIExtraParameters |] + config.AnalyzersPath + |> Array.iter (fun analyzerPath -> + match rootPath with + | None -> () + | Some workspacePath -> + let dir = + if + System.IO.Path.IsPathRooted analyzerPath + // if analyzer is using absolute path, use it as is + then + analyzerPath + // otherwise, it is a relative path and should be combined with the workspace path + else + System.IO.Path.Combine(workspacePath, analyzerPath) - if config.EnableAnalyzers then - Loggers.analyzers.info ( - Log.setMessage "Using analyzer roots of {roots}" - >> Log.addContextDestructured "roots" config.AnalyzersPath - ) + Loggers.analyzers.info (Log.setMessageI $"Loading analyzers from {dir:dir}") - config.AnalyzersPath - |> Array.iter (fun analyzerPath -> - match rootPath with - | None -> () - | Some workspacePath -> - let dir = - if - System.IO.Path.IsPathRooted analyzerPath - // if analyzer is using absolute path, use it as is - then - analyzerPath - // otherwise, it is a relative path and should be combined with the workspace path - else - System.IO.Path.Combine(workspacePath, analyzerPath) + let (dllCount, analyzerCount) = dir |> FSharp.Analyzers.SDK.Client.loadAnalyzers - Loggers.analyzers.info ( - Log.setMessage "Loading analyzers from {dir}" - >> Log.addContextDestructured "dir" dir - ) + Loggers.analyzers.info ( + Log.setMessageI + $"From {analyzerPath:name}: {dllCount:dllNo} dlls including {analyzerCount:analyzersNo} analyzers" + )) - let (n, m) = dir |> FSharp.Analyzers.SDK.Client.loadAnalyzers + else + Loggers.analyzers.info (Log.setMessage "Analyzers disabled") - Loggers.analyzers.info ( - Log.setMessage "From {name}: {dllNo} dlls including {analyzersNo} analyzers" - >> Log.addContextDestructured "name" analyzerPath - >> Log.addContextDestructured "dllNo" n - >> Log.addContextDestructured "analyzersNo" m - )) + /// + /// the FSharpCompilerServiceChecker + /// The path to dotnet + /// The root path + /// + let setDotnetRoot (checker: FSharpCompilerServiceChecker) (dotnetRoot: string) (rootPath: string option) = + let di = DirectoryInfo dotnetRoot + + if di.Exists then + let dotnetBinary = + if + System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(Runtime.InteropServices.OSPlatform.Windows) + then + FileInfo(Path.Combine(di.FullName, "dotnet.exe")) + else + FileInfo(Path.Combine(di.FullName, "dotnet")) - else - Loggers.analyzers.info (Log.setMessage "Analyzers disabled") + if dotnetBinary.Exists then + checker.SetDotnetRoot(dotnetBinary, defaultArg rootPath System.Environment.CurrentDirectory |> DirectoryInfo) - let di = DirectoryInfo config.DotNetRoot + else + // if we were mistakenly given the path to a dotnet binary + // then use the parent directory as the dotnet root instead + let fi = FileInfo(di.FullName) - if di.Exists then - let dotnetBinary = - if - System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(Runtime.InteropServices.OSPlatform.Windows) - then - FileInfo(Path.Combine(di.FullName, "dotnet.exe")) - else - FileInfo(Path.Combine(di.FullName, "dotnet")) + if fi.Exists && (fi.Name = "dotnet" || fi.Name = "dotnet.exe") then + checker.SetDotnetRoot(fi, defaultArg rootPath System.Environment.CurrentDirectory |> DirectoryInfo) - if dotnetBinary.Exists then - checker.SetDotnetRoot(dotnetBinary, defaultArg rootPath System.Environment.CurrentDirectory |> DirectoryInfo) + let configChanges = + aval { + let! config = config + and! checker = checker + and! rootPath = rootPath - else - // if we were mistakenly given the path to a dotnet binary - // then use the parent directory as the dotnet root instead - let fi = FileInfo(di.FullName) + return config, checker, rootPath + } - if fi.Exists && (fi.Name = "dotnet" || fi.Name = "dotnet.exe") then - checker.SetDotnetRoot(fi, defaultArg rootPath System.Environment.CurrentDirectory |> DirectoryInfo) + // Syncs config changes to the mutable world + do + AVal.Observable.onValueChangedWeak configChanges + |> Observable.subscribe (fun (config, checker, rootPath) -> + toggleTraceNotification config.Notifications.Trace config.Notifications.TraceNamespaces - return () - } + setFSIArgs checker config.FSICompilerToolLocations config.FSIExtraParameters - let updateConfig c = - transact (fun () -> config.Value <- c) - mutableConfigChanges |> AVal.force + loadAnalyzers config rootPath + + setDotnetRoot checker config.DotNetRoot rootPath) + |> disposables.Add + + let updateConfig c = transact (fun () -> config.Value <- c) let tfmConfig = config @@ -176,14 +201,9 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar else FSIRefs.TFM.NetFx) - let logger = LogProvider.getLoggerFor () let sendDiagnostics (uri: DocumentUri) (diags: Diagnostic[]) = - logger.info ( - Log.setMessage "SendDiag for {file}: {diags} entries" - >> Log.addContextDestructured "file" uri - >> Log.addContextDestructured "diags" diags.Length - ) + logger.info (Log.setMessageI $"SendDiag for {uri:file}: {diags.Length:diags} entries") { Uri = uri; Diagnostics = diags } |> lspClient.TextDocumentPublishDiagnostics @@ -200,87 +220,148 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let fileChecked = Event() - do - disposables.Add - <| fileParsed.Publish.Subscribe(fun (parseResults, proj, ct) -> - try - logger.info ( - Log.setMessage "Test Detection of {file} started" - >> Log.addContextDestructured "file" parseResults.FileName - ) + let detectTests (parseResults: FSharpParseFileResults) (proj: FSharpProjectOptions) ct = + try + logger.info (Log.setMessageI $"Test Detection of {parseResults.FileName:file} started") - let fn = UMX.tag parseResults.FileName + let fn = UMX.tag parseResults.FileName - let res = - if proj.OtherOptions |> Seq.exists (fun o -> o.Contains "Expecto.dll") then - TestAdapter.getExpectoTests parseResults.ParseTree - elif proj.OtherOptions |> Seq.exists (fun o -> o.Contains "nunit.framework.dll") then - TestAdapter.getNUnitTest parseResults.ParseTree - elif proj.OtherOptions |> Seq.exists (fun o -> o.Contains "xunit.assert.dll") then - TestAdapter.getXUnitTest parseResults.ParseTree - else - [] + let res = + if proj.OtherOptions |> Seq.exists (fun o -> o.Contains "Expecto.dll") then + TestAdapter.getExpectoTests parseResults.ParseTree + elif proj.OtherOptions |> Seq.exists (fun o -> o.Contains "nunit.framework.dll") then + TestAdapter.getNUnitTest parseResults.ParseTree + elif proj.OtherOptions |> Seq.exists (fun o -> o.Contains "xunit.assert.dll") then + TestAdapter.getXUnitTest parseResults.ParseTree + else + [] - logger.info ( - Log.setMessage "Test Detection of {file} - {res}" - >> Log.addContextDestructured "file" parseResults.FileName - >> Log.addContextDestructured "res" res - ) + logger.info (Log.setMessageI $"Test Detection of {parseResults.FileName:file} - {res:res}") - notifications.Trigger(NotificationEvent.TestDetected(fn, res |> List.toArray), ct) - with e -> - logger.info ( - Log.setMessage "Test Detection of {file} failed - {res}" - >> Log.addContextDestructured "file" parseResults.FileName - >> Log.addException e - )) + notifications.Trigger(NotificationEvent.TestDetected(fn, res |> List.toArray), ct) + with e -> + logger.info ( + Log.setMessageI $"Test Detection of {parseResults.FileName:file} failed" + >> Log.addExn e + ) do disposables.Add - <| fileChecked.Publish.Subscribe(fun (parseAndCheck, volatileFile, ct) -> + <| fileParsed.Publish.Subscribe(fun (parseResults, proj, ct) -> detectTests parseResults proj ct) + + let builtInCompilerAnalyzers config (file: VolatileFile) (tyRes: ParseAndCheckResults) = + let filePath = file.FileName + let source = file.Lines + let version = file.Version + + let checkUnusedOpens = async { - if analyzersEnabled |> AVal.force then - let file = volatileFile.FileName + try + let! ct = Async.CancellationToken - try - Loggers.analyzers.info ( - Log.setMessage "begin analysis of {file}" - >> Log.addContextDestructured "file" file - ) + let! unused = + UnusedOpens.getUnusedOpens (tyRes.GetCheckResults, (fun i -> (source: ISourceText).GetLineString(i - 1))) - match parseAndCheck.GetCheckResults.ImplementationFile with - | Some tast -> - - let res = - Commands.analyzerHandler ( - file, - volatileFile.Lines.ToString().Split("\n"), - parseAndCheck.GetParseResults.ParseTree, - tast, - parseAndCheck.GetCheckResults.PartialAssemblySignature.Entities |> Seq.toList, - parseAndCheck.GetAllEntities - ) + notifications.Trigger(NotificationEvent.UnusedOpens(filePath, (unused |> List.toArray)), ct) + with e -> + logger.error (Log.setMessage "checkUnusedOpens failed" >> Log.addExn e) + } - notifications.Trigger(NotificationEvent.AnalyzerMessage(res, file), ct) + let checkUnusedDeclarations = + async { + try + let! ct = Async.CancellationToken + let isScript = Utils.isAScript (UMX.untag filePath) + let! unused = UnusedDeclarations.getUnusedDeclarations (tyRes.GetCheckResults, isScript) + let unused = unused |> Seq.toArray - Loggers.analyzers.info ( - Log.setMessage "end analysis of {file}" - >> Log.addContextDestructured "file" file - ) + notifications.Trigger(NotificationEvent.UnusedDeclarations(filePath, unused), ct) + with e -> + logger.error (Log.setMessage "checkUnusedDeclarations failed" >> Log.addExn e) + } - | _ -> - Loggers.analyzers.info ( - Log.setMessage "missing components of {file} to run analyzers, skipped them" - >> Log.addContextDestructured "file" file + let checkSimplifiedNames = + async { + try + let getSourceLine lineNo = + (source: ISourceText).GetLineString(lineNo - 1) + + let! ct = Async.CancellationToken + let! simplified = SimplifyNames.getSimplifiableNames (tyRes.GetCheckResults, getSourceLine) + let simplified = Array.ofSeq simplified + notifications.Trigger(NotificationEvent.SimplifyNames(filePath, simplified), ct) + with e -> + logger.error (Log.setMessage "checkSimplifiedNames failed" >> Log.addExn e) + } + + let analyzers = + [ + // if config.Linter then + // commands.Lint filePath |> Async .Ignore + if config.UnusedOpensAnalyzer then + checkUnusedOpens + if config.UnusedDeclarationsAnalyzer then + checkUnusedDeclarations + if config.SimplifyNameAnalyzer then + checkSimplifiedNames ] + + async { + do! analyzers |> Async.parallel75 |> Async.Ignore + + do! + lspClient.NotifyDocumentAnalyzed + { TextDocument = + { Uri = filePath |> Path.LocalPathToUri + Version = version } } + } + + + let runAnalyzers (config: FSharpConfig) (parseAndCheck: ParseAndCheckResults) (volatileFile: VolatileFile) = + async { + if config.EnableAnalyzers then + let file = volatileFile.FileName + + try + Loggers.analyzers.info ( + Log.setMessage "begin analysis of {file}" + >> Log.addContextDestructured "file" file + ) + + match parseAndCheck.GetCheckResults.ImplementationFile with + | Some tast -> + do! Async.SwitchToNewThread() + + let res = + Commands.analyzerHandler ( + file, + volatileFile.Lines.ToString().Split("\n"), + parseAndCheck.GetParseResults.ParseTree, + tast, + parseAndCheck.GetCheckResults.PartialAssemblySignature.Entities |> Seq.toList, + parseAndCheck.GetAllEntities ) - () - with ex -> - Loggers.analyzers.error ( - Log.setMessage "Run failed for {file}" - >> Log.addContextDestructured "file" file - >> Log.addExn ex - ) + let! ct = Async.CancellationToken + notifications.Trigger(NotificationEvent.AnalyzerMessage(res, file), ct) + + Loggers.analyzers.info (Log.setMessageI $"end analysis of {file:file}") + + | _ -> + Loggers.analyzers.info (Log.setMessageI $"missing components of {file:file} to run analyzers, skipped them") + + () + with ex -> + Loggers.analyzers.error (Log.setMessageI $"Run failed for {file:file}" >> Log.addExn ex) + } + + do + disposables.Add + <| fileChecked.Publish.Subscribe(fun (parseAndCheck, volatileFile, ct) -> + async { + let config = config |> AVal.force + do! builtInCompilerAnalyzers config volatileFile parseAndCheck + do! runAnalyzers config parseAndCheck volatileFile + } |> Async.StartWithCT ct) @@ -288,6 +369,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let handleCommandEvents (n: NotificationEvent, ct: CancellationToken) = try async { + try match n with | NotificationEvent.FileParsed fn -> @@ -498,7 +580,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar |> AVal.map (fun writeTime -> filePath, writeTime) let addAValLogging cb (aval: aval<_>) = - let cb = aval.AddMarkingCallback(cb) + let cb = aval.AddWeakMarkingCallback(cb) aval |> AVal.mapDisposableTuple (fun x -> x, cb) let projectFileChanges project (filePath: string) = @@ -511,14 +593,12 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let loader = cval workspaceLoader - - let binlogConfig = aval { - let! config = config + let! generateBinLog = config |> AVal.map (fun c -> c.GenerateBinlog) and! rootPath = rootPath - match config.GenerateBinlog, rootPath with + match generateBinLog, rootPath with | _, None | false, _ -> return Ionide.ProjInfo.BinaryLogGeneration.Off | true, Some rootPath -> @@ -716,10 +796,10 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar do // Reload Projects with some debouncing if `loadedProjectOptions` is out of date. - AVal.Observable.onWeakMarking loadedProjectOptions + AVal.Observable.onOutOfDateWeak loadedProjectOptions |> Observable.throttleOn Concurrency.NewThreadScheduler.Default (TimeSpan.FromMilliseconds(200.)) |> Observable.observeOn Concurrency.NewThreadScheduler.Default - |> Observable.subscribe (forceLoadProjects >> ignore) + |> Observable.subscribe (fun _ -> forceLoadProjects () |> ignore>) |> disposables.Add @@ -765,10 +845,6 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar >> Log.addContextDestructured "version" v.Version ) - let tee f x = - f x - x - let openFilesWithChanges: amap<_, aval> = openFilesReadOnly |> AMap.map (fun filePath file -> @@ -827,7 +903,8 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar text) - return (file) |> tee logTextChange + logTextChange file + return file }) @@ -856,7 +933,8 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar cancelToken filePath value new CancellationTokenSource() - openFilesTokens.AddOrUpdate(filePath, adder, updater) |> ignore + openFilesTokens.AddOrUpdate(filePath, adder, updater) + |> ignore let updateOpenFiles (file: VolatileFile) = @@ -869,7 +947,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let updateTextchanges filePath p = let adder _ = cset<_> [ p ] - let updater _ (v: cset<_>) = v.Add p |> ignore + let updater _ (v: cset<_>) = v.Add p |> ignore resetCancellationToken filePath transact (fun () -> textChanges.AddOrElse(filePath, adder, updater)) @@ -877,121 +955,127 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let isFileOpen file = openFiles |> AMap.tryFindA file |> AVal.map (Option.isSome) - let findFileInOpenFiles' file = + let findFileInOpenFiles file = openFilesWithChanges |> AMap.tryFindA file - let findFileInOpenFiles file = findFileInOpenFiles' file - let forceFindOpenFile filePath = findFileInOpenFiles filePath |> AVal.force let forceFindOpenFileOrRead file = - findFileInOpenFiles file - |> AVal.force - |> Option.orElseWith (fun () -> - // TODO: Log how many times this kind area gets hit and possibly if this should be rethought - try - logger.info ( - Log.setMessage "forceFindOpenFileOrRead else - {file}" - >> Log.addContextDestructured "file" file - ) - - let untagged = UMX.untag file + asyncOption { - if File.Exists untagged && isFileWithFSharp untagged then - let change = File.ReadAllText untagged - - let lastWriteTime = File.GetLastWriteTimeUtc untagged + match findFileInOpenFiles file |> AVal.force with + | Some s -> return s + | None -> + // TODO: Log how many times this kind area gets hit and possibly if this should be rethought + try + logger.debug ( + Log.setMessage "forceFindOpenFileOrRead else - {file}" + >> Log.addContextDestructured "file" file + ) - let file = - { Touched = lastWriteTime - Lines = NamedText(file, change) - Version = None } + let untagged = UMX.untag file - Some file - else - None - with e -> - logger.warn ( - Log.setMessage "Could not read file {file}" - >> Log.addContextDestructured "file" file - >> Log.addExn e - ) + if File.Exists untagged && isFileWithFSharp untagged then + let! change = File.ReadAllTextAsync untagged |> Async.AwaitTask + let lastWriteTime = File.GetLastWriteTimeUtc untagged - None) - |> Result.ofOption (fun () -> $"Could not read file: {file}") + let file = + { Touched = lastWriteTime + Lines = NamedText(file, change) + Version = None } + return file + else + return! None + with e -> + logger.warn ( + Log.setMessage "Could not read file {file}" + >> Log.addContextDestructured "file" file + >> Log.addExn e + ) + return! None + } + |> Async.map (Result.ofOption (fun () -> $"Could not read file: {file}")) do + let fileshimChanges = openFilesWithChanges |> AMap.mapA (fun _ v -> v) + let filesystemShim file = // GetLastWriteTimeShim gets called _alot_ and when we do checks on save we use Async.Parallel for type checking. // Adaptive uses lots of locks under the covers, so many threads can get blocked waiting for data. - // We know we don't store anything other than Fsharp type files in open files so this so we shouldn't hit any locks - // when F# compiler asks for DLL timestamps - if Utils.isFileWithFSharp %file then - forceFindOpenFile file - else - None + // flattening openFilesWithChanges makes this check a lot quicker as it's not needing to recalculate each value. + fileshimChanges |> AMap.force |> HashMap.tryFind file FSharp.Compiler.IO.FileSystemAutoOpens.FileSystem <- FileSystem(FSharp.Compiler.IO.FileSystemAutoOpens.FileSystem, filesystemShim) + /// Parses a source code for a file and caches the results. Returns an AST that can be traversed for various features. + /// The FSharpCompilerServiceChecker. + /// The source to be parsed. + /// Parsing options for the project or script + /// The options for the project or script. + /// + let parseFile (checker: FSharpCompilerServiceChecker) (source: VolatileFile) parseOpts options = + async { + let! result = checker.ParseFile(source.FileName, source.Lines, parseOpts) + + let! ct = Async.CancellationToken + fileParsed.Trigger(result, options, ct) + return result + } + + /// Parses all files in the workspace. This is mostly used to trigger finding tests. let parseAllFiles () = - aval { + asyncAVal { let! projects = loadedProjectOptions - and! checker = checker + and! (checker: FSharpCompilerServiceChecker) = checker return projects |> Array.ofList |> Array.Parallel.collect (fun p -> let parseOpts = Utils.projectOptionsToParseOptions p - p.SourceFiles |> Array.map (fun s -> p, parseOpts, s)) - |> Array.Parallel.choose (fun (opts, parseOpts, fileName) -> + p.SourceFiles |> Array.Parallel.map (fun s -> p, parseOpts, s)) + |> Array.Parallel.map (fun (opts, parseOpts, fileName) -> let fileName = UMX.tag fileName - let file = forceFindOpenFileOrRead fileName - file - |> Result.toOption - |> Option.map (fun file -> - async { - let! parseResult = checker.ParseFile(fileName, file.Lines, parseOpts) - let! ct = Async.CancellationToken - fileParsed.Trigger(parseResult, opts, ct) - return parseResult - })) + asyncResult { + let! file = forceFindOpenFileOrRead fileName + return! parseFile checker file parseOpts opts + } + |> Async.map Result.toOption) |> Async.parallel75 - } let forceFindSourceText filePath = - forceFindOpenFileOrRead filePath |> Result.map (fun f -> f.Lines) + forceFindOpenFileOrRead filePath |> AsyncResult.map (fun f -> f.Lines) let openFilesToChangesAndProjectOptions = openFilesWithChanges - |> AMap.mapAVal (fun filePath file -> - aval { + |> AMapAsync.mapAVal (fun filePath file ctok -> + asyncAVal { if Utils.isAScript (UMX.untag filePath) then - let! checker = checker + let! (checker: FSharpCompilerServiceChecker) = checker and! tfmConfig = tfmConfig - let projs = - option { + let! projs = + taskOption { let! cts = tryGetOpenFileToken filePath let! opts = checker.GetProjectOptionsFromScript(filePath, file.Lines, tfmConfig) - |> Async.RunSynchronouslyWithCTSafe(fun () -> cts.Token) + |> Async.withCancellation cts.Token + |> Async.startImmediateAsTask ctok opts |> scriptFileProjectOptions.Trigger return opts } - |> Option.toList - return file, projs + return file, Option.toList projs else let! projs = sourceFileToProjectOptions @@ -1003,18 +1087,29 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let allProjectOptions = let wins = - openFilesToChangesAndProjectOptions |> AMap.map (fun k v -> v |> AVal.map snd) + openFilesToChangesAndProjectOptions + |> AMap.map (fun k v -> v |> AsyncAVal.mapSync (fun d _ -> snd d)) - let loses = sourceFileToProjectOptions |> AMap.map (fun k v -> AVal.constant v) + let loses = sourceFileToProjectOptions |> AMap.map (fun k v -> AsyncAVal.constant v) AMap.union loses wins - let allProjectOptions' = - allProjectOptions |> AMap.toASetValues |> ASet.collect (ASet.ofAVal) + let getAllProjectOptions () = + async { + let! set = + allProjectOptions + |> AMap.toASetValues + |> ASet.force + |> HashSet.toArray + |> Array.map (AsyncAVal.forceAsync) + |> Async.parallel75 + + return set |> Array.collect (List.toArray) + } let getProjectOptionsForFile (filePath: string) = - aval { - match! allProjectOptions |> AMap.tryFindA filePath with + asyncAVal { + match! allProjectOptions |> AMapAsync.tryFindA filePath with | Some projs -> return projs | None -> return [] } @@ -1038,75 +1133,14 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let getAutoCompleteNamespacesByDeclName name = autoCompleteNamespaces |> AMap.tryFind name - let analyzeFile config (filePath: string, version, source, tyRes: ParseAndCheckResults) = - let checkUnusedOpens = - async { - try - let! ct = Async.CancellationToken - - let! unused = - UnusedOpens.getUnusedOpens (tyRes.GetCheckResults, (fun i -> (source: ISourceText).GetLineString(i - 1))) - - notifications.Trigger(NotificationEvent.UnusedOpens(filePath, (unused |> List.toArray)), ct) - with e -> - logger.error (Log.setMessage "checkUnusedOpens failed" >> Log.addExn e) - } - - let checkUnusedDeclarations = - async { - try - let! ct = Async.CancellationToken - let isScript = Utils.isAScript (UMX.untag filePath) - let! unused = UnusedDeclarations.getUnusedDeclarations (tyRes.GetCheckResults, isScript) - let unused = unused |> Seq.toArray - - notifications.Trigger(NotificationEvent.UnusedDeclarations(filePath, unused), ct) - with e -> - logger.error (Log.setMessage "checkUnusedDeclarations failed" >> Log.addExn e) - } - - let checkSimplifiedNames = - async { - try - let getSourceLine lineNo = source.GetLineString(lineNo - 1) - - let! ct = Async.CancellationToken - let! simplified = SimplifyNames.getSimplifiableNames (tyRes.GetCheckResults, getSourceLine) - let simplified = Array.ofSeq simplified - notifications.Trigger(NotificationEvent.SimplifyNames(filePath, simplified), ct) - with e -> - logger.error (Log.setMessage "checkSimplifiedNames failed" >> Log.addExn e) - } - - let analyzers = - [ - // if config.Linter then - // commands.Lint filePath |> Async .Ignore - if config.UnusedOpensAnalyzer then - checkUnusedOpens - if config.UnusedDeclarationsAnalyzer then - checkUnusedDeclarations - if config.SimplifyNameAnalyzer then - checkSimplifiedNames ] - - async { - do! analyzers |> Async.Parallel |> Async.Ignore - - do! - lspClient.NotifyDocumentAnalyzed - { TextDocument = - { Uri = filePath |> Path.LocalPathToUri - Version = version } } - } /// Gets Parse and Check results of a given file while also handling other concerns like Progress, Logging, Eventing. /// The FSharpCompilerServiceChecker. /// The name of the file in the project whose source to find a typecheck. /// The options for the project or script. - /// The FSharpConfig. /// Determines if the typecheck should be cached for autocompletions. /// - let parseAndCheckFile (checker: FSharpCompilerServiceChecker) (file: VolatileFile) options config shouldCache = + let parseAndCheckFile (checker: FSharpCompilerServiceChecker) (file: VolatileFile) options shouldCache = async { let tags = [ SemanticConventions.fsac_sourceCodePath, box (UMX.untag file.Lines.FileName) @@ -1176,7 +1210,6 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ct ) - Async.Start(analyzeFile config (file.Lines.FileName, file.Version, file.Lines, parseAndCheck), ct) return parseAndCheck } @@ -1191,11 +1224,10 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let checker = checker |> AVal.force - let config = config |> AVal.force - match forceFindOpenFileOrRead filePath with + match! forceFindOpenFileOrRead filePath with // Don't cache for autocompletions as we really only want to cache "Opened" files. - | Ok(fileInfo) -> return! parseAndCheckFile checker fileInfo opts config false |> Async.Ignore + | Ok(fileInfo) -> return! parseAndCheckFile checker fileInfo opts false |> Async.Ignore | _ -> () with e -> @@ -1208,33 +1240,30 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let openFilesToParsedResults = openFilesToChangesAndProjectOptions - |> AMap.mapAVal (fun _ (info, projectOptions) -> - aval { + |> AMapAsync.mapAsyncAVal (fun _ (info, projectOptions) ctok -> + asyncAVal { let file = info.Lines.FileName let! checker = checker - return - option { + return! + taskOption { let! opts = selectProject projectOptions and! cts = tryGetOpenFileToken file let parseOpts = Utils.projectOptionsToParseOptions opts - let! result = - checker.ParseFile(file, info.Lines, parseOpts) - |> Async.RunSynchronouslyWithCTSafe(fun () -> cts.Token) - - fileParsed.Trigger(result, opts, cts.Token) - return result + return! + parseFile checker info parseOpts opts + |> Async.withCancellation cts.Token + |> Async.startImmediateAsTask ctok } - }) let openFilesToRecentCheckedFilesResults = openFilesToChangesAndProjectOptions - |> AMap.mapAVal (fun _ (info, projectOptions) -> - aval { + |> AMapAsync.mapAsyncAVal (fun _ (info, projectOptions) _ -> + asyncAVal { let file = info.Lines.FileName let! checker = checker @@ -1247,53 +1276,54 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let openFilesToCheckedFilesResults = openFilesToChangesAndProjectOptions - |> AMap.mapAVal (fun _ (info, projectOptions) -> - aval { + |> AMapAsync.mapAsyncAVal (fun _ (info, projectOptions) ctok -> + asyncAVal { let file = info.Lines.FileName let! checker = checker - and! config = config - return - option { + return! + taskOption { let! opts = selectProject projectOptions and! cts = tryGetOpenFileToken file return! - Debug.measure $"parseAndCheckFile - {file}" - <| fun () -> - parseAndCheckFile checker info opts config true - |> Async.RunSynchronouslyWithCTSafe(fun () -> cts.Token) + parseAndCheckFile checker info opts true + |> Async.withCancellation cts.Token + |> fun work -> Async.StartImmediateAsTask(work, ctok) } }) let getParseResults filePath = - openFilesToParsedResults |> AMap.tryFindAndFlatten filePath + openFilesToParsedResults |> AMapAsync.tryFindAndFlatten filePath let getTypeCheckResults filePath = - openFilesToCheckedFilesResults |> AMap.tryFindAndFlatten (filePath) + openFilesToCheckedFilesResults |> AMapAsync.tryFindAndFlatten (filePath) let getRecentTypeCheckResults filePath = - openFilesToRecentCheckedFilesResults |> AMap.tryFindAndFlatten (filePath) + openFilesToRecentCheckedFilesResults |> AMapAsync.tryFindAndFlatten (filePath) let tryGetLineStr pos (text: NamedText) = text.GetLine(pos) |> Result.ofOption (fun () -> $"No line in {text.FileName} at position {pos}") let forceGetParseResults filePath = - getParseResults filePath - |> AVal.force - |> Result.ofOption (fun () -> $"No parse results for {filePath}") + async { + let! results = getParseResults filePath |> AsyncAVal.forceAsync + return results |> Result.ofOption (fun () -> $"No parse results for {filePath}") + } let forceGetRecentTypeCheckResults filePath = - getRecentTypeCheckResults filePath - |> AVal.force - |> Result.ofOption (fun () -> $"No typecheck results for {filePath}") + async { + let! results = getRecentTypeCheckResults filePath |> AsyncAVal.forceAsync + return results |> Result.ofOption (fun () -> $"No typecheck results for {filePath}") + } let forceGetTypeCheckResults (filePath: string) = - getTypeCheckResults (filePath) - |> AVal.force - |> Result.ofOption (fun () -> $"No typecheck results for {filePath}") + async { + let! results = getTypeCheckResults (filePath) |> AsyncAVal.forceAsync + return results |> Result.ofOption (fun () -> $"No typecheck results for {filePath}") + } /// /// This will attempt to get typecheck results in this order @@ -1307,50 +1337,85 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar /// The name of the file in the project whose source to find a typecheck. /// A Result of ParseAndCheckResults let forceGetTypeCheckResultsStale (filePath: string) = - aval { - let! checker = checker + asyncAVal { + let! (checker: FSharpCompilerServiceChecker) = checker let inline tryGetLastCheckResultForFile filePath = checker.TryGetLastCheckResultForFile(filePath) |> Result.ofOption (fun () -> $"No typecheck results for {filePath}") + |> async.Return return tryGetLastCheckResultForFile filePath - |> Result.orElseWith (fun _ -> forceGetRecentTypeCheckResults filePath) - |> Result.orElseWith (fun _ -> forceGetTypeCheckResults filePath) - |> Result.tee (fun _ -> Async.Start(async { forceGetTypeCheckResults filePath |> ignore })) + |> AsyncResult.orElseWith (fun _ -> forceGetRecentTypeCheckResults filePath) + |> AsyncResult.orElseWith (fun _ -> forceGetTypeCheckResults filePath) + |> Async.map (fun r -> + Async.Start( + async { + // This needs to be in a try catch as it can throw on cancellation which causes the server to crash + try + do! + forceGetTypeCheckResults filePath + |> Async.Ignore> + with e -> + () + } + ) + + r) } - |> AVal.force + |> AsyncAVal.forceAsync let openFilesToCheckedDeclarations = openFilesToCheckedFilesResults |> AMap.map (fun k v -> v - |> AVal.mapOption (fun c -> c.GetParseResults.GetNavigationItems().Declarations)) + |> AsyncAVal.mapOption (fun c _ -> c.GetParseResults.GetNavigationItems().Declarations)) let getAllDeclarations () = - openFilesToCheckedDeclarations |> AMap.chooseA (fun k v -> v) |> AMap.force + async { + let! results = + openFilesToCheckedDeclarations + |> AMap.force + |> HashMap.toArray + |> Array.map (fun (k, v) -> + async { + let! decls = AsyncAVal.forceAsync v + return Option.map (fun v -> k, v) decls + }) + |> Async.parallel75 + + return results |> Array.Parallel.choose id + + } let getDeclarations filename = - openFilesToCheckedDeclarations |> AMap.tryFindAndFlatten filename + openFilesToCheckedDeclarations |> AMapAsync.tryFindAndFlatten filename let getFilePathAndPosition (p: ITextDocumentPositionParams) = let filePath = p.GetFilePath() |> Utils.normalizePath let pos = p.GetFcsPos() filePath, pos + let forceGetProjectOptions filePath = - getProjectOptionsForFile filePath - |> AVal.force - |> selectProject - |> Result.ofOption (fun () -> $"Could not find project containing {filePath}") + asyncAVal { + let! projects = getProjectOptionsForFile filePath + let project = selectProject projects + + return + project + |> Result.ofOption (fun () -> $"Could not find project containing {filePath}") + + } + |> AsyncAVal.forceAsync let codeGenServer = { new ICodeGenerationService with member x.TokenizeLine(file, i) = - option { - let! (text) = forceFindOpenFileOrRead file |> Option.ofResult + asyncOption { + let! (text) = forceFindOpenFileOrRead file |> Async.map Option.ofResult try let! line = text.Lines.GetLine(Position.mkPos i 0) @@ -1360,9 +1425,9 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar } member x.GetSymbolAtPosition(file, pos) = - option { + asyncOption { try - let! (text) = forceFindOpenFileOrRead file |> Option.ofResult + let! (text) = forceFindOpenFileOrRead file |> Async.map Option.ofResult let! line = tryGetLineStr pos text.Lines |> Option.ofResult return! Lexer.getSymbol pos.Line pos.Column line SymbolLookupKind.Fuzzy [||] with _ -> @@ -1374,9 +1439,9 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let! symbol = x.GetSymbolAtPosition(fileName, pos) if symbol.Kind = kind then - let! (text) = forceFindOpenFileOrRead fileName |> Option.ofResult + let! (text) = forceFindOpenFileOrRead fileName |> Async.map Option.ofResult let! line = tryGetLineStr pos text.Lines |> Option.ofResult - let! tyRes = forceGetTypeCheckResults fileName |> Option.ofResult + let! tyRes = forceGetTypeCheckResults fileName |> Async.map (Option.ofResult) let symbolUse = tyRes.TryGetSymbolUse pos line return! Some(symbol, symbolUse) else @@ -1384,7 +1449,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar } member x.ParseFileInProject(file) = - forceGetParseResults file |> Option.ofResult } + forceGetParseResults file |> Async.map (Option.ofResult) } let getDependentProjectsOfProjects ps = let projectSnapshot = forceLoadProjects () @@ -1420,10 +1485,10 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let getDeclarationLocation (symbolUse, text) = let getProjectOptions file = - getProjectOptionsForFile file |> AVal.force |> selectProject + getProjectOptionsForFile file |> AsyncAVal.forceAsync |> Async.map selectProject let projectsThatContainFile file = - getProjectOptionsForFile file |> AVal.force + getProjectOptionsForFile file |> AsyncAVal.forceAsync SymbolLocation.getDeclarationLocation ( symbolUse, @@ -1452,7 +1517,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return! checker.FindReferencesForSymbolInFile(UMX.untag file, project, symbol) else // untitled script files - match forceGetRecentTypeCheckResults file with + match! forceGetTypeCheckResultsStale file with | Error _ -> return [||] | Ok tyRes -> let! ct = Async.CancellationToken @@ -1461,17 +1526,14 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar } let tryGetProjectOptionsForFsproj (file: string) = - forceGetProjectOptions file |> Option.ofResult - - let getAllProjectOptions () : _ seq = - allProjectOptions'.Content |> AVal.force :> _ + forceGetProjectOptions file |> Async.map Option.ofResult Commands.symbolUseWorkspace getDeclarationLocation findReferencesForSymbolInFile forceFindSourceText tryGetProjectOptionsForFsproj - getAllProjectOptions + (getAllProjectOptions >> Async.map Array.toSeq) includeDeclarations includeBackticks errorOnFailureToFixRange @@ -1493,8 +1555,10 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar } let getRangeText fileName (range: Ionide.LanguageServerProtocol.Types.Range) = - getFileLines fileName - |> Result.bind (fun lines -> lines.GetText(protocolRangeToRange (UMX.untag fileName) range)) + asyncResult { + let! lines = getFileLines fileName + return! lines.GetText(protocolRangeToRange (UMX.untag fileName) range) + } let tryFindUnionDefinitionFromPos = tryFindUnionDefinitionFromPos codeGenServer @@ -1521,6 +1585,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let getLineText (lines: NamedText) (range: Ionide.LanguageServerProtocol.Types.Range) = lines.GetText(protocolRangeToRange (UMX.untag lines.FileName) range) + |> Async.singleton let abstractClassStubReplacements config () = Map.ofList @@ -1606,106 +1671,113 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar RenameParamToMatchSignature.fix tryGetParseResultsForFile |]) let forgetDocument (uri: DocumentUri) = - let filePath = uri |> Path.FileUriToLocalPath |> Utils.normalizePath + async { + let filePath = uri |> Path.FileUriToLocalPath |> Utils.normalizePath - let doesNotExist (file: string) = not (File.Exists(UMX.untag file)) + let doesNotExist (file: string) = not (File.Exists(UMX.untag file)) - let isOutsideWorkspace (file: string) = - aval { - let! rootPath = rootPath + let isOutsideWorkspace (file: string) = + asyncAVal { + let! rootPath = rootPath - match rootPath with - | None -> return true // no root workspace specified - | Some rootPath -> - let rec isInside (rootDir: DirectoryInfo, dirToCheck: DirectoryInfo) = - if String.Equals(rootDir.FullName, dirToCheck.FullName, StringComparison.InvariantCultureIgnoreCase) then - true - else - match dirToCheck.Parent with - | null -> false - | parent -> isInside (rootDir, parent) + match rootPath with + | None -> return true // no root workspace specified + | Some rootPath -> + let rec isInside (rootDir: DirectoryInfo, dirToCheck: DirectoryInfo) = + if String.Equals(rootDir.FullName, dirToCheck.FullName, StringComparison.InvariantCultureIgnoreCase) then + true + else + match dirToCheck.Parent with + | null -> false + | parent -> isInside (rootDir, parent) - let rootDir = DirectoryInfo(rootPath) - let fileDir = FileInfo(UMX.untag file).Directory + let rootDir = DirectoryInfo(rootPath) + let fileDir = FileInfo(UMX.untag file).Directory - if isInside (rootDir, fileDir) then - return false - else - let! projectOptions = getProjectOptionsForFile file + if isInside (rootDir, fileDir) then + return false + else + let! projectOptions = getProjectOptionsForFile file + + match projectOptions |> selectProject with + | None -> return true + | Some projectOptions -> + if doesNotExist (UMX.tag projectOptions.ProjectFileName) then + return true // script file + else + // issue: fs-file does never get removed from project options (-> requires reload of FSAC to register) + // -> don't know if file still part of project (file might have been removed from project) + // -> keep cache for file + return false + } - match projectOptions |> selectProject with - | None -> return true - | Some projectOptions -> - if doesNotExist (UMX.tag projectOptions.ProjectFileName) then - return true // script file - else - // issue: fs-file does never get removed from project options (-> requires reload of FSAC to register) - // -> don't know if file still part of project (file might have been removed from project) - // -> keep cache for file - return false - } + |> AsyncAVal.forceAsync - |> AVal.force + transact (fun () -> + openFiles.Remove filePath |> ignore - transact (fun () -> - openFiles.Remove filePath |> ignore + match openFilesTokens.TryRemove(filePath) with + | (true, cts) -> cancelToken filePath cts + | _ -> () - match openFilesTokens.TryRemove(filePath) with - | (true, cts) -> cancelToken filePath cts - | _ -> () + textChanges.Remove filePath |> ignore) - textChanges.Remove filePath |> ignore) + let! isOutsideWorkspace = isOutsideWorkspace filePath - if doesNotExist filePath || isOutsideWorkspace filePath then - logger.info ( - Log.setMessage "Removing cached data for {file}." - >> Log.addContext "file" filePath - ) + if doesNotExist filePath || isOutsideWorkspace then + logger.info ( + Log.setMessage "Removing cached data for {file}." + >> Log.addContext "file" filePath + ) + + diagnosticCollections.ClearFor(uri) + else + logger.info ( + Log.setMessage "File {file} exists inside workspace so diagnostics will not be cleared" + >> Log.addContext "file" filePath + ) + } - diagnosticCollections.ClearFor(uri) - else - logger.info ( - Log.setMessage "File {file} exists inside workspace so diagnostics will not be cleared" - >> Log.addContext "file" filePath - ) let getDependentFilesForFile file = - let projects = getProjectOptionsForFile file |> AVal.force + async { + let! projects = getProjectOptionsForFile file |> AsyncAVal.forceAsync - projects - |> List.toArray - |> Array.collect (fun proj -> - logger.info ( - Log.setMessage "Source Files: {sourceFiles}" - >> Log.addContextDestructured "sourceFiles" proj.SourceFiles - ) + return + projects + |> List.toArray + |> Array.collect (fun proj -> + logger.info ( + Log.setMessage "Source Files: {sourceFiles}" + >> Log.addContextDestructured "sourceFiles" proj.SourceFiles + ) - let idx = proj.SourceFiles |> Array.findIndex (fun x -> x = UMX.untag file) + let idx = proj.SourceFiles |> Array.findIndex (fun x -> x = UMX.untag file) - proj.SourceFiles - |> Array.splitAt idx - |> snd - |> Array.map (fun sourceFile -> proj, sourceFile)) - |> Array.distinct + proj.SourceFiles + |> Array.splitAt idx + |> snd + |> Array.map (fun sourceFile -> proj, sourceFile)) + |> Array.distinct + } let bypassAdaptiveAndCheckDepenenciesForFile (filePath: string) = async { let tags = [ SemanticConventions.fsac_sourceCodePath, box (UMX.untag filePath) ] use _ = fsacActivitySource.StartActivityForType(thisType, tags = tags) - let dependentFiles = getDependentFilesForFile filePath + let! dependentFiles = getDependentFilesForFile filePath + + let! projs = getProjectOptionsForFile filePath |> AsyncAVal.forceAsync let dependentProjects = - getProjectOptionsForFile filePath - |> AVal.force + projs |> getDependentProjectsOfProjects |> List.toArray |> Array.collect (fun proj -> proj.SourceFiles |> Array.map (fun sourceFile -> proj, sourceFile)) let mutable checksCompleted = 0 - let progressToken = ProgressToken.Second(Guid.NewGuid().ToString()) - do! lspClient.WorkDoneProgressCreate progressToken |> Async.Ignore use progressReporter = new ServerProgressReport(lspClient) let percentage numerator denominator = @@ -1737,7 +1809,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar |> Async.Ignore |> Async.bind (fun _ -> async { - Interlocked.Increment(&checksCompleted) |> ignore + let checksCompleted = Interlocked.Increment(&checksCompleted) do! progressReporter.Report( @@ -1754,20 +1826,15 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar percentage = percentage 0 checksToPerform.Length ) - let maxConcurrency = - Math.Max(1.0, Math.Floor((float System.Environment.ProcessorCount) * 0.75)) - do! checksToPerform |> Async.parallel75 |> Async.Ignore } + member private x.handleSemanticTokens (filePath: string) range : AsyncLspResult = + asyncResult { - - member private x.handleSemanticTokens (filePath: string) range : LspResult = - result { - - let! tyRes = forceGetTypeCheckResults filePath |> Result.ofStringErr + let! tyRes = forceGetTypeCheckResults filePath |> AsyncResult.ofStringErr let r = tyRes.GetCheckResults.GetSemanticClassification(range) let filteredRanges = Commands.scrubRanges r @@ -1925,7 +1992,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return! LspResult.internalError "Fantomas install not found." | (FormatDocumentResponse.Error ex) -> return! LspResult.internalError ex with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error (Log.setMessage "HandleFormatting Request Errored {p}" >> Log.addExn e) return! LspResult.internalError (string e) } @@ -2025,7 +2092,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar Capabilities = defaultSettings } with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "Initialize Request Errored {p}" @@ -2043,11 +2110,11 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar try logger.info (Log.setMessage "Initialized request {p}" >> Log.addContextDestructured "p" p) - let! _ = parseAllFiles () |> AVal.force + let! _ = parseAllFiles () |> AsyncAVal.forceAsync return () with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "Initialized Request Errored {p}" @@ -2060,12 +2127,10 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar override __.TextDocumentDidOpen(p: DidOpenTextDocumentParams) = async { - let tags = [ "InitializedParams", box p ] + let tags = [ "DidOpenTextDocumentParams", box p ] use trace = fsacActivitySource.StartActivityForType(thisType, tags = tags) try - trace.SetTagSafe("DidOpenTextDocumentParams", p) |> ignore - logger.info ( Log.setMessage "TextDocumentDidOpen Request: {parms}" >> Log.addContextDestructured "parms" p @@ -2080,10 +2145,10 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar // We want to try to use the file system's datetime if available let file = VolatileFile.Create(filePath, doc.Text, (Some doc.Version)) updateOpenFiles file - forceGetTypeCheckResults filePath |> ignore + let! _ = forceGetTypeCheckResults filePath return () with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentDidOpen Request Errored {p}" @@ -2106,11 +2171,11 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let doc = p.TextDocument - forgetDocument doc.Uri + do! forgetDocument doc.Uri return () with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentDidClose Request Errored {p}" @@ -2137,12 +2202,12 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar updateTextchanges filePath (p, DateTime.UtcNow) - forceGetTypeCheckResults filePath |> ignore + let! _ = forceGetTypeCheckResults filePath return () with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentDidChange Request Errored {p}" @@ -2180,9 +2245,9 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar transact (fun () -> updateOpenFiles file - textChanges.Remove filePath |> ignore) + textChanges.Remove filePath |> ignore) - forceGetTypeCheckResults filePath |> ignore + let! _ = forceGetTypeCheckResults filePath do! bypassAdaptiveAndCheckDepenenciesForFile filePath do! lspClient.CodeLensRefresh() @@ -2193,7 +2258,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return () with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentDidSave Request Errored {p}" @@ -2217,7 +2282,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let (filePath, pos) = getFilePathAndPosition p - let! (namedText2) = forceFindOpenFileOrRead filePath |> Result.ofStringErr + let! (namedText2) = forceFindOpenFileOrRead filePath |> AsyncResult.ofStringErr let! lineStr2 = namedText2.Lines |> tryGetLineStr pos |> Result.ofStringErr @@ -2288,7 +2353,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar d.NameInList, (d, pos, filePath, namedText.Lines.GetLine, typeCheckResults.GetAST) ] ) |> autoCompleteItems.UpdateTo) - |> ignore + |> ignore let includeKeywords = config.KeywordsAutocomplete && shouldKeywords @@ -2327,7 +2392,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar success (Some completionList) with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentCompletion Request Errored {p}" @@ -2419,7 +2484,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar | Some insertText -> helpText insertText |> Result.ofCoreResponse - |> Result.fold + |> Result.bimap (function | None -> ci | Some text -> mapHelpText ci text) @@ -2427,7 +2492,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar |> success with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "CompletionItemResolve Request Errored {p}" @@ -2451,8 +2516,8 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let (filePath, pos) = getFilePathAndPosition p - let! (namedText) = forceFindOpenFileOrRead filePath |> Result.ofStringErr - and! tyRes = forceGetTypeCheckResults filePath |> Result.ofStringErr + let! (namedText) = forceFindOpenFileOrRead filePath |> AsyncResult.ofStringErr + and! tyRes = forceGetTypeCheckResults filePath |> AsyncResult.ofStringErr @@ -2492,7 +2557,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return! success (Some res) with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentSignatureHelp Request: {parms}" @@ -2515,9 +2580,9 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let (filePath, pos) = getFilePathAndPosition p - let! (namedText) = forceFindOpenFileOrRead filePath |> Result.ofStringErr + let! (namedText) = forceFindOpenFileOrRead filePath |> AsyncResult.ofStringErr let! lineStr = namedText.Lines |> tryGetLineStr pos |> Result.ofStringErr - and! tyRes = forceGetTypeCheckResultsStale filePath |> Result.ofStringErr + and! tyRes = forceGetTypeCheckResultsStale filePath |> AsyncResult.ofStringErr match tyRes.TryGetToolTipEnhanced pos lineStr with | Ok(Some tooltipResult) -> @@ -2585,11 +2650,11 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return! LspResult.internalError $"No TryGetToolTipEnhanced results for {filePath}" | Error e -> - trace.RecordError(e, "TextDocumentHover.Error") |> ignore + trace.RecordError(e, "TextDocumentHover.Error") |> ignore logger.error (Log.setMessage "Failed with {error}" >> Log.addContext "error" e) return! LspResult.internalError e with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentHover Request Errored {p}" @@ -2608,9 +2673,9 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let (filePath, pos) = getFilePathAndPosition p - let! namedText = forceFindOpenFileOrRead filePath |> Result.ofStringErr + let! namedText = forceFindOpenFileOrRead filePath |> AsyncResult.ofStringErr let! lineStr = namedText.Lines |> tryGetLineStr pos |> Result.ofStringErr - let! tyRes = forceGetTypeCheckResults filePath |> Result.ofStringErr + let! tyRes = forceGetTypeCheckResults filePath |> AsyncResult.ofStringErr let! (_, _, range) = Commands.renameSymbolRange getDeclarationLocation false pos lineStr namedText.Lines tyRes @@ -2631,9 +2696,9 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let (filePath, pos) = getFilePathAndPosition p - let! (namedText) = forceFindOpenFileOrRead filePath |> Result.ofStringErr + let! (namedText) = forceFindOpenFileOrRead filePath |> AsyncResult.ofStringErr let! lineStr = namedText.Lines |> tryGetLineStr pos |> Result.ofStringErr - and! tyRes = forceGetTypeCheckResults filePath |> Result.ofStringErr + and! tyRes = forceGetTypeCheckResults filePath |> AsyncResult.ofStringErr // validate name and surround with backticks if necessary let! newName = @@ -2649,33 +2714,37 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar symbolUseWorkspace true true true pos lineStr namedText.Lines tyRes |> AsyncResult.mapError (fun msg -> JsonRpc.Error.Create(JsonRpc.ErrorCodes.invalidParams, msg)) - let documentChanges = + let! documentChanges = ranges |> Seq.map (fun kvp -> - let edits = - kvp.Value - |> Array.map (fun range -> - let range = fcsRangeToLsp range - { Range = range; NewText = newName }) + async { + let edits = + kvp.Value + |> Array.map (fun range -> + let range = fcsRangeToLsp range + { Range = range; NewText = newName }) - let file: string = kvp.Key + let file: string = kvp.Key - let version = - forceFindOpenFileOrRead file - |> Option.ofResult - |> Option.bind (fun (f) -> f.Version) + let! version = + async { + let! file = forceFindOpenFileOrRead file + return file |> Option.ofResult |> Option.bind (fun (f) -> f.Version) + } - { TextDocument = - { Uri = Path.FilePathToUri(UMX.untag file) - Version = version } - Edits = edits }) - |> Array.ofSeq + return + { TextDocument = + { Uri = Path.FilePathToUri(UMX.untag file) + Version = version } + Edits = edits } + }) + |> Async.parallel75 let clientCapabilities = clientCapabilities |> AVal.force |> Option.get return WorkspaceEdit.Create(documentChanges, clientCapabilities) |> Some with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentRename Request Errored {p}" @@ -2698,14 +2767,14 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let (filePath, pos) = getFilePathAndPosition p - let! (namedText) = forceFindOpenFileOrRead filePath |> Result.ofStringErr + let! (namedText) = forceFindOpenFileOrRead filePath |> AsyncResult.ofStringErr let! lineStr = namedText.Lines |> tryGetLineStr pos |> Result.ofStringErr - and! tyRes = forceGetTypeCheckResults filePath |> Result.ofStringErr + and! tyRes = forceGetTypeCheckResults filePath |> AsyncResult.ofStringErr let! decl = tyRes.TryFindDeclaration pos lineStr |> AsyncResult.ofStringErr return decl |> findDeclToLspLocation |> GotoResult.Single |> Some with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentDefinition Request Errored {p}" @@ -2729,13 +2798,13 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let (filePath, pos) = getFilePathAndPosition p - let! (namedText) = forceFindOpenFileOrRead filePath |> Result.ofStringErr + let! (namedText) = forceFindOpenFileOrRead filePath |> AsyncResult.ofStringErr let! lineStr = namedText.Lines |> tryGetLineStr pos |> Result.ofStringErr - and! tyRes = forceGetTypeCheckResults filePath |> Result.ofStringErr + and! tyRes = forceGetTypeCheckResults filePath |> AsyncResult.ofStringErr let! decl = tyRes.TryFindTypeDeclaration pos lineStr |> AsyncResult.ofStringErr return decl |> findDeclToLspLocation |> GotoResult.Single |> Some with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentTypeDefinition Request Errored {p}" @@ -2758,9 +2827,9 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let (filePath, pos) = getFilePathAndPosition p - let! (namedText) = forceFindOpenFileOrRead filePath |> Result.ofStringErr + let! (namedText) = forceFindOpenFileOrRead filePath |> AsyncResult.ofStringErr let! lineStr = tryGetLineStr pos namedText.Lines |> Result.ofStringErr - and! tyRes = forceGetTypeCheckResults filePath |> Result.ofStringErr + and! tyRes = forceGetTypeCheckResults filePath |> AsyncResult.ofStringErr let! (_, usages) = symbolUseWorkspace true true false pos lineStr namedText.Lines tyRes @@ -2771,7 +2840,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return Some references with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentReferences Request Errored {p}" @@ -2794,9 +2863,9 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let (filePath, pos) = getFilePathAndPosition p - let! (namedText) = forceFindOpenFileOrRead filePath |> Result.ofStringErr + let! (namedText) = forceFindOpenFileOrRead filePath |> AsyncResult.ofStringErr let! lineStr = tryGetLineStr pos namedText.Lines |> Result.ofStringErr - and! tyRes = forceGetTypeCheckResults filePath |> Result.ofStringErr + and! tyRes = forceGetTypeCheckResults filePath |> AsyncResult.ofStringErr match tyRes.TryGetSymbolUseAndUsages pos lineStr @@ -2812,7 +2881,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar Kind = None }) |> Some with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentDocumentHighlight Request Errored {p}" @@ -2836,9 +2905,9 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let (filePath, pos) = getFilePathAndPosition p - let! (namedText) = forceFindOpenFileOrRead filePath |> Result.ofStringErr + let! (namedText) = forceFindOpenFileOrRead filePath |> AsyncResult.ofStringErr let! lineStr = tryGetLineStr pos namedText.Lines |> Result.ofStringErr - and! tyRes = forceGetTypeCheckResults filePath |> Result.ofStringErr + and! tyRes = forceGetTypeCheckResults filePath |> AsyncResult.ofStringErr logger.info ( Log.setMessage "TextDocumentImplementation Request: {parms}" @@ -2846,7 +2915,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let getProjectOptions file = - getProjectOptionsForFile file |> AVal.force |> List.head + getProjectOptionsForFile file |> AsyncAVal.forceAsync |> Async.map List.head let checker = checker |> AVal.force @@ -2857,11 +2926,13 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar allProjectOptions |> AMap.force |> Seq.toList - |> List.choose (fun (path, opt) -> - option { - let! opt = AVal.force opt |> selectProject - return UMX.untag path, opt + |> Seq.map (fun (k, v) -> + async { + let! proj = AsyncAVal.forceAsync v + return Option.map (fun proj -> UMX.untag k, proj) (selectProject proj) }) + |> Async.parallel75 + |> Async.map (Array.choose id >> List.ofArray) let! res = Commands.symbolImplementationProject getProjectOptions getUsesOfSymbol getAllProjects tyRes pos lineStr @@ -2881,7 +2952,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar | [| single |] -> return Some(GotoResult.Single single) | multiple -> return Some(GotoResult.Multiple multiple) with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentImplementation Request Errored {p}" @@ -2905,7 +2976,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let fn = p.TextDocument.GetFilePath() |> Utils.normalizePath - match getDeclarations fn |> AVal.force with + match! getDeclarations fn |> AsyncAVal.forceAsync with | Some decls -> return glyphToSymbolKind @@ -2918,7 +2989,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar |> Some | None -> return! LspResult.internalError $"No declarations for {fn}" with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentDocumentSymbol Request Errored {p}" @@ -2943,7 +3014,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let glyphToSymbolKind = glyphToSymbolKind |> AVal.force - let decls = getAllDeclarations () |> Seq.toArray + let! decls = getAllDeclarations () let res = decls @@ -2957,7 +3028,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return res with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "WorkspaceSymbol Request Errored {p}" @@ -2999,7 +3070,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return! x.HandleFormatting(fileName, action, handlerFormattedDoc, (fun (_, _, _) -> [||])) with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentFormatting Request Errored {p}" @@ -3052,7 +3123,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return! x.HandleFormatting(fileName, action, (fun (_, _) -> [||]), handlerFormattedRangeDoc) with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentRangeFormatting Request Errored {p}" @@ -3085,7 +3156,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar with e -> return Ok [] }) - |> Async.Parallel + |> Async.parallel75 let! fixes = fixes let (actions: Fix list[], errors: string[]) = Array.partitionResults fixes @@ -3102,22 +3173,24 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let tryGetFileVersion filePath = - forceFindOpenFileOrRead filePath - |> Option.ofResult - |> Option.bind (fun (f) -> f.Version) + async { + let! foo = forceFindOpenFileOrRead filePath + return foo |> Option.ofResult |> Option.bind (fun (f) -> f.Version) + } let clientCapabilities = clientCapabilities |> AVal.force match actions with | [] -> return None | actions -> - return + let! fixes = actions - |> List.map (CodeAction.OfFix tryGetFileVersion clientCapabilities.Value >> U2.Second) - |> List.toArray - |> Some + |> List.map (CodeAction.OfFix tryGetFileVersion clientCapabilities.Value) + |> Async.parallel75 + + return Some(fixes |> Array.map U2.Second) with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentCodeAction Request Errored {p}" @@ -3141,7 +3214,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let fn = p.TextDocument.GetFilePath() |> Utils.normalizePath - match getDeclarations (fn) |> AVal.force with + match! getDeclarations (fn) |> AsyncAVal.forceAsync with | None -> return None | Some decls -> let config = AVal.force config @@ -3155,7 +3228,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return Some res with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentCodeLens Request Errored {p}" @@ -3186,7 +3259,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let filePath = Path.FileUriToLocalPath data.[0] |> Utils.normalizePath try - let! tyRes = forceGetTypeCheckResultsStale filePath |> Result.ofStringErr + let! tyRes = forceGetTypeCheckResultsStale filePath |> AsyncResult.ofStringErr logger.info ( @@ -3194,7 +3267,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar >> Log.addContextDestructured "file" filePath ) - let! (namedText: NamedText) = forceFindSourceText filePath |> Result.ofStringErr + let! (namedText: NamedText) = forceFindSourceText filePath |> AsyncResult.ofStringErr let! lineStr = namedText |> tryGetLineStr pos |> Result.ofStringErr let typ = data.[1] @@ -3224,7 +3297,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return codeLens with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "CodeLensResolve - Operation failed on {file}" @@ -3329,14 +3402,11 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar >> Log.addContextDestructured "parms" p ) - p.Changes - |> Array.iter (fun c -> + for c in p.Changes do if c.Type = FileChangeType.Deleted then - forgetDocument c.Uri - - ()) + do! forgetDocument c.Uri with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "WorkspaceDidChangeWatchedFiles Request Errored {p}" @@ -3365,7 +3435,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar updateConfig c) with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "WorkspaceDidChangeConfiguration Request Errored {p}" @@ -3397,7 +3467,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let! scopes = Commands.scopesForFile getParseResultsForFile file |> AsyncResult.ofStringErr return scopes |> Seq.map Structure.toFoldingRange |> Set.ofSeq |> List.ofSeq |> Some with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentFoldingRange Request Errored {p}" @@ -3443,7 +3513,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return ranges |> List.choose mkSelectionRanges |> Some with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentSelectionRange Request Errored {p}" @@ -3469,7 +3539,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return! x.handleSemanticTokens fn None with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentSemanticTokensFull Request Errored {p}" @@ -3497,7 +3567,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let fcsRange = protocolRangeToRange (UMX.untag fn) p.Range return! x.handleSemanticTokens fn (Some fcsRange) with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentSemanticTokensRange Request Errored {p}" @@ -3520,9 +3590,9 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let filePath = p.TextDocument.GetFilePath() |> Utils.normalizePath - let! (namedText) = forceFindOpenFileOrRead filePath |> Result.ofStringErr + let! (namedText) = forceFindOpenFileOrRead filePath |> AsyncResult.ofStringErr - and! tyRes = forceGetTypeCheckResults filePath |> Result.ofStringErr + and! tyRes = forceGetTypeCheckResults filePath |> AsyncResult.ofStringErr let fcsRange = protocolRangeToRange (UMX.untag filePath) p.Range let config = config |> AVal.force @@ -3602,7 +3672,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return (Some hints) with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentInlayHint Request Errored {p}" @@ -3625,10 +3695,10 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let filePath = p.TextDocument.GetFilePath() |> Utils.normalizePath - let! (namedText) = forceFindOpenFileOrRead filePath |> Result.ofStringErr + let! (namedText) = forceFindOpenFileOrRead filePath |> AsyncResult.ofStringErr - let! tyRes = forceGetTypeCheckResults filePath |> Result.ofStringErr + let! tyRes = forceGetTypeCheckResults filePath |> AsyncResult.ofStringErr let fcsRange = protocolRangeToRange (UMX.untag filePath) p.Range @@ -3644,7 +3714,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return hints with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "TextDocumentInlineValue Request Errored {p}" @@ -3829,17 +3899,17 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let (filePath, pos) = getFilePathAndPosition p - let! (namedText) = forceFindOpenFileOrRead filePath |> Result.ofStringErr + let! (namedText) = forceFindOpenFileOrRead filePath |> AsyncResult.ofStringErr let! lineStr = namedText.Lines |> tryGetLineStr pos |> Result.ofStringErr - and! tyRes = forceGetTypeCheckResults filePath |> Result.ofStringErr + and! tyRes = forceGetTypeCheckResults filePath |> AsyncResult.ofStringErr let! tip = Commands.typesig tyRes pos lineStr |> Result.ofCoreResponse return tip |> Option.map (fun tip -> { Content = CommandResponse.typeSig FsAutoComplete.JsonSerializer.writeJson tip }) with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FSharpSignature Request Errored {p}" @@ -3865,10 +3935,10 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar FSharp.Compiler.Text.Position.mkPos (p.Position.Line) (p.Position.Character + 2) let filePath = p.TextDocument.GetFilePath() |> Utils.normalizePath - let! (namedText) = forceFindOpenFileOrRead filePath |> Result.ofStringErr + let! (namedText) = forceFindOpenFileOrRead filePath |> AsyncResult.ofStringErr let! lineStr = namedText.Lines |> tryGetLineStr pos |> Result.ofStringErr - and! tyRes = forceGetTypeCheckResults filePath |> Result.ofStringErr + and! tyRes = forceGetTypeCheckResults filePath |> AsyncResult.ofStringErr let! (typ, parms, generics) = tyRes.TryGetSignatureData pos lineStr |> Result.ofStringErr return @@ -3876,7 +3946,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar { Content = CommandResponse.signatureData FsAutoComplete.JsonSerializer.writeJson (typ, parms, generics) } with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FSharpSignatureData Request Errored {p}" @@ -3900,10 +3970,10 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let (filePath, pos) = getFilePathAndPosition p - let! (namedText) = forceFindOpenFileOrRead filePath |> Result.ofStringErr + let! (namedText) = forceFindOpenFileOrRead filePath |> AsyncResult.ofStringErr let! lineStr = namedText.Lines |> tryGetLineStr pos |> Result.ofStringErr - and! tyRes = forceGetTypeCheckResults filePath |> Result.ofStringErr + and! tyRes = forceGetTypeCheckResults filePath |> AsyncResult.ofStringErr match! Commands.GenerateXmlDocumentation(tyRes, pos, lineStr) @@ -3928,7 +3998,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return () with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FSharpDocumentationGenerator Request Errored {p}" @@ -3952,7 +4022,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar let fn = p.Project.GetFilePath() |> Utils.normalizePath - match getDeclarations fn |> AVal.force with + match! getDeclarations fn |> AsyncAVal.forceAsync with | None -> return! LspResult.internalError $"No declerations found for {fn}" | Some decls -> let decls = decls |> Array.map (fun d -> d, fn) @@ -3960,7 +4030,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return Some { Content = CommandResponse.declarations FsAutoComplete.JsonSerializer.writeJson decls } with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FSharpLineLense Request Errored {p}" @@ -3988,12 +4058,12 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar |> HashSet.ofArray transact (fun () -> workspacePaths.Value <- (WorkspaceChosen.Projs projs)) - let! _ = parseAllFiles () |> AVal.force + let! _ = parseAllFiles () |> AsyncAVal.forceAsync return { Content = CommandResponse.workspaceLoad FsAutoComplete.JsonSerializer.writeJson true } with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FSharpWorkspaceLoad Request Errored {p}" @@ -4031,7 +4101,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return! res with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FSharpWorkspacePeek Request Errored {p}" @@ -4073,7 +4143,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return! Helpers.notImplemented with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FSharpWorkspacePeek Request Errored {p}" @@ -4109,7 +4179,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return Some { Content = CommandResponse.dotnetnewlist FsAutoComplete.JsonSerializer.writeJson funcs } | None -> return None with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FSharpDotnetNewList Request Errored {p}" @@ -4134,11 +4204,11 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar do! Commands.DotnetNewRun p.Template p.Name p.Output [] |> AsyncResult.ofCoreResponse - |> AsyncResult.map ignore // mapping unit option to unit + |> AsyncResult.ignore // mapping unit option to unit return None with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FSharpDotnetNewRun Request Errored {p}" @@ -4163,11 +4233,11 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar do! Commands.DotnetAddProject p.Target p.Reference |> AsyncResult.ofCoreResponse - |> AsyncResult.map ignore // mapping unit option to unit + |> AsyncResult.ignore // mapping unit option to unit return None with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FSharpDotnetAddProject Request Errored {p}" @@ -4192,11 +4262,11 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar do! Commands.DotnetRemoveProject p.Target p.Reference |> AsyncResult.ofCoreResponse - |> AsyncResult.map ignore + |> AsyncResult.ignore return None with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FSharpDotnetRemoveProject Request Errored {p}" @@ -4221,11 +4291,11 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar do! Commands.DotnetSlnAdd p.Target p.Reference |> AsyncResult.ofCoreResponse - |> AsyncResult.map ignore + |> AsyncResult.ignore return None with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FSharpDotnetSlnAdd Request Errored {p}" @@ -4248,15 +4318,15 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let (filePath, pos) = getFilePathAndPosition p - let! (namedText) = forceFindOpenFileOrRead filePath |> Result.ofStringErr + let! (namedText) = forceFindOpenFileOrRead filePath |> AsyncResult.ofStringErr let! lineStr = namedText.Lines |> tryGetLineStr pos |> Result.ofStringErr - and! tyRes = forceGetTypeCheckResults filePath |> Result.ofStringErr + and! tyRes = forceGetTypeCheckResults filePath |> AsyncResult.ofStringErr match! Commands.Help tyRes pos lineStr |> Result.ofCoreResponse with | Some t -> return Some { Content = CommandResponse.help FsAutoComplete.JsonSerializer.writeJson t } | None -> return None with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FSharpHelp Request Errored {p}" @@ -4279,9 +4349,9 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let (filePath, pos) = getFilePathAndPosition p - let! (namedText) = forceFindOpenFileOrRead filePath |> Result.ofStringErr + let! (namedText) = forceFindOpenFileOrRead filePath |> AsyncResult.ofStringErr let! lineStr = namedText.Lines |> tryGetLineStr pos |> Result.ofStringErr - and! tyRes = forceGetTypeCheckResults filePath |> Result.ofStringErr + and! tyRes = forceGetTypeCheckResults filePath |> AsyncResult.ofStringErr lastFSharpDocumentationTypeCheck <- Some tyRes match! Commands.FormattedDocumentation tyRes pos lineStr |> Result.ofCoreResponse with @@ -4298,7 +4368,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar XmlKey = xmlKey |} } | None -> return None with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FSharpDocumentation Request Errored {p}" @@ -4344,7 +4414,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar XmlKey = xmlKey |} } |> Some with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FSharpDocumentationSymbol Request Errored {p}" @@ -4374,7 +4444,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return LspResult.success () with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e Loggers.analyzers.error (Log.setMessage "Loading failed" >> Log.addExn e) return LspResult.success () } @@ -4391,14 +4461,14 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) let filePath = p.TextDocument.GetFilePath() |> Utils.normalizePath - let! tyRes = forceGetTypeCheckResults filePath |> Result.ofStringErr + let! tyRes = forceGetTypeCheckResults filePath |> AsyncResult.ofStringErr - match! Commands.pipelineHints forceFindSourceText tyRes |> Result.ofCoreResponse with + match! Commands.pipelineHints forceFindSourceText tyRes |> AsyncResult.ofCoreResponse with | None -> return None | Some res -> return Some { Content = CommandResponse.pipelineHint FsAutoComplete.JsonSerializer.writeJson res } with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FSharpPipelineHints Request Errored {p}" @@ -4423,11 +4493,11 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar do! Commands.FsProjMoveFileUp p.FsProj p.FileVirtualPath |> AsyncResult.ofCoreResponse - |> AsyncResult.map ignore + |> AsyncResult.ignore return None with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FsProjMoveFileUp Request Errored {p}" @@ -4453,11 +4523,11 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar do! Commands.FsProjMoveFileDown p.FsProj p.FileVirtualPath |> AsyncResult.ofCoreResponse - |> AsyncResult.map ignore + |> AsyncResult.ignore return None with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FsProjMoveFileDown Request Errored {p}" @@ -4483,11 +4553,11 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar do! Commands.addFileAbove p.FsProj p.FileVirtualPath p.NewFile |> AsyncResult.ofCoreResponse - |> AsyncResult.map ignore + |> AsyncResult.ignore return None with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FsProjAddFileAbove Request Errored {p}" @@ -4512,11 +4582,11 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar do! Commands.addFileBelow p.FsProj p.FileVirtualPath p.NewFile |> AsyncResult.ofCoreResponse - |> AsyncResult.map ignore + |> AsyncResult.ignore return None with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FsProjAddFileBelow Request Errored {p}" @@ -4541,11 +4611,11 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar do! Commands.renameFile p.FsProj p.OldFileVirtualPath p.NewFileName |> AsyncResult.ofCoreResponse - |> AsyncResult.map ignore + |> AsyncResult.ignore return None with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FsProjRenameFile Request Errored {p}" @@ -4571,11 +4641,11 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar do! Commands.addFile p.FsProj p.FileVirtualPath |> AsyncResult.ofCoreResponse - |> AsyncResult.map ignore + |> AsyncResult.ignore return None with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FsProjAddFile Request Errored {p}" @@ -4602,14 +4672,14 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar do! Commands.removeFile p.FsProj p.FileVirtualPath |> AsyncResult.ofCoreResponse - |> AsyncResult.map ignore + |> AsyncResult.ignore let fileUri = Path.FilePathToUri fullPath diagnosticCollections.ClearFor fileUri return None with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FsProjRemoveFile Request Errored {p}" @@ -4634,11 +4704,11 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar do! Commands.addExistingFile p.FsProj p.FileVirtualPath |> AsyncResult.ofCoreResponse - |> AsyncResult.map ignore + |> AsyncResult.ignore return None with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "FsProjAddExistingFile Request Errored {p}" @@ -4649,7 +4719,9 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar return! LspResult.internalError (string e) } - override x.Dispose() = disposables.Dispose() + override x.Dispose() = + traceNotifications |> Option.iter (dispose) + disposables.Dispose() member this.WorkDoneProgessCancel(token: ProgressToken) : Async = async { @@ -4664,7 +4736,7 @@ type AdaptiveFSharpLspServer(workspaceLoader: IWorkspaceLoader, lspClient: FShar ) with e -> - trace.SetStatusErrorSafe(e.Message).RecordExceptions(e) |> ignore + trace |> Tracing.recordException e logger.error ( Log.setMessage "WorkDoneProgessCancel Request Errored {p}" diff --git a/src/FsAutoComplete/LspServers/Common.fs b/src/FsAutoComplete/LspServers/Common.fs index a6e9d8cf9..00fb67e7a 100644 --- a/src/FsAutoComplete/LspServers/Common.fs +++ b/src/FsAutoComplete/LspServers/Common.fs @@ -150,13 +150,6 @@ module Async = let inline logCancelled e = logger.trace (Log.setMessage "Operation Cancelled" >> Log.addExn e) - /// Creates an asynchronous computation that executes all the given asynchronous computations, using 75% of the Environment.ProcessorCount - /// A sequence of distinct computations to be parallelized. - let parallel75 computations = - let maxConcurrency = - Math.Max(1.0, Math.Floor((float System.Environment.ProcessorCount) * 0.75)) - - Async.Parallel(computations, int maxConcurrency) let withCancellation (ct: CancellationToken) (a: Async<'a>) : Async<'a> = async { @@ -194,19 +187,7 @@ module Async = let StartWithCT ct work = Async.Start(work, ct) - let RunSynchronouslyWithCT ct work = - Async.RunSynchronously(work, cancellationToken = ct) - - let RunSynchronouslyWithCTSafe ct work = - try - work |> RunSynchronouslyWithCT(ct ()) |> Some - with - | :? OperationCanceledException as e -> - logCancelled e - None - | :? ObjectDisposedException as e when e.Message.Contains("CancellationTokenSource has been disposed") -> - logCancelled e - None + let startImmediateAsTask ct work = Async.StartImmediateAsTask(work, ct) [] module ObservableExtensions = diff --git a/src/FsAutoComplete/LspServers/FSharpLspClient.fs b/src/FsAutoComplete/LspServers/FSharpLspClient.fs index c5aeb03a4..dc3b9954b 100644 --- a/src/FsAutoComplete/LspServers/FSharpLspClient.fs +++ b/src/FsAutoComplete/LspServers/FSharpLspClient.fs @@ -148,7 +148,7 @@ open System.Diagnostics open Ionide.ProjInfo.Logging -/// listener for the the events generated from the fsc ActivitySource +/// listener for the the events generated from the fsc ActivitySource type ProgressListener(lspClient: FSharpLspClient, traceNamespace: string array) = let isOneOf list string = diff --git a/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs b/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs index 8ad54220b..61f039e50 100644 --- a/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs +++ b/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs @@ -68,7 +68,7 @@ type FSharpLspServer(state: State, lspClient: FSharpLspClient) = commands.CheckSimplifiedNames filePath ] async { - do! analyzers |> Async.Parallel |> Async.Ignore + do! analyzers |> Async.parallel75 |> Async.Ignore do! lspClient.NotifyDocumentAnalyzed @@ -1105,19 +1105,23 @@ type FSharpLspServer(state: State, lspClient: FSharpLspClient) = | Some false -> None | None -> None - let getFileLines = commands.TryGetFileCheckerOptionsWithLines >> Result.map snd + let getFileLines = + commands.TryGetFileCheckerOptionsWithLines >> Result.map snd >> Async.singleton let getLineText (lines: NamedText) (range: Ionide.LanguageServerProtocol.Types.Range) = lines.GetText(protocolRangeToRange (UMX.untag lines.FileName) range) + |> Async.singleton let getRangeText fileName (range: Ionide.LanguageServerProtocol.Types.Range) = - getFileLines fileName - |> Result.bind (fun lines -> lines.GetText(protocolRangeToRange (UMX.untag fileName) range)) + asyncResult { + let! lines = getFileLines fileName + return! lines.GetText(protocolRangeToRange (UMX.untag fileName) range) + } let getProjectOptsAndLines = commands.TryGetFileCheckerOptionsWithLinesAndLineStr let tryGetProjectOptions = - commands.TryGetFileCheckerOptionsWithLines >> Result.map fst + commands.TryGetFileCheckerOptionsWithLines >> Result.map fst >> Async.singleton let implementInterfaceConfig () : ImplementInterface.Config = { ObjectIdentifier = config.InterfaceStubGenerationObjectIdentifier @@ -1326,7 +1330,7 @@ type FSharpLspServer(state: State, lspClient: FSharpLspClient) = let initialText = state.TryGetFileSource(filePath) - |> Result.fold id (fun _ -> NamedText(filePath, "")) + |> Result.bimap id (fun _ -> NamedText(filePath, "")) let evolvedFileContent = (initialText, p.ContentChanges) @@ -1917,7 +1921,7 @@ type FSharpLspServer(state: State, lspClient: FSharpLspClient) = with e -> return Ok [] }) - |> Async.Parallel + |> Async.parallel75 let! fixes = fixes let (actions: Fix list[], errors: string[]) = Array.partitionResults fixes @@ -1936,14 +1940,12 @@ type FSharpLspServer(state: State, lspClient: FSharpLspClient) = match actions with | [] -> return None | actions -> - return + let! fixes = actions - |> List.map ( - CodeAction.OfFix commands.TryGetFileVersion clientCapabilities.Value - >> U2.Second - ) - |> List.toArray - |> Some + |> List.map (CodeAction.OfFix (commands.TryGetFileVersion >> Async.singleton) clientCapabilities.Value) + |> Async.parallel75 + + return Some(fixes |> Array.map U2.Second) } override __.TextDocumentCodeLens(p: CodeLensParams) = @@ -2873,14 +2875,16 @@ type FSharpLspServer(state: State, lspClient: FSharpLspClient) = p.TextDocument |> x.fileHandler (fun fn tyRes lines -> - match commands.PipelineHints tyRes with - | CoreResponse.InfoRes msg -> async.Return(success None) - | CoreResponse.ErrorRes msg -> AsyncLspResult.internalError msg - | CoreResponse.Res(res) -> - { Content = CommandResponse.pipelineHint FsAutoComplete.JsonSerializer.writeJson res } - |> Some - |> success - |> async.Return) + async { + match! commands.PipelineHints tyRes with + | CoreResponse.InfoRes msg -> return! async.Return(success None) + | CoreResponse.ErrorRes msg -> return! AsyncLspResult.internalError msg + | CoreResponse.Res(res) -> + return + { Content = CommandResponse.pipelineHint FsAutoComplete.JsonSerializer.writeJson res } + |> Some + |> success + }) override x.TextDocumentInlineValue(p: InlineValueParams) : AsyncLspResult = logger.info ( diff --git a/test/FsAutoComplete.Tests.Lsp/DetectUnitTests.fs b/test/FsAutoComplete.Tests.Lsp/DetectUnitTests.fs index 9ad1c1626..1b57357df 100644 --- a/test/FsAutoComplete.Tests.Lsp/DetectUnitTests.fs +++ b/test/FsAutoComplete.Tests.Lsp/DetectUnitTests.fs @@ -10,7 +10,7 @@ open FsToolkit.ErrorHandling open Helpers.Expecto.ShadowedTimeouts let tests state = - let geTestNotification projectFolder fileName = + let getTestNotification projectFolder fileName = async { let path = Path.Combine(__SOURCE_DIRECTORY__, "TestCases", projectFolder) let! server, events = serverInitialize path defaultConfigDto state @@ -24,12 +24,13 @@ let tests state = } |> Async.Cache - testList + testSequenced + <| testList "Find unit tests" [ testCaseAsync "Find nunit test" (async { - let! testNotification = geTestNotification "NUnitTests" "UnitTest1.fs" + let! testNotification = getTestNotification "NUnitTests" "UnitTest1.fs" Expect.hasLength testNotification.Tests 1 "Expected to have found 1 nunit test" Expect.equal testNotification.Tests[0].Childs[1].Childs[0].Name "Inner" "Expect nested module to be named Inner" @@ -41,7 +42,7 @@ let tests state = testCaseAsync "Find xunit test" (async { - let! testNotification = geTestNotification "XUnitTests" "Tests.fs" + let! testNotification = getTestNotification "XUnitTests" "Tests.fs" Expect.hasLength testNotification.Tests 1 "Expected to have found 1 xunit test list" Expect.equal testNotification.Tests[0].ModuleType "Module" "Expected top list to be module" @@ -52,7 +53,7 @@ let tests state = testCaseAsync "Find expecto tests" (async { - let! testNotification = geTestNotification "ExpectoTests" "Sample.fs" + let! testNotification = getTestNotification "ExpectoTests" "Sample.fs" Expect.hasLength testNotification.Tests 1 "Expected to have found 1 expecto test list" Expect.hasLength testNotification.Tests.[0].Childs 8 "Expected to have found 8 expecto tests" }) ]