Coder Social home page Coder Social logo

spectre.cli's Introduction

spectre.cli's People

Contributors

daveaglick avatar devlead avatar gep13 avatar patriksvensson avatar rajivharris avatar simoncropp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spectre.cli's Issues

Runtime command description override

Now that we can change the behavior of a command at runtime by either passing data to it or doing something different based on the command name, being able to change the description of a command at runtime would be helpful too.

I propose a new WithDescription(string description) fluent method to set a description override when registering commands. Anything provided through the method will override an existing attribute-based description on the command class.

If you’re okay with the change I’ll submit a PR.

Delegate commands

One of the evil things I was able to do with the new command data passing is implement delegate-based commands using a single DelegateCommand<TSettings> class and passing the delegate in as data. Is this something that would be cool in-the-box?

Usage would look like this:

public class QuoteCommandSettings : CommandSettings
{
    public string Quote { get; set; }
}

public class Program
{
    public static int Main(string[] args)
    {
        var app = new CommandApp();

        app.Configure(config =>
        {
            config.AddCommand<QuoteCommandSettings>(
                (context, settings) => Console.WriteLine(
                    $”Abe Lincoln once said {settings.Quote}”));
        });

        return app.Run(args);
    }
}

Any interest in me pulling this in?

Add non-generic overloads for `AddBranch` and/or `AddCommand`

If you don't feel this is a good feature, feel free to close, but I just ran into this problem in an app and thought I'd suggest it.

Having an overload for AddBranch or AddCommand that supports specifying the settings type as a parameter would make it possible to add commands without access to the type parameter (e.g. dynamically added commands).

I'm not sure if this is possible given there'd be no way to know what settings type to pass to the IConfigurator but maybe you can think of something I can't!

For example:

void AddBranch(string name, Type settingsType, Action<IConfigurator<>> action);

--

This is similar to what's available in the Microsoft.Extensions packages:

services.AddSingleton<ConfigLoader>();
// is equivalent to 
services.AddSingleton(typeof(ConfigLoader), objectInstance);

A way to pass data to commands

What I want to do is register multiple commands using the same command type but pass different data to it when defining the commands. In other words, I want to be able to create a "dynamic" command at run time using the same base command.

The easiest way I can think to do this is add something like an object Data { get; } to the CommandContext and pass it through.

I imagine this might look something like:

public class FooCommandSettings : CommandSettings
{
    public string Bar { get; set; }
}

public class FooCommand : AsyncCommand<FooCommandSettings>
{
    public sealed override async Task<int> ExecuteAsync(
        CommandContext context, FooCommandSettings settings)
    {
        Console.WriteLine(context.Data + settings.Bar);
    }
}

public class Program
{
    public static int Main(string[] args)
    {
        var app = new CommandApp();

        app.Configure(config =>
        {
            // Set CommandContext.Data to "FIZZ"
            config.AddCommand<FooCommand >("fizz", "FIZZ");
            // Set CommandContext.Data to "FUZZ"
            config.AddCommand<FooCommand >("fuzz", "FUZZ");
        });

        return app.Run(args);
    }
}

Thoughts? Would you accept a PR?

Parameter dependencies

Would be nice to be able to tell the command line parsing engine that an argument is dependent on another options existence (or non-existence).

public sealed class AddCustomerSettings
{
  [CommandOption("--email <EMAIL>")]
  public string Email { get; set; }

  [CommandOption("--wantemail")]
  [MustBeProvided(nameof(Email), "No email has been provided.")]
  public bool WantsEmail { get; set; }

  [CommandOption("--noemail")]
  [MustNotBeProvided(nameof(Email), "Customer do not want email. Please remove email argument.")]
  public string DoNotWantEmail { get; set; }
}

Add way of specifying examples for commands

Top level

USAGE:
    myapp [OPTIONS] <COMMAND>

EXAMPLES:
    myapp --help
    myapp dog   

OPTIONS:
    -h, --help    Prints help information

COMMANDS:
    dog        The dog command
    cat        The cat command
    horse      The horse command
    giraffe    The giraffe command

Command

USAGE:
    myapp cat [LEGS] lion <TEETH> [OPTIONS]

EXAMPLES:
    myapp cat 3 lion 32 -c 3
    myapp cat lion 31 -c 1

ARGUMENTS:
    <TEETH>    The number of teeth the lion has

OPTIONS:
    -h, --help       Prints help information
    -c <CHILDREN>    The number of children the lion has

Wrong .NET 4.5.1 dependencies?

I'm not using .NET Core yet and have no deep knowledge of it but it seems to me that the dependencies for the .NET 4.5.1 nuget package are wrong? Shouldn't it be just Microsoft.Extensions.CommandLineUtils?

image

CommandAppBase ignores resolver on CommandAppSettings

In the constructor for CommandAppBase, the Resolver property is set using the value from CommandAppSettings parameter's Resolver property.

However, this means that updating the CommandAppBase.Settings.Resolver property (a perfectly valid syntactic operation) is ignored, since the value of the CommandAppBase.Resolver property is only set in the constructor (and has no accessible set).

Note that the same applies for the CommandAppBase.Settings.Streams property

Is this expected behaviour?

Add suggestions when executing a non-existent command

It would be convenient if the command line application could give suggestions to commands in case you spell it wrong.

Given the following configuration:

app.Configure(config =>
{
    config.AddCommand<GitSettings>("git", animal =>
    {
        animal.AddCommand<PushCommand>("push");
        animal.AddCommand<CloneCommand>("clone");
    });
});

Would give the following output:

> git pusg

Unknown command 'pusg'.
Did you mean 'push'?

Inherited settings aren't handled properly

Using a setup like this sample, I would expect that settings would be handled as follows:

  • Arguments and options on the proxy command setting are applied "to" the proxy command ✅
  • Arguments and options on the child command settings class are applied to the child command ✅
  • Arguments and options inherited "between" the proxy command class and the child command class should also be parsed and included in help ❓

In the above example, that would mean that the Name argument would be included in the help and parsing for both MyCommand/child and MyOtherCommand/other

Let me know if that's not clear.

Help Option does not work for top-level help

Running a Spectre-enabled app without any arguments shows the help text and available commands. Likewise, running an individual command with the help switches set in SetHelpOption shows the help for the command.

However, I would expect that using the same option (from SetHelpOption) with the top-level executable should also display available commands etc, same as running without any arguments does.

That is, I would say that running:

MyConsoleApp

and

MyConsoleApp --help

...should give the same output.

Sample repo included here

Support for repeating parameters

Hi Patrik,

I was wondering if it would be possible to repeat a param that one can enter.

e.g. myapp.exe myaction --myparam = string1 --myparam = string2

Thanks,

Maurice

Add support for validation of parameters

Would be nice if we could validate parameters.

public sealed class MyOption
{
  [CommandOption("-n|--name")]
  [Validator(typeof(NotEmptyValidator))]
  public string Name { get; set; }
}
public sealed class NotEmptyValidator : IValidator<string>
{
    public ValidationResult Validate(string name, string value)
    {
        if(string.IsNullOrWhiteSpace(value))
        {
            ValidationResult.Fail($"Parameter {name} can not be empty!");
        }
        return ValidationResult.Success();
    }
}

A runtime check to ensure that the validator type is the same as the provided parameter type must be done.

Allow relaxed option parsing

Introduce a "relaxed" mode where options that are unknown are ignored and added to the list of remaining arguments. The -- delimiter is not required in this mode for remaining arguments.

This is needed by Cake.

Remove develop branch

To make releasing new versions easier, let's remove the develop branch and only work on the master branch. We will then release to NuGet by tagging the master branch. We won't generate release notes anymore, but that's ok.

Add better template exception messages

There is currently a lot of different kinds of configuration exceptions, and while we cover a lot of cases, they could be friendlier to the poor developer trying to get things to work.

For example, the following setting:

public sealed class InvalidSettings : CommandSettings
{
    [CommandOption("-f|--g <BAR>")]
    public string Foo { get; set; }
}

Currently gives the following exception:

Long option names must consist of more than one character.

It would be much nicer if we could pinpoint the problem a little more.

An error occured when parsing template for Program.InvalidSettings.Foo.

-f|--g <BAR>
   ^^^ Long option names must consist of more than one character.

I could write more examples, but hopefully this captures the gist of what I want.
It would also be nice if we extracted all exception logic to it's own helper class.

Support default commands

We should support a default command which would be invoked if no command is provided by the user. This way the user can provide custom options on the application level.

using System.Threading.Tasks;
using Spectre.CommandLine;

namespace MyApp
{
    public static class Program
    {
        public static async Task<int> Main(string[] args)
        {
            var app = new CommandApp<RootCommand>();
            app.Configure(config =>
            {
                config.SetApplicationName("myapp");
                config.AddCommand<RunCommand>("run");
            });

            return await app.RunAsync(args);
        }
    }
}
> ./foo.exe --magic
RootCommand: Magic!

Support for optional option values

I currently have some options with optional values. For example, turning on a web server: --serve (with a default port) and turning on a server with optional port: --serve 1234.

This can currently be represented by using two options (a flag + a value) like --serve --port 1234. Doing so requires a little extra validation to make sure that they're provided as a pair (I.e., --port is never specified without --serve). Being able to combine them as a single option is a little cleaner.

One implementation idea is to use a new special value type named something like OptionalValue<T> to indicate the option has an optional value and to convey whether it was unspecified, specified without a value, or specified with a value (and what the value was).

Only support remaining arguments after `--`

Right now, we accept all arguments not specified in settings, and provide them in a ILookup<string, string> collection. We should only allow unspecified arguments after a trailing --.

Remaining arguments should be represented as ICollection<string> instead of ILookup<string, string> and making sense of remaining arguments is up to the command. This is because it might be desirable to pass the arguments to some other application.

Completely remove references to System.ValueTuple

There's so many problems related to consuming a netstandard2.0 library that uses the "new" value tuple from a net461 project, so let's remove it for now. If this problem is fixed in the future we might add it back again since it removes some boiler plate code.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.