diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 00000000..c6020604
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,31 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Either fork from this fiddle and paste link here: https://dotnetfiddle.net/mh9CjX
+
+or
+
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.gitignore b/.gitignore
index 55f900a1..4969d4de 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,5 +37,7 @@ artifacts/*
*.DotSettings.user
# Visual Studio 2015 cache/options directory
.vs/
+# Rider
+.idea/
[R|r]elease/**
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 00000000..eea8ad12
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,174 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+CommandLineParser project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [2.9.0-preview2]
+
+### Added
+- Properly assign arguments after a double dash to values, fix #605 by [@robnasby, PR# 610](https://github.com/commandlineparser/commandline/pull/610).
+
+### Changed
+- Drop "Add multi-instance option support".
+
+
+## [2.9.0-preview1] - 2020-7-24
+
+### Added
+- Add multi-instance option support by [@rmunn and @tydunkel, PR# 594](https://github.com/commandlineparser/commandline/pull/594).
+- Fix unparsing FileInfo and DirectoryInfo by[@kapsiR, PR# 627](https://github.com/commandlineparser/commandline/pull/627).
+- Move Errors and Value up to the abstract class definition, fixes #543 , #165 by [@johnjaylward, PR# 634](https://github.com/commandlineparser/commandline/pull/634).
+- Add support for flags enums, fixes #247, #599 and #582 by [@shaosss, PR# 623](https://github.com/commandlineparser/commandline/pull/623).
+- Implement verb aliases, fixes #6, #517 by[@johnjaylward, PR# 636](https://github.com/commandlineparser/commandline/pull/636).
+- Add a new method FormatCommandLineArgs to unparse commandline to array of string, Fix #375 and #628 .
+ - Also, add SplitArgs method to split commandline, fix #665 by[@moh-hassan, PR# 662](https://github.com/commandlineparser/commandline/pull/662) and [commit cccae2db](https://github.com/commandlineparser/commandline/commit/cccae2db749c2ebf25125bfd18e05427be0adbcf).
+- Allow single dash as a value, fix #300 and #574 by [@moh-hassan, PR# 669](https://github.com/commandlineparser/commandline/pull/669).
+
+
+## [2.8.0] - 2020-5-1
+## [2.8.0-preview4] - 2020-4-30
+## [2.8.0-preview1] - 2020-3-14
+
+### Added
+- Added support for async programming for `WithParsed and WithNotParsed` by [@joseangelmt, PR# 390 ](https://github.com/commandlineparser/commandline/pull/390).
+- Publish a new symbol packages with source link support for c# and F# (.snupkg) to improved package debugging experience by [@moh-hassan, PR#554](https://github.com/commandlineparser/commandline/pull/554)
+- Add default verb support by [@Artentus, PR# 556](https://github.com/commandlineparser/commandline/pull/556).
+- Add more details for localized attribute properties by [@EdmondShtogu, PR# 558](https://github.com/commandlineparser/commandline/pull/558)
+- Support Default in Group Options and raise error if both SetName and Group are applied on option by [@hadzhiyski, PR# 575](https://github.com/commandlineparser/commandline/pull/575).
+- Support mutable types without empty constructor that only does explicit implementation of interfaces by [@pergardebrink, PR#590](https://github.com/commandlineparser/commandline/pull/590).
+
+
+### Changed
+- Tests cleanup by [@gsscoder, PR# 560](https://github.com/commandlineparser/commandline/pull/560).
+- Upgraded parts of CSharpx from Version 1.6.2-alpha by [@gsscoder, PR# 561](https://github.com/commandlineparser/commandline/pull/561).
+- Upgraded RailwaySharp from Version 1.1.0 by [@gsscoder, PR# 562](https://github.com/commandlineparser/commandline/pull/562).
+- SkipDefault is being respected by [Usage] Examples by [@kendfrey, PR# 565](https://github.com/commandlineparser/commandline/pull/565).
+- Remove useless testing code by [@gsscoder, PR# 568](https://github.com/commandlineparser/commandline/pull/568).
+- Remove constraint on T for ParseArguments with factory (required by issue #70) by [@pergardebrink](https://github.com/commandlineparser/commandline/pull/590).
+- Update nuget api key by [@ericnewton76](https://github.com/commandlineparser/commandline/commit/2218294550e94bcbc2b76783970541385eaf9c07)
+
+### Fixed
+- Fix #579 Unable to parse TimeSpan given from the FormatCommandLine by [@gsscoder, PR# 580](https://github.com/commandlineparser/commandline/pull/580).
+- Fix issue #339 for using custom struct having a constructor with string parameter by [moh-hassan, PR# 588](https://github.com/commandlineparser/commandline/pull/588).
+- Fix issue #409 to avoid IOException break in Debug mode in WPF app by [moh-hassan, PR# 589 ](https://github.com/commandlineparser/commandline/pull/589).
+
+
+## [2.7.82] - 2020-1-1
+## [2.7.0] - 2020-1-1
+### Added
+- Add option groups feature by [@hadzhiyski](https://github.com/commandlineparser/commandline/pull/552) - When one or more options has group set, at least one of these properties should have set value (they behave as required).
+- Add a new overload method for AutoBuild to enable HelpText customization by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/557).
+- Improve spacing in HelpText by [@asherber](https://github.com/commandlineparser/commandline/pull/494) by adding a new option in the HelpText.
+- Add a new option "SkipDefault" in UnParserSettings by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/550) to add the ability of skipping the options with a default value and fix [#541](https://github.com/commandlineparser/commandline/issues/541).
+- Generate a new symbolic nuget Package by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/554) to Improve the debugging of Applications with the NuGet package using [symbols experience](https://github.com/NuGet/Home/wiki/NuGet-Package-Debugging-&-Symbols-Improvements).
+- Add Support to [SourceLink](https://github.com/dotnet/sourcelink/blob/master/docs/README.md) in the nuget package [@moh-hassan](https://github.com/commandlineparser/commandline/pull/554).
+
+### Changed
+- Remove the Exception when both CompanyAttribute and CopyRightAttribute are null in the Excuting assembly and set the copyright text to a default value by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/557).
+- Change the default copyright to include current year instead of 1 by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/557).
+- Enabling c# 8 and Vs2019 image in Appveyor.
+
+### Fixed
+- Fix NullReferenceException when creating a default immutable instance by [@0xced](https://github.com/commandlineparser/commandline/pull/495).
+- Fix issue [#496](https://github.com/commandlineparser/commandline/issues/496) - Cryptic error message with immutable option class by[@moh-hassan](https://github.com/commandlineparser/commandline/pull/555).
+- Fix UnParserExtensions.FormatCommandLine by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/550) to resolve:
+ - Fix Quote for Options of type DatTime [#502](https://github.com/commandlineparser/commandline/issues/502) and [#528](https://github.com/commandlineparser/commandline/issues/258).
+ - Fix Quote for options of type TimeSpan and DateTimeOffset.
+ - Fix Nullable type [#305](https://github.com/commandlineparser/commandline/issues/305)
+
+- Fix nuget Licence in nuget package by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/549) and fix issue [#545](https://github.com/commandlineparser/commandline/issues/545).
+- Fix PackageIconUrl warning in nuget package by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/551).
+- Fix immutable nullException, Improve exception message when immutable type can't be created
+- Fix Custom help for verbs issue[#529](https://github.com/commandlineparser/commandline/issues/529) by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/557).
+- Fix --help switch throwing exception in F# [#366](https://github.com/commandlineparser/commandline/issues/366)
+by [@WallaceKelly](https://github.com/commandlineparser/commandline/pull/493)
+
+## [2.6.0] - 2019-07-31
+### Added
+- Support HelpText localization with ResourceType property by [@tkouba](https://github.com/commandlineparser/commandline/pull/356).
+- Add demo for complete localization of command line help using resources by[@tkouba](https://github.com/commandlineparser/commandline/pull/485).
+- Localize VerbAttribute by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/473).
+- Improve support for multiline help text by [@NeilMacMullen](https://github.com/commandlineparser/commandline/pull/456/).
+- Reorder options in auto help text (issue #482) [@b3b00](https://github.com/commandlineparser/commandline/pull/484).
+- Add IsHelp() and IsVersion() Extension methods to mange HelpText errors by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/467).
+
+### Fixed
+- Fix issues for HelpText.AutoBuild configuration (issues #224 , # 259) by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/467).
+- Test maintainance: add missed tests and removing xUnit1013 warning by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/462).
+- Fix issue #104 of nullable enum by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/453).
+- Fix issue #418, modify version screen to print a new line at the end by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/443).
+
+
+## [2.5.0] - 2019-04-27
+### Added
+- Add support to NET40 and NET45 for both CSharp and FSharp by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/430).
+
+
+### Changed
+- Proposed changes for enhancement by [@Wind010](https://github.com/commandlineparser/commandline/pull/314), cover:appveyor.yml, ReflectionExtensions.cs and error.cs.
+- Enhance the CSharp demo to run in multi-target net40;net45;netcoreapp2.0;netcoreapp2.1 by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/430).
+- Added explicit support for .NET 4.6.1 and .NET Core 2.0 by [@ravenpride](https://github.com/commandlineparser/commandline/pull/400).
+- Convert commandline project to multi-target project netstandard2.0;net40;net45;net461.
+- Convert commandline Test to multi-target project net461;netcoreapp2.0.
+
+
+
+### Fixed
+- Fix the null EntryAssembly Exception in unit test of net4x projects: issues #389,#424 by [@moh-hassan](https://github.com/commandlineparser/commandline/pull/430).
+- Fix the test case 'Add unit tests for Issue #389 and #392
+- Fix CSC error CS7027: Error signing output with public key from file 'CommandLine.snk' -- Invalid public key in appveyor CI.
+- Fix the error CS0234: The type or namespace name 'FSharp' for net40 Framework.
+- Fix Mis-typed CommandLine.BaseAttribute.Default results in ArgumentException: Object of type 'X' cannot be converted to type 'Y' (issue #189) by[@Wind010](https://github.com/commandlineparser/commandline/pull/314).
+
+
+
+
+## [2.4.3] - 2019-01-09
+### Added
+- Add support to NetStandard2.0 by [@ViktorHofer](https://github.com/commandlineparser/commandline/pull/307)
+- Add strong name signing [@ViktorHofer](https://github.com/commandlineparser/commandline/pull/307)
+- Added AutoBuild and AutoVersion properties to control adding of implicit 'help' and 'version' options/verbs by [@Athari](https://github.com/commandlineparser/commandline/pull/256).
+- Added simpler C# Quick Start example at readme.md by [@lythix](https://github.com/commandlineparser/commandline/pull/274).
+- Add validate feature in Set parameter, and throw exception, and show usage,Issue #283 by[@e673](https://github.com/commandlineparser/commandline/pull/286).
+
+
+### Deprecated
+- Drop support for NET40 and NET45
+
+
+### Removed
+- Disable faulty tests in netsatbdard2.0 and enable testing in CI.
+
+
+### Fixed
+- Fix grammar error in specification error message by [@DillonAd](https://github.com/commandlineparser/commandline/pull/276).
+- Fix HelpText.AutoBuild Usage spacing by[@ElijahReva](https://github.com/commandlineparser/commandline/pull/280).
+- Fix type at readme.md file by [@matthewjberger](https://github.com/commandlineparser/commandline/pull/304)
+- Fix not showing correct header info, issue #34 by[@tynar](https://github.com/commandlineparser/commandline/pull/312).
+- Fix title of assembly renders oddly issue-#197 by [@Yiabiten](https://github.com/commandlineparser/commandline/pull/344).
+- Fix nuget apikey by [@ericnewton76](https://github.com/commandlineparser/commandline/pull/386).
+- Fix missing fsharp from github release deployment by @ericnewton76.
+- Fix to Display Width Tests by [@Oddley](https://github.com/commandlineparser/commandline/pull/278).
+- Fixing DisplayWidth for newer Mono by [@Oddley](https://github.com/commandlineparser/commandline/pull/279).
+
+
+## [2.3.0] - 2018-08-13
+### Added
+- Properly handle CaseInsensitiveEnumValues flag fixing issue #198 by [@niklaskarl](https://github.com/commandlineparser/commandline/pull/231).
+
+### Changed
+- Updated README examples quick start example for c# and Vb.net to work with the new API by [@loligans](https://github.com/commandlineparser/commandline/pull/218).
+- Updated README by [@ericnewton76](https://github.com/commandlineparser/commandline/pull/208).
+- Update copyright in unit tests
+- Patching appveyor dotnet csproj
+- Updates to appveyor to create a build matrix
+
+### Fixed
+- hotfix/issue #213 fsharp dependency by [@ericnewton76](https://github.com/commandlineparser/commandline/pull/215).
+
+
+## [2.2.1] - 2018-01-10
+
+## [2.2.0] - 2018-01-07
+
+## [1.9.71.2] - 2013-02-27: The starting bascode version
diff --git a/CommandLine.sln b/CommandLine.sln
index 06356a14..102837f1 100644
--- a/CommandLine.sln
+++ b/CommandLine.sln
@@ -3,9 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27703.2042
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommandLine", "src\CommandLine\CommandLine.csproj", "{E1BD3C65-49C3-49E7-BABA-C60980CB3F20}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommandLine", "src\CommandLine\CommandLine.csproj", "{E1BD3C65-49C3-49E7-BABA-C60980CB3F20}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommandLine.Tests", "tests\CommandLine.Tests\CommandLine.Tests.csproj", "{0A15C4D2-B3E9-43AB-8155-1B39F7AC8A5E}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommandLine.Tests", "tests\CommandLine.Tests\CommandLine.Tests.csproj", "{0A15C4D2-B3E9-43AB-8155-1B39F7AC8A5E}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{1361E8B1-D0E1-493E-B8C1-7380A7B7C472}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -25,6 +27,9 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {0A15C4D2-B3E9-43AB-8155-1B39F7AC8A5E} = {1361E8B1-D0E1-493E-B8C1-7380A7B7C472}
+ EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5B5A476C-82FB-49FB-B592-5224D9005186}
EndGlobalSection
diff --git a/CommandLine.snk b/CommandLine.snk
index 96087a73..6b0b6501 100644
Binary files a/CommandLine.snk and b/CommandLine.snk differ
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 00000000..3db45ca4
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,18 @@
+
+
+ CS1591;CS0219;8002;NU5125
+ $(MSBuildThisFileDirectory)
+ false
+
+
+ $(DefineConstants);NETFRAMEWORK
+
+
+
+
+ runtime; build; native; contentfiles; analyzers
+ all
+
+
+
+
diff --git a/README.md b/README.md
index 7f11109e..79a16fa7 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
[](https://ci.appveyor.com/project/commandlineparser/commandline/branch/master)
[](http://nuget.org/packages/commandlineparser)
-[](http://nuget.org/packages/commandlineparser)
-[](http://nuget.org/packages/commandlineparser)
+[](https://www.nuget.org/packages/CommandLineParser/)
+[](https://www.nuget.org/packages/CommandLineParser/)
[](https://gitter.im/gsscoder/commandline?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
# Command Line Parser Library for CLR and NetStandard
@@ -14,22 +14,40 @@ The Command Line Parser Library offers CLR applications a clean and concise API
C:\Project> NuGet Install CommandLineParser
```
+# Nightly Build
+
+Nightly version of the CommandLineParser can be downloaded from github [Releases](https://github.com/commandlineparser/commandline/releases).
+
+The Last new features and fixes, read [changelog](https://github.com/commandlineparser/commandline/blob/master/CHANGELOG.md)
+
+
_NOTE: Mentioned F# Support is provided via ```CommandLineParser.FSharp``` package with FSharp dependencies._
__This library provides _hassle free_ command line parsing with a constantly updated API since 2005.__
# At a glance:
-- Compatible with __.NET Framework 4.0+__, __Mono 2.1+ Profile__, and __.NET Core__
+- Compatible with __.NET Framework 4.0+__, __Mono 2.1+ Profile__, __.NET Standard__ and __.NET Core__
- Doesn't depend on other packages (No dependencies beyond standard base libraries)
-- One line parsing using default singleton: `CommandLine.Parser.Default.ParseArguments(...)`.
+- One line parsing using default singleton: `CommandLine.Parser.Default.ParseArguments(...)` and three overload methods.
- Automatic or one line help screen generator: `HelpText.AutoBuild(...)`.
-- Supports `--help`, `--version`, `version` and `help [verb]` by default.
+- Supports `--help`, `--version`, `version` and `help [verb]` by default with customization.
- Map to sequences (via `IEnumerable` and similar) and scalar types, including Enums and `Nullable`.
-- You can also map to every type with a constructor that accepts a string (like `System.Uri`).
-- Define [verb commands](https://github.com/commandlineparser/commandline/wiki#verbs) similar to `git commit -a`.
+- You can also map to every type with a constructor that accepts a string (like `System.Uri`) for reference and value types.
+- Verbs can be array of types collected from Plugins or IoC container.
+- Define [verb commands](https://github.com/commandlineparser/commandline/wiki/Verbs) similar to `git commit -a`.
+- Support default verb.
+- Support Mutable and Immutable types.
+- Support HelpText localization.
+- Support ordering of options in HelpText.
+- Support [Mutually Exclusive Options](https://github.com/commandlineparser/commandline/wiki/Mutually-Exclusive-Options) and [Option groups](https://github.com/commandlineparser/commandline/wiki/Option-Groups).
+- Support named and value options.
+- Support Asynchronous programming with async and await.
- Unparsing support: `CommandLine.Parser.Default.FormatCommandLine(T options)`.
- CommandLineParser.FSharp package is F#-friendly with support for `option<'a>`, see [demo](https://github.com/commandlineparser/commandline/blob/master/demo/fsharp-demo.fsx). _NOTE: This is a separate NuGet package._
+- Include wiki documentation with lot of examples ready to run online.
+- Support Source Link and symbolic nuget package snupkg.
+- Tested in Windows, Linux Ubuntu 18.04 and Mac OS.
- Most of features applies with a [CoC](http://en.wikipedia.org/wiki/Convention_over_configuration) philosophy.
- C# demo: source [here](https://github.com/commandlineparser/commandline/tree/master/demo/ReadText.Demo).
@@ -48,7 +66,7 @@ You can utilize the parser library in several ways:
C# Quick Start:
-```csharp
+```cs
using System;
using CommandLine;
@@ -83,9 +101,13 @@ namespace QuickStart
}
```
-C# Examples:
+## C# Examples:
+
+
+ Click to expand!
+
+```cs
-```csharp
class Options
{
[Option('r', "read", Required = true, HelpText = "Input files to be processed.")]
@@ -109,14 +131,31 @@ class Options
static void Main(string[] args)
{
CommandLine.Parser.Default.ParseArguments(args)
- .WithParsed(opts => RunOptionsAndReturnExitCode(opts))
- .WithNotParsed((errs) => HandleParseError(errs));
+ .WithParsed(RunOptions)
+ .WithNotParsed(HandleParseError);
+}
+static void RunOptions(Options opts)
+{
+ //handle options
}
+static void HandleParseError(IEnumerable errs)
+{
+ //handle errors
+}
+
```
-F# Examples:
+
+
+Demo to show IEnumerable options and other usage: [Online Demo](https://dotnetfiddle.net/wrcAxr)
+
+## F# Examples:
+
+
+ Click to expand!
```fsharp
+
type options = {
[
+
+## VB.NET Example:
-VB.NET:
+
+ Click to expand!
+
+```vb
-```VB.NET
Class Options
@@ -159,14 +203,19 @@ Sub Main(ByVal args As String())
.WithNotParsed(Function(errs As IEnumerable(Of [Error])) 1)
End Sub
```
+
-### For verbs:
+## For verbs:
1. Create separate option classes for each verb. An options base class is supported.
2. Call ParseArguments with all the verb attribute decorated options classes.
3. Use MapResult to direct program flow to the verb that was parsed.
-C# example:
+### C# example:
+
+
+
+ Click to expand!
```csharp
[Verb("add", HelpText = "Add file contents to the index.")]
@@ -191,10 +240,15 @@ int Main(string[] args) {
errs => 1);
}
```
+
-VB.NET example:
+### VB.NET example:
-```VB.NET
+
+
+ Click to expand!
+
+```vb
Public Class AddOptions
'Normal options here
@@ -218,10 +272,14 @@ Function Main(ByVal args As String()) As Integer
)
End Function
```
+
-F# Example:
+### F# Example:
-```fsharp
+
+ Click to expand!
+
+```fs
open CommandLine
[]
@@ -248,6 +306,11 @@ let main args =
| :? CloneOptions as opts -> RunCloneAndReturnExitCode opts
| :? CommandLine.NotParsed -> 1
```
+
+
+# Release History
+
+See the [changelog](CHANGELOG.md)
# Contributors
First off, _Thank you!_ All contributions are welcome.
@@ -263,6 +326,7 @@ __And most importantly, please target the ```develop``` branch in your pull requ
- Dan Nemec (@nemec)
- Eric Newton (@ericnewton76)
- Kevin Moore (@gimmemoore)
+- Moh-Hassan (@moh-hassan)
- Steven Evans
- Thomas Démoulins (@Thilas)
@@ -284,3 +348,4 @@ __And most importantly, please target the ```develop``` branch in your pull requ
- GitHub: [ericnewton76](https://github.com/ericnewton76)
- Blog:
- Twitter: [enorl76](http://twitter.com/enorl76)
+- Moh-Hassan
diff --git a/appveyor.yml b/appveyor.yml
index a3b73034..d11d6abf 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,5 +1,8 @@
#version should be only changed with RELEASE eminent, see RELEASE.md
-version: 2.4.{build}
+
+version: 2.9.1-ci-{build}
+
+image: Visual Studio 2019
clone_depth: 1
pull_requests:
@@ -32,6 +35,8 @@ after_test:
artifacts:
- path: 'src/CommandLine/bin/Release/*.nupkg'
name: NuGetPackages
+- path: 'src/CommandLine/bin/Release/*.snupkg'
+ name: symbol
on_failure:
- cmd: |
@@ -39,18 +44,9 @@ on_failure:
appveyor PushArtifact .\files.lst -DeploymentName "Failed Build File Listing"
deploy:
-- provider: GitHub
- auth_token:
- secure: hVyVwHl0JiVq0VxXB4VMRWbUtrGclIzadfnWFcWCQBLvbgMLahLBnWlwGglT63pZ
- artifact: 'NuGetPackages'
- prerelease: false
- force_update: true #fsharp package runs as separate build job, so have to force_update to add fsharp.nuget added
- on:
- APPVEYOR_REPO_TAG: true
-
- provider: NuGet
api_key:
- secure: Ab4T/48EyIJhVrqkfKdUxmHUtseEVuXuyrGACxZ0KN35rb/BzABlBM2YjZojicvT
- artifact: 'NuGetPackages'
+ secure: llMIgYMuLHh9thyKMEAmkWraTaA9Zvcm1F8/yRwm0HCiPIt/ehR/GI4kJKyMTPyf
+ artifact: /.*(\.|\.s)nupkg/
on:
APPVEYOR_REPO_TAG: true
diff --git a/demo/ReadText.Demo/Options.cs b/demo/ReadText.Demo/Options.cs
index ed4db350..3b14014a 100644
--- a/demo/ReadText.Demo/Options.cs
+++ b/demo/ReadText.Demo/Options.cs
@@ -27,7 +27,7 @@ interface IOptions
string FileName { get; set; }
}
- [Verb("head", HelpText = "Displays first lines of a file.")]
+ [Verb("head", true, HelpText = "Displays first lines of a file.")]
class HeadOptions : IOptions
{
public uint? Lines { get; set; }
@@ -62,4 +62,4 @@ class TailOptions : IOptions
public string FileName { get; set; }
}
-}
\ No newline at end of file
+}
diff --git a/demo/ReadText.Demo/ReadText.Demo.csproj b/demo/ReadText.Demo/ReadText.Demo.csproj
index f07c8801..71f16965 100644
--- a/demo/ReadText.Demo/ReadText.Demo.csproj
+++ b/demo/ReadText.Demo/ReadText.Demo.csproj
@@ -1,52 +1,10 @@
-
-
+
- Debug
- AnyCPU
- 12.0.0
- 2.0
- {F9D3B288-1A73-4C91-8ED7-11ED1704B817}
Exe
- ReadText.Demo
- ReadText.Demo
+ net40;net45;net461;netcoreapp2.1;netcoreapp2.0
+false
-
- true
- full
- false
- bin\Debug
- DEBUG;
- prompt
- 4
- true
-
-
- full
- true
- bin\Release
- prompt
- 4
- true
-
-
-
- packages\CommandLineParser.2.1.1-beta\lib\net40\CommandLine.dll
-
-
-
-
-
-
- Properties\SharedAssemblyInfo.cs
-
-
-
-
-
-
- Designer
-
+
-
\ No newline at end of file
diff --git a/demo/ReadText.Demo/ReadText.Demo.sln b/demo/ReadText.Demo/ReadText.Demo.sln
index 1cac367d..cafe0089 100644
--- a/demo/ReadText.Demo/ReadText.Demo.sln
+++ b/demo/ReadText.Demo/ReadText.Demo.sln
@@ -1,9 +1,11 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.31101.0
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.106
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReadText.Demo", "ReadText.Demo.csproj", "{F9D3B288-1A73-4C91-8ED7-11ED1704B817}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReadText.Demo", "ReadText.Demo.csproj", "{F9D3B288-1A73-4C91-8ED7-11ED1704B817}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommandLine", "..\..\src\CommandLine\CommandLine.csproj", "{A03AADAC-F7E5-44A6-8BCC-492B1697CCC9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -15,8 +17,15 @@ Global
{F9D3B288-1A73-4C91-8ED7-11ED1704B817}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F9D3B288-1A73-4C91-8ED7-11ED1704B817}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F9D3B288-1A73-4C91-8ED7-11ED1704B817}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A03AADAC-F7E5-44A6-8BCC-492B1697CCC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A03AADAC-F7E5-44A6-8BCC-492B1697CCC9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A03AADAC-F7E5-44A6-8BCC-492B1697CCC9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A03AADAC-F7E5-44A6-8BCC-492B1697CCC9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {FF14CDF0-EF51-448B-918C-47CD369568DF}
+ EndGlobalSection
EndGlobal
diff --git a/demo/ReadText.LocalizedDemo/.cr/personal/Navigation/RecentFilesHistory.xml b/demo/ReadText.LocalizedDemo/.cr/personal/Navigation/RecentFilesHistory.xml
new file mode 100644
index 00000000..7b2b2ccb
--- /dev/null
+++ b/demo/ReadText.LocalizedDemo/.cr/personal/Navigation/RecentFilesHistory.xml
@@ -0,0 +1,16 @@
+
+
+
+
+ -
+ LocalizableAttributeProperty.cs
+ d:\work\arci\commandline\src\commandline\infrastructure\localizableattributeproperty.cs
+
+
- Infrastructure
+
+ d:\WORK\ARCI\commandline\src\CommandLine\CommandLine.csproj
+ CommandLine
+
+
+
+
\ No newline at end of file
diff --git a/demo/ReadText.LocalizedDemo/LocalizableSentenceBuilder.cs b/demo/ReadText.LocalizedDemo/LocalizableSentenceBuilder.cs
new file mode 100644
index 00000000..bf2b7c56
--- /dev/null
+++ b/demo/ReadText.LocalizedDemo/LocalizableSentenceBuilder.cs
@@ -0,0 +1,122 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using CommandLine;
+using CommandLine.Text;
+
+namespace ReadText.LocalizedDemo
+{
+ public class LocalizableSentenceBuilder : SentenceBuilder
+ {
+ public override Func RequiredWord
+ {
+ get { return () => Properties.Resources.SentenceRequiredWord; }
+ }
+
+ public override Func ErrorsHeadingText
+ {
+ // Cannot be pluralized
+ get { return () => Properties.Resources.SentenceErrorsHeadingText; }
+ }
+
+ public override Func UsageHeadingText
+ {
+ get { return () => Properties.Resources.SentenceUsageHeadingText; }
+ }
+
+ public override Func HelpCommandText
+ {
+ get
+ {
+ return isOption => isOption
+ ? Properties.Resources.SentenceHelpCommandTextOption
+ : Properties.Resources.SentenceHelpCommandTextVerb;
+ }
+ }
+
+ public override Func VersionCommandText
+ {
+ get { return _ => Properties.Resources.SentenceVersionCommandText; }
+ }
+
+ public override Func FormatError
+ {
+ get
+ {
+ return error =>
+ {
+ switch (error.Tag)
+ {
+ case ErrorType.BadFormatTokenError:
+ return String.Format(Properties.Resources.SentenceBadFormatTokenError, ((BadFormatTokenError)error).Token);
+ case ErrorType.MissingValueOptionError:
+ return String.Format(Properties.Resources.SentenceMissingValueOptionError, ((MissingValueOptionError)error).NameInfo.NameText);
+ case ErrorType.UnknownOptionError:
+ return String.Format(Properties.Resources.SentenceUnknownOptionError, ((UnknownOptionError)error).Token);
+ case ErrorType.MissingRequiredOptionError:
+ var errMisssing = ((MissingRequiredOptionError)error);
+ return errMisssing.NameInfo.Equals(NameInfo.EmptyName)
+ ? Properties.Resources.SentenceMissingRequiredOptionError
+ : String.Format(Properties.Resources.SentenceMissingRequiredOptionError, errMisssing.NameInfo.NameText);
+ case ErrorType.BadFormatConversionError:
+ var badFormat = ((BadFormatConversionError)error);
+ return badFormat.NameInfo.Equals(NameInfo.EmptyName)
+ ? Properties.Resources.SentenceBadFormatConversionErrorValue
+ : String.Format(Properties.Resources.SentenceBadFormatConversionErrorOption, badFormat.NameInfo.NameText);
+ case ErrorType.SequenceOutOfRangeError:
+ var seqOutRange = ((SequenceOutOfRangeError)error);
+ return seqOutRange.NameInfo.Equals(NameInfo.EmptyName)
+ ? Properties.Resources.SentenceSequenceOutOfRangeErrorValue
+ : String.Format(Properties.Resources.SentenceSequenceOutOfRangeErrorOption,
+ seqOutRange.NameInfo.NameText);
+ case ErrorType.BadVerbSelectedError:
+ return String.Format(Properties.Resources.SentenceBadVerbSelectedError, ((BadVerbSelectedError)error).Token);
+ case ErrorType.NoVerbSelectedError:
+ return Properties.Resources.SentenceNoVerbSelectedError;
+ case ErrorType.RepeatedOptionError:
+ return String.Format(Properties.Resources.SentenceRepeatedOptionError, ((RepeatedOptionError)error).NameInfo.NameText);
+ case ErrorType.SetValueExceptionError:
+ var setValueError = (SetValueExceptionError)error;
+ return String.Format(Properties.Resources.SentenceSetValueExceptionError, setValueError.NameInfo.NameText, setValueError.Exception.Message);
+ }
+ throw new InvalidOperationException();
+ };
+ }
+ }
+
+ public override Func, string> FormatMutuallyExclusiveSetErrors
+ {
+ get
+ {
+ return errors =>
+ {
+ var bySet = from e in errors
+ group e by e.SetName into g
+ select new { SetName = g.Key, Errors = g.ToList() };
+
+ var msgs = bySet.Select(
+ set =>
+ {
+ var names = String.Join(
+ String.Empty,
+ (from e in set.Errors select String.Format("'{0}', ", e.NameInfo.NameText)).ToArray());
+ var namesCount = set.Errors.Count();
+
+ var incompat = String.Join(
+ String.Empty,
+ (from x in
+ (from s in bySet where !s.SetName.Equals(set.SetName) from e in s.Errors select e)
+ .Distinct()
+ select String.Format("'{0}', ", x.NameInfo.NameText)).ToArray());
+ //TODO: Pluralize by namesCount
+ return
+ String.Format(Properties.Resources.SentenceMutuallyExclusiveSetErrors,
+ names.Substring(0, names.Length - 2), incompat.Substring(0, incompat.Length - 2));
+ }).ToArray();
+ return string.Join(Environment.NewLine, msgs);
+ };
+ }
+ }
+ }
+}
diff --git a/demo/ReadText.LocalizedDemo/Options.cs b/demo/ReadText.LocalizedDemo/Options.cs
new file mode 100644
index 00000000..6ab1e3ee
--- /dev/null
+++ b/demo/ReadText.LocalizedDemo/Options.cs
@@ -0,0 +1,69 @@
+using CommandLine;
+using CommandLine.Text;
+using System.Collections.Generic;
+
+namespace ReadText.LocalizedDemo
+{
+ interface IOptions
+ {
+ [Option('n', "lines",
+ Default = 5U,
+ SetName = "bylines",
+ HelpText = "HelpTextLines",
+ ResourceType = typeof(Properties.Resources))]
+ uint? Lines { get; set; }
+
+ [Option('c', "bytes",
+ SetName = "bybytes",
+ HelpText = "HelpTextBytes",
+ ResourceType = typeof(Properties.Resources))]
+ uint? Bytes { get; set; }
+
+ [Option('q', "quiet",
+ HelpText = "HelpTextQuiet",
+ ResourceType = typeof(Properties.Resources))]
+ bool Quiet { get; set; }
+
+ [Value(0, MetaName = "input file",
+ HelpText = "HelpTextFileName",
+ Required = true,
+ ResourceType = typeof(Properties.Resources))]
+ string FileName { get; set; }
+ }
+
+ [Verb("head", HelpText = "HelpTextVerbHead", ResourceType = typeof(Properties.Resources))]
+ class HeadOptions : IOptions
+ {
+ public uint? Lines { get; set; }
+
+ public uint? Bytes { get; set; }
+
+ public bool Quiet { get; set; }
+
+ public string FileName { get; set; }
+
+ [Usage(ApplicationAlias = "ReadText.LocalizedDemo.exe")]
+ public static IEnumerable Examples
+ {
+ get
+ {
+ yield return new Example(Properties.Resources.ExamplesNormalScenario, new HeadOptions { FileName = "file.bin"});
+ yield return new Example(Properties.Resources.ExamplesSpecifyBytes, new HeadOptions { FileName = "file.bin", Bytes=100 });
+ yield return new Example(Properties.Resources.ExamplesSuppressSummary, UnParserSettings.WithGroupSwitchesOnly(), new HeadOptions { FileName = "file.bin", Quiet = true });
+ yield return new Example(Properties.Resources.ExamplesReadMoreLines, new[] { UnParserSettings.WithGroupSwitchesOnly(), UnParserSettings.WithUseEqualTokenOnly() }, new HeadOptions { FileName = "file.bin", Lines = 10 });
+ }
+ }
+ }
+
+ [Verb("tail", HelpText = "HelpTextVerbTail", ResourceType = typeof(Properties.Resources))]
+ class TailOptions : IOptions
+ {
+ public uint? Lines { get; set; }
+
+ public uint? Bytes { get; set; }
+
+ public bool Quiet { get; set; }
+
+ public string FileName { get; set; }
+ }
+}
diff --git a/demo/ReadText.LocalizedDemo/Program.cs b/demo/ReadText.LocalizedDemo/Program.cs
new file mode 100644
index 00000000..defa6412
--- /dev/null
+++ b/demo/ReadText.LocalizedDemo/Program.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using CommandLine;
+using CommandLine.Text;
+
+namespace ReadText.LocalizedDemo
+{
+ class Program
+ {
+ public static int Main(string[] args)
+ {
+ // Set sentence builder to localizable
+ SentenceBuilder.Factory = () => new LocalizableSentenceBuilder();
+
+ Func reader = opts =>
+ {
+ var fromTop = opts.GetType() == typeof(HeadOptions);
+ return opts.Lines.HasValue
+ ? ReadLines(opts.FileName, fromTop, (int)opts.Lines)
+ : ReadBytes(opts.FileName, fromTop, (int)opts.Bytes);
+ };
+ Func header = opts =>
+ {
+ if (opts.Quiet)
+ {
+ return string.Empty;
+ }
+ var fromTop = opts.GetType() == typeof(HeadOptions);
+ var builder = new StringBuilder(Properties.Resources.Reading);
+ builder = opts.Lines.HasValue
+ ? builder.Append(opts.Lines).Append(Properties.Resources.Lines)
+ : builder.Append(opts.Bytes).Append(Properties.Resources.Bytes);
+ builder = fromTop ? builder.Append(Properties.Resources.FromTop) : builder.Append(Properties.Resources.FromBottom);
+ return builder.ToString();
+ };
+ Action printIfNotEmpty = text =>
+ {
+ if (text.Length == 0) { return; }
+ Console.WriteLine(text);
+ };
+
+ var result = Parser.Default.ParseArguments(args);
+ var texts = result
+ .MapResult(
+ (HeadOptions opts) => Tuple.Create(header(opts), reader(opts)),
+ (TailOptions opts) => Tuple.Create(header(opts), reader(opts)),
+ _ => MakeError());
+
+ printIfNotEmpty(texts.Item1);
+ printIfNotEmpty(texts.Item2);
+
+ return texts.Equals(MakeError()) ? 1 : 0;
+ }
+
+ private static string ReadLines(string fileName, bool fromTop, int count)
+ {
+ var lines = File.ReadAllLines(fileName);
+ if (fromTop)
+ {
+ return string.Join(Environment.NewLine, lines.Take(count));
+ }
+ return string.Join(Environment.NewLine, lines.Reverse().Take(count));
+ }
+
+ private static string ReadBytes(string fileName, bool fromTop, int count)
+ {
+ var bytes = File.ReadAllBytes(fileName);
+ if (fromTop)
+ {
+ return Encoding.UTF8.GetString(bytes, 0, count);
+ }
+ return Encoding.UTF8.GetString(bytes, bytes.Length - count, count);
+ }
+
+ private static Tuple MakeError()
+ {
+ return Tuple.Create("\0", "\0");
+ }
+ }
+}
diff --git a/demo/ReadText.LocalizedDemo/Properties/AssemblyInfo.cs b/demo/ReadText.LocalizedDemo/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..eaf1b66f
--- /dev/null
+++ b/demo/ReadText.LocalizedDemo/Properties/AssemblyInfo.cs
@@ -0,0 +1,11 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyTitle("ReadText.Demo")]
+[assembly: AssemblyDescription("ReadText.Demo for Command Line Parser Library")]
+[assembly: AssemblyTrademark("")]
+#if DEBUG
+[assembly: AssemblyConfiguration("Debug")]
+#else
+[assembly: AssemblyConfiguration("Release")]
+#endif
diff --git a/demo/ReadText.LocalizedDemo/Properties/Resources.Designer.cs b/demo/ReadText.LocalizedDemo/Properties/Resources.Designer.cs
new file mode 100644
index 00000000..f2ca4b31
--- /dev/null
+++ b/demo/ReadText.LocalizedDemo/Properties/Resources.Designer.cs
@@ -0,0 +1,378 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace ReadText.LocalizedDemo.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ public class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ReadText.LocalizedDemo.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to bytes.
+ ///
+ public static string Bytes {
+ get {
+ return ResourceManager.GetString("Bytes", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to normal scenario.
+ ///
+ public static string ExamplesNormalScenario {
+ get {
+ return ResourceManager.GetString("ExamplesNormalScenario", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to read more lines.
+ ///
+ public static string ExamplesReadMoreLines {
+ get {
+ return ResourceManager.GetString("ExamplesReadMoreLines", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to specify bytes.
+ ///
+ public static string ExamplesSpecifyBytes {
+ get {
+ return ResourceManager.GetString("ExamplesSpecifyBytes", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to suppress summary.
+ ///
+ public static string ExamplesSuppressSummary {
+ get {
+ return ResourceManager.GetString("ExamplesSuppressSummary", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to from bottom:.
+ ///
+ public static string FromBottom {
+ get {
+ return ResourceManager.GetString("FromBottom", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to from top:.
+ ///
+ public static string FromTop {
+ get {
+ return ResourceManager.GetString("FromTop", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Bytes to be printed from the beginning or end of the file..
+ ///
+ public static string HelpTextBytes {
+ get {
+ return ResourceManager.GetString("HelpTextBytes", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Input file to be processed..
+ ///
+ public static string HelpTextFileName {
+ get {
+ return ResourceManager.GetString("HelpTextFileName", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Lines to be printed from the beginning or end of the file..
+ ///
+ public static string HelpTextLines {
+ get {
+ return ResourceManager.GetString("HelpTextLines", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Suppresses summary messages..
+ ///
+ public static string HelpTextQuiet {
+ get {
+ return ResourceManager.GetString("HelpTextQuiet", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Displays first lines of a file..
+ ///
+ public static string HelpTextVerbHead {
+ get {
+ return ResourceManager.GetString("HelpTextVerbHead", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Displays last lines of a file..
+ ///
+ public static string HelpTextVerbTail {
+ get {
+ return ResourceManager.GetString("HelpTextVerbTail", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to lines.
+ ///
+ public static string Lines {
+ get {
+ return ResourceManager.GetString("Lines", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Reading .
+ ///
+ public static string Reading {
+ get {
+ return ResourceManager.GetString("Reading", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Možnost '{0}' je definována ve špatném formátu..
+ ///
+ public static string SentenceBadFormatConversionErrorOption {
+ get {
+ return ResourceManager.GetString("SentenceBadFormatConversionErrorOption", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to A value not bound to option name is defined with a bad format..
+ ///
+ public static string SentenceBadFormatConversionErrorValue {
+ get {
+ return ResourceManager.GetString("SentenceBadFormatConversionErrorValue", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Token '{0}' is not recognized..
+ ///
+ public static string SentenceBadFormatTokenError {
+ get {
+ return ResourceManager.GetString("SentenceBadFormatTokenError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Verb '{0}' is not recognized..
+ ///
+ public static string SentenceBadVerbSelectedError {
+ get {
+ return ResourceManager.GetString("SentenceBadVerbSelectedError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to ERROR(S):.
+ ///
+ public static string SentenceErrorsHeadingText {
+ get {
+ return ResourceManager.GetString("SentenceErrorsHeadingText", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Display this help screen..
+ ///
+ public static string SentenceHelpCommandTextOption {
+ get {
+ return ResourceManager.GetString("SentenceHelpCommandTextOption", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Display more information on a specific command..
+ ///
+ public static string SentenceHelpCommandTextVerb {
+ get {
+ return ResourceManager.GetString("SentenceHelpCommandTextVerb", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Required option '{0}' is missing..
+ ///
+ public static string SentenceMissingRequiredOptionError {
+ get {
+ return ResourceManager.GetString("SentenceMissingRequiredOptionError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to A required value not bound to option name is missing..
+ ///
+ public static string SentenceMissingRequiredValueError {
+ get {
+ return ResourceManager.GetString("SentenceMissingRequiredValueError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Option '{0}' has no value..
+ ///
+ public static string SentenceMissingValueOptionError {
+ get {
+ return ResourceManager.GetString("SentenceMissingValueOptionError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Options: {0} are not compatible with {1}..
+ ///
+ public static string SentenceMutuallyExclusiveSetErrors {
+ get {
+ return ResourceManager.GetString("SentenceMutuallyExclusiveSetErrors", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to No verb selected..
+ ///
+ public static string SentenceNoVerbSelectedError {
+ get {
+ return ResourceManager.GetString("SentenceNoVerbSelectedError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Option '{0}' is defined multiple times..
+ ///
+ public static string SentenceRepeatedOptionError {
+ get {
+ return ResourceManager.GetString("SentenceRepeatedOptionError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Required..
+ ///
+ public static string SentenceRequiredWord {
+ get {
+ return ResourceManager.GetString("SentenceRequiredWord", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to A sequence option '{0}' is defined with fewer or more items than required..
+ ///
+ public static string SentenceSequenceOutOfRangeErrorOption {
+ get {
+ return ResourceManager.GetString("SentenceSequenceOutOfRangeErrorOption", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to A sequence value not bound to option name is defined with fewer items than required..
+ ///
+ public static string SentenceSequenceOutOfRangeErrorValue {
+ get {
+ return ResourceManager.GetString("SentenceSequenceOutOfRangeErrorValue", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Error setting value to option '{0}': {1}.
+ ///
+ public static string SentenceSetValueExceptionError {
+ get {
+ return ResourceManager.GetString("SentenceSetValueExceptionError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Option '{0}' is unknown..
+ ///
+ public static string SentenceUnknownOptionError {
+ get {
+ return ResourceManager.GetString("SentenceUnknownOptionError", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to USAGE:.
+ ///
+ public static string SentenceUsageHeadingText {
+ get {
+ return ResourceManager.GetString("SentenceUsageHeadingText", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Display version information..
+ ///
+ public static string SentenceVersionCommandText {
+ get {
+ return ResourceManager.GetString("SentenceVersionCommandText", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/demo/ReadText.LocalizedDemo/Properties/Resources.cs.resx b/demo/ReadText.LocalizedDemo/Properties/Resources.cs.resx
new file mode 100644
index 00000000..cae11e19
--- /dev/null
+++ b/demo/ReadText.LocalizedDemo/Properties/Resources.cs.resx
@@ -0,0 +1,225 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Čtení
+
+
+ řádků
+
+
+ bytů
+
+
+ od začátku:
+
+
+ ok konce:
+
+
+ Počet řádek zobrazených od začátku nebo konce souboru.
+
+
+ Počet bytů zobrazených od začátku nebo konce souboru.
+
+
+ Potlačit sumář.
+
+
+ Jméno vstupního souboru.
+
+
+ Zobrazit první řádky souboru.
+
+
+ normální scénář
+
+
+ specifikace počtu byte
+
+
+ potlačit sumář
+
+
+ přečíst více řádek
+
+
+ Zobrazit poslední řádky souboru.
+
+
+ CHYBY:
+
+
+ Povinné.
+
+
+ POUŽITÍ:
+
+
+ Zobrazit tuto nápovědu.
+
+
+ Zobrazit podrobnou nápovědu pro příkaz.
+
+
+ Zobrazit informaci o verzi.
+
+
+ Token '{0}' nebyl rozpoznán.
+
+
+ Přepínač '{0}' nemá hodnotu.
+
+
+ Neznámý přepínač '{0}'
+
+
+ Přepínač '{0}' je definován ve špatném formátu.
+
+
+ Hodnota nevázaná na přepínač je definována ve špatném formátu.
+
+
+ Příkaz '{0}' nebyl rozpoznán.
+
+
+ Chybí povinný přepínač '{0}'.
+
+
+ Chybí požadovaný přepínač, který není vázán na název možnosti.
+
+
+ Přepínače: {0} nejsou kompatibilní s {1}.
+
+
+ Nebyl vybrán příkaz.
+
+
+ Přepínač '{0}' je definován vícenásobně.
+
+
+ Přepínač sekvence '{0}' je definován méně nebo vícekrát než je povoleno.
+
+
+ Hodnota přepínače je definována méněkrát než je povoleno.
+
+
+ Chyba při nastavení hodnoty přepínače '{0}': {1}
+
+
\ No newline at end of file
diff --git a/demo/ReadText.LocalizedDemo/Properties/Resources.resx b/demo/ReadText.LocalizedDemo/Properties/Resources.resx
new file mode 100644
index 00000000..b002fc43
--- /dev/null
+++ b/demo/ReadText.LocalizedDemo/Properties/Resources.resx
@@ -0,0 +1,225 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Reading
+
+
+ lines
+
+
+ bytes
+
+
+ from top:
+
+
+ from bottom:
+
+
+ Lines to be printed from the beginning or end of the file.
+
+
+ Bytes to be printed from the beginning or end of the file.
+
+
+ Suppresses summary messages.
+
+
+ Input file to be processed.
+
+
+ Displays first lines of a file.
+
+
+ normal scenario
+
+
+ specify bytes
+
+
+ suppress summary
+
+
+ read more lines
+
+
+ Displays last lines of a file.
+
+
+ Možnost '{0}' je definována ve špatném formátu.
+
+
+ A value not bound to option name is defined with a bad format.
+
+
+ Token '{0}' is not recognized.
+
+
+ Verb '{0}' is not recognized.
+
+
+ ERROR(S):
+
+
+ Display this help screen.
+
+
+ Display more information on a specific command.
+
+
+ Required option '{0}' is missing.
+
+
+ A required value not bound to option name is missing.
+
+
+ Option '{0}' has no value.
+
+
+ Options: {0} are not compatible with {1}.
+
+
+ No verb selected.
+
+
+ Option '{0}' is defined multiple times.
+
+
+ Required.
+
+
+ A sequence option '{0}' is defined with fewer or more items than required.
+
+
+ A sequence value not bound to option name is defined with fewer items than required.
+
+
+ Error setting value to option '{0}': {1}
+
+
+ Option '{0}' is unknown.
+
+
+ USAGE:
+
+
+ Display version information.
+
+
\ No newline at end of file
diff --git a/demo/ReadText.LocalizedDemo/Properties/launchSettings.json b/demo/ReadText.LocalizedDemo/Properties/launchSettings.json
new file mode 100644
index 00000000..a5627a1b
--- /dev/null
+++ b/demo/ReadText.LocalizedDemo/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "ReadText.LocalizedDemo": {
+ "commandName": "Project",
+ "commandLineArgs": "head"
+ }
+ }
+}
\ No newline at end of file
diff --git a/demo/ReadText.LocalizedDemo/ReadText.LocalizedDemo.csproj b/demo/ReadText.LocalizedDemo/ReadText.LocalizedDemo.csproj
new file mode 100644
index 00000000..57251e03
--- /dev/null
+++ b/demo/ReadText.LocalizedDemo/ReadText.LocalizedDemo.csproj
@@ -0,0 +1,23 @@
+
+
+ Exe
+ net40;net45;net461;netcoreapp2.1;netcoreapp2.0
+false
+
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+ PublicResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
\ No newline at end of file
diff --git a/demo/ReadText.LocalizedDemo/ReadText.LocalizedDemo.sln b/demo/ReadText.LocalizedDemo/ReadText.LocalizedDemo.sln
new file mode 100644
index 00000000..e769b7da
--- /dev/null
+++ b/demo/ReadText.LocalizedDemo/ReadText.LocalizedDemo.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.106
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReadText.LocalizedDemo", "ReadText.LocalizedDemo.csproj", "{F9D3B288-1A73-4C91-8ED7-11ED1704B817}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommandLine", "..\..\src\CommandLine\CommandLine.csproj", "{A03AADAC-F7E5-44A6-8BCC-492B1697CCC9}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F9D3B288-1A73-4C91-8ED7-11ED1704B817}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F9D3B288-1A73-4C91-8ED7-11ED1704B817}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F9D3B288-1A73-4C91-8ED7-11ED1704B817}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F9D3B288-1A73-4C91-8ED7-11ED1704B817}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A03AADAC-F7E5-44A6-8BCC-492B1697CCC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A03AADAC-F7E5-44A6-8BCC-492B1697CCC9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A03AADAC-F7E5-44A6-8BCC-492B1697CCC9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A03AADAC-F7E5-44A6-8BCC-492B1697CCC9}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {FF14CDF0-EF51-448B-918C-47CD369568DF}
+ EndGlobalSection
+EndGlobal
diff --git a/demo/ReadText.LocalizedDemo/packages.config b/demo/ReadText.LocalizedDemo/packages.config
new file mode 100644
index 00000000..d34c1336
--- /dev/null
+++ b/demo/ReadText.LocalizedDemo/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/demo/fsharp-demo.fsx b/demo/fsharp-demo.fsx
index 81b1640d..8aff84e3 100644
--- a/demo/fsharp-demo.fsx
+++ b/demo/fsharp-demo.fsx
@@ -22,9 +22,11 @@ let formatLong o =
let formatInput (o : options) =
sprintf "--stringvalue: %s\n-i: %A\n-x: %b\nvalue: %s\n" o.stringValue o.intSequence o.boolValue (formatLong o.longValue)
-let inline (|Success|Fail|) (result : ParserResult<'a>) =
+let inline (|Success|Help|Version|Fail|) (result : ParserResult<'a>) =
match result with
| :? Parsed<'a> as parsed -> Success(parsed.Value)
+ | :? NotParsed<'a> as notParsed when notParsed.Errors.IsHelp() -> Help
+ | :? NotParsed<'a> as notParsed when notParsed.Errors.IsVersion() -> Version
| :? NotParsed<'a> as notParsed -> Fail(notParsed.Errors)
| _ -> failwith "invalid parser result"
@@ -34,3 +36,4 @@ let result = Parser.Default.ParseArguments(args)
match result with
| Success(opts) -> printf "%s" (formatInput opts)
| Fail(errs) -> printf "Invalid: %A, Errors: %u\n" args (Seq.length errs)
+ | Help | Version -> ()
diff --git a/src/CommandLine/BaseAttribute.cs b/src/CommandLine/BaseAttribute.cs
index 255dc0d1..be0a3826 100644
--- a/src/CommandLine/BaseAttribute.cs
+++ b/src/CommandLine/BaseAttribute.cs
@@ -12,8 +12,9 @@ public abstract class BaseAttribute : Attribute
private int min;
private int max;
private object @default;
- private string helpText;
+ private Infrastructure.LocalizableAttributeProperty helpText;
private string metaValue;
+ private Type resourceType;
///
/// Initializes a new instance of the class.
@@ -22,8 +23,9 @@ protected internal BaseAttribute()
{
min = -1;
max = -1;
- helpText = string.Empty;
+ helpText = new Infrastructure.LocalizableAttributeProperty(nameof(HelpText));
metaValue = string.Empty;
+ resourceType = null;
}
///
@@ -90,11 +92,8 @@ public object Default
///
public string HelpText
{
- get { return helpText; }
- set
- {
- helpText = value ?? throw new ArgumentNullException("value");
- }
+ get => helpText.Value??string.Empty;
+ set => helpText.Value = value ?? throw new ArgumentNullException("value");
}
///
@@ -105,7 +104,12 @@ public string MetaValue
get { return metaValue; }
set
{
- metaValue = value ?? throw new ArgumentNullException("value");
+ if (value == null)
+ {
+ throw new ArgumentNullException("value");
+ }
+
+ metaValue = value;
}
}
@@ -117,5 +121,18 @@ public bool Hidden
get;
set;
}
+
+ ///
+ /// Gets or sets the that contains the resources for .
+ ///
+ public Type ResourceType
+ {
+ get { return resourceType; }
+ set
+ {
+ resourceType =
+ helpText.ResourceType = value;
+ }
+ }
}
}
diff --git a/src/CommandLine/CastExtensions.cs b/src/CommandLine/CastExtensions.cs
new file mode 100644
index 00000000..fa34928c
--- /dev/null
+++ b/src/CommandLine/CastExtensions.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Linq;
+using System.Reflection;
+
+namespace CommandLine
+{
+ internal static class CastExtensions
+ {
+ private const string ImplicitCastMethodName = "op_Implicit";
+ private const string ExplicitCastMethodName = "op_Explicit";
+
+ public static bool CanCast(this Type baseType)
+ {
+ return baseType.CanImplicitCast() || baseType.CanExplicitCast();
+ }
+
+ public static bool CanCast(this object obj)
+ {
+ var objType = obj.GetType();
+ return objType.CanCast();
+ }
+
+ public static T Cast(this object obj)
+ {
+ try
+ {
+ return (T) obj;
+ }
+ catch (InvalidCastException)
+ {
+ if (obj.CanImplicitCast())
+ return obj.ImplicitCast();
+ if (obj.CanExplicitCast())
+ return obj.ExplicitCast();
+ else
+ throw;
+ }
+ }
+
+ private static bool CanImplicitCast(this Type baseType)
+ {
+ return baseType.CanCast(ImplicitCastMethodName);
+ }
+
+ private static bool CanImplicitCast(this object obj)
+ {
+ var baseType = obj.GetType();
+ return baseType.CanImplicitCast();
+ }
+
+ private static bool CanExplicitCast(this Type baseType)
+ {
+ return baseType.CanCast(ExplicitCastMethodName);
+ }
+
+ private static bool CanExplicitCast(this object obj)
+ {
+ var baseType = obj.GetType();
+ return baseType.CanExplicitCast();
+ }
+
+ private static bool CanCast(this Type baseType, string castMethodName)
+ {
+ var targetType = typeof(T);
+ return baseType.GetMethods(BindingFlags.Public | BindingFlags.Static)
+ .Where(mi => mi.Name == castMethodName && mi.ReturnType == targetType)
+ .Any(mi =>
+ {
+ ParameterInfo pi = mi.GetParameters().FirstOrDefault();
+ return pi != null && pi.ParameterType == baseType;
+ });
+ }
+
+ private static T ImplicitCast(this object obj)
+ {
+ return obj.Cast(ImplicitCastMethodName);
+ }
+
+ private static T ExplicitCast(this object obj)
+ {
+ return obj.Cast(ExplicitCastMethodName);
+ }
+
+ private static T Cast(this object obj, string castMethodName)
+ {
+ var objType = obj.GetType();
+ MethodInfo conversionMethod = objType.GetMethods(BindingFlags.Public | BindingFlags.Static)
+ .Where(mi => mi.Name == castMethodName && mi.ReturnType == typeof(T))
+ .SingleOrDefault(mi =>
+ {
+ ParameterInfo pi = mi.GetParameters().FirstOrDefault();
+ return pi != null && pi.ParameterType == objType;
+ });
+ if (conversionMethod != null)
+ return (T) conversionMethod.Invoke(null, new[] {obj});
+ else
+ throw new InvalidCastException($"No method to cast {objType.FullName} to {typeof(T).FullName}");
+ }
+ }
+}
diff --git a/src/CommandLine/CommandLine.csproj b/src/CommandLine/CommandLine.csproj
index 46cd3c1c..04496eb8 100644
--- a/src/CommandLine/CommandLine.csproj
+++ b/src/CommandLine/CommandLine.csproj
@@ -1,42 +1,56 @@
-
- CommandLine
- Library
- netstandard2.0
- $(DefineConstants);CSX_EITHER_INTERNAL;CSX_REM_EITHER_BEYOND_2;CSX_ENUM_INTERNAL;ERRH_INTERNAL;ERRH_DISABLE_INLINE_METHODS;CSX_MAYBE_INTERNAL;CSX_REM_EITHER_FUNC
- $(DefineConstants);SKIP_FSHARP
- true
- ..\..\CommandLine.snk
- true
- CommandLineParser
- CommandLineParser.FSharp
- gsscoder;nemec;ericnewton76
- Command Line Parser Library
- $(VersionSuffix)
- 2.4.0
- Terse syntax C# command line parser for .NET. For FSharp support see CommandLineParser.FSharp. The Command Line Parser Library offers to CLR applications a clean and concise API for manipulating command line arguments and related tasks.
- Terse syntax C# command line parser for .NET with F# support. The Command Line Parser Library offers to CLR applications a clean and concise API for manipulating command line arguments and related tasks.
- Copyright (c) 2005 - 2018 Giacomo Stelluti Scala & Contributors
- https://raw.githubusercontent.com/gsscoder/commandline/master/doc/LICENSE
- https://github.com/gsscoder/commandline
- https://raw.githubusercontent.com/commandlineparser/commandline/master/art/CommandLine20.png
- command line;commandline;argument;option;parser;parsing;library;syntax;shell
-
+
+ CommandLine
+ Library
+ netstandard2.0;net40;net45;net461
+ $(DefineConstants);CSX_EITHER_INTERNAL;CSX_REM_EITHER_BEYOND_2;CSX_ENUM_INTERNAL;ERRH_INTERNAL;CSX_MAYBE_INTERNAL;CSX_REM_EITHER_FUNC;CSX_REM_CRYPTORAND;ERRH_ADD_MAYBE_METHODS
+ $(DefineConstants);SKIP_FSHARP
+ true
+ ..\..\CommandLine.snk
+ true
+ CommandLineParser
+ CommandLineParser.FSharp
+ gsscoder;nemec;ericnewton76;moh-hassan
+ Command Line Parser Library
+ $(VersionSuffix)
+ 0.0.0
+ Terse syntax C# command line parser for .NET. For FSharp support see CommandLineParser.FSharp. The Command Line Parser Library offers to CLR applications a clean and concise API for manipulating command line arguments and related tasks.
+ Terse syntax C# command line parser for .NET with F# support. The Command Line Parser Library offers to CLR applications a clean and concise API for manipulating command line arguments and related tasks.
+ Copyright (c) 2005 - 2020 Giacomo Stelluti Scala & Contributors
+ License.md
+ CommandLine20.png
+ https://github.com/commandlineparser/commandline
+ command line;commandline;argument;option;parser;parsing;library;syntax;shell
+ https://github.com/commandlineparser/commandline/blob/master/CHANGELOG.md
+ true
+ 8.0
+ true
+ snupkg
+
-
-
-
+
+
+
-
-
- true
- README.md
-
-
+
+
+ true
+ README.md
+
+
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/CommandLine/Core/GetoptTokenizer.cs b/src/CommandLine/Core/GetoptTokenizer.cs
new file mode 100644
index 00000000..b8c97fc2
--- /dev/null
+++ b/src/CommandLine/Core/GetoptTokenizer.cs
@@ -0,0 +1,228 @@
+// Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using CommandLine.Infrastructure;
+using CSharpx;
+using RailwaySharp.ErrorHandling;
+using System.Text.RegularExpressions;
+
+namespace CommandLine.Core
+{
+ static class GetoptTokenizer
+ {
+ public static Result, Error> Tokenize(
+ IEnumerable arguments,
+ Func nameLookup)
+ {
+ return GetoptTokenizer.Tokenize(arguments, nameLookup, ignoreUnknownArguments:false, allowDashDash:true, posixlyCorrect:false);
+ }
+
+ public static Result, Error> Tokenize(
+ IEnumerable arguments,
+ Func nameLookup,
+ bool ignoreUnknownArguments,
+ bool allowDashDash,
+ bool posixlyCorrect)
+ {
+ var errors = new List();
+ Action onBadFormatToken = arg => errors.Add(new BadFormatTokenError(arg));
+ Action unknownOptionError = name => errors.Add(new UnknownOptionError(name));
+ Action doNothing = name => {};
+ Action onUnknownOption = ignoreUnknownArguments ? doNothing : unknownOptionError;
+
+ int consumeNext = 0;
+ Action onConsumeNext = (n => consumeNext = consumeNext + n);
+ bool forceValues = false;
+
+ var tokens = new List();
+
+ var enumerator = arguments.GetEnumerator();
+ while (enumerator.MoveNext())
+ {
+ switch (enumerator.Current) {
+ case null:
+ break;
+
+ case string arg when forceValues:
+ tokens.Add(Token.ValueForced(arg));
+ break;
+
+ case string arg when consumeNext > 0:
+ tokens.Add(Token.Value(arg));
+ consumeNext = consumeNext - 1;
+ break;
+
+ case "--" when allowDashDash:
+ forceValues = true;
+ break;
+
+ case "--":
+ tokens.Add(Token.Value("--"));
+ if (posixlyCorrect) forceValues = true;
+ break;
+
+ case "-":
+ // A single hyphen is always a value (it usually means "read from stdin" or "write to stdout")
+ tokens.Add(Token.Value("-"));
+ if (posixlyCorrect) forceValues = true;
+ break;
+
+ case string arg when arg.StartsWith("--"):
+ tokens.AddRange(TokenizeLongName(arg, nameLookup, onBadFormatToken, onUnknownOption, onConsumeNext));
+ break;
+
+ case string arg when arg.StartsWith("-"):
+ tokens.AddRange(TokenizeShortName(arg, nameLookup, onUnknownOption, onConsumeNext));
+ break;
+
+ case string arg:
+ // If we get this far, it's a plain value
+ tokens.Add(Token.Value(arg));
+ if (posixlyCorrect) forceValues = true;
+ break;
+ }
+ }
+
+ return Result.Succeed, Error>(tokens.AsEnumerable(), errors.AsEnumerable());
+ }
+
+ public static Result, Error> ExplodeOptionList(
+ Result, Error> tokenizerResult,
+ Func> optionSequenceWithSeparatorLookup)
+ {
+ var tokens = tokenizerResult.SucceededWith().Memoize();
+
+ var exploded = new List(tokens is ICollection coll ? coll.Count : tokens.Count());
+ var nothing = Maybe.Nothing(); // Re-use same Nothing instance for efficiency
+ var separator = nothing;
+ foreach (var token in tokens) {
+ if (token.IsName()) {
+ separator = optionSequenceWithSeparatorLookup(token.Text);
+ exploded.Add(token);
+ } else {
+ // Forced values are never considered option values, so they should not be split
+ if (separator.MatchJust(out char sep) && sep != '\0' && !token.IsValueForced()) {
+ if (token.Text.Contains(sep)) {
+ exploded.AddRange(token.Text.Split(sep).Select(Token.ValueFromSeparator));
+ } else {
+ exploded.Add(token);
+ }
+ } else {
+ exploded.Add(token);
+ }
+ separator = nothing; // Only first value after a separator can possibly be split
+ }
+ }
+ return Result.Succeed(exploded as IEnumerable, tokenizerResult.SuccessMessages());
+ }
+
+ public static Func<
+ IEnumerable,
+ IEnumerable,
+ Result, Error>>
+ ConfigureTokenizer(
+ StringComparer nameComparer,
+ bool ignoreUnknownArguments,
+ bool enableDashDash,
+ bool posixlyCorrect)
+ {
+ return (arguments, optionSpecs) =>
+ {
+ var tokens = GetoptTokenizer.Tokenize(arguments, name => NameLookup.Contains(name, optionSpecs, nameComparer), ignoreUnknownArguments, enableDashDash, posixlyCorrect);
+ var explodedTokens = GetoptTokenizer.ExplodeOptionList(tokens, name => NameLookup.HavingSeparator(name, optionSpecs, nameComparer));
+ return explodedTokens;
+ };
+ }
+
+ private static IEnumerable TokenizeShortName(
+ string arg,
+ Func nameLookup,
+ Action onUnknownOption,
+ Action onConsumeNext)
+ {
+
+ // First option char that requires a value means we swallow the rest of the string as the value
+ // But if there is no rest of the string, then instead we swallow the next argument
+ string chars = arg.Substring(1);
+ int len = chars.Length;
+ if (len > 0 && Char.IsDigit(chars[0]))
+ {
+ // Assume it's a negative number
+ yield return Token.Value(arg);
+ yield break;
+ }
+ for (int i = 0; i < len; i++)
+ {
+ var s = new String(chars[i], 1);
+ switch(nameLookup(s))
+ {
+ case NameLookupResult.OtherOptionFound:
+ yield return Token.Name(s);
+
+ if (i+1 < len)
+ {
+ // Rest of this is the value (e.g. "-sfoo" where "-s" is a string-consuming arg)
+ yield return Token.Value(chars.Substring(i+1));
+ yield break;
+ }
+ else
+ {
+ // Value is in next param (e.g., "-s foo")
+ onConsumeNext(1);
+ }
+ break;
+
+ case NameLookupResult.NoOptionFound:
+ onUnknownOption(s);
+ break;
+
+ default:
+ yield return Token.Name(s);
+ break;
+ }
+ }
+ }
+
+ private static IEnumerable TokenizeLongName(
+ string arg,
+ Func nameLookup,
+ Action onBadFormatToken,
+ Action onUnknownOption,
+ Action onConsumeNext)
+ {
+ string[] parts = arg.Substring(2).Split(new char[] { '=' }, 2);
+ string name = parts[0];
+ string value = (parts.Length > 1) ? parts[1] : null;
+ // A parameter like "--stringvalue=" is acceptable, and makes stringvalue be the empty string
+ if (String.IsNullOrWhiteSpace(name) || name.Contains(" "))
+ {
+ onBadFormatToken(arg);
+ yield break;
+ }
+ switch(nameLookup(name))
+ {
+ case NameLookupResult.NoOptionFound:
+ onUnknownOption(name);
+ yield break;
+
+ case NameLookupResult.OtherOptionFound:
+ yield return Token.Name(name);
+ if (value == null) // NOT String.IsNullOrEmpty
+ {
+ onConsumeNext(1);
+ }
+ else
+ {
+ yield return Token.Value(value);
+ }
+ break;
+
+ default:
+ yield return Token.Name(name);
+ break;
+ }
+ }
+ }
+}
diff --git a/src/CommandLine/Core/InstanceBuilder.cs b/src/CommandLine/Core/InstanceBuilder.cs
index 82c29ea8..f48127b1 100644
--- a/src/CommandLine/Core/InstanceBuilder.cs
+++ b/src/CommandLine/Core/InstanceBuilder.cs
@@ -24,54 +24,78 @@ public static ParserResult Build(
bool autoVersion,
IEnumerable nonFatalErrors)
{
+ return Build(
+ factory,
+ tokenizer,
+ arguments,
+ nameComparer,
+ ignoreValueCase,
+ parsingCulture,
+ autoHelp,
+ autoVersion,
+ false,
+ nonFatalErrors);
+ }
+
+ public static ParserResult Build(
+ Maybe> factory,
+ Func, IEnumerable, Result, Error>> tokenizer,
+ IEnumerable arguments,
+ StringComparer nameComparer,
+ bool ignoreValueCase,
+ CultureInfo parsingCulture,
+ bool autoHelp,
+ bool autoVersion,
+ bool allowMultiInstance,
+ IEnumerable nonFatalErrors) {
var typeInfo = factory.MapValueOrDefault(f => f().GetType(), typeof(T));
var specProps = typeInfo.GetSpecifications(pi => SpecificationProperty.Create(
Specification.FromProperty(pi), pi, Maybe.Nothing