diff --git a/FSharp.CommandLine.fsproj b/FSharp.CommandLine.fsproj new file mode 100644 index 0000000..b23486a --- /dev/null +++ b/FSharp.CommandLine.fsproj @@ -0,0 +1,28 @@ + + + net6.0;netstandard2.0 + A framework for building command line application in F#. Supports command line option parsing, type-safe scanf, monadic command construction, automatic help & shell completion generation, and so on. + cannorin + + (c) cannorin 2017-2022 + https://github.com/cannorin/FSharp.CommandLine + https://github.com/cannorin/FSharp.CommandLine/blob/master/LICENSE.txt + fsharp commandline parsing framework + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FSharp.CommandLine.sln b/FSharp.CommandLine.sln deleted file mode 100755 index e57f2c1..0000000 --- a/FSharp.CommandLine.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27428.2011 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{f2a71f9b-5d33-465a-a702-920d77279786}") = "FSharp.CommandLine", "src\FSharp.CommandLine\FSharp.CommandLine.fsproj", "{32A93182-5504-4C36-98E0-D2486AA6B361}" -EndProject -Project("{f2a71f9b-5d33-465a-a702-920d77279786}") = "FSharp.Scanf", "src\FSharp.Scanf\FSharp.Scanf.fsproj", "{9540C26A-B0A5-4E78-A596-C62F036A2DF1}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {32A93182-5504-4C36-98E0-D2486AA6B361}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {32A93182-5504-4C36-98E0-D2486AA6B361}.Debug|Any CPU.Build.0 = Debug|Any CPU - {32A93182-5504-4C36-98E0-D2486AA6B361}.Release|Any CPU.ActiveCfg = Release|Any CPU - {32A93182-5504-4C36-98E0-D2486AA6B361}.Release|Any CPU.Build.0 = Release|Any CPU - {9540C26A-B0A5-4E78-A596-C62F036A2DF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9540C26A-B0A5-4E78-A596-C62F036A2DF1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9540C26A-B0A5-4E78-A596-C62F036A2DF1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9540C26A-B0A5-4E78-A596-C62F036A2DF1}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {80272E67-BBF7-47F2-A615-C56E4B39D7D6} - EndGlobalSection -EndGlobal diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 199f445..046dd7e 100755 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,9 +1,10 @@ +* 4.0.0 - Massive refactoring * 3.4.* - Indent multiline command descriptions * 3.3.* - Fixed scanf parser. * 3.2.* - Fixed scanf parser. * 3.1.* - Improve comments. Some refactoring. * 3.0.* - Breaking API changes. Use FAKE again. Refactor Scanf. -* 2.2.* - Fix broken NuGet dependency +* 2.2.* - Fix broken NuGet dependency * 2.1.* - Separated scanf module * 2.0.* - Breaking API changes: no more internal side effects * 1.2.* - Get rid of FAKE diff --git a/build.fsx b/build.fsx index 5f8f649..07af2cd 100755 --- a/build.fsx +++ b/build.fsx @@ -1,14 +1,14 @@ #r "paket: -source https://api.nuget.org/v3/index.json nuget FSharp.Core nuget Fake.DotNet.Cli -nuget Fake.IO.FileSystem nuget Fake.DotNet.MSBuild -nuget Fake.Core.Target nuget Fake.DotNet.AssemblyInfoFile -nuget Fake.Core.ReleaseNotes //" - +nuget Fake.Core.Target +nuget Fake.Core.ReleaseNotes +nuget Fake.IO.FileSystem +//" #load ".fake/build.fsx/intellisense.fsx" + open Fake.Core open Fake.DotNet open Fake.IO @@ -51,7 +51,7 @@ let disableLogging (c: MSBuild.CliArguments) = { c with ConsoleLogParameters = []; DistributedLoggers = None; DisableInternalBinLog = true } Target.create "WriteVersion" (fun _ -> - AssemblyInfoFile.createFSharp "./src/common/Version.fs" [ + AssemblyInfoFile.createFSharp "./src/version.fs" [ AssemblyInfo.Version release.AssemblyVersion AssemblyInfo.FileVersion release.AssemblyVersion ] @@ -60,7 +60,7 @@ Target.create "WriteVersion" (fun _ -> Target.create "Clean" (fun _ -> !! "src/**/bin" ++ "src/**/obj" - |> Shell.cleanDirs + |> Shell.cleanDirs ) Target.create "Build" (fun _ -> diff --git a/build.fsx.lock b/build.fsx.lock old mode 100755 new mode 100644 index 6b14a07..9b65aee --- a/build.fsx.lock +++ b/build.fsx.lock @@ -1,576 +1,233 @@ STORAGE: NONE -RESTRICTION: == netstandard2.0 +RESTRICTION: || (== net6.0) (== netstandard2.0) NUGET remote: https://api.nuget.org/v3/index.json - BlackFox.VsWhere (1.0) + BlackFox.VsWhere (1.1) FSharp.Core (>= 4.2.3) - Fake.Core.CommandLineParsing (5.11.1) - FParsec (>= 1.0.3) + Microsoft.Win32.Registry (>= 4.7) + Fake.Core.CommandLineParsing (5.22) + FParsec (>= 1.1.1) + FSharp.Core (>= 6.0) + Fake.Core.Context (5.22) + FSharp.Core (>= 6.0) + Fake.Core.Environment (5.22) + FSharp.Core (>= 6.0) + Fake.Core.FakeVar (5.22) + Fake.Core.Context (>= 5.22) + FSharp.Core (>= 6.0) + Fake.Core.Process (5.22) + Fake.Core.Environment (>= 5.22) + Fake.Core.FakeVar (>= 5.22) + Fake.Core.String (>= 5.22) + Fake.Core.Trace (>= 5.22) + Fake.IO.FileSystem (>= 5.22) + FSharp.Core (>= 6.0) + System.Collections.Immutable (>= 5.0) + Fake.Core.ReleaseNotes (5.22) + Fake.Core.SemVer (>= 5.22) + Fake.Core.String (>= 5.22) + FSharp.Core (>= 6.0) + Fake.Core.SemVer (5.22) + FSharp.Core (>= 6.0) + Fake.Core.String (5.22) + FSharp.Core (>= 6.0) + Fake.Core.Target (5.22) + Fake.Core.CommandLineParsing (>= 5.22) + Fake.Core.Context (>= 5.22) + Fake.Core.Environment (>= 5.22) + Fake.Core.FakeVar (>= 5.22) + Fake.Core.Process (>= 5.22) + Fake.Core.String (>= 5.22) + Fake.Core.Trace (>= 5.22) + FSharp.Control.Reactive (>= 5.0.2) + FSharp.Core (>= 6.0) + Fake.Core.Tasks (5.22) + Fake.Core.Trace (>= 5.22) + FSharp.Core (>= 6.0) + Fake.Core.Trace (5.22) + Fake.Core.Environment (>= 5.22) + Fake.Core.FakeVar (>= 5.22) + FSharp.Core (>= 6.0) + Fake.Core.Xml (5.22) + Fake.Core.String (>= 5.22) + FSharp.Core (>= 6.0) + Fake.DotNet.AssemblyInfoFile (5.22) + Fake.Core.Environment (>= 5.22) + Fake.Core.String (>= 5.22) + Fake.Core.Trace (>= 5.22) + Fake.IO.FileSystem (>= 5.22) + FSharp.Core (>= 6.0) + Fake.DotNet.Cli (5.22) + Fake.Core.Environment (>= 5.22) + Fake.Core.Process (>= 5.22) + Fake.Core.String (>= 5.22) + Fake.Core.Trace (>= 5.22) + Fake.DotNet.MSBuild (>= 5.22) + Fake.DotNet.NuGet (>= 5.22) + Fake.IO.FileSystem (>= 5.22) + FSharp.Core (>= 6.0) + Mono.Posix.NETStandard (>= 1.0) + Newtonsoft.Json (>= 13.0.1) + Fake.DotNet.MSBuild (5.22) + BlackFox.VsWhere (>= 1.1) + Fake.Core.Environment (>= 5.22) + Fake.Core.Process (>= 5.22) + Fake.Core.String (>= 5.22) + Fake.Core.Trace (>= 5.22) + Fake.IO.FileSystem (>= 5.22) + FSharp.Core (>= 6.0) + MSBuild.StructuredLogger (>= 2.1.545) + Fake.DotNet.NuGet (5.22) + Fake.Core.Environment (>= 5.22) + Fake.Core.Process (>= 5.22) + Fake.Core.SemVer (>= 5.22) + Fake.Core.String (>= 5.22) + Fake.Core.Tasks (>= 5.22) + Fake.Core.Trace (>= 5.22) + Fake.Core.Xml (>= 5.22) + Fake.IO.FileSystem (>= 5.22) + Fake.Net.Http (>= 5.22) + FSharp.Core (>= 6.0) + Newtonsoft.Json (>= 13.0.1) + NuGet.Protocol (>= 5.11) + Fake.IO.FileSystem (5.22) + Fake.Core.String (>= 5.22) + FSharp.Core (>= 6.0) + Fake.Net.Http (5.22) + Fake.Core.Trace (>= 5.22) + FSharp.Core (>= 6.0) + FParsec (1.1.1) FSharp.Core (>= 4.3.4) - Fake.Core.Context (5.11.1) - FSharp.Core (>= 4.3.4) - Fake.Core.Environment (5.11.1) - FSharp.Core (>= 4.3.4) - Fake.Core.FakeVar (5.11.1) - Fake.Core.Context (>= 5.11.1) - FSharp.Core (>= 4.3.4) - Fake.Core.Process (5.11.1) - Fake.Core.Environment (>= 5.11.1) - Fake.Core.FakeVar (>= 5.11.1) - Fake.Core.String (>= 5.11.1) - Fake.Core.Trace (>= 5.11.1) - Fake.IO.FileSystem (>= 5.11.1) - FSharp.Core (>= 4.3.4) - System.Diagnostics.Process (>= 4.3) - Fake.Core.ReleaseNotes (5.11.1) - Fake.Core.SemVer (>= 5.11.1) - Fake.Core.String (>= 5.11.1) - FSharp.Core (>= 4.3.4) - Fake.Core.SemVer (5.11.1) - FSharp.Core (>= 4.3.4) - System.Runtime.Numerics (>= 4.3) - Fake.Core.String (5.11.1) - FSharp.Core (>= 4.3.4) - Fake.Core.Target (5.11.1) - Fake.Core.CommandLineParsing (>= 5.11.1) - Fake.Core.Context (>= 5.11.1) - Fake.Core.Environment (>= 5.11.1) - Fake.Core.FakeVar (>= 5.11.1) - Fake.Core.Process (>= 5.11.1) - Fake.Core.String (>= 5.11.1) - Fake.Core.Trace (>= 5.11.1) - FSharp.Control.Reactive (>= 4.1) - FSharp.Core (>= 4.3.4) - System.Reactive.Compatibility (>= 4.1.2) - Fake.Core.Trace (5.11.1) - Fake.Core.Environment (>= 5.11.1) - Fake.Core.FakeVar (>= 5.11.1) - FSharp.Core (>= 4.3.4) - Fake.DotNet.AssemblyInfoFile (5.11.1) - Fake.Core.Environment (>= 5.11.1) - Fake.Core.String (>= 5.11.1) - Fake.Core.Trace (>= 5.11.1) - Fake.IO.FileSystem (>= 5.11.1) - FSharp.Core (>= 4.3.4) - Fake.DotNet.Cli (5.11.1) - Fake.Core.Environment (>= 5.11.1) - Fake.Core.Process (>= 5.11.1) - Fake.Core.String (>= 5.11.1) - Fake.Core.Trace (>= 5.11.1) - Fake.DotNet.MSBuild (>= 5.11.1) - Fake.IO.FileSystem (>= 5.11.1) - FSharp.Core (>= 4.3.4) - Newtonsoft.Json (>= 12.0.1) - Fake.DotNet.MSBuild (5.11.1) - BlackFox.VsWhere (>= 1.0) - Fake.Core.Environment (>= 5.11.1) - Fake.Core.Process (>= 5.11.1) - Fake.Core.String (>= 5.11.1) - Fake.Core.Trace (>= 5.11.1) - Fake.IO.FileSystem (>= 5.11.1) - FSharp.Core (>= 4.3.4) - MSBuild.StructuredLogger (>= 2.0.61) - Fake.IO.FileSystem (5.11.1) - Fake.Core.String (>= 5.11.1) - FSharp.Core (>= 4.3.4) - System.Diagnostics.FileVersionInfo (>= 4.3) - System.IO.FileSystem.Watcher (>= 4.3) - FParsec (1.0.3) - FSharp.Core (>= 4.2.3) - NETStandard.Library (>= 1.6.1) - FSharp.Control.Reactive (4.1) - FSharp.Core (>= 4.2.3) - System.Reactive (>= 4.0) - FSharp.Core (4.5.4) - Microsoft.Build (15.9.20) - Microsoft.Build.Framework (>= 15.9.20) + FSharp.Control.Reactive (5.0.5) + FSharp.Core (>= 4.7.2) + System.Reactive (>= 5.0 < 6.0) + FSharp.Core (6.0.3) + Microsoft.Build (17.1) + Microsoft.Build.Framework (>= 17.1) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) + Microsoft.NET.StringTools (>= 1.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) + Microsoft.Win32.Registry (>= 4.3) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net6.0)) + System.Collections.Immutable (>= 5.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) + System.Configuration.ConfigurationManager (>= 4.7) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) + System.Reflection.Metadata (>= 1.6) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net6.0)) + System.Security.Principal.Windows (>= 4.7) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net6.0)) + System.Text.Encoding.CodePages (>= 4.0.1) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net6.0)) + System.Text.Json (>= 6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) + System.Threading.Tasks.Dataflow (>= 6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) + Microsoft.Build.Framework (17.1) Microsoft.Win32.Registry (>= 4.3) - System.Collections.Immutable (>= 1.5) - System.Diagnostics.TraceSource (>= 4.0) - System.IO.Compression (>= 4.3) - System.Reflection.Metadata (>= 1.6) - System.Reflection.TypeExtensions (>= 4.1) - System.Runtime.InteropServices.RuntimeInformation (>= 4.3) - System.Runtime.Loader (>= 4.0) - System.Text.Encoding.CodePages (>= 4.0.1) - System.Threading.Tasks.Dataflow (>= 4.6) - Microsoft.Build.Framework (15.9.20) - System.Runtime.Serialization.Primitives (>= 4.1.1) - System.Threading.Thread (>= 4.0) - Microsoft.Build.Tasks.Core (15.9.20) - Microsoft.Build.Framework (>= 15.9.20) - Microsoft.Build.Utilities.Core (>= 15.9.20) + System.Security.Permissions (>= 4.7) + Microsoft.Build.Tasks.Core (17.1) + Microsoft.Build.Framework (>= 17.1) + Microsoft.Build.Utilities.Core (>= 17.1) + Microsoft.NET.StringTools (>= 1.0) Microsoft.Win32.Registry (>= 4.3) System.CodeDom (>= 4.4) - System.Collections.Immutable (>= 1.5) - System.Linq.Parallel (>= 4.0.1) - System.Net.Http (>= 4.3) + System.Collections.Immutable (>= 5.0) System.Reflection.Metadata (>= 1.6) - System.Reflection.TypeExtensions (>= 4.1) - System.Resources.Writer (>= 4.0) - System.Threading.Tasks.Dataflow (>= 4.6) - Microsoft.Build.Utilities.Core (15.9.20) - Microsoft.Build.Framework (>= 15.9.20) + System.Resources.Extensions (>= 4.6) + System.Security.Cryptography.Pkcs (>= 4.7) + System.Security.Cryptography.Xml (>= 4.7) + System.Security.Permissions (>= 4.7) + System.Threading.Tasks.Dataflow (>= 6.0) + Microsoft.Build.Utilities.Core (17.1) + Microsoft.Build.Framework (>= 17.1) + Microsoft.NET.StringTools (>= 1.0) Microsoft.Win32.Registry (>= 4.3) - System.Collections.Immutable (>= 1.5) - System.Runtime.InteropServices.RuntimeInformation (>= 4.3) - System.Text.Encoding.CodePages (>= 4.4) - Microsoft.NETCore.Platforms (2.2) - Microsoft.NETCore.Targets (2.1) - Microsoft.Win32.Primitives (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - Microsoft.Win32.Registry (4.5) - System.Buffers (>= 4.4) - System.Memory (>= 4.5) - System.Security.AccessControl (>= 4.5) - System.Security.Principal.Windows (>= 4.5) - MSBuild.StructuredLogger (2.0.64) - Microsoft.Build (>= 15.8.166) - Microsoft.Build.Framework (>= 15.8.166) - Microsoft.Build.Tasks.Core (>= 15.8.166) - Microsoft.Build.Utilities.Core (>= 15.8.166) - NETStandard.Library (2.0.3) - Microsoft.NETCore.Platforms (>= 1.1) - Newtonsoft.Json (12.0.1) - runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.debian.9-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.27-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.fedora.28-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.native.System (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - runtime.native.System.IO.Compression (4.3.2) - Microsoft.NETCore.Platforms (>= 1.1.1) - Microsoft.NETCore.Targets (>= 1.1.3) - runtime.native.System.Net.Http (4.3.1) + System.Collections.Immutable (>= 5.0) + System.Configuration.ConfigurationManager (>= 4.7) + System.Security.Permissions (>= 4.7) + System.Text.Encoding.CodePages (>= 4.0.1) + Microsoft.NET.StringTools (1.0) + System.Memory (>= 4.5.4) + System.Runtime.CompilerServices.Unsafe (>= 5.0) + Microsoft.NETCore.Platforms (6.0.3) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard1.2)) (&& (== net6.0) (< netstandard1.3)) (&& (== net6.0) (< netstandard1.5)) (== netstandard2.0) + Microsoft.NETCore.Targets (5.0) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard1.2)) (&& (== net6.0) (< netstandard1.3)) (&& (== net6.0) (< netstandard1.5)) (== netstandard2.0) + 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)) (== netstandard2.0) + System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (< netcoreapp2.0)) (&& (== net6.0) (< netcoreapp2.1)) (&& (== net6.0) (>= uap10.1)) (== netstandard2.0) + System.Security.AccessControl (>= 5.0) + System.Security.Principal.Windows (>= 5.0) + Microsoft.Win32.SystemEvents (6.0.1) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) + Mono.Posix.NETStandard (1.0) + MSBuild.StructuredLogger (2.1.630) + Microsoft.Build (>= 16.10) + Microsoft.Build.Framework (>= 16.10) + Microsoft.Build.Tasks.Core (>= 16.10) + Microsoft.Build.Utilities.Core (>= 16.10) + Newtonsoft.Json (13.0.1) + NuGet.Common (6.1) + NuGet.Frameworks (>= 6.1) + NuGet.Configuration (6.1) + NuGet.Common (>= 6.1) + System.Security.Cryptography.ProtectedData (>= 4.4) + NuGet.Frameworks (6.1) + NuGet.Packaging (6.1) + Newtonsoft.Json (>= 13.0.1) + NuGet.Configuration (>= 6.1) + NuGet.Versioning (>= 6.1) + System.Security.Cryptography.Cng (>= 5.0) + System.Security.Cryptography.Pkcs (>= 5.0) + NuGet.Protocol (6.1) + NuGet.Packaging (>= 6.1) + NuGet.Versioning (6.1) + 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)) (== netstandard2.0) + System.CodeDom (6.0) + System.Collections.Immutable (6.0) + System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0) + System.Runtime.CompilerServices.Unsafe (>= 6.0) + System.Configuration.ConfigurationManager (6.0) + System.Security.Cryptography.ProtectedData (>= 6.0) + System.Security.Permissions (>= 6.0) + System.Drawing.Common (6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) + Microsoft.Win32.SystemEvents (>= 6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) + System.Formats.Asn1 (6.0) + System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0) + System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0) + System.Memory (4.5.4) + 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)) (== netstandard2.0) + System.Numerics.Vectors (>= 4.4) - restriction: || (&& (== net6.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)) (== netstandard2.0) + System.Numerics.Vectors (4.5) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0) + System.Reactive (5.0) + System.Runtime.InteropServices.WindowsRuntime (>= 4.3) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (== netstandard2.0) + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net472)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (>= uap10.1)) (== netstandard2.0) + System.Reflection.Metadata (6.0.1) + System.Collections.Immutable (>= 6.0) + System.Resources.Extensions (6.0) + System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0) + System.Runtime (4.3.1) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (== netstandard2.0) Microsoft.NETCore.Platforms (>= 1.1.1) Microsoft.NETCore.Targets (>= 1.1.3) - runtime.native.System.Security.Cryptography.Apple (4.3.1) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple (>= 4.3.1) - runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.debian.9-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.27-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.fedora.28-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.42.3-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.ubuntu.18.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.3) - runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.opensuse.42.3-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple (4.3.1) - runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - runtime.ubuntu.18.04-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) - System.Buffers (4.5) - System.CodeDom (4.5) - System.Collections (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Collections.Concurrent (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Diagnostics.Tracing (>= 4.3) - System.Globalization (>= 4.3) - System.Reflection (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Collections.Immutable (1.5) - System.Diagnostics.Debug (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Diagnostics.DiagnosticSource (4.5.1) - System.Diagnostics.FileVersionInfo (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.IO.FileSystem (>= 4.3) - System.IO.FileSystem.Primitives (>= 4.3) - System.Reflection.Metadata (>= 1.4.1) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Diagnostics.Process (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.Win32.Primitives (>= 4.3) - Microsoft.Win32.Registry (>= 4.3) - runtime.native.System (>= 4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.IO.FileSystem (>= 4.3) - System.IO.FileSystem.Primitives (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Text.Encoding.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Threading.Thread (>= 4.3) - System.Threading.ThreadPool (>= 4.3) - System.Diagnostics.TraceSource (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System (>= 4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Diagnostics.Tracing (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Globalization (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Globalization.Calendars (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Globalization (>= 4.3) - System.Runtime (>= 4.3) - System.Globalization.Extensions (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - System.Globalization (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.IO (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.IO.Compression (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System (>= 4.3) - runtime.native.System.IO.Compression (>= 4.3) - System.Buffers (>= 4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.IO (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.IO.FileSystem (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.IO (>= 4.3) - System.IO.FileSystem.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.IO.FileSystem.Primitives (4.3) - System.Runtime (>= 4.3) - System.IO.FileSystem.Watcher (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.Win32.Primitives (>= 4.3) - runtime.native.System (>= 4.3) - System.Collections (>= 4.3) - System.IO.FileSystem (>= 4.3) - System.IO.FileSystem.Primitives (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Overlapped (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Threading.Thread (>= 4.3) - System.Linq (4.3) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Linq.Parallel (4.3) - System.Collections (>= 4.3) - System.Collections.Concurrent (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Diagnostics.Tracing (>= 4.3) - System.Linq (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Memory (4.5.1) - System.Buffers (>= 4.4) - System.Numerics.Vectors (>= 4.4) - System.Runtime.CompilerServices.Unsafe (>= 4.5) - System.Net.Http (4.3.4) - Microsoft.NETCore.Platforms (>= 1.1.1) - runtime.native.System (>= 4.3) - runtime.native.System.Net.Http (>= 4.3) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Diagnostics.DiagnosticSource (>= 4.3) - System.Diagnostics.Tracing (>= 4.3) - System.Globalization (>= 4.3) - System.Globalization.Extensions (>= 4.3) - System.IO (>= 4.3) - System.IO.FileSystem (>= 4.3) - System.Net.Primitives (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Security.Cryptography.Algorithms (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.OpenSsl (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Security.Cryptography.X509Certificates (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Net.Primitives (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Numerics.Vectors (4.5) - System.Reactive (4.1.2) - System.Runtime.InteropServices.WindowsRuntime (>= 4.3) - System.Threading.Tasks.Extensions (>= 4.5.1) - System.Reactive.Compatibility (4.1.2) - System.Reactive.Core (>= 4.1.2) - System.Reactive.Interfaces (>= 4.1.2) - System.Reactive.Linq (>= 4.1.2) - System.Reactive.PlatformServices (>= 4.1.2) - System.Reactive.Providers (>= 4.1.2) - System.Reactive.Core (4.1.2) - System.Reactive (>= 4.1.2) - System.Threading.Tasks.Extensions (>= 4.5.1) - System.Reactive.Interfaces (4.1.2) - System.Reactive (>= 4.1.2) - System.Threading.Tasks.Extensions (>= 4.5.1) - System.Reactive.Linq (4.1.2) - System.Reactive (>= 4.1.2) - System.Threading.Tasks.Extensions (>= 4.5.1) - System.Reactive.PlatformServices (4.1.2) - System.Reactive (>= 4.1.2) - System.Threading.Tasks.Extensions (>= 4.5.1) - System.Reactive.Providers (4.1.2) - System.Reactive (>= 4.1.2) - System.Threading.Tasks.Extensions (>= 4.5.1) - System.Reflection (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.IO (>= 4.3) - System.Reflection.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Reflection.Extensions (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Reflection (>= 4.3) - System.Runtime (>= 4.3) - System.Reflection.Metadata (1.6) - System.Collections.Immutable (>= 1.5) - System.Reflection.Primitives (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Reflection.TypeExtensions (4.5.1) - System.Resources.ResourceManager (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Globalization (>= 4.3) - System.Reflection (>= 4.3) - System.Runtime (>= 4.3) - System.Resources.Writer (4.3) - System.Collections (>= 4.3) - System.IO (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Runtime (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime.CompilerServices.Unsafe (4.5.2) - System.Runtime.Extensions (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Runtime.Handles (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Runtime.InteropServices (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Reflection (>= 4.3) - System.Reflection.Primitives (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices.RuntimeInformation (4.3) - runtime.native.System (>= 4.3) - System.Reflection (>= 4.3) - System.Reflection.Extensions (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Threading (>= 4.3) - System.Runtime.InteropServices.WindowsRuntime (4.3) - System.Runtime (>= 4.3) - System.Runtime.Loader (4.3) - System.IO (>= 4.3) - System.Reflection (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Numerics (4.3) - System.Globalization (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Serialization.Primitives (4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Security.AccessControl (4.5) - System.Security.Principal.Windows (>= 4.5) - System.Security.Cryptography.Algorithms (4.3.1) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System.Security.Cryptography.Apple (>= 4.3.1) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2) - System.Collections (>= 4.3) - System.IO (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Runtime.Numerics (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Security.Cryptography.Cng (4.5) - System.Security.Cryptography.Csp (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - System.IO (>= 4.3) - System.Reflection (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Security.Cryptography.Algorithms (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (>= 4.3) - System.Security.Cryptography.Encoding (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3) - System.Collections (>= 4.3) - System.Collections.Concurrent (>= 4.3) - System.Linq (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Security.Cryptography.OpenSsl (4.5) - System.Security.Cryptography.Primitives (4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.IO (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Threading (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Security.Cryptography.X509Certificates (4.3.2) - Microsoft.NETCore.Platforms (>= 1.1) - runtime.native.System (>= 4.3) - runtime.native.System.Net.Http (>= 4.3) - runtime.native.System.Security.Cryptography.OpenSsl (>= 4.3.2) - System.Collections (>= 4.3) - System.Diagnostics.Debug (>= 4.3) - System.Globalization (>= 4.3) - System.Globalization.Calendars (>= 4.3) - System.IO (>= 4.3) - System.IO.FileSystem (>= 4.3) - System.IO.FileSystem.Primitives (>= 4.3) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Extensions (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Runtime.InteropServices (>= 4.3) - System.Runtime.Numerics (>= 4.3) - System.Security.Cryptography.Algorithms (>= 4.3) - System.Security.Cryptography.Cng (>= 4.3) - System.Security.Cryptography.Csp (>= 4.3) - System.Security.Cryptography.Encoding (>= 4.3) - System.Security.Cryptography.OpenSsl (>= 4.3) - System.Security.Cryptography.Primitives (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (>= 4.3) - System.Security.Principal.Windows (4.5.1) - System.Text.Encoding (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Text.Encoding.CodePages (4.5) - System.Runtime.CompilerServices.Unsafe (>= 4.5) - System.Text.Encoding.Extensions (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Text.Encoding (>= 4.3) - System.Threading (4.3) - System.Runtime (>= 4.3) - System.Threading.Tasks (>= 4.3) - System.Threading.Overlapped (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - System.Resources.ResourceManager (>= 4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) - System.Threading.Tasks (4.3) - Microsoft.NETCore.Platforms (>= 1.1) - Microsoft.NETCore.Targets (>= 1.1) - System.Runtime (>= 4.3) - System.Threading.Tasks.Dataflow (4.9) - System.Threading.Tasks.Extensions (4.5.1) - System.Runtime.CompilerServices.Unsafe (>= 4.5) - System.Threading.Thread (4.3) - System.Runtime (>= 4.3) - System.Threading.ThreadPool (4.3) - System.Runtime (>= 4.3) - System.Runtime.Handles (>= 4.3) + System.Runtime.CompilerServices.Unsafe (6.0) + System.Runtime.InteropServices.WindowsRuntime (4.3) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (== netstandard2.0) + System.Runtime (>= 4.3) + System.Security.AccessControl (6.0) + System.Security.Principal.Windows (>= 5.0) - restriction: || (&& (== net6.0) (>= net461)) (== netstandard2.0) + System.Security.Cryptography.Cng (5.0) + System.Formats.Asn1 (>= 5.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.0)) + System.Security.Cryptography.Pkcs (6.0) + System.Buffers (>= 4.5.1) - restriction: || (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0) + System.Formats.Asn1 (>= 6.0) + System.Memory (>= 4.5.4) - restriction: || (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0) + System.Security.Cryptography.Cng (>= 5.0) - restriction: || (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (< netstandard2.1)) (== netstandard2.0) + System.Security.Cryptography.ProtectedData (6.0) + System.Security.Cryptography.Xml (6.0) + System.Memory (>= 4.5.4) - restriction: == netstandard2.0 + System.Security.AccessControl (>= 6.0) + System.Security.Cryptography.Pkcs (>= 6.0) + System.Security.Permissions (6.0) + System.Security.AccessControl (>= 6.0) + System.Windows.Extensions (>= 6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) + System.Security.Principal.Windows (5.0) + System.Text.Encoding.CodePages (6.0) + System.Runtime.CompilerServices.Unsafe (>= 6.0) + System.Text.Encodings.Web (6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.0) + System.Text.Json (6.0.3) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= net472)) (&& (== netstandard2.0) (>= net6.0)) + System.Runtime.CompilerServices.Unsafe (>= 6.0) + System.Text.Encodings.Web (>= 6.0) + System.Threading.Tasks.Dataflow (6.0) + System.Threading.Tasks.Extensions (4.5.4) - restriction: || (&& (== net6.0) (>= net472)) (&& (== net6.0) (< netcoreapp3.1)) (&& (== net6.0) (>= uap10.1)) (== netstandard2.0) + 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)) (== netstandard2.0) + System.Windows.Extensions (6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) + System.Drawing.Common (>= 6.0) - restriction: || (== net6.0) (&& (== netstandard2.0) (>= netcoreapp3.1)) diff --git a/fake.cmd b/fake.cmd deleted file mode 100755 index 2f757d1..0000000 --- a/fake.cmd +++ /dev/null @@ -1,7 +0,0 @@ -SET TOOL_PATH=.fake - -IF NOT EXIST "%TOOL_PATH%\fake.exe" ( - dotnet tool install fake-cli --tool-path ./%TOOL_PATH% -) - -"%TOOL_PATH%/fake.exe" %* \ No newline at end of file diff --git a/fake.sh b/fake.sh deleted file mode 100755 index f6bbfcc..0000000 --- a/fake.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -export DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER=0 - -set -eu -set -o pipefail - -# liberated from https://stackoverflow.com/a/18443300/433393 -realpath() { - OURPWD=$PWD - cd "$(dirname "$1")" - LINK=$(readlink "$(basename "$1")") - while [ "$LINK" ]; do - cd "$(dirname "$LINK")" - LINK=$(readlink "$(basename "$1")") - done - REALPATH="$PWD/$(basename "$1")" - cd "$OURPWD" - echo "$REALPATH" -} - -TOOL_PATH=$(realpath .fake) -FAKE="$TOOL_PATH"/fake - -if ! [ -e "$FAKE" ] -then - dotnet tool install fake-cli --tool-path "$TOOL_PATH" -fi -"$FAKE" "$@" diff --git a/nuget.config b/nuget.config deleted file mode 100755 index fa83729..0000000 --- a/nuget.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/FSharp.CommandLine/FSharp.CommandLine.fsproj b/src/FSharp.CommandLine/FSharp.CommandLine.fsproj deleted file mode 100755 index ebf263e..0000000 --- a/src/FSharp.CommandLine/FSharp.CommandLine.fsproj +++ /dev/null @@ -1,33 +0,0 @@ - - - - - netstandard2.0;net46 - A framework for building command line application in F#. Supports command line option parsing, type-safe scanf, monadic command construction, automatic help & shell completion generation, and so on. - cannorin - - (c) cannorin 2017-2019 - https://github.com/cannorin/FSharp.CommandLine - https://github.com/cannorin/FSharp.CommandLine/blob/master/LICENSE.txt - fsharp commandline parsing framework - - - - - - - - - - - - - - - - - - - - - diff --git a/src/FSharp.CommandLine/abstraction.fs b/src/FSharp.CommandLine/abstraction.fs deleted file mode 100755 index 7382ec6..0000000 --- a/src/FSharp.CommandLine/abstraction.fs +++ /dev/null @@ -1,54 +0,0 @@ -namespace FSharp.CommandLine.Internals - -module Abstraction = - type State<'Args, 'a> = 'Args -> ('a * 'Args) - - type StateConfig<'Config, 'Args, 'a> = { - config: 'Config -> 'Config - func: State<'Args, 'a> - } - - module StateConfig = - let inline scbind (f: 'a -> StateConfig<'Config, 'Args, 'b>) (g: 'Config -> 'Config) (m: StateConfig<'Config, 'Args, 'a>) = - { - config = m.config >> g - func = - fun args -> - let (a, args) = m.func args - (f a).func args - } - - let inline returnValue (a: 'a) : StateConfig<_, _, 'a> = - { - config = id - func = fun args -> (a, args) - } - - let inline returnWith (f: unit -> 'a) : StateConfig<_, _, 'a> = - { - config = id - func = fun args -> (f(), args) - } - - let inline bind f m = m |> scbind f id - - let inline mapConfig g m = m |> scbind returnValue g - - let inline map f m = m |> bind (f >> returnValue) - - let inline zip (m: StateConfig<_, _, 'a>) (n: StateConfig<_, _, 'b>) (f: 'a -> 'b -> 'c) = - scbind (fun a -> - { - config = id - func = fun args -> let (b, args) = n.func args in (f a b, args) - }) - n.config - m - - let inline combine (a: StateConfig<_,_,_>) (b: StateConfig<_,_,_>) = zip a b (fun _ b -> b) - - let args = - { - config = id - func = fun args -> (args, args) - } diff --git a/src/FSharp.CommandLine/basictypes.fs b/src/FSharp.CommandLine/basictypes.fs deleted file mode 100755 index dff9c97..0000000 --- a/src/FSharp.CommandLine/basictypes.fs +++ /dev/null @@ -1,160 +0,0 @@ -namespace FSharp.CommandLine - -[] -module BasicTypes = - open FSharp.CommandLine.Internals.Abstraction - open System.Runtime.CompilerServices - - type Args = string list - - type HelpElement = - /// prints `usage: $(command name) $(args)`. - | HelpUsage - /// prints `usage: $(command name) $(args)` of which `args` can be customized. - | HelpUsageCustomArgs of args: string list - /// prints a string. - | HelpRawString of text: string - /// prints the infomation of all the subcommands. - | HelpAllSubcommands - /// prints the infomation of the specified subcommands. - | HelpSpecificSubcommands of names: string list - /// prints the infomation of all the command options. - | HelpAllOptions - /// prints the infomation of the specified command options. - | HelpSpecificOptions of namesWithoutHyphen: string list - /// prints elements as a section. the content will be indented. - /// nested sections make the indentation deeper. - | HelpSection of sectionName: string * sectionBody: seq - /// prints an empty line. - | HelpEmptyLine - - module internal Seq = - let inline snoc x xs = seq { yield! xs; yield x } - - [] - type HelpBuilder = - member inline __.For (_, _) = failwith "Not supported" - member inline __.Yield _ : HelpElement seq = Seq.empty - /// prints `usage: $(command name) $(args)`. - [] - member inline __.Usage xs = xs |> Seq.snoc HelpUsage - /// prints `usage: $(command name) $(args)` of which `args` can be customized. - [] - member inline __.UsageWithCustomArgs (xs, argNames) = xs |> Seq.snoc (HelpUsageCustomArgs argNames) - /// prints a string. - [] - member inline __.RawText (xs, str) = xs |> Seq.snoc (HelpRawString str) - /// prints the infomation of all the subcommands. - [] - member inline __.Subcommands xs = xs |> Seq.snoc HelpAllSubcommands - /// prints the infomation of the specified subcommands. - [] - member inline __.SpecificSubcommands (xs, cmds) = xs |> Seq.snoc (HelpSpecificSubcommands cmds) - /// prints the infomation of all the command options. - [] - member inline __.Options xs = xs |> Seq.snoc HelpAllOptions - /// prints the infomation of the specified command options. - [] - member inline __.SpecificOptions (xs, opts) = xs |> Seq.snoc (HelpSpecificOptions opts) - /// prints elements as a section. the content will be indented. - /// nested sections make the indentation deeper. - [] - member inline __.Section (xs, sectionName, section) = xs |> Seq.snoc (HelpSection(sectionName, section)) - /// prints elements as a section when the condition holds. the content will be indented. - /// nested sections make the indentation deeper. - [] - member inline __.ConditionalSection (xs, sectionName, cond, section) = - if cond() then - xs |> Seq.snoc (HelpSection(sectionName, section)) - else - xs - /// prints an empty line. - [] - member inline __.EmptyLine xs = xs |> Seq.snoc HelpEmptyLine - - let helpText = HelpBuilder () - - type CommandSuggestion = - /// suggests a set of string. - | Values of string list - /// suggests a set of string with description. - | ValuesWithDescription of (string * string) list - /// suggests files optionally with pattern. - | Files of pattern: string option - /// suggests directories. - | Directories of pattern: string option - /// suggests a command option. - | OptionSuggestion of (string list) * string - /// prints a message. - | Message of string - - type CommandOptionSummary = { - names: string list; - description: string; - isFlag: bool; - paramNames: (string list) list - isMatch: string list -> string list option - genSuggestions: string option -> CommandSuggestion list - } - with - member this.Param = - let rec print eq xss = - let heads = xss |> List.map List.tryHead - if heads |> List.exists Option.isSome then - let isOptional = heads |> List.exists Option.isNone - let groups = xss |> List.filter (List.isEmpty >> not) - |> List.groupBy List.head - |> List.map (fun (g, xs) -> sprintf "%s%s" g (xs |> List.map List.tail |> print "")) - let s = - if List.length groups > 1 then - let s = groups |> String.concat "|" - if isOptional then s else sprintf "{%s}" s - else - groups |> String.concat "" - if isOptional then sprintf "[%s%s]" eq s else sprintf "%s%s"eq s - else - "" - in print "=" (this.paramNames |> List.rev) - - member this.NameRepresentations = - this.names |> List.collect (function - | x when x.Length = 1 -> - [ "-"; "/" ] |> List.map (fun prefix -> sprintf "%s%s" prefix x) - | x -> - [ "--"; "/" ] |> List.map (fun prefix -> sprintf "%s%s" prefix x)) - - member this.Print () = - let o x = if this.isFlag then sprintf "%s[+|-]" x else sprintf "%s%s" x this.Param - ((this.NameRepresentations |> List.filter (String.startsWith "-") |> String.concat ", " |> o), this.description) - - [] - type CommandSummary = { - name: string; - displayName: string option; - description: string; - paramNames: (string list) option - help: HelpElement seq option - genSuggestions: Args -> CommandSuggestion list - } - - [] - type CommandInfo = { - summary: CommandSummary - options: CommandOptionSummary list - subcommands: Command list - } - and Command<'a> = StateConfig - - type CommandInfo with - static member empty = - { - summary = Unchecked.defaultof - options = [] - subcommands = [] - } - - [] - type ICommandExt() = - [] - static member inline Summary(x: Command<_>) = - (x.config CommandInfo.empty).summary diff --git a/src/FSharp.CommandLine/commands.fs b/src/FSharp.CommandLine/commands.fs deleted file mode 100755 index 034bffd..0000000 --- a/src/FSharp.CommandLine/commands.fs +++ /dev/null @@ -1,185 +0,0 @@ -namespace FSharp.CommandLine - -[] -module Commands = - open System - open FSharp.CommandLine.Options - open FSharp.CommandLine.Generators - open FSharp.CommandLine.Internals.Abstraction - - let inline private mapSummary f co = - co |> StateConfig.mapConfig (fun cfg -> { cfg with summary = f cfg.summary }) - - type CommandBuilder() = - member inline __.Bind (c, f) : Command<_> = StateConfig.bind f c - member inline __.Return x = StateConfig.returnValue x - member inline __.For (c, f) : Command<_> = StateConfig.bind f c - member inline __.Yield x = StateConfig.returnValue x - member inline __.ReturnFrom (x: Command<_>) = x - member inline __.Combine (a, b) : Command<_> = StateConfig.combine a b - member inline __.Combine (f: unit -> _, b: Command<_>) : Command<_> = StateConfig.combine (f()) b - member inline __.Combine (a: Command<_>, f: unit -> _) : Command<_> = StateConfig.combine a (f()) - member inline __.Zero () = StateConfig.returnValue () - member inline __.Delay (f: unit -> Command<_>) = f - member inline __.Undelay x : Command<_> = x() - member inline __.Run f : Command<_> = f() - member inline __.TryWith (f, h) = try f() with exn -> h exn - member inline __.TryFinally (f, h) = try f() finally h() - member inline this.Using (disp: #System.IDisposable, m) = - this.TryFinally( - this.Delay(fun () -> m disp), - fun () -> dispose disp - ) - member inline this.While (cond, m: unit -> Command<_>) = - let rec loop cond m : Command<_> = - if cond () then this.Combine(this.Undelay m, loop cond m) - else this.Zero () - loop cond m - member inline this.For (xs: #seq<_>, exec) = - this.Using( - (xs :> seq<_>).GetEnumerator(), - fun en -> - this.While( - en.MoveNext, - this.Delay(fun () -> exec en.Current)) - ) - /// uses a command option. - [] - member inline __.UseOption (co: Command<'a>, opt: #ICommandOption<'b>, f: 'a -> 'b -> 'c) = - { - config = co.config >> opt.Config - func = - fun args -> - let (a, args) = co.func args - let (b, args) = opt.Parse args - (f a b, args) - } - /// imports a command to this command. will inherit options and other metadatas. - [] - member inline __.ImportCommand (c1, c2, f) : Command<_> = StateConfig.zip c1 c2 f - /// required. sets the name of the command. will also be used when this command is - /// a subcommand of the other one. - [] - member inline __.Name (co, x) = - co |> mapSummary (fun s -> { s with name = x }) - /// optional. sets the name of the command that will be displayed in the help text. - /// the one speficied by `name` will be used if not specified. - [] - member inline __.DisplayName (co, n) = - co |> mapSummary (fun s -> { s with displayName = Some n }) - /// required. sets the description of the command. - [] - member inline __.Description (co, x) = - co |> mapSummary (fun s -> { s with description = x }) - /// optional. speficies the suggestions it will generate. - [] - member inline __.Suggests (co: Command<_>, f) = - co |> mapSummary (fun s -> { s with genSuggestions = f }) - /// optional. customizes the help text. - [] - member inline __.Help (co: Command<_>, xs: HelpElement seq) = - co |> mapSummary (fun s -> { s with help = Some xs }) - [] - [] - member inline __.Preprocess xs = xs - /// optional. specifies the subcommands. - [] - member inline __.Subcommands (co, xs) = - { - config = - fun cfg -> - let cfg = co.config cfg - { cfg with subcommands = cfg.subcommands @ xs } - func = - fun args -> - let sc = - match args with - | h :: _ -> - List.tryFind (fun (x:Command<_>) -> x.Summary().name = h) xs - | _ -> None - if sc.IsSome then - let (code, _) = sc.Value.func (List.tail args) - RequestExit code |> raise - else - co.func args - } - - let command = CommandBuilder () - - module Command = - let args : Command = StateConfig.args - let inline bind f m : Command<_> = StateConfig.bind f m - let inline returnValue x : Command<_> = StateConfig.returnValue x - let inline returnWith f : Command<_> = StateConfig.returnWith f - let inline map f m : Command<_> = StateConfig.map f m - let inline mapInfo f m : Command<_> = StateConfig.mapConfig f m - let inline zip a b f : Command<_> = StateConfig.zip a b f - let inline combine a b : Command<_> = StateConfig.combine a b - - let private runMain args (cmd: Command) = - match args |> List.ofArray with - | OptionParse ReservedCommandOptions.suggestOption (sug, rest) -> - Suggestions.generate rest cmd - |> Suggestions.print (SuggestionBackends.findByName sug) - |> printfn "%A" - (0, []) - | OptionParse ReservedCommandOptions.helpOption (true, rest) -> - for line in Help.generate rest cmd do - printfn "%s" line - (0, []) - | args -> - cmd.func args - - #if DEBUG - let runAsEntryPointDebug args (cmd: Command) = runMain args cmd - #endif - - /// executes the command as an entry point: - /// - /// ``` - /// [] - /// let main argv = - /// Command.runAsEntryPoint argv command - /// ``` - let runAsEntryPoint args (cmd: Command) = - try - runMain args cmd |> fst - with - | RequestExit code -> code - | RequestShowHelp msg -> - cprintfn ConsoleColor.Red "error: %s\n" msg - for line in Help.generate (args |> List.ofArray) cmd do - printfn "%s" line - -1 - | OptionParseFailed (_, msg) - | CommandExecutionFailed msg -> cprintfn ConsoleColor.Red "error: %s\n" msg; -1 - | e -> reraise' e - - /// stops the execution immediately and then exits with the specified code. - let inline exit code = - RequestExit code |> raise - - /// stops the execution immediately and then exits with the specified error message and code `-1`. - let inline fail msg = - CommandExecutionFailed msg |> raise - - /// stops the execution immediately and then exits with the specified error message and code `-1`. - let inline failf fmt = - Printf.kprintf (fun msg -> CommandExecutionFailed msg |> raise ) fmt - - /// if there are remaining unknown options, then stops the execution - /// immediately and then exits with code `-1`. - let failOnUnknownOptions () = - command { - let! argv = StateConfig.args in - let uks = argv |> CommandOption.getRemainingOptions in - if uks |> List.isEmpty then - return () - else - sprintf "unknown option: '%s'" (List.head uks) |> CommandExecutionFailed |> raise - } - - /// shows the error message and the help of the current (sub)command, then exits with code `-1`. - let inline failShowingHelp message = - RequestShowHelp message |> raise - diff --git a/src/FSharp.CommandLine/extensions.fs b/src/FSharp.CommandLine/extensions.fs deleted file mode 100755 index 9f19065..0000000 --- a/src/FSharp.CommandLine/extensions.fs +++ /dev/null @@ -1,25 +0,0 @@ -namespace FSharp.CommandLine - -[] -module InternalExtensions = - open Microsoft.FSharp.Quotations - open Microsoft.FSharp.Quotations.Patterns - open Microsoft.FSharp.Linq.RuntimeHelpers - - type FuncHelper = private | FuncHelper with - static member compileFunc (x: Expr<'a -> 'b>) = - LeafExpressionConverter.EvaluateQuotation x :?> ('a -> 'b) - - static member getFirstArgumentName (x: Expr<'a -> 'b>) = - let rec gn tupleArgName = function - | Let (v, TupleGet(Var tn, index), body) when (tupleArgName = tn.Name) -> - (index, v.Name) :: gn tupleArgName body - | _ -> [] - in - match x with - | Lambda (v, e) -> - match (gn v.Name e) with - | [] -> Some [v.Name] - | xs -> xs |> List.sortBy fst |> List.map snd |> Some - | _ -> None - diff --git a/src/FSharp.CommandLine/optionValues.fs b/src/FSharp.CommandLine/optionValues.fs deleted file mode 100755 index acb1917..0000000 --- a/src/FSharp.CommandLine/optionValues.fs +++ /dev/null @@ -1,105 +0,0 @@ -namespace FSharp.CommandLine - -[] -module OptionValues = - open System - open FSharp.Scanf - open FSharp.Scanf.Optimized - open Microsoft.FSharp.Quotations - open System.Text.RegularExpressions - - type ValueFormat<'p,'st,'rd,'rl,'t,'a> = { - format: PrintfFormat<'p,'st,'rd,'rl,'t> - paramNames: (string list) option - handler: 't -> 'a - } - with - static member inline construct (this: ValueFormat<_,_,_,_,_,_>) = - let parser s = - s |> tryKsscanf this.format this.handler - |> function Ok x -> Some x | _ -> None - in - let formatTokens = - let defaultNames = - this.format.GetFormatterNames() - |> List.map (String.replace ' ' '_' >> String.toUpperInvariant) - |> List.map (sprintf "%s_VALUE") - in - let names = (this.paramNames ?| defaultNames) |> List.map (sprintf "<%s>") in - this.format.PrettyTokenize names - in - (parser, formatTokens) - - member this.map ([]mapper: Expr<'a -> 'b>) = - let mf x = (FuncHelper.compileFunc mapper) x in - let pns = FuncHelper.getFirstArgumentName mapper in - { format = this.format; handler = this.handler >> mf; paramNames = pns } - - member this.withNames names = - { this with paramNames = Some names } - - member this.asConst value = - { format = this.format; handler = (fun _ -> value); paramNames = this.paramNames } - - let inline format (fmt: PrintfFormat<_,_,_,_,'t>) : ValueFormat<_,_,_,_,'t,'t> = - { format = fmt; handler = id; paramNames = None } - - type ValueRegex<'a> = { - regex: Regex - handler: string list -> 'a - } - with - static member construct (this: ValueRegex<_>) = - let parser (str: string) = - let m: Match = this.regex.Match(str) - if m.Success then - m.Groups - |> Seq.cast - |> List.ofSeq - |> List.zip (this.regex.GetGroupNames() |> List.ofArray) - |> List.filter (fun (name, _) -> name |> String.forall Char.IsDigit |> not) - |> List.map (fun (_, x) -> x.Value) - |> this.handler |> Some - else None - let tokens = [to_s this.regex] - (parser, tokens) - - member this.map mapper = - { regex = this.regex; handler = this.handler >> mapper } - - member this.asConst value = - { regex = this.regex; handler = fun _ -> value } - - let inline regex r = - { regex = Regex(r); handler = id } - - type ValueTypedRegex<'a, '_Regex, '_Match > = { - typedRegex: '_Regex - handler: '_Match -> 'a - } - with - static member inline construct (this: ValueTypedRegex<_, ^Regex, ^Match>) : _ - when ^Match :> Match = - let parser str = - let m = (^Regex: (member TypedMatch: string -> ^Match) this.typedRegex,str) - if m.Success then - this.handler m |> Some - else None - let tokens = [to_s this.typedRegex] - (parser, tokens) - - member inline this.map mapper = - { typedRegex = this.typedRegex; handler = this.handler >> mapper } - - member inline this.asConst value = - { typedRegex = this.typedRegex; handler = fun _ -> value } - - let inline typedRegex< ^Regex, ^Match when ^Regex: (new: unit -> ^Regex) and ^Regex: (member TypedMatch: string -> ^Match) > : ValueTypedRegex< ^Match, ^Regex, ^Match > = - { typedRegex = new ^Regex(); handler = id } - - let inline asConst value (optionValue: ^X) = - (^X: (member asConst: _ -> _) optionValue,value) - - let inline internal construct (optionValue: ^X) = - (^X: (static member construct: _ -> _) optionValue) - diff --git a/src/FSharp.CommandLine/options.fs b/src/FSharp.CommandLine/options.fs deleted file mode 100755 index 834fc59..0000000 --- a/src/FSharp.CommandLine/options.fs +++ /dev/null @@ -1,435 +0,0 @@ -namespace FSharp.CommandLine - -[] -module rec Options = - open FSharp.Scanf.Optimized - open Microsoft.FSharp.Quotations - - open CommandOption - - /// specify how to treat options like ```-abcd``` - type SingleHyphenStyle = - /// treat ```-abcd``` as ```--abcd``` - | SingleLong - /// treat ```-abcd``` as ```-a bcd``` - | SingleShort - /// treat ```-abcd``` as ```-a -b -c -d``` - | MergedShort - - [] - type CommandOptionNoArgProvided<'a> = - | UseDefault of 'a - | JustFail - - [] - type CommandOptionKind<'a> = - | Flag of (bool -> 'a) - | TakingValueWith of CommandOptionNoArgProvided<'a> * (string -> 'a option) list - - type ICommandOption<'a> = - abstract member Parse: string list -> ('a * string list) - abstract member Config: CommandInfo -> CommandInfo - abstract member Summary: CommandOptionSummary - - /// represents a command option parser that tries to parse the arguments - /// and returns an optional result value. - [] - type CommandOption<'a> = { - baseSummary: CommandOptionSummary - kind: CommandOptionKind<'a> - style: SingleHyphenStyle - } - with - member this.Summary = - let self = this - { - this.baseSummary with - isMatch = - fun argv -> - match (parseImpl self argv) with - | (Some _, rem) -> Some rem - | (None, _) -> None - } - member this.Parse argv = parseImpl this argv - interface ICommandOption<'a option> with - member this.Summary = this.Summary - member this.Parse argv = parseImpl this argv - member this.Config cfg = - { - cfg with - options = this.Summary :: cfg.options - } - - /// represents a command option of which behavior and/or functionality are augmented. - /// (e.g. can parse multiple occurrence of the option at once) - [] - type AugmentedCommandOption<'a, 'b> = { - orig: ICommandOption<'a> - augmenter: ICommandOption<'a> -> Args -> ('b * Args) - } - with - interface ICommandOption<'b> with - member this.Summary = this.orig.Summary - member this.Parse argv = this.augmenter this.orig argv - member this.Config cfg = (this.orig :> ICommandOption<_>).Config cfg - - let inline private defaultCO () = - { - baseSummary = - { - names = []; - description = ""; - isFlag = false; - paramNames = []; - isMatch = fun _ -> None - genSuggestions = (fun _ -> []) - }; - kind = TakingValueWith (JustFail, []); - style = MergedShort - } - - let inline private defaultCF () = - { - baseSummary = - { - names = []; - description = ""; - isFlag = true; - paramNames = []; - isMatch = fun _ -> None - genSuggestions = (fun _ -> []) - }; - kind = Flag id; - style = MergedShort - } - - - module ReservedCommandOptions = - let helpOption = - { - baseSummary = - { - names = ["?"; "h"; "help"] - description = "display this help usage." - isFlag = false - paramNames = [] - isMatch = fun _ -> None - genSuggestions = (fun _ -> []) - } - kind = Flag id - style = MergedShort - } - - let suggestOption = - { - baseSummary = - { - names = ["generate-suggestions"; "generate-suggestions-incomplete"] - description = "" - isFlag = false - paramNames = [["name"]] - isMatch = fun _ -> None - genSuggestions = (fun _ -> []) - } - kind = TakingValueWith (UseDefault "zsh", [Some]) - style = MergedShort - } - - [] - type CommandOptionBuilder<'a>(dc: unit -> CommandOption<'a>) = - member __.For (_, _) = failwith "Not supported" - member __.Yield _ = dc () - /// required. - /// specifies the option's names. hyphens should not be included, - /// as they will automatically be handled depending on - /// the length of the name and optionally the `style` command. - [] - member __.Names (co, x) = { co with baseSummary = { co.baseSummary with names = x } } - [] - member __.Description (co, x) = { co with baseSummary = { co.baseSummary with description = x } } - /// required for command option. - /// specifies the format of the argument. for example: - /// `takes (format("%s").map(fun str -> someFunc str))` - [] - member inline __.Takes (co: CommandOption<'a>, x) = - let (f, ts) = construct x in - { co with - kind = - match co.kind with - | TakingValueWith (d, xs) -> TakingValueWith (d, List.append xs [f]) - | _ -> TakingValueWith (JustFail, [f]); - baseSummary = - { co.baseSummary with - paramNames = ts :: co.baseSummary.paramNames - } - } - /// `takesFormat fmt (fun .. -> ..)` is a shorthand for - /// `takes (format(fmt).map(fun .. -> ..))`. - [] - member inline __.TakesFormat (co: CommandOption<_>, fmt: PrintfFormat<_,_,_,_,_>, []mapper: Expr<_ -> _>) = - let mf x = (FuncHelper.compileFunc mapper) x in - let pns = FuncHelper.getFirstArgumentName mapper in - let x = - { format = fmt; handler = mf; paramNames = pns } - let (f, ts) = construct x in - { co with - kind = - match co.kind with - | TakingValueWith (d, xs) -> TakingValueWith (d, List.append xs [f]) - | _ -> TakingValueWith (JustFail, [f]); - baseSummary = - { co.baseSummary with - paramNames = ts :: co.baseSummary.paramNames - } - } - /// optional. - /// makes the option's argument optional, and specifies the default value - /// that will be used when the argument is not provided. - [] - member __.DefaultValue (co: CommandOption<'a>, value: 'a) = - { co with - kind = - match co.kind with - | TakingValueWith (_, xs) -> TakingValueWith (UseDefault value, xs) - | x -> x - } - /// optional. - /// specifies the command suggestions this option will generate. - [] - member __.Suggests (co, f) = { co with baseSummary = { co.baseSummary with genSuggestions=f } } - /// optional. - /// specify how to treat options like ```-abcd```. - /// the default value is `MergedShort`. - [] - member __.Style (co, st) = { co with style = st } - - let commandOption<'a> = CommandOptionBuilder<'a> defaultCO - let commandFlag = CommandOptionBuilder defaultCF - - type Command = - /// short-form definition of command option - static member inline option (_names, _format, ?_descr, ?defVal, ?_style) = - let mutable co = - commandOption { - names _names - takes (format _format) - description (_descr ?| "") - style (_style ?| SingleHyphenStyle.MergedShort) - } - defVal |> Option.iter (fun x -> co <- commandOption<_>.DefaultValue(co, x)) - co - - /// short-form definition of command flag - static member inline flag (_names, ?_descr, ?_style) = - commandFlag { - names _names - description (_descr ?| "") - style (_style ?| SingleHyphenStyle.MergedShort) - } - - type private RefinedToken = - | RFlag of string - | RFlagDisable of string - | RFlagAndValue of string * string - | RMaybeCombinedFlag of string - | RMaybeCombinedFlagAndValue of string * string - | RValue of string - | RIgnoreAfter - with - override this.ToString() = - match this with - | RFlag s -> sprintf "--%s" s - | RFlagDisable s -> sprintf "-%s-" s - | RFlagAndValue (s, v) -> sprintf "--%s=%s" s v - | RMaybeCombinedFlag s -> sprintf "-%s" s - | RMaybeCombinedFlagAndValue (s, v) -> sprintf "-%s=%s" s v - | RValue s -> s - | RIgnoreAfter -> "--" - - let private optionForms = [ - tryKsscanf "--" (fun () -> RIgnoreAfter) - tryKsscanf "-%c" (RFlag << to_s); - tryKsscanf "-%c=%s" (Tuple.map2 to_s id >> RFlagAndValue); - tryKsscanf "--%s=%s" RFlagAndValue; - tryKsscanf "/%s=%s" RFlagAndValue; - tryKsscanf "--%s" RFlag; - tryKsscanf "-%c+" (RFlag << to_s); - tryKsscanf "-%c-" (RFlagDisable << to_s); - tryKsscanf "-%s=%s" RMaybeCombinedFlagAndValue; - tryKsscanf "-%s" RMaybeCombinedFlag; - tryKsscanf "/%s" RFlag; - tryKsscanf "%s" RValue - ] - - let rec private tokenize argv = - seq { - if List.isEmpty argv then - yield! Seq.empty - else - let (h, t) = (List.head argv, List.tail argv) - let ro = optionForms |> List.map (fun f -> f h) - |> List.choose (function Ok x -> Some x | _ -> None) - |> List.tryHead - if Option.isSome ro then - yield ro.Value; - yield! - match ro.Value with - | RIgnoreAfter -> t |> Seq.map RValue - | _ -> tokenize t - else - yield! Seq.empty - } - - module CommandOption = - /// gets the arguments which look like (will potentially be recognized by the parser as) - /// a command option. - let getRemainingOptions argv = - argv |> tokenize |> List.ofSeq - |> List.choose (function RIgnoreAfter | RValue _ -> None | x -> Some x) - |> List.map to_s - - let internal parseImpl (opt: CommandOption<'a>) argv = - let inline isSingle s = String.length s = 1 - let inline matches x = opt.baseSummary.names |> List.contains x - let shortNames = opt.baseSummary.names |> List.filter isSingle - let opf msg = OptionParseFailed(opt.baseSummary, msg) - - let tokens = tokenize argv |> List.ofSeq - let rec find ts = - match opt.kind with - | Flag f -> - let inline f x = f x |> Some - match ts with - | RFlag x :: rest when matches x -> (f true, rest) - | RFlagDisable x :: rest when matches x -> (f false, rest) - | RFlagAndValue (x, _) :: _ when matches x -> - sprintf "'%s' is a flag and does not take an argument" x |> opf |> raise - | RMaybeCombinedFlag xs :: rest & x :: _ -> - match opt.style with - | MergedShort when shortNames |> List.exists xs.Contains -> - let c = shortNames |> List.find xs.Contains - (f true, RMaybeCombinedFlag (xs.Replace(c, "")) :: rest) - | SingleLong when matches xs -> (f true, rest) - | SingleShort when shortNames |> List.exists xs.StartsWith -> - sprintf "'%c' is a flag and does not take an argument" (xs.[0]) |> opf |> raise - | _ -> find rest |> Tuple.map2 id (fun rest' -> x :: rest') - | RMaybeCombinedFlagAndValue (xs, v) :: rest & x :: _ -> - match opt.style with - | MergedShort when shortNames |> List.exists xs.Contains -> - let c = shortNames |> List.find xs.Contains - if shortNames |> List.exists xs.EndsWith then - sprintf "'%s' is a flag and does not take an argument" c |> opf |> raise - else - (f true, RMaybeCombinedFlagAndValue(xs.Replace(c, ""), v) :: rest) - | SingleLong when matches xs -> - sprintf "'%s' is a flag and does not take an argument" xs |> opf |> raise - | SingleShort -> sprintf "invalid option: '-%s=%s'" xs v |> opf |> raise - | _ -> find rest |> Tuple.map2 id (fun rest' -> x :: rest') - | x :: rest -> find rest |> Tuple.map2 id (fun rest' -> x :: rest') - | [] -> (None, []) - | TakingValueWith (na, fs) -> - let inline tryReturn v name = - match (fs |> List.map (fun f -> f v) |> List.choose id |> List.tryHead) with - | Some x -> Some x - | None -> - sprintf "the value '%s' is invalid for the option '%s'" v name |> opf |> raise - let inline tryDefault name = - match na with - | UseDefault x -> Some x - | JustFail -> - sprintf "a value is missing for the option '%s'" name |> opf |> raise - match ts with - | RFlag x :: RValue v :: rest - | RFlagAndValue (x, v) :: rest when matches x -> (tryReturn v x, rest) - | RFlag x :: rest when matches x -> (tryDefault x, rest) - | RFlagDisable x :: _ when matches x -> - sprintf "a value is missing for the option '%s'" x |> opf |> raise - | RMaybeCombinedFlag xs :: RValue v :: rest & x :: _ :: _-> - match opt.style with - | MergedShort when shortNames |> List.exists xs.EndsWith -> - let c = shortNames |> List.find xs.EndsWith - (tryReturn v c, RMaybeCombinedFlag (xs.Replace(c, "")) :: rest) - | MergedShort when shortNames |> List.exists xs.Contains -> - let c = shortNames |> List.find xs.Contains - (tryDefault c, RMaybeCombinedFlag (xs.Replace(c, "")) :: RValue v :: rest) - | SingleShort when shortNames |> List.exists xs.StartsWith -> - let c = shortNames |> List.find xs.StartsWith - let v' = xs.Substring(1) - (tryReturn v' c, RValue v :: rest) - | SingleLong when matches xs -> - (tryReturn v xs, rest) - | _ -> find rest |> Tuple.map2 id (fun rest' -> x :: RValue v :: rest') - | RMaybeCombinedFlagAndValue (xs, v) :: rest & x :: _ -> - match opt.style with - | MergedShort when shortNames |> List.exists xs.EndsWith -> - let c = shortNames |> List.find xs.EndsWith - (tryReturn v c, RMaybeCombinedFlag (xs.Replace(c, "")) :: rest) - | MergedShort when shortNames |> List.exists xs.Contains -> - let c = shortNames |> List.find xs.Contains - (tryDefault c, RMaybeCombinedFlagAndValue (xs.Replace(c, ""), v) :: rest) - | SingleLong when matches xs -> - (tryReturn v xs, rest) - | SingleShort -> sprintf "invalid option: '-%s=%s'" xs v |> opf |> raise - | _ -> find rest |> Tuple.map2 id (fun rest' -> x :: rest') - | x :: rest -> find rest |> Tuple.map2 id (fun rest' -> x :: rest') - | [] -> (None, []) - find tokens |> Tuple.map2 id (List.map to_s) - - /// given a command option and arguments, applies the parser to the arguments - /// and returns the parsed result and the remaining arguments. - let inline parse (opt: #ICommandOption<_>) argv = opt.Parse argv - - /// given a command option and arguments, applies the parser to the arguments until it fails - /// and returns the results and the remaining arguments. - let parseMany (opt: #ICommandOption<_>) argv = - let rec p xs = - seq { - yield! - match (opt.Parse xs) with - | (Some x, rest) -> - seq { yield (x, rest); yield! p rest } - | (None, _) -> - Seq.empty - } - let x = p argv - (x |> Seq.map fst |> List.ofSeq, x |> Seq.map snd |> Seq.tryLast ?| argv) - - /// given a command option, augments its functionality by modifying - /// its behavior. both the original command option and the arguments which - /// will be passed at the execution time are available. - let inline augment f c = { orig=c; augmenter=f } - let inline map f c = - let ac = augment (fun c args -> c.Parse args) c - { - orig=ac.orig; - augmenter=(fun o x -> ac.augmenter o x |> Tuple.map2 f id) - } - - /// given a command option, returns a new command option that parses - /// zero or more occurrence of that command option. - let inline zeroOrMore co = - co |> augment parseMany - - /// given a command option, returns a new command option that fails - /// if there are more than one occurrence of that command option. - let inline zeroOrExactlyOne co = - co |> zeroOrMore - |> map (function - | [] -> None - | x :: [] -> Some x - | _ -> - let msg = sprintf "the option '%s' should be provided only once" - (co.Summary.NameRepresentations |> List.head) - OptionParseFailed (co.Summary, msg) |> raise - ) - - /// given a command option, returns a new command option that returns - /// the specified default value if there is no occurence. - let inline whenMissingUse defaultValue co = - co |> map (function Some x -> x | None -> defaultValue) - - /// an active pattern to parse the arguments using the command option - /// and gets the result and the remaining arguments. - let inline (|OptionParse|_|) opt argv = - let (reso, argv') = parse opt argv - reso |> Option.map (fun x -> (x, argv')) \ No newline at end of file diff --git a/src/FSharp.Scanf/FSharp.Scanf.fsproj b/src/FSharp.Scanf/FSharp.Scanf.fsproj deleted file mode 100755 index 5d270db..0000000 --- a/src/FSharp.Scanf/FSharp.Scanf.fsproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - - netstandard2.0;netstandard1.6;net46;net45 - Type-safe scanf for F# - cannorin - - (c) cannorin 2017-2019 - https://github.com/cannorin/FSharp.CommandLine/tree/master/src/FSharp.Scanf - MIT - fsharp commandline console scanf - - - - - - - - - - - - - diff --git a/src/FSharp.Scanf/scanf.fs b/src/FSharp.Scanf/scanf.fs deleted file mode 100755 index b94fe61..0000000 --- a/src/FSharp.Scanf/scanf.fs +++ /dev/null @@ -1,436 +0,0 @@ -(* -The MIT License -Scanf.fs - type safe scanf -Copyright(c) 2018-2019 cannorin -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*) - -// original: http://www.fssnip.net/4I/title/sscanf-parsing-with-format-strings - -/// Scanf functions. -/// If the result type is 7-tuple or less, consider using `FSharp.Scanf.Optimized` module instead. -module FSharp.Scanf - -open System -open System.IO -open Microsoft.FSharp.Reflection - -let inline internal to_s x = x.ToString() - -let inline internal check f x = if f x then x else failwithf "format failure \"%s\"" x - -let inline internal parseDecimal x = Decimal.Parse(x, System.Globalization.CultureInfo.InvariantCulture) - -module Internal = - // type wrapper - [] - type ScanfTypeMarker<'t> = | ScanfTypeMarker - - [] - let parserChars = "bdisuxXoeEfFgGMcA" - - let inline internal formatIntegerStr str fmt = - match fmt with - | 'i' | 'd' | 'u' -> str - | 'x' -> str |> check (String.forall (fun c -> Char.IsLower c || Char.IsDigit c)) |> ((+) "0x") - | 'X' -> str |> check (String.forall (fun c -> Char.IsUpper c || Char.IsDigit c)) |> ((+) "0x") - | 'o' -> "0o" + str - | _ -> str - - let inline internal convertUnsafe fmt targetType str = - let str = formatIntegerStr str fmt - if targetType = typeof then box str - else if targetType = typeof then int32 str |> box - else if targetType = typeof then float str |> box - else if targetType = typeof then char str |> box - else if targetType = typeof then Boolean.Parse(str) |> box - else if targetType = typeof then int8 str |> box - else if targetType = typeof then uint8 str |> box - else if targetType = typeof then int16 str |> box - else if targetType = typeof then uint16 str |> box - else if targetType = typeof then uint32 str |> box - else if targetType = typeof then int64 str |> box - else if targetType = typeof then uint64 str |> box - else if targetType = typeof then float32 str |> box - else if targetType = typeof then parseDecimal str |> box - else if targetType = typeof then box () - else if targetType = typeof then bigint.Parse str |> box - else failwithf "Unsupported type '%s'" targetType.Name - - let inline internal typemarker<'t> : ScanfTypeMarker<'t> = ScanfTypeMarker - - // Compile-time resolved string-to-value parsers - type OptimizedConverter = - static member inline Convert (_: ScanfTypeMarker, _, _) = () - static member inline Convert (_: ScanfTypeMarker, s: string list, _) = Boolean.Parse(s.Head) - static member inline Convert (_: ScanfTypeMarker, s: string list, _) = s.Head - static member inline Convert (_: ScanfTypeMarker, s:string list, _) = char s.Head - static member inline Convert (_: ScanfTypeMarker, s: string list, formatters: char list) = - formatIntegerStr s.Head formatters.Head |> int8 - static member inline Convert (_: ScanfTypeMarker, s: string list, formatters: char list) = - formatIntegerStr s.Head formatters.Head |> uint8 - static member inline Convert (_: ScanfTypeMarker, s: string list, formatters: char list) = - formatIntegerStr s.Head formatters.Head |> int16 - static member inline Convert (_: ScanfTypeMarker, s: string list, formatters: char list) = - formatIntegerStr s.Head formatters.Head |> uint16 - static member inline Convert (_: ScanfTypeMarker, s: string list, formatters: char list) = - formatIntegerStr s.Head formatters.Head |> int32 - static member inline Convert (_: ScanfTypeMarker, s: string list, formatters: char list) = - formatIntegerStr s.Head formatters.Head |> uint32 - static member inline Convert (_: ScanfTypeMarker, s: string list, formatters: char list) = - formatIntegerStr s.Head formatters.Head |> int64 - static member inline Convert (_: ScanfTypeMarker, s: string list, formatters: char list) = - formatIntegerStr s.Head formatters.Head |> uint64 - static member inline Convert (_: ScanfTypeMarker, s: string list, formatters: char list) = - formatIntegerStr s.Head formatters.Head |> bigint.Parse - static member inline Convert (_: ScanfTypeMarker, s:string list, _) = float s.Head - static member inline Convert (_: ScanfTypeMarker, s:string list, _) = float32 s.Head - static member inline Convert (_: ScanfTypeMarker, s:string list, _) = parseDecimal s.Head - - let inline internal convertFast (typ: ScanfTypeMarker< ^t >) (s: string list) (formatter:char list) = - let inline call_2 (_: ScanfTypeMarker< ^Converter >, _: ScanfTypeMarker< ^x >) = - ((^Converter or ^x): (static member Convert: _*_*_ -> ^t) typ,s,formatter) - let inline call (a: ScanfTypeMarker<'a>, b: ScanfTypeMarker<'b>) = call_2 (a, b) - call (typemarker, typ) - - // 8-tuples or more are reprensented as `System.Tuple'7<_,_,_,_,_,_,_,System.Tuple<...>>` - // but it is impossible to handle them generically - type OptimizedConverter with - static member inline Convert (_: ScanfTypeMarker<'t1*'t2>, s: string list, fs: char list) = - convertFast typemarker<'t1> s fs, - convertFast typemarker<'t2> s.Tail fs.Tail - static member inline Convert (_: ScanfTypeMarker<'t1*'t2*'t3>, s: string list, fs: char list) = - convertFast typemarker<'t1> s fs, - convertFast typemarker<'t2> s.Tail fs.Tail, - convertFast typemarker<'t3> s.Tail.Tail fs.Tail.Tail - static member inline Convert (_: ScanfTypeMarker<'t1*'t2*'t3*'t4>, s: string list, fs: char list) = - convertFast typemarker<'t1> s fs, - convertFast typemarker<'t2> s.Tail fs.Tail, - convertFast typemarker<'t3> s.Tail.Tail fs.Tail.Tail, - convertFast typemarker<'t4> s.Tail.Tail.Tail fs.Tail.Tail.Tail - static member inline Convert (_: ScanfTypeMarker<'t1*'t2*'t3*'t4*'t5>, s: string list, fs: char list) = - convertFast typemarker<'t1> s fs, - convertFast typemarker<'t2> s.Tail fs.Tail, - convertFast typemarker<'t3> s.Tail.Tail fs.Tail.Tail, - convertFast typemarker<'t4> s.Tail.Tail.Tail fs.Tail.Tail.Tail, - convertFast typemarker<'t5> s.Tail.Tail.Tail.Tail fs.Tail.Tail.Tail.Tail - static member inline Convert (_: ScanfTypeMarker<'t1*'t2*'t3*'t4*'t5*'t6>, s: string list, fs: char list) = - convertFast typemarker<'t1> s fs, - convertFast typemarker<'t2> s.Tail fs.Tail, - convertFast typemarker<'t3> s.Tail.Tail fs.Tail.Tail, - convertFast typemarker<'t4> s.Tail.Tail.Tail fs.Tail.Tail.Tail, - convertFast typemarker<'t5> s.Tail.Tail.Tail.Tail fs.Tail.Tail.Tail.Tail, - convertFast typemarker<'t6> s.Tail.Tail.Tail.Tail.Tail fs.Tail.Tail.Tail.Tail.Tail - static member inline Convert (_: ScanfTypeMarker<'t1*'t2*'t3*'t4*'t5*'t6*'t7>, s: string list, fs: char list) = - convertFast typemarker<'t1> s fs, - convertFast typemarker<'t2> s.Tail fs.Tail, - convertFast typemarker<'t3> s.Tail.Tail fs.Tail.Tail, - convertFast typemarker<'t4> s.Tail.Tail.Tail fs.Tail.Tail.Tail, - convertFast typemarker<'t5> s.Tail.Tail.Tail.Tail fs.Tail.Tail.Tail.Tail, - convertFast typemarker<'t6> s.Tail.Tail.Tail.Tail.Tail fs.Tail.Tail.Tail.Tail.Tail, - convertFast typemarker<'t7> s.Tail.Tail.Tail.Tail.Tail.Tail fs.Tail.Tail.Tail.Tail.Tail.Tail - - // Creates a list of formatter characters from a format string, - // for example "(%s,%d)" -> ['s', 'd'] - let rec internal getFormatters xs = - match xs with - | '%' :: '%' :: xr -> getFormatters xr - | '%' :: x :: xr -> - if parserChars |> Seq.contains x then x :: getFormatters xr - else failwithf "Unsupported formatter '%%%c'" x - | _ :: xr -> getFormatters xr - | [] -> [] - - [] - type FormatStringPart = - | Placeholder of typ:char - | Literal of string - | Space - static member getFormatters(fmt: FormatStringPart list) = - let rec get = function - | Placeholder c :: rest -> c :: get rest - | _ :: rest -> get rest - | [] -> [] - get fmt - - let inline internal (<+>) h t = - match h, t with - | FormatStringPart.Literal s, FormatStringPart.Literal t :: rest -> - FormatStringPart.Literal (s+t) :: rest - | _ -> h :: t - - let rec internal parsePlaceholderImpl currentPos (str: string) = - let c = str.[currentPos] - let nextPos = currentPos + 1 - if Char.IsLetter c then - FormatStringPart.Placeholder c :: parseFormatImpl nextPos nextPos str - else if c = '%' then - FormatStringPart.Literal "%" <+> parseFormatImpl nextPos nextPos str - else failwithf "Unsupported formatter '%%%c'" c - - and internal parseFormatImpl startPos currentPos (str: string) = - if currentPos >= str.Length then - if currentPos = startPos then [] - else - let s = str.Substring(startPos, currentPos - startPos) - FormatStringPart.Literal s :: [] - else - let c = str.[currentPos] - if c = '%' then - let nextPos = currentPos + 1 - if currentPos = startPos then - parsePlaceholderImpl nextPos str - else - let s = str.Substring(startPos, currentPos - startPos) - FormatStringPart.Literal s <+> parsePlaceholderImpl nextPos str - else if c = ' ' || c = '\n' || c = '\r' || c = '\t' then - let mutable i = 1 - while currentPos + i < str.Length - && let c = str.[currentPos + i] in - c = ' ' || c = '\n' || c = '\r' || c = '\t' do i <- i+1 - let nextPos = currentPos + i - if currentPos = startPos then - FormatStringPart.Space :: parseFormatImpl nextPos nextPos str - else - let s = str.Substring(startPos, currentPos - startPos) - FormatStringPart.Literal s :: FormatStringPart.Space :: parseFormatImpl nextPos nextPos str - else - parseFormatImpl startPos (currentPos + 1) str - - let inline internal parseFormat (str: string) = - parseFormatImpl 0 0 str - - open FParsec - let inline (<++>) p1 p2 = p1 .>>. p2 |>> List.Cons - let inline strOf p = withSkippedString (fun s _ -> s) p - - let rec internal buildParser = function - | [] -> eof >>% [] - | FormatStringPart.Space :: rest -> - spaces1 >>. buildParser rest - | FormatStringPart.Literal lit :: rest -> - skipString lit >>. buildParser rest - | FormatStringPart.Placeholder c :: rest-> - let cont = buildParser rest - match c with - | 'b' -> (pstring "true" <|> pstring "false") <++> cont - | 'd' | 'i' -> many1Satisfy isDigit <++> cont - | 's' | 'A' -> - manyCharsTill anyChar (followedBy cont) .>>.? cont |>> List.Cons - | 'u' -> strOf puint64 <++> cont - | 'x' | 'X' -> manySatisfy isHex <++> cont - | 'o' -> manySatisfy isOctal <++> cont - | 'e' | 'E' | 'f' | 'F' | 'g' | 'G' -> - (skipStringCI "nan" >>% "NaN") - <|> (skipStringCI "infinity" <|> skipStringCI "inf" >>% "Infinity") - <|> (strOf pfloat) - <++> cont - | 'M' -> - many1Satisfy isDigit .>>.? opt (skipChar '.' >>? many1Satisfy isDigit) - |>> (fun (i, j) -> i + Option.defaultValue "" j) - <++> cont - | 'c' -> anyChar |>> string <++> cont - | c -> failwithf "Unsupported formatter '%%%c'" c - - let inline internal matchFormat fmt fmtStr str = - match run (buildParser fmt) str with - | Success (xs, _, _) -> xs - | Failure (msg, _, _) -> - failwithf "the input does not match the format '%s': %s" fmtStr msg - - // Extracts string matches and the format from a format string and a given string. - let getMatchesAndFormat (pf: PrintfFormat<_, _, _, _, _>) s = - let formatStr = pf.Value - let fmt = parseFormat formatStr - let groups = matchFormat fmt formatStr s - let formatters = FormatStringPart.getFormatters fmt - groups, formatStr, formatters - -open Internal - -type PrintfFormat<'a,'b,'c,'d,'e> with - member this.GetFormatterNames () = - let fs = this.Value.ToCharArray() - |> Array.toList |> getFormatters in - let print = function - | 's' -> "string" - | 'c' -> "char" - | 'b' -> "bool" - | 'i' | 'd' -> "int" - | 'u' -> "uint" - | 'x' -> "lowercase hex" - | 'X' -> "uppercase hex" - | 'o' -> "octal" - | 'f' | 'e' | 'E' | 'g' | 'G' -> "double" - | 'M' -> "decimal" - | 'A' -> "any type" - | x -> failwithf "Unsupported formatter '%%%c'" x - in - fs |> List.map print - - member this.PrettyTokenize names = - let fcs = this.Value.ToCharArray() |> Array.toList in - if (List.length names) < (fcs |> getFormatters |> List.length) then - failwith "Parameter count does not match to the format" - else - let rec replace = function - | [], _ -> [] - | cs, [] -> - cs |> List.map to_s - | '%' :: '%' :: cs, ns -> - replace (cs, ns) - | '%' :: c :: cs, n :: ns when parserChars |> Seq.contains c -> - n :: replace (cs, ns) - | c :: cs, ns -> - to_s c :: replace (cs, ns) - in - replace (fcs, names) - - member this.PrettyPrint names = this.PrettyTokenize names |> String.concat "" - -type ScanfTypeMarker<'t> = Internal.ScanfTypeMarker<'t> - -/// If the result type is 7-tuple or less, consider using `FSharp.Scanf.Optimized` module instead. -let ksscanf (pf: PrintfFormat<_,_,_,_,'t>) (cont: 't -> 'u) s : 'u = - let matches, formatStr, formatters = getMatchesAndFormat pf s - let value = - if typeof<'t> = typeof then - if s = formatStr then - box () :?> 't - else - failwith "Match failed" - else - if matches.Length = 1 then - convertUnsafe formatters.[0] typeof<'t> matches.[0] :?> 't - else - let targetTypes = FSharpType.GetTupleElements(typeof<'t>) - let values = - (formatters, targetTypes, matches) - |||> Seq.map3 convertUnsafe - |> Seq.toArray - FSharpValue.MakeTuple(values, typeof<'t>) :?> 't - cont value - -/// If the result type is 7-tuple or less, consider using `FSharp.Scanf.Optimized` module instead. -let inline tryKsscanf pf cont s = - try - ksscanf pf cont s |> Ok - with - | ex -> Error ex - -/// If the result type is 7-tuple or less, consider using `FSharp.Scanf.Optimized` module instead. -let inline sscanf pf s = - ksscanf pf id s - -/// If the result type is 7-tuple or less, consider using `FSharp.Scanf.Optimized` module instead. -let inline trySscanf pf s = - tryKsscanf pf id s - -/// If the result type is 7-tuple or less, consider using `FSharp.Scanf.Optimized` module instead. -let inline scanfn pf = - Console.ReadLine() |> sscanf pf - -/// If the result type is 7-tuple or less, consider using `FSharp.Scanf.Optimized` module instead. -let inline tryScanfn pf = - Console.ReadLine() |> trySscanf pf - -/// If the result type is 7-tuple or less, consider using `FSharp.Scanf.Optimized` module instead. -let inline kscanfn pf cont = - ksscanf pf cont <| Console.ReadLine() - -/// If the result type is 7-tuple or less, consider using `FSharp.Scanf.Optimized` module instead. -let inline tryKscanfn pf cont = - tryKsscanf pf cont <| Console.ReadLine() - -/// If the result type is 7-tuple or less, consider using `FSharp.Scanf.Optimized` module instead. -let inline fscanfn pf (tr: TextReader) = - tr.ReadLine() |> sscanf pf - -/// If the result type is 7-tuple or less, consider using `FSharp.Scanf.Optimized` module instead. -let inline tryFscanfn pf (tr: TextReader) = - tr.ReadLine() |> trySscanf pf - -/// If the result type is 7-tuple or less, consider using `FSharp.Scanf.Optimized` module instead. -let inline kfscanfn pf cont (tr: TextReader) = - ksscanf pf cont <| tr.ReadLine() - -/// If the result type is 7-tuple or less, consider using `FSharp.Scanf.Optimized` module instead. -let inline tryKfscanfn pf cont (tr: TextReader) = - tryKsscanf pf cont <| tr.ReadLine() - -// active pattern -let (|Sscanf|_|) (format:PrintfFormat<_,_,_,_,'t>) input = - trySscanf format input |> function | Ok x -> Some x | Error _ -> None - -/// Scanf functions, no reflection/boxing. About 6x-7x faster than unoptimized ones. -/// -/// Can only be used with up to 7 captures (i.e. the result type must be up to 7-tuples). -/// -/// If you implement a static member with signature `Convert: ScanfTypeMarker * string list * char list -> YourType`, -/// you can directly parse the string into that type by using `%A`. -/// -/// ``` -/// type A = A of string with -/// static member Convert (_: ScanfTypeMarker, ss: string list, _) = ss.[0] -/// -/// let a: A = sscanf "%A" "foo" -/// // val a : A = A "foo" -/// ``` -module Optimized = - type ScanfTypeMarker<'t> = Internal.ScanfTypeMarker<'t> - - /// If the result type is 8-tuple or more, it fails to typecheck. Use `FSharp.Scanf` module instead or try reducing the captures by applying `scanf` to the result string. - let inline ksscanf (pf: PrintfFormat<_,_,_,_,^t>) (cont: ^t -> 'u) s : 'u = - let matches, _, formatters = getMatchesAndFormat pf s - let strings = matches |> Seq.toList - convertFast typemarker< ^t > strings formatters |> cont - /// If the result type is 8-tuple or more, it fails to typecheck. Use `FSharp.Scanf` module instead or try reducing the captures by applying `scanf` to the result string. - let inline tryKsscanf pf cont s = - try - ksscanf pf cont s |> Ok - with - | ex -> Error ex - /// If the result type is 8-tuple or more, it fails to typecheck. Use `FSharp.Scanf` module instead or try reducing the captures by applying `scanf` to the result string. - let inline sscanf pf s = - ksscanf pf id s - /// If the result type is 8-tuple or more, it fails to typecheck. Use `FSharp.Scanf` module instead or try reducing the captures by applying `scanf` to the result string. - let inline trySscanf pf s = - tryKsscanf pf id s - /// If the result type is 8-tuple or more, it fails to typecheck. Use `FSharp.Scanf` module instead or try reducing the captures by applying `scanf` to the result string. - let inline scanfn pf = - Console.ReadLine() |> sscanf pf - /// If the result type is 8-tuple or more, it fails to typecheck. Use `FSharp.Scanf` module instead or try reducing the captures by applying `scanf` to the result string. - let inline tryScanfn pf = - Console.ReadLine() |> trySscanf pf - /// If the result type is 8-tuple or more, it fails to typecheck. Use `FSharp.Scanf` module instead or try reducing the captures by applying `scanf` to the result string. - let inline kscanfn pf cont = - ksscanf pf cont <| Console.ReadLine() - /// If the result type is 8-tuple or more, it fails to typecheck. Use `FSharp.Scanf` module instead or try reducing the captures by applying `scanf` to the result string. - let inline tryKscanfn pf cont = - tryKsscanf pf cont <| Console.ReadLine() - /// If the result type is 8-tuple or more, it fails to typecheck. Use `FSharp.Scanf` module instead or try reducing the captures by applying `scanf` to the result string. - let inline fscanfn pf (tr: TextReader) = - tr.ReadLine() |> sscanf pf - /// If the result type is 8-tuple or more, it fails to typecheck. Use `FSharp.Scanf` module instead or try reducing the captures by applying `scanf` to the result string. - let inline tryFscanfn pf (tr: TextReader) = - tr.ReadLine() |> trySscanf pf - /// If the result type is 8-tuple or more, it fails to typecheck. Use `FSharp.Scanf` module instead or try reducing the captures by applying `scanf` to the result string. - let inline kfscanfn pf cont (tr: TextReader) = - ksscanf pf cont <| tr.ReadLine() - /// If the result type is 8-tuple or more, it fails to typecheck. Use `FSharp.Scanf` module instead or try reducing the captures by applying `scanf` to the result string. - let inline tryKfscanfn pf cont (tr: TextReader) = - tryKsscanf pf cont <| tr.ReadLine() diff --git a/src/abstractions.fs b/src/abstractions.fs new file mode 100644 index 0000000..2b916cc --- /dev/null +++ b/src/abstractions.fs @@ -0,0 +1,53 @@ +namespace FSharp.CommandLine.Internals + +type State<'Args, 'a> = 'Args -> ('a * 'Args) + +type StateConfig<'Config, 'Args, 'a> = { + config: 'Config -> 'Config + func: State<'Args, 'a> +} + +module StateConfig = + let inline scbind (f: 'a -> StateConfig<'Config, 'Args, 'b>) (g: 'Config -> 'Config) (m: StateConfig<'Config, 'Args, 'a>) = + { + config = m.config >> g + func = + fun args -> + let (a, args) = m.func args + (f a).func args + } + + let inline returnValue (a: 'a) : StateConfig<_, _, 'a> = + { + config = id + func = fun args -> (a, args) + } + + let inline returnWith (f: unit -> 'a) : StateConfig<_, _, 'a> = + { + config = id + func = fun args -> (f(), args) + } + + let inline bind f m = m |> scbind f id + + let inline mapConfig g m = m |> scbind returnValue g + + let inline map f m = m |> bind (f >> returnValue) + + let inline zip (m: StateConfig<_, _, 'a>) (n: StateConfig<_, _, 'b>) (f: 'a -> 'b -> 'c) = + scbind (fun a -> + { + config = id + func = fun args -> let (b, args) = n.func args in (f a b, args) + }) + n.config + m + + let inline combine (a: StateConfig<_,_,_>) (b: StateConfig<_,_,_>) = zip a b (fun _ b -> b) + + let args = + { + config = id + func = fun args -> (args, args) + } diff --git a/src/basictypes.fs b/src/basictypes.fs new file mode 100644 index 0000000..3a9f2f6 --- /dev/null +++ b/src/basictypes.fs @@ -0,0 +1,112 @@ +namespace FSharp.CommandLine + +open FSharp.CommandLine.Internals +open System.Runtime.CompilerServices + +type Args = string list + +type HelpElement = + /// prints `usage: $(command name) $(args)`. + | HelpUsage + /// prints `usage: $(command name) $(args)` of which `args` can be customized. + | HelpUsageCustomArgs of args: string list + /// prints a string. + | HelpRawString of text: string + /// prints the infomation of all the subcommands. + | HelpAllSubcommands + /// prints the infomation of the specified subcommands. + | HelpSpecificSubcommands of names: string list + /// prints the infomation of all the command options. + | HelpAllOptions + /// prints the infomation of the specified command options. + | HelpSpecificOptions of namesWithoutHyphen: string list + /// prints elements as a section. the content will be indented. + /// nested sections make the indentation deeper. + | HelpSection of sectionName: string * sectionBody: seq + /// prints an empty line. + | HelpEmptyLine + +type HelpText = HelpElement seq + +type CommandSuggestion = + /// suggests a set of string. + | Values of string list + /// suggests a set of string with description. + | ValuesWithDescription of (string * string) list + /// suggests files optionally with pattern. + | Files of pattern: string option + /// suggests directories. + | Directories of pattern: string option + /// suggests a command option. + | OptionSuggestion of (string list) * string + /// prints a message. + | Message of string + +type CommandOptionSummary = { + names: string list; + description: string; + isFlag: bool; + paramNames: (string list) list + isMatch: string list -> string list option + genSuggestions: string option -> CommandSuggestion list +} +with + member this.Param = + let rec print eq xss = + let heads = xss |> List.map List.tryHead + if heads |> List.exists Option.isSome then + let isOptional = heads |> List.exists Option.isNone + let groups = xss |> List.filter (List.isEmpty >> not) + |> List.groupBy List.head + |> List.map (fun (g, xs) -> sprintf "%s%s" g (xs |> List.map List.tail |> print "")) + let s = + if List.length groups > 1 then + let s = groups |> String.concat "|" + if isOptional then s else sprintf "{%s}" s + else + groups |> String.concat "" + if isOptional then sprintf "[%s%s]" eq s else sprintf "%s%s"eq s + else + "" + in print "=" (this.paramNames |> List.rev) + + member this.NameRepresentations = + this.names |> List.collect (function + | x when x.Length = 1 -> + [ "-"; "/" ] |> List.map (fun prefix -> sprintf "%s%s" prefix x) + | x -> + [ "--"; "/" ] |> List.map (fun prefix -> sprintf "%s%s" prefix x)) + + member this.Print () = + let o x = if this.isFlag then sprintf "%s[+|-]" x else sprintf "%s%s" x this.Param + ((this.NameRepresentations |> List.filter (String.startsWith "-") |> String.concat ", " |> o), this.description) + +type CommandSummary = { + name: string; + displayName: string option; + description: string; + paramNames: (string list) option + help: HelpText option + genSuggestions: Args -> CommandSuggestion list +} + +type CommandInfo = { + summary: CommandSummary + options: CommandOptionSummary list + subcommands: Command list +} +and Command<'a> = StateConfig + +type CommandInfo with + static member empty = + { + summary = Unchecked.defaultof + options = [] + subcommands = [] + } + +[] +type ICommandExt() = + [] + static member inline Summary(x: Command<_>) = + (x.config CommandInfo.empty).summary diff --git a/src/builders.fs b/src/builders.fs new file mode 100644 index 0000000..fb84d71 --- /dev/null +++ b/src/builders.fs @@ -0,0 +1,244 @@ +namespace FSharp.CommandLine.Internals + +open FSharp.CommandLine +open Microsoft.FSharp.Quotations + +module internal Helpers = + let inline snoc x xs = seq { yield! xs; yield x } + + let inline mapSummary f co = + co |> Command.mapInfo (fun cfg -> { cfg with summary = f cfg.summary }) + +open Helpers + +type HelpBuilder() = + member inline __.For (_, _) = failwith "Not supported" + member inline __.Yield _ : HelpElement seq = Seq.empty + + /// prints `usage: $(command name) $(args)`. + [] + member inline __.Usage xs = xs |> snoc HelpUsage + + /// prints `usage: $(command name) $(args)` of which `args` can be customized. + [] + member inline __.UsageWithCustomArgs (xs, argNames) = xs |> snoc (HelpUsageCustomArgs argNames) + + /// prints a string. + [] + member inline __.RawText (xs, str) = xs |> snoc (HelpRawString str) + + /// prints the infomation of all the subcommands. + [] + member inline __.Subcommands xs = xs |> snoc HelpAllSubcommands + + /// prints the infomation of the specified subcommands. + [] + member inline __.SpecificSubcommands (xs, cmds) = xs |> snoc (HelpSpecificSubcommands cmds) + + /// prints the infomation of all the command options. + [] + member inline __.Options xs = xs |> snoc HelpAllOptions + + /// prints the infomation of the specified command options. + [] + member inline __.SpecificOptions (xs, opts) = xs |> snoc (HelpSpecificOptions opts) + + /// prints elements as a section. the content will be indented. + /// nested sections make the indentation deeper. + [] + member inline __.Section (xs, sectionName, section) = xs |> snoc (HelpSection(sectionName, section)) + + /// prints elements as a section when the condition holds. the content will be indented. + /// nested sections make the indentation deeper. + [] + member inline __.ConditionalSection (xs, sectionName, cond, section) = + if cond() then + xs |> snoc (HelpSection(sectionName, section)) + else + xs + + /// prints an empty line. + [] + member inline __.EmptyLine xs = xs |> snoc HelpEmptyLine + +type CommandOptionBuilder<'a>(dc: unit -> CommandOption<'a>) = + member __.For (_, _) = failwith "Not supported" + member __.Yield _ = dc () + + /// required. + /// specifies the option's names. hyphens should not be included, + /// as they will automatically be handled depending on + /// the length of the name and optionally the `style` command. + [] + member __.Names (co, x) = { co with baseSummary = { co.baseSummary with names = x } } + + [] + member __.Description (co, x) = { co with baseSummary = { co.baseSummary with description = x } } + + /// required for command option. + /// specifies the format of the argument. for example: + /// `takes (format("%s").map(fun str -> someFunc str))` + [] + member inline __.Takes (co: CommandOption<'a>, x) = + let (f, ts) = construct x in + { co with + kind = + match co.kind with + | TakingValueWith (d, xs) -> TakingValueWith (d, List.append xs [f]) + | _ -> TakingValueWith (JustFail, [f]); + baseSummary = + { co.baseSummary with + paramNames = ts :: co.baseSummary.paramNames + } + } + + /// `takesFormat fmt (fun .. -> ..)` is a shorthand for + /// `takes (format(fmt).map(fun .. -> ..))`. + [] + member inline __.TakesFormat (co: CommandOption<_>, fmt: PrintfFormat<_,_,_,_,_>, []mapper: Expr<_ -> _>) = + let mf x = (FuncHelper.compileFunc mapper) x in + let pns = FuncHelper.getFirstArgumentName mapper in + let x = + { format = fmt; handler = mf; paramNames = pns } + let (f, ts) = construct x in + { co with + kind = + match co.kind with + | TakingValueWith (d, xs) -> TakingValueWith (d, List.append xs [f]) + | _ -> TakingValueWith (JustFail, [f]); + baseSummary = + { co.baseSummary with + paramNames = ts :: co.baseSummary.paramNames + } + } + + /// optional. + /// makes the option's argument optional, and specifies the default value + /// that will be used when the argument is not provided. + [] + member __.DefaultValue (co: CommandOption<'a>, value: 'a) = + { co with + kind = + match co.kind with + | TakingValueWith (_, xs) -> TakingValueWith (UseDefault value, xs) + | x -> x + } + + /// optional. + /// specifies the command suggestions this option will generate. + [] + member __.Suggests (co, f) = { co with baseSummary = { co.baseSummary with genSuggestions=f } } + + /// optional. + /// specify how to treat options like ```-abcd```. + /// the default value is `MergedShort`. + [] + member __.Style (co, st) = { co with style = st } + +type CommandBuilder() = + member inline __.Bind (c, f) = Command.bind f c + member inline __.Return x = Command.returnValue x + member inline __.For (c, f) = Command.bind f c + member inline __.Yield x = Command.returnValue x + member inline __.ReturnFrom (x: Command<_>) = x + member inline __.Combine (a, b) = Command.combine a b + member inline __.Combine (f, b) = Command.combine (f()) b + member inline __.Combine (a, f) = Command.combine a (f()) + member inline __.Zero () = Command.returnValue () + member inline __.Delay (f: unit -> Command<_>) = f + member inline __.Undelay x : Command<_> = x() + member inline __.Run f : Command<_> = f() + member inline __.TryWith (f, h) = try f() with exn -> h exn + member inline __.TryFinally (f, h) = try f() finally h() + member inline this.Using (disp: #System.IDisposable, m) = this.TryFinally(this.Delay(fun () -> m disp), fun () -> dispose disp) + member inline this.While (cond, m: unit -> Command<_>) = + let rec loop cond m : Command<_> = + if cond () then this.Combine(this.Undelay m, loop cond m) + else this.Zero () + loop cond m + member inline this.For (xs: #seq<_>, exec) = + this.Using( + (xs :> seq<_>).GetEnumerator(), + fun en -> + this.While( + en.MoveNext, + this.Delay(fun () -> exec en.Current)) + ) + + /// uses a command option. + [] + member inline __.UseOption (co: Command<'a>, opt: #ICommandOption<'b>, f: 'a -> 'b -> 'c) = + { + config = co.config >> opt.Config + func = + fun args -> + let (a, args) = co.func args + let (b, args) = opt.Parse args + (f a b, args) + } + + /// imports a command to this command. will inherit options and other metadatas. + [] + member inline __.ImportCommand (c1, c2, f) : Command<_> = Command.zip c1 c2 f + + /// required. sets the name of the command. will also be used when this command is + /// a subcommand of the other one. + [] + member inline __.Name (co, x) = + co |> mapSummary (fun s -> { s with name = x }) + + /// optional. sets the name of the command that will be displayed in the help text. + /// the one speficied by `name` will be used if not specified. + [] + member inline __.DisplayName (co, n) = + co |> mapSummary (fun s -> { s with displayName = Some n }) + + /// required. sets the description of the command. + [] + member inline __.Description (co, x) = + co |> mapSummary (fun s -> { s with description = x }) + + /// optional. speficies the suggestions it will generate. + [] + member inline __.Suggests (co: Command<_>, f) = + co |> mapSummary (fun s -> { s with genSuggestions = f }) + + /// optional. customizes the help text. + [] + member inline __.Help (co: Command<_>, xs: HelpElement seq) = + co |> mapSummary (fun s -> { s with help = Some xs }) + + /// optional. specifies the subcommands. + [] + member inline __.Subcommands (co, xs) = { + config = + fun cfg -> + let cfg = co.config cfg + { cfg with subcommands = cfg.subcommands @ xs } + func = + fun args -> + let sc = + match args with + | h :: _ -> + List.tryFind (fun (x:Command<_>) -> x.Summary().name = h) xs + | _ -> None + if sc.IsSome then + let (code, _) = sc.Value.func (List.tail args) + RequestExit code |> raise + else + co.func args + } + + +namespace FSharp.CommandLine + +open FSharp.CommandLine.Internals + +[] +module Builders = + let helpText = new HelpBuilder() + let commandOption<'a> = + new CommandOptionBuilder<'a>(fun () -> CommandOption<'a>.defaultOption) + let commandFlag = + new CommandOptionBuilder<_>(fun () -> CommandOption.defaultFlag) + let command = CommandBuilder () \ No newline at end of file diff --git a/src/commands.fs b/src/commands.fs new file mode 100644 index 0000000..f523bc0 --- /dev/null +++ b/src/commands.fs @@ -0,0 +1,80 @@ +namespace FSharp.CommandLine + +open System +open FSharp.CommandLine.Generators +open FSharp.CommandLine.Internals + +module Command = + let args : Command = StateConfig.args + let bind (f: 'a -> Command<'b>) (m: Command<'a>) : Command<'b> = StateConfig.bind f m + let returnValue (x: 'a) : Command<'a> = StateConfig.returnValue x + let returnWith (f: unit -> 'a) : Command<'a> = StateConfig.returnWith f + let map (f: 'a -> 'b) (m: Command<'a>) : Command<'b> = StateConfig.map f m + let mapInfo (f: CommandInfo -> CommandInfo) (m: Command<'a>) : Command<'a> = StateConfig.mapConfig f m + let zip (a: Command<'a>) (b: Command<'b>) (f: 'a -> 'b -> 'c) : Command<'c> = StateConfig.zip a b f + let combine (a: Command<'a>) (b: Command<'b>) : Command<'b> = StateConfig.combine a b + + let private runMain args (cmd: Command) = + match args |> List.ofArray with + | CommandOption.Parse ReservedCommandOptions.suggestOption (sug, rest) -> + Suggestions.generate rest cmd + |> Suggestions.print (SuggestionBackends.findByName sug) + |> printfn "%A" + (0, []) + | CommandOption.Parse ReservedCommandOptions.helpOption (true, rest) -> + for line in Help.generate rest cmd do + printfn "%s" line + (0, []) + | args -> + cmd.func args + + #if DEBUG + let runAsEntryPointDebug args (cmd: Command) = runMain args cmd + #endif + + /// executes the command as an entry point: + /// + /// ``` + /// [] + /// let main argv = + /// Command.runAsEntryPoint argv command + /// ``` + let runAsEntryPoint args (cmd: Command) = + try + runMain args cmd |> fst + with + | RequestExit code -> code + | RequestShowHelp msg -> + cprintfn ConsoleColor.Red "error: %s\n" msg + for line in Help.generate (args |> List.ofArray) cmd do + printfn "%s" line + -1 + | OptionParseFailed (_, msg) + | CommandExecutionFailed msg -> cprintfn ConsoleColor.Red "error: %s\n" msg; -1 + | e -> reraise' e + + /// stops the execution immediately and then exits with the specified code. + let exit code = RequestExit code |> raise + + /// stops the execution immediately and then exits with the specified error message and code `-1`. + let fail msg = CommandExecutionFailed msg |> raise + + /// stops the execution immediately and then exits with the specified error message and code `-1`. + let failf fmt = Printf.kprintf (fun msg -> CommandExecutionFailed msg |> raise ) fmt + + /// if there are remaining unknown options, then stops the execution + /// immediately and then exits with code `-1`. + let failOnUnknownOptions () = + args |> bind (fun argv -> + let unknownOptions = CommandOption.getRemainingOptions argv + if List.isEmpty unknownOptions then returnValue () + else + unknownOptions + |> List.head + |> sprintf "unknown option: '%s'" + |> CommandExecutionFailed + |> raise + ) + + /// shows the error message and the help of the current (sub)command, then exits with code `-1`. + let failShowingHelp message = RequestShowHelp message |> raise \ No newline at end of file diff --git a/src/common/Version.fs b/src/common/Version.fs deleted file mode 100644 index c767a7a..0000000 --- a/src/common/Version.fs +++ /dev/null @@ -1,11 +0,0 @@ -// Auto-Generated by FAKE; do not edit -namespace System -open System.Reflection - -[] -[] -do () - -module internal AssemblyVersionInformation = - let [] AssemblyVersion = "3.3.3805.29705" - let [] AssemblyFileVersion = "3.3.3805.29705" diff --git a/src/FSharp.CommandLine/exceptions.fs b/src/exceptions.fs old mode 100755 new mode 100644 similarity index 100% rename from src/FSharp.CommandLine/exceptions.fs rename to src/exceptions.fs diff --git a/src/extensions.fs b/src/extensions.fs new file mode 100644 index 0000000..58c792f --- /dev/null +++ b/src/extensions.fs @@ -0,0 +1,22 @@ +namespace FSharp.CommandLine.Internals + +open Microsoft.FSharp.Quotations +open Microsoft.FSharp.Quotations.Patterns +open Microsoft.FSharp.Linq.RuntimeHelpers + +type FuncHelper = private | FuncHelper with + static member compileFunc (x: Expr<'a -> 'b>) = + LeafExpressionConverter.EvaluateQuotation x :?> ('a -> 'b) + + static member getFirstArgumentName (x: Expr<'a -> 'b>) = + let rec gn tupleArgName = function + | Let (v, TupleGet(Var tn, index), body) when (tupleArgName = tn.Name) -> + (index, v.Name) :: gn tupleArgName body + | _ -> [] + in + match x with + | Lambda (v, e) -> + match (gn v.Name e) with + | [] -> Some [v.Name] + | xs -> xs |> List.sortBy fst |> List.map snd |> Some + | _ -> None diff --git a/src/FSharp.CommandLine/generators.fs b/src/generators.fs old mode 100755 new mode 100644 similarity index 92% rename from src/FSharp.CommandLine/generators.fs rename to src/generators.fs index 8ee45e4..7023f58 --- a/src/FSharp.CommandLine/generators.fs +++ b/src/generators.fs @@ -14,7 +14,7 @@ module Generators = match config.subcommands |> List.tryFind (fun sc -> sc.Summary().name = List.head args) with | Some sc -> dig (List.tail args) sc | None -> (cmd, args) - + let private getCommandInfo (cmd: Command<_>) = let config = (cmd.config CommandInfo.empty) (config.summary, config.subcommands, config.options) @@ -40,7 +40,7 @@ module Generators = yield! (bLines.Tail |> List.map (sprintf "%s %s" indent)) } - let private genParamNames pns subs options = + let private genParamNames pns subs options = match pns with | Some xs -> xs |> String.concat " " | None -> @@ -51,7 +51,7 @@ module Generators = | (false, false) -> "[options] " /// given a help generator and a command, generates the help text. - let interpret (generator: Command<_> -> #seq) (cmd: Command<_>) = + let interpret (generator: Command<_> -> HelpText) (cmd: Command<_>) = let (smry, scs, opts) = getCommandInfo cmd let dn = smry.displayName ?| smry.name let rec print elems = @@ -103,26 +103,21 @@ module Generators = generator cmd |> print /// a default help generator for the command. - let defaultGenerator (cmd: Command<_>) = + let defaultGenerator (cmd: Command<_>) : HelpText = let (smry, scs, opts) = getCommandInfo cmd - helpText { - defaultUsage - emptyLine - text smry.description - emptyLine - conditionalSection "commands" (fun () -> scs |> List.isEmpty |> not) ( - helpText { - allSubcommands - emptyLine - } - ) - conditionalSection "options" (fun () -> opts |> List.isEmpty |> not) ( - helpText { - allOptions - } - ) + seq { + yield HelpUsage + yield HelpEmptyLine + yield HelpRawString smry.description + yield HelpEmptyLine + if scs |> List.isEmpty |> not then + yield HelpAllSubcommands + yield HelpEmptyLine + if opts |> List.isEmpty |> not then + yield HelpAllOptions + yield HelpEmptyLine } - + /// generates a help text from the arguments and the command. let generate args cmd = let (cmd, _) = dig args cmd @@ -187,7 +182,7 @@ module Generators = | Values xs -> "_values" :: "-w" :: "'values'" :: (xs |> List.map (escape >> quote)) | ValuesWithDescription xs -> - "_values" :: "-w" :: "'values'" :: (xs |> List.map (fun (v, descr) -> sprintf "%s[%s]" v descr) + "_values" :: "-w" :: "'values'" :: (xs |> List.map (fun (v, descr) -> sprintf "%s[%s]" v descr) |> List.map (escape >> quote)) | Files (Some pattern) -> "_files" :: "-g" :: [pattern |> quote] | Files None -> ["_files"] diff --git a/src/optionValues.fs b/src/optionValues.fs new file mode 100644 index 0000000..a87e205 --- /dev/null +++ b/src/optionValues.fs @@ -0,0 +1,106 @@ +namespace FSharp.CommandLine + +open System +open System.Text.RegularExpressions +open FSharp.Scanf +open FSharp.Scanf.Internals.Parser +open FSharp.CommandLine.Internals +open Microsoft.FSharp.Quotations + +type ValueFormat<'p,'st,'rd,'rl,'t,'a> = { + format: PrintfFormat<'p,'st,'rd,'rl,'t> + paramNames: (string list) option + handler: 't -> 'a +} +with + static member inline construct (this: ValueFormat<_,_,_,_,_,_>) = + let parser s = + s |> tryKsscanf this.format this.handler + |> function Ok x -> Some x | _ -> None + in + let formatTokens = + let defaultNames = + this.format.GetFormatterNames() + |> List.map (String.replace ' ' '_' >> String.toUpperInvariant) + |> List.map (sprintf "%s_VALUE") + in + let names = (this.paramNames ?| defaultNames) |> List.map (sprintf "<%s>") in + this.format.PrettyTokenize names + in + (parser, formatTokens) + + member this.map ([]mapper: Expr<'a -> 'b>) = + let mf x = (FuncHelper.compileFunc mapper) x in + let pns = FuncHelper.getFirstArgumentName mapper in + { format = this.format; handler = this.handler >> mf; paramNames = pns } + + member this.withNames names = + { this with paramNames = Some names } + + member this.asConst value = + { format = this.format; handler = (fun _ -> value); paramNames = this.paramNames } + +type ValueRegex<'a> = { + regex: Regex + handler: string list -> 'a +} +with + static member construct (this: ValueRegex<_>) = + let parser (str: string) = + let m: Match = this.regex.Match(str) + if m.Success then + m.Groups + |> Seq.cast + |> List.ofSeq + |> List.zip (this.regex.GetGroupNames() |> List.ofArray) + |> List.filter (fun (name, _) -> name |> String.forall Char.IsDigit |> not) + |> List.map (fun (_, x) -> x.Value) + |> this.handler |> Some + else None + let tokens = [string this.regex] + (parser, tokens) + + member this.map mapper = + { regex = this.regex; handler = this.handler >> mapper } + + member this.asConst value = + { regex = this.regex; handler = fun _ -> value } + +type ValueTypedRegex<'a, '_Regex, '_Match > = { + typedRegex: '_Regex + handler: '_Match -> 'a +} +with + static member inline construct (this: ValueTypedRegex<_, ^Regex, ^Match>) : _ + when ^Match :> Match = + let parser str = + let m = (^Regex: (member TypedMatch: string -> ^Match) this.typedRegex,str) + if m.Success then + this.handler m |> Some + else None + let tokens = [string this.typedRegex] + (parser, tokens) + + member inline this.map mapper = + { typedRegex = this.typedRegex; handler = this.handler >> mapper } + + member inline this.asConst value = + { typedRegex = this.typedRegex; handler = fun _ -> value } + +[] +module OptionValues = + let inline format (fmt: PrintfFormat<_,_,_,_,'t>) : ValueFormat<_,_,_,_,'t,'t> = + { format = fmt; handler = id; paramNames = None } + + let inline regex r = + { regex = Regex(r); handler = id } + + let inline typedRegex< ^Regex, ^Match when ^Regex: (new: unit -> ^Regex) and ^Regex: (member TypedMatch: string -> ^Match) > : ValueTypedRegex< ^Match, ^Regex, ^Match > = + { typedRegex = new ^Regex(); handler = id } + + let inline asConst value (optionValue: ^X) = + (^X: (member asConst: _ -> _) optionValue,value) + + let inline internal construct (optionValue: ^X) = + (^X: (static member construct: _ -> _) optionValue) + diff --git a/src/options.fs b/src/options.fs new file mode 100644 index 0000000..fc73062 --- /dev/null +++ b/src/options.fs @@ -0,0 +1,332 @@ +namespace rec FSharp.CommandLine + +open FSharp.Scanf +open OptionParser + +/// specify how to treat options like ```-abcd``` +type SingleHyphenStyle = + /// treat ```-abcd``` as ```--abcd``` + | SingleLong + /// treat ```-abcd``` as ```-a bcd``` + | SingleShort + /// treat ```-abcd``` as ```-a -b -c -d``` + | MergedShort + +type CommandOptionNoArgProvided<'a> = + | UseDefault of 'a + | JustFail + +type CommandOptionKind<'a> = + | Flag of (bool -> 'a) + | TakingValueWith of CommandOptionNoArgProvided<'a> * (string -> 'a option) list + +type ICommandOption<'a> = + abstract member Parse: string list -> ('a * string list) + abstract member Config: CommandInfo -> CommandInfo + abstract member Summary: CommandOptionSummary + +/// represents a command option parser that tries to parse the arguments +/// and returns an optional result value. +type CommandOption<'a> = { + baseSummary: CommandOptionSummary + kind: CommandOptionKind<'a> + style: SingleHyphenStyle +} +with + member this.Summary = + let self = this + { + this.baseSummary with + isMatch = + fun argv -> + match (parseImpl self argv) with + | (Some _, rem) -> Some rem + | (None, _) -> None + } + member this.Parse argv = parseImpl this argv + + static member internal defaultOption : CommandOption<'a> = { + baseSummary = { + names = [] + description = "" + isFlag = false + paramNames = [] + isMatch = (fun _ -> None) + genSuggestions = (fun _ -> []) + } + kind = TakingValueWith (JustFail, []) + style = MergedShort + } + + static member internal defaultFlag : CommandOption = { + baseSummary = { + names = [] + description = "" + isFlag = true + paramNames = [] + isMatch = (fun _ -> None) + genSuggestions = (fun _ -> []) + } + kind = Flag id + style = MergedShort + } + + interface ICommandOption<'a option> with + member this.Summary = this.Summary + member this.Parse argv = parseImpl this argv + member this.Config cfg = + { + cfg with + options = this.Summary :: cfg.options + } + +/// represents a command option of which behavior and/or functionality are augmented. +/// (e.g. can parse multiple occurrence of the option at once) +type AugmentedCommandOption<'a, 'b> = { + orig: ICommandOption<'a> + augmenter: ICommandOption<'a> -> Args -> ('b * Args) +} +with + interface ICommandOption<'b> with + member this.Summary = this.orig.Summary + member this.Parse argv = this.augmenter this.orig argv + member this.Config cfg = (this.orig :> ICommandOption<_>).Config cfg + +module CommandOption = + /// gets the arguments which look like (will potentially be recognized by the parser as) + /// a command option. + let getRemainingOptions argv = + argv |> tokenize |> List.ofSeq + |> List.choose (function RIgnoreAfter | RValue _ -> None | x -> Some x) + |> List.map string + + /// given a command option and arguments, applies the parser to the arguments + /// and returns the parsed result and the remaining arguments. + let inline parse (opt: #ICommandOption<_>) argv = opt.Parse argv + + /// given a command option and arguments, applies the parser to the arguments until it fails + /// and returns the results and the remaining arguments. + let parseMany (opt: #ICommandOption<_>) argv = + let rec p xs = + seq { + yield! + match (opt.Parse xs) with + | (Some x, rest) -> + seq { yield (x, rest); yield! p rest } + | (None, _) -> + Seq.empty + } + let x = p argv + (x |> Seq.map fst |> List.ofSeq, x |> Seq.map snd |> Seq.tryLast ?| argv) + + /// given a command option, augments its functionality by modifying + /// its behavior. both the original command option and the arguments which + /// will be passed at the execution time are available. + let inline augment f c = { orig=c; augmenter=f } + let inline map f c = + let ac = augment (fun c args -> c.Parse args) c + { + orig=ac.orig; + augmenter=(fun o x -> ac.augmenter o x |> Tuple.map2 f id) + } + + /// given a command option, returns a new command option that parses + /// zero or more occurrence of that command option. + let inline zeroOrMore co = + co |> augment parseMany + + /// given a command option, returns a new command option that fails + /// if there are more than one occurrence of that command option. + let inline zeroOrExactlyOne co = + co + |> zeroOrMore + |> map (function + | [] -> None + | x :: [] -> Some x + | _ -> + let msg = sprintf "the option '%s' should be provided only once" + (co.Summary.NameRepresentations |> List.head) + OptionParseFailed (co.Summary, msg) |> raise) + + /// given a command option, returns a new command option that returns + /// the specified default value if there is no occurence. + let inline whenMissingUse defaultValue co = + co |> map (function Some x -> x | None -> defaultValue) + + /// an active pattern to parse the arguments using the command option + /// and gets the result and the remaining arguments. + let inline (|Parse|_|) opt argv = + let (reso, argv') = parse opt argv + reso |> Option.map (fun x -> (x, argv')) + +module ReservedCommandOptions = + let helpOption = + { + baseSummary = + { + names = ["?"; "h"; "help"] + description = "display this help usage." + isFlag = false + paramNames = [] + isMatch = fun _ -> None + genSuggestions = (fun _ -> []) + } + kind = Flag id + style = MergedShort + } + + let suggestOption = + { + baseSummary = + { + names = ["generate-suggestions"; "generate-suggestions-incomplete"] + description = "" + isFlag = false + paramNames = [["name"]] + isMatch = fun _ -> None + genSuggestions = (fun _ -> []) + } + kind = TakingValueWith (UseDefault "zsh", [Some]) + style = MergedShort + } + +module private OptionParser = + type RefinedToken = + | RFlag of string + | RFlagDisable of string + | RFlagAndValue of string * string + | RMaybeCombinedFlag of string + | RMaybeCombinedFlagAndValue of string * string + | RValue of string + | RIgnoreAfter + with + override this.ToString() = + match this with + | RFlag s -> sprintf "--%s" s + | RFlagDisable s -> sprintf "-%s-" s + | RFlagAndValue (s, v) -> sprintf "--%s=%s" s v + | RMaybeCombinedFlag s -> sprintf "-%s" s + | RMaybeCombinedFlagAndValue (s, v) -> sprintf "-%s=%s" s v + | RValue s -> s + | RIgnoreAfter -> "--" + + let optionForms = [ + tryKsscanf "--" (fun () -> RIgnoreAfter) + tryKsscanf "-%c" (RFlag << string); + tryKsscanf "-%c=%s" (Tuple.map2 string id >> RFlagAndValue); + tryKsscanf "--%s=%s" RFlagAndValue; + tryKsscanf "/%s=%s" RFlagAndValue; + tryKsscanf "--%s" RFlag; + tryKsscanf "-%c+" (RFlag << string); + tryKsscanf "-%c-" (RFlagDisable << string); + tryKsscanf "-%s=%s" RMaybeCombinedFlagAndValue; + tryKsscanf "-%s" RMaybeCombinedFlag; + tryKsscanf "/%s" RFlag; + tryKsscanf "%s" RValue + ] + + let rec tokenize argv = + seq { + if List.isEmpty argv then + yield! Seq.empty + else + let (h, t) = (List.head argv, List.tail argv) + let ro = optionForms |> List.map (fun f -> f h) + |> List.choose (function Ok x -> Some x | _ -> None) + |> List.tryHead + if Option.isSome ro then + yield ro.Value; + yield! + match ro.Value with + | RIgnoreAfter -> t |> Seq.map RValue + | _ -> tokenize t + else + yield! Seq.empty + } + + let parseImpl (opt: CommandOption<'a>) argv = + let inline isSingle s = String.length s = 1 + let inline matches x = opt.baseSummary.names |> List.contains x + let shortNames = opt.baseSummary.names |> List.filter isSingle + let opf msg = OptionParseFailed(opt.baseSummary, msg) + + let tokens = tokenize argv |> List.ofSeq + let rec find ts = + match opt.kind with + | Flag f -> + let inline f x = f x |> Some + match ts with + | RFlag x :: rest when matches x -> (f true, rest) + | RFlagDisable x :: rest when matches x -> (f false, rest) + | RFlagAndValue (x, _) :: _ when matches x -> + sprintf "'%s' is a flag and does not take an argument" x |> opf |> raise + | RMaybeCombinedFlag xs :: rest & x :: _ -> + match opt.style with + | MergedShort when shortNames |> List.exists xs.Contains -> + let c = shortNames |> List.find xs.Contains + (f true, RMaybeCombinedFlag (xs.Replace(c, "")) :: rest) + | SingleLong when matches xs -> (f true, rest) + | SingleShort when shortNames |> List.exists xs.StartsWith -> + sprintf "'%c' is a flag and does not take an argument" (xs.[0]) |> opf |> raise + | _ -> find rest |> Tuple.map2 id (fun rest' -> x :: rest') + | RMaybeCombinedFlagAndValue (xs, v) :: rest & x :: _ -> + match opt.style with + | MergedShort when shortNames |> List.exists xs.Contains -> + let c = shortNames |> List.find xs.Contains + if shortNames |> List.exists xs.EndsWith then + sprintf "'%s' is a flag and does not take an argument" c |> opf |> raise + else + (f true, RMaybeCombinedFlagAndValue(xs.Replace(c, ""), v) :: rest) + | SingleLong when matches xs -> + sprintf "'%s' is a flag and does not take an argument" xs |> opf |> raise + | SingleShort -> sprintf "invalid option: '-%s=%s'" xs v |> opf |> raise + | _ -> find rest |> Tuple.map2 id (fun rest' -> x :: rest') + | x :: rest -> find rest |> Tuple.map2 id (fun rest' -> x :: rest') + | [] -> (None, []) + | TakingValueWith (na, fs) -> + let inline tryReturn v name = + match (fs |> List.map (fun f -> f v) |> List.choose id |> List.tryHead) with + | Some x -> Some x + | None -> + sprintf "the value '%s' is invalid for the option '%s'" v name |> opf |> raise + let inline tryDefault name = + match na with + | UseDefault x -> Some x + | JustFail -> + sprintf "a value is missing for the option '%s'" name |> opf |> raise + match ts with + | RFlag x :: RValue v :: rest + | RFlagAndValue (x, v) :: rest when matches x -> (tryReturn v x, rest) + | RFlag x :: rest when matches x -> (tryDefault x, rest) + | RFlagDisable x :: _ when matches x -> + sprintf "a value is missing for the option '%s'" x |> opf |> raise + | RMaybeCombinedFlag xs :: RValue v :: rest & x :: _ :: _-> + match opt.style with + | MergedShort when shortNames |> List.exists xs.EndsWith -> + let c = shortNames |> List.find xs.EndsWith + (tryReturn v c, RMaybeCombinedFlag (xs.Replace(c, "")) :: rest) + | MergedShort when shortNames |> List.exists xs.Contains -> + let c = shortNames |> List.find xs.Contains + (tryDefault c, RMaybeCombinedFlag (xs.Replace(c, "")) :: RValue v :: rest) + | SingleShort when shortNames |> List.exists xs.StartsWith -> + let c = shortNames |> List.find xs.StartsWith + let v' = xs.Substring(1) + (tryReturn v' c, RValue v :: rest) + | SingleLong when matches xs -> + (tryReturn v xs, rest) + | _ -> find rest |> Tuple.map2 id (fun rest' -> x :: RValue v :: rest') + | RMaybeCombinedFlagAndValue (xs, v) :: rest & x :: _ -> + match opt.style with + | MergedShort when shortNames |> List.exists xs.EndsWith -> + let c = shortNames |> List.find xs.EndsWith + (tryReturn v c, RMaybeCombinedFlag (xs.Replace(c, "")) :: rest) + | MergedShort when shortNames |> List.exists xs.Contains -> + let c = shortNames |> List.find xs.Contains + (tryDefault c, RMaybeCombinedFlagAndValue (xs.Replace(c, ""), v) :: rest) + | SingleLong when matches xs -> + (tryReturn v xs, rest) + | SingleShort -> sprintf "invalid option: '-%s=%s'" xs v |> opf |> raise + | _ -> find rest |> Tuple.map2 id (fun rest' -> x :: rest') + | x :: rest -> find rest |> Tuple.map2 id (fun rest' -> x :: rest') + | [] -> (None, []) + find tokens |> Tuple.map2 id (List.map string) diff --git a/src/common/prelude.fs b/src/prelude.fs old mode 100755 new mode 100644 similarity index 97% rename from src/common/prelude.fs rename to src/prelude.fs index 3db31c8..a4d9be0 --- a/src/common/prelude.fs +++ b/src/prelude.fs @@ -29,13 +29,12 @@ module internal Prelude [] module ToplevelOperators = open System - let inline to_s x = x.ToString() let inline (?|) opt df = defaultArg opt df let inline (!!) (x: Lazy<'a>) = x.Value - let inline undefined (x: 'a) : 'b = NotImplementedException(to_s x) |> raise + let inline undefined (x: 'a) : 'b = NotImplementedException(string x) |> raise let inline reraise' ex = System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(ex).Throw(); failwith "impossible" @@ -88,7 +87,7 @@ module Flag = xs |> Seq.fold (|||) (Unchecked.defaultof< ^flag >) let inline contains (x: ^flag) (flags: ^flag) : bool when ^flag: enum = - (x &&& flags) = x + (x &&& flags) = x module Number = open System.Globalization @@ -123,7 +122,7 @@ module Patterns = match x with | Some v -> v | None -> dv - + [] module Kvp = open System.Collections.Generic @@ -151,16 +150,16 @@ module String = let inline contains (s: ^a) (str: ^String) : bool = (^String: (member IndexOf: ^a -> int) str, s) <> -1 - let inline findIndex (q: ^T) (str: ^String) = + let inline findIndex (q: ^T) (str: ^String) = (^String: (member IndexOf: ^T -> int) (str, q)) - let inline findIndexAfter (q: ^T) i (str: ^String) = + let inline findIndexAfter (q: ^T) i (str: ^String) = (^String: (member IndexOf: ^T -> int -> int) (str, q, i)) - let inline findLastIndex (q: ^T) (str: ^String) = + let inline findLastIndex (q: ^T) (str: ^String) = (^String: (member LastIndexOf: ^T -> int) (str, q)) - let inline findLastIndexAfter (q: ^T) i (str: ^String) = + let inline findLastIndexAfter (q: ^T) i (str: ^String) = (^String: (member LastIndexOf: ^T -> int -> int) (str, q, i)) let inline insertAt s i (str: string) = str.Insert(i, s) @@ -173,7 +172,7 @@ module String = let inline substring startIndex endIndex (str: string) = str.Substring(startIndex, endIndex) - let inline normalize (nfo: NormalizationForm option) (str: string) = + let inline normalize (nfo: NormalizationForm option) (str: string) = match nfo with Some nf -> str.Normalize nf | None -> str.Normalize() let inline toLower (ci: CultureInfo) (str: string) = str.ToLower ci @@ -187,7 +186,7 @@ module String = let inline padLeft i (str: string) = str.PadLeft i let inline padLeftBy i c (str: string) = str.PadLeft(i, c) - + let inline padRight i (str: string) = str.PadRight i let inline padRightBy i c (str: string) = str.PadRight(i, c) @@ -199,15 +198,15 @@ module String = let inline trimEnd (str: string) = str.TrimEnd() let inline trimBy (trimChar: char) (str: string) = str.Trim(trimChar) - + let inline trimBySeq (trimChars: char seq) (str: string) = str.Trim(trimChars |> Seq.toArray) let inline trimStartBy (trimChar: char) (str: string) = str.TrimStart(trimChar) - + let inline trimStartBySeq (trimChars: char seq) (str: string) = str.TrimStart(trimChars |> Seq.toArray) let inline trimEndBy (trimChar: char) (str: string) = str.TrimEnd(trimChar) - + let inline trimEndBySeq (trimChars: char seq) (str: string) = str.TrimEnd(trimChars |> Seq.toArray) let inline replace (before: ^T) (after: ^T) (s: ^String) = @@ -227,7 +226,7 @@ module String = let inline nth i (str: string) = str.[i] - let inline rev (str: string) = + let inline rev (str: string) = new String(str.ToCharArray() |> Array.rev) let inline private whileBase pred act str = @@ -275,7 +274,7 @@ module StringExtensions = open System.Collections.Generic type array2d<'t> = 't[,] -type array3d<'t> = 't[,,] +type array3d<'t> = 't[,,] module List = let inline splitWith predicate xs = @@ -309,10 +308,10 @@ module Seq = xs |> Seq.groupBy (fun x -> if predicate x then incr i; 0 else !i) |> Seq.filter (fst >> ((<>) 0)) |> Seq.map snd - + let inline split separator xs = splitWith ((=) separator) xs - let inline skipSafe length xs = + let inline skipSafe length xs = xs |> Seq.indexed |> Seq.skipWhile (fst >> ((>) length)) |> Seq.map snd @@ -322,7 +321,7 @@ module Seq = if xs' |> Seq.exists (fst >> ((=) (length - 1))) then xs' |> Seq.take length |> Seq.map snd |> Some else None - + let inline foldi folder state xs = Seq.fold (fun (i, state) x -> (i + 1, folder i state x)) (0, state) xs |> snd @@ -365,12 +364,12 @@ module Map = /// will be called: the first parameter is the key, the second is the value /// found in the formar map `m1`, and the third is the one found in `m2`. let inline merge merger m1 m2 = - Map.fold (fun m k v1 -> + Map.fold (fun m k v1 -> match m |> Map.tryFind k with | Some v2 -> Map.add k (merger k v1 v2) m | None -> Map.add k v1 m ) m1 m2 - + /// Merges multiple maps. If there is a duplicate key, the `merger` function /// will be called: the first parameter is the key, the second is the value /// already found in the earlier maps, and the third is the value newly found. @@ -420,7 +419,7 @@ module Lazy = let inline run (x: Lazy<_>) = x.Value let inline force (x: Lazy<_>) = x.Force() - + let inline bind (f: 'a -> Lazy<'b>) (x: Lazy<'a>) : Lazy<'b> = Lazy<_>.Create (fun () -> x |> force |> f |> force) @@ -451,7 +450,7 @@ module Result = match res with | Ok x -> Some x | Error _ -> None - + let inline toChoice res = match res with | Ok x -> Choice1Of2 x @@ -512,10 +511,10 @@ module ComputationExpressions = member inline this.Undelay f = f() member inline this.TryWith (f, h) = try f() with exn -> h exn member inline this.TryFinally (f, h) = try f() finally h() - + // boilerplate for any monad to add for/while - + member inline this.Zero () = this.Return () member inline this.Using (disp: #System.IDisposable, m) = this.TryFinally( @@ -542,7 +541,7 @@ module ComputationExpressions = member inline this.Bind(m, f) = Option.bind f m member inline this.Return x = Some x member inline this.ReturnFrom x = x - + member inline this.Delay f = f member inline this.Undelay f = f() member inline this.TryWith (f, h) = try f() with exn -> h exn @@ -568,17 +567,17 @@ module ComputationExpressions = en.MoveNext, this.Delay(fun () -> exec en.Current)) ) - + type ResultBuilder() = member inline this.Bind(m, f) = Result.bind f m member inline this.Return x = Ok x member inline this.ReturnFrom x = x - + member inline this.Delay f = f member inline this.Undelay f = f() member inline this.TryWith (f, h) = try f() with exn -> h exn member inline this.TryFinally (f, h) = try f() finally h() - + member inline this.Zero () = this.Return () member inline this.Using (disp: #System.IDisposable, m) = this.TryFinally( @@ -599,7 +598,7 @@ module ComputationExpressions = en.MoveNext, this.Delay(fun () -> exec en.Current)) ) - + type LazyBuilder() = member inline this.Bind(m, f) = Lazy.bind f m @@ -612,7 +611,7 @@ module ComputationExpressions = lazy (try Lazy.force m with exn -> f exn) member inline this.TryFinally (m, f) = lazy (try Lazy.force m finally f() ) - + member inline this.Zero () = this.Return () member inline this.Using (disp: #System.IDisposable, m) = this.TryFinally( @@ -636,9 +635,9 @@ module ComputationExpressions = open System.Threading.Tasks type AsyncBuilder with - member inline this.Bind(t:Task<'T>, f:'T -> Async<'R>) : Async<'R> = + member inline this.Bind(t:Task<'T>, f:'T -> Async<'R>) : Async<'R> = async.Bind(Async.AwaitTask t, f) - member inline this.Bind(t:Task, f:unit -> Async<'R>) : Async<'R> = + member inline this.Bind(t:Task, f:unit -> Async<'R>) : Async<'R> = async.Bind(Async.AwaitTask t, f) [] @@ -662,14 +661,14 @@ module Path = let filePath = new Uri(file) let path = new Uri ( - if (parentDir |> String.endsWith (to_s Path.DirectorySeparatorChar) |> not) then + if (parentDir |> String.endsWith (string Path.DirectorySeparatorChar) |> not) then sprintf "%s%c" parentDir Path.DirectorySeparatorChar else parentDir ) Uri.UnescapeDataString( path.MakeRelativeUri(filePath) - |> to_s + |> string |> String.replace '/' Path.DirectorySeparatorChar) module File = @@ -679,7 +678,7 @@ module File = module Directory = let inline isHidden dir = DirectoryInfo(dir).Attributes.HasFlag(FileAttributes.Hidden) - + let rec enumerateFilesRecursively includeHidden dir = seq { for x in Directory.EnumerateFiles dir do @@ -710,8 +709,8 @@ module Task = let inline bind (f: 'a -> 'b task) (t: 'a task) : 'b task = t.ContinueWith(fun (x: _ task) -> f x.Result).Unwrap() - let inline returnValue x : _ task= - let s = TaskCompletionSource() + let inline returnValue x : 'a task = + let s = new TaskCompletionSource<'a>() s.SetResult x s.Task @@ -832,7 +831,7 @@ module Shell = do p.StartInfo.FileName <- cmd do p.StartInfo.Arguments <- args |> String.concat " " do p.Start() |> ignore - do p.WaitForExit() + do p.WaitForExit() return p.ExitCode } diff --git a/src/version.fs b/src/version.fs new file mode 100644 index 0000000..05753b2 --- /dev/null +++ b/src/version.fs @@ -0,0 +1,11 @@ +// Auto-Generated by FAKE; do not edit +namespace System +open System.Reflection + +[] +[] +do () + +module internal AssemblyVersionInformation = + let [] AssemblyVersion = "4.0.0" + let [] AssemblyFileVersion = "4.0.0"