Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pipe character for listing options e.g. --option [RED|GREEN|BLUE] #1434

Closed
peteristhegreat opened this issue Jan 22, 2024 · 4 comments · Fixed by #1498
Closed

Pipe character for listing options e.g. --option [RED|GREEN|BLUE] #1434

peteristhegreat opened this issue Jan 22, 2024 · 4 comments · Fixed by #1498
Labels
area-CLI Command-Line Interface feature
Milestone

Comments

@peteristhegreat
Copy link

peteristhegreat commented Jan 22, 2024

Is your feature request related to a problem? Please describe.
Right now, if I describe a CommandSetting with [CommandOption("--option [RED|GREEN|BLUE]")], it fails with

Error: An error occured when parsing template.
       Encountered invalid character '|' in value name.

       --option [RED|GREEN|BLUE]
                    ^ Invalid character

Likely caused by this line:
https://github.com/spectreconsole/spectre.console/blob/main/src/Spectre.Console.Cli/Internal/Configuration/TemplateParser.cs#L91

Describe the solution you'd like
I don't really expect the validation to use the list I put in the help text, but I would like it to allow the concise help to be able to show a list of acceptable answers instead of having to put it in the description.

Describe alternatives you've considered
I tried commas, and with angle brackets.

I think my next best workaround is something like:

[CommandOption("--option <RED_or_GREEN_or_BLUE>")]

or

[CommandOption("--option <COLOR>")]
[Description("Options for COLOR are RED, GREEN, or BLUE.")]

But both of the above doesn't seem quite as concise as my proposed solution of supporting the pipe character.

Additional context
If there is a better way to do this for this library, maybe seeing an example in the docs would be nice.

Also, thanks for the awesome library. The docs are awesome, and I am loving the experience using it so far.


Please upvote 👍 this issue if you are interested in it.

@FrankRay78
Copy link
Contributor

Hi @peteristhegreat, out of interest, what is the type for the color option? ie. are these strings or Spectre.Console.Color or System.Drawing.Color

I ask, because it would be helpful to know.

I wonder if a similar thing for other values is/may be needed? eg. allowable ints of 1, 5 or 10

I know we can do this with custom validation, but that's after the fact, and I'd like to look into this more with the premise of better supporting the input behaviour at the CommandOption definition

@peteristhegreat
Copy link
Author

peteristhegreat commented Mar 15, 2024 via email

@FrankRay78
Copy link
Contributor

Ok, I've started looking into this and I have managed to come up with a half decent solution (imho). See:

using Spectre.Console;
using Spectre.Console.Cli;
using System.ComponentModel;

namespace ConsoleApp1;

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public sealed class AllowedValuesValidationAttribute : ParameterValidationAttribute
{
    string[] allowedValues;

    private static string FormatErrorMessage(string[] values)
    {
        return $"Must be {string.Join(", ", values)}.";
    }

    public AllowedValuesValidationAttribute(params string[] values)
        : base(FormatErrorMessage(values))
    {
        allowedValues = values;
    }

    public override ValidationResult Validate(CommandParameterContext context)
    {
        if (context.Value is string str)
        {
            if (allowedValues.Any(a => a.Equals(str ?? "")))
            {
                return ValidationResult.Success();
            }

            return ValidationResult.Error();
        }

        throw new InvalidOperationException();
    }
}

public sealed class SomeCommandSettings : CommandSettings
{
    [CommandOption("--account-type")]
    [DefaultValue("FREE")]
    [Description("FREE, HOBBY or PRO.")]
    [AllowedValuesValidation("FREE", "HOBBY", "PRO")]
    public string AccountType { get; set; }
}

public sealed class SomeCommand : Command<SomeCommandSettings>
{
    public SomeCommand()
    {
    }

    public override int Execute(CommandContext context, SomeCommandSettings settings)
    {
        AnsiConsole.WriteLine($"AccountType: {settings.AccountType ?? ""}");
        return 0;
    }
}

public class Program
{
    static void Main(string[] args)
    {
        var app = new CommandApp<SomeCommand>();
        app.Run(args);
    }
}

Which performs as follows:

image

Pipe parsing error

That said, I want to take a look into the pipe parsing error, as perhaps that's easily fixed.

I notice that the Microsoft CommandLine (a poor competitor to spectre.console 🤣) allows the pipe as a delimiter:

image

https://learn.microsoft.com/en-us/dotnet/standard/commandline/define-commands

@FrankRay78
Copy link
Contributor

As far as I can tell, the Option Value is for display purposes in the command help (ie. when -h or --help is run), and so I cannot see any reason as to why the pipe command shouldn't be allowed.

Any validation of the actual allowable values entered on the command line can be done through validators, as per above.

This looks to me as the offending line, preventing the pipe delimiter being used:

character != '=' && character != '-' && character != '_')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-CLI Command-Line Interface feature
Projects
Status: Done 🚀
Development

Successfully merging a pull request may close this issue.

3 participants