Closed NeilMacMullen closed 11 months ago
Hi, I am glad you found it useful.
I have just released v1.4.0 which now has better Parse methods:
If you need to simply parse the command-line arguments without invocation, use this:
var rootCliCommand = Cli.Parse<RootCliCommand>(args);
If you need to examine the parse result, such as errors:
var rootCliCommand = Cli.Parse<RootCliCommand>(args, out var parseResult);
if (parseResult.Errors.Count > 0)
{
}
By the way you don't need to tokenize UiControl.Text
, there are already methods signatures for Run<> and Parse<> which accepts a command line string too (in addition to array).
Thanks - that sounds like what I was looking for but I can't seem to get it to work (at least, not the way I was expecting it to work...)
internal class Program
{
private static void Main(string[] args)
{
var testArgs = "--First 100 --Second 200";
var testCommand = Cli.Parse<TestCommand>(testArgs, out var parseResult);
foreach (var error in parseResult.Errors)
Console.WriteLine($"ERROR: {error.Message}");
Console.WriteLine($"Parsed: '{testCommand.First}','{testCommand.Second}'");
}
}
[CliCommand]
public class TestCommand
{
[CliArgument] public string First { get; set; } = "1";
[CliArgument] public string Second { get; set; } = "2";
}
produces this output with 1.4.0...
ERROR: Unrecognized command or argument '--Second'.
ERROR: Unrecognized command or argument '200'.
Parsed: '--First','100'
You need to use [CliOption]
instead of [CliArgument]
so your class should look like this:
[CliCommand]
public class TestCommand
{
[CliOption] public string First { get; set; } = "1";
[CliOption] public string Second { get; set; } = "2";
}
Argument means a value which is passed to a command or an option. For example in 100 --Second 200
, 100 would be an argument for the root command, and 200 would be the argument for the option --Second
. Option means a name-value pair, argument means only the value.
So from the parser perspective, when you pass --First 100 --Second 200
, it sees 4 arguments because in your class you only define 2 arguments and parser does not know any option names. That's why you get Parsed: '--First','100'
.
Ah - yes that makes sense. Was a bit confused coming from the CommandLineParser library where everything is an 'Option' but you can supply a "Position" property on the attribute to allow it to be used as argument if you prefer. (In other words it's similar to the powershell model where you can choose to write
my.exe run -width 100
or
my.exe run 100
Anyway, it works great with CliOption (when I also remembered to lower-case the option names) - thanks again, definitely going to be using this library going forward. :-)
Yes, System.CommandLine and so this library distinguishes options and arguments. Options have a name (usually with a prefix) and an argument with specific type (string, bool, int vs.). Arguments are values passed to an option or a root command or a sub-command. Options can be specified in any order. Arguments, when they are multiple, the order does matter so they are positional. I recommend you take a look at https://learn.microsoft.com/en-us/dotnet/standard/commandline/syntax for more details.
Note that you can have a specific type for a Property with a CliOption or CliArgument, for example you can use int
for your options and this will be parsed automatically:
[CliCommand]
public class TestCommand
{
[CliOption] public int First { get; set; } = 1;
[CliOption] public int Second { get; set; } = 2;
}
Supported types:
bool
byte
DateTime
DateTimeOffset
decimal
double
float
Guid
int
long
sbyte
short
uint
ulong
ushort
when I also remembered to lower-case the option names
This is because, by default the property names are converted to kebab-case (e.g. PropertyName
-> property-Name
), however you can change this:
[CliCommand(NameCasingConvention = CliNameCasingConvention.None)]
public class TestCommand
{
[CliOption] public int First { get; set; } = 1;
[CliOption] public int Second { get; set; } = 2;
}
Then the parser would be able to parse --First 100 --Second 200
because it knows the option names are First
and Second
(and not first
and second
). Command and option names and aliases are case-sensitive by default according to POSIX convention. If you want your CLI to be case insensitive, define aliases for the various casing alternatives. For example, First
property could have aliases --first
and --FIRST
.
84dcd0b
This library looks great!
In some applications it's useful to be able to treat a string supplied by the user as a "command line" and to populate the properties of an "options" object with the parsed values. The options can then be used later on in a different context . In the ideal world I'd like to be able to write something like this...
I may be missing something but I can't see an easy way of achieving this?
On a related note, it would be really nice to expose an implementation of "Tokenise" that correctly handles quotes and escapes but I assume this is regarded as a responsibility of the shell and considered out of scope.