-
Notifications
You must be signed in to change notification settings - Fork 292
Verb Commands
From Version 1.9.4.91 you get the opportunity to define a syntax similar to git or other popular command line tools.
$ git commit -a
$ git push -u origin commit
$ git tag -a tagname -m 'Tag Description'
commit, push, and tag are all verb commands. The options that follows are options ordinary, defined as specified in Mapping Properties To Options.
To begin we will define three ordinary options class:
class CommitSubOptions
{
[Option('a', "all", HelpText="Tell the command to automatically stage files.")]
public bool All { get; set; }
// Remainder omitted
}
class PushSubOptions
{
// Remainder omitted
}
class TagSubOptions
{
// Remainder omitted
}
If the remainder were not omitted, XXXSubOptions::GetUsage()
would not have been defined. Now we can define the master options class that will host all these sub options.
class Options
{
public OptionsWithVerbsHelp()
{
// Since we create this instance the parser will not overwrite it
CommitVerb = new CommitSubOptions {Patch = true};
}
[VerbOption("commit", HelpText = "Record changes to the repository.")]
public CommitSubOptions CommitVerb { get; set; }
[VerbOption("push", HelpText = "Update remote refs along with associated objects.")]
public PushOptions AddVerb { get; set; }
[VerbOption("tag", HelpText = "Update remote refs along with associated objects.")]
public TagSubOptions TagVerb { get; set; }
}
Subsequent call to ParseArguments()
occurs as usual:
var options = new Options();
if (CommandLineParser.Default.ParseArguments(args, options))
{
// if parsing succeeds the correct instance will be created
// (if needed) and feeded with parsed values
if (args[0] == "commit") {
Console.WriteLine("do something with {0}", options.CommitVerb);
} else if(args[0] == "push") {
Console.WriteLine("do something with {0}", options.PushVerb);
} else if(args[0] == "tag") {
Console.WriteLine("do something with {0}", options.TagVerb);
}
throw new InvalidOperation("if parsed succeed this code is unreachable!");
}
By design verbs can be specified only as first argument, they can't live side by side with ordinary options and they are implicitly mutually exclusive. If you have common options you can define it in a base class:
abstract class CommonSubOptions
{
[Option('q', "quiet",
HelpText = "Suppress summary message.")]
public bool Quiet { get; set; }
}
class CommitSubOptions : CommonSubOptions
{
// Remainder omitted
}
Since its inception this library was built around this founding philosophy: respect as much as possible developers programmer style. This the reason why CommandLineOptionsBase
was removed, we did not want our base types propagating through your class hierarchies.
For this reason if you want the parser create a sub option class for you, just define the class with a parameterless constructor. But if you want define different constructors, use object initializers, take advantage of IoC/DI frameworks, deserialize it from a persistence layer or simply create the instance by your own, just do it. The parser will not try overwrite an existing instance.
HelpText
was updated to render verbs help index (to be honest only HelpText::AutoBuilder
and related code was slightly modified, because it already allow you to print options without dashes). You do not need (and should not) define GetUsage
for sub options.
The parser will look in the master option class for method that accepts and returns a string marked with HelpVerbOptionAttribute
. Let's give a look at an example:
[HelpVerbOption]
public string GetUsage(string verb)
{
bool found;
var instance = (CommandLineOptionsBase) CommandLineParser.GetVerbOptionsInstanceByName(verb, this, out found);
var verbsIndex = verb == null || !found;
var target = verbsIndex ? this : instance;
return HelpText.AutoBuild(target, current => HelpText.DefaultParsingErrorsHandler(target, current), verbsIndex);
}
From developer perspective you only need to know that if verb == null
, you have to print the help index (an help screen that summarizes all verb commands).
But if verb == "a-verb-command"
, you should print the help screen of sub options that belong to requested verb.
Since HelpText::AutoBuild
can do all the magic for you, take advantage of CommandLineParser::GetVerbOptionsInstanceByName
static helper to identify the correct instance.