[Mono.Options] Add Mono.Options.Command, .CommandSet
authorJonathan Pryor <jonpryor@vt.edu>
Tue, 31 Jan 2017 20:27:32 +0000 (15:27 -0500)
committerMarek Safar <marek.safar@gmail.com>
Mon, 6 Mar 2017 22:37:55 +0000 (23:37 +0100)
Mono.Options.CommandSet allows easily having separate commands and
associated command options, allowing creation of a *suite* along the
lines of **git**(1), **svn**(1), etc.

CommandSet allows intermixing plain text strings for `--help` output,
Option values -- as supported by OptionSet -- and Command instances,
which have a name, optional help text, and an optional OptionSet.

var suite = new CommandSet ("suite-name") {
// Use strings and option values, as with OptionSet
"usage: suite-name COMMAND [OPTIONS]+",
{ "v:", "verbosity", (int? v) => Verbosity = v.HasValue ? v.Value : Verbosity+1 },
// Commands may also be specified
new Command ("command-name", "command help") {
Options = new OptionSet {/*...*/},
Run     = args => { /*...*/},
},
new MyCommandSubclass (),
};
suite.Run (new string[]{...});

CommandSet provides a `help` command, and forwards `help COMMAND`
to the registered Command instance by invoking Command.Invoke()
with `--help` as an option.

14 files changed:
mcs/class/Mono.Options/Documentation/en/Mono.Options/Command.xml [new file with mode: 0644]
mcs/class/Mono.Options/Documentation/en/Mono.Options/CommandSet.xml [new file with mode: 0644]
mcs/class/Mono.Options/Documentation/en/Mono.Options/HelpCommand.xml [new file with mode: 0644]
mcs/class/Mono.Options/Documentation/en/Mono.Options/OptionSet.xml
mcs/class/Mono.Options/Documentation/en/examples/commands.cs [new file with mode: 0644]
mcs/class/Mono.Options/Documentation/en/examples/commands.in [new file with mode: 0644]
mcs/class/Mono.Options/Documentation/en/examples/commands.txt [new file with mode: 0644]
mcs/class/Mono.Options/Documentation/en/index.xml
mcs/class/Mono.Options/Makefile
mcs/class/Mono.Options/Mono.Options/Options.cs
mcs/class/Mono.Options/Mono.Options_test.dll.sources
mcs/class/Mono.Options/Test/Mono.Options-Test-net_4_x.csproj [new file with mode: 0644]
mcs/class/Mono.Options/Test/Mono.Options/CommandSetTest.cs [new file with mode: 0644]
mcs/class/Mono.Options/Test/Mono.Options/CommandTest.cs [new file with mode: 0644]

diff --git a/mcs/class/Mono.Options/Documentation/en/Mono.Options/Command.xml b/mcs/class/Mono.Options/Documentation/en/Mono.Options/Command.xml
new file mode 100644 (file)
index 0000000..de2cda6
--- /dev/null
@@ -0,0 +1,286 @@
+<Type Name="Command" FullName="Mono.Options.Command">
+  <TypeSignature Language="C#" Value="public class Command" />
+  <TypeSignature Language="ILAsm" Value=".class public auto ansi beforefieldinit Command extends System.Object" />
+  <AssemblyInfo>
+    <AssemblyName>Mono.Options</AssemblyName>
+    <AssemblyVersion>0.2.3.0</AssemblyVersion>
+  </AssemblyInfo>
+  <ThreadingSafetyStatement>
+    Public <c>static</c> members of this type are thread safe.
+    Any instance members are not guaranteed to be thread safe.
+  </ThreadingSafetyStatement>
+  <Base>
+    <BaseTypeName>System.Object</BaseTypeName>
+  </Base>
+  <Interfaces />
+  <Docs>
+    <summary>
+      Represents a program command.
+    </summary>
+    <remarks>
+      <para>
+        Many command-line utilities are <i>suites</i> of commands, with a single
+        "outer" command and multiple commands. Examples of this style of
+        utility includes <b>git</b>, <b>svn</b>, and <b>mdoc</b>.
+      </para>
+      <para>
+        A <c>Command</c> represents a specific command in such a suite.
+        It has a <see cref="P:Mono.Options.Command.Name" /> which is the
+        command name for invocation purposes, optional help text through
+        the <see cref="P:Mono.Options.Command.Help" /> property, an optional
+        <see cref="T:Mono.Options.OptionSet" /> accessible through the
+        <see cref="P:Mono.Options.Command.Options" /> property for command-line
+        parsing, and two ways to have code executed when a command is
+        invoked: the <see cref="P:Mono.Options.Command.Run" /> property and
+        the <see cref="M:Mono.Options.Command.Invoke" /> method.
+      </para>
+    </remarks>
+  </Docs>
+  <Members>
+    <Member MemberName=".ctor">
+      <MemberSignature Language="C#" Value="public Command (string name, string help = null);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig specialname rtspecialname instance void .ctor(string name, string help) cil managed" />
+      <MemberType>Constructor</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <Parameters>
+        <Parameter Name="name" Type="System.String" />
+        <Parameter Name="help" Type="System.String" />
+      </Parameters>
+      <Docs>
+        <param name="name">
+          A <see cref="T:System.String" /> which is the command name.
+        </param>
+        <param name="help">
+          A <see cref="T:System.String" /> which is the command help text.
+        </param>
+        <summary>
+          Creates and initializes a new instance of the <c>Command</c> class.
+        </summary>
+        <remarks>
+          <para>
+          This constructor initializes the
+          <see cref="P:Mono.Options.Command.Name" /> property of the new
+          instance using <paramref name="name" /> and initializes the
+          <see cref="P:Mono.Options.Command.Help" /> property of the new
+          instance using <paramref name="help" />.
+        </para>
+        </remarks>
+        <exception cref="T:System.ArgumentNullException">
+          <paramref name="name" /> is <see langword="null" />.
+        </exception>
+      </Docs>
+    </Member>
+    <Member MemberName="CommandSet">
+      <MemberSignature Language="C#" Value="public Mono.Options.CommandSet CommandSet { get; }" />
+      <MemberSignature Language="ILAsm" Value=".property instance class Mono.Options.CommandSet CommandSet" />
+      <MemberType>Property</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Mono.Options.CommandSet</ReturnType>
+      </ReturnValue>
+      <Docs>
+        <summary>
+          A <see cref="T:Mono.Options.CommandSet" /> instance which owns the
+          <c>Command</c>.
+        </summary>
+        <value>
+          A <see cref="T:Mono.Options.CommandSet" /> instance which owns the
+          <c>Command</c>.
+        </value>
+        <remarks>
+          <para>
+            A <c>Command</c> instance may belong to only one
+            <see cref="T:Mono.Options.CommandSet" /> instance.
+            The <c>CommandSet</c> property is set upon calling
+            <see cref="M:Mono.Options.CommandSet.Add(Mono.Options.Command)" />.
+          </para>
+          <para>
+            If the <c>Command</c> instance has not yet been added to a
+            <c>CommandSet</c>, then this property is <see langword="null" />.
+          </para>
+          <para>
+            Use the <c>CommandSet</c> instance from either the
+            <see cref="P:Mono.Options.Command.Run" /> property or an overridden
+            <see cref="M:Mono.Options.Command.Invoke" /> method to access
+            localization facilities through
+            <see cref="P:Mono.Options.CommandSet.MessageLocalizer" />, the
+            preferred message output stream through
+            <see cref="P:Mono.Options.CommandSet.Out" />, and other features.
+          </para>
+        </remarks>
+      </Docs>
+    </Member>
+    <Member MemberName="Help">
+      <MemberSignature Language="C#" Value="public string Help { get; }" />
+      <MemberSignature Language="ILAsm" Value=".property instance string Help" />
+      <MemberType>Property</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>System.String</ReturnType>
+      </ReturnValue>
+      <Docs>
+        <summary>
+          A short, one-line, description of the <c>Command</c>.
+        </summary>
+        <value>
+          A <see cref="T:System.String" /> containing the optional help text
+          of the <c>Command</c>.
+        </value>
+        <remarks>
+          <para>
+            The <c>Help</c> property text is shown when the <c>help</c>
+            command is invoked.
+          </para>
+        </remarks>
+      </Docs>
+    </Member>
+    <Member MemberName="Invoke">
+      <MemberSignature Language="C#" Value="public virtual int Invoke (System.Collections.Generic.IEnumerable&lt;string&gt; arguments);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig newslot virtual instance int32 Invoke(class System.Collections.Generic.IEnumerable`1&lt;string&gt; arguments) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>System.Int32</ReturnType>
+      </ReturnValue>
+      <Parameters>
+        <Parameter Name="arguments" Type="System.Collections.Generic.IEnumerable&lt;System.String&gt;" />
+      </Parameters>
+      <Docs>
+        <param name="arguments">
+          A <see cref="T:System.Collections.Generic.IEnumerable{System.String}" />
+          which contains the unprocessed command-line arguments.
+        </param>
+        <summary>
+          Invoked by <see cref="M:Mono.Options.CommandSet.Run" /> when a command
+          has been executed.
+        </summary>
+        <returns>
+          A <see cref="T:System.Int32" /> which should be treated as the process
+          exit value.
+        </returns>
+        <remarks>
+          <para>
+            The value returned by <c>Invoke()</c> is the return value of
+            <see cref="M:Mono.Options.CommandSet.Run" />, and should be treated
+            as a possible process exit value.
+          </para>
+          <block subset="none" type="behaviors">
+            <para>
+              If the <c>Invoke()</c> method is not overridden by a subclass,
+              the <c>Invoke()</c> method will use
+              <see cref="P:Mono.Options.Command.Options" /> to parse
+              <paramref name="arguments" />, and pass any un-processed values
+              on to <see cref="P:Mono.Options.Command.Run" />.
+            </para>
+            <para>
+              If the <c>Options</c> property is <see langword="null" />, then no
+              option processing will occur, and <paramref name="arguments" />
+              will be provided to the <c>Run</c> property as-is.
+            </para>
+            <para>
+              If the <c>Run</c> property is <see langword="null" />, then
+              no further processing occurs.
+            </para>
+          </block>
+          <block subset="none" type="overrides">
+            <para>
+              Method overrides do not need to call the base class method.
+            </para>
+          </block>
+        </remarks>
+      </Docs>
+    </Member>
+    <Member MemberName="Name">
+      <MemberSignature Language="C#" Value="public string Name { get; }" />
+      <MemberSignature Language="ILAsm" Value=".property instance string Name" />
+      <MemberType>Property</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>System.String</ReturnType>
+      </ReturnValue>
+      <Docs>
+        <summary>
+          The name of the <c>Command</c>, which is used for command invocation.
+        </summary>
+        <value>
+          A <see cref="T:System.String" /> which is the name of the <c>Command</c>.
+        </value>
+        <remarks>
+          <para>
+            The <c>Name</c> value must be unique across all <c>Commmand</c> instances
+            referred to by a <see cref="T:Mono.Options.CommandSet" />.
+          </para>
+        </remarks>
+      </Docs>
+    </Member>
+    <Member MemberName="Options">
+      <MemberSignature Language="C#" Value="public Mono.Options.OptionSet Options { get; set; }" />
+      <MemberSignature Language="ILAsm" Value=".property instance class Mono.Options.OptionSet Options" />
+      <MemberType>Property</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Mono.Options.OptionSet</ReturnType>
+      </ReturnValue>
+      <Docs>
+        <summary>
+          Optional command-line option information.
+        </summary>
+        <value>
+          A <see cref="T:Mono.Options.OptionSet" /> instance which contains the
+          available command-line options for the <c>Command</c>.
+        </value>
+        <remarks>
+          <para>
+            If the <c>Options</c> property is not <see langword="null" /> when
+            the command is processed,
+            <see cref="M:Mono.Options.OptionSet.Parse" /> will be invoked on
+            the <c>Options</c> instance, and the return value of
+            <c>OptionSet.Parse()</c> will be forwarded to
+            <see cref="M:Mono.Options.Command.Invoke" />.
+          </para>
+        </remarks>
+      </Docs>
+    </Member>
+    <Member MemberName="Run">
+      <MemberSignature Language="C#" Value="public Action&lt;System.Collections.Generic.IEnumerable&lt;string&gt;&gt; Run { get; set; }" />
+      <MemberSignature Language="ILAsm" Value=".property instance class System.Action`1&lt;class System.Collections.Generic.IEnumerable`1&lt;string&gt;&gt; Run" />
+      <MemberType>Property</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>System.Action&lt;System.Collections.Generic.IEnumerable&lt;System.String&gt;&gt;</ReturnType>
+      </ReturnValue>
+      <Docs>
+        <summary>
+          Optional command handler.
+        </summary>
+        <value>
+          A <see cref="T:System.Action{System.Collections.Generic.IEnumerable{System.String}}" />
+          delegate which is executed by
+          <see cref="M:Mono.Options.Command.Invoke" />.
+        </value>
+        <remarks>
+          <para>
+            The <c>Run</c> property is executed by the the 
+            <see cref="M:Mono.Options.Command.Invoke" /> method when
+            <see cref="M:Mono.Options.CommandSet.Run" /> dispatches to a
+            <c>Command</c> instance.
+          </para>
+        </remarks>
+      </Docs>
+    </Member>
+  </Members>
+</Type>
diff --git a/mcs/class/Mono.Options/Documentation/en/Mono.Options/CommandSet.xml b/mcs/class/Mono.Options/Documentation/en/Mono.Options/CommandSet.xml
new file mode 100644 (file)
index 0000000..5d82495
--- /dev/null
@@ -0,0 +1,1349 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Type Name="CommandSet" FullName="Mono.Options.CommandSet">
+  <TypeSignature Language="C#" Value="public class CommandSet : System.Collections.ObjectModel.KeyedCollection&lt;string,Mono.Options.Command&gt;" />
+  <TypeSignature Language="ILAsm" Value=".class public auto ansi beforefieldinit CommandSet extends System.Collections.ObjectModel.KeyedCollection`2&lt;string, class Mono.Options.Command&gt;" />
+  <AssemblyInfo>
+    <AssemblyName>Mono.Options</AssemblyName>
+    <AssemblyVersion>0.2.3.0</AssemblyVersion>
+  </AssemblyInfo>
+  <ThreadingSafetyStatement>
+    Public <c>static</c> members of this type are thread safe.
+    Any instance members are not guaranteed to be thread safe.
+  </ThreadingSafetyStatement>
+  <Base>
+    <BaseTypeName>System.Collections.ObjectModel.KeyedCollection&lt;System.String,Mono.Options.Command&gt;</BaseTypeName>
+    <BaseTypeArguments>
+      <BaseTypeArgument TypeParamName="!0">System.String</BaseTypeArgument>
+      <BaseTypeArgument TypeParamName="!1">Mono.Options.Command</BaseTypeArgument>
+    </BaseTypeArguments>
+  </Base>
+  <Interfaces />
+  <Docs>
+    <summary>
+      A <i>suite</i> of commands, global program options, and associated documentation.
+    </summary>
+    <remarks>
+      <para>
+        A common requirement of some programs are discrete <i>commands</i>.
+        A <c>CommandSet</c> represents a <i>suite</i> of commands, intermixed
+        with suite documentation. Commands are managed by
+        <see cref="T:Mono.Options.Command" /> instances, which have a required
+        <i>name</i> and optional help text, and <c>CommandSet</c> will use the
+        intermixed documentation, options, and commands to produce <c>help</c>
+        command output.
+      </para>
+      <para>
+        To create a <c>CommandSet</c> instance, use the
+        <see cref="C:Mono.Options.CommandSet(System.String, System.Converter, System.IO.TextWriter, System.IO.TextWriter)" />
+        constructor. Only the suite name is required; all other parameters are
+        optional.
+      </para>
+      <para>
+        Once a <c>CommandSet</c> instance has been constructed, use the
+        <see cref="M:Mono.Options.CommandSet.Add" /> methods to add and
+        intermix suite documentation, global options, and commands.
+        Documentation is any string constant, global options are handled
+        by <see cref="T:Mono.Options.Option" /> instances and associated
+        <c>Add()</c> method overloads which implicitly create <c>Option</c>
+        instances, and commands are through <c>Command</c> instances.
+      </para>
+      <para>
+        Once the <c>CommandSet</c> instance has been initialized, call the
+        <see cref="M:Mono.Options.CommandSet.Run(System.String[])" />
+        method to process the arguments provided to <c>Main()</c>.
+        The appropriate <c>Command</c> instance will be determined, it's
+        options parsed, and <see cref="M:Mono.Options.Command.Invoke" />
+        will be executed. The return value of <c>Command.Invoke()</c>
+        is returned from <c>CommandSet.Run()</c>, and should be treated
+        as the process exit value.
+      </para>
+    </remarks>
+    <example>
+      <para>
+        The following <c>commands</c> example demonstrates some simple usage
+        of <see cref="T:Mono.Options.CommandSet" />.
+      </para>
+      <code lang="C#" src="examples/commands.cs">// Sub-commands with Mono.Options.CommandSet
+//
+// Compile as:
+//   mcs -r:Mono.Options.dll commands.cs
+
+using System;
+using System.Collections.Generic;
+
+using Mono.Options;
+
+class CommandDemo {
+       public static int Main (string[] args)
+       {
+               var commands = new CommandSet ("commands") {
+                       "usage: commands COMMAND [OPTIONS]",
+                       "",
+                       "Mono.Options.CommandSet sample app.",
+                       "",
+                       "Global options:",
+                       { "v:",
+                         "Output verbosity.",
+                         (int? n) =&gt; Verbosity = n.HasValue ? n.Value : Verbosity + 1 },
+                       "",
+                       "Available commands:",
+                       new Command ("echo", "Echo arguments to the screen") {
+                               Run = ca =&gt; Console.WriteLine ("{0}", string.Join (" ", ca)),
+                       },
+                       new RequiresArgs (),
+               };
+               return commands.Run (args);
+       }
+
+       public static int Verbosity;
+}
+
+class RequiresArgs : Command {
+
+       public RequiresArgs ()
+               : base ("requires-args", "Class-based Command subclass")
+       {
+               Options = new OptionSet () {
+                       "usage: commands requires-args [OPTIONS]",
+                       "",
+                       "Class-based Command subclass example.",
+                       { "name|n=",
+                         "{name} of person to greet.",
+                         v =&gt; Name = v },
+                       { "help|h|?",
+                         "Show this message and exit.",
+                         v =&gt; ShowHelp = v != null },
+               };
+       }
+
+       public        bool    ShowHelp    {get; private set;}
+       public  new   string  Name        {get; private set;}
+
+       public override int Invoke (IEnumerable&lt;string&gt; args)
+       {
+               try {
+                       var extra = Options.Parse (args);
+                       if (ShowHelp) {
+                               Options.WriteOptionDescriptions (CommandSet.Out);
+                               return 0;
+                       }
+                       if (string.IsNullOrEmpty (Name)) {
+                               Console.Error.WriteLine ("commands: Missing required argument `--name=NAME`.");
+                               Console.Error.WriteLine ("commands: Use `commands help requires-args` for details.");
+                               return 1;
+                       }
+                       Console.WriteLine ($"Hello, {Name}!");
+                       return 0;
+               }
+               catch (Exception e) {
+                       Console.Error.WriteLine ("commands: {0}", CommandDemo.Verbosity &gt;= 1 ? e.ToString () : e.Message);
+                       return 1;
+               }
+       }
+}
+</code>
+      <para>
+        The output, under the influence of different command-line arguments, is:
+      </para>
+      <code lang="sh" src="examples/commands.txt">$ mono commands.exe
+Use `commands help` for usage.
+
+$ mono commands.exe --help
+usage: commands COMMAND [OPTIONS]
+
+Mono.Options.CommandSet sample app.
+
+Global options:
+  -v[=VALUE]                 Output verbosity.
+
+Available commands:
+        echo                 Echo arguments to the screen
+        requires-args        Class-based Command subclass
+
+$ mono commands.exe help
+usage: commands COMMAND [OPTIONS]
+
+Mono.Options.CommandSet sample app.
+
+Global options:
+  -v[=VALUE]                 Output verbosity.
+
+Available commands:
+        echo                 Echo arguments to the screen
+        requires-args        Class-based Command subclass
+
+$ mono commands.exe help --help
+Usage: commands COMMAND [OPTIONS]
+Use `commands help COMMAND` for help on a specific command.
+
+Available commands:
+
+        echo                 Echo arguments to the screen
+        requires-args        Class-based Command subclass
+        help                 Show this message and exit
+
+$ mono commands.exe help echo
+--help
+
+$ mono commands.exe echo --help
+--help
+
+$ mono commands.exe echo hello, world
+hello, world
+
+$ mono commands.exe requires-args
+commands: Missing required argument `--name=NAME`.
+commands: Use `commands help requires-args` for details.
+
+$ mono commands.exe help requires-args
+usage: commands requires-args [OPTIONS]
+
+Class-based Command subclass example.
+      --name, -n=name        name of person to greet.
+      --help, -h, -?         Show this message and exit.
+
+$ mono commands.exe requires-args --help
+usage: commands requires-args [OPTIONS]
+
+Class-based Command subclass example.
+      --name, -n=name        name of person to greet.
+      --help, -h, -?         Show this message and exit.
+
+$ mono commands.exe requires-args -n World
+Hello, World!
+
+$ mono commands.exe invalid-command
+commands: Unknown command: invalid-command
+commands: Use `commands help` for usage.
+
+$ mono commands.exe help invalid-command
+commands: Unknown command: invalid-command
+commands: Use `commands help` for usage.
+</code>
+      <para>
+        The <c>commands.exe</c> output is short, informing the user that
+        commands are required for use.
+      </para>
+      <para>
+        The <c>commands.exe --help</c> is identical to the <c>commands help</c>
+        output, and shows the provided suite documentation.
+      </para>
+      <para>
+        <c>commands.exe COMMAND --help</c> and <c>commands.exe help COMMAND</c>
+        output is likewise identical, and will attempt to generate documentation
+        for the specified command, if available. This is performed by invoking
+        <see cref="M:Mono.Options.Command.Invoke(System.Collections.Generic.IEnumerable{System.String})" />
+        with the value <c>{ "--help" }</c>. This can be seen in the
+        <c>commands.exe help echo</c> and <c>commands.exe echo --help</c>
+        output, which simply prints <c>--help</c>. If a command wants
+        to partake in <c>help COMMAND</c> support, it needs to explicitly
+        handle the <c>--help</c> option in its associated
+        <see cref="T:Mono.Options.OptionSet" /> instance, referenced by the
+        <see cref="P:Mono.Options.Command.Options" /> property.
+      </para>
+      <para>
+        Finally, if an invalid command is specified, then an error is written
+        to <see cref="P:Mono.Options.CommandSet.Error" />, prefixed with the
+        <see cref="P:Mono.Options.CommandSet.Suite" /> value.
+      </para>
+    </example>
+  </Docs>
+  <Members>
+    <Member MemberName=".ctor">
+      <MemberSignature Language="C#" Value="public CommandSet (string suite, Converter&lt;string,string&gt; localizer = null, System.IO.TextWriter output = null, System.IO.TextWriter error = null);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig specialname rtspecialname instance void .ctor(string suite, class System.Converter`2&lt;string, string&gt; localizer, class System.IO.TextWriter output, class System.IO.TextWriter error) cil managed" />
+      <MemberType>Constructor</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <Parameters>
+        <Parameter Name="suite" Type="System.String" />
+        <Parameter Name="localizer" Type="System.Converter&lt;System.String,System.String&gt;" />
+        <Parameter Name="output" Type="System.IO.TextWriter" />
+        <Parameter Name="error" Type="System.IO.TextWriter" />
+      </Parameters>
+      <Docs>
+        <param name="suite">
+          A <see cref="T:System.String" /> containing the name of the suite.
+          This value is used in default <c>help</c> text output.
+        </param>
+        <param name="localizer">
+          A <see cref="T:System.Converter{System.String,System.String}" />
+          instance that will be used to translate strings.
+          If <see langword="null" />, then no localization is performed.
+        </param>
+        <param name="output">
+          A <see cref="T:System.IO.TextWriter" /> where output messages will be
+          written to. If <see langword="null" />, then the
+          <see cref="P:System.Console.Out" /> property will be used.
+        </param>
+        <param name="error">
+          A <see cref="T:System.IO.TextWriter" /> where error messages will be
+          written to. If <see langword="null" />, then the
+          <see cref="P:System.Console.Error" /> property will be used.
+        </param>
+        <summary>
+          Creates and initializes a new <c>CommandSet</c> instance.
+        </summary>
+        <remarks>
+          <para>
+            This constructor initializes
+            the <see cref="P:Mono.Options.CommandSet.Suite" /> property
+            of the new instance using <paramref name="suite" />,
+            the <see cref="P:Mono.Options.CommandSet.MessageLocalizer" /> property
+            of the new instance using <paramref name="localizer" />,
+            the <see cref="P:Mono.Options.CommandSet.Out" /> property
+            of the new instance using <paramref name="output" />, and
+            the <see cref="P:Mono.Options.CommandSet.Error" /> property
+            of the new instance using <paramref name="error" />.
+          </para>
+        </remarks>
+        <exception cref="T:System.ArgumentNullException">
+          <paramref name="suite" /> is <see langword="null" />.
+        </exception>
+      </Docs>
+    </Member>
+    <Member MemberName="Add">
+      <MemberSignature Language="C#" Value="public Mono.Options.CommandSet Add (Mono.Options.ArgumentSource source);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig instance class Mono.Options.CommandSet Add(class Mono.Options.ArgumentSource source) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Mono.Options.CommandSet</ReturnType>
+      </ReturnValue>
+      <Parameters>
+        <Parameter Name="source" Type="Mono.Options.ArgumentSource" />
+      </Parameters>
+      <Docs>
+        <param name="source">
+          A <see cref="T:Mono.Options.ArgumentSource" /> to register for
+          argument processing.
+        </param>
+        <summary>
+          Registers <paramref name="source" /> so that it may be consulted
+          during argument processing within
+          <see cref="M:Mono.Options.CommandSet.Run(System.Collections.Generic.IEnumerable{System.String})" />.
+        </summary>
+        <returns>
+          The current <see cref="T:Mono.Options.CommandSet" /> instance.
+          This is to permit method chaining.
+        </returns>
+        <remarks>
+        </remarks>
+        <exception cref="T:System.ArgumentNullException">
+          <paramref name="source" /> is <see langword="null" />.
+        </exception>
+      </Docs>
+    </Member>
+    <Member MemberName="Add">
+      <MemberSignature Language="C#" Value="public Mono.Options.CommandSet Add (Mono.Options.Command value);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig instance class Mono.Options.CommandSet Add(class Mono.Options.Command value) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Mono.Options.CommandSet</ReturnType>
+      </ReturnValue>
+      <Parameters>
+        <Parameter Name="value" Type="Mono.Options.Command" />
+      </Parameters>
+      <Docs>
+        <param name="value">
+          A <see cref="T:Mono.Options.Command" /> to add to the suite.
+        </param>
+        <summary>
+          Add a <c>Command</c> to the suite.
+        </summary>
+        <returns>
+          The current <see cref="T:Mono.Options.CommandSet" /> instance.
+          This is to permit method chaining.
+        </returns>
+        <remarks>
+        </remarks>
+        <exception cref="T:System.ArgumentException">
+          <para>
+            A <c>Command</c> with the same value for
+            <c><paramref name="value" />.Name</c>
+            has already been added to the <c>CommandSet</c>.
+          </para>
+          <para>-or-</para>
+          <para>
+            <paramref name="value" /> has been <c>Add()</c>ed to a different
+            <c>CommandSet</c> instance.
+          </para>
+        </exception>
+        <exception cref="T:System.ArgumentNullException">
+          <paramref name="value" /> is <see langword="null" />.
+        </exception>
+      </Docs>
+    </Member>
+    <Member MemberName="Add">
+      <MemberSignature Language="C#" Value="public Mono.Options.CommandSet Add (Mono.Options.Option option);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig instance class Mono.Options.CommandSet Add(class Mono.Options.Option option) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Mono.Options.CommandSet</ReturnType>
+      </ReturnValue>
+      <Parameters>
+        <Parameter Name="option" Type="Mono.Options.Option" />
+      </Parameters>
+      <Docs>
+        <param name="option">
+          The <see cref="T:Mono.Options.Option" /> to register.
+        </param>
+        <summary>
+          Adds <paramref name="option" /> as a global suite option.
+        </summary>
+        <returns>
+          The current <see cref="T:Mono.Options.CommandSet" /> instance.
+          This is to permit method chaining.
+        </returns>
+        <remarks>
+          <para>
+            Registers each option name returned by
+            <see cref="M:Mono.Options.Option.GetNames" />, ensuring that any
+            option with a matching name will be handled by the
+            <paramref name="option" /> instance.
+          </para>
+        </remarks>
+        <exception cref="T:System.ArgumentException">
+          <paramref name="option" /> has an alias (as returned from
+          <see cref="M:Mono.Options.Option.GetNames" />) that conflicts with
+          a previously registered <see cref="T:Mono.Options.Option" />.
+        </exception>
+        <exception cref="T:System.ArgumentNullException">
+          <paramref name="option" /> is <see langword="null" />.
+        </exception>
+      </Docs>
+    </Member>
+    <Member MemberName="Add">
+      <MemberSignature Language="C#" Value="public Mono.Options.CommandSet Add (string header);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig instance class Mono.Options.CommandSet Add(string header) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Mono.Options.CommandSet</ReturnType>
+      </ReturnValue>
+      <Parameters>
+        <Parameter Name="header" Type="System.String" />
+      </Parameters>
+      <Docs>
+        <param name="header">
+          A <see cref="T:System.String" /> containing the header to display
+          during <see cref="M:Mono.Options.CommandSet.Run" /><c>help</c> processing.
+        </param>
+        <summary>
+          Declare a header to be printed during for <c>help</c> output.
+        </summary>
+        <returns>
+          The current <see cref="T:Mono.Options.CommandSet" /> instance.
+          This is to permit method chaining.
+        </returns>
+        <remarks>
+        </remarks>
+      </Docs>
+    </Member>
+    <Member MemberName="Add">
+      <MemberSignature Language="C#" Value="public Mono.Options.CommandSet Add (string prototype, Mono.Options.OptionAction&lt;string,string&gt; action);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig instance class Mono.Options.CommandSet Add(string prototype, class Mono.Options.OptionAction`2&lt;string, string&gt; action) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Mono.Options.CommandSet</ReturnType>
+      </ReturnValue>
+      <Parameters>
+        <Parameter Name="prototype" Type="System.String" />
+        <Parameter Name="action" Type="Mono.Options.OptionAction&lt;System.String,System.String&gt;" />
+      </Parameters>
+      <Docs>
+        <param name="prototype">
+          A <see cref="T:System.String" /> containing all option aliases to
+          register, an (optional) type specifier, and an (optional) value
+          separator list; see 
+          <see cref="C:Mono.Options.Option(System.String,System.String,System.Int32)" />
+          for details.
+        </param>
+        <param name="action">
+          A <see cref="T:Mono.Options.OptionAction{System.String,System.String}" />
+          to invoke when an option is parsed.
+        </param>
+        <summary>
+          Registers each alias within <paramref name="prototype" /> so that any 
+          options matching the aliases in <paramref name="prototype" /> will be
+          handled by <paramref name="action" /> during any subsequent
+          <see cref="M:Mono.Options.OptionSet.Parse(System.Collections.Generic.IEnumerable{System.String})" />
+          calls.
+        </summary>
+        <returns>
+          The current <see cref="T:Mono.Options.CommandSet" /> instance.
+          This is to permit method chaining.
+        </returns>
+        <remarks>
+          Calls 
+          <see cref="M:Mono.Options.CommandSet.Add(System.String,System.String,Mono.Options.OptionAction{System.String,System.String})" />
+          with a <paramref name="description" /> value of 
+          <see langword="null" />.
+        </remarks>
+        <altmember cref="M:Mono.Options.CommandSet.Add(System.String,System.String,Mono.Options.OptionAction{System.String,System.String})" />
+        <altmember cref="M:Mono.Options.CommandSet.Add(Mono.Options.Option)" />
+        <exception cref="T:System.ArgumentException">
+          <paramref name="prototype" /> has an alias (as returned from
+          <see cref="M:Mono.Options.Option.GetNames" />) that conflicts with
+          a previously registered <see cref="T:Mono.Options.Option" />.
+        </exception>
+        <exception cref="T:System.ArgumentNullException">
+          <para>
+            <paramref name="prototype" /> is <see langword="null" /></para>
+          <para>-or-</para>
+          <para>
+            <paramref name="action" /> is <see langword="null" /></para>
+        </exception>
+      </Docs>
+    </Member>
+    <Member MemberName="Add">
+      <MemberSignature Language="C#" Value="public Mono.Options.CommandSet Add (string prototype, Action&lt;string&gt; action);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig instance class Mono.Options.CommandSet Add(string prototype, class System.Action`1&lt;string&gt; action) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Mono.Options.CommandSet</ReturnType>
+      </ReturnValue>
+      <Parameters>
+        <Parameter Name="prototype" Type="System.String" />
+        <Parameter Name="action" Type="System.Action&lt;System.String&gt;" />
+      </Parameters>
+      <Docs>
+        <param name="prototype">
+          A <see cref="T:System.String" /> containing all option aliases to
+          register, an (optional) type specifier, and an (optional) value
+          separator list; see 
+          <see cref="C:Mono.Options.Option(System.String,System.String,System.Int32)" />
+          for details.
+        </param>
+        <param name="action">
+          A <see cref="T:System.Action{System.String}" />
+          to invoke when an option is parsed.
+        </param>
+        <summary>
+          Registers each alias within <paramref name="prototype" /> so that any 
+          options matching the aliases in <paramref name="prototype" /> will be
+          handled by <paramref name="action" /> during any subsequent
+          <see cref="M:Mono.Options.CommandSet.Run(System.Collections.Generic.IEnumerable{System.String})" />
+          calls.
+        </summary>
+        <returns>
+          The current <see cref="T:Mono.Options.CommandSet" /> instance.
+          This is to permit method chaining.
+        </returns>
+        <remarks>
+          Calls 
+          <see cref="M:Mono.Options.CommandSet.Add(System.String,System.String,System.Action{System.String})" />
+          with a <paramref name="description" /> value of 
+          <see langword="null" />.
+        </remarks>
+        <altmember cref="M:Mono.Options.CommandSet.Add(System.String,System.String,System.Action{System.String})" />
+        <altmember cref="M:Mono.Options.CommandSet.Add(Mono.Options.Option)" />
+        <exception cref="T:System.ArgumentException">
+          <paramref name="prototype" /> has an alias (as returned from
+          <see cref="M:Mono.Options.Option.GetNames" />) that conflicts with
+          a previously registered <see cref="T:Mono.Options.Option" />.
+        </exception>
+        <exception cref="T:System.ArgumentNullException">
+          <para>
+            <paramref name="prototype" /> is <see langword="null" /></para>
+          <para>-or-</para>
+          <para>
+            <paramref name="action" /> is <see langword="null" /></para>
+        </exception>
+      </Docs>
+    </Member>
+    <Member MemberName="Add">
+      <MemberSignature Language="C#" Value="public Mono.Options.CommandSet Add (string prototype, string description, Mono.Options.OptionAction&lt;string,string&gt; action);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig instance class Mono.Options.CommandSet Add(string prototype, string description, class Mono.Options.OptionAction`2&lt;string, string&gt; action) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Mono.Options.CommandSet</ReturnType>
+      </ReturnValue>
+      <Parameters>
+        <Parameter Name="prototype" Type="System.String" />
+        <Parameter Name="description" Type="System.String" />
+        <Parameter Name="action" Type="Mono.Options.OptionAction&lt;System.String,System.String&gt;" />
+      </Parameters>
+      <Docs>
+        <param name="prototype">
+          A <see cref="T:System.String" /> containing all option aliases to
+          register, an (optional) type specifier, and an (optional) value
+          separator list; see 
+          <see cref="C:Mono.Options.Option(System.String,System.String,System.Int32)" />
+          for details.
+        </param>
+        <param name="description">
+          A <see cref="T:System.String" /> to be used to initialize
+          the <see cref="P:Mono.Options.Option.Description" /> property.
+        </param>
+        <param name="action">
+          A <see cref="T:Mono.Options.OptionAction{System.String,System.String}" />
+          to invoke when an option is parsed.
+        </param>
+        <summary>
+          Registers each alias within <paramref name="prototype" /> so that any 
+          options matching the aliases in <paramref name="prototype" /> will be
+          handled by <paramref name="action" /> during any subsequent
+          <see cref="M:Mono.Options.CommandSet.Run(System.Collections.Generic.IEnumerable{System.String})" />
+          calls.
+        </summary>
+        <returns>
+          The current <see cref="T:Mono.Options.CommandSet" /> instance.
+          This is to permit method chaining.
+        </returns>
+        <remarks>
+          <para>
+            Use this method when <paramref name="prototype" /> should accept
+            two values, generally a key and a value.
+          </para>
+          <block subset="none" type="note">
+            If <paramref name="prototype" /> specifies a 
+            <see cref="F:Mono.Options.OptionValueType.Optional" /> option,
+            then it's possible that both the key and the value will be
+            <see langword="null" /> in the callback function.
+          </block>
+        </remarks>
+        <altmember cref="M:Mono.Options.CommandSet.Add(Mono.Options.Option)" />
+        <exception cref="T:System.ArgumentException">
+          <paramref name="prototype" /> has an alias (as returned from
+          <see cref="M:Mono.Options.Option.GetNames" />) that conflicts with
+          a previously registered <see cref="T:Mono.Options.Option" />.
+        </exception>
+        <exception cref="T:System.ArgumentNullException">
+          <para>
+            <paramref name="prototype" /> is <see langword="null" /></para>
+          <para>-or-</para>
+          <para>
+            <paramref name="action" /> is <see langword="null" /></para>
+        </exception>
+      </Docs>
+    </Member>
+    <Member MemberName="Add">
+      <MemberSignature Language="C#" Value="public Mono.Options.CommandSet Add (string prototype, string description, Action&lt;string&gt; action);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig instance class Mono.Options.CommandSet Add(string prototype, string description, class System.Action`1&lt;string&gt; action) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Mono.Options.CommandSet</ReturnType>
+      </ReturnValue>
+      <Parameters>
+        <Parameter Name="prototype" Type="System.String" />
+        <Parameter Name="description" Type="System.String" />
+        <Parameter Name="action" Type="System.Action&lt;System.String&gt;" />
+      </Parameters>
+      <Docs>
+        <param name="prototype">
+          A <see cref="T:System.String" /> containing all option aliases to
+          register, an (optional) type specifier, and an (optional) value
+          separator list; see 
+          <see cref="C:Mono.Options.Option(System.String,System.String,System.Int32)" />
+          for details.
+        </param>
+        <param name="description">
+          A <see cref="T:System.String" /> containing to used to initialize
+          the <see cref="P:Mono.Options.Option.Description" /> property.
+        </param>
+        <param name="action">
+          A <see cref="T:System.Action{System.String}" />
+          to invoke when an option is parsed.
+        </param>
+        <summary>
+          Registers each alias within <paramref name="prototype" /> so that any 
+          options matching the aliases in <paramref name="prototype" /> will be
+          handled by <paramref name="action" /> during any subsequent
+          <see cref="M:Mono.Options.CommandSet.Run(System.Collections.Generic.IEnumerable{System.String})" />
+          calls.
+        </summary>
+        <returns>
+          The current <see cref="T:Mono.Options.CommandSet" /> instance.
+          This is to permit method chaining.
+        </returns>
+        <remarks>
+        </remarks>
+        <altmember cref="M:Mono.Options.CommandSet.Add(Mono.Options.Option)" />
+        <exception cref="T:System.ArgumentException">
+          <paramref name="option" /> has an alias (as returned from
+          <see cref="M:Mono.Options.Option.GetNames" />) that conflicts with
+          a previously registered <see cref="T:Mono.Options.Option" />.
+        </exception>
+        <exception cref="T:System.ArgumentNullException">
+          <para>
+            <paramref name="prototype" /> is <see langword="null" /></para>
+          <para>-or-</para>
+          <para>
+            <paramref name="action" /> is <see langword="null" /></para>
+        </exception>
+      </Docs>
+    </Member>
+    <Member MemberName="Add">
+      <MemberSignature Language="C#" Value="public Mono.Options.CommandSet Add (string prototype, string description, Mono.Options.OptionAction&lt;string,string&gt; action, bool hidden);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig instance class Mono.Options.CommandSet Add(string prototype, string description, class Mono.Options.OptionAction`2&lt;string, string&gt; action, bool hidden) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Mono.Options.CommandSet</ReturnType>
+      </ReturnValue>
+      <Parameters>
+        <Parameter Name="prototype" Type="System.String" />
+        <Parameter Name="description" Type="System.String" />
+        <Parameter Name="action" Type="Mono.Options.OptionAction&lt;System.String,System.String&gt;" />
+        <Parameter Name="hidden" Type="System.Boolean" />
+      </Parameters>
+      <Docs>
+        <param name="prototype">
+          A <see cref="T:System.String" /> containing all option aliases to
+          register, an (optional) type specifier, and an (optional) value
+          separator list; see
+          <see cref="C:Mono.Options.Option(System.String,System.String,System.Int32)" />
+          for details.
+        </param>
+        <param name="description">
+          A <see cref="T:System.String" /> containing to used to initialize
+          the <see cref="P:Mono.Options.Option.Description" /> property.
+        </param>
+        <param name="action">
+          A <see cref="T:Mono.Options.OptionAction{System.String,System.String}" />
+          to invoke when an option is parsed.
+        </param>
+        <param name="hidden">
+          A <see cref="T:System.Boolean" /> specifying whether or not the
+          Option should be displayed in
+          <see cref="M:Mono.Options.CommandSet.Run" /><c>help</c> output.
+        </param>
+        <summary>
+          Registers each alias within <paramref name="prototype" /> so that any
+          options matching the aliases in <paramref name="prototype" /> will be
+          handled by <paramref name="action" /> during any subsequent
+          <see cref="M:Mono.Options.CommandSet.Run(System.Collections.Generic.IEnumerable{System.String})" />
+          calls.
+        </summary>
+        <returns>
+          The current <see cref="T:Mono.Options.CommandSet" /> instance.
+          This is to permit method chaining.
+        </returns>
+        <remarks>
+        </remarks>
+        <altmember cref="M:Mono.Options.CommandSet.Add(Mono.Options.Option)" />
+        <exception cref="T:System.ArgumentException">
+          <paramref name="option" /> has an alias (as returned from
+          <see cref="M:Mono.Options.Option.GetNames" />) that conflicts with
+          a previously registered <see cref="T:Mono.Options.Option" />.
+        </exception>
+        <exception cref="T:System.ArgumentNullException">
+          <para>
+            <paramref name="prototype" /> is <see langword="null" /></para>
+          <para>-or-</para>
+          <para>
+            <paramref name="action" /> is <see langword="null" /></para>
+        </exception>
+      </Docs>
+    </Member>
+    <Member MemberName="Add">
+      <MemberSignature Language="C#" Value="public Mono.Options.CommandSet Add (string prototype, string description, Action&lt;string&gt; action, bool hidden);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig instance class Mono.Options.CommandSet Add(string prototype, string description, class System.Action`1&lt;string&gt; action, bool hidden) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Mono.Options.CommandSet</ReturnType>
+      </ReturnValue>
+      <Parameters>
+        <Parameter Name="prototype" Type="System.String" />
+        <Parameter Name="description" Type="System.String" />
+        <Parameter Name="action" Type="System.Action&lt;System.String&gt;" />
+        <Parameter Name="hidden" Type="System.Boolean" />
+      </Parameters>
+      <Docs>
+        <param name="prototype">
+          A <see cref="T:System.String" /> containing all option aliases to
+          register, an (optional) type specifier, and an (optional) value
+          separator list; see
+          <see cref="C:Mono.Options.Option(System.String,System.String,System.Int32)" />
+          for details.
+        </param>
+        <param name="description">
+          A <see cref="T:System.String" /> containing to used to initialize
+          the <see cref="P:Mono.Options.Option.Description" /> property.
+        </param>
+        <param name="action">
+          A <see cref="T:System.Action{System.String}" />
+          to invoke when an option is parsed.
+        </param>
+        <param name="hidden">
+          A <see cref="T:System.Boolean" /> specifying whether or not the
+          Option should be displayed in
+          <see cref="M:Mono.Options.CommandSet.Run" /><c>help</c> output.
+        </param>
+        <summary>
+          Registers each alias within <paramref name="prototype" /> so that any
+          options matching the aliases in <paramref name="prototype" /> will be
+          handled by <paramref name="action" /> during any subsequent
+          <see cref="M:Mono.Options.CommandSet.Run(System.Collections.Generic.IEnumerable{System.String})" />
+          calls.
+        </summary>
+        <returns>
+          The current <see cref="T:Mono.Options.CommandSet" /> instance.
+          This is to permit method chaining.
+        </returns>
+        <remarks>
+        </remarks>
+        <altmember cref="M:Mono.Options.OptionSet.Add(Mono.Options.Option)" />
+        <exception cref="T:System.ArgumentException">
+          <paramref name="option" /> has an alias (as returned from
+          <see cref="M:Mono.Options.Option.GetNames" />) that conflicts with
+          a previously registered <see cref="T:Mono.Options.Option" />.
+        </exception>
+        <exception cref="T:System.ArgumentNullException">
+          <para>
+            <paramref name="prototype" /> is <see langword="null" /></para>
+          <para>-or-</para>
+          <para>
+            <paramref name="action" /> is <see langword="null" /></para>
+        </exception>
+      </Docs>
+    </Member>
+    <Member MemberName="Add&lt;T&gt;">
+      <MemberSignature Language="C#" Value="public Mono.Options.CommandSet Add&lt;T&gt; (string prototype, Action&lt;T&gt; action);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig instance class Mono.Options.CommandSet Add&lt;T&gt;(string prototype, class System.Action`1&lt;!!T&gt; action) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Mono.Options.CommandSet</ReturnType>
+      </ReturnValue>
+      <TypeParameters>
+        <TypeParameter Name="T" />
+      </TypeParameters>
+      <Parameters>
+        <Parameter Name="prototype" Type="System.String" />
+        <Parameter Name="action" Type="System.Action&lt;T&gt;" />
+      </Parameters>
+      <Docs>
+        <typeparam name="T">
+          The type of the option to parse and provide to the 
+          <paramref name="action" /> callback.
+        </typeparam>
+        <param name="prototype">
+          A <see cref="T:System.String" /> containing all option aliases to
+          register, an (optional) type specifier, and an (optional) value
+          separator list; see 
+          <see cref="C:Mono.Options.Option(System.String,System.String,System.Int32)" />
+          for details.
+        </param>
+        <param name="action">
+          A <see cref="T:System.Action{``0}" />
+          to invoke when an option is parsed.
+        </param>
+        <summary>
+          Registers each alias within <paramref name="prototype" /> so that any 
+          options matching the aliases in <paramref name="prototype" /> will be
+          handled by <paramref name="action" /> during any subsequent
+          <see cref="M:Mono.Options.CommandSet.Run(System.Collections.Generic.IEnumerable{System.String})" />
+          calls.
+        </summary>
+        <returns>
+          The current <see cref="T:Mono.Options.CommandSet" /> instance.
+          This is to permit method chaining.
+        </returns>
+        <remarks>
+          Calls 
+          <see cref="M:Mono.Options.OptionSet.Add``1(System.String,System.String,System.Action{``0})" />
+          with a <paramref name="description" /> value of 
+          <see langword="null" />.
+        </remarks>
+        <altmember cref="M:Mono.Options.CommandSet.Add(Mono.Options.Option)" />
+        <altmember cref="M:Mono.Options.CommandSet.Add``1(System.String,System.String,System.Action{``0})" />
+        <exception cref="T:System.ArgumentException">
+          <paramref name="option" /> has an alias (as returned from
+          <see cref="M:Mono.Options.Option.GetNames" />) that conflicts with
+          a previously registered <see cref="T:Mono.Options.Option" />.
+        </exception>
+      </Docs>
+    </Member>
+    <Member MemberName="Add&lt;T&gt;">
+      <MemberSignature Language="C#" Value="public Mono.Options.CommandSet Add&lt;T&gt; (string prototype, string description, Action&lt;T&gt; action);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig instance class Mono.Options.CommandSet Add&lt;T&gt;(string prototype, string description, class System.Action`1&lt;!!T&gt; action) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Mono.Options.CommandSet</ReturnType>
+      </ReturnValue>
+      <TypeParameters>
+        <TypeParameter Name="T" />
+      </TypeParameters>
+      <Parameters>
+        <Parameter Name="prototype" Type="System.String" />
+        <Parameter Name="description" Type="System.String" />
+        <Parameter Name="action" Type="System.Action&lt;T&gt;" />
+      </Parameters>
+      <Docs>
+        <typeparam name="T">
+          The type of the option to parse and provide to the 
+          <paramref name="action" /> callback.
+        </typeparam>
+        <param name="prototype">
+          A <see cref="T:System.String" /> containing all option aliases to
+          register, an (optional) type specifier, and an (optional) value
+          separator list; see 
+          <see cref="C:Mono.Options.Option(System.String,System.String,System.Int32)" />
+          for details.
+        </param>
+        <param name="description">
+          A <see cref="T:System.String" /> containing to used to initialize
+          the <see cref="P:Mono.Options.Option.Description" /> property.
+        </param>
+        <param name="action">
+          A <see cref="T:System.Action{``0}" />
+          to invoke when an option is parsed.
+        </param>
+        <summary>
+          Registers each alias within <paramref name="prototype" /> so that any 
+          options matching the aliases in <paramref name="prototype" /> will be
+          handled by <paramref name="action" /> during any subsequent
+          <see cref="M:Mono.Options.CommandSet.Run(System.Collections.Generic.IEnumerable{System.String})" />
+          calls.
+        </summary>
+        <returns>
+          The current <see cref="T:Mono.Options.CommandSet" /> instance.
+          This is to permit method chaining.
+        </returns>
+        <remarks>
+          <para>
+            Use this typed overload when you want strongly typed option values
+            that correspond to a managed type.
+            <see cref="M:System.ComponentModel.TypeDescriptor.GetConverter(System.Type)" />
+            is used to lookup the
+            <see cref="T:System.ComponentModel.TypeConverter" /> to use when
+            performing the string-to-type conversion.
+          </para>
+          <para>
+            Special support is provided for <see cref="T:System.Nullable{X}" />
+            types; <see cref="T:System.ComponentModel.TypeConverter" />
+            doesn't currently support their use, but if 
+            <typeparamref name="T" /> is a nullable type, then this method
+            will instead use the 
+            <see cref="T:System.ComponentModel.TypeConverter" /> for the 
+            <typeparamref name="X" /> type.  This allows straightforward use
+            of nullable types, identical to using any other strongly typed
+            value.
+          </para>
+          <block subset="none" type="note">
+            <para>
+              If <paramref name="prototype" /> specifies an
+              <see cref="F:Mono.Options.OptionValueType.Optional" /> value
+              and the value is not provided, then <c>default(T)</c> is
+              provided as the value to <paramref name="action" />.
+            </para>
+          </block>
+        </remarks>
+        <altmember cref="M:Mono.Options.OptionSet.Add(Mono.Options.Option)" />
+        <exception cref="T:System.ArgumentException">
+          <paramref name="option" /> has an alias (as returned from
+          <see cref="M:Mono.Options.Option.GetNames" />) that conflicts with
+          a previously registered <see cref="T:Mono.Options.Option" />.
+        </exception>
+        <exception cref="T:System.ArgumentNullException">
+          <para>
+            <paramref name="prototype" /> is <see langword="null" /></para>
+          <para>-or-</para>
+          <para>
+            <paramref name="action" /> is <see langword="null" /></para>
+        </exception>
+      </Docs>
+    </Member>
+    <Member MemberName="Add&lt;TKey,TValue&gt;">
+      <MemberSignature Language="C#" Value="public Mono.Options.CommandSet Add&lt;TKey,TValue&gt; (string prototype, Mono.Options.OptionAction&lt;TKey,TValue&gt; action);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig instance class Mono.Options.CommandSet Add&lt;TKey, TValue&gt;(string prototype, class Mono.Options.OptionAction`2&lt;!!TKey, !!TValue&gt; action) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Mono.Options.CommandSet</ReturnType>
+      </ReturnValue>
+      <TypeParameters>
+        <TypeParameter Name="TKey" />
+        <TypeParameter Name="TValue" />
+      </TypeParameters>
+      <Parameters>
+        <Parameter Name="prototype" Type="System.String" />
+        <Parameter Name="action" Type="Mono.Options.OptionAction&lt;TKey,TValue&gt;" />
+      </Parameters>
+      <Docs>
+        <typeparam name="TKey">
+          The type of the first argument to parse and provide to the 
+          <paramref name="action" /> callback.
+        </typeparam>
+        <typeparam name="TValue">
+          The type of the second argument to parse and provide to the 
+          <paramref name="action" /> callback.
+        </typeparam>
+        <param name="prototype">
+          A <see cref="T:System.String" /> containing all option aliases to
+          register, an (optional) type specifier, and an (optional) value
+          separator list; see 
+          <see cref="C:Mono.Options.Option(System.String,System.String,System.Int32)" />
+          for details.
+        </param>
+        <param name="action">
+          A <see cref="T:Mono.Options.OptionAction{TKey,TValue}" />
+          to invoke when an option is parsed.
+        </param>
+        <summary>
+          Registers each alias within <paramref name="prototype" /> so that any 
+          options matching the aliases in <paramref name="prototype" /> will be
+          handled by <paramref name="action" /> during any subsequent
+          <see cref="M:Mono.Options.CommandSet.Run(System.Collections.Generic.IEnumerable{System.String})" />
+          calls.
+        </summary>
+        <returns>
+          The current <see cref="T:Mono.Options.CommandSet" /> instance.
+          This is to permit method chaining.
+        </returns>
+        <remarks>
+          Calls 
+          <see cref="M:Mono.Options.OptionSet.Add``2(System.String,System.String,Mono.Options.OptionAction{``0,``1})" />
+          with a <paramref name="description" /> value of 
+          <see langword="null" />.
+        </remarks>
+        <altmember cref="M:Mono.Options.CommandSet.Add(Mono.Options.Option)" />
+        <altmember cref="M:Mono.Options.CommandSet.Add``2(System.String,System.String,Mono.Options.OptionAction{``0,``1})" />
+        <exception cref="T:System.ArgumentException">
+          <paramref name="prototype" /> has an alias (as returned from
+          <see cref="M:Mono.Options.Option.GetNames" />) that conflicts with
+          a previously registered <see cref="T:Mono.Options.Option" />.
+        </exception>
+        <exception cref="T:System.ArgumentNullException">
+          <para>
+            <paramref name="prototype" /> is <see langword="null" /></para>
+          <para>-or-</para>
+          <para>
+            <paramref name="action" /> is <see langword="null" /></para>
+        </exception>
+      </Docs>
+    </Member>
+    <Member MemberName="Add&lt;TKey,TValue&gt;">
+      <MemberSignature Language="C#" Value="public Mono.Options.CommandSet Add&lt;TKey,TValue&gt; (string prototype, string description, Mono.Options.OptionAction&lt;TKey,TValue&gt; action);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig instance class Mono.Options.CommandSet Add&lt;TKey, TValue&gt;(string prototype, string description, class Mono.Options.OptionAction`2&lt;!!TKey, !!TValue&gt; action) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Mono.Options.CommandSet</ReturnType>
+      </ReturnValue>
+      <TypeParameters>
+        <TypeParameter Name="TKey" />
+        <TypeParameter Name="TValue" />
+      </TypeParameters>
+      <Parameters>
+        <Parameter Name="prototype" Type="System.String" />
+        <Parameter Name="description" Type="System.String" />
+        <Parameter Name="action" Type="Mono.Options.OptionAction&lt;TKey,TValue&gt;" />
+      </Parameters>
+      <Docs>
+        <typeparam name="TKey">
+          The type of the first argument to parse and provide to the 
+          <paramref name="action" /> callback.
+        </typeparam>
+        <typeparam name="TValue">
+          The type of the second argument to parse and provide to the 
+          <paramref name="action" /> callback.
+        </typeparam>
+        <param name="prototype">
+          A <see cref="T:System.String" /> containing all option aliases to
+          register, an (optional) type specifier, and an (optional) value
+          separator list; see 
+          <see cref="C:Mono.Options.Option(System.String,System.String,System.Int32)" />
+          for details.
+        </param>
+        <param name="description">
+          A <see cref="T:System.String" /> to be used to initialize
+          the <see cref="P:Mono.Options.Option.Description" /> property.
+        </param>
+        <param name="action">
+          A <see cref="T:Mono.Options.OptionAction{TKey,TValue}" />
+          to invoke when an option is parsed.
+        </param>
+        <summary>
+          Registers each alias within <paramref name="prototype" /> so that any 
+          options matching the aliases in <paramref name="prototype" /> will be
+          handled by <paramref name="action" /> during any subsequent
+          <see cref="M:Mono.Options.CommandSet.Run(System.Collections.Generic.IEnumerable{System.String})" />
+          calls.
+        </summary>
+        <returns>
+          The current <see cref="T:Mono.Options.CommandSet" /> instance.
+          This is to permit method chaining.
+        </returns>
+        <remarks>
+          <para>
+            Use this method when <paramref name="prototype" /> should accept
+            two typed values, generally a key and a value.
+          </para>
+          <block subset="none" type="note">
+            <para>
+              If <paramref name="prototype" /> specifies an
+              <see cref="F:Mono.Options.OptionValueType.Optional" /> value
+              and the value is not provided, then <c>default(TKey)</c> and
+              <c>default(TValue)</c> may be provided as the values to
+              <paramref name="action" />.
+            </para>
+          </block>
+        </remarks>
+        <altmember cref="M:Mono.Options.CommandSet.Add(Mono.Options.Option)" />
+        <exception cref="T:System.ArgumentException">
+          <paramref name="prototype" /> has an alias (as returned from
+          <see cref="M:Mono.Options.Option.GetNames" />) that conflicts with
+          a previously registered <see cref="T:Mono.Options.Option" />.
+        </exception>
+        <exception cref="T:System.ArgumentNullException">
+          <para>
+            <paramref name="prototype" /> is <see langword="null" /></para>
+          <para>-or-</para>
+          <para>
+            <paramref name="action" /> is <see langword="null" /></para>
+        </exception>
+      </Docs>
+    </Member>
+    <Member MemberName="Error">
+      <MemberSignature Language="C#" Value="public System.IO.TextWriter Error { get; }" />
+      <MemberSignature Language="ILAsm" Value=".property instance class System.IO.TextWriter Error" />
+      <MemberType>Property</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>System.IO.TextWriter</ReturnType>
+      </ReturnValue>
+      <Docs>
+        <summary>
+          Where <c>CommandSet</c> should write error messages.
+        </summary>
+        <value>
+          A <see cref="T:System.IO.TextWriter" /> where error messages will
+          be written to.
+        </value>
+        <remarks>
+          <para>
+            This value may be set by providing the <paramref name="error" />
+            constructor parameter. If not specified, then
+            <see cref="P:System.Console.Error" /> will be used.
+          </para>
+          <para>
+            Error messages by <c>CommandSet</c> are written to the <c>Error</c>
+            property. <c>Command</c> instances may also choose to write error
+            messages to the <c>CommandSet.Error</c> property. This is suggested
+            to help with unit testing.
+          </para>
+        </remarks>
+      </Docs>
+    </Member>
+    <Member MemberName="GetKeyForItem">
+      <MemberSignature Language="C#" Value="protected override string GetKeyForItem (Mono.Options.Command item);" />
+      <MemberSignature Language="ILAsm" Value=".method familyhidebysig virtual instance string GetKeyForItem(class Mono.Options.Command item) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>System.String</ReturnType>
+      </ReturnValue>
+      <Parameters>
+        <Parameter Name="item" Type="Mono.Options.Command" />
+      </Parameters>
+      <Docs>
+        <param name="item">
+          An <see cref="T:Mono.Options.Command" /> to return the key of.
+        </param>
+        <summary>
+          Returns <c><paramref name="item" />.Name</c>.
+        </summary>
+        <returns>
+          A <see cref="T:System.String" /> containing the command name.
+        </returns>
+        <remarks>
+          <para>
+            This is to support the
+            <see cref="T:System.Collections.ObjectModel.KeyedCollection{System.String,Mono.Options.Command}" />
+            infrastructure.
+          </para>
+        </remarks>
+      </Docs>
+    </Member>
+    <Member MemberName="MessageLocalizer">
+      <MemberSignature Language="C#" Value="public Converter&lt;string,string&gt; MessageLocalizer { get; }" />
+      <MemberSignature Language="ILAsm" Value=".property instance class System.Converter`2&lt;string, string&gt; MessageLocalizer" />
+      <MemberType>Property</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>System.Converter&lt;System.String,System.String&gt;</ReturnType>
+      </ReturnValue>
+      <Docs>
+        <summary>
+          Permits access to the message localization facility.
+        </summary>
+        <value>
+          A <see cref="T:System.Converter{System.String,System.String}" />
+          that can be used to localize messages.
+        </value>
+        <remarks>
+        </remarks>
+      </Docs>
+    </Member>
+    <Member MemberName="Out">
+      <MemberSignature Language="C#" Value="public System.IO.TextWriter Out { get; }" />
+      <MemberSignature Language="ILAsm" Value=".property instance class System.IO.TextWriter Out" />
+      <MemberType>Property</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>System.IO.TextWriter</ReturnType>
+      </ReturnValue>
+      <Docs>
+        <summary>
+          Where <c>CommandSet</c> should write output messages.
+        </summary>
+        <value>
+          A <see cref="T:System.IO.TextWriter" /> where output messages will
+          be written to.
+        </value>
+        <remarks>
+          <para>
+            This value may be set by providing the <paramref name="output" />
+            constructor parameter. If not specified, then
+            <see cref="P:System.Console.Out" /> will be used.
+          </para>
+          <para>
+            Output messages by <c>CommandSet</c> are written to the <c>Out</c>
+            property. <c>Command</c> instances may also choose to write output
+            messages to the <c>CommandSet.Out</c> property. This is suggested
+            to help with unit testing.
+          </para>
+        </remarks>
+      </Docs>
+    </Member>
+    <Member MemberName="Run">
+      <MemberSignature Language="C#" Value="public int Run (System.Collections.Generic.IEnumerable&lt;string&gt; arguments);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig instance int32 Run(class System.Collections.Generic.IEnumerable`1&lt;string&gt; arguments) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>System.Int32</ReturnType>
+      </ReturnValue>
+      <Parameters>
+        <Parameter Name="arguments" Type="System.Collections.Generic.IEnumerable&lt;System.String&gt;" />
+      </Parameters>
+      <Docs>
+        <param name="arguments">
+          A <see cref="T:System.Collections.Generic.IEnumerable{System.String}" />
+          containing the command-line arguments to process.
+        </param>
+        <summary>
+          Processes command-line arguments and invokes the specified command.
+        </summary>
+        <returns>
+          A <see cref="T:System.Int32" /> containing the command's exit value.
+          Normal Unix process exit values should be used: <c>0</c> for success,
+          non-zero values for failures.
+        </returns>
+        <remarks>
+          <para>
+            Processes <paramref name="arguments" />, parsing global options in the first pass.
+            The first unprocessed argument is treated as a command name, and the
+            <see cref="T:Mono.Options.Command" /> instance with a
+            <see cref="P:Mono.Options.Command.Name" /> value matching the command name
+            has its <see cref="M:Mono.Options.Command.Invoke" /> method invoked with the
+            unprocessed arguments.
+          </para>
+          <block subset="none" type="behaviors">
+            <para>
+              If no command is specified within <paramref name="arguments" /><i>or</i> an invalid command name is specified, then <c>1</c> is returned.
+              Otherwise, the value returned from
+              <see cref="M:Mono.Options.Command.Invoke" /> is returned.
+            </para>
+          </block>
+          <para>
+            If the <c>help</c> command is provided with no arguments, then the
+            suite help text will be written to
+            <see cref="P:Mono.Options.CommandSet.Out" />
+            consisting of the descriptive text ("headers"), options, and
+            <c>Command</c> values provided to
+            <see cref="M:Mono.Options.CommandSet.Add" />.
+          </para>
+          <para>
+            If the <c>help</c> command is provided with <c>--help</c> as an
+            argument, then all registered <c>Command</c> instances are written to
+            <see cref="P:Mono.Options.CommandSet.Out" />.
+          </para>
+          <para>
+            If the <c>help</c> command is provided with any other string, the
+            following value is treated as a command name, and the output of
+            <c>command --help</c> is written to
+            <see cref="P:Mono.Options.CommandSet.Out" />. If the specified
+            command name has not been registered, then an error message is written to
+            <see cref="P:Mono.Options.CommandSet.Error" />.
+          </para>
+        </remarks>
+      </Docs>
+    </Member>
+    <Member MemberName="Suite">
+      <MemberSignature Language="C#" Value="public string Suite { get; }" />
+      <MemberSignature Language="ILAsm" Value=".property instance string Suite" />
+      <MemberType>Property</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>System.String</ReturnType>
+      </ReturnValue>
+      <Docs>
+        <summary>
+          The name of the suite.
+        </summary>
+        <value>
+          A <see cref="T:System.String" /> containing the name of the command suite.
+        </value>
+        <remarks>
+          <para>
+            The <c>Suite</c> value is used when no command is specified, or
+            when an unregistered command name is provided.
+          </para>
+        </remarks>
+      </Docs>
+    </Member>
+  </Members>
+</Type>
\ No newline at end of file
diff --git a/mcs/class/Mono.Options/Documentation/en/Mono.Options/HelpCommand.xml b/mcs/class/Mono.Options/Documentation/en/Mono.Options/HelpCommand.xml
new file mode 100644 (file)
index 0000000..74af856
--- /dev/null
@@ -0,0 +1,51 @@
+<Type Name="HelpCommand" FullName="Mono.Options.HelpCommand">
+  <TypeSignature Language="C#" Value="public class HelpCommand : Mono.Options.Command" />
+  <TypeSignature Language="ILAsm" Value=".class public auto ansi beforefieldinit HelpCommand extends Mono.Options.Command" />
+  <AssemblyInfo>
+    <AssemblyName>Mono.Options</AssemblyName>
+    <AssemblyVersion>0.2.3.0</AssemblyVersion>
+  </AssemblyInfo>
+  <Base>
+    <BaseTypeName>Mono.Options.Command</BaseTypeName>
+  </Base>
+  <Interfaces />
+  <Docs>
+    <summary>To be added.</summary>
+    <remarks>To be added.</remarks>
+  </Docs>
+  <Members>
+    <Member MemberName=".ctor">
+      <MemberSignature Language="C#" Value="public HelpCommand ();" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig specialname rtspecialname instance void .ctor() cil managed" />
+      <MemberType>Constructor</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <Parameters />
+      <Docs>
+        <summary>To be added.</summary>
+        <remarks>To be added.</remarks>
+      </Docs>
+    </Member>
+    <Member MemberName="Invoke">
+      <MemberSignature Language="C#" Value="public override int Invoke (System.Collections.Generic.IEnumerable&lt;string&gt; arguments);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig virtual instance int32 Invoke(class System.Collections.Generic.IEnumerable`1&lt;string&gt; arguments) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>0.2.3.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>System.Int32</ReturnType>
+      </ReturnValue>
+      <Parameters>
+        <Parameter Name="arguments" Type="System.Collections.Generic.IEnumerable&lt;System.String&gt;" />
+      </Parameters>
+      <Docs>
+        <param name="arguments">To be added.</param>
+        <summary>To be added.</summary>
+        <returns>To be added.</returns>
+        <remarks>To be added.</remarks>
+      </Docs>
+    </Member>
+  </Members>
+</Type>
index 67225ad77680005658a2e3e423e91d7120289bdc..56ba9fdfdbae727a7812af0e87eb613942f9b05e 100644 (file)
@@ -1059,7 +1059,7 @@ localization: hello:Could not convert string `not-an-int' to type Int32 for opti
         <remarks>
         </remarks>
         <exception cref="T:System.ArgumentNullException">
-          <paramref name="option" /> is <see langword="null" />.
+          <paramref name="source" /> is <see langword="null" />.
         </exception>
       </Docs>
     </Member>
@@ -1137,8 +1137,8 @@ localization: hello:Could not convert string `not-an-int' to type Int32 for opti
         </returns>
         <remarks>
           <para>
-            The <c>Add(string)</c> method can be used to provide option groupin
-            in the output generatedy by
+            The <c>Add(string)</c> method can be used to provide option grouping
+            in the output generated by
             <see cref="M:Mono.Options.OptionSet.WriteOptionDescriptions(System.IO.TextWriter)" />.
           </para>
         </remarks>
diff --git a/mcs/class/Mono.Options/Documentation/en/examples/commands.cs b/mcs/class/Mono.Options/Documentation/en/examples/commands.cs
new file mode 100644 (file)
index 0000000..d8c48e4
--- /dev/null
@@ -0,0 +1,78 @@
+// Sub-commands with Mono.Options.CommandSet
+//
+// Compile as:
+//   mcs -r:Mono.Options.dll commands.cs
+
+using System;
+using System.Collections.Generic;
+
+using Mono.Options;
+
+class CommandDemo {
+       public static int Main (string[] args)
+       {
+               var commands = new CommandSet ("commands") {
+                       "usage: commands COMMAND [OPTIONS]",
+                       "",
+                       "Mono.Options.CommandSet sample app.",
+                       "",
+                       "Global options:",
+                       { "v:",
+                         "Output verbosity.",
+                         (int? n) => Verbosity = n.HasValue ? n.Value : Verbosity + 1 },
+                       "",
+                       "Available commands:",
+                       new Command ("echo", "Echo arguments to the screen") {
+                               Run = ca => Console.WriteLine ("{0}", string.Join (" ", ca)),
+                       },
+                       new RequiresArgs (),
+               };
+               return commands.Run (args);
+       }
+
+       public static int Verbosity;
+}
+
+class RequiresArgs : Command {
+
+       public RequiresArgs ()
+               : base ("requires-args", "Class-based Command subclass")
+       {
+               Options = new OptionSet () {
+                       "usage: commands requires-args [OPTIONS]",
+                       "",
+                       "Class-based Command subclass example.",
+                       { "name|n=",
+                         "{name} of person to greet.",
+                         v => Name = v },
+                       { "help|h|?",
+                         "Show this message and exit.",
+                         v => ShowHelp = v != null },
+               };
+       }
+
+       public        bool    ShowHelp    {get; private set;}
+       public  new   string  Name        {get; private set;}
+
+       public override int Invoke (IEnumerable<string> args)
+       {
+               try {
+                       var extra = Options.Parse (args);
+                       if (ShowHelp) {
+                               Options.WriteOptionDescriptions (CommandSet.Out);
+                               return 0;
+                       }
+                       if (string.IsNullOrEmpty (Name)) {
+                               Console.Error.WriteLine ("commands: Missing required argument `--name=NAME`.");
+                               Console.Error.WriteLine ("commands: Use `commands help requires-args` for details.");
+                               return 1;
+                       }
+                       Console.WriteLine ($"Hello, {Name}!");
+                       return 0;
+               }
+               catch (Exception e) {
+                       Console.Error.WriteLine ("commands: {0}", CommandDemo.Verbosity >= 1 ? e.ToString () : e.Message);
+                       return 1;
+               }
+       }
+}
diff --git a/mcs/class/Mono.Options/Documentation/en/examples/commands.in b/mcs/class/Mono.Options/Documentation/en/examples/commands.in
new file mode 100644 (file)
index 0000000..96855a8
--- /dev/null
@@ -0,0 +1,25 @@
+mono Documentation/en/examples/commands.exe
+
+mono Documentation/en/examples/commands.exe --help
+
+mono Documentation/en/examples/commands.exe help
+
+mono Documentation/en/examples/commands.exe help --help
+
+mono Documentation/en/examples/commands.exe help echo
+
+mono Documentation/en/examples/commands.exe echo --help
+
+mono Documentation/en/examples/commands.exe echo hello, world
+
+mono Documentation/en/examples/commands.exe requires-args
+
+mono Documentation/en/examples/commands.exe help requires-args
+
+mono Documentation/en/examples/commands.exe requires-args --help
+
+mono Documentation/en/examples/commands.exe requires-args -n World
+
+mono Documentation/en/examples/commands.exe invalid-command
+
+mono Documentation/en/examples/commands.exe help invalid-command
diff --git a/mcs/class/Mono.Options/Documentation/en/examples/commands.txt b/mcs/class/Mono.Options/Documentation/en/examples/commands.txt
new file mode 100644 (file)
index 0000000..1930680
--- /dev/null
@@ -0,0 +1,74 @@
+$ mono commands.exe
+Use `commands help` for usage.
+
+$ mono commands.exe --help
+usage: commands COMMAND [OPTIONS]
+
+Mono.Options.CommandSet sample app.
+
+Global options:
+  -v[=VALUE]                 Output verbosity.
+
+Available commands:
+        echo                 Echo arguments to the screen
+        requires-args        Class-based Command subclass
+
+$ mono commands.exe help
+usage: commands COMMAND [OPTIONS]
+
+Mono.Options.CommandSet sample app.
+
+Global options:
+  -v[=VALUE]                 Output verbosity.
+
+Available commands:
+        echo                 Echo arguments to the screen
+        requires-args        Class-based Command subclass
+
+$ mono commands.exe help --help
+Usage: commands COMMAND [OPTIONS]
+Use `commands help COMMAND` for help on a specific command.
+
+Available commands:
+
+        echo                 Echo arguments to the screen
+        requires-args        Class-based Command subclass
+        help                 Show this message and exit
+
+$ mono commands.exe help echo
+--help
+
+$ mono commands.exe echo --help
+--help
+
+$ mono commands.exe echo hello, world
+hello, world
+
+$ mono commands.exe requires-args
+commands: Missing required argument `--name=NAME`.
+commands: Use `commands help requires-args` for details.
+
+$ mono commands.exe help requires-args
+usage: commands requires-args [OPTIONS]
+
+Class-based Command subclass example.
+      --name, -n=name        name of person to greet.
+      --help, -h, -?         Show this message and exit.
+
+$ mono commands.exe requires-args --help
+usage: commands requires-args [OPTIONS]
+
+Class-based Command subclass example.
+      --name, -n=name        name of person to greet.
+      --help, -h, -?         Show this message and exit.
+
+$ mono commands.exe requires-args -n World
+Hello, World!
+
+$ mono commands.exe invalid-command
+commands: Unknown command: invalid-command
+commands: Use `commands help` for usage.
+
+$ mono commands.exe help invalid-command
+commands: Unknown command: invalid-command
+commands: Use `commands help` for usage.
index 4cdca7c2a7d2479e0959d9ffa6cd53e0b0140c9c..f8fdaddee4279048f4b0cc8fdf5eab105de6cff5 100644 (file)
@@ -18,6 +18,9 @@
         <Attribute>
           <AttributeName>System.Reflection.AssemblyTitle("Mono.Options.dll")</AttributeName>
         </Attribute>
+        <Attribute>
+          <AttributeName>System.Runtime.CompilerServices.CompilationRelaxations(8)</AttributeName>
+        </Attribute>
         <Attribute>
           <AttributeName>System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows=true)</AttributeName>
         </Attribute>
@@ -30,6 +33,9 @@
   <Types>
     <Namespace Name="Mono.Options">
       <Type Name="ArgumentSource" Kind="Class" />
+      <Type Name="Command" Kind="Class" />
+      <Type Name="CommandSet" Kind="Class" />
+      <Type Name="HelpCommand" Kind="Class" />
       <Type Name="Option" Kind="Class" />
       <Type Name="OptionAction`2" DisplayName="OptionAction&lt;TKey,TValue&gt;" Kind="Delegate" />
       <Type Name="OptionContext" Kind="Class" />
index 2fb4724b28123360a10f265cb35ae4fe5ce77153..d8cad7eeab1912d8673dac03ef36bbcaf0ff0c64 100644 (file)
@@ -17,6 +17,16 @@ mono_options_DATA = Mono.Options/Options.cs
 
 include ../../build/library.make
 
+test-local: Mono.Options-PCL.dll
+
+clean-local: clean-pcl
+
+Mono.Options-PCL.dll: Mono.Options.dll.sources $(shell cat Mono.Options.dll.sources)
+       $(CSCOMPILE) -target:library -out:$@ -debug+ -d:PCL -r:../lib/$(PROFILE)/System.dll @$<
+
+clean-pcl:
+       -rm Mono.Options-PCL.dll
+
 install-local: install-source
 
 uninstall-local: uninstall-source
@@ -35,6 +45,7 @@ fixup-docs:
 
 DOC_EXAMPLES_OUTPUT = \
        Documentation/en/examples/bundling.txt \
+       Documentation/en/examples/commands.txt \
        Documentation/en/examples/context.txt \
        Documentation/en/examples/greet.txt \
        Documentation/en/examples/localization.txt \
@@ -47,7 +58,7 @@ Documentation/en/examples/Mono.Options.dll: $(the_lib)
        -cp $^.mdb $@.mdb
 
 %.exe: %.cs Documentation/en/examples/Mono.Options.dll
-       $(CSCOMPILE) -debug+ -r:Mono.Posix.dll -r:System.Core.dll -lib:Documentation/en/examples -r:Mono.Options.dll -out:$@ $<
+       $(CSCOMPILE) -debug+ -r:../lib/$(PROFILE)/System.dll -r:../lib/$(PROFILE)/Mono.Posix.dll -r:../lib/$(PROFILE)/System.Core.dll -lib:Documentation/en/examples -r:../lib/$(PROFILE)/Mono.Options.dll -out:$@ $<
 
 Documentation/en/examples/locale/es/LC_MESSAGES/localization.mo: Documentation/en/examples/localization-es.po
        msgfmt $< -o $@
index 05810c39481db0174ff22f0c42d2954b5b044195..029bcb87dded329d093d7a039a36dc82472efb71 100644 (file)
@@ -2,13 +2,14 @@
 // Options.cs
 //
 // Authors:
-//  Jonathan Pryor <jpryor@novell.com>
+//  Jonathan Pryor <jpryor@novell.com>, <Jonathan.Pryor@microsoft.com>
 //  Federico Di Gregorio <fog@initd.org>
 //  Rolf Bjarne Kvinge <rolf@xamarin.com>
 //
 // Copyright (C) 2008 Novell (http://www.novell.com)
 // Copyright (C) 2009 Federico Di Gregorio.
 // Copyright (C) 2012 Xamarin Inc (http://www.xamarin.com)
+// Copyright (C) 2017 Microsoft Corporation (http://www.microsoft.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -31,8 +32,8 @@
 //
 
 // Compile With:
-//   gmcs -debug+ -r:System.Core Options.cs -o:NDesk.Options.dll
-//   gmcs -debug+ -d:LINQ -r:System.Core Options.cs -o:NDesk.Options.dll
+//   mcs -debug+ -r:System.Core Options.cs -o:Mono.Options.dll
+//   mcs -debug+ -d:LINQ -r:System.Core Options.cs -o:Mono.Options.dll
 //
 // The LINQ version just changes the implementation of
 // OptionSet.Parse(IEnumerable<string>), and confers no semantic changes.
@@ -40,7 +41,7 @@
 //
 // A Getopt::Long-inspired option parsing library for C#.
 //
-// NDesk.Options.OptionSet is built upon a key/value table, where the
+// Mono.Options.OptionSet is built upon a key/value table, where the
 // key is a option format string and the value is a delegate that is 
 // invoked when the format string is matched.
 //
 //      p.Parse (new string[]{"-a-"});  // sets v == null
 //
 
+//
+// Mono.Options.CommandSet allows easily having separate commands and
+// associated command options, allowing creation of a *suite* along the
+// lines of **git**(1), **svn**(1), etc.
+//
+// CommandSet allows intermixing plain text strings for `--help` output,
+// Option values -- as supported by OptionSet -- and Command instances,
+// which have a name, optional help text, and an optional OptionSet.
+//
+//  var suite = new CommandSet ("suite-name") {
+//    // Use strings and option values, as with OptionSet
+//    "usage: suite-name COMMAND [OPTIONS]+",
+//    { "v:", "verbosity", (int? v) => Verbosity = v.HasValue ? v.Value : Verbosity+1 },
+//    // Commands may also be specified
+//    new Command ("command-name", "command help") {
+//      Options = new OptionSet {/*...*/},
+//      Run     = args => { /*...*/},
+//    },
+//    new MyCommandSubclass (),
+//  };
+//  return suite.Run (new string[]{...});
+//
+// CommandSet provides a `help` command, and forwards `help COMMAND`
+// to the registered Command instance by invoking Command.Invoke()
+// with `--help` as an option.
+//
+
 using System;
 using System.Collections;
 using System.Collections.Generic;
@@ -414,7 +442,7 @@ namespace Mono.Options
                                ? new[]{prototype + this.GetHashCode ()}
                                : prototype.Split ('|');
 
-                       if (this is OptionSet.Category)
+                       if (this is OptionSet.Category || this is CommandOption)
                                return;
 
                        this.type        = ParsePrototype ();
@@ -585,6 +613,11 @@ namespace Mono.Options
 
                protected abstract void OnParseComplete (OptionContext c);
 
+               internal void InvokeOnParseComplete (OptionContext c)
+               {
+                       OnParseComplete (c);
+               }
+
                public override string ToString ()
                {
                        return Prototype;
@@ -732,20 +765,26 @@ namespace Mono.Options
        public class OptionSet : KeyedCollection<string, Option>
        {
                public OptionSet ()
-                       : this (delegate (string f) {return f;})
+                       : this (null)
                {
                }
 
                public OptionSet (MessageLocalizerConverter localizer)
                {
+                       this.roSources = new ReadOnlyCollection<ArgumentSource> (sources);
                        this.localizer = localizer;
-                       this.roSources = new ReadOnlyCollection<ArgumentSource>(sources);
+                       if (this.localizer == null) {
+                               this.localizer = delegate (string f) {
+                                       return f;
+                               };
+                       }
                }
 
                MessageLocalizerConverter localizer;
 
                public MessageLocalizerConverter MessageLocalizer {
                        get {return localizer;}
+                       internal set {localizer = value;}
                }
 
                List<ArgumentSource> sources = new List<ArgumentSource> ();
@@ -1210,6 +1249,9 @@ namespace Mono.Options
                private const int Description_FirstWidth  = 80 - OptionWidth;
                private const int Description_RemWidth    = 80 - OptionWidth - 2;
 
+               static  readonly    string      CommandHelpIndentStart       = new string (' ', OptionWidth);
+               static  readonly    string      CommandHelpIndentRemaining   = new string (' ', OptionWidth + 2);
+
                public void WriteOptionDescriptions (TextWriter o)
                {
                        foreach (Option p in this) {
@@ -1223,6 +1265,11 @@ namespace Mono.Options
                                        WriteDescription (o, p.Description, "", 80, 80);
                                        continue;
                                }
+                               CommandOption co = p as CommandOption;
+                               if (co != null) {
+                                       WriteCommandDescription (o, co.Command);
+                                       continue;
+                               }
 
                                if (!WriteOptionPrototype (o, p, ref written))
                                        continue;
@@ -1264,6 +1311,17 @@ namespace Mono.Options
                        }
                }
 
+               internal void WriteCommandDescription (TextWriter o, Command c)
+               {
+                       var name = new string (' ', 8) + c.Name;
+                       if (name.Length < OptionWidth - 1) {
+                               WriteDescription (o, name + new string (' ', OptionWidth - name.Length) + c.Help, CommandHelpIndentRemaining, 80, Description_RemWidth);
+                       } else {
+                               WriteDescription (o, name, "", 80, 80);
+                               WriteDescription (o, CommandHelpIndentStart + c.Help, CommandHelpIndentRemaining, 80, Description_RemWidth);
+                       }
+               }
+
                void WriteDescription (TextWriter o, string value, string prefix, int firstWidth, int remWidth)
                {
                        bool indent = false;
@@ -1403,5 +1461,341 @@ namespace Mono.Options
                        return StringCoda.WrappedLines (description, firstWidth, remWidth);
                }
        }
+
+       public class Command
+       {
+               public      string                              Name            {get;}
+               public      string                              Help            {get;}
+
+               public      OptionSet                           Options         {get; set;}
+               public      Action<IEnumerable<string>>         Run             {get; set;}
+
+               public      CommandSet                          CommandSet      {get; internal set;}
+
+               public Command (string name, string help = null)
+               {
+                       if (string.IsNullOrEmpty (name))
+                               throw new ArgumentNullException (nameof (name));
+
+                       Name    = name;
+                       Help    = help;
+               }
+
+               public virtual int Invoke (IEnumerable<string> arguments)
+               {
+                       var rest    = Options?.Parse (arguments) ?? arguments;
+                       Run?.Invoke (rest);
+                       return 0;
+               }
+       }
+
+       class CommandOption : Option
+       {
+               public      Command             Command         {get;}
+
+               // Prototype starts with '=' because this is an invalid prototype
+               // (see Option.ParsePrototype(), and thus it'll prevent Category
+               // instances from being accidentally used as normal options.
+               public CommandOption (Command command, bool hidden = false)
+                       : base ("=:Command:= " + command?.Name, command?.Name, maxValueCount: 0, hidden: hidden)
+               {
+                       if (command == null)
+                               throw new ArgumentNullException (nameof (command));
+                       Command = command;
+               }
+
+               protected override void OnParseComplete (OptionContext c)
+               {
+                       throw new NotSupportedException ("CommandOption.OnParseComplete should not be invoked.");
+               }
+       }
+
+       class HelpOption : Option
+       {
+               Option      option;
+               CommandSet  commands;
+
+               public HelpOption (CommandSet commands, Option d)
+                       : base (d.Prototype, d.Description, d.MaxValueCount, d.Hidden)
+               {
+                       this.commands   = commands;
+                       this.option     = d;
+               }
+
+               protected override void OnParseComplete (OptionContext c)
+               {
+                       commands.showHelp  = true;
+
+                       option?.InvokeOnParseComplete (c);
+               }
+       }
+
+       class CommandOptionSet : OptionSet
+       {
+               CommandSet  commands;
+
+               public CommandOptionSet (CommandSet commands, MessageLocalizerConverter localizer)
+                       : base (localizer)
+               {
+                       this.commands = commands;
+               }
+
+               protected override void SetItem (int index, Option item)
+               {
+                       if (ShouldWrapOption (item)) {
+                               base.SetItem (index, new HelpOption (commands, item));
+                               return;
+                       }
+                       base.SetItem (index, item);
+               }
+
+               bool ShouldWrapOption (Option item)
+               {
+                       if (item == null)
+                               return false;
+                       var help = item as HelpOption;
+                       if (help != null)
+                               return false;
+                       foreach (var n in item.Names) {
+                               if (n == "help")
+                                       return true;
+                       }
+                       return false;
+               }
+
+               protected override void InsertItem (int index, Option item)
+               {
+                       if (ShouldWrapOption (item)) {
+                               base.InsertItem (index, new HelpOption (commands, item));
+                               return;
+                       }
+                       base.InsertItem (index, item);
+               }
+       }
+
+       public class CommandSet : KeyedCollection<string, Command>
+       {
+               readonly    OptionSet       options;
+               readonly    TextWriter      outWriter;
+               readonly    TextWriter      errorWriter;
+               readonly    string          suite;
+
+               HelpCommand help;
+
+               internal    bool            showHelp;
+
+               internal    OptionSet       Options     => options;
+
+               public CommandSet (string suite, MessageLocalizerConverter localizer = null, TextWriter output = null, TextWriter error = null)
+               {
+                       if (suite == null)
+                               throw new ArgumentNullException (nameof (suite));
+                       this.suite  = suite;
+                       options     = new CommandOptionSet (this, localizer);
+                       outWriter   = output    ?? Console.Out;
+                       errorWriter = error     ?? Console.Error;
+               }
+
+               public  string                          Suite               => suite;
+               public  TextWriter                      Out                 => outWriter;
+               public  TextWriter                      Error               => errorWriter;
+               public  MessageLocalizerConverter       MessageLocalizer    => options.MessageLocalizer;
+
+               protected override string GetKeyForItem (Command item)
+               {
+                       return item?.Name;
+               }
+
+               public new CommandSet Add (Command value)
+               {
+                       if (value == null)
+                               throw new ArgumentNullException (nameof (value));
+                       AddCommand (value);
+                       options.Add (new CommandOption (value));
+                       return this;
+               }
+
+               void AddCommand (Command value)
+               {
+                       if (value.CommandSet != null && value.CommandSet != this) {
+                               throw new ArgumentException ("Command instances can only be added to a single CommandSet.", nameof (value));
+                       }
+                       value.CommandSet                = this;
+                       if (value.Options != null) {
+                               value.Options.MessageLocalizer  = options.MessageLocalizer;
+                       }
+
+                       base.Add (value);
+
+                       help    = help ?? value as HelpCommand;
+               }
+
+               public CommandSet Add (string header)
+               {
+                       options.Add (header);
+                       return this;
+               }
+
+               public CommandSet Add (Option option)
+               {
+                       options.Add (option);
+                       return this;
+               }
+
+               public CommandSet Add (string prototype, Action<string> action)
+               {
+                       options.Add (prototype, action);
+                       return this;
+               }
+
+               public CommandSet Add (string prototype, string description, Action<string> action)
+               {
+                       options.Add (prototype, description, action);
+                       return this;
+               }
+
+               public CommandSet Add (string prototype, string description, Action<string> action, bool hidden)
+               {
+                       options.Add (prototype, description, action, hidden);
+                       return this;
+               }
+
+               public CommandSet Add (string prototype, OptionAction<string, string> action)
+               {
+                       options.Add (prototype, action);
+                       return this;
+               }
+
+               public CommandSet Add (string prototype, string description, OptionAction<string, string> action)
+               {
+                       options.Add (prototype, description, action);
+                       return this;
+               }
+
+               public CommandSet Add (string prototype, string description, OptionAction<string, string> action, bool hidden)
+               {
+                       options.Add (prototype, description, action, hidden);
+                       return this;
+               }
+
+               public CommandSet Add<T> (string prototype, Action<T> action)
+               {
+                       options.Add (prototype, null, action);
+                       return this;
+               }
+
+               public CommandSet Add<T> (string prototype, string description, Action<T> action)
+               {
+                       options.Add (prototype, description, action);
+                       return this;
+               }
+
+               public CommandSet Add<TKey, TValue> (string prototype, OptionAction<TKey, TValue> action)
+               {
+                       options.Add (prototype, action);
+                       return this;
+               }
+
+               public CommandSet Add<TKey, TValue> (string prototype, string description, OptionAction<TKey, TValue> action)
+               {
+                       options.Add (prototype, description, action);
+                       return this;
+               }
+
+               public CommandSet Add (ArgumentSource source)
+               {
+                       options.Add (source);
+                       return this;
+               }
+
+               public int Run (IEnumerable<string> arguments)
+               {
+                       if (arguments == null)
+                               throw new ArgumentNullException (nameof (arguments));
+
+                       this.showHelp   = false;
+                       if (help == null) {
+                               help    = new HelpCommand ();
+                               AddCommand (help);
+                       }
+                       Action<string>  setHelp     = v => showHelp = v != null;
+                       if (!options.Contains ("help")) {
+                               options.Add ("help", "", setHelp, hidden: true);
+                       }
+                       if (!options.Contains ("?")) {
+                               options.Add ("?", "", setHelp, hidden: true);
+                       }
+                       var extra   = options.Parse (arguments);
+                       if (extra.Count == 0) {
+                               if (showHelp) {
+                                       return help.Invoke (extra);
+                               }
+                               Out.WriteLine (options.MessageLocalizer ($"Use `{Suite} help` for usage."));
+                               return 1;
+                       }
+                       var command = Contains (extra [0]) ? this [extra [0]] : null;
+                       if (command == null) {
+                               help.WriteUnknownCommand (extra [0]);
+                               return 1;
+                       }
+                       extra.RemoveAt (0);
+                       if (showHelp) {
+                               if (command.Options?.Contains ("help") ?? true) {
+                                       extra.Add ("--help");
+                                       return command.Invoke (extra);
+                               }
+                               command.Options.WriteOptionDescriptions (Out);
+                               return 0;
+                       }
+                       return command.Invoke (extra);
+               }
+       }
+
+       public class HelpCommand : Command
+       {
+               public HelpCommand ()
+                       : base ("help", help: "Show this message and exit")
+               {
+               }
+
+               public override int Invoke (IEnumerable<string> arguments)
+               {
+                       var extra   = new List<string> (arguments ?? new string [0]);
+                       var _       = CommandSet.Options.MessageLocalizer;
+                       if (extra.Count == 0) {
+                               CommandSet.Options.WriteOptionDescriptions (CommandSet.Out);
+                               return 0;
+                       }
+                       var command = CommandSet.Contains (extra [0])
+                               ? CommandSet [extra [0]]
+                               : null;
+                       if (command == this || extra [0] == "--help") {
+                               CommandSet.Out.WriteLine (_ ($"Usage: {CommandSet.Suite} COMMAND [OPTIONS]"));
+                               CommandSet.Out.WriteLine (_ ($"Use `{CommandSet.Suite} help COMMAND` for help on a specific command."));
+                               CommandSet.Out.WriteLine ();
+                               CommandSet.Out.WriteLine (_ ($"Available commands:"));
+                               CommandSet.Out.WriteLine ();
+                               foreach (var c in CommandSet) {
+                                       CommandSet.Options.WriteCommandDescription (CommandSet.Out, c);
+                               }
+                               return 0;
+                       }
+                       if (command == null) {
+                               WriteUnknownCommand (extra [0]);
+                               return 1;
+                       }
+                       if (command.Options != null) {
+                               command.Options.WriteOptionDescriptions (CommandSet.Out);
+                               return 0;
+                       }
+                       return command.Invoke (new [] { "--help" });
+               }
+
+               internal void WriteUnknownCommand (string unknownCommand)
+               {
+                       CommandSet.Error.WriteLine (CommandSet.Options.MessageLocalizer ($"{CommandSet.Suite}: Unknown command: {unknownCommand}"));
+                       CommandSet.Error.WriteLine (CommandSet.Options.MessageLocalizer ($"{CommandSet.Suite}: Use `{CommandSet.Suite} help` for usage."));
+               }
+       }
 }
 
index 686fa1244eff719ae8dccd11d0a6caefc9a1f9b4..d63b1f2c83bede4268c63a0904d441768665f247 100644 (file)
@@ -1,5 +1,6 @@
 Mono.Options/BaseRocksFixture.cs
 Mono.Options/CollectionContract.cs
+Mono.Options/CommandSetTest.cs
 Mono.Options/ListContract.cs
 Mono.Options/OptionContextTest.cs
 Mono.Options/OptionSetTest.cs
diff --git a/mcs/class/Mono.Options/Test/Mono.Options-Test-net_4_x.csproj b/mcs/class/Mono.Options/Test/Mono.Options-Test-net_4_x.csproj
new file mode 100644 (file)
index 0000000..83ffda6
--- /dev/null
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <PropertyGroup>\r
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>\r
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>\r
+    <ProjectGuid>{472A5C45-8331-4849-B89F-A872CF884DA3}</ProjectGuid>\r
+    <OutputType>Library</OutputType>\r
+    <RootNamespace>Mono.Options_Test_net_4_x</RootNamespace>\r
+    <AssemblyName>Mono.Options_Test_net_4_x</AssemblyName>\r
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">\r
+    <DebugSymbols>true</DebugSymbols>\r
+    <DebugType>full</DebugType>\r
+    <Optimize>false</Optimize>\r
+    <OutputPath>bin\Debug</OutputPath>\r
+    <DefineConstants>DEBUG;</DefineConstants>\r
+    <ErrorReport>prompt</ErrorReport>\r
+    <WarningLevel>4</WarningLevel>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">\r
+    <Optimize>true</Optimize>\r
+    <OutputPath>bin\Release</OutputPath>\r
+    <ErrorReport>prompt</ErrorReport>\r
+    <WarningLevel>4</WarningLevel>\r
+  </PropertyGroup>\r
+  <ItemGroup>\r
+    <Reference Include="System" />\r
+    <Reference Include="nunit.framework">\r
+      <HintPath>..\lib\net_4_x\nunit.framework.dll</HintPath>\r
+    </Reference>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <Compile Include="Mono.Options\BaseRocksFixture.cs" />\r
+    <Compile Include="Mono.Options\CategoryTest.cs" />\r
+    <Compile Include="Mono.Options\CollectionContract.cs" />\r
+    <Compile Include="Mono.Options\ListContract.cs" />\r
+    <Compile Include="Mono.Options\OptionContextTest.cs" />\r
+    <Compile Include="Mono.Options\OptionSetTest.cs" />\r
+    <Compile Include="Mono.Options\OptionTest.cs" />\r
+    <Compile Include="Mono.Options\Utils.cs" />\r
+    <Compile Include="Mono.Options\CommandSetTest.cs" />\r
+    <Compile Include="Mono.Options\CommandTest.cs" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ProjectReference Include="..\Mono.Options-net_4_x.csproj">\r
+      <Project>{115711B0-D1F2-4E50-83F9-63128E70CE05}</Project>\r
+      <Name>Mono.Options-net_4_x</Name>\r
+    </ProjectReference>\r
+  </ItemGroup>\r
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />\r
+</Project>
\ No newline at end of file
diff --git a/mcs/class/Mono.Options/Test/Mono.Options/CommandSetTest.cs b/mcs/class/Mono.Options/Test/Mono.Options/CommandSetTest.cs
new file mode 100644 (file)
index 0000000..a195e43
--- /dev/null
@@ -0,0 +1,249 @@
+//
+// CommandSetTest.cs
+//
+// Authors:
+//  Jonathan Pryor <Jonathan.Pryor@microsoft.com>
+//
+// Copyright (C) 2017 Microsoft (http://www.microsoft.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+
+#if NDESK_OPTIONS
+using NDesk.Options;
+#else
+using Mono.Options;
+#endif
+
+using Cadenza.Collections.Tests;
+
+using NUnit.Framework;
+
+#if NDESK_OPTIONS
+namespace Tests.NDesk.Options
+#else
+namespace MonoTests.Mono.Options
+#endif
+{
+       [TestFixture]
+       public class CommandSetTest : ListContract<Command>
+       {
+               protected override ICollection<Command> CreateCollection (IEnumerable<Command> values)
+               {
+                       var set = new CommandSet ("test");
+                       foreach (var value in values)
+                               set.Add (value);
+                       return set;
+               }
+
+               protected override Command CreateValueA ()
+               {
+                       return new Command (
+                               "foo",
+                               "foo help");
+               }
+
+               protected override Command CreateValueB ()
+               {
+                       return new Command (
+                               "bar",
+                               "bar help");
+               }
+
+               protected override Command CreateValueC ()
+               {
+                       return new Command (
+                               "baz",
+                               "baz help");
+               }
+
+               static IEnumerable<string> _ (params string [] a)
+               {
+                       return a;
+               }
+
+               [Test]
+               public void Constructor_SuiteRequired ()
+               {
+                       Assert.Throws<ArgumentNullException> (() => new CommandSet (null));
+               }
+
+               [Test]
+               public void Add_NullCommand ()
+               {
+                       var c = new CommandSet ("cs");
+                       Assert.Throws<ArgumentNullException> (() => c.Add ((Command)null));
+               }
+
+               [Test]
+               public void Add_CommandCanBeAddedToOnlyOneSet ()
+               {
+                       var cs1 = new CommandSet ("cs1");
+                       var cs2 = new CommandSet ("cs2");
+                       var c   = new Command ("command", "help");
+                       cs1.Add (c);
+                       Assert.Throws<ArgumentException> (() => cs2.Add (c));
+               }
+
+               [Test]
+               public void Add_SetsCommandSet ()
+               {
+                       var cs  = new CommandSet ("cs");
+                       var c   = new Command ("command");
+                       Assert.IsNull (c.CommandSet);
+                       cs.Add (c);
+                       Assert.AreSame (cs, c.CommandSet);
+               }
+
+               [Test]
+               public void Add_DuplicateCommand ()
+               {
+                       var s = new CommandSet ("set");
+                       s.Add (new Command ("value"));
+                       Assert.Throws<ArgumentException> (() => s.Add (new Command ("value")));
+               }
+
+               [Test]
+               public void Run_Help ()
+               {
+                       var o = new StringWriter ();
+                       var e = new StringWriter ();
+
+                       var showVersion = false;
+                       var showHelp    = false;
+
+                       var git = new CommandSet ("git", output: o, error: e) {
+                               "usage: git [--version] ... <command> [<args>]",
+                               "",
+                               "Common Options:",
+                               { "version",
+                                 "show version info",
+                                 v => showVersion = v != null },
+                               { "help",
+                                 "show this message and exit",
+                                 v => showHelp = v != null },
+                               "",
+                               "These are common Git commands used in various situations:",
+                               "",
+                               "start a working area (see also: git help tutorial)",
+                               new Command ("clone", "Clone a repository into a new directory"),
+                               new Command ("init",  "Create an empty Git repository or reinitialize an existing one"),
+                               new Command ("thisIsAVeryLongCommandNameInOrderToInduceWrapping", "Create an empty Git repository or reinitialize an existing one. Let's make this really long to cause a line wrap, shall we?"),
+                       };
+
+                       var expectedHelp = new StringWriter ();
+
+                       expectedHelp.WriteLine ("usage: git [--version] ... <command> [<args>]");
+                       expectedHelp.WriteLine ("");
+                       expectedHelp.WriteLine ("Common Options:");
+                       expectedHelp.WriteLine ("      --version              show version info");
+                       expectedHelp.WriteLine ("      --help                 show this message and exit");
+                       expectedHelp.WriteLine ("");
+                       expectedHelp.WriteLine ("These are common Git commands used in various situations:");
+                       expectedHelp.WriteLine ("");
+                       expectedHelp.WriteLine ("start a working area (see also: git help tutorial)");
+                       expectedHelp.WriteLine ("        clone                Clone a repository into a new directory");
+                       expectedHelp.WriteLine ("        init                 Create an empty Git repository or reinitialize an");
+                       expectedHelp.WriteLine ("                               existing one");
+                       expectedHelp.WriteLine ("        thisIsAVeryLongCommandNameInOrderToInduceWrapping");
+                       expectedHelp.WriteLine ("                             Create an empty Git repository or reinitialize an");
+                       expectedHelp.WriteLine ("                               existing one. Let's make this really long to");
+                       expectedHelp.WriteLine ("                               cause a line wrap, shall we?");
+
+                       Assert.AreEqual (0, git.Run (new [] { "help" }));
+                       Assert.AreEqual (expectedHelp.ToString (), o.ToString ());
+
+                       var expectedHelpHelp    = new StringWriter ();
+                       expectedHelpHelp.WriteLine ("Usage: git COMMAND [OPTIONS]");
+                       expectedHelpHelp.WriteLine ("Use `git help COMMAND` for help on a specific command.");
+                       expectedHelpHelp.WriteLine ();
+                       expectedHelpHelp.WriteLine ("Available commands:");
+                       expectedHelpHelp.WriteLine ();
+                       expectedHelpHelp.WriteLine ("        clone                Clone a repository into a new directory");
+                       expectedHelpHelp.WriteLine ("        init                 Create an empty Git repository or reinitialize an");
+                       expectedHelpHelp.WriteLine ("                               existing one");
+                       expectedHelpHelp.WriteLine ("        thisIsAVeryLongCommandNameInOrderToInduceWrapping");
+                       expectedHelpHelp.WriteLine ("                             Create an empty Git repository or reinitialize an");
+                       expectedHelpHelp.WriteLine ("                               existing one. Let's make this really long to");
+                       expectedHelpHelp.WriteLine ("                               cause a line wrap, shall we?");
+                       expectedHelpHelp.WriteLine ("        help                 Show this message and exit");
+
+                       o.GetStringBuilder ().Clear ();
+                       Assert.AreEqual (0, git.Run (new [] { "help", "--help" }));
+                       Assert.AreEqual (expectedHelpHelp.ToString (), o.ToString ());
+               }
+
+               [Test]
+               public void Run_Command ()
+               {
+                       var a = 0;
+                       var b = 0;
+                       var c = new CommandSet ("set") {
+                               new Command ("a") { Run = v => a = v.Count () },
+                               new Command ("b") { Run = v => b = v.Count () },
+                       };
+                       Assert.AreEqual (0, c.Run (new [] { "a", "extra" }));
+                       Assert.AreEqual (1, a);
+                       Assert.AreEqual (0, b);
+
+                       a = b = 0;
+                       Assert.AreEqual (0, c.Run (new [] { "b" }));
+                       Assert.AreEqual (0, a);
+                       Assert.AreEqual (0, b);
+
+                       Assert.AreEqual (0, c.Run (new [] { "b", "one", "two" }));
+                       Assert.AreEqual (0, a);
+                       Assert.AreEqual (2, b);
+               }
+
+               [Test]
+               public void Run_HelpCommandSendsHelpOption ()
+               {
+                       var e = new Command ("echo");
+                       e.Run = (args) => e.CommandSet.Out.WriteLine (string.Join (" ", args));
+
+                       var o = new StringWriter ();
+                       var c = new CommandSet ("set", output:o) {
+                               e,
+                       };
+                       Assert.AreEqual (0, c.Run (new [] { "help", "echo" }));
+
+                       var expected    = $"--help{Environment.NewLine}";
+                       var actual      = o.ToString ();
+                       Assert.AreEqual (expected, actual);
+               }
+
+               [Test]
+               public void Run_NullArgument ()
+               {
+                       var c = new CommandSet ("c");
+                       Assert.Throws<ArgumentNullException> (() => c.Run (null));
+               }
+       }
+}
+
diff --git a/mcs/class/Mono.Options/Test/Mono.Options/CommandTest.cs b/mcs/class/Mono.Options/Test/Mono.Options/CommandTest.cs
new file mode 100644 (file)
index 0000000..5805f28
--- /dev/null
@@ -0,0 +1,102 @@
+//
+// CommandSetTest.cs
+//
+// Authors:
+//  Jonathan Pryor <Jonathan.Pryor@microsoft.com>
+//
+// Copyright (C) 2017 Microsoft (http://www.microsoft.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+
+#if NDESK_OPTIONS
+using NDesk.Options;
+#else
+using Mono.Options;
+#endif
+
+using Cadenza.Collections.Tests;
+
+using NUnit.Framework;
+
+#if NDESK_OPTIONS
+namespace Tests.NDesk.Options
+#else
+namespace MonoTests.Mono.Options
+#endif
+{
+       [TestFixture]
+       public class CommandTest
+       {
+               [Test]
+               public void Constructor_NameRequired ()
+               {
+                       Assert.Throws<ArgumentNullException> (() => new Command (name: null, help: null));
+               }
+
+               [Test]
+               public void Constructor ()
+               {
+                       var c = new Command ("command", "help");
+                       Assert.AreEqual ("command", c.Name);
+                       Assert.AreEqual ("help",    c.Help);
+               }
+
+               [Test]
+               public void Invoke_CallsRun ()
+               {
+                       bool runInvoked = false;
+                       var c = new Command ("command") {
+                               Run = v => runInvoked = true,
+                       };
+                       Assert.AreEqual (0, c.Invoke (null));
+                       Assert.IsTrue (runInvoked);
+               }
+
+               [Test]
+               public void Invoke_RequiresNothing ()
+               {
+                       var c = new Command ("c");
+                       Assert.AreEqual (0, c.Invoke (null));
+               }
+
+               [Test]
+               public void Invoke_UsesOptions ()
+               {
+                       bool showHelp = false;
+                       var c = new Command ("c") {
+                               Options = new OptionSet {
+                                       { "help", v => showHelp = v != null },
+                               },
+                       };
+                       Assert.AreEqual (0, c.Invoke (new [] { "--help" }));
+                       Assert.IsTrue (showHelp);
+               }
+       }
+}
+