spectreconsole / spectre.console

A .NET library that makes it easier to create beautiful console applications.

Home Page:https://spectreconsole.net

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

peteristhegreat opened this issue · comments

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.

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

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

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 != '_')