command-line-api
command-line-api copied to clipboard
No way to distinguish between ParseArgument invoked for user-supplied input and default value
When using an option that has a custom parser with isDefault set to true, the custom parser cannot distinguish between being invoked to provide a default value and being invoked to parse input that has no tokens.
Example:
private static IEnumerable<string> Formats { get; } = new List<string>
{
"foo",
"bar"
};
var option = new Option<List<string>>("--formats",
parseArgument: ParseFormats,
isDefault: true,
description: "Narrows the operation to process only files with these formats. Supported formats: "
+ string.Join(", ", Formats)));
private static List<string> ParseFormats(ArgumentResult result)
{
var formats = result.Tokens.Select(t => t.Value).ToList();
var invalidFormats = formats.Where(t => !Formats.Contains(t));
if (invalidFormats.Any())
{
result.ErrorMessage = $"One or more formats are invalid: {string.Join(", ", invalidFormats)}";
}
//Not provided or no formats specified on the command line
else if (formats.Count == 0)
{
return Formats.ToList();
}
return formats;
}
(Formats cannot be an enum here because the list in the actual code is constructed from a list of objects providing a string property)
In this case the parser cannot constrain input to require one or more tokens because this will also be the case when getting a default value.
Some way to know when it's being invoked for a default value would be nice.
In this case the parser cannot constrain input to require one or more tokens because this will also be the case when getting a default value.
It sounds to me you want to set the min/max number of required arguments for your --formats option. Unless i misunderstood you, is there a particular reason why you are not setting the option argument arity to achieve this?
In this case the parser cannot constrain input to require one or more tokens because this will also be the case when getting a default value.
It sounds to me you want to set the min/max number of required arguments for your --formats option. Unless i have misunderstood you, is there a particular reason why you are not setting the option argument arity to achieve this?
Because i can't do that. The Option API doesn't let you set arity when using the custom parser constructor:
https://github.com/dotnet/command-line-api/blob/56139ef91d83b1ba86b8ffbd81e0f88298bd21ae/src/System.CommandLine/Option%7BT%7D.cs#L32-L38
Oh dang... :-(
You can now set Option.Arity.
Another thing you can do is to check whether the ArgumentResult is implicit (indicating it was created via the default value because there were no tokens provided on the command line).
Maybe we should make this property public:
https://github.com/dotnet/command-line-api/blob/b751c2e3cc5aeee1916be9892a2fee5ddbef69fb/src/System.CommandLine/Parsing/ArgumentResult.cs#L30
This does the job, thank you. I agree that the IsImplicit property should be made public. Being able to differentiate between the default and a user-provided value could be very useful.
Does this still require feedback or was my comment above sufficient?
https://github.com/dotnet/command-line-api/pull/2073 may have fixed this, by giving Argument<T> and Option<T> separate DefaultValueFactory and CustomParser properties, each of which has type Func<ArgumentResult, T>?.
Looks like it, that seems to solve the problem entirely.