all repos — WarBot2020 @ 18ce8cf3a05f92a571e69680c7954c3ccc17c324

Bootleg version of "WorldWarBot 2020" done in Java and without a map.

picocli/CommandLine.java (view raw)

    1/*
    2   Copyright 2017 Remko Popma
    3
    4   Licensed under the Apache License, Version 2.0 (the "License");
    5   you may not use this file except in compliance with the License.
    6   You may obtain a copy of the License at
    7
    8       http://www.apache.org/licenses/LICENSE-2.0
    9
   10   Unless required by applicable law or agreed to in writing, software
   11   distributed under the License is distributed on an "AS IS" BASIS,
   12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13   See the License for the specific language governing permissions and
   14   limitations under the License.
   15 */
   16package picocli;
   17
   18import java.io.*;
   19import java.lang.annotation.Annotation;
   20import java.lang.annotation.ElementType;
   21import java.lang.annotation.Retention;
   22import java.lang.annotation.RetentionPolicy;
   23import java.lang.annotation.Target;
   24import java.lang.reflect.*;
   25import java.math.BigDecimal;
   26import java.math.BigInteger;
   27import java.net.InetAddress;
   28import java.net.MalformedURLException;
   29import java.net.NetworkInterface;
   30import java.net.URI;
   31import java.net.URISyntaxException;
   32import java.net.URL;
   33import java.nio.ByteOrder;
   34import java.nio.charset.Charset;
   35import java.text.BreakIterator;
   36import java.text.ParseException;
   37import java.text.SimpleDateFormat;
   38import java.util.*;
   39import java.util.concurrent.Callable;
   40import java.util.regex.Pattern;
   41import picocli.CommandLine.Help.Ansi.IStyle;
   42import picocli.CommandLine.Help.Ansi.Style;
   43import picocli.CommandLine.Help.Ansi.Text;
   44import picocli.CommandLine.Model.*;
   45import picocli.CommandLine.ParseResult.MatchedGroup;
   46
   47import static java.util.Locale.ENGLISH;
   48import static picocli.CommandLine.Help.Column.Overflow.SPAN;
   49import static picocli.CommandLine.Help.Column.Overflow.TRUNCATE;
   50import static picocli.CommandLine.Help.Column.Overflow.WRAP;
   51
   52/**
   53 * <p>
   54 * CommandLine interpreter that uses reflection to initialize an annotated domain object with values obtained from the
   55 * command line arguments.
   56 * </p><h2>Example</h2>
   57 * <pre>import static picocli.CommandLine.*;
   58 *
   59 * &#064;Command(mixinStandardHelpOptions = true, version = "v3.0.0",
   60 *         header = "Encrypt FILE(s), or standard input, to standard output or to the output file.")
   61 * public class Encrypt {
   62 *
   63 *     &#064;Parameters(type = File.class, description = "Any number of input files")
   64 *     private List&lt;File&gt; files = new ArrayList&lt;File&gt;();
   65 *
   66 *     &#064;Option(names = { "-o", "--out" }, description = "Output file (default: print to console)")
   67 *     private File outputFile;
   68 *
   69 *     &#064;Option(names = { "-v", "--verbose"}, description = "Verbose mode. Helpful for troubleshooting. Multiple -v options increase the verbosity.")
   70 *     private boolean[] verbose;
   71 * }
   72 * </pre>
   73 * <p>
   74 * Use {@code CommandLine} to initialize a domain object as follows:
   75 * </p><pre>
   76 * public static void main(String... args) {
   77 *     Encrypt encrypt = new Encrypt();
   78 *     try {
   79 *         ParseResult parseResult = new CommandLine(encrypt).parseArgs(args);
   80 *         if (!CommandLine.printHelpIfRequested(parseResult)) {
   81 *             runProgram(encrypt);
   82 *         }
   83 *     } catch (ParameterException ex) { // command line arguments could not be parsed
   84 *         System.err.println(ex.getMessage());
   85 *         ex.getCommandLine().usage(System.err);
   86 *     }
   87 * }
   88 * </pre><p>
   89 * Invoke the above program with some command line arguments. The below are all equivalent:
   90 * </p>
   91 * <pre>
   92 * --verbose --out=outfile in1 in2
   93 * --verbose --out outfile in1 in2
   94 * -v --out=outfile in1 in2
   95 * -v -o outfile in1 in2
   96 * -v -o=outfile in1 in2
   97 * -vo outfile in1 in2
   98 * -vo=outfile in1 in2
   99 * -v -ooutfile in1 in2
  100 * -vooutfile in1 in2
  101 * </pre>
  102 * <p>
  103 * Another example that implements {@code Callable} and uses the {@link #call(Callable, String...) CommandLine.call} convenience API to run in a single line of code:
  104 * </p>
  105 * <pre>
  106 *  &#064;Command(description = "Prints the checksum (MD5 by default) of a file to STDOUT.",
  107 *          name = "checksum", mixinStandardHelpOptions = true, version = "checksum 3.0")
  108 * class CheckSum implements Callable&lt;Void&gt; {
  109 *
  110 *     &#064;Parameters(index = "0", description = "The file whose checksum to calculate.")
  111 *     private File file;
  112 *
  113 *     &#064;Option(names = {"-a", "--algorithm"}, description = "MD5, SHA-1, SHA-256, ...")
  114 *     private String algorithm = "MD5";
  115 *
  116 *     public static void main(String[] args) throws Exception {
  117 *         // CheckSum implements Callable, so parsing, error handling and handling user
  118 *         // requests for usage help or version help can be done with one line of code.
  119 *         CommandLine.call(new CheckSum(), args);
  120 *     }
  121 *
  122 *     &#064;Override
  123 *     public Void call() throws Exception {
  124 *         // your business logic goes here...
  125 *         byte[] fileContents = Files.readAllBytes(file.toPath());
  126 *         byte[] digest = MessageDigest.getInstance(algorithm).digest(fileContents);
  127 *         System.out.println(javax.xml.bind.DatatypeConverter.printHexBinary(digest));
  128 *         return null;
  129 *     }
  130 * }
  131 * </pre>
  132 * <h2>Classes and Interfaces for Defining a CommandSpec Model</h2>
  133 * <p>
  134 * <img src="doc-files/class-diagram-definition.png" alt="Classes and Interfaces for Defining a CommandSpec Model">
  135 * </p>
  136 * <h2>Classes Related to Parsing Command Line Arguments</h2>
  137 * <p>
  138 * <img src="doc-files/class-diagram-parsing.png" alt="Classes Related to Parsing Command Line Arguments">
  139 * </p>
  140 */
  141public class CommandLine {
  142
  143    /** This is picocli version {@value}. */
  144    public static final String VERSION = "4.0.0-alpha-2-SNAPSHOT";
  145
  146    private final Tracer tracer = new Tracer();
  147    private final CommandSpec commandSpec;
  148    private final Interpreter interpreter;
  149    private final IFactory factory;
  150
  151    /**
  152     * Constructs a new {@code CommandLine} interpreter with the specified object (which may be an annotated user object or a {@link CommandSpec CommandSpec}) and a default subcommand factory.
  153     * <p>The specified object may be a {@link CommandSpec CommandSpec} object, or it may be a {@code @Command}-annotated
  154     * user object with {@code @Option} and {@code @Parameters}-annotated fields, in which case picocli automatically
  155     * constructs a {@code CommandSpec} from this user object.
  156     * </p><p>
  157     * When the {@link #parse(String...)} method is called, the {@link CommandSpec CommandSpec} object will be
  158     * initialized based on command line arguments. If the commandSpec is created from an annotated user object, this
  159     * user object will be initialized based on the command line arguments.</p>
  160     * @param command an annotated user object or a {@code CommandSpec} object to initialize from the command line arguments
  161     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
  162     */
  163    public CommandLine(Object command) {
  164        this(command, new DefaultFactory());
  165    }
  166    /**
  167     * Constructs a new {@code CommandLine} interpreter with the specified object (which may be an annotated user object or a {@link CommandSpec CommandSpec}) and object factory.
  168     * <p>The specified object may be a {@link CommandSpec CommandSpec} object, or it may be a {@code @Command}-annotated
  169     * user object with {@code @Option} and {@code @Parameters}-annotated fields, in which case picocli automatically
  170     * constructs a {@code CommandSpec} from this user object.
  171     *  </p><p> If the specified command object is an interface {@code Class} with {@code @Option} and {@code @Parameters}-annotated methods,
  172     * picocli creates a {@link java.lang.reflect.Proxy Proxy} whose methods return the matched command line values.
  173     * If the specified command object is a concrete {@code Class}, picocli delegates to the {@linkplain IFactory factory} to get an instance.
  174     * </p><p>
  175     * When the {@link #parse(String...)} method is called, the {@link CommandSpec CommandSpec} object will be
  176     * initialized based on command line arguments. If the commandSpec is created from an annotated user object, this
  177     * user object will be initialized based on the command line arguments.</p>
  178     * @param command an annotated user object or a {@code CommandSpec} object to initialize from the command line arguments
  179     * @param factory the factory used to create instances of {@linkplain Command#subcommands() subcommands}, {@linkplain Option#converter() converters}, etc., that are registered declaratively with annotation attributes
  180     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
  181     * @since 2.2 */
  182    public CommandLine(Object command, IFactory factory) {
  183        this.factory = Assert.notNull(factory, "factory");
  184        interpreter = new Interpreter();
  185        commandSpec = CommandSpec.forAnnotatedObject(command, factory);
  186        commandSpec.commandLine(this);
  187        commandSpec.validate();
  188        if (commandSpec.unmatchedArgsBindings().size() > 0) { setUnmatchedArgumentsAllowed(true); }
  189    }
  190
  191    /**
  192     * Returns the {@code CommandSpec} model that this {@code CommandLine} was constructed with.
  193     * @return the {@code CommandSpec} model
  194     * @since 3.0 */
  195    public CommandSpec getCommandSpec() { return commandSpec; }
  196
  197    /**
  198     * Adds the options and positional parameters in the specified mixin to this command.
  199     * <p>The specified object may be a {@link CommandSpec CommandSpec} object, or it may be a user object with
  200     * {@code @Option} and {@code @Parameters}-annotated fields, in which case picocli automatically
  201     * constructs a {@code CommandSpec} from this user object.
  202     * </p>
  203     * @param name the name by which the mixin object may later be retrieved
  204     * @param mixin an annotated user object or a {@link CommandSpec CommandSpec} object whose options and positional parameters to add to this command
  205     * @return this CommandLine object, to allow method chaining
  206     * @since 3.0 */
  207    public CommandLine addMixin(String name, Object mixin) {
  208        getCommandSpec().addMixin(name, CommandSpec.forAnnotatedObject(mixin, factory));
  209        return this;
  210    }
  211
  212    /**
  213     * Returns a map of user objects whose options and positional parameters were added to ("mixed in" with) this command.
  214     * @return a new Map containing the user objects mixed in with this command. If {@code CommandSpec} objects without
  215     *          user objects were programmatically added, use the {@link CommandSpec#mixins() underlying model} directly.
  216     * @since 3.0 */
  217    public Map<String, Object> getMixins() {
  218        Map<String, CommandSpec> mixins = getCommandSpec().mixins();
  219        Map<String, Object> result = new LinkedHashMap<String, Object>();
  220        for (String name : mixins.keySet()) { result.put(name, mixins.get(name).userObject); }
  221        return result;
  222    }
  223
  224    /** Registers a subcommand with the specified name. For example:
  225     * <pre>
  226     * CommandLine commandLine = new CommandLine(new Git())
  227     *         .addSubcommand("status",   new GitStatus())
  228     *         .addSubcommand("commit",   new GitCommit();
  229     *         .addSubcommand("add",      new GitAdd())
  230     *         .addSubcommand("branch",   new GitBranch())
  231     *         .addSubcommand("checkout", new GitCheckout())
  232     *         //...
  233     *         ;
  234     * </pre>
  235     *
  236     * <p>The specified object can be an annotated object or a
  237     * {@code CommandLine} instance with its own nested subcommands. For example:</p>
  238     * <pre>
  239     * CommandLine commandLine = new CommandLine(new MainCommand())
  240     *         .addSubcommand("cmd1",                 new ChildCommand1()) // subcommand
  241     *         .addSubcommand("cmd2",                 new ChildCommand2())
  242     *         .addSubcommand("cmd3", new CommandLine(new ChildCommand3()) // subcommand with nested sub-subcommands
  243     *                 .addSubcommand("cmd3sub1",                 new GrandChild3Command1())
  244     *                 .addSubcommand("cmd3sub2",                 new GrandChild3Command2())
  245     *                 .addSubcommand("cmd3sub3", new CommandLine(new GrandChild3Command3()) // deeper nesting
  246     *                         .addSubcommand("cmd3sub3sub1", new GreatGrandChild3Command3_1())
  247     *                         .addSubcommand("cmd3sub3sub2", new GreatGrandChild3Command3_2())
  248     *                 )
  249     *         );
  250     * </pre>
  251     * <p>The default type converters are available on all subcommands and nested sub-subcommands, but custom type
  252     * converters are registered only with the subcommand hierarchy as it existed when the custom type was registered.
  253     * To ensure a custom type converter is available to all subcommands, register the type converter last, after
  254     * adding subcommands.</p>
  255     * <p>See also the {@link Command#subcommands()} annotation to register subcommands declaratively.</p>
  256     *
  257     * @param name the string to recognize on the command line as a subcommand
  258     * @param command the object to initialize with command line arguments following the subcommand name.
  259     *          This may be a {@code CommandLine} instance with its own (nested) subcommands
  260     * @return this CommandLine object, to allow method chaining
  261     * @see #registerConverter(Class, ITypeConverter)
  262     * @since 0.9.7
  263     * @see Command#subcommands()
  264     */
  265    public CommandLine addSubcommand(String name, Object command) {
  266        return addSubcommand(name, command, new String[0]);
  267    }
  268
  269    /** Registers a subcommand with the specified name and all specified aliases. See also {@link #addSubcommand(String, Object)}.
  270     *
  271     *
  272     * @param name the string to recognize on the command line as a subcommand
  273     * @param command the object to initialize with command line arguments following the subcommand name.
  274     *          This may be a {@code CommandLine} instance with its own (nested) subcommands
  275     * @param aliases zero or more alias names that are also recognized on the command line as this subcommand
  276     * @return this CommandLine object, to allow method chaining
  277     * @since 3.1
  278     * @see #addSubcommand(String, Object)
  279     */
  280    public CommandLine addSubcommand(String name, Object command, String... aliases) {
  281        CommandLine subcommandLine = toCommandLine(command, factory);
  282        subcommandLine.getCommandSpec().aliases.addAll(Arrays.asList(aliases));
  283        getCommandSpec().addSubcommand(name, subcommandLine);
  284        CommandLine.Model.CommandReflection.initParentCommand(subcommandLine.getCommandSpec().userObject(), getCommandSpec().userObject());
  285        return this;
  286    }
  287    /** Returns a map with the subcommands {@linkplain #addSubcommand(String, Object) registered} on this instance.
  288     * @return a map with the registered subcommands
  289     * @since 0.9.7
  290     */
  291    public Map<String, CommandLine> getSubcommands() {
  292        return new LinkedHashMap<String, CommandLine>(getCommandSpec().subcommands());
  293    }
  294    /**
  295     * Returns the command that this is a subcommand of, or {@code null} if this is a top-level command.
  296     * @return the command that this is a subcommand of, or {@code null} if this is a top-level command
  297     * @see #addSubcommand(String, Object)
  298     * @see Command#subcommands()
  299     * @since 0.9.8
  300     */
  301    public CommandLine getParent() {
  302        CommandSpec parent = getCommandSpec().parent();
  303        return parent == null ? null : parent.commandLine();
  304    }
  305
  306    /** Returns the annotated user object that this {@code CommandLine} instance was constructed with.
  307     * @param <T> the type of the variable that the return value is being assigned to
  308     * @return the annotated object that this {@code CommandLine} instance was constructed with
  309     * @since 0.9.7
  310     */
  311    @SuppressWarnings("unchecked")
  312    public <T> T getCommand() {
  313        return (T) getCommandSpec().userObject();
  314    }
  315
  316    /** Returns {@code true} if an option annotated with {@link Option#usageHelp()} was specified on the command line.
  317     * @return whether the parser encountered an option annotated with {@link Option#usageHelp()}.
  318     * @since 0.9.8 */
  319    public boolean isUsageHelpRequested() { return interpreter.parseResultBuilder != null && interpreter.parseResultBuilder.usageHelpRequested; }
  320
  321    /** Returns {@code true} if an option annotated with {@link Option#versionHelp()} was specified on the command line.
  322     * @return whether the parser encountered an option annotated with {@link Option#versionHelp()}.
  323     * @since 0.9.8 */
  324    public boolean isVersionHelpRequested() { return interpreter.parseResultBuilder != null && interpreter.parseResultBuilder.versionHelpRequested; }
  325
  326    /** Returns the {@code IHelpFactory} that is used to construct the usage help message.
  327     * @see #setHelpFactory(IHelpFactory)
  328     * @since 3.9
  329     */
  330    public IHelpFactory getHelpFactory() {
  331        return getCommandSpec().usageMessage().helpFactory();
  332    }
  333
  334    /** Sets a new {@code IHelpFactory} to customize the usage help message.
  335     * @param helpFactory the new help factory. Must be non-{@code null}.
  336     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  337     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  338     * later will have the default setting. To ensure a setting is applied to all
  339     * subcommands, call the setter last, after adding subcommands.</p>
  340     * @return this {@code CommandLine} object, to allow method chaining
  341     * @since 3.9
  342     */
  343    public CommandLine setHelpFactory(IHelpFactory helpFactory) {
  344        getCommandSpec().usageMessage().helpFactory(helpFactory);
  345        for (CommandLine command : getCommandSpec().subcommands().values()) {
  346            command.setHelpFactory(helpFactory);
  347        }
  348        return this;
  349    }
  350
  351    /**
  352     * Returns the section keys in the order that the usage help message should render the sections.
  353     * This ordering may be modified with {@link #setHelpSectionKeys(List) setSectionKeys}. The default keys are (in order):
  354     * <ol>
  355     *   <li>{@link UsageMessageSpec#SECTION_KEY_HEADER_HEADING SECTION_KEY_HEADER_HEADING}</li>
  356     *   <li>{@link UsageMessageSpec#SECTION_KEY_HEADER SECTION_KEY_HEADER}</li>
  357     *   <li>{@link UsageMessageSpec#SECTION_KEY_SYNOPSIS_HEADING SECTION_KEY_SYNOPSIS_HEADING}</li>
  358     *   <li>{@link UsageMessageSpec#SECTION_KEY_SYNOPSIS SECTION_KEY_SYNOPSIS}</li>
  359     *   <li>{@link UsageMessageSpec#SECTION_KEY_DESCRIPTION_HEADING SECTION_KEY_DESCRIPTION_HEADING}</li>
  360     *   <li>{@link UsageMessageSpec#SECTION_KEY_DESCRIPTION SECTION_KEY_DESCRIPTION}</li>
  361     *   <li>{@link UsageMessageSpec#SECTION_KEY_PARAMETER_LIST_HEADING SECTION_KEY_PARAMETER_LIST_HEADING}</li>
  362     *   <li>{@link UsageMessageSpec#SECTION_KEY_PARAMETER_LIST SECTION_KEY_PARAMETER_LIST}</li>
  363     *   <li>{@link UsageMessageSpec#SECTION_KEY_OPTION_LIST_HEADING SECTION_KEY_OPTION_LIST_HEADING}</li>
  364     *   <li>{@link UsageMessageSpec#SECTION_KEY_OPTION_LIST SECTION_KEY_OPTION_LIST}</li>
  365     *   <li>{@link UsageMessageSpec#SECTION_KEY_COMMAND_LIST_HEADING SECTION_KEY_COMMAND_LIST_HEADING}</li>
  366     *   <li>{@link UsageMessageSpec#SECTION_KEY_COMMAND_LIST SECTION_KEY_COMMAND_LIST}</li>
  367     *   <li>{@link UsageMessageSpec#SECTION_KEY_FOOTER_HEADING SECTION_KEY_FOOTER_HEADING}</li>
  368     *   <li>{@link UsageMessageSpec#SECTION_KEY_FOOTER SECTION_KEY_FOOTER}</li>
  369     * </ol>
  370     * @since 3.9
  371     */
  372    public List<String> getHelpSectionKeys() { return getCommandSpec().usageMessage().sectionKeys(); }
  373
  374    /**
  375     * Sets the section keys in the order that the usage help message should render the sections.
  376     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  377     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  378     * later will have the default setting. To ensure a setting is applied to all
  379     * subcommands, call the setter last, after adding subcommands.</p>
  380     * <p>Use {@link UsageMessageSpec#sectionKeys(List)} to customize a command without affecting its subcommands.</p>
  381     * @see #getHelpSectionKeys
  382     * @since 3.9
  383     */
  384    public CommandLine setHelpSectionKeys(List<String> keys) {
  385        getCommandSpec().usageMessage().sectionKeys(keys);
  386        for (CommandLine command : getCommandSpec().subcommands().values()) {
  387            command.setHelpSectionKeys(keys);
  388        }
  389        return this;
  390    }
  391
  392    /**
  393     * Returns the map of section keys and renderers used to construct the usage help message.
  394     * The usage help message can be customized by adding, replacing and removing section renderers from this map.
  395     * Sections can be reordered with {@link #setHelpSectionKeys(List) setSectionKeys}.
  396     * Sections that are either not in this map or not in the list returned by {@link #getHelpSectionKeys() getSectionKeys} are omitted.
  397     * <p>
  398     * NOTE: By modifying the returned {@code Map}, only the usage help message <em>of this command</em> is affected.
  399     * Use {@link #setHelpSectionMap(Map)} to customize the usage help message for this command <em>and all subcommands</em>.
  400     * </p>
  401     * @since 3.9
  402     */
  403    public Map<String, IHelpSectionRenderer> getHelpSectionMap() { return getCommandSpec().usageMessage().sectionMap(); }
  404
  405    /**
  406     * Sets the map of section keys and renderers used to construct the usage help message.
  407     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  408     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  409     * later will have the default setting. To ensure a setting is applied to all
  410     * subcommands, call the setter last, after adding subcommands.</p>
  411     * <p>Use {@link UsageMessageSpec#sectionMap(Map)} to customize a command without affecting its subcommands.</p>
  412     * @see #getHelpSectionMap
  413     * @since 3.9
  414     */
  415    public CommandLine setHelpSectionMap(Map<String, IHelpSectionRenderer> map) {
  416        getCommandSpec().usageMessage().sectionMap(map);
  417        for (CommandLine command : getCommandSpec().subcommands().values()) {
  418            command.setHelpSectionMap(map);
  419        }
  420        return this;
  421    }
  422
  423    /** Returns whether the value of boolean flag options should be "toggled" when the option is matched.
  424     * By default, flags are toggled, so if the value is {@code true} it is set to {@code false}, and when the value is
  425     * {@code false} it is set to {@code true}. If toggling is off, flags are simply set to {@code true}.
  426     * @return {@code true} the value of boolean flag options should be "toggled" when the option is matched, {@code false} otherwise
  427     * @since 3.0
  428     */
  429    public boolean isToggleBooleanFlags() {
  430        return getCommandSpec().parser().toggleBooleanFlags();
  431    }
  432
  433    /** Sets whether the value of boolean flag options should be "toggled" when the option is matched. The default is {@code true}.
  434     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  435     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  436     * later will have the default setting. To ensure a setting is applied to all
  437     * subcommands, call the setter last, after adding subcommands.</p>
  438     * @param newValue the new setting
  439     * @return this {@code CommandLine} object, to allow method chaining
  440     * @since 3.0
  441     */
  442    public CommandLine setToggleBooleanFlags(boolean newValue) {
  443        getCommandSpec().parser().toggleBooleanFlags(newValue);
  444        for (CommandLine command : getCommandSpec().subcommands().values()) {
  445            command.setToggleBooleanFlags(newValue);
  446        }
  447        return this;
  448    }
  449
  450    /** Returns whether options for single-value fields can be specified multiple times on the command line.
  451     * The default is {@code false} and a {@link OverwrittenOptionException} is thrown if this happens.
  452     * When {@code true}, the last specified value is retained.
  453     * @return {@code true} if options for single-value fields can be specified multiple times on the command line, {@code false} otherwise
  454     * @since 0.9.7
  455     */
  456    public boolean isOverwrittenOptionsAllowed() {
  457        return getCommandSpec().parser().overwrittenOptionsAllowed();
  458    }
  459
  460    /** Sets whether options for single-value fields can be specified multiple times on the command line without a {@link OverwrittenOptionException} being thrown.
  461     * The default is {@code false}.
  462     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  463     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  464     * later will have the default setting. To ensure a setting is applied to all
  465     * subcommands, call the setter last, after adding subcommands.</p>
  466     * @param newValue the new setting
  467     * @return this {@code CommandLine} object, to allow method chaining
  468     * @since 0.9.7
  469     */
  470    public CommandLine setOverwrittenOptionsAllowed(boolean newValue) {
  471        getCommandSpec().parser().overwrittenOptionsAllowed(newValue);
  472        for (CommandLine command : getCommandSpec().subcommands().values()) {
  473            command.setOverwrittenOptionsAllowed(newValue);
  474        }
  475        return this;
  476    }
  477
  478    /** Returns whether the parser accepts clustered short options. The default is {@code true}.
  479     * @return {@code true} if short options like {@code -x -v -f SomeFile} can be clustered together like {@code -xvfSomeFile}, {@code false} otherwise
  480     * @since 3.0 */
  481    public boolean isPosixClusteredShortOptionsAllowed() { return getCommandSpec().parser().posixClusteredShortOptionsAllowed(); }
  482
  483    /** Sets whether short options like {@code -x -v -f SomeFile} can be clustered together like {@code -xvfSomeFile}. The default is {@code true}.
  484     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  485     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  486     * later will have the default setting. To ensure a setting is applied to all
  487     * subcommands, call the setter last, after adding subcommands.</p>
  488     * @param newValue the new setting
  489     * @return this {@code CommandLine} object, to allow method chaining
  490     * @since 3.0
  491     */
  492    public CommandLine setPosixClusteredShortOptionsAllowed(boolean newValue) {
  493        getCommandSpec().parser().posixClusteredShortOptionsAllowed(newValue);
  494        for (CommandLine command : getCommandSpec().subcommands().values()) {
  495            command.setPosixClusteredShortOptionsAllowed(newValue);
  496        }
  497        return this;
  498    }
  499
  500    /** Returns whether the parser should ignore case when converting arguments to {@code enum} values. The default is {@code false}.
  501     * @return {@code true} if enum values can be specified that don't match the {@code toString()} value of the enum constant, {@code false} otherwise;
  502     * e.g., for an option of type <a href="https://docs.oracle.com/javase/8/docs/api/java/time/DayOfWeek.html">java.time.DayOfWeek</a>,
  503     * values {@code MonDaY}, {@code monday} and {@code MONDAY} are all recognized if {@code true}.
  504     * @since 3.4 */
  505    public boolean isCaseInsensitiveEnumValuesAllowed() { return getCommandSpec().parser().caseInsensitiveEnumValuesAllowed(); }
  506
  507    /** Sets whether the parser should ignore case when converting arguments to {@code enum} values. The default is {@code false}.
  508     * When set to true, for example, for an option of type <a href="https://docs.oracle.com/javase/8/docs/api/java/time/DayOfWeek.html">java.time.DayOfWeek</a>,
  509     * values {@code MonDaY}, {@code monday} and {@code MONDAY} are all recognized if {@code true}.
  510     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  511     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  512     * later will have the default setting. To ensure a setting is applied to all
  513     * subcommands, call the setter last, after adding subcommands.</p>
  514     * @param newValue the new setting
  515     * @return this {@code CommandLine} object, to allow method chaining
  516     * @since 3.4
  517     */
  518    public CommandLine setCaseInsensitiveEnumValuesAllowed(boolean newValue) {
  519        getCommandSpec().parser().caseInsensitiveEnumValuesAllowed(newValue);
  520        for (CommandLine command : getCommandSpec().subcommands().values()) {
  521            command.setCaseInsensitiveEnumValuesAllowed(newValue);
  522        }
  523        return this;
  524    }
  525
  526    /** Returns whether the parser should trim quotes from command line arguments before processing them. The default is
  527     * read from the system property "picocli.trimQuotes" and will be {@code true} if the property is present and empty,
  528     * or if its value is "true".
  529     * @return {@code true} if the parser should trim quotes from command line arguments before processing them, {@code false} otherwise;
  530     * @since 3.7 */
  531    public boolean isTrimQuotes() { return getCommandSpec().parser().trimQuotes(); }
  532
  533    /** Sets whether the parser should trim quotes from command line arguments before processing them. The default is
  534     * read from the system property "picocli.trimQuotes" and will be {@code true} if the property is set and empty, or
  535     * if its value is "true".
  536     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  537     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  538     * later will have the default setting. To ensure a setting is applied to all
  539     * subcommands, call the setter last, after adding subcommands.</p>
  540     * <p>Calling this method will cause the "picocli.trimQuotes" property to have no effect.</p>
  541     * @param newValue the new setting
  542     * @return this {@code CommandLine} object, to allow method chaining
  543     * @since 3.7
  544     */
  545    public CommandLine setTrimQuotes(boolean newValue) {
  546        getCommandSpec().parser().trimQuotes(newValue);
  547        for (CommandLine command : getCommandSpec().subcommands().values()) {
  548            command.setTrimQuotes(newValue);
  549        }
  550        return this;
  551    }
  552
  553    /** Returns whether the parser is allowed to split quoted Strings or not. The default is {@code false},
  554     * so quoted strings are treated as a single value that cannot be split.
  555     * @return {@code true} if the parser is allowed to split quoted Strings, {@code false} otherwise;
  556     * @see ArgSpec#splitRegex()
  557     * @since 3.7 */
  558    public boolean isSplitQuotedStrings() { return getCommandSpec().parser().splitQuotedStrings(); }
  559
  560    /** Sets whether the parser is allowed to split quoted Strings. The default is {@code false}.
  561     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  562     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  563     * later will have the default setting. To ensure a setting is applied to all
  564     * subcommands, call the setter last, after adding subcommands.</p>
  565     * @param newValue the new setting
  566     * @return this {@code CommandLine} object, to allow method chaining
  567     * @see ArgSpec#splitRegex()
  568     * @since 3.7
  569     */
  570    public CommandLine setSplitQuotedStrings(boolean newValue) {
  571        getCommandSpec().parser().splitQuotedStrings(newValue);
  572        for (CommandLine command : getCommandSpec().subcommands().values()) {
  573            command.setSplitQuotedStrings(newValue);
  574        }
  575        return this;
  576    }
  577
  578    /** Returns the end-of-options delimiter that signals that the remaining command line arguments should be treated as positional parameters.
  579     * @return the end-of-options delimiter. The default is {@code "--"}.
  580     * @since 3.5 */
  581    public String getEndOfOptionsDelimiter() { return getCommandSpec().parser().endOfOptionsDelimiter(); }
  582
  583    /** Sets the end-of-options delimiter that signals that the remaining command line arguments should be treated as positional parameters.
  584     * @param delimiter the end-of-options delimiter; must not be {@code null}. The default is {@code "--"}.
  585     * @return this {@code CommandLine} object, to allow method chaining
  586     * @since 3.5 */
  587    public CommandLine setEndOfOptionsDelimiter(String delimiter) {
  588        getCommandSpec().parser().endOfOptionsDelimiter(delimiter);
  589        for (CommandLine command : getCommandSpec().subcommands().values()) {
  590            command.setEndOfOptionsDelimiter(delimiter);
  591        }
  592        return this;
  593    }
  594
  595    /** Returns the default value provider for the command, or {@code null} if none has been set.
  596     * @return the default value provider for this command, or {@code null}
  597     * @since 3.6
  598     * @see Command#defaultValueProvider()
  599     * @see CommandSpec#defaultValueProvider()
  600     * @see ArgSpec#defaultValueString()
  601     */
  602    public IDefaultValueProvider getDefaultValueProvider() {
  603        return getCommandSpec().defaultValueProvider();
  604    }
  605
  606    /** Sets a default value provider for the command and sub-commands
  607     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  608     * sub-commands and nested sub-subcommands <em>at the moment this method is called</em>. Sub-commands added
  609     * later will have the default setting. To ensure a setting is applied to all
  610     * sub-commands, call the setter last, after adding sub-commands.</p>
  611     * @param newValue the default value provider to use
  612     * @return this {@code CommandLine} object, to allow method chaining
  613     * @since 3.6
  614     */
  615    public CommandLine setDefaultValueProvider(IDefaultValueProvider newValue) {
  616        getCommandSpec().defaultValueProvider(newValue);
  617        for (CommandLine command : getCommandSpec().subcommands().values()) {
  618            command.setDefaultValueProvider(newValue);
  619        }
  620        return this;
  621    }
  622
  623    /** Returns whether the parser interprets the first positional parameter as "end of options" so the remaining
  624     * arguments are all treated as positional parameters. The default is {@code false}.
  625     * @return {@code true} if all values following the first positional parameter should be treated as positional parameters, {@code false} otherwise
  626     * @since 2.3
  627     */
  628    public boolean isStopAtPositional() {
  629        return getCommandSpec().parser().stopAtPositional();
  630    }
  631
  632    /** Sets whether the parser interprets the first positional parameter as "end of options" so the remaining
  633     * arguments are all treated as positional parameters. The default is {@code false}.
  634     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  635     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  636     * later will have the default setting. To ensure a setting is applied to all
  637     * subcommands, call the setter last, after adding subcommands.</p>
  638     * @param newValue {@code true} if all values following the first positional parameter should be treated as positional parameters, {@code false} otherwise
  639     * @return this {@code CommandLine} object, to allow method chaining
  640     * @since 2.3
  641     */
  642    public CommandLine setStopAtPositional(boolean newValue) {
  643        getCommandSpec().parser().stopAtPositional(newValue);
  644        for (CommandLine command : getCommandSpec().subcommands().values()) {
  645            command.setStopAtPositional(newValue);
  646        }
  647        return this;
  648    }
  649
  650    /** Returns whether the parser should stop interpreting options and positional parameters as soon as it encounters an
  651     * unmatched option. Unmatched options are arguments that look like an option but are not one of the known options, or
  652     * positional arguments for which there is no available slots (the command has no positional parameters or their size is limited).
  653     * The default is {@code false}.
  654     * <p>Setting this flag to {@code true} automatically sets the {@linkplain #isUnmatchedArgumentsAllowed() unmatchedArgumentsAllowed} flag to {@code true} also.</p>
  655     * @return {@code true} when an unmatched option should result in the remaining command line arguments to be added to the
  656     *      {@linkplain #getUnmatchedArguments() unmatchedArguments list}
  657     * @since 2.3
  658     */
  659    public boolean isStopAtUnmatched() {
  660        return getCommandSpec().parser().stopAtUnmatched();
  661    }
  662
  663    /** Sets whether the parser should stop interpreting options and positional parameters as soon as it encounters an
  664     * unmatched option. Unmatched options are arguments that look like an option but are not one of the known options, or
  665     * positional arguments for which there is no available slots (the command has no positional parameters or their size is limited).
  666     * The default is {@code false}.
  667     * <p>Setting this flag to {@code true} automatically sets the {@linkplain #setUnmatchedArgumentsAllowed(boolean) unmatchedArgumentsAllowed} flag to {@code true} also.</p>
  668     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  669     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  670     * later will have the default setting. To ensure a setting is applied to all
  671     * subcommands, call the setter last, after adding subcommands.</p>
  672     * @param newValue {@code true} when an unmatched option should result in the remaining command line arguments to be added to the
  673     *      {@linkplain #getUnmatchedArguments() unmatchedArguments list}
  674     * @return this {@code CommandLine} object, to allow method chaining
  675     * @since 2.3
  676     */
  677    public CommandLine setStopAtUnmatched(boolean newValue) {
  678        getCommandSpec().parser().stopAtUnmatched(newValue);
  679        for (CommandLine command : getCommandSpec().subcommands().values()) {
  680            command.setStopAtUnmatched(newValue);
  681        }
  682        if (newValue) { setUnmatchedArgumentsAllowed(true); }
  683        return this;
  684    }
  685
  686    /** Returns whether arguments on the command line that resemble an option should be treated as positional parameters.
  687     * The default is {@code false} and the parser behaviour depends on {@link #isUnmatchedArgumentsAllowed()}.
  688     * @return {@code true} arguments on the command line that resemble an option should be treated as positional parameters, {@code false} otherwise
  689     * @see #getUnmatchedArguments()
  690     * @since 3.0
  691     */
  692    public boolean isUnmatchedOptionsArePositionalParams() {
  693        return getCommandSpec().parser().unmatchedOptionsArePositionalParams();
  694    }
  695
  696    /** Sets whether arguments on the command line that resemble an option should be treated as positional parameters.
  697     * The default is {@code false}.
  698     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  699     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  700     * later will have the default setting. To ensure a setting is applied to all
  701     * subcommands, call the setter last, after adding subcommands.</p>
  702     * @param newValue the new setting. When {@code true}, arguments on the command line that resemble an option should be treated as positional parameters.
  703     * @return this {@code CommandLine} object, to allow method chaining
  704     * @since 3.0
  705     * @see #getUnmatchedArguments()
  706     * @see #isUnmatchedArgumentsAllowed
  707     */
  708    public CommandLine setUnmatchedOptionsArePositionalParams(boolean newValue) {
  709        getCommandSpec().parser().unmatchedOptionsArePositionalParams(newValue);
  710        for (CommandLine command : getCommandSpec().subcommands().values()) {
  711            command.setUnmatchedOptionsArePositionalParams(newValue);
  712        }
  713        return this;
  714    }
  715
  716    /** Returns whether the end user may specify arguments on the command line that are not matched to any option or parameter fields.
  717     * The default is {@code false} and a {@link UnmatchedArgumentException} is thrown if this happens.
  718     * When {@code true}, the last unmatched arguments are available via the {@link #getUnmatchedArguments()} method.
  719     * @return {@code true} if the end use may specify unmatched arguments on the command line, {@code false} otherwise
  720     * @see #getUnmatchedArguments()
  721     * @since 0.9.7
  722     */
  723    public boolean isUnmatchedArgumentsAllowed() {
  724        return getCommandSpec().parser().unmatchedArgumentsAllowed();
  725    }
  726
  727    /** Sets whether the end user may specify unmatched arguments on the command line without a {@link UnmatchedArgumentException} being thrown.
  728     * The default is {@code false}.
  729     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
  730     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
  731     * later will have the default setting. To ensure a setting is applied to all
  732     * subcommands, call the setter last, after adding subcommands.</p>
  733     * @param newValue the new setting. When {@code true}, the last unmatched arguments are available via the {@link #getUnmatchedArguments()} method.
  734     * @return this {@code CommandLine} object, to allow method chaining
  735     * @since 0.9.7
  736     * @see #getUnmatchedArguments()
  737     */
  738    public CommandLine setUnmatchedArgumentsAllowed(boolean newValue) {
  739        getCommandSpec().parser().unmatchedArgumentsAllowed(newValue);
  740        for (CommandLine command : getCommandSpec().subcommands().values()) {
  741            command.setUnmatchedArgumentsAllowed(newValue);
  742        }
  743        return this;
  744    }
  745
  746    /** Returns the list of unmatched command line arguments, if any.
  747     * @return the list of unmatched command line arguments or an empty list
  748     * @see #isUnmatchedArgumentsAllowed()
  749     * @since 0.9.7
  750     */
  751    public List<String> getUnmatchedArguments() {
  752        return interpreter.parseResultBuilder == null ? Collections.<String>emptyList() : UnmatchedArgumentException.stripErrorMessage(interpreter.parseResultBuilder.unmatched);
  753    }
  754
  755    /**
  756     * <p>
  757     * Convenience method that initializes the specified annotated object from the specified command line arguments.
  758     * </p><p>
  759     * This is equivalent to
  760     * </p><pre>
  761     * CommandLine cli = new CommandLine(command);
  762     * cli.parse(args);
  763     * return command;
  764     * </pre>
  765     *
  766     * @param command the object to initialize. This object contains fields annotated with
  767     *          {@code @Option} or {@code @Parameters}.
  768     * @param args the command line arguments to parse
  769     * @param <T> the type of the annotated object
  770     * @return the specified annotated object
  771     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
  772     * @throws ParameterException if the specified command line arguments are invalid
  773     * @since 0.9.7
  774     */
  775    public static <T> T populateCommand(T command, String... args) {
  776        CommandLine cli = toCommandLine(command, new DefaultFactory());
  777        cli.parse(args);
  778        return command;
  779    }
  780
  781    /**
  782     * <p>
  783     * Convenience method that derives the command specification from the specified interface class, and returns an
  784     * instance of the specified interface. The interface is expected to have annotated getter methods. Picocli will
  785     * instantiate the interface and the getter methods will return the option and positional parameter values matched on the command line.
  786     * </p><p>
  787     * This is equivalent to
  788     * </p><pre>
  789     * CommandLine cli = new CommandLine(spec);
  790     * cli.parse(args);
  791     * return cli.getCommand();
  792     * </pre>
  793     *
  794     * @param spec the interface that defines the command specification. This object contains getter methods annotated with
  795     *          {@code @Option} or {@code @Parameters}.
  796     * @param args the command line arguments to parse
  797     * @param <T> the type of the annotated object
  798     * @return an instance of the specified annotated interface
  799     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
  800     * @throws ParameterException if the specified command line arguments are invalid
  801     * @since 3.1
  802     */
  803    public static <T> T populateSpec(Class<T> spec, String... args) {
  804        CommandLine cli = toCommandLine(spec, new DefaultFactory());
  805        cli.parse(args);
  806        return cli.getCommand();
  807    }
  808
  809    /** Parses the specified command line arguments and returns a list of {@code CommandLine} objects representing the
  810     * top-level command and any subcommands (if any) that were recognized and initialized during the parsing process.
  811     * <p>
  812     * If parsing succeeds, the first element in the returned list is always {@code this CommandLine} object. The
  813     * returned list may contain more elements if subcommands were {@linkplain #addSubcommand(String, Object) registered}
  814     * and these subcommands were initialized by matching command line arguments. If parsing fails, a
  815     * {@link ParameterException} is thrown.
  816     * </p>
  817     *
  818     * @param args the command line arguments to parse
  819     * @return a list with the top-level command and any subcommands initialized by this method
  820     * @throws ParameterException if the specified command line arguments are invalid; use
  821     *      {@link ParameterException#getCommandLine()} to get the command or subcommand whose user input was invalid
  822     */
  823    public List<CommandLine> parse(String... args) {
  824        return interpreter.parse(args);
  825    }
  826    /** Parses the specified command line arguments and returns a list of {@code ParseResult} with the options, positional
  827     * parameters, and subcommands (if any) that were recognized and initialized during the parsing process.
  828     * <p>If parsing fails, a {@link ParameterException} is thrown.</p>
  829     *
  830     * @param args the command line arguments to parse
  831     * @return a list with the top-level command and any subcommands initialized by this method
  832     * @throws ParameterException if the specified command line arguments are invalid; use
  833     *      {@link ParameterException#getCommandLine()} to get the command or subcommand whose user input was invalid
  834     */
  835    public ParseResult parseArgs(String... args) {
  836        interpreter.parse(args);
  837        return getParseResult();
  838    }
  839    public ParseResult getParseResult() { return interpreter.parseResultBuilder == null ? null : interpreter.parseResultBuilder.build(); }
  840    /**
  841     * Represents a function that can process a List of {@code CommandLine} objects resulting from successfully
  842     * {@linkplain #parse(String...) parsing} the command line arguments. This is a
  843     * <a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html">functional interface</a>
  844     * whose functional method is {@link #handleParseResult(List, PrintStream, CommandLine.Help.Ansi)}.
  845     * <p>
  846     * Implementations of this functions can be passed to the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) CommandLine::parseWithHandler}
  847     * methods to take some next step after the command line was successfully parsed.
  848     * </p>
  849     * @see RunFirst
  850     * @see RunLast
  851     * @see RunAll
  852     * @deprecated Use {@link IParseResultHandler2} instead.
  853     * @since 2.0 */
  854    @Deprecated public static interface IParseResultHandler {
  855        /** Processes a List of {@code CommandLine} objects resulting from successfully
  856         * {@linkplain #parse(String...) parsing} the command line arguments and optionally returns a list of results.
  857         * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
  858         * @param out the {@code PrintStream} to print help to if requested
  859         * @param ansi for printing help messages using ANSI styles and colors
  860         * @return a list of results, or an empty list if there are no results
  861         * @throws ParameterException if a help command was invoked for an unknown subcommand. Any {@code ParameterExceptions}
  862         *      thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler}
  863         * @throws ExecutionException if a problem occurred while processing the parse results; use
  864         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
  865         */
  866        List<Object> handleParseResult(List<CommandLine> parsedCommands, PrintStream out, Help.Ansi ansi) throws ExecutionException;
  867    }
  868
  869    /**
  870     * Represents a function that can process the {@code ParseResult} object resulting from successfully
  871     * {@linkplain #parseArgs(String...) parsing} the command line arguments. This is a
  872     * <a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html">functional interface</a>
  873     * whose functional method is {@link IParseResultHandler2#handleParseResult(CommandLine.ParseResult)}.
  874     * <p>
  875     * Implementations of this function can be passed to the {@link #parseWithHandlers(IParseResultHandler2,  IExceptionHandler2, String...) CommandLine::parseWithHandlers}
  876     * methods to take some next step after the command line was successfully parsed.
  877     * </p><p>
  878     * This interface replaces the {@link IParseResultHandler} interface; it takes the parse result as a {@code ParseResult}
  879     * object instead of a List of {@code CommandLine} objects, and it has the freedom to select the {@link Help.Ansi} style
  880     * to use and what {@code PrintStreams} to print to.
  881     * </p>
  882     * @param <R> the return type of this handler
  883     * @see RunFirst
  884     * @see RunLast
  885     * @see RunAll
  886     * @since 3.0 */
  887    public static interface IParseResultHandler2<R> {
  888        /** Processes the {@code ParseResult} object resulting from successfully
  889         * {@linkplain CommandLine#parseArgs(String...) parsing} the command line arguments and returns a return value.
  890         * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments
  891         * @throws ParameterException if a help command was invoked for an unknown subcommand. Any {@code ParameterExceptions}
  892         *      thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler2}
  893         * @throws ExecutionException if a problem occurred while processing the parse results; use
  894         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
  895         */
  896        R handleParseResult(ParseResult parseResult) throws ExecutionException;
  897    }
  898    /**
  899     * Represents a function that can handle a {@code ParameterException} that occurred while
  900     * {@linkplain #parse(String...) parsing} the command line arguments. This is a
  901     * <a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html">functional interface</a>
  902     * whose functional method is {@link #handleException(CommandLine.ParameterException, PrintStream, CommandLine.Help.Ansi, String...)}.
  903     * <p>
  904     * Implementations of this function can be passed to the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) CommandLine::parseWithHandlers}
  905     * methods to handle situations when the command line could not be parsed.
  906     * </p>
  907     * @deprecated Use {@link IExceptionHandler2} instead.
  908     * @see DefaultExceptionHandler
  909     * @since 2.0 */
  910    @Deprecated public static interface IExceptionHandler {
  911        /** Handles a {@code ParameterException} that occurred while {@linkplain #parse(String...) parsing} the command
  912         * line arguments and optionally returns a list of results.
  913         * @param ex the ParameterException describing the problem that occurred while parsing the command line arguments,
  914         *           and the CommandLine representing the command or subcommand whose input was invalid
  915         * @param out the {@code PrintStream} to print help to if requested
  916         * @param ansi for printing help messages using ANSI styles and colors
  917         * @param args the command line arguments that could not be parsed
  918         * @return a list of results, or an empty list if there are no results
  919         */
  920        List<Object> handleException(ParameterException ex, PrintStream out, Help.Ansi ansi, String... args);
  921    }
  922    /**
  923     * Classes implementing this interface know how to handle {@code ParameterExceptions} (usually from invalid user input)
  924     * and {@code ExecutionExceptions} that occurred while executing the {@code Runnable} or {@code Callable} command.
  925     * <p>
  926     * Implementations of this interface can be passed to the
  927     * {@link #parseWithHandlers(IParseResultHandler2,  IExceptionHandler2, String...) CommandLine::parseWithHandlers} method.
  928     * </p><p>
  929     * This interface replaces the {@link IParseResultHandler} interface.
  930     * </p>
  931     * @param <R> the return type of this handler
  932     * @see DefaultExceptionHandler
  933     * @since 3.0 */
  934    public static interface IExceptionHandler2<R> {
  935        /** Handles a {@code ParameterException} that occurred while {@linkplain #parseArgs(String...) parsing} the command
  936         * line arguments and optionally returns a list of results.
  937         * @param ex the ParameterException describing the problem that occurred while parsing the command line arguments,
  938         *           and the CommandLine representing the command or subcommand whose input was invalid
  939         * @param args the command line arguments that could not be parsed
  940         * @return an object resulting from handling the exception
  941         */
  942        R handleParseException(ParameterException ex, String[] args);
  943        /** Handles a {@code ExecutionException} that occurred while executing the {@code Runnable} or
  944         * {@code Callable} command and optionally returns a list of results.
  945         * @param ex the ExecutionException describing the problem that occurred while executing the {@code Runnable} or
  946         *          {@code Callable} command, and the CommandLine representing the command or subcommand that was being executed
  947         * @param parseResult the result of parsing the command line arguments
  948         * @return an object resulting from handling the exception
  949         */
  950        R handleExecutionException(ExecutionException ex, ParseResult parseResult);
  951    }
  952
  953    /** Abstract superclass for {@link IParseResultHandler2} and {@link IExceptionHandler2} implementations.
  954     * <p>Note that {@code AbstractHandler} is a generic type. This, along with the abstract {@code self} method,
  955     * allows method chaining to work properly in subclasses, without the need for casts. An example subclass can look like this:</p>
  956     * <pre>{@code
  957     * class MyResultHandler extends AbstractHandler<MyReturnType, MyResultHandler> implements IParseResultHandler2<MyReturnType> {
  958     *
  959     *     public MyReturnType handleParseResult(ParseResult parseResult) { ... }
  960     *
  961     *     protected MyResultHandler self() { return this; }
  962     * }
  963     * }</pre>
  964     * @param <R> the return type of this handler
  965     * @param <T> The type of the handler subclass; for fluent API method chaining
  966     * @since 3.0 */
  967    public static abstract class AbstractHandler<R, T extends AbstractHandler<R, T>> {
  968        private Help.Ansi ansi = Help.Ansi.AUTO;
  969        private Integer exitCode;
  970        private PrintStream out = System.out;
  971        private PrintStream err = System.err;
  972
  973        /** Returns the stream to print command output to. Defaults to {@code System.out}, unless {@link #useOut(PrintStream)}
  974         * was called with a different stream.
  975         * <p>{@code IParseResultHandler2} implementations should use this stream.
  976         * By <a href="http://www.gnu.org/prep/standards/html_node/_002d_002dhelp.html">convention</a>, when the user requests
  977         * help with a {@code --help} or similar option, the usage help message is printed to the standard output stream so that it can be easily searched and paged.</p> */
  978        public PrintStream out()     { return out; }
  979        /** Returns the stream to print diagnostic messages to. Defaults to {@code System.err}, unless {@link #useErr(PrintStream)}
  980         * was called with a different stream. <p>{@code IExceptionHandler2} implementations should use this stream to print error
  981         * messages (which may include a usage help message) when an unexpected error occurs.</p> */
  982        public PrintStream err()     { return err; }
  983        /** Returns the ANSI style to use. Defaults to {@code Help.Ansi.AUTO}, unless {@link #useAnsi(CommandLine.Help.Ansi)} was called with a different setting. */
  984        public Help.Ansi ansi()      { return ansi; }
  985        /** Returns the exit code to use as the termination status, or {@code null} (the default) if the handler should
  986         * not call {@link System#exit(int)} after processing completes.
  987         * @see #andExit(int) */
  988        public Integer exitCode()    { return exitCode; }
  989        /** Returns {@code true} if an exit code was set with {@link #andExit(int)}, or {@code false} (the default) if
  990         * the handler should not call {@link System#exit(int)} after processing completes. */
  991        public boolean hasExitCode() { return exitCode != null; }
  992
  993        /** Convenience method for subclasses that returns the specified result object if no exit code was set,
  994         * or otherwise, if an exit code {@linkplain #andExit(int) was set}, calls {@code System.exit} with the configured
  995         * exit code to terminate the currently running Java virtual machine. */
  996        protected R returnResultOrExit(R result) {
  997            if (hasExitCode()) { exit(exitCode()); }
  998            return result;
  999        }
 1000
 1001        /** Convenience method for subclasses that throws the specified ExecutionException if no exit code was set,
 1002         * or otherwise, if an exit code {@linkplain #andExit(int) was set}, prints the stacktrace of the specified exception
 1003         * to the diagnostic error stream and calls {@code System.exit} with the configured
 1004         * exit code to terminate the currently running Java virtual machine. */
 1005        protected R throwOrExit(ExecutionException ex) {
 1006            if (hasExitCode()) {
 1007                ex.printStackTrace(this.err());
 1008                exit(exitCode());
 1009            }
 1010            throw ex;
 1011        }
 1012        /** Calls {@code System.exit(int)} with the specified exit code. */
 1013        protected void exit(int exitCode) { System.exit(exitCode); }
 1014
 1015        /** Returns {@code this} to allow method chaining when calling the setters for a fluent API. */
 1016        protected abstract T self();
 1017
 1018        /** Sets the stream to print command output to. For use by {@code IParseResultHandler2} implementations.
 1019         * @see #out() */
 1020        public T useOut(PrintStream out)   { this.out =  Assert.notNull(out, "out");   return self(); }
 1021        /** Sets the stream to print diagnostic messages to. For use by {@code IExceptionHandler2} implementations.
 1022         * @see #err()*/
 1023        public T useErr(PrintStream err)   { this.err =  Assert.notNull(err, "err");   return self(); }
 1024        /** Sets the ANSI style to use.
 1025         * @see #ansi() */
 1026        public T useAnsi(Help.Ansi ansi)   { this.ansi = Assert.notNull(ansi, "ansi"); return self(); }
 1027        /** Indicates that the handler should call {@link System#exit(int)} after processing completes and sets the exit code to use as the termination status. */
 1028        public T andExit(int exitCode)     { this.exitCode = exitCode; return self(); }
 1029    }
 1030
 1031    /**
 1032     * Default exception handler that handles invalid user input by printing the exception message, followed by the usage
 1033     * message for the command or subcommand whose input was invalid.
 1034     * <p>{@code ParameterExceptions} (invalid user input) is handled like this:</p>
 1035     * <pre>
 1036     *     err().println(paramException.getMessage());
 1037     *     paramException.getCommandLine().usage(err(), ansi());
 1038     *     if (hasExitCode()) System.exit(exitCode()); else return returnValue;
 1039     * </pre>
 1040     * <p>{@code ExecutionExceptions} that occurred while executing the {@code Runnable} or {@code Callable} command are simply rethrown and not handled.</p>
 1041     * @since 2.0 */
 1042    @SuppressWarnings("deprecation")
 1043    public static class DefaultExceptionHandler<R> extends AbstractHandler<R, DefaultExceptionHandler<R>> implements IExceptionHandler, IExceptionHandler2<R> {
 1044        public List<Object> handleException(ParameterException ex, PrintStream out, Help.Ansi ansi, String... args) {
 1045            internalHandleParseException(ex, out, ansi, args); return Collections.<Object>emptyList(); }
 1046
 1047        /** Prints the message of the specified exception, followed by the usage message for the command or subcommand
 1048         * whose input was invalid, to the stream returned by {@link #err()}.
 1049         * @param ex the ParameterException describing the problem that occurred while parsing the command line arguments,
 1050         *           and the CommandLine representing the command or subcommand whose input was invalid
 1051         * @param args the command line arguments that could not be parsed
 1052         * @return the empty list
 1053         * @since 3.0 */
 1054        public R handleParseException(ParameterException ex, String[] args) {
 1055            internalHandleParseException(ex, err(), ansi(), args); return returnResultOrExit(null); }
 1056
 1057        private void internalHandleParseException(ParameterException ex, PrintStream out, Help.Ansi ansi, String[] args) {
 1058            out.println(ex.getMessage());
 1059            if (!UnmatchedArgumentException.printSuggestions(ex, out)) {
 1060                ex.getCommandLine().usage(out, ansi);
 1061            }
 1062        }
 1063        /** This implementation always simply rethrows the specified exception.
 1064         * @param ex the ExecutionException describing the problem that occurred while executing the {@code Runnable} or {@code Callable} command
 1065         * @param parseResult the result of parsing the command line arguments
 1066         * @return nothing: this method always rethrows the specified exception
 1067         * @throws ExecutionException always rethrows the specified exception
 1068         * @since 3.0 */
 1069        public R handleExecutionException(ExecutionException ex, ParseResult parseResult) { return throwOrExit(ex); }
 1070
 1071        @Override protected DefaultExceptionHandler<R> self() { return this; }
 1072    }
 1073    /** Convenience method that returns {@code new DefaultExceptionHandler<List<Object>>()}. */
 1074    public static DefaultExceptionHandler<List<Object>> defaultExceptionHandler() { return new DefaultExceptionHandler<List<Object>>(); }
 1075
 1076    /** @deprecated use {@link #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi)} instead
 1077     * @since 2.0 */
 1078    @Deprecated public static boolean printHelpIfRequested(List<CommandLine> parsedCommands, PrintStream out, Help.Ansi ansi) {
 1079        return printHelpIfRequested(parsedCommands, out, out, ansi);
 1080    }
 1081
 1082    /** Delegates to {@link #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi)} with
 1083     * {@code parseResult.asCommandLineList(), System.out, System.err, Help.Ansi.AUTO}.
 1084     * @since 3.0 */
 1085    public static boolean printHelpIfRequested(ParseResult parseResult) {
 1086        return printHelpIfRequested(parseResult.asCommandLineList(), System.out, System.err, Help.Ansi.AUTO);
 1087    }
 1088    /**
 1089     * Helper method that may be useful when processing the list of {@code CommandLine} objects that result from successfully
 1090     * {@linkplain #parse(String...) parsing} command line arguments. This method prints out
 1091     * {@linkplain #usage(PrintStream, Help.Ansi) usage help} if {@linkplain #isUsageHelpRequested() requested}
 1092     * or {@linkplain #printVersionHelp(PrintStream, Help.Ansi) version help} if {@linkplain #isVersionHelpRequested() requested}
 1093     * and returns {@code true}. If the command is a {@link Command#helpCommand()} and {@code runnable} or {@code callable},
 1094     * that command is executed and this method returns {@code true}.
 1095     * Otherwise, if none of the specified {@code CommandLine} objects have help requested,
 1096     * this method returns {@code false}.<p>
 1097     * Note that this method <em>only</em> looks at the {@link Option#usageHelp() usageHelp} and
 1098     * {@link Option#versionHelp() versionHelp} attributes. The {@link Option#help() help} attribute is ignored.
 1099     * </p><p><b>Implementation note:</b></p><p>
 1100     * When an error occurs while processing the help request, it is recommended custom Help commands throw a
 1101     * {@link ParameterException} with a reference to the parent command. This will print the error message and the
 1102     * usage for the parent command, and will use the exit code of the exception handler if one was set.
 1103     * </p>
 1104     * @param parsedCommands the list of {@code CommandLine} objects to check if help was requested
 1105     * @param out the {@code PrintStream} to print help to if requested
 1106     * @param err the error string to print diagnostic messages to, in addition to the output from the exception handler
 1107     * @param ansi for printing help messages using ANSI styles and colors
 1108     * @return {@code true} if help was printed, {@code false} otherwise
 1109     * @see IHelpCommandInitializable
 1110     * @since 3.0 */
 1111    public static boolean printHelpIfRequested(List<CommandLine> parsedCommands, PrintStream out, PrintStream err, Help.Ansi ansi) {
 1112        return printHelpIfRequested(parsedCommands, out, err, Help.defaultColorScheme(ansi));
 1113    }
 1114    /**
 1115     * Helper method that may be useful when processing the list of {@code CommandLine} objects that result from successfully
 1116     * {@linkplain #parse(String...) parsing} command line arguments. This method prints out
 1117     * {@linkplain #usage(PrintStream, Help.ColorScheme) usage help} if {@linkplain #isUsageHelpRequested() requested}
 1118     * or {@linkplain #printVersionHelp(PrintStream, Help.Ansi) version help} if {@linkplain #isVersionHelpRequested() requested}
 1119     * and returns {@code true}. If the command is a {@link Command#helpCommand()} and {@code runnable} or {@code callable},
 1120     * that command is executed and this method returns {@code true}.
 1121     * Otherwise, if none of the specified {@code CommandLine} objects have help requested,
 1122     * this method returns {@code false}.<p>
 1123     * Note that this method <em>only</em> looks at the {@link Option#usageHelp() usageHelp} and
 1124     * {@link Option#versionHelp() versionHelp} attributes. The {@link Option#help() help} attribute is ignored.
 1125     * </p><p><b>Implementation note:</b></p><p>
 1126     * When an error occurs while processing the help request, it is recommended custom Help commands throw a
 1127     * {@link ParameterException} with a reference to the parent command. This will print the error message and the
 1128     * usage for the parent command, and will use the exit code of the exception handler if one was set.
 1129     * </p>
 1130     * @param parsedCommands the list of {@code CommandLine} objects to check if help was requested
 1131     * @param out the {@code PrintStream} to print help to if requested
 1132     * @param err the error string to print diagnostic messages to, in addition to the output from the exception handler
 1133     * @param colorScheme for printing help messages using ANSI styles and colors
 1134     * @return {@code true} if help was printed, {@code false} otherwise
 1135     * @see IHelpCommandInitializable
 1136     * @since 3.6 */
 1137    public static boolean printHelpIfRequested(List<CommandLine> parsedCommands, PrintStream out, PrintStream err, Help.ColorScheme colorScheme) {
 1138        for (int i = 0; i < parsedCommands.size(); i++) {
 1139            CommandLine parsed = parsedCommands.get(i);
 1140            if (parsed.isUsageHelpRequested()) {
 1141                parsed.usage(out, colorScheme);
 1142                return true;
 1143            } else if (parsed.isVersionHelpRequested()) {
 1144                parsed.printVersionHelp(out, colorScheme.ansi);
 1145                return true;
 1146            } else if (parsed.getCommandSpec().helpCommand()) {
 1147                if (parsed.getCommand() instanceof IHelpCommandInitializable) {
 1148                    ((IHelpCommandInitializable) parsed.getCommand()).init(parsed, colorScheme.ansi, out, err);
 1149                }
 1150                execute(parsed, new ArrayList<Object>());
 1151                return true;
 1152            }
 1153        }
 1154        return false;
 1155    }
 1156    private static List<Object> execute(CommandLine parsed, List<Object> executionResult) {
 1157        Object command = parsed.getCommand();
 1158        if (command instanceof Runnable) {
 1159            try {
 1160                ((Runnable) command).run();
 1161                executionResult.add(null); // for compatibility with picocli 2.x
 1162                return executionResult;
 1163            } catch (ParameterException ex) {
 1164                throw ex;
 1165            } catch (ExecutionException ex) {
 1166                throw ex;
 1167            } catch (Exception ex) {
 1168                throw new ExecutionException(parsed, "Error while running command (" + command + "): " + ex, ex);
 1169            }
 1170        } else if (command instanceof Callable) {
 1171            try {
 1172                @SuppressWarnings("unchecked") Callable<Object> callable = (Callable<Object>) command;
 1173                executionResult.add(callable.call());
 1174                return executionResult;
 1175            } catch (ParameterException ex) {
 1176                throw ex;
 1177            } catch (ExecutionException ex) {
 1178                throw ex;
 1179            } catch (Exception ex) {
 1180                throw new ExecutionException(parsed, "Error while calling command (" + command + "): " + ex, ex);
 1181            }
 1182        } else if (command instanceof Method) {
 1183            try {
 1184                if (Modifier.isStatic(((Method) command).getModifiers())) {
 1185                    // invoke static method
 1186                    executionResult.add(((Method) command).invoke(null, parsed.getCommandSpec().argValues()));
 1187                    return executionResult;
 1188                } else if (parsed.getCommandSpec().parent() != null) {
 1189                    executionResult.add(((Method) command).invoke(parsed.getCommandSpec().parent().userObject(), parsed.getCommandSpec().argValues()));
 1190                    return executionResult;
 1191                } else {
 1192                    for (Constructor<?> constructor : ((Method) command).getDeclaringClass().getDeclaredConstructors()) {
 1193                        if (constructor.getParameterTypes().length == 0) {
 1194                            executionResult.add(((Method) command).invoke(constructor.newInstance(), parsed.getCommandSpec().argValues()));
 1195                            return executionResult;
 1196                        }
 1197                    }
 1198                    throw new UnsupportedOperationException("Invoking non-static method without default constructor not implemented");
 1199                }
 1200            } catch (InvocationTargetException ex) {
 1201                Throwable t = ex.getTargetException();
 1202                if (t instanceof ParameterException) {
 1203                    throw (ParameterException) t;
 1204                } else if (t instanceof ExecutionException) {
 1205                    throw (ExecutionException) t;
 1206                } else {
 1207                    throw new ExecutionException(parsed, "Error while calling command (" + command + "): " + t, t);
 1208                }
 1209            } catch (Exception ex) {
 1210                throw new ExecutionException(parsed, "Unhandled error while calling command (" + command + "): " + ex, ex);
 1211            }
 1212        }
 1213        throw new ExecutionException(parsed, "Parsed command (" + command + ") is not Method, Runnable or Callable");
 1214    }
 1215    /** Command line parse result handler that returns a value. This handler prints help if requested, and otherwise calls
 1216     * {@link #handle(CommandLine.ParseResult)} with the parse result. Facilitates implementation of the {@link IParseResultHandler2} interface.
 1217     * <p>Note that {@code AbstractParseResultHandler} is a generic type. This, along with the abstract {@code self} method,
 1218     * allows method chaining to work properly in subclasses, without the need for casts. An example subclass can look like this:</p>
 1219     * <pre>{@code
 1220     * class MyResultHandler extends AbstractParseResultHandler<MyReturnType> {
 1221     *
 1222     *     protected MyReturnType handle(ParseResult parseResult) throws ExecutionException { ... }
 1223     *
 1224     *     protected MyResultHandler self() { return this; }
 1225     * }
 1226     * }</pre>
 1227     * @since 3.0 */
 1228    public abstract static class AbstractParseResultHandler<R> extends AbstractHandler<R, AbstractParseResultHandler<R>> implements IParseResultHandler2<R> {
 1229        /** Prints help if requested, and otherwise calls {@link #handle(CommandLine.ParseResult)}.
 1230         * Finally, either a list of result objects is returned, or the JVM is terminated if an exit code {@linkplain #andExit(int) was set}.
 1231         *
 1232         * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments
 1233         * @return the result of {@link #handle(ParseResult) processing parse results}
 1234         * @throws ParameterException if the {@link HelpCommand HelpCommand} was invoked for an unknown subcommand. Any {@code ParameterExceptions}
 1235         *      thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler2}
 1236         * @throws ExecutionException if a problem occurred while processing the parse results; client code can use
 1237         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1238         */
 1239        public R handleParseResult(ParseResult parseResult) throws ExecutionException {
 1240            if (printHelpIfRequested(parseResult.asCommandLineList(), out(), err(), ansi())) {
 1241                return returnResultOrExit(null);
 1242            }
 1243            return returnResultOrExit(handle(parseResult));
 1244        }
 1245
 1246        /** Processes the specified {@code ParseResult} and returns the result as a list of objects.
 1247         * Implementations are responsible for catching any exceptions thrown in the {@code handle} method, and
 1248         * rethrowing an {@code ExecutionException} that details the problem and captures the offending {@code CommandLine} object.
 1249         *
 1250         * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments
 1251         * @return the result of processing parse results
 1252         * @throws ExecutionException if a problem occurred while processing the parse results; client code can use
 1253         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1254         */
 1255        protected abstract R handle(ParseResult parseResult) throws ExecutionException;
 1256    }
 1257    /**
 1258     * Command line parse result handler that prints help if requested, and otherwise executes the top-level
 1259     * {@code Runnable} or {@code Callable} command.
 1260     * For use in the {@link #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...) parseWithHandler} methods.
 1261     * @since 2.0 */
 1262    public static class RunFirst extends AbstractParseResultHandler<List<Object>> implements IParseResultHandler {
 1263        /** Prints help if requested, and otherwise executes the top-level {@code Runnable} or {@code Callable} command.
 1264         * Finally, either a list of result objects is returned, or the JVM is terminated if an exit code {@linkplain #andExit(int) was set}.
 1265         * If the top-level command does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException}
 1266         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
 1267         *
 1268         * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
 1269         * @param out the {@code PrintStream} to print help to if requested
 1270         * @param ansi for printing help messages using ANSI styles and colors
 1271         * @return an empty list if help was requested, or a list containing a single element: the result of calling the
 1272         *      {@code Callable}, or a {@code null} element if the top-level command was a {@code Runnable}
 1273         * @throws ParameterException if the {@link HelpCommand HelpCommand} was invoked for an unknown subcommand. Any {@code ParameterExceptions}
 1274         *      thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler}
 1275         * @throws ExecutionException if a problem occurred while processing the parse results; use
 1276         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1277         */
 1278        public List<Object> handleParseResult(List<CommandLine> parsedCommands, PrintStream out, Help.Ansi ansi) {
 1279            if (printHelpIfRequested(parsedCommands, out, err(), ansi)) { return returnResultOrExit(Collections.emptyList()); }
 1280            return returnResultOrExit(execute(parsedCommands.get(0), new ArrayList<Object>()));
 1281        }
 1282        /** Executes the top-level {@code Runnable} or {@code Callable} subcommand.
 1283         * If the top-level command does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException}
 1284         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
 1285         *
 1286         * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments
 1287         * @return an empty list if help was requested, or a list containing a single element: the result of calling the
 1288         *      {@code Callable}, or a {@code null} element if the last (sub)command was a {@code Runnable}
 1289         * @throws ExecutionException if a problem occurred while processing the parse results; use
 1290         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1291         * @since 3.0 */
 1292        protected List<Object> handle(ParseResult parseResult) throws ExecutionException {
 1293            return execute(parseResult.commandSpec().commandLine(), new ArrayList<Object>()); // first
 1294        }
 1295        @Override protected RunFirst self() { return this; }
 1296    }
 1297    /**
 1298     * Command line parse result handler that prints help if requested, and otherwise executes the most specific
 1299     * {@code Runnable} or {@code Callable} subcommand.
 1300     * For use in the {@link #parseWithHandlers(IParseResultHandler2,  IExceptionHandler2, String...) parseWithHandler} methods.
 1301     * <p>
 1302     * Something like this:</p>
 1303     * <pre>{@code
 1304     *     // RunLast implementation: print help if requested, otherwise execute the most specific subcommand
 1305     *     List<CommandLine> parsedCommands = parseResult.asCommandLineList();
 1306     *     if (CommandLine.printHelpIfRequested(parsedCommands, out(), err(), ansi())) {
 1307     *         return emptyList();
 1308     *     }
 1309     *     CommandLine last = parsedCommands.get(parsedCommands.size() - 1);
 1310     *     Object command = last.getCommand();
 1311     *     Object result = null;
 1312     *     if (command instanceof Runnable) {
 1313     *         try {
 1314     *             ((Runnable) command).run();
 1315     *         } catch (Exception ex) {
 1316     *             throw new ExecutionException(last, "Error in runnable " + command, ex);
 1317     *         }
 1318     *     } else if (command instanceof Callable) {
 1319     *         try {
 1320     *             result = ((Callable) command).call();
 1321     *         } catch (Exception ex) {
 1322     *             throw new ExecutionException(last, "Error in callable " + command, ex);
 1323     *         }
 1324     *     } else {
 1325     *         throw new ExecutionException(last, "Parsed command (" + command + ") is not Runnable or Callable");
 1326     *     }
 1327     *     if (hasExitCode()) { System.exit(exitCode()); }
 1328     *     return Arrays.asList(result);
 1329     * }</pre>
 1330     * <p>
 1331     * From picocli v2.0, {@code RunLast} is used to implement the {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...) run}
 1332     * and {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...) call} convenience methods.
 1333     * </p>
 1334     * @since 2.0 */
 1335    public static class RunLast extends AbstractParseResultHandler<List<Object>> implements IParseResultHandler {
 1336        /** Prints help if requested, and otherwise executes the most specific {@code Runnable} or {@code Callable} subcommand.
 1337         * Finally, either a list of result objects is returned, or the JVM is terminated if an exit code {@linkplain #andExit(int) was set}.
 1338         * If the last (sub)command does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException}
 1339         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
 1340         *
 1341         * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
 1342         * @param out the {@code PrintStream} to print help to if requested
 1343         * @param ansi for printing help messages using ANSI styles and colors
 1344         * @return an empty list if help was requested, or a list containing a single element: the result of calling the
 1345         *      {@code Callable}, or a {@code null} element if the last (sub)command was a {@code Runnable}
 1346         * @throws ParameterException if the {@link HelpCommand HelpCommand} was invoked for an unknown subcommand. Any {@code ParameterExceptions}
 1347         *      thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler}
 1348         * @throws ExecutionException if a problem occurred while processing the parse results; use
 1349         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1350         */
 1351        public List<Object> handleParseResult(List<CommandLine> parsedCommands, PrintStream out, Help.Ansi ansi) {
 1352            if (printHelpIfRequested(parsedCommands, out, err(), ansi)) { return returnResultOrExit(Collections.emptyList()); }
 1353            return returnResultOrExit(execute(parsedCommands.get(parsedCommands.size() - 1), new ArrayList<Object>()));
 1354        }
 1355        /** Executes the most specific {@code Runnable} or {@code Callable} subcommand.
 1356         * If the last (sub)command does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException}
 1357         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
 1358         *
 1359         * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments
 1360         * @return an empty list if help was requested, or a list containing a single element: the result of calling the
 1361         *      {@code Callable}, or a {@code null} element if the last (sub)command was a {@code Runnable}
 1362         * @throws ExecutionException if a problem occurred while processing the parse results; use
 1363         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1364         * @since 3.0 */
 1365        protected List<Object> handle(ParseResult parseResult) throws ExecutionException {
 1366            List<CommandLine> parsedCommands = parseResult.asCommandLineList();
 1367            return execute(parsedCommands.get(parsedCommands.size() - 1), new ArrayList<Object>());
 1368        }
 1369        @Override protected RunLast self() { return this; }
 1370    }
 1371    /**
 1372     * Command line parse result handler that prints help if requested, and otherwise executes the top-level command and
 1373     * all subcommands as {@code Runnable} or {@code Callable}.
 1374     * For use in the {@link #parseWithHandlers(IParseResultHandler2,  IExceptionHandler2, String...) parseWithHandler} methods.
 1375     * @since 2.0 */
 1376    public static class RunAll extends AbstractParseResultHandler<List<Object>> implements IParseResultHandler {
 1377        /** Prints help if requested, and otherwise executes the top-level command and all subcommands as {@code Runnable}
 1378         * or {@code Callable}. Finally, either a list of result objects is returned, or the JVM is terminated if an exit
 1379         * code {@linkplain #andExit(int) was set}. If any of the {@code CommandLine} commands does not implement either
 1380         * {@code Runnable} or {@code Callable}, an {@code ExecutionException}
 1381         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
 1382         *
 1383         * @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
 1384         * @param out the {@code PrintStream} to print help to if requested
 1385         * @param ansi for printing help messages using ANSI styles and colors
 1386         * @return an empty list if help was requested, or a list containing the result of executing all commands:
 1387         *      the return values from calling the {@code Callable} commands, {@code null} elements for commands that implement {@code Runnable}
 1388         * @throws ParameterException if the {@link HelpCommand HelpCommand} was invoked for an unknown subcommand. Any {@code ParameterExceptions}
 1389         *      thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler}
 1390         * @throws ExecutionException if a problem occurred while processing the parse results; use
 1391         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1392         */
 1393        public List<Object> handleParseResult(List<CommandLine> parsedCommands, PrintStream out, Help.Ansi ansi) {
 1394            if (printHelpIfRequested(parsedCommands, out, err(), ansi)) { return returnResultOrExit(Collections.emptyList()); }
 1395            List<Object> result = new ArrayList<Object>();
 1396            for (CommandLine parsed : parsedCommands) {
 1397                execute(parsed, result);
 1398            }
 1399            return returnResultOrExit(result);
 1400        }
 1401        /** Executes the top-level command and all subcommands as {@code Runnable} or {@code Callable}.
 1402         * If any of the {@code CommandLine} commands does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException}
 1403         * is thrown detailing the problem and capturing the offending {@code CommandLine} object.
 1404         *
 1405         * @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments
 1406         * @return an empty list if help was requested, or a list containing the result of executing all commands:
 1407         *      the return values from calling the {@code Callable} commands, {@code null} elements for commands that implement {@code Runnable}
 1408         * @throws ExecutionException if a problem occurred while processing the parse results; use
 1409         *      {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1410         * @since 3.0 */
 1411        protected List<Object> handle(ParseResult parseResult) throws ExecutionException {
 1412            List<Object> result = new ArrayList<Object>();
 1413            execute(parseResult.commandSpec().commandLine(), result);
 1414            while (parseResult.hasSubcommand()) {
 1415                parseResult = parseResult.subcommand();
 1416                execute(parseResult.commandSpec().commandLine(), result);
 1417            }
 1418            return returnResultOrExit(result);
 1419        }
 1420        @Override protected RunAll self() { return this; }
 1421    }
 1422
 1423    /** @deprecated use {@link #parseWithHandler(IParseResultHandler2,  String[])} instead
 1424     * @since 2.0 */
 1425    @Deprecated public List<Object> parseWithHandler(IParseResultHandler handler, PrintStream out, String... args) {
 1426        return parseWithHandlers(handler, out, Help.Ansi.AUTO, defaultExceptionHandler(), args);
 1427    }
 1428    /**
 1429     * Returns the result of calling {@link #parseWithHandlers(IParseResultHandler2,  IExceptionHandler2, String...)} with
 1430     * a new {@link DefaultExceptionHandler} in addition to the specified parse result handler and the specified command line arguments.
 1431     * <p>
 1432     * This is a convenience method intended to offer the same ease of use as the {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...) run}
 1433     * and {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...) call} methods, but with more flexibility and better
 1434     * support for nested subcommands.
 1435     * </p>
 1436     * <p>Calling this method roughly expands to:</p>
 1437     * <pre>{@code
 1438     * try {
 1439     *     ParseResult parseResult = parseArgs(args);
 1440     *     return handler.handleParseResult(parseResult);
 1441     * } catch (ParameterException ex) {
 1442     *     return new DefaultExceptionHandler<R>().handleParseException(ex, args);
 1443     * }
 1444     * }</pre>
 1445     * <p>
 1446     * Picocli provides some default handlers that allow you to accomplish some common tasks with very little code.
 1447     * The following handlers are available:</p>
 1448     * <ul>
 1449     *   <li>{@link RunLast} handler prints help if requested, and otherwise gets the last specified command or subcommand
 1450     * and tries to execute it as a {@code Runnable} or {@code Callable}.</li>
 1451     *   <li>{@link RunFirst} handler prints help if requested, and otherwise executes the top-level command as a {@code Runnable} or {@code Callable}.</li>
 1452     *   <li>{@link RunAll} handler prints help if requested, and otherwise executes all recognized commands and subcommands as {@code Runnable} or {@code Callable} tasks.</li>
 1453     *   <li>{@link DefaultExceptionHandler} prints the error message followed by usage help</li>
 1454     * </ul>
 1455     * @param <R> the return type of this handler
 1456     * @param handler the function that will handle the result of successfully parsing the command line arguments
 1457     * @param args the command line arguments
 1458     * @return an object resulting from handling the parse result or the exception that occurred while parsing the input
 1459     * @throws ExecutionException if the command line arguments were parsed successfully but a problem occurred while processing the
 1460     *      parse results; use {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1461     * @see RunLast
 1462     * @see RunAll
 1463     * @since 3.0 */
 1464    public <R> R parseWithHandler(IParseResultHandler2<R> handler, String[] args) {
 1465        return parseWithHandlers(handler, new DefaultExceptionHandler<R>(), args);
 1466    }
 1467
 1468    /** @deprecated use {@link #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)} instead
 1469     * @since 2.0 */
 1470    @Deprecated public List<Object> parseWithHandlers(IParseResultHandler handler, PrintStream out, Help.Ansi ansi, IExceptionHandler exceptionHandler, String... args) {
 1471        try {
 1472            List<CommandLine> result = parse(args);
 1473            return handler.handleParseResult(result, out, ansi);
 1474        } catch (ParameterException ex) {
 1475            return exceptionHandler.handleException(ex, out, ansi, args);
 1476        }
 1477    }
 1478    /**
 1479     * Tries to {@linkplain #parseArgs(String...) parse} the specified command line arguments, and if successful, delegates
 1480     * the processing of the resulting {@code ParseResult} object to the specified {@linkplain IParseResultHandler2 handler}.
 1481     * If the command line arguments were invalid, the {@code ParameterException} thrown from the {@code parse} method
 1482     * is caught and passed to the specified {@link IExceptionHandler2}.
 1483     * <p>
 1484     * This is a convenience method intended to offer the same ease of use as the {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...) run}
 1485     * and {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...) call} methods, but with more flexibility and better
 1486     * support for nested subcommands.
 1487     * </p>
 1488     * <p>Calling this method roughly expands to:</p>
 1489     * <pre>
 1490     * ParseResult parseResult = null;
 1491     * try {
 1492     *     parseResult = parseArgs(args);
 1493     *     return handler.handleParseResult(parseResult);
 1494     * } catch (ParameterException ex) {
 1495     *     return exceptionHandler.handleParseException(ex, (String[]) args);
 1496     * } catch (ExecutionException ex) {
 1497     *     return exceptionHandler.handleExecutionException(ex, parseResult);
 1498     * }
 1499     * </pre>
 1500     * <p>
 1501     * Picocli provides some default handlers that allow you to accomplish some common tasks with very little code.
 1502     * The following handlers are available:</p>
 1503     * <ul>
 1504     *   <li>{@link RunLast} handler prints help if requested, and otherwise gets the last specified command or subcommand
 1505     * and tries to execute it as a {@code Runnable} or {@code Callable}.</li>
 1506     *   <li>{@link RunFirst} handler prints help if requested, and otherwise executes the top-level command as a {@code Runnable} or {@code Callable}.</li>
 1507     *   <li>{@link RunAll} handler prints help if requested, and otherwise executes all recognized commands and subcommands as {@code Runnable} or {@code Callable} tasks.</li>
 1508     *   <li>{@link DefaultExceptionHandler} prints the error message followed by usage help</li>
 1509     * </ul>
 1510     *
 1511     * @param handler the function that will handle the result of successfully parsing the command line arguments
 1512     * @param exceptionHandler the function that can handle the {@code ParameterException} thrown when the command line arguments are invalid
 1513     * @param args the command line arguments
 1514     * @return an object resulting from handling the parse result or the exception that occurred while parsing the input
 1515     * @throws ExecutionException if the command line arguments were parsed successfully but a problem occurred while processing the parse
 1516     *      result {@code ParseResult} object; use {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
 1517     * @param <R> the return type of the result handler and exception handler
 1518     * @see RunLast
 1519     * @see RunAll
 1520     * @see DefaultExceptionHandler
 1521     * @since 3.0 */
 1522    public <R> R parseWithHandlers(IParseResultHandler2<R> handler, IExceptionHandler2<R> exceptionHandler, String... args) {
 1523        ParseResult parseResult = null;
 1524        try {
 1525            parseResult = parseArgs(args);
 1526            return handler.handleParseResult(parseResult);
 1527        } catch (ParameterException ex) {
 1528            return exceptionHandler.handleParseException(ex, args);
 1529        } catch (ExecutionException ex) {
 1530            return exceptionHandler.handleExecutionException(ex, parseResult);
 1531        }
 1532    }
 1533    static String versionString() {
 1534        return String.format("%s, JVM: %s (%s %s %s), OS: %s %s %s", VERSION,
 1535                System.getProperty("java.version"), System.getProperty("java.vendor"), System.getProperty("java.vm.name"), System.getProperty("java.vm.version"),
 1536                System.getProperty("os.name"), System.getProperty("os.version"), System.getProperty("os.arch"));
 1537    }
 1538    /**
 1539     * Equivalent to {@code new CommandLine(command).usage(out)}. See {@link #usage(PrintStream)} for details.
 1540     * @param command the object annotated with {@link Command}, {@link Option} and {@link Parameters}
 1541     * @param out the print stream to print the help message to
 1542     * @throws IllegalArgumentException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1543     */
 1544    public static void usage(Object command, PrintStream out) {
 1545        toCommandLine(command, new DefaultFactory()).usage(out);
 1546    }
 1547
 1548    /**
 1549     * Equivalent to {@code new CommandLine(command).usage(out, ansi)}.
 1550     * See {@link #usage(PrintStream, Help.Ansi)} for details.
 1551     * @param command the object annotated with {@link Command}, {@link Option} and {@link Parameters}
 1552     * @param out the print stream to print the help message to
 1553     * @param ansi whether the usage message should contain ANSI escape codes or not
 1554     * @throws IllegalArgumentException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1555     */
 1556    public static void usage(Object command, PrintStream out, Help.Ansi ansi) {
 1557        toCommandLine(command, new DefaultFactory()).usage(out, ansi);
 1558    }
 1559
 1560    /**
 1561     * Equivalent to {@code new CommandLine(command).usage(out, colorScheme)}.
 1562     * See {@link #usage(PrintStream, Help.ColorScheme)} for details.
 1563     * @param command the object annotated with {@link Command}, {@link Option} and {@link Parameters}
 1564     * @param out the print stream to print the help message to
 1565     * @param colorScheme the {@code ColorScheme} defining the styles for options, parameters and commands when ANSI is enabled
 1566     * @throws IllegalArgumentException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1567     */
 1568    public static void usage(Object command, PrintStream out, Help.ColorScheme colorScheme) {
 1569        toCommandLine(command, new DefaultFactory()).usage(out, colorScheme);
 1570    }
 1571
 1572    /**
 1573     * Delegates to {@link #usage(PrintStream, Help.Ansi)} with the {@linkplain Help.Ansi#AUTO platform default}.
 1574     * @param out the printStream to print to
 1575     * @see #usage(PrintStream, Help.ColorScheme)
 1576     */
 1577    public void usage(PrintStream out) { usage(out, Help.Ansi.AUTO); }
 1578    /**
 1579     * Delegates to {@link #usage(PrintWriter, Help.Ansi)} with the {@linkplain Help.Ansi#AUTO platform default}.
 1580     * @param writer the PrintWriter to print to
 1581     * @see #usage(PrintWriter, Help.ColorScheme)
 1582     * @since 3.0 */
 1583    public void usage(PrintWriter writer) { usage(writer, Help.Ansi.AUTO); }
 1584
 1585    /**
 1586     * Delegates to {@link #usage(PrintStream, Help.ColorScheme)} with the {@linkplain Help#defaultColorScheme(CommandLine.Help.Ansi) default color scheme}.
 1587     * @param out the printStream to print to
 1588     * @param ansi whether the usage message should include ANSI escape codes or not
 1589     * @see #usage(PrintStream, Help.ColorScheme)
 1590     */
 1591    public void usage(PrintStream out, Help.Ansi ansi) { usage(out, Help.defaultColorScheme(ansi)); }
 1592    /** Similar to {@link #usage(PrintStream, Help.Ansi)} but with the specified {@code PrintWriter} instead of a {@code PrintStream}.
 1593     * @since 3.0 */
 1594    public void usage(PrintWriter writer, Help.Ansi ansi) { usage(writer, Help.defaultColorScheme(ansi)); }
 1595
 1596    /**
 1597     * Prints a usage help message for the annotated command class to the specified {@code PrintStream}.
 1598     * Delegates construction of the usage help message to the {@link Help} inner class and is equivalent to:
 1599     * <pre>
 1600     * Help.ColorScheme colorScheme = Help.defaultColorScheme(Help.Ansi.AUTO);
 1601     * Help help = getHelpFactory().create(getCommandSpec(), colorScheme)
 1602     * StringBuilder sb = new StringBuilder();
 1603     * for (String key : getHelpSectionKeys()) {
 1604     *     IHelpSectionRenderer renderer = getHelpSectionMap().get(key);
 1605     *     if (renderer != null) { sb.append(renderer.render(help)); }
 1606     * }
 1607     * out.print(sb);
 1608     * </pre>
 1609     * <p>Annotate your class with {@link Command} to control many aspects of the usage help message, including
 1610     * the program name, text of section headings and section contents, and some aspects of the auto-generated sections
 1611     * of the usage help message.
 1612     * <p>To customize the auto-generated sections of the usage help message, like how option details are displayed,
 1613     * instantiate a {@link Help} object and use a {@link Help.TextTable} with more of fewer columns, a custom
 1614     * {@linkplain Help.Layout layout}, and/or a custom option {@linkplain Help.IOptionRenderer renderer}
 1615     * for ultimate control over which aspects of an Option or Field are displayed where.</p>
 1616     * @param out the {@code PrintStream} to print the usage help message to
 1617     * @param colorScheme the {@code ColorScheme} defining the styles for options, parameters and commands when ANSI is enabled
 1618     * @see UsageMessageSpec
 1619     */
 1620    public void usage(PrintStream out, Help.ColorScheme colorScheme) {
 1621        out.print(usage(new StringBuilder(), getHelpFactory().create(getCommandSpec(), colorScheme)));
 1622    }
 1623    /** Similar to {@link #usage(PrintStream, Help.ColorScheme)}, but with the specified {@code PrintWriter} instead of a {@code PrintStream}.
 1624     * @since 3.0 */
 1625    public void usage(PrintWriter writer, Help.ColorScheme colorScheme) {
 1626        writer.print(usage(new StringBuilder(), getHelpFactory().create(getCommandSpec(), colorScheme)));
 1627    }
 1628    /** Similar to {@link #usage(PrintStream)}, but returns the usage help message as a String instead of printing it to the {@code PrintStream}.
 1629     * @since 3.2 */
 1630    public String getUsageMessage() {
 1631        return usage(new StringBuilder(), getHelpFactory().create(getCommandSpec(), Help.defaultColorScheme(Help.Ansi.AUTO))).toString();
 1632    }
 1633    /** Similar to {@link #usage(PrintStream, Help.Ansi)}, but returns the usage help message as a String instead of printing it to the {@code PrintStream}.
 1634     * @since 3.2 */
 1635    public String getUsageMessage(Help.Ansi ansi) {
 1636        return usage(new StringBuilder(), getHelpFactory().create(getCommandSpec(), Help.defaultColorScheme(ansi))).toString();
 1637    }
 1638    /** Similar to {@link #usage(PrintStream, Help.ColorScheme)}, but returns the usage help message as a String instead of printing it to the {@code PrintStream}.
 1639     * @since 3.2 */
 1640    public String getUsageMessage(Help.ColorScheme colorScheme) {
 1641        return usage(new StringBuilder(), getHelpFactory().create(getCommandSpec(), colorScheme)).toString();
 1642    }
 1643
 1644    private StringBuilder usage(StringBuilder sb, Help help) {
 1645        for (String key : getHelpSectionKeys()) {
 1646            IHelpSectionRenderer renderer = getHelpSectionMap().get(key);
 1647            if (renderer != null) { sb.append(renderer.render(help)); }
 1648        }
 1649        return sb;
 1650    }
 1651
 1652    /**
 1653     * Delegates to {@link #printVersionHelp(PrintStream, Help.Ansi)} with the {@linkplain Help.Ansi#AUTO platform default}.
 1654     * @param out the printStream to print to
 1655     * @see #printVersionHelp(PrintStream, Help.Ansi)
 1656     * @since 0.9.8
 1657     */
 1658    public void printVersionHelp(PrintStream out) { printVersionHelp(out, Help.Ansi.AUTO); }
 1659
 1660    /**
 1661     * Prints version information from the {@link Command#version()} annotation to the specified {@code PrintStream}.
 1662     * Each element of the array of version strings is printed on a separate line. Version strings may contain
 1663     * <a href="http://picocli.info/#_usage_help_with_styles_and_colors">markup for colors and style</a>.
 1664     * @param out the printStream to print to
 1665     * @param ansi whether the usage message should include ANSI escape codes or not
 1666     * @see Command#version()
 1667     * @see Option#versionHelp()
 1668     * @see #isVersionHelpRequested()
 1669     * @since 0.9.8
 1670     */
 1671    public void printVersionHelp(PrintStream out, Help.Ansi ansi) {
 1672        for (String versionInfo : getCommandSpec().version()) {
 1673            out.println(ansi.new Text(versionInfo));
 1674        }
 1675    }
 1676    /**
 1677     * Prints version information from the {@link Command#version()} annotation to the specified {@code PrintStream}.
 1678     * Each element of the array of version strings is {@linkplain String#format(String, Object...) formatted} with the
 1679     * specified parameters, and printed on a separate line. Both version strings and parameters may contain
 1680     * <a href="http://picocli.info/#_usage_help_with_styles_and_colors">markup for colors and style</a>.
 1681     * @param out the printStream to print to
 1682     * @param ansi whether the usage message should include ANSI escape codes or not
 1683     * @param params Arguments referenced by the format specifiers in the version strings
 1684     * @see Command#version()
 1685     * @see Option#versionHelp()
 1686     * @see #isVersionHelpRequested()
 1687     * @since 1.0.0
 1688     */
 1689    public void printVersionHelp(PrintStream out, Help.Ansi ansi, Object... params) {
 1690        for (String versionInfo : getCommandSpec().version()) {
 1691            out.println(ansi.new Text(format(versionInfo, params)));
 1692        }
 1693    }
 1694
 1695    /**
 1696     * Delegates to {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.out} for
 1697     * requested usage help messages, {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}.
 1698     * @param callable the command to call when {@linkplain #parseArgs(String...) parsing} succeeds.
 1699     * @param args the command line arguments to parse
 1700     * @param <C> the annotated object must implement Callable
 1701     * @param <T> the return type of the most specific command (must implement {@code Callable})
 1702     * @see #call(Callable, PrintStream, PrintStream, Help.Ansi, String...)
 1703     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1704     * @throws ExecutionException if the Callable throws an exception
 1705     * @return {@code null} if an error occurred while parsing the command line options, or if help was requested and printed. Otherwise returns the result of calling the Callable
 1706     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1707     * @since 3.0
 1708     */
 1709    public static <C extends Callable<T>, T> T call(C callable, String... args) {
 1710        return call(callable, System.out, System.err, Help.Ansi.AUTO, args);
 1711    }
 1712
 1713    /**
 1714     * Delegates to {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.err} for
 1715     * diagnostic error messages and {@link Help.Ansi#AUTO}.
 1716     * @param callable the command to call when {@linkplain #parseArgs(String...) parsing} succeeds.
 1717     * @param out the printStream to print the usage help message to when the user requested help
 1718     * @param args the command line arguments to parse
 1719     * @param <C> the annotated object must implement Callable
 1720     * @param <T> the return type of the most specific command (must implement {@code Callable})
 1721     * @see #call(Callable, PrintStream, PrintStream, Help.Ansi, String...)
 1722     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1723     * @throws ExecutionException if the Callable throws an exception
 1724     * @return {@code null} if an error occurred while parsing the command line options, or if help was requested and printed. Otherwise returns the result of calling the Callable
 1725     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1726     * @see RunLast
 1727     */
 1728    public static <C extends Callable<T>, T> T call(C callable, PrintStream out, String... args) {
 1729        return call(callable, out, System.err, Help.Ansi.AUTO, args);
 1730    }
 1731    /**
 1732     * Delegates to {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.err} for diagnostic error messages.
 1733     * @param callable the command to call when {@linkplain #parseArgs(String...) parsing} succeeds.
 1734     * @param out the printStream to print the usage help message to when the user requested help
 1735     * @param ansi the ANSI style to use
 1736     * @param args the command line arguments to parse
 1737     * @param <C> the annotated object must implement Callable
 1738     * @param <T> the return type of the most specific command (must implement {@code Callable})
 1739     * @see #call(Callable, PrintStream, PrintStream, Help.Ansi, String...)
 1740     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1741     * @throws ExecutionException if the Callable throws an exception
 1742     * @return {@code null} if an error occurred while parsing the command line options, or if help was requested and printed. Otherwise returns the result of calling the Callable
 1743     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1744     * @see RunLast
 1745     */
 1746    public static <C extends Callable<T>, T> T call(C callable, PrintStream out, Help.Ansi ansi, String... args) {
 1747        return call(callable, out, System.err, ansi, args);
 1748    }
 1749    /**
 1750     * Convenience method to allow command line application authors to avoid some boilerplate code in their application.
 1751     * The annotated object needs to implement {@link Callable}. Calling this method is equivalent to:
 1752     * <pre>{@code
 1753     * CommandLine cmd = new CommandLine(callable);
 1754     * List<Object> results = cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi),
 1755     *                                              new DefaultExceptionHandler().useErr(err).useAnsi(ansi),
 1756     *                                              args);
 1757     * T result = results == null || results.isEmpty() ? null : (T) results.get(0);
 1758     * return result;
 1759     * }</pre>
 1760     * <p>
 1761     * If the specified Callable command has subcommands, the {@linkplain RunLast last} subcommand specified on the
 1762     * command line is executed.
 1763     * Commands with subcommands may be interested in calling the {@link #parseWithHandler(IParseResultHandler2, String[]) parseWithHandler}
 1764     * method with the {@link RunAll} handler or a custom handler.
 1765     * </p><p>
 1766     * Use {@link #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...) call(Class, IFactory, ...)} instead of this method
 1767     * if you want to use a factory that performs Dependency Injection.
 1768     * </p>
 1769     * @param callable the command to call when {@linkplain #parse(String...) parsing} succeeds.
 1770     * @param out the printStream to print the usage help message to when the user requested help
 1771     * @param err the printStream to print diagnostic messages to
 1772     * @param ansi whether the usage message should include ANSI escape codes or not
 1773     * @param args the command line arguments to parse
 1774     * @param <C> the annotated object must implement Callable
 1775     * @param <T> the return type of the specified {@code Callable}
 1776     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1777     * @throws ExecutionException if the Callable throws an exception
 1778     * @return {@code null} if an error occurred while parsing the command line options, or if help was requested and printed. Otherwise returns the result of calling the Callable
 1779     * @see #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 1780     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1781     * @see RunLast
 1782     * @since 3.0
 1783     */
 1784    public static <C extends Callable<T>, T> T call(C callable, PrintStream out, PrintStream err, Help.Ansi ansi, String... args) {
 1785        CommandLine cmd = new CommandLine(callable);
 1786        List<Object> results = cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi), new DefaultExceptionHandler<List<Object>>().useErr(err).useAnsi(ansi), args);
 1787        @SuppressWarnings("unchecked") T result = (results == null || results.isEmpty()) ? null : (T) results.get(0);
 1788        return result;
 1789    }
 1790    /**
 1791     * Delegates to {@link #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.out} for
 1792     * requested usage help messages, {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}.
 1793     * @param callableClass class of the command to call when {@linkplain #parseArgs(String...) parsing} succeeds.
 1794     * @param factory the factory responsible for instantiating the specified callable class and potentially inject other components
 1795     * @param args the command line arguments to parse
 1796     * @param <C> the annotated class must implement Callable
 1797     * @param <T> the return type of the most specific command (must implement {@code Callable})
 1798     * @see #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 1799     * @throws InitializationException if the specified class cannot be instantiated by the factory, or does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1800     * @throws ExecutionException if the Callable throws an exception
 1801     * @return {@code null} if an error occurred while parsing the command line options, or if help was requested and printed. Otherwise returns the result of calling the Callable
 1802     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1803     * @since 3.2
 1804     */
 1805    public static <C extends Callable<T>, T> T call(Class<C> callableClass, IFactory factory, String... args) {
 1806        return call(callableClass, factory, System.out, System.err, Help.Ansi.AUTO, args);
 1807    }
 1808    /**
 1809     * Delegates to {@link #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)} with
 1810     * {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}.
 1811     * @param callableClass class of the command to call when {@linkplain #parseArgs(String...) parsing} succeeds.
 1812     * @param factory the factory responsible for instantiating the specified callable class and potentially injecting other components
 1813     * @param out the printStream to print the usage help message to when the user requested help
 1814     * @param args the command line arguments to parse
 1815     * @param <C> the annotated class must implement Callable
 1816     * @param <T> the return type of the most specific command (must implement {@code Callable})
 1817     * @see #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 1818     * @throws InitializationException if the specified class cannot be instantiated by the factory, or does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1819     * @throws ExecutionException if the Callable throws an exception
 1820     * @return {@code null} if an error occurred while parsing the command line options, or if help was requested and printed. Otherwise returns the result of calling the Callable
 1821     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1822     * @since 3.2
 1823     */
 1824    public static <C extends Callable<T>, T> T call(Class<C> callableClass, IFactory factory, PrintStream out, String... args) {
 1825        return call(callableClass, factory, out, System.err, Help.Ansi.AUTO, args);
 1826    }
 1827    /**
 1828     * Delegates to {@link #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)} with
 1829     * {@code System.err} for diagnostic error messages.
 1830     * @param callableClass class of the command to call when {@linkplain #parseArgs(String...) parsing} succeeds.
 1831     * @param factory the factory responsible for instantiating the specified callable class and potentially injecting other components
 1832     * @param out the printStream to print the usage help message to when the user requested help
 1833     * @param ansi the ANSI style to use
 1834     * @param args the command line arguments to parse
 1835     * @param <C> the annotated class must implement Callable
 1836     * @param <T> the return type of the most specific command (must implement {@code Callable})
 1837     * @see #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 1838     * @throws InitializationException if the specified class cannot be instantiated by the factory, or does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1839     * @throws ExecutionException if the Callable throws an exception
 1840     * @return {@code null} if an error occurred while parsing the command line options, or if help was requested and printed. Otherwise returns the result of calling the Callable
 1841     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1842     * @since 3.2
 1843     */
 1844    public static <C extends Callable<T>, T> T call(Class<C> callableClass, IFactory factory, PrintStream out, Help.Ansi ansi, String... args) {
 1845        return call(callableClass, factory, out, System.err, ansi, args);
 1846    }
 1847    /**
 1848     * Convenience method to allow command line application authors to avoid some boilerplate code in their application.
 1849     * The specified {@linkplain IFactory factory} will create an instance of the specified {@code callableClass};
 1850     * use this method instead of {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...) call(Callable, ...)}
 1851     * if you want to use a factory that performs Dependency Injection.
 1852     * The annotated class needs to implement {@link Callable}. Calling this method is equivalent to:
 1853     * <pre>{@code
 1854     * CommandLine cmd = new CommandLine(callableClass, factory);
 1855     * List<Object> results = cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi),
 1856     *                                              new DefaultExceptionHandler().useErr(err).useAnsi(ansi),
 1857     *                                              args);
 1858     * T result = results == null || results.isEmpty() ? null : (T) results.get(0);
 1859     * return result;
 1860     * }</pre>
 1861     * <p>
 1862     * If the specified Callable command has subcommands, the {@linkplain RunLast last} subcommand specified on the
 1863     * command line is executed.
 1864     * Commands with subcommands may be interested in calling the {@link #parseWithHandler(IParseResultHandler2, String[]) parseWithHandler}
 1865     * method with the {@link RunAll} handler or a custom handler.
 1866     * </p>
 1867     * @param callableClass class of the command to call when {@linkplain #parseArgs(String...) parsing} succeeds.
 1868     * @param factory the factory responsible for instantiating the specified callable class and potentially injecting other components
 1869     * @param out the printStream to print the usage help message to when the user requested help
 1870     * @param err the printStream to print diagnostic messages to
 1871     * @param ansi the ANSI style to use
 1872     * @param args the command line arguments to parse
 1873     * @param <C> the annotated class must implement Callable
 1874     * @param <T> the return type of the most specific command (must implement {@code Callable})
 1875     * @see #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 1876     * @throws InitializationException if the specified class cannot be instantiated by the factory, or does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1877     * @throws ExecutionException if the Callable throws an exception
 1878     * @return {@code null} if an error occurred while parsing the command line options, or if help was requested and printed. Otherwise returns the result of calling the Callable
 1879     * @see #call(Callable, PrintStream, PrintStream, Help.Ansi, String...)
 1880     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1881     * @since 3.2
 1882     */
 1883    public static <C extends Callable<T>, T> T call(Class<C> callableClass, IFactory factory, PrintStream out, PrintStream err, Help.Ansi ansi, String... args) {
 1884        CommandLine cmd = new CommandLine(callableClass, factory);
 1885        List<Object> results = cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi), new DefaultExceptionHandler<List<Object>>().useErr(err).useAnsi(ansi), args);
 1886        @SuppressWarnings("unchecked") T result = (results == null || results.isEmpty()) ? null : (T) results.get(0);
 1887        return result;
 1888    }
 1889
 1890    /**
 1891     * Delegates to {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.out} for
 1892     * requested usage help messages, {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}.
 1893     * @param runnable the command to run when {@linkplain #parseArgs(String...) parsing} succeeds.
 1894     * @param args the command line arguments to parse
 1895     * @param <R> the annotated object must implement Runnable
 1896     * @see #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...)
 1897     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1898     * @throws ExecutionException if the Runnable throws an exception
 1899     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1900     * @see RunLast
 1901     * @since 3.0
 1902     */
 1903    public static <R extends Runnable> void run(R runnable, String... args) {
 1904        run(runnable, System.out, System.err, Help.Ansi.AUTO, args);
 1905    }
 1906
 1907    /**
 1908     * Delegates to {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.err} for diagnostic error messages and {@link Help.Ansi#AUTO}.
 1909     * @param runnable the command to run when {@linkplain #parseArgs(String...) parsing} succeeds.
 1910     * @param out the printStream to print the usage help message to when the user requested help
 1911     * @param args the command line arguments to parse
 1912     * @param <R> the annotated object must implement Runnable
 1913     * @see #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...)
 1914     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1915     * @throws ExecutionException if the Runnable throws an exception
 1916     * @see #parseWithHandler(IParseResultHandler2, String[])
 1917     * @see RunLast
 1918     */
 1919    public static <R extends Runnable> void run(R runnable, PrintStream out, String... args) {
 1920        run(runnable, out, System.err, Help.Ansi.AUTO, args);
 1921    }
 1922    /**
 1923     * Delegates to {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.err} for diagnostic error messages.
 1924     * @param runnable the command to run when {@linkplain #parseArgs(String...) parsing} succeeds.
 1925     * @param out the printStream to print the usage help message to when the user requested help
 1926     * @param ansi whether the usage message should include ANSI escape codes or not
 1927     * @param args the command line arguments to parse
 1928     * @param <R> the annotated object must implement Runnable
 1929     * @see #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...)
 1930     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1931     * @throws ExecutionException if the Runnable throws an exception
 1932     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1933     * @see RunLast
 1934     */
 1935    public static <R extends Runnable> void run(R runnable, PrintStream out, Help.Ansi ansi, String... args) {
 1936        run(runnable, out, System.err, ansi, args);
 1937    }
 1938    /**
 1939     * Convenience method to allow command line application authors to avoid some boilerplate code in their application.
 1940     * The annotated object needs to implement {@link Runnable}. Calling this method is equivalent to:
 1941     * <pre>{@code
 1942     * CommandLine cmd = new CommandLine(runnable);
 1943     * cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi),
 1944     *                       new DefaultExceptionHandler().useErr(err).useAnsi(ansi),
 1945     *                       args);
 1946     * }</pre>
 1947     * <p>
 1948     * If the specified Runnable command has subcommands, the {@linkplain RunLast last} subcommand specified on the
 1949     * command line is executed.
 1950     * Commands with subcommands may be interested in calling the {@link #parseWithHandler(IParseResultHandler2, String[]) parseWithHandler}
 1951     * method with the {@link RunAll} handler or a custom handler.
 1952     * </p><p>
 1953     * From picocli v2.0, this method prints usage help or version help if {@linkplain #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi) requested},
 1954     * and any exceptions thrown by the {@code Runnable} are caught and rethrown wrapped in an {@code ExecutionException}.
 1955     * </p><p>
 1956     * Use {@link #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...) run(Class, IFactory, ...)} instead of this method
 1957     * if you want to use a factory that performs Dependency Injection.
 1958     * </p>
 1959     * @param runnable the command to run when {@linkplain #parse(String...) parsing} succeeds.
 1960     * @param out the printStream to print the usage help message to when the user requested help
 1961     * @param err the printStream to print diagnostic messages to
 1962     * @param ansi whether the usage message should include ANSI escape codes or not
 1963     * @param args the command line arguments to parse
 1964     * @param <R> the annotated object must implement Runnable
 1965     * @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1966     * @throws ExecutionException if the Runnable throws an exception
 1967     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1968     * @see RunLast
 1969     * @see #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 1970     * @since 3.0
 1971     */
 1972    public static <R extends Runnable> void run(R runnable, PrintStream out, PrintStream err, Help.Ansi ansi, String... args) {
 1973        CommandLine cmd = new CommandLine(runnable);
 1974        cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi), new DefaultExceptionHandler<List<Object>>().useErr(err).useAnsi(ansi), args);
 1975    }
 1976    /**
 1977     * Delegates to {@link #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.out} for
 1978     * requested usage help messages, {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}.
 1979     * @param runnableClass class of the command to run when {@linkplain #parseArgs(String...) parsing} succeeds.
 1980     * @param factory the factory responsible for instantiating the specified Runnable class and potentially injecting other components
 1981     * @param args the command line arguments to parse
 1982     * @param <R> the annotated class must implement Runnable
 1983     * @see #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 1984     * @throws InitializationException if the specified class cannot be instantiated by the factory, or does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 1985     * @throws ExecutionException if the Runnable throws an exception
 1986     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 1987     * @see RunLast
 1988     * @since 3.2
 1989     */
 1990    public static <R extends Runnable> void run(Class<R> runnableClass, IFactory factory, String... args) {
 1991        run(runnableClass, factory, System.out, System.err, Help.Ansi.AUTO, args);
 1992    }
 1993    /**
 1994     * Delegates to {@link #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)} with
 1995     * {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}.
 1996     * @param runnableClass class of the command to run when {@linkplain #parseArgs(String...) parsing} succeeds.
 1997     * @param factory the factory responsible for instantiating the specified Runnable class and potentially injecting other components
 1998     * @param out the printStream to print the usage help message to when the user requested help
 1999     * @param args the command line arguments to parse
 2000     * @param <R> the annotated class must implement Runnable
 2001     * @see #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 2002     * @throws InitializationException if the specified class cannot be instantiated by the factory, or does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 2003     * @throws ExecutionException if the Runnable throws an exception
 2004     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 2005     * @see RunLast
 2006     * @since 3.2
 2007     */
 2008    public static <R extends Runnable> void run(Class<R> runnableClass, IFactory factory, PrintStream out, String... args) {
 2009        run(runnableClass, factory, out, System.err, Help.Ansi.AUTO, args);
 2010    }
 2011    /**
 2012     * Delegates to {@link #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)} with
 2013     * {@code System.err} for diagnostic error messages.
 2014     * @param runnableClass class of the command to run when {@linkplain #parseArgs(String...) parsing} succeeds.
 2015     * @param factory the factory responsible for instantiating the specified Runnable class and potentially injecting other components
 2016     * @param out the printStream to print the usage help message to when the user requested help
 2017     * @param ansi whether the usage message should include ANSI escape codes or not
 2018     * @param args the command line arguments to parse
 2019     * @param <R> the annotated class must implement Runnable
 2020     * @see #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 2021     * @throws InitializationException if the specified class cannot be instantiated by the factory, or does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 2022     * @throws ExecutionException if the Runnable throws an exception
 2023     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 2024     * @see RunLast
 2025     * @since 3.2
 2026     */
 2027    public static <R extends Runnable> void run(Class<R> runnableClass, IFactory factory, PrintStream out, Help.Ansi ansi, String... args) {
 2028        run(runnableClass, factory, out, System.err, ansi, args);
 2029    }
 2030    /**
 2031     * Convenience method to allow command line application authors to avoid some boilerplate code in their application.
 2032     * The specified {@linkplain IFactory factory} will create an instance of the specified {@code runnableClass};
 2033     * use this method instead of {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...) run(Runnable, ...)}
 2034     * if you want to use a factory that performs Dependency Injection.
 2035     * The annotated class needs to implement {@link Runnable}. Calling this method is equivalent to:
 2036     * <pre>{@code
 2037     * CommandLine cmd = new CommandLine(runnableClass, factory);
 2038     * cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi),
 2039     *                       new DefaultExceptionHandler().useErr(err).useAnsi(ansi),
 2040     *                       args);
 2041     * }</pre>
 2042     * <p>
 2043     * If the specified Runnable command has subcommands, the {@linkplain RunLast last} subcommand specified on the
 2044     * command line is executed.
 2045     * Commands with subcommands may be interested in calling the {@link #parseWithHandler(IParseResultHandler2, String[]) parseWithHandler}
 2046     * method with the {@link RunAll} handler or a custom handler.
 2047     * </p><p>
 2048     * This method prints usage help or version help if {@linkplain #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi) requested},
 2049     * and any exceptions thrown by the {@code Runnable} are caught and rethrown wrapped in an {@code ExecutionException}.
 2050     * </p>
 2051     * @param runnableClass class of the command to run when {@linkplain #parseArgs(String...) parsing} succeeds.
 2052     * @param factory the factory responsible for instantiating the specified Runnable class and potentially injecting other components
 2053     * @param out the printStream to print the usage help message to when the user requested help
 2054     * @param err the printStream to print diagnostic messages to
 2055     * @param ansi whether the usage message should include ANSI escape codes or not
 2056     * @param args the command line arguments to parse
 2057     * @param <R> the annotated class must implement Runnable
 2058     * @see #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 2059     * @throws InitializationException if the specified class cannot be instantiated by the factory, or does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
 2060     * @throws ExecutionException if the Runnable throws an exception
 2061     * @see #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...)
 2062     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 2063     * @see RunLast
 2064     * @since 3.2
 2065     */
 2066    public static <R extends Runnable> void run(Class<R> runnableClass, IFactory factory, PrintStream out, PrintStream err, Help.Ansi ansi, String... args) {
 2067        CommandLine cmd = new CommandLine(runnableClass, factory);
 2068        cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi), new DefaultExceptionHandler<List<Object>>().useErr(err).useAnsi(ansi), args);
 2069    }
 2070
 2071    /**
 2072     * Delegates to {@link #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...)} with {@code System.out} for
 2073     * requested usage help messages, {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}.
 2074     * @param methodName the {@code @Command}-annotated method to build a {@link CommandSpec} model from,
 2075     *                   and run when {@linkplain #parseArgs(String...) parsing} succeeds.
 2076     * @param cls the class where the {@code @Command}-annotated method is declared, or a subclass
 2077     * @param args the command line arguments to parse
 2078     * @see #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...)
 2079     * @throws InitializationException if the specified method does not have a {@link Command} annotation,
 2080     *      or if the specified class contains multiple {@code @Command}-annotated methods with the specified name
 2081     * @throws ExecutionException if the Runnable throws an exception
 2082     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 2083     * @since 3.6
 2084     */
 2085    public static Object invoke(String methodName, Class<?> cls, String... args) {
 2086        return invoke(methodName, cls, System.out, System.err, Help.Ansi.AUTO, args);
 2087    }
 2088    /**
 2089     * Delegates to {@link #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...)} with the specified stream for
 2090     * requested usage help messages, {@code System.err} for diagnostic error messages, and {@link Help.Ansi#AUTO}.
 2091     * @param methodName the {@code @Command}-annotated method to build a {@link CommandSpec} model from,
 2092     *                   and run when {@linkplain #parseArgs(String...) parsing} succeeds.
 2093     * @param cls the class where the {@code @Command}-annotated method is declared, or a subclass
 2094     * @param out the printstream to print requested help message to
 2095     * @param args the command line arguments to parse
 2096     * @see #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...)
 2097     * @throws InitializationException if the specified method does not have a {@link Command} annotation,
 2098     *      or if the specified class contains multiple {@code @Command}-annotated methods with the specified name
 2099     * @throws ExecutionException if the Runnable throws an exception
 2100     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 2101     * @since 3.6
 2102     */
 2103    public static Object invoke(String methodName, Class<?> cls, PrintStream out, String... args) {
 2104        return invoke(methodName, cls, out, System.err, Help.Ansi.AUTO, args);
 2105    }
 2106    /**
 2107     * Delegates to {@link #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...)} with the specified stream for
 2108     * requested usage help messages, {@code System.err} for diagnostic error messages, and the specified Ansi mode.
 2109     * @param methodName the {@code @Command}-annotated method to build a {@link CommandSpec} model from,
 2110     *                   and run when {@linkplain #parseArgs(String...) parsing} succeeds.
 2111     * @param cls the class where the {@code @Command}-annotated method is declared, or a subclass
 2112     * @param out the printstream to print requested help message to
 2113     * @param ansi whether the usage message should include ANSI escape codes or not
 2114     * @param args the command line arguments to parse
 2115     * @see #invoke(String, Class, PrintStream, PrintStream, Help.Ansi, String...)
 2116     * @throws InitializationException if the specified method does not have a {@link Command} annotation,
 2117     *      or if the specified class contains multiple {@code @Command}-annotated methods with the specified name
 2118     * @throws ExecutionException if the Runnable throws an exception
 2119     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 2120     * @since 3.6
 2121     */
 2122    public static Object invoke(String methodName, Class<?> cls, PrintStream out, Help.Ansi ansi, String... args) {
 2123        return invoke(methodName, cls, out, System.err, ansi, args);
 2124    }
 2125    /**
 2126     * Convenience method to allow command line application authors to avoid some boilerplate code in their application.
 2127     * Constructs a {@link CommandSpec} model from the {@code @Option} and {@code @Parameters}-annotated method parameters
 2128     * of the {@code @Command}-annotated method, parses the specified command line arguments and invokes the specified method.
 2129     * Calling this method is equivalent to:
 2130     * <pre>{@code
 2131     * Method commandMethod = getCommandMethods(cls, methodName).get(0);
 2132     * CommandLine cmd = new CommandLine(commandMethod);
 2133     * List<Object> list = cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi),
 2134     *                                           new DefaultExceptionHandler().useErr(err).useAnsi(ansi),
 2135     *                                           args);
 2136     * return list == null ? null : list.get(0);
 2137     * }</pre>
 2138     * @param methodName the {@code @Command}-annotated method to build a {@link CommandSpec} model from,
 2139     *                   and run when {@linkplain #parseArgs(String...) parsing} succeeds.
 2140     * @param cls the class where the {@code @Command}-annotated method is declared, or a subclass
 2141     * @param out the printStream to print the usage help message to when the user requested help
 2142     * @param err the printStream to print diagnostic messages to
 2143     * @param ansi whether the usage message should include ANSI escape codes or not
 2144     * @param args the command line arguments to parse
 2145     * @throws InitializationException if the specified method does not have a {@link Command} annotation,
 2146     *      or if the specified class contains multiple {@code @Command}-annotated methods with the specified name
 2147     * @throws ExecutionException if the method throws an exception
 2148     * @see #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...)
 2149     * @since 3.6
 2150     */
 2151    public static Object invoke(String methodName, Class<?> cls, PrintStream out, PrintStream err, Help.Ansi ansi, String... args) {
 2152        List<Method> candidates = getCommandMethods(cls, methodName);
 2153        if (candidates.size() != 1) { throw new InitializationException("Expected exactly one @Command-annotated method for " + cls.getName() + "::" + methodName + "(...), but got: " + candidates); }
 2154        Method method = candidates.get(0);
 2155        CommandLine cmd = new CommandLine(method);
 2156        List<Object> list = cmd.parseWithHandlers(new RunLast().useOut(out).useAnsi(ansi), new DefaultExceptionHandler<List<Object>>().useErr(err).useAnsi(ansi), args);
 2157        return list == null ? null : list.get(0);
 2158    }
 2159
 2160    /**
 2161     * Helper to get methods of a class annotated with {@link Command @Command} via reflection, optionally filtered by method name (not {@link Command#name() @Command.name}).
 2162     * Methods have to be either public (inherited) members or be declared by {@code cls}, that is "inherited" static or protected methods will not be picked up.
 2163     *
 2164     * @param cls the class to search for methods annotated with {@code @Command}
 2165     * @param methodName if not {@code null}, return only methods whose method name (not {@link Command#name() @Command.name}) equals this string. Ignored if {@code null}.
 2166     * @return the matching command methods, or an empty list
 2167     * @see #invoke(String, Class, String...)
 2168     * @since 3.6.0
 2169     */
 2170    public static List<Method> getCommandMethods(Class<?> cls, String methodName) {
 2171        Set<Method> candidates = new HashSet<Method>();
 2172        // traverse public member methods (excludes static/non-public, includes inherited)
 2173        candidates.addAll(Arrays.asList(Assert.notNull(cls, "class").getMethods()));
 2174        // traverse directly declared methods (includes static/non-public, excludes inherited)
 2175        candidates.addAll(Arrays.asList(Assert.notNull(cls, "class").getDeclaredMethods()));
 2176
 2177        List<Method> result = new ArrayList<Method>();
 2178        for (Method method : candidates) {
 2179            if (method.isAnnotationPresent(Command.class)) {
 2180                if (methodName == null || methodName.equals(method.getName())) { result.add(method); }
 2181            }
 2182        }
 2183        Collections.sort(result, new Comparator<Method>() {
 2184            public int compare(Method o1, Method o2) { return o1.getName().compareTo(o2.getName()); }
 2185        });
 2186        return result;
 2187    }
 2188
 2189    /**
 2190     * Registers the specified type converter for the specified class. When initializing fields annotated with
 2191     * {@link Option}, the field's type is used as a lookup key to find the associated type converter, and this
 2192     * type converter converts the original command line argument string value to the correct type.
 2193     * <p>
 2194     * Java 8 lambdas make it easy to register custom type converters:
 2195     * </p>
 2196     * <pre>
 2197     * commandLine.registerConverter(java.nio.file.Path.class, s -&gt; java.nio.file.Paths.get(s));
 2198     * commandLine.registerConverter(java.time.Duration.class, s -&gt; java.time.Duration.parse(s));</pre>
 2199     * <p>
 2200     * Built-in type converters are pre-registered for the following java 1.5 types:
 2201     * </p>
 2202     * <ul>
 2203     *   <li>all primitive types</li>
 2204     *   <li>all primitive wrapper types: Boolean, Byte, Character, Double, Float, Integer, Long, Short</li>
 2205     *   <li>any enum</li>
 2206     *   <li>java.io.File</li>
 2207     *   <li>java.math.BigDecimal</li>
 2208     *   <li>java.math.BigInteger</li>
 2209     *   <li>java.net.InetAddress</li>
 2210     *   <li>java.net.URI</li>
 2211     *   <li>java.net.URL</li>
 2212     *   <li>java.nio.charset.Charset</li>
 2213     *   <li>java.sql.Time</li>
 2214     *   <li>java.util.Date</li>
 2215     *   <li>java.util.UUID</li>
 2216     *   <li>java.util.regex.Pattern</li>
 2217     *   <li>StringBuilder</li>
 2218     *   <li>CharSequence</li>
 2219     *   <li>String</li>
 2220     * </ul>
 2221     * <p>The specified converter will be registered with this {@code CommandLine} and the full hierarchy of its
 2222     * subcommands and nested sub-subcommands <em>at the moment the converter is registered</em>. Subcommands added
 2223     * later will not have this converter added automatically. To ensure a custom type converter is available to all
 2224     * subcommands, register the type converter last, after adding subcommands.</p>
 2225     *
 2226     * @param cls the target class to convert parameter string values to
 2227     * @param converter the class capable of converting string values to the specified target type
 2228     * @param <K> the target type
 2229     * @return this CommandLine object, to allow method chaining
 2230     * @see #addSubcommand(String, Object)
 2231     */
 2232    public <K> CommandLine registerConverter(Class<K> cls, ITypeConverter<K> converter) {
 2233        interpreter.converterRegistry.put(Assert.notNull(cls, "class"), Assert.notNull(converter, "converter"));
 2234        for (CommandLine command : getCommandSpec().commands.values()) {
 2235            command.registerConverter(cls, converter);
 2236        }
 2237        return this;
 2238    }
 2239
 2240    /** Returns the String that separates option names from option values when parsing command line options.
 2241     * @return the String the parser uses to separate option names from option values
 2242     * @see ParserSpec#separator() */
 2243    public String getSeparator() { return getCommandSpec().parser().separator(); }
 2244
 2245    /** Sets the String the parser uses to separate option names from option values to the specified value.
 2246     * The separator may also be set declaratively with the {@link CommandLine.Command#separator()} annotation attribute.
 2247     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
 2248     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
 2249     * later will have the default setting. To ensure a setting is applied to all
 2250     * subcommands, call the setter last, after adding subcommands.</p>
 2251     * @param separator the String that separates option names from option values
 2252     * @see ParserSpec#separator(String)
 2253     * @return this {@code CommandLine} object, to allow method chaining */
 2254    public CommandLine setSeparator(String separator) {
 2255        getCommandSpec().parser().separator(Assert.notNull(separator, "separator"));
 2256        for (CommandLine command : getCommandSpec().subcommands().values()) {
 2257            command.setSeparator(separator);
 2258        }
 2259        return this;
 2260    }
 2261
 2262    /** Returns the ResourceBundle of this command or {@code null} if no resource bundle is set.
 2263     * @see Command#resourceBundle()
 2264     * @see CommandSpec#resourceBundle()
 2265     * @since 3.6 */
 2266    public ResourceBundle getResourceBundle() { return getCommandSpec().resourceBundle(); }
 2267
 2268    /** Sets the ResourceBundle containing usage help message strings.
 2269     * <p>The specified bundle will be registered with this {@code CommandLine} and the full hierarchy of its
 2270     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
 2271     * later will not be impacted. To ensure a setting is applied to all
 2272     * subcommands, call the setter last, after adding subcommands.</p>
 2273     * @param bundle the ResourceBundle containing usage help message strings
 2274     * @return this {@code CommandLine} object, to allow method chaining
 2275     * @see Command#resourceBundle()
 2276     * @see CommandSpec#resourceBundle(ResourceBundle)
 2277     * @since 3.6 */
 2278    public CommandLine setResourceBundle(ResourceBundle bundle) {
 2279        getCommandSpec().resourceBundle(bundle);
 2280        for (CommandLine command : getCommandSpec().subcommands().values()) {
 2281            command.getCommandSpec().resourceBundle(bundle);
 2282        }
 2283        return this;
 2284    }
 2285
 2286    /** Returns the maximum width of the usage help message. The default is 80.
 2287     * @see UsageMessageSpec#width() */
 2288    public int getUsageHelpWidth() { return getCommandSpec().usageMessage().width(); }
 2289
 2290    /** Sets the maximum width of the usage help message. Longer lines are wrapped.
 2291     * <p>The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
 2292     * subcommands and nested sub-subcommands <em>at the moment this method is called</em>. Subcommands added
 2293     * later will have the default setting. To ensure a setting is applied to all
 2294     * subcommands, call the setter last, after adding subcommands.</p>
 2295     * @param width the maximum width of the usage help message
 2296     * @see UsageMessageSpec#width(int)
 2297     * @return this {@code CommandLine} object, to allow method chaining */
 2298    public CommandLine setUsageHelpWidth(int width) {
 2299        getCommandSpec().usageMessage().width(width);
 2300        for (CommandLine command : getCommandSpec().subcommands().values()) {
 2301            command.setUsageHelpWidth(width);
 2302        }
 2303        return this;
 2304    }
 2305
 2306    /** Returns the command name (also called program name) displayed in the usage help synopsis.
 2307     * @return the command name (also called program name) displayed in the usage
 2308     * @see CommandSpec#name()
 2309     * @since 2.0 */
 2310    public String getCommandName() { return getCommandSpec().name(); }
 2311
 2312    /** Sets the command name (also called program name) displayed in the usage help synopsis to the specified value.
 2313     * Note that this method only modifies the usage help message, it does not impact parsing behaviour.
 2314     * The command name may also be set declaratively with the {@link CommandLine.Command#name()} annotation attribute.
 2315     * @param commandName command name (also called program name) displayed in the usage help synopsis
 2316     * @return this {@code CommandLine} object, to allow method chaining
 2317     * @see CommandSpec#name(String)
 2318     * @since 2.0 */
 2319    public CommandLine setCommandName(String commandName) {
 2320        getCommandSpec().name(Assert.notNull(commandName, "commandName"));
 2321        return this;
 2322    }
 2323
 2324    /** Returns whether arguments starting with {@code '@'} should be treated as the path to an argument file and its
 2325     * contents should be expanded into separate arguments for each line in the specified file.
 2326     * This property is {@code true} by default.
 2327     * @return whether "argument files" or {@code @files} should be expanded into their content
 2328     * @since 2.1 */
 2329    public boolean isExpandAtFiles() { return getCommandSpec().parser().expandAtFiles(); }
 2330
 2331    /** Sets whether arguments starting with {@code '@'} should be treated as the path to an argument file and its
 2332     * contents should be expanded into separate arguments for each line in the specified file. ({@code true} by default.)
 2333     * @param expandAtFiles whether "argument files" or {@code @files} should be expanded into their content
 2334     * @return this {@code CommandLine} object, to allow method chaining
 2335     * @since 2.1 */
 2336    public CommandLine setExpandAtFiles(boolean expandAtFiles) {
 2337        getCommandSpec().parser().expandAtFiles(expandAtFiles);
 2338        return this;
 2339    }
 2340
 2341    /** Returns the character that starts a single-line comment or {@code null} if all content of argument files should
 2342     * be interpreted as arguments (without comments).
 2343     * If specified, all characters from the comment character to the end of the line are ignored.
 2344     * @return the character that starts a single-line comment or {@code null}. The default is {@code '#'}.
 2345     * @since 3.5 */
 2346    public Character getAtFileCommentChar() { return getCommandSpec().parser().atFileCommentChar(); }
 2347
 2348    /** Sets the character that starts a single-line comment or {@code null} if all content of argument files should
 2349     * be interpreted as arguments (without comments).
 2350     * If specified, all characters from the comment character to the end of the line are ignored.
 2351     * @param atFileCommentChar the character that starts a single-line comment or {@code null}. The default is {@code '#'}.
 2352     * @return this {@code CommandLine} object, to allow method chaining
 2353     * @since 3.5 */
 2354    public CommandLine setAtFileCommentChar(Character atFileCommentChar) {
 2355        getCommandSpec().parser().atFileCommentChar(atFileCommentChar);
 2356        for (CommandLine command : getCommandSpec().subcommands().values()) {
 2357            command.setAtFileCommentChar(atFileCommentChar);
 2358        }
 2359        return this;
 2360    }
 2361
 2362    /** Returns whether to use a simplified argument file format that is compatible with JCommander.
 2363     * In this format, every line (except empty lines and comment lines)
 2364     * is interpreted as a single argument. Arguments containing whitespace do not need to be quoted.
 2365     * When system property {@code "picocli.useSimplifiedAtFiles"} is defined, the system property value overrides the programmatically set value.
 2366     * @return whether to use a simplified argument file format. The default is {@code false}.
 2367     * @since 3.9 */
 2368    public boolean isUseSimplifiedAtFiles() { return getCommandSpec().parser().useSimplifiedAtFiles(); }
 2369
 2370    /** Sets whether to use a simplified argument file format that is compatible with JCommander.
 2371     * In this format, every line (except empty lines and comment lines)
 2372     * is interpreted as a single argument. Arguments containing whitespace do not need to be quoted.
 2373     * When system property {@code "picocli.useSimplifiedAtFiles"} is defined, the system property value overrides the programmatically set value.
 2374     * @param simplifiedAtFiles whether to use a simplified argument file format. The default is {@code false}.
 2375     * @return this {@code CommandLine} object, to allow method chaining
 2376     * @since 3.9 */
 2377    public CommandLine setUseSimplifiedAtFiles(boolean simplifiedAtFiles) {
 2378        getCommandSpec().parser().useSimplifiedAtFiles(simplifiedAtFiles);
 2379        for (CommandLine command : getCommandSpec().subcommands().values()) {
 2380            command.setUseSimplifiedAtFiles(simplifiedAtFiles);
 2381        }
 2382        return this;
 2383    }
 2384    private static boolean empty(String str) { return str == null || str.trim().length() == 0; }
 2385    private static boolean empty(Object[] array) { return array == null || array.length == 0; }
 2386    private static String str(String[] arr, int i) { return (arr == null || arr.length <= i) ? "" : arr[i]; }
 2387    private static boolean isBoolean(Class<?> type) { return type == Boolean.class || type == Boolean.TYPE; }
 2388    private static CommandLine toCommandLine(Object obj, IFactory factory) { return obj instanceof CommandLine ? (CommandLine) obj : new CommandLine(obj, factory);}
 2389    private static boolean isMultiValue(Class<?> cls) { return cls.isArray() || Collection.class.isAssignableFrom(cls) || Map.class.isAssignableFrom(cls); }
 2390    private static String format(String formatString, Object... params) {
 2391        try {
 2392            return formatString == null ? "" : String.format(formatString, params);
 2393        } catch (IllegalFormatException ex) {
 2394            new Tracer().warn("Could not format '%s' (Underlying error: %s). " +
 2395                    "Using raw String: '%%n' format strings have not been replaced with newlines. " +
 2396                    "Please ensure to escape '%%' characters with another '%%'.%n", formatString, ex.getMessage());
 2397            return formatString;
 2398        }
 2399    }
 2400
 2401    private static class NoCompletionCandidates implements Iterable<String> {
 2402        public Iterator<String> iterator() { throw new UnsupportedOperationException(); }
 2403    }
 2404    /**
 2405     * <p>
 2406     * Annotate fields in your class with {@code @Option} and picocli will initialize these fields when matching
 2407     * arguments are specified on the command line. In the case of command methods (annotated with {@code @Command}),
 2408     * command options can be defined by annotating method parameters with {@code @Option}.
 2409     * </p><p>
 2410     * Command class example:
 2411     * </p>
 2412     * <pre>
 2413     * import static picocli.CommandLine.*;
 2414     *
 2415     * public class MyClass {
 2416     *     &#064;Parameters(description = "Any number of input files")
 2417     *     private List&lt;File&gt; files = new ArrayList&lt;File&gt;();
 2418     *
 2419     *     &#064;Option(names = { "-o", "--out" }, description = "Output file (default: print to console)")
 2420     *     private File outputFile;
 2421     *
 2422     *     &#064;Option(names = { "-v", "--verbose"}, description = "Verbose mode. Helpful for troubleshooting. Multiple -v options increase the verbosity.")
 2423     *     private boolean[] verbose;
 2424     *
 2425     *     &#064;Option(names = { "-h", "--help", "-?", "-help"}, usageHelp = true, description = "Display this help and exit")
 2426     *     private boolean help;
 2427     * }
 2428     * </pre>
 2429     * <p>
 2430     * A field cannot be annotated with both {@code @Parameters} and {@code @Option} or a
 2431     * {@code ParameterException} is thrown.
 2432     * </p>
 2433     */
 2434    @Retention(RetentionPolicy.RUNTIME)
 2435    @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
 2436    public @interface Option {
 2437        /**
 2438         * One or more option names. At least one option name is required.
 2439         * <p>
 2440         * Different environments have different conventions for naming options, but usually options have a prefix
 2441         * that sets them apart from parameters.
 2442         * Picocli supports all of the below styles. The default separator is {@code '='}, but this can be configured.
 2443         * </p><p>
 2444         * <b>*nix</b>
 2445         * </p><p>
 2446         * In Unix and Linux, options have a short (single-character) name, a long name or both.
 2447         * Short options
 2448         * (<a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02">POSIX
 2449         * style</a> are single-character and are preceded by the {@code '-'} character, e.g., {@code `-v'}.
 2450         * <a href="https://www.gnu.org/software/tar/manual/html_node/Long-Options.html">GNU-style</a> long
 2451         * (or <em>mnemonic</em>) options start with two dashes in a row, e.g., {@code `--file'}.
 2452         * </p><p>Picocli supports the POSIX convention that short options can be grouped, with the last option
 2453         * optionally taking a parameter, which may be attached to the option name or separated by a space or
 2454         * a {@code '='} character. The below examples are all equivalent:
 2455         * </p><pre>
 2456         * -xvfFILE
 2457         * -xvf FILE
 2458         * -xvf=FILE
 2459         * -xv --file FILE
 2460         * -xv --file=FILE
 2461         * -x -v --file FILE
 2462         * -x -v --file=FILE
 2463         * </pre><p>
 2464         * <b>DOS</b>
 2465         * </p><p>
 2466         * DOS options mostly have upper case single-character names and start with a single slash {@code '/'} character.
 2467         * Option parameters are separated by a {@code ':'} character. Options cannot be grouped together but
 2468         * must be specified separately. For example:
 2469         * </p><pre>
 2470         * DIR /S /A:D /T:C
 2471         * </pre><p>
 2472         * <b>PowerShell</b>
 2473         * </p><p>
 2474         * Windows PowerShell options generally are a word preceded by a single {@code '-'} character, e.g., {@code `-Help'}.
 2475         * Option parameters are separated by a space or by a {@code ':'} character.
 2476         * </p>
 2477         * @return one or more option names
 2478         */
 2479        String[] names();
 2480
 2481        /**
 2482         * Indicates whether this option is required. By default this is false.
 2483         * <p>If an option is required, but a user invokes the program without specifying the required option,
 2484         * a {@link MissingParameterException} is thrown from the {@link #parse(String...)} method.</p>
 2485         * <p>Required options that are part of a {@linkplain ArgGroup group} are required <em>within the group</em>, not required within the command:
 2486         * the group's {@linkplain ArgGroup#multiplicity() multiplicity} determines whether the group itself is required or optional.</p>
 2487         * @return whether this option is required
 2488         */
 2489        boolean required() default false;
 2490
 2491        /**
 2492         * Set {@code help=true} if this option should disable validation of the remaining arguments:
 2493         * If the {@code help} option is specified, no error message is generated for missing required options.
 2494         * <p>
 2495         * This attribute is useful for special options like help ({@code -h} and {@code --help} on unix,
 2496         * {@code -?} and {@code -Help} on Windows) or version ({@code -V} and {@code --version} on unix,
 2497         * {@code -Version} on Windows).
 2498         * </p>
 2499         * <p>
 2500         * Note that the {@link #parse(String...)} method will not print help documentation. It will only set
 2501         * the value of the annotated field. It is the responsibility of the caller to inspect the annotated fields
 2502         * and take the appropriate action.
 2503         * </p>
 2504         * @return whether this option disables validation of the other arguments
 2505         * @deprecated Use {@link #usageHelp()} and {@link #versionHelp()} instead. See {@link #printHelpIfRequested(List, PrintStream, CommandLine.Help.Ansi)}
 2506         */
 2507        @Deprecated boolean help() default false;
 2508
 2509        /**
 2510         * Set {@code usageHelp=true} for the {@code --help} option that triggers display of the usage help message.
 2511         * The <a href="http://picocli.info/#_printing_help_automatically">convenience methods</a> {@code Commandline.call},
 2512         * {@code Commandline.run}, and {@code Commandline.parseWithHandler(s)} will automatically print usage help
 2513         * when an option with {@code usageHelp=true} was specified on the command line.
 2514         * <p>
 2515         * By default, <em>all</em> options and positional parameters are included in the usage help message
 2516         * <em>except when explicitly marked {@linkplain #hidden() hidden}.</em>
 2517         * </p><p>
 2518         * If this option is specified on the command line, picocli will not validate the remaining arguments (so no "missing required
 2519         * option" errors) and the {@link CommandLine#isUsageHelpRequested()} method will return {@code true}.
 2520         * </p><p>
 2521         * Alternatively, consider annotating your command with {@linkplain Command#mixinStandardHelpOptions() @Command(mixinStandardHelpOptions = true)}.
 2522         * </p>
 2523         * @return whether this option allows the user to request usage help
 2524         * @since 0.9.8
 2525         * @see #hidden()
 2526         * @see #run(Runnable, String...)
 2527         * @see #call(Callable, String...)
 2528         * @see #parseWithHandler(IParseResultHandler2, String[])
 2529         * @see #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi)
 2530         */
 2531        boolean usageHelp() default false;
 2532
 2533        /**
 2534         * Set {@code versionHelp=true} for the {@code --version} option that triggers display of the version information.
 2535         * The <a href="http://picocli.info/#_printing_help_automatically">convenience methods</a> {@code Commandline.call},
 2536         * {@code Commandline.run}, and {@code Commandline.parseWithHandler(s)} will automatically print version information
 2537         * when an option with {@code versionHelp=true} was specified on the command line.
 2538         * <p>
 2539         * The version information string is obtained from the command's {@linkplain Command#version() version} annotation
 2540         * or from the {@linkplain Command#versionProvider() version provider}.
 2541         * </p><p>
 2542         * If this option is specified on the command line, picocli will not validate the remaining arguments (so no "missing required
 2543         * option" errors) and the {@link CommandLine#isUsageHelpRequested()} method will return {@code true}.
 2544         * </p><p>
 2545         * Alternatively, consider annotating your command with {@linkplain Command#mixinStandardHelpOptions() @Command(mixinStandardHelpOptions = true)}.
 2546         * </p>
 2547         * @return whether this option allows the user to request version information
 2548         * @since 0.9.8
 2549         * @see #hidden()
 2550         * @see #run(Runnable, String...)
 2551         * @see #call(Callable, String...)
 2552         * @see #parseWithHandler(IParseResultHandler2, String[])
 2553         * @see #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi)
 2554         */
 2555        boolean versionHelp() default false;
 2556
 2557        /**
 2558         * Description of this option, used when generating the usage documentation. Each element of the array is rendered on a separate line.
 2559         * <p>May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.
 2560         * </p><p>
 2561         * The description may contain variables that are rendered when help is requested.
 2562         * The string {@code ${DEFAULT-VALUE}} is replaced with the default value of the option. This is regardless of
 2563         * the command's {@link Command#showDefaultValues() showDefaultValues} setting or the option's {@link #showDefaultValue() showDefaultValue} setting.
 2564         * The string {@code ${COMPLETION-CANDIDATES}} is replaced with the completion candidates generated by
 2565         * {@link #completionCandidates()} in the description for this option.
 2566         * Also, embedded {@code %n} newline markers are converted to actual newlines.
 2567         * </p>
 2568         * @return the description of this option
 2569         */
 2570        String[] description() default {};
 2571
 2572        /**
 2573         * Specifies the minimum number of required parameters and the maximum number of accepted parameters.
 2574         * If an option declares a positive arity, and the user specifies an insufficient number of parameters on the
 2575         * command line, a {@link MissingParameterException} is thrown by the {@link #parse(String...)} method.
 2576         * <p>
 2577         * In many cases picocli can deduce the number of required parameters from the field's type.
 2578         * By default, flags (boolean options) have arity zero,
 2579         * and single-valued type fields (String, int, Integer, double, Double, File, Date, etc) have arity one.
 2580         * Generally, fields with types that cannot hold multiple values can omit the {@code arity} attribute.
 2581         * </p><p>
 2582         * Fields used to capture options with arity two or higher should have a type that can hold multiple values,
 2583         * like arrays or Collections. See {@link #type()} for strongly-typed Collection fields.
 2584         * </p><p>
 2585         * For example, if an option has 2 required parameters and any number of optional parameters,
 2586         * specify {@code @Option(names = "-example", arity = "2..*")}.
 2587         * </p>
 2588         * <b>A note on boolean options</b>
 2589         * <p>
 2590         * By default picocli does not expect boolean options (also called "flags" or "switches") to have a parameter.
 2591         * You can make a boolean option take a required parameter by annotating your field with {@code arity="1"}.
 2592         * For example: </p>
 2593         * <pre>&#064;Option(names = "-v", arity = "1") boolean verbose;</pre>
 2594         * <p>
 2595         * Because this boolean field is defined with arity 1, the user must specify either {@code <program> -v false}
 2596         * or {@code <program> -v true}
 2597         * on the command line, or a {@link MissingParameterException} is thrown by the {@link #parse(String...)}
 2598         * method.
 2599         * </p><p>
 2600         * To make the boolean parameter possible but optional, define the field with {@code arity = "0..1"}.
 2601         * For example: </p>
 2602         * <pre>&#064;Option(names="-v", arity="0..1") boolean verbose;</pre>
 2603         * <p>This will accept any of the below without throwing an exception:</p>
 2604         * <pre>
 2605         * -v
 2606         * -v true
 2607         * -v false
 2608         * </pre>
 2609         * @return how many arguments this option requires
 2610         */
 2611        String arity() default "";
 2612
 2613        /**
 2614         * Specify a {@code paramLabel} for the option parameter to be used in the usage help message. If omitted,
 2615         * picocli uses the field name in fish brackets ({@code '<'} and {@code '>'}) by default. Example:
 2616         * <pre>class Example {
 2617         *     &#064;Option(names = {"-o", "--output"}, paramLabel="FILE", description="path of the output file")
 2618         *     private File out;
 2619         *     &#064;Option(names = {"-j", "--jobs"}, arity="0..1", description="Allow N jobs at once; infinite jobs with no arg.")
 2620         *     private int maxJobs = -1;
 2621         * }</pre>
 2622         * <p>By default, the above gives a usage help message like the following:</p><pre>
 2623         * Usage: &lt;main class&gt; [OPTIONS]
 2624         * -o, --output FILE       path of the output file
 2625         * -j, --jobs [&lt;maxJobs&gt;]  Allow N jobs at once; infinite jobs with no arg.
 2626         * </pre>
 2627         * @return name of the option parameter used in the usage help message
 2628         */
 2629        String paramLabel() default "";
 2630
 2631        /** Returns whether usage syntax decorations around the {@linkplain #paramLabel() paramLabel} should be suppressed.
 2632         * The default is {@code false}: by default, the paramLabel is surrounded with {@code '['} and {@code ']'} characters
 2633         * if the value is optional and followed by ellipses ("...") when multiple values can be specified.
 2634         * @since 3.6.0 */
 2635        boolean hideParamSyntax() default false;
 2636
 2637        /** <p>
 2638         * Optionally specify a {@code type} to control exactly what Class the option parameter should be converted
 2639         * to. This may be useful when the field type is an interface or an abstract class. For example, a field can
 2640         * be declared to have type {@code java.lang.Number}, and annotating {@code @Option(type=Short.class)}
 2641         * ensures that the option parameter value is converted to a {@code Short} before setting the field value.
 2642         * </p><p>
 2643         * For array fields whose <em>component</em> type is an interface or abstract class, specify the concrete <em>component</em> type.
 2644         * For example, a field with type {@code Number[]} may be annotated with {@code @Option(type=Short.class)}
 2645         * to ensure that option parameter values are converted to {@code Short} before adding an element to the array.
 2646         * </p><p>
 2647         * Picocli will use the {@link ITypeConverter} that is
 2648         * {@linkplain #registerConverter(Class, ITypeConverter) registered} for the specified type to convert
 2649         * the raw String values before modifying the field value.
 2650         * </p><p>
 2651         * Prior to 2.0, the {@code type} attribute was necessary for {@code Collection} and {@code Map} fields,
 2652         * but starting from 2.0 picocli will infer the component type from the generic type's type arguments.
 2653         * For example, for a field of type {@code Map<TimeUnit, Long>} picocli will know the option parameter
 2654         * should be split up in key=value pairs, where the key should be converted to a {@code java.util.concurrent.TimeUnit}
 2655         * enum value, and the value should be converted to a {@code Long}. No {@code @Option(type=...)} type attribute
 2656         * is required for this. For generic types with wildcards, picocli will take the specified upper or lower bound
 2657         * as the Class to convert to, unless the {@code @Option} annotation specifies an explicit {@code type} attribute.
 2658         * </p><p>
 2659         * If the field type is a raw collection or a raw map, and you want it to contain other values than Strings,
 2660         * or if the generic type's type arguments are interfaces or abstract classes, you may
 2661         * specify a {@code type} attribute to control the Class that the option parameter should be converted to.
 2662         * @return the type(s) to convert the raw String values
 2663         */
 2664        Class<?>[] type() default {};
 2665
 2666        /**
 2667         * Optionally specify one or more {@link ITypeConverter} classes to use to convert the command line argument into
 2668         * a strongly typed value (or key-value pair for map fields). This is useful when a particular field should
 2669         * use a custom conversion that is different from the normal conversion for the field's type.
 2670         * <p>For example, for a specific field you may want to use a converter that maps the constant names defined
 2671         * in {@link java.sql.Types java.sql.Types} to the {@code int} value of these constants, but any other {@code int} fields should
 2672         * not be affected by this and should continue to use the standard int converter that parses numeric values.</p>
 2673         * @return the type converter(s) to use to convert String values to strongly typed values for this field
 2674         * @see CommandLine#registerConverter(Class, ITypeConverter)
 2675         */
 2676        Class<? extends ITypeConverter<?>>[] converter() default {};
 2677
 2678        /**
 2679         * Specify a regular expression to use to split option parameter values before applying them to the field.
 2680         * All elements resulting from the split are added to the array or Collection. Ignored for single-value fields.
 2681         * @return a regular expression to split option parameter values or {@code ""} if the value should not be split
 2682         * @see String#split(String)
 2683         */
 2684        String split() default "";
 2685
 2686        /**
 2687         * Set {@code hidden=true} if this option should not be included in the usage help message.
 2688         * @return whether this option should be excluded from the usage documentation
 2689         */
 2690        boolean hidden() default false;
 2691
 2692        /** Returns the default value of this option, before splitting and type conversion.
 2693         * @return a String that (after type conversion) will be used as the value for this option if no value was specified on the command line
 2694         * @since 3.2 */
 2695        String defaultValue() default "__no_default_value__";
 2696
 2697        /** Use this attribute to control for a specific option whether its default value should be shown in the usage
 2698         * help message. If not specified, the default value is only shown when the {@link Command#showDefaultValues()}
 2699         * is set {@code true} on the command. Use this attribute to specify whether the default value
 2700         * for this specific option should always be shown or never be shown, regardless of the command setting.
 2701         * <p>Note that picocli 3.2 allows {@linkplain #description() embedding default values} anywhere in the description that ignores this setting.</p>
 2702         * @return whether this option's default value should be shown in the usage help message
 2703         */
 2704        Help.Visibility showDefaultValue() default Help.Visibility.ON_DEMAND;
 2705
 2706        /** Use this attribute to specify an {@code Iterable<String>} class that generates completion candidates for this option.
 2707         * For map fields, completion candidates should be in {@code key=value} form.
 2708         * <p>
 2709         * Completion candidates are used in bash completion scripts generated by the {@code picocli.AutoComplete} class.
 2710         * Bash has special completion options to generate file names and host names, and the bash completion scripts
 2711         * generated by {@code AutoComplete} delegate to these bash built-ins for {@code @Options} whose {@code type} is
 2712         * {@code java.io.File}, {@code java.nio.file.Path} or {@code java.net.InetAddress}.
 2713         * </p><p>
 2714         * For {@code @Options} whose {@code type} is a Java {@code enum}, {@code AutoComplete} can generate completion
 2715         * candidates from the type. For other types, use this attribute to specify completion candidates.
 2716         * </p>
 2717         *
 2718         * @return a class whose instances can iterate over the completion candidates for this option
 2719         * @see picocli.CommandLine.IFactory
 2720         * @since 3.2 */
 2721        Class<? extends Iterable<String>> completionCandidates() default NoCompletionCandidates.class;
 2722
 2723        /**
 2724         * Set {@code interactive=true} if this option will prompt the end user for a value (like a password).
 2725         * Only supported for single-value options (not arrays, collections or maps).
 2726         * When running on Java 6 or greater, this will use the {@link Console#readPassword()} API to get a value without echoing input to the console.
 2727         * @return whether this option prompts the end user for a value to be entered on the command line
 2728         * @since 3.5
 2729         */
 2730        boolean interactive() default false;
 2731
 2732        /** ResourceBundle key for this option. If not specified, (and a ResourceBundle {@linkplain Command#resourceBundle() exists for this command}) an attempt
 2733         * is made to find the option description using any of the option names (without leading hyphens) as key.
 2734         * @see OptionSpec#description()
 2735         * @since 3.6
 2736         */
 2737        String descriptionKey() default "";
 2738
 2739        /**
 2740         * When {@link Command#sortOptions() @Command(sortOptions = false)} is specified, this attribute can be used to control the order in which options are listed in the usage help message.
 2741         * @return the position in the options list at which this option should be shown. Options with a lower number are shown before options with a higher number. Gaps are allowed.
 2742         * @since 3.9
 2743         */
 2744        int order() default -1;
 2745
 2746        /**
 2747         * Specify the name of one or more options that this option is mutually exclusive with.
 2748         * Picocli will internally create a mutually exclusive {@linkplain ArgGroup group} with all specified options (and
 2749         * any options that the specified options are mutually exclusive with).
 2750         * <p>
 2751         * Options cannot be part of multiple groups to avoid ambiguity for the parser. Constructions
 2752         * where an option is part of multiple groups must be simplified so that the option is in just one group.
 2753         * For example: {@code (-a | -b) | (-a -x)} can be simplified to {@code (-a [-x] | -b)}.
 2754         * </p>
 2755         * @return the name or names of the option(s) that this option is mutually exclusive with.
 2756         * @since 4.0
 2757         */
 2758        String[] excludes() default {};
 2759
 2760        /**
 2761         * Specify the name of one or more options that this option must co-occur with.
 2762         * Picocli will internally create a co-occurring {@linkplain ArgGroup group} with all specified options (and
 2763         * any options that the specified options must co-occur with).
 2764         * <p>
 2765         * Options cannot be part of multiple groups to avoid ambiguity for the parser. Constructions
 2766         * where an option is part of multiple groups must be simplified so that the option is in just one group.
 2767         * For example: {@code (-a -x) | (-a -y)} can be simplified to {@code (-a [-x | -y])}.
 2768         * </p>
 2769         * @return the name or names of the option(s) that this option must co-occur with.
 2770         * @since 4.0
 2771         */
 2772        String[] needs() default {};
 2773    }
 2774    /**
 2775     * <p>
 2776     * Fields annotated with {@code @Parameters} will be initialized with positional parameters. By specifying the
 2777     * {@link #index()} attribute you can pick the exact position or a range of positional parameters to apply. If no
 2778     * index is specified, the field will get all positional parameters (and so it should be an array or a collection).
 2779     * </p><p>
 2780     * In the case of command methods (annotated with {@code @Command}), method parameters may be annotated with {@code @Parameters},
 2781     * but are are considered positional parameters by default, unless they are annotated with {@code @Option}.
 2782     * </p><p>
 2783     * Command class example:
 2784     * </p>
 2785     * <pre>
 2786     * import static picocli.CommandLine.*;
 2787     *
 2788     * public class MyCalcParameters {
 2789     *     &#064;Parameters(description = "Any number of input numbers")
 2790     *     private List&lt;BigDecimal&gt; files = new ArrayList&lt;BigDecimal&gt;();
 2791     *
 2792     *     &#064;Option(names = { "-h", "--help" }, usageHelp = true, description = "Display this help and exit")
 2793     *     private boolean help;
 2794     * }
 2795     * </pre><p>
 2796     * A field cannot be annotated with both {@code @Parameters} and {@code @Option} or a {@code ParameterException}
 2797     * is thrown.</p>
 2798     */
 2799    @Retention(RetentionPolicy.RUNTIME)
 2800    @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
 2801    public @interface Parameters {
 2802        /** Specify an index ("0", or "1", etc.) to pick which of the command line arguments should be assigned to this
 2803         * field. For array or Collection fields, you can also specify an index range ("0..3", or "2..*", etc.) to assign
 2804         * a subset of the command line arguments to this field. The default is "*", meaning all command line arguments.
 2805         * @return an index or range specifying which of the command line arguments should be assigned to this field
 2806         */
 2807        String index() default "";
 2808
 2809        /** Description of the parameter(s), used when generating the usage documentation. Each element of the array is rendered on a separate line.
 2810         * <p>May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.
 2811         * </p><p>
 2812         * The description may contain variables that are rendered when help is requested.
 2813         * The string {@code ${DEFAULT-VALUE}} is replaced with the default value of the positional parameter. This is regardless of
 2814         * the command's {@link Command#showDefaultValues() showDefaultValues} setting or the positional parameter's {@link #showDefaultValue() showDefaultValue} setting.
 2815         * The string {@code ${COMPLETION-CANDIDATES}} is replaced with the completion candidates generated by
 2816         * {@link #completionCandidates()} in the description for this positional parameter.
 2817         * Also, embedded {@code %n} newline markers are converted to actual newlines.
 2818         * </p>
 2819         * @return the description of the parameter(s)
 2820         */
 2821        String[] description() default {};
 2822
 2823        /**
 2824         * Specifies the minimum number of required parameters and the maximum number of accepted parameters. If a
 2825         * positive arity is declared, and the user specifies an insufficient number of parameters on the command line,
 2826         * {@link MissingParameterException} is thrown by the {@link #parse(String...)} method.
 2827         * <p>The default depends on the type of the parameter: booleans require no parameters, arrays and Collections
 2828         * accept zero to any number of parameters, and any other type accepts one parameter.</p>
 2829         * <p>For single-value parameters, setting {@code arity = "0..1"} makes a positional parameter optional, while setting {@code arity = "1"} makes it required.</p>
 2830         * <p>Required parameters that are part of a {@linkplain ArgGroup group} are required <em>within the group</em>, not required within the command:
 2831         * the group's {@linkplain ArgGroup#multiplicity() multiplicity} determines whether the group itself is required or optional.</p>
 2832         * @return the range of minimum and maximum parameters accepted by this command
 2833         */
 2834        String arity() default "";
 2835
 2836        /**
 2837         * Specify a {@code paramLabel} for the parameter to be used in the usage help message. If omitted,
 2838         * picocli uses the field name in fish brackets ({@code '<'} and {@code '>'}) by default. Example:
 2839         * <pre>class Example {
 2840         *     &#064;Parameters(paramLabel="FILE", description="path of the input FILE(s)")
 2841         *     private File[] inputFiles;
 2842         * }</pre>
 2843         * <p>By default, the above gives a usage help message like the following:</p><pre>
 2844         * Usage: &lt;main class&gt; [FILE...]
 2845         * [FILE...]       path of the input FILE(s)
 2846         * </pre>
 2847         * @return name of the positional parameter used in the usage help message
 2848         */
 2849        String paramLabel() default "";
 2850
 2851        /** Returns whether usage syntax decorations around the {@linkplain #paramLabel() paramLabel} should be suppressed.
 2852         * The default is {@code false}: by default, the paramLabel is surrounded with {@code '['} and {@code ']'} characters
 2853         * if the value is optional and followed by ellipses ("...") when multiple values can be specified.
 2854         * @since 3.6.0 */
 2855        boolean hideParamSyntax() default false;
 2856
 2857        /**
 2858         * <p>
 2859         * Optionally specify a {@code type} to control exactly what Class the positional parameter should be converted
 2860         * to. This may be useful when the field type is an interface or an abstract class. For example, a field can
 2861         * be declared to have type {@code java.lang.Number}, and annotating {@code @Parameters(type=Short.class)}
 2862         * ensures that the positional parameter value is converted to a {@code Short} before setting the field value.
 2863         * </p><p>
 2864         * For array fields whose <em>component</em> type is an interface or abstract class, specify the concrete <em>component</em> type.
 2865         * For example, a field with type {@code Number[]} may be annotated with {@code @Parameters(type=Short.class)}
 2866         * to ensure that positional parameter values are converted to {@code Short} before adding an element to the array.
 2867         * </p><p>
 2868         * Picocli will use the {@link ITypeConverter} that is
 2869         * {@linkplain #registerConverter(Class, ITypeConverter) registered} for the specified type to convert
 2870         * the raw String values before modifying the field value.
 2871         * </p><p>
 2872         * Prior to 2.0, the {@code type} attribute was necessary for {@code Collection} and {@code Map} fields,
 2873         * but starting from 2.0 picocli will infer the component type from the generic type's type arguments.
 2874         * For example, for a field of type {@code Map<TimeUnit, Long>} picocli will know the positional parameter
 2875         * should be split up in key=value pairs, where the key should be converted to a {@code java.util.concurrent.TimeUnit}
 2876         * enum value, and the value should be converted to a {@code Long}. No {@code @Parameters(type=...)} type attribute
 2877         * is required for this. For generic types with wildcards, picocli will take the specified upper or lower bound
 2878         * as the Class to convert to, unless the {@code @Parameters} annotation specifies an explicit {@code type} attribute.
 2879         * </p><p>
 2880         * If the field type is a raw collection or a raw map, and you want it to contain other values than Strings,
 2881         * or if the generic type's type arguments are interfaces or abstract classes, you may
 2882         * specify a {@code type} attribute to control the Class that the positional parameter should be converted to.
 2883         * @return the type(s) to convert the raw String values
 2884         */
 2885        Class<?>[] type() default {};
 2886
 2887        /**
 2888         * Optionally specify one or more {@link ITypeConverter} classes to use to convert the command line argument into
 2889         * a strongly typed value (or key-value pair for map fields). This is useful when a particular field should
 2890         * use a custom conversion that is different from the normal conversion for the field's type.
 2891         * <p>For example, for a specific field you may want to use a converter that maps the constant names defined
 2892         * in {@link java.sql.Types java.sql.Types} to the {@code int} value of these constants, but any other {@code int} fields should
 2893         * not be affected by this and should continue to use the standard int converter that parses numeric values.</p>
 2894         * @return the type converter(s) to use to convert String values to strongly typed values for this field
 2895         * @see CommandLine#registerConverter(Class, ITypeConverter)
 2896         */
 2897        Class<? extends ITypeConverter<?>>[] converter() default {};
 2898
 2899        /**
 2900         * Specify a regular expression to use to split positional parameter values before applying them to the field.
 2901         * All elements resulting from the split are added to the array or Collection. Ignored for single-value fields.
 2902         * @return a regular expression to split operand values or {@code ""} if the value should not be split
 2903         * @see String#split(String)
 2904         */
 2905        String split() default "";
 2906
 2907        /**
 2908         * Set {@code hidden=true} if this parameter should not be included in the usage message.
 2909         * @return whether this parameter should be excluded from the usage message
 2910         */
 2911        boolean hidden() default false;
 2912
 2913        /** Returns the default value of this positional parameter, before splitting and type conversion.
 2914         * @return a String that (after type conversion) will be used as the value for this positional parameter if no value was specified on the command line
 2915         * @since 3.2 */
 2916        String defaultValue() default "__no_default_value__";
 2917
 2918        /** Use this attribute to control for a specific positional parameter whether its default value should be shown in the usage
 2919         * help message. If not specified, the default value is only shown when the {@link Command#showDefaultValues()}
 2920         * is set {@code true} on the command. Use this attribute to specify whether the default value
 2921         * for this specific positional parameter should always be shown or never be shown, regardless of the command setting.
 2922         * <p>Note that picocli 3.2 allows {@linkplain #description() embedding default values} anywhere in the description that ignores this setting.</p>
 2923         * @return whether this positional parameter's default value should be shown in the usage help message
 2924         */
 2925        Help.Visibility showDefaultValue() default Help.Visibility.ON_DEMAND;
 2926
 2927        /** Use this attribute to specify an {@code Iterable<String>} class that generates completion candidates for
 2928         * this positional parameter. For map fields, completion candidates should be in {@code key=value} form.
 2929         * <p>
 2930         * Completion candidates are used in bash completion scripts generated by the {@code picocli.AutoComplete} class.
 2931         * Unfortunately, {@code picocli.AutoComplete} is not very good yet at generating completions for positional parameters.
 2932         * </p>
 2933         *
 2934         * @return a class whose instances can iterate over the completion candidates for this positional parameter
 2935         * @see picocli.CommandLine.IFactory
 2936         * @since 3.2 */
 2937        Class<? extends Iterable<String>> completionCandidates() default NoCompletionCandidates.class;
 2938
 2939        /**
 2940         * Set {@code interactive=true} if this positional parameter will prompt the end user for a value (like a password).
 2941         * Only supported for single-value positional parameters (not arrays, collections or maps).
 2942         * When running on Java 6 or greater, this will use the {@link Console#readPassword()} API to get a value without echoing input to the console.
 2943         * @return whether this positional parameter prompts the end user for a value to be entered on the command line
 2944         * @since 3.5
 2945         */
 2946        boolean interactive() default false;
 2947
 2948        /** ResourceBundle key for this option. If not specified, (and a ResourceBundle {@linkplain Command#resourceBundle() exists for this command}) an attempt
 2949         * is made to find the positional parameter description using {@code paramLabel() + "[" + index() + "]"} as key.
 2950         *
 2951         * @see PositionalParamSpec#description()
 2952         * @since 3.6
 2953         */
 2954        String descriptionKey() default "";
 2955
 2956        /**
 2957         * Specify the name of one or more options that this positional parameter is mutually exclusive with.
 2958         * Picocli will internally create a mutually exclusive {@linkplain ArgGroup group} with all specified options (and
 2959         * any options and positional parameters that the specified options are mutually exclusive with).
 2960         * <p>
 2961         * An option or positional parameter cannot be part of multiple groups to avoid ambiguity for the parser. Constructions
 2962         * where an option is part of multiple groups must be simplified so that the option is in just one group.
 2963         * For example: {@code (-a | -b) | (-a -x)} can be simplified to {@code (-a [-x] | -b)}.
 2964         * </p>
 2965         * @return the name or names of the option(s) that this positional parameter is mutually exclusive with.
 2966         * @since 4.0
 2967         */
 2968        String[] excludes() default {};
 2969
 2970        /**
 2971         * Specify the name of one or more options that this option must co-occur with.
 2972         * Picocli will internally create a co-occurring {@linkplain ArgGroup group} with all specified options (and
 2973         * any options that the specified options must co-occur with).
 2974         * <p>
 2975         * Options cannot be part of multiple groups to avoid ambiguity for the parser. Constructions
 2976         * where an option is part of multiple groups must be simplified so that the option is in just one group.
 2977         * For example: {@code (-a -x) | (-a -y)} can be simplified to {@code (-a [-x | -y])}.
 2978         * </p>
 2979         * @return the name or names of the option(s) that this option must co-occur with.
 2980         * @since 4.0
 2981         */
 2982        String[] needs() default {};
 2983    }
 2984
 2985    /**
 2986     * <p>
 2987     * Fields annotated with {@code @ParentCommand} will be initialized with the parent command of the current subcommand.
 2988     * If the current command does not have a parent command, this annotation has no effect.
 2989     * </p><p>
 2990     * Parent commands often define options that apply to all the subcommands.
 2991     * This annotation offers a convenient way to inject a reference to the parent command into a subcommand, so the
 2992     * subcommand can access its parent options. For example:
 2993     * </p><pre>
 2994     * &#064;Command(name = "top", subcommands = Sub.class)
 2995     * class Top implements Runnable {
 2996     *
 2997     *     &#064;Option(names = {"-d", "--directory"}, description = "this option applies to all subcommands")
 2998     *     File baseDirectory;
 2999     *
 3000     *     public void run() { System.out.println("Hello from top"); }
 3001     * }
 3002     *
 3003     * &#064;Command(name = "sub")
 3004     * class Sub implements Runnable {
 3005     *
 3006     *     &#064;ParentCommand
 3007     *     private Top parent;
 3008     *
 3009     *     public void run() {
 3010     *         System.out.println("Subcommand: parent command 'directory' is " + parent.baseDirectory);
 3011     *     }
 3012     * }
 3013     * </pre>
 3014     * @since 2.2
 3015     */
 3016    @Retention(RetentionPolicy.RUNTIME)
 3017    @Target(ElementType.FIELD)
 3018    public @interface ParentCommand { }
 3019
 3020    /**
 3021     * Fields annotated with {@code @Unmatched} will be initialized with the list of unmatched command line arguments, if any.
 3022     * If this annotation is found, picocli automatically sets {@linkplain CommandLine#setUnmatchedArgumentsAllowed(boolean) unmatchedArgumentsAllowed} to {@code true}.
 3023     * @see CommandLine#isUnmatchedArgumentsAllowed()
 3024     * @since 3.0
 3025     */
 3026    @Retention(RetentionPolicy.RUNTIME)
 3027    @Target(ElementType.FIELD)
 3028    public @interface Unmatched { }
 3029
 3030    /**
 3031     * <p>
 3032     * Fields annotated with {@code @Mixin} are "expanded" into the current command: {@link Option @Option} and
 3033     * {@link Parameters @Parameters} in the mixin class are added to the options and positional parameters of this command.
 3034     * A {@link DuplicateOptionAnnotationsException} is thrown if any of the options in the mixin has the same name as
 3035     * an option in this command.
 3036     * </p><p>
 3037     * The {@code Mixin} annotation provides a way to reuse common options and parameters without subclassing. For example:
 3038     * </p><pre>
 3039     * class HelloWorld implements Runnable {
 3040     *
 3041     *     // adds the --help and --version options to this command
 3042     *     &#064;Mixin
 3043     *     private HelpOptions = new HelpOptions();
 3044     *
 3045     *     &#064;Option(names = {"-u", "--userName"}, required = true, description = "The user name")
 3046     *     String userName;
 3047     *
 3048     *     public void run() { System.out.println("Hello, " + userName); }
 3049     * }
 3050     *
 3051     * // Common reusable help options.
 3052     * class HelpOptions {
 3053     *
 3054     *     &#064;Option(names = { "-h", "--help"}, usageHelp = true, description = "Display this help and exit")
 3055     *     private boolean help;
 3056     *
 3057     *     &#064;Option(names = { "-V", "--version"}, versionHelp = true, description = "Display version info and exit")
 3058     *     private boolean versionHelp;
 3059     * }
 3060     * </pre>
 3061     * @since 3.0
 3062     */
 3063    @Retention(RetentionPolicy.RUNTIME)
 3064    @Target({ElementType.FIELD, ElementType.PARAMETER})
 3065    public @interface Mixin {
 3066        /** Optionally specify a name that the mixin object can be retrieved with from the {@code CommandSpec}.
 3067         * If not specified the name of the annotated field is used.
 3068         * @return a String to register the mixin object with, or an empty String if the name of the annotated field should be used */
 3069        String name() default "";
 3070    }
 3071    /**
 3072     * Fields annotated with {@code @Spec} will be initialized with the {@code CommandSpec} for the command the field is part of. Example usage:
 3073     * <pre>
 3074     * class InjectSpecExample implements Runnable {
 3075     *     &#064;Spec CommandSpec commandSpec;
 3076     *     //...
 3077     *     public void run() {
 3078     *         // do something with the injected objects
 3079     *     }
 3080     * }
 3081     * </pre>
 3082     * @since 3.2
 3083     */
 3084    @Retention(RetentionPolicy.RUNTIME)
 3085    @Target({ElementType.FIELD, ElementType.METHOD})
 3086    public @interface Spec { }
 3087    /**
 3088     * <p>Annotate your class with {@code @Command} when you want more control over the format of the generated help
 3089     * message. From 3.6, methods can also be annotated with {@code @Command}, where the method parameters define the
 3090     * command options and positional parameters.
 3091     * </p><pre>
 3092     * &#064;Command(name      = "Encrypt", mixinStandardHelpOptions = true,
 3093     *        description = "Encrypt FILE(s), or standard input, to standard output or to the output file.",
 3094     *        version     = "Encrypt version 1.0",
 3095     *        footer      = "Copyright (c) 2017")
 3096     * public class Encrypt {
 3097     *     &#064;Parameters(paramLabel = "FILE", description = "Any number of input files")
 3098     *     private List&lt;File&gt; files = new ArrayList&lt;File&gt;();
 3099     *
 3100     *     &#064;Option(names = { "-o", "--out" }, description = "Output file (default: print to console)")
 3101     *     private File outputFile;
 3102     *
 3103     *     &#064;Option(names = { "-v", "--verbose"}, description = "Verbose mode. Helpful for troubleshooting. Multiple -v options increase the verbosity.")
 3104     *     private boolean[] verbose;
 3105     * }</pre>
 3106     * <p>
 3107     * The structure of a help message looks like this:
 3108     * </p><ul>
 3109     *   <li>[header]</li>
 3110     *   <li>[synopsis]: {@code Usage: <commandName> [OPTIONS] [FILE...]}</li>
 3111     *   <li>[description]</li>
 3112     *   <li>[parameter list]: {@code      [FILE...]   Any number of input files}</li>
 3113     *   <li>[option list]: {@code   -h, --help   prints this help message and exits}</li>
 3114     *   <li>[footer]</li>
 3115     * </ul> */
 3116    @Retention(RetentionPolicy.RUNTIME)
 3117    @Target({ElementType.TYPE, ElementType.LOCAL_VARIABLE, ElementType.FIELD, ElementType.PACKAGE, ElementType.METHOD})
 3118    public @interface Command {
 3119        /** Program name to show in the synopsis. If omitted, {@code "<main class>"} is used.
 3120         * For {@linkplain #subcommands() declaratively added} subcommands, this attribute is also used
 3121         * by the parser to recognize subcommands in the command line arguments.
 3122         * @return the program name to show in the synopsis
 3123         * @see CommandSpec#name()
 3124         * @see Help#commandName() */
 3125        String name() default "<main class>";
 3126
 3127        /** Alternative command names by which this subcommand is recognized on the command line.
 3128         * @return one or more alternative command names
 3129         * @since 3.1 */
 3130        String[] aliases() default {};
 3131
 3132        /** A list of classes to instantiate and register as subcommands. When registering subcommands declaratively
 3133         * like this, you don't need to call the {@link CommandLine#addSubcommand(String, Object)} method. For example, this:
 3134         * <pre>
 3135         * &#064;Command(subcommands = {
 3136         *         GitStatus.class,
 3137         *         GitCommit.class,
 3138         *         GitBranch.class })
 3139         * public class Git { ... }
 3140         *
 3141         * CommandLine commandLine = new CommandLine(new Git());
 3142         * </pre> is equivalent to this:
 3143         * <pre>
 3144         * // alternative: programmatically add subcommands.
 3145         * // NOTE: in this case there should be no `subcommands` attribute on the @Command annotation.
 3146         * &#064;Command public class Git { ... }
 3147         *
 3148         * CommandLine commandLine = new CommandLine(new Git())
 3149         *         .addSubcommand("status",   new GitStatus())
 3150         *         .addSubcommand("commit",   new GitCommit())
 3151         *         .addSubcommand("branch",   new GitBranch());
 3152         * </pre>
 3153         * @return the declaratively registered subcommands of this command, or an empty array if none
 3154         * @see CommandLine#addSubcommand(String, Object)
 3155         * @see HelpCommand
 3156         * @since 0.9.8
 3157         */
 3158        Class<?>[] subcommands() default {};
 3159
 3160        /** Specify whether methods annotated with {@code @Command} should be registered as subcommands of their
 3161         * enclosing {@code @Command} class.
 3162         * The default is {@code true}. For example:
 3163         * <pre>
 3164         * &#064;Command
 3165         * public class Git {
 3166         *     &#064;Command
 3167         *     void status() { ... }
 3168         * }
 3169         *
 3170         * CommandLine git = new CommandLine(new Git());
 3171         * </pre> is equivalent to this:
 3172         * <pre>
 3173         * // don't add command methods as subcommands automatically
 3174         * &#064;Command(addMethodSubcommands = false)
 3175         * public class Git {
 3176         *     &#064;Command
 3177         *     void status() { ... }
 3178         * }
 3179         *
 3180         * // add command methods as subcommands programmatically
 3181         * CommandLine git = new CommandLine(new Git());
 3182         * CommandLine status = new CommandLine(CommandLine.getCommandMethods(Git.class, "status").get(0));
 3183         * git.addSubcommand("status", status);
 3184         * </pre>
 3185         * @return whether methods annotated with {@code @Command} should be registered as subcommands
 3186         * @see CommandLine#addSubcommand(String, Object)
 3187         * @see CommandLine#getCommandMethods(Class, String)
 3188         * @see CommandSpec#addMethodSubcommands()
 3189         * @since 3.6.0 */
 3190        boolean addMethodSubcommands() default true;
 3191
 3192        /** String that separates options from option parameters. Default is {@code "="}. Spaces are also accepted.
 3193         * @return the string that separates options from option parameters, used both when parsing and when generating usage help
 3194         * @see CommandLine#setSeparator(String) */
 3195        String separator() default "=";
 3196
 3197        /** Version information for this command, to print to the console when the user specifies an
 3198         * {@linkplain Option#versionHelp() option} to request version help. Each element of the array is rendered on a separate line.
 3199         * <p>May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.</p>
 3200         * <p>This is not part of the usage help message.</p>
 3201         *
 3202         * @return a string or an array of strings with version information about this command (each string in the array is displayed on a separate line).
 3203         * @since 0.9.8
 3204         * @see CommandLine#printVersionHelp(PrintStream)
 3205         */
 3206        String[] version() default {};
 3207
 3208        /** Class that can provide version information dynamically at runtime. An implementation may return version
 3209         * information obtained from the JAR manifest, a properties file or some other source.
 3210         * @return a Class that can provide version information dynamically at runtime
 3211         * @since 2.2 */
 3212        Class<? extends IVersionProvider> versionProvider() default NoVersionProvider.class;
 3213
 3214        /**
 3215         * Adds the standard {@code -h} and {@code --help} {@linkplain Option#usageHelp() usageHelp} options and {@code -V}
 3216         * and {@code --version} {@linkplain Option#versionHelp() versionHelp} options to the options of this command.
 3217         * <p>
 3218         * Note that if no {@link #version()} or {@link #versionProvider()} is specified, the {@code --version} option will not print anything.
 3219         * </p><p>
 3220         * For {@linkplain #resourceBundle() internationalization}: the help option has {@code descriptionKey = "mixinStandardHelpOptions.help"},
 3221         * and the version option has {@code descriptionKey = "mixinStandardHelpOptions.version"}.
 3222         * </p>
 3223         * @return whether the auto-help mixin should be added to this command
 3224         * @since 3.0 */
 3225        boolean mixinStandardHelpOptions() default false;
 3226
 3227        /** Set this attribute to {@code true} if this subcommand is a help command, and required options and positional
 3228         * parameters of the parent command should not be validated. If a subcommand marked as {@code helpCommand} is
 3229         * specified on the command line, picocli will not validate the parent arguments (so no "missing required
 3230         * option" errors) and the {@link CommandLine#printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi)} method will return {@code true}.
 3231         * @return {@code true} if this subcommand is a help command and picocli should not check for missing required
 3232         *      options and positional parameters on the parent command
 3233         * @since 3.0 */
 3234        boolean helpCommand() default false;
 3235
 3236        /** Set the heading preceding the header section.
 3237         * <p>May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.</p>
 3238         * @return the heading preceding the header section
 3239         * @see UsageMessageSpec#headerHeading()
 3240         * @see Help#headerHeading(Object...)  */
 3241        String headerHeading() default "";
 3242
 3243        /** Optional summary description of the command, shown before the synopsis. Each element of the array is rendered on a separate line.
 3244         * <p>May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.</p>
 3245         * @return summary description of the command
 3246         * @see UsageMessageSpec#header()
 3247         * @see Help#header(Object...)  */
 3248        String[] header() default {};
 3249
 3250        /** Set the heading preceding the synopsis text. The default heading is {@code "Usage: "} (without a line break between the heading and the synopsis text).
 3251         * <p>May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.</p>
 3252         * @return the heading preceding the synopsis text
 3253         * @see Help#synopsisHeading(Object...)  */
 3254        String synopsisHeading() default "Usage: ";
 3255
 3256        /** Specify {@code true} to generate an abbreviated synopsis like {@code "<main> [OPTIONS] [PARAMETERS...]"}.
 3257         * By default, a detailed synopsis with individual option names and parameters is generated.
 3258         * @return whether the synopsis should be abbreviated
 3259         * @see Help#abbreviatedSynopsis()
 3260         * @see Help#detailedSynopsis(Comparator, boolean) */
 3261        boolean abbreviateSynopsis() default false;
 3262
 3263        /** Specify one or more custom synopsis lines to display instead of an auto-generated synopsis. Each element of the array is rendered on a separate line.
 3264         * <p>May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.</p>
 3265         * @return custom synopsis text to replace the auto-generated synopsis
 3266         * @see Help#customSynopsis(Object...) */
 3267        String[] customSynopsis() default {};
 3268
 3269        /** Set the heading preceding the description section.
 3270         * <p>May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.</p>
 3271         * @return the heading preceding the description section
 3272         * @see Help#descriptionHeading(Object...)  */
 3273        String descriptionHeading() default "";
 3274
 3275        /** Optional text to display between the synopsis line(s) and the list of options. Each element of the array is rendered on a separate line.
 3276         * <p>May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.</p>
 3277         * @return description of this command
 3278         * @see Help#description(Object...) */
 3279        String[] description() default {};
 3280
 3281        /** Set the heading preceding the parameters list.
 3282         * <p>May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.</p>
 3283         * @return the heading preceding the parameters list
 3284         * @see Help#parameterListHeading(Object...)  */
 3285        String parameterListHeading() default "";
 3286
 3287        /** Set the heading preceding the options list.
 3288         * <p>May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.</p>
 3289         * @return the heading preceding the options list
 3290         * @see Help#optionListHeading(Object...)  */
 3291        String optionListHeading() default "";
 3292
 3293        /** Specify {@code false} to show Options in declaration order. The default is to sort alphabetically.
 3294         * @return whether options should be shown in alphabetic order. */
 3295        boolean sortOptions() default true;
 3296
 3297        /** Prefix required options with this character in the options list. The default is no marker: the synopsis
 3298         * indicates which options and parameters are required.
 3299         * @return the character to show in the options list to mark required options */
 3300        char requiredOptionMarker() default ' ';
 3301
 3302        /** Class that can provide default values dynamically at runtime. An implementation may return default
 3303         * value obtained from a configuration file like a properties file or some other source.
 3304         * @return a Class that can provide default values dynamically at runtime
 3305         * @since 3.6 */
 3306        Class<? extends IDefaultValueProvider> defaultValueProvider() default NoDefaultProvider.class;
 3307
 3308        /** Specify {@code true} to show default values in the description column of the options list (except for
 3309         * boolean options). False by default.
 3310         * <p>Note that picocli 3.2 allows {@linkplain Option#description() embedding default values} anywhere in the
 3311         * option or positional parameter description that ignores this setting.</p>
 3312         * @return whether the default values for options and parameters should be shown in the description column */
 3313        boolean showDefaultValues() default false;
 3314
 3315        /** Set the heading preceding the subcommands list. The default heading is {@code "Commands:%n"} (with a line break at the end).
 3316         * <p>May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.</p>
 3317         * @return the heading preceding the subcommands list
 3318         * @see Help#commandListHeading(Object...)  */
 3319        String commandListHeading() default "Commands:%n";
 3320
 3321        /** Set the heading preceding the footer section.
 3322         * <p>May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.</p>
 3323         * @return the heading preceding the footer section
 3324         * @see Help#footerHeading(Object...)  */
 3325        String footerHeading() default "";
 3326
 3327        /** Optional text to display after the list of options. Each element of the array is rendered on a separate line.
 3328         * <p>May contain embedded {@linkplain java.util.Formatter format specifiers} like {@code %n} line separators. Literal percent {@code '%'} characters must be escaped with another {@code %}.</p>
 3329         * @return text to display after the list of options
 3330         * @see Help#footer(Object...) */
 3331        String[] footer() default {};
 3332
 3333        /**
 3334         * Set {@code hidden=true} if this command should not be included in the list of commands in the usage help of the parent command.
 3335         * @return whether this command should be excluded from the usage message
 3336         * @since 3.0
 3337         */
 3338        boolean hidden() default false;
 3339
 3340        /** Set the base name of the ResourceBundle to find option and positional parameters descriptions, as well as
 3341         * usage help message sections and section headings. <p>See {@link Messages} for more details and an example.</p>
 3342         * @return the base name of the ResourceBundle for usage help strings
 3343         * @see ArgSpec#messages()
 3344         * @see UsageMessageSpec#messages()
 3345         * @see CommandSpec#resourceBundle()
 3346         * @see CommandLine#setResourceBundle(ResourceBundle)
 3347         * @since 3.6
 3348         */
 3349        String resourceBundle() default "";
 3350
 3351        /** Set the {@link UsageMessageSpec#width(int) usage help message width}. The default is 80.
 3352         * @since 3.7
 3353         */
 3354        int usageHelpWidth() default 80;
 3355    }
 3356    /** A {@code Command} may define one or more {@code ArgGroups}: a group of options, positional parameters or a mixture of the two.
 3357     * Groups can be used to:
 3358     * <ul>
 3359     *     <li>define <b>mutually exclusive</b> arguments. By default, options and positional parameters
 3360     *     in a group are mutually exclusive. This can be controlled with the {@link #exclusive() exclusive} attribute.
 3361     *     Picocli will throw a {@link MutuallyExclusiveArgsException} if the command line contains multiple arguments that are mutually exclusive.</li>
 3362     *     <li>define a set of arguments that <b>must co-occur</b>. Set {@link #exclusive() exclusive = false}
 3363     *     to define a group of options and positional parameters that must always be specified together.
 3364     *     Picocli will throw a {@link MissingParameterException MissingParameterException} if not all the options and positional parameters in a co-occurring group are specified together.</li>
 3365     *     <li>create an <b>option section</b> in the usage help message.
 3366     *     To be shown in the usage help message, a group needs to have a {@link #heading() heading} (which may come from a {@linkplain #headingKey() resource bundle}).
 3367     *     Groups without a heading are only used for validation.
 3368     *     Set {@link #validate() validate = false} for groups whose purpose is only to customize the usage help message.</li>
 3369     *     <li>define <b>composite repeating argument groups</b>. Groups may contain other groups to create composite groups.</li>
 3370     * </ul>
 3371     * <p>Groups may be optional ({@code multiplicity = "0..1"}), required ({@code multiplicity = "1"}), or repeating groups ({@code multiplicity = "0..*"} or {@code multiplicity = "1..*"}).
 3372     * For a group of mutually exclusive arguments, making the group required means that one of the arguments in the group must appear on the command line, or a {@link MissingParameterException MissingParameterException} is thrown.
 3373     * For a group of co-occurring arguments, all arguments in the group must appear on the command line.
 3374     * </p>
 3375     * <p>Groups can be composed for validation purposes:</p>
 3376     * <ul>
 3377     * <li>When the parent group is mutually exclusive, only one of the subgroups may be present.</li>
 3378     * <li>When the parent group is a co-occurring group, all subgroups must be present.</li>
 3379     * <li>When the parent group is required, at least one subgroup must be present.</li>
 3380     * </ul>
 3381     * <p>
 3382     * Below is an example of an {@code ArgGroup} defining a set of dependent options that must occur together.
 3383     * All options are required <em>within the group</em>, while the group itself is optional:</p>
 3384     * <pre>
 3385     * public class DependentOptions {
 3386     *     &#064;ArgGroup(exclusive = false, multiplicity = "0..1")
 3387     *     Dependent group;
 3388     *
 3389     *     static class Dependent {
 3390     *         &#064;Option(names = "-a", required = true) int a;
 3391     *         &#064;Option(names = "-b", required = true) int b;
 3392     *         &#064;Option(names = "-c", required = true) int c;
 3393     *     }
 3394     * }</pre>
 3395     * @see ArgGroupSpec
 3396     * @since 4.0 */
 3397    @Retention(RetentionPolicy.RUNTIME)
 3398    @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
 3399    public @interface ArgGroup {
 3400        /** The heading of this group, used when generating the usage documentation.
 3401         * When neither a {@link #heading() heading} nor a {@link #headingKey() headingKey} are specified,
 3402         * this group is used for validation only and does not change the usage help message. */
 3403        String heading() default "__no_heading__";
 3404
 3405        /** ResourceBundle key for this group's usage help message section heading.
 3406         * When neither a {@link #heading() heading} nor a {@link #headingKey() headingKey} are specified,
 3407         * this group is used for validation only and does not change the usage help message. */
 3408        String headingKey() default "__no_heading_key__";
 3409        /** Determines whether this is a mutually exclusive group; {@code true} by default.
 3410         * If {@code false}, this is a co-occurring group. Ignored if {@link #validate()} is {@code false}. */
 3411        boolean exclusive() default true;
 3412        /** Determines how often this group can be specified on the command line; {@code "0..1"} (optional) by default.
 3413         * For a group of mutually exclusive arguments, making the group required {@code multiplicity = "1"} means that
 3414         * one of the arguments in the group must appear on the command line, or a MissingParameterException is thrown.
 3415         * For a group of co-occurring arguments, making the group required means that all arguments in the group must appear on the command line.
 3416         * Ignored if {@link #validate()} is {@code false}. */
 3417        String multiplicity() default "0..1";
 3418        /** Determines whether picocli should validate the rules of this group ({@code true} by default).
 3419         * For a mutually exclusive group validation means verifying that no more than one elements of the group is specified on the command line;
 3420         * for a co-ocurring group validation means verifying that all elements of the group are specified on the command line.
 3421         * Set {@link #validate() validate = false} for groups whose purpose is only to customize the usage help message.
 3422         * @see #multiplicity()
 3423         * @see #heading() */
 3424        boolean validate() default true;
 3425        /** Determines the position in the options list in the usage help message at which this group should be shown.
 3426         * Options with a lower number are shown before options with a higher number.
 3427         * This attribute is only honored if {@link UsageMessageSpec#sortOptions()} is {@code false} for this command.*/
 3428        int order() default -1;
 3429    }
 3430    /**
 3431     * <p>
 3432     * When parsing command line arguments and initializing
 3433     * fields annotated with {@link Option @Option} or {@link Parameters @Parameters},
 3434     * String values can be converted to any type for which a {@code ITypeConverter} is registered.
 3435     * </p><p>
 3436     * This interface defines the contract for classes that know how to convert a String into some domain object.
 3437     * Custom converters can be registered with the {@link #registerConverter(Class, ITypeConverter)} method.
 3438     * </p><p>
 3439     * Java 8 lambdas make it easy to register custom type converters:
 3440     * </p>
 3441     * <pre>
 3442     * commandLine.registerConverter(java.nio.file.Path.class, s -&gt; java.nio.file.Paths.get(s));
 3443     * commandLine.registerConverter(java.time.Duration.class, s -&gt; java.time.Duration.parse(s));</pre>
 3444     * <p>
 3445     * Built-in type converters are pre-registered for the following java 1.5 types:
 3446     * </p>
 3447     * <ul>
 3448     *   <li>all primitive types</li>
 3449     *   <li>all primitive wrapper types: Boolean, Byte, Character, Double, Float, Integer, Long, Short</li>
 3450     *   <li>any enum</li>
 3451     *   <li>java.io.File</li>
 3452     *   <li>java.math.BigDecimal</li>
 3453     *   <li>java.math.BigInteger</li>
 3454     *   <li>java.net.InetAddress</li>
 3455     *   <li>java.net.URI</li>
 3456     *   <li>java.net.URL</li>
 3457     *   <li>java.nio.charset.Charset</li>
 3458     *   <li>java.sql.Time</li>
 3459     *   <li>java.util.Date</li>
 3460     *   <li>java.util.UUID</li>
 3461     *   <li>java.util.regex.Pattern</li>
 3462     *   <li>StringBuilder</li>
 3463     *   <li>CharSequence</li>
 3464     *   <li>String</li>
 3465     * </ul>
 3466     * @param <K> the type of the object that is the result of the conversion
 3467     */
 3468    public interface ITypeConverter<K> {
 3469        /**
 3470         * Converts the specified command line argument value to some domain object.
 3471         * @param value the command line argument String value
 3472         * @return the resulting domain object
 3473         * @throws Exception an exception detailing what went wrong during the conversion
 3474         */
 3475        K convert(String value) throws Exception;
 3476    }
 3477
 3478    /**
 3479     * Provides version information for a command. Commands may configure a provider with the
 3480     * {@link Command#versionProvider()} annotation attribute.
 3481     * @since 2.2 */
 3482    public interface IVersionProvider {
 3483        /**
 3484         * Returns version information for a command.
 3485         * @return version information (each string in the array is displayed on a separate line)
 3486         * @throws Exception an exception detailing what went wrong when obtaining version information
 3487         */
 3488        String[] getVersion() throws Exception;
 3489    }
 3490    private static class NoVersionProvider implements IVersionProvider {
 3491        public String[] getVersion() throws Exception { throw new UnsupportedOperationException(); }
 3492    }
 3493
 3494    /**
 3495     * Provides default value for a command. Commands may configure a provider with the
 3496     * {@link Command#defaultValueProvider()} annotation attribute.
 3497     * @since 3.6 */
 3498    public interface IDefaultValueProvider {
 3499
 3500        /** Returns the default value for an option or positional parameter or {@code null}.
 3501        * The returned value is converted to the type of the option/positional parameter
 3502        * via the same type converter used when populating this option/positional
 3503        * parameter from a command line argument.
 3504        * @param argSpec the option or positional parameter, never {@code null}
 3505        * @return the default value for the option or positional parameter, or {@code null} if
 3506        *       this provider has no default value for the specified option or positional parameter
 3507        * @throws Exception when there was a problem obtaining the default value
 3508        */
 3509        String defaultValue(ArgSpec argSpec) throws Exception;
 3510    }
 3511    private static class NoDefaultProvider implements IDefaultValueProvider {
 3512        public String defaultValue(ArgSpec argSpec) { throw new UnsupportedOperationException(); }
 3513    }
 3514
 3515    /**
 3516     * Creates the {@link Help} instance used to render the usage help message.
 3517     * @since 3.9
 3518     */
 3519    public interface IHelpFactory {
 3520        /** Returns a {@code Help} instance to assist in rendering the usage help message
 3521         * @param commandSpec the command to create usage help for
 3522         * @param colorScheme the color scheme to use when rendering usage help
 3523         * @return a {@code Help} instance
 3524         */
 3525        Help create(CommandSpec commandSpec, Help.ColorScheme colorScheme);
 3526    }
 3527
 3528    private static class DefaultHelpFactory implements IHelpFactory {
 3529        public Help create(CommandSpec commandSpec, Help.ColorScheme colorScheme) {
 3530            return new Help(commandSpec, colorScheme);
 3531        }
 3532    }
 3533
 3534    /**
 3535     * Factory for instantiating classes that are registered declaratively with annotation attributes, like
 3536     * {@link Command#subcommands()}, {@link Option#converter()}, {@link Parameters#converter()} and {@link Command#versionProvider()}.
 3537     * <p>The default factory implementation simply creates a new instance of the specified class when {@link #create(Class)} is invoked.
 3538     * </p><p>
 3539     * You may provide a custom implementation of this interface.
 3540     * For example, a custom factory implementation could delegate to a dependency injection container that provides the requested instance.
 3541     * </p>
 3542     * @see picocli.CommandLine#CommandLine(Object, IFactory)
 3543     * @see #call(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 3544     * @see #run(Class, IFactory, PrintStream, PrintStream, Help.Ansi, String...)
 3545     * @since 2.2 */
 3546    public interface IFactory {
 3547        /**
 3548         * Returns an instance of the specified class.
 3549         * @param cls the class of the object to return
 3550         * @param <K> the type of the object to return
 3551         * @return the instance
 3552         * @throws Exception an exception detailing what went wrong when creating or obtaining the instance
 3553         */
 3554        <K> K create(Class<K> cls) throws Exception;
 3555    }
 3556    /** Returns a default {@link IFactory} implementation. Package-protected for testing purposes. */
 3557    static IFactory defaultFactory() { return new DefaultFactory(); }
 3558    private static class DefaultFactory implements IFactory {
 3559        public <T> T create(Class<T> cls) throws Exception {
 3560            if (cls.isInterface() && Collection.class.isAssignableFrom(cls)) {
 3561                if (List.class.isAssignableFrom(cls)) {
 3562                    return cls.cast(new ArrayList<Object>());
 3563                } else if (SortedSet.class.isAssignableFrom(cls)) {
 3564                    return cls.cast(new TreeSet<Object>());
 3565                } else if (Set.class.isAssignableFrom(cls)) {
 3566                    return cls.cast(new LinkedHashSet<Object>());
 3567                } else if (Queue.class.isAssignableFrom(cls)) {
 3568                    return cls.cast(new LinkedList<Object>()); // ArrayDeque is only available since 1.6
 3569                }
 3570                return cls.cast(new ArrayList<Object>());
 3571            }
 3572            if (Map.class.isAssignableFrom(cls)) {
 3573                try { // if it is an implementation class, instantiate it
 3574                    return cls.cast(cls.getDeclaredConstructor().newInstance());
 3575                } catch (Exception ignored) { }
 3576                return cls.cast(new LinkedHashMap<Object, Object>());
 3577            }
 3578            try {
 3579                return cls.newInstance();
 3580            } catch (Exception ex) {
 3581                Constructor<T> constructor = cls.getDeclaredConstructor();
 3582                constructor.setAccessible(true);
 3583                return constructor.newInstance();
 3584            }
 3585        }
 3586        private static ITypeConverter<?>[] createConverter(IFactory factory, Class<? extends ITypeConverter<?>>[] classes) {
 3587            ITypeConverter<?>[] result = new ITypeConverter<?>[classes.length];
 3588            for (int i = 0; i < classes.length; i++) { result[i] = create(factory, classes[i]); }
 3589            return result;
 3590        }
 3591        static IVersionProvider createVersionProvider(IFactory factory, Class<? extends IVersionProvider> cls) {
 3592            return create(factory, cls);
 3593        }
 3594        static IDefaultValueProvider createDefaultValueProvider(IFactory factory, Class<? extends IDefaultValueProvider> cls) {
 3595            return create(factory, cls);
 3596        }
 3597        static Iterable<String> createCompletionCandidates(IFactory factory, Class<? extends Iterable<String>> cls) {
 3598            return create(factory, cls);
 3599        }
 3600        static <T> T create(IFactory factory, Class<T> cls) {
 3601            try { return factory.create(cls); }
 3602            catch (Exception ex) { throw new InitializationException("Could not instantiate " + cls + ": " + ex, ex); }
 3603        }
 3604    }
 3605    /** Describes the number of parameters required and accepted by an option or a positional parameter.
 3606     * @since 0.9.7
 3607     */
 3608    public static class Range implements Comparable<Range> {
 3609        /** Required number of parameters for an option or positional parameter. */
 3610        public final int min;
 3611        /** Maximum accepted number of parameters for an option or positional parameter. */
 3612        public final int max;
 3613        public final boolean isVariable;
 3614        private final boolean isUnspecified;
 3615        private final String originalValue;
 3616
 3617        /** Constructs a new Range object with the specified parameters.
 3618         * @param min minimum number of required parameters
 3619         * @param max maximum number of allowed parameters (or Integer.MAX_VALUE if variable)
 3620         * @param variable {@code true} if any number or parameters is allowed, {@code false} otherwise
 3621         * @param unspecified {@code true} if no arity was specified on the option/parameter (value is based on type)
 3622         * @param originalValue the original value that was specified on the option or parameter
 3623         */
 3624        public Range(int min, int max, boolean variable, boolean unspecified, String originalValue) {
 3625            if (min < 0 || max < 0) { throw new InitializationException("Invalid negative range (min=" + min + ", max=" + max + ")"); }
 3626            if (min > max) { throw new InitializationException("Invalid range (min=" + min + ", max=" + max + ")"); }
 3627            this.min = min;
 3628            this.max = max;
 3629            this.isVariable = variable;
 3630            this.isUnspecified = unspecified;
 3631            this.originalValue = originalValue;
 3632        }
 3633        /** Returns a new {@code Range} based on the {@link Option#arity()} annotation on the specified field,
 3634         * or the field type's default arity if no arity was specified.
 3635         * @param field the field whose Option annotation to inspect
 3636         * @return a new {@code Range} based on the Option arity annotation on the specified field */
 3637        public static Range optionArity(Field field) { return optionArity(new TypedMember(field)); }
 3638        private static Range optionArity(IAnnotatedElement member) {
 3639            return member.isAnnotationPresent(Option.class)
 3640                    ? adjustForType(Range.valueOf(member.getAnnotation(Option.class).arity()), member)
 3641                    : new Range(0, 0, false, true, "0");
 3642        }
 3643        /** Returns a new {@code Range} based on the {@link Parameters#arity()} annotation on the specified field,
 3644         * or the field type's default arity if no arity was specified.
 3645         * @param field the field whose Parameters annotation to inspect
 3646         * @return a new {@code Range} based on the Parameters arity annotation on the specified field */
 3647        public static Range parameterArity(Field field) { return parameterArity(new TypedMember(field)); }
 3648        private static Range parameterArity(IAnnotatedElement member) {
 3649            if (member.isAnnotationPresent(Parameters.class)) {
 3650                return adjustForType(Range.valueOf(member.getAnnotation(Parameters.class).arity()), member);
 3651            } else {
 3652                return member.isMethodParameter()
 3653                        ? adjustForType(Range.valueOf(""), member)
 3654                        : new Range(0, 0, false, true, "0");
 3655            }
 3656        }
 3657        /** Returns a new {@code Range} based on the {@link Parameters#index()} annotation on the specified field.
 3658         * @param field the field whose Parameters annotation to inspect
 3659         * @return a new {@code Range} based on the Parameters index annotation on the specified field */
 3660        public static Range parameterIndex(Field field) { return parameterIndex(new TypedMember(field)); }
 3661        private static Range parameterIndex(IAnnotatedElement member) {
 3662            if (member.isAnnotationPresent(Parameters.class)) {
 3663                Range result = Range.valueOf(member.getAnnotation(Parameters.class).index());
 3664                if (!result.isUnspecified) { return result; }
 3665            }
 3666            if (member.isMethodParameter()) {
 3667                int min = member.getMethodParamPosition();
 3668                int max = member.isMultiValue() ? Integer.MAX_VALUE : min;
 3669                return new Range(min, max, member.isMultiValue(), false, "");
 3670            }
 3671            return Range.valueOf("*"); // the default
 3672        }
 3673        static Range adjustForType(Range result, IAnnotatedElement member) {
 3674            return result.isUnspecified ? defaultArity(member) : result;
 3675        }
 3676        /** Returns the default arity {@code Range}: for {@link Option options} this is 0 for booleans and 1 for
 3677         * other types, for {@link Parameters parameters} booleans have arity 0, arrays or Collections have
 3678         * arity "0..*", and other types have arity 1.
 3679         * @param field the field whose default arity to return
 3680         * @return a new {@code Range} indicating the default arity of the specified field
 3681         * @since 2.0 */
 3682        public static Range defaultArity(Field field) { return defaultArity(new TypedMember(field)); }
 3683        private static Range defaultArity(IAnnotatedElement member) {
 3684            ITypeInfo info = member.getTypeInfo();
 3685            if (member.isAnnotationPresent(Option.class)) {
 3686                boolean zeroArgs = info.isBoolean() || (info.isMultiValue() && info.getAuxiliaryTypeInfos().get(0).isBoolean());
 3687                return zeroArgs ? Range.valueOf("0").unspecified(true)
 3688                                : Range.valueOf("1").unspecified(true);
 3689            }
 3690            if (info.isMultiValue()) {
 3691                return Range.valueOf("0..1").unspecified(true);
 3692            }
 3693            return Range.valueOf("1").unspecified(true);// for single-valued fields (incl. boolean positional parameters)
 3694        }
 3695        /** Returns the default arity {@code Range} for {@link Option options}: booleans have arity 0, other types have arity 1.
 3696         * @param type the type whose default arity to return
 3697         * @return a new {@code Range} indicating the default arity of the specified type
 3698         * @deprecated use {@link #defaultArity(Field)} instead */
 3699        @Deprecated public static Range defaultArity(Class<?> type) {
 3700            return isBoolean(type) ? Range.valueOf("0").unspecified(true) : Range.valueOf("1").unspecified(true);
 3701        }
 3702        private int size() { return 1 + max - min; }
 3703        static Range parameterCapacity(IAnnotatedElement member) {
 3704            Range arity = parameterArity(member);
 3705            if (!member.isMultiValue()) { return arity; }
 3706            Range index = parameterIndex(member);
 3707            return parameterCapacity(arity, index);
 3708        }
 3709        private static Range parameterCapacity(Range arity, Range index) {
 3710            if (arity.max == 0)    { return arity; }
 3711            if (index.size() == 1) { return arity; }
 3712            if (index.isVariable)  { return Range.valueOf(arity.min + "..*"); }
 3713            if (arity.size() == 1) { return Range.valueOf(arity.min * index.size() + ""); }
 3714            if (arity.isVariable)  { return Range.valueOf(arity.min * index.size() + "..*"); }
 3715            return Range.valueOf(arity.min * index.size() + ".." + arity.max * index.size());
 3716        }
 3717
 3718        /** Leniently parses the specified String as an {@code Range} value and return the result. A range string can
 3719         * be a fixed integer value or a range of the form {@code MIN_VALUE + ".." + MAX_VALUE}. If the
 3720         * {@code MIN_VALUE} string is not numeric, the minimum is zero. If the {@code MAX_VALUE} is not numeric, the
 3721         * range is taken to be variable and the maximum is {@code Integer.MAX_VALUE}.
 3722         * @param range the value range string to parse
 3723         * @return a new {@code Range} value */
 3724        public static Range valueOf(String range) {
 3725            range = range.trim();
 3726            boolean unspecified = range.length() == 0 || range.startsWith(".."); // || range.endsWith("..");
 3727            int min = -1, max = -1;
 3728            boolean variable = false;
 3729            int dots = -1;
 3730            if ((dots = range.indexOf("..")) >= 0) {
 3731                min = parseInt(range.substring(0, dots), 0);
 3732                max = parseInt(range.substring(dots + 2), Integer.MAX_VALUE);
 3733                variable = max == Integer.MAX_VALUE;
 3734            } else {
 3735                max = parseInt(range, Integer.MAX_VALUE);
 3736                variable = max == Integer.MAX_VALUE;
 3737                min = variable ? 0 : max;
 3738            }
 3739            Range result = new Range(min, max, variable, unspecified, range);
 3740            return result;
 3741        }
 3742        private static int parseInt(String str, int defaultValue) {
 3743            try {
 3744                return Integer.parseInt(str);
 3745            } catch (Exception ex) {
 3746                return defaultValue;
 3747            }
 3748        }
 3749        /** Returns a new Range object with the {@code min} value replaced by the specified value.
 3750         * The {@code max} of the returned Range is guaranteed not to be less than the new {@code min} value.
 3751         * @param newMin the {@code min} value of the returned Range object
 3752         * @return a new Range object with the specified {@code min} value */
 3753        public Range min(int newMin) { return new Range(newMin, Math.max(newMin, max), isVariable, isUnspecified, originalValue); }
 3754
 3755        /** Returns a new Range object with the {@code max} value replaced by the specified value.
 3756         * The {@code min} of the returned Range is guaranteed not to be greater than the new {@code max} value.
 3757         * @param newMax the {@code max} value of the returned Range object
 3758         * @return a new Range object with the specified {@code max} value */
 3759        public Range max(int newMax) { return new Range(Math.min(min, newMax), newMax, isVariable, isUnspecified, originalValue); }
 3760
 3761        /** Returns a new Range object with the {@code isUnspecified} value replaced by the specified value.
 3762         * @param unspecified the {@code unspecified} value of the returned Range object
 3763         * @return a new Range object with the specified {@code unspecified} value */
 3764        public Range unspecified(boolean unspecified) { return new Range(min, max, isVariable, unspecified, originalValue); }
 3765        /** Returns {@code true} if this Range is a default value, {@code false} if the user specified this value.
 3766         * @since 4.0 */
 3767        public boolean isUnspecified() { return isUnspecified; }
 3768
 3769        /**
 3770         * Returns {@code true} if this Range includes the specified value, {@code false} otherwise.
 3771         * @param value the value to check
 3772         * @return {@code true} if the specified value is not less than the minimum and not greater than the maximum of this Range
 3773         */
 3774        public boolean contains(int value) { return min <= value && max >= value; }
 3775
 3776        public boolean equals(Object object) {
 3777            if (!(object instanceof Range)) { return false; }
 3778            Range other = (Range) object;
 3779            return other.max == this.max && other.min == this.min && other.isVariable == this.isVariable;
 3780        }
 3781        public int hashCode() {
 3782            return ((17 * 37 + max) * 37 + min) * 37 + (isVariable ? 1 : 0);
 3783        }
 3784        public String toString() {
 3785            return min == max ? String.valueOf(min) : min + ".." + (isVariable ? "*" : max);
 3786        }
 3787        public int compareTo(Range other) {
 3788            int result = min - other.min;
 3789            return (result == 0) ? max - other.max : result;
 3790        }
 3791
 3792        boolean overlaps(Range index) {
 3793            return contains(index.min) || contains(index.max) || index.contains(min) || index.contains(max);
 3794        }
 3795    }
 3796    private static void validatePositionalParameters(List<PositionalParamSpec> positionalParametersFields) {
 3797        int min = 0;
 3798        for (PositionalParamSpec positional : positionalParametersFields) {
 3799            Range index = positional.index();
 3800            if (index.min > min) {
 3801                throw new ParameterIndexGapException("Command definition should have a positional parameter with index=" + min +
 3802                        ". Nearest positional parameter '" + positional.paramLabel() + "' has index=" + index.min);
 3803            }
 3804            min = Math.max(min, index.max);
 3805            min = min == Integer.MAX_VALUE ? min : min + 1;
 3806        }
 3807    }
 3808    @SuppressWarnings("unchecked") private static Stack<String> copy(Stack<String> stack) { return (Stack<String>) stack.clone(); }
 3809    private static <T> Stack<T> reverse(Stack<T> stack) {
 3810        Collections.reverse(stack);
 3811        return stack;
 3812    }
 3813    private static <T> List<T> reverseList(List<T> list) {
 3814        Collections.reverse(list);
 3815        return list;
 3816    }
 3817
 3818    /** This class provides a namespace for classes and interfaces that model concepts and attributes of command line interfaces in picocli.
 3819     * @since 3.0 */
 3820    public static final class Model {
 3821        private Model() {}
 3822
 3823        /** The scope of a binding is the context where the current value should be gotten from or set to.
 3824         * For a field, the scope is the object whose field value to get/set. For a method binding, it is the
 3825         * object on which the method should be invoked.
 3826         * <p>The getter and setter of the scope allow you to change the object onto which the option and positional parameter getters and setters should be applied.</p>
 3827         * @since 4.0
 3828         */
 3829        public interface IScope extends IGetter, ISetter {}
 3830
 3831        /** Customizable getter for obtaining the current value of an option or positional parameter.
 3832         * When an option or positional parameter is matched on the command line, its getter or setter is invoked to capture the value.
 3833         * For example, an option can be bound to a field or a method, and when the option is matched on the command line, the
 3834         * field's value is set or the method is invoked with the option parameter value.
 3835         * @since 3.0 */
 3836        public static interface IGetter {
 3837            /** Returns the current value of the binding. For multi-value options and positional parameters,
 3838             * this method returns an array, collection or map to add values to.
 3839             * @throws PicocliException if a problem occurred while obtaining the current value
 3840             * @throws Exception internally, picocli call sites will catch any exceptions thrown from here and rethrow them wrapped in a PicocliException */
 3841            <T> T get() throws Exception;
 3842        }
 3843        /** Customizable setter for modifying the value of an option or positional parameter.
 3844         * When an option or positional parameter is matched on the command line, its setter is invoked to capture the value.
 3845         * For example, an option can be bound to a field or a method, and when the option is matched on the command line, the
 3846         * field's value is set or the method is invoked with the option parameter value.
 3847         * @since 3.0 */
 3848        public static interface ISetter {
 3849            /** Sets the new value of the option or positional parameter.
 3850             *
 3851             * @param value the new value of the option or positional parameter
 3852             * @param <T> type of the value
 3853             * @return the previous value of the binding (if supported by this binding)
 3854             * @throws PicocliException if a problem occurred while setting the new value
 3855             * @throws Exception internally, picocli call sites will catch any exceptions thrown from here and rethrow them wrapped in a PicocliException */
 3856            <T> T set(T value) throws Exception;
 3857        }
 3858
 3859        /** The {@code CommandSpec} class models a command specification, including the options, positional parameters and subcommands
 3860         * supported by the command, as well as attributes for the version help message and the usage help message of the command.
 3861         * <p>
 3862         * Picocli views a command line application as a hierarchy of commands: there is a top-level command (usually the Java
 3863         * class with the {@code main} method) with optionally a set of command line options, positional parameters and subcommands.
 3864         * Subcommands themselves can have options, positional parameters and nested sub-subcommands to any level of depth.
 3865         * </p><p>
 3866         * The object model has a corresponding hierarchy of {@code CommandSpec} objects, each with a set of {@link OptionSpec},
 3867         * {@link PositionalParamSpec} and {@linkplain CommandLine subcommands} associated with it.
 3868         * This object model is used by the picocli command line interpreter and help message generator.
 3869         * </p><p>Picocli can construct a {@code CommandSpec} automatically from classes with {@link Command @Command}, {@link Option @Option} and
 3870         * {@link Parameters @Parameters} annotations. Alternatively a {@code CommandSpec} can be constructed programmatically.
 3871         * </p>
 3872         * @since 3.0 */
 3873        public static class CommandSpec {
 3874            /** Constant String holding the default program name: {@code "<main class>" }. */
 3875            static final String DEFAULT_COMMAND_NAME = "<main class>";
 3876
 3877            /** Constant Boolean holding the default setting for whether this is a help command: <code>{@value}</code>.*/
 3878            static final Boolean DEFAULT_IS_HELP_COMMAND = Boolean.FALSE;
 3879
 3880            /** Constant Boolean holding the default setting for whether method commands should be added as subcommands: <code>{@value}</code>.*/
 3881            static final Boolean DEFAULT_IS_ADD_METHOD_SUBCOMMANDS = Boolean.TRUE;
 3882
 3883            private final Map<String, CommandLine> commands = new LinkedHashMap<String, CommandLine>();
 3884            private final Map<String, OptionSpec> optionsByNameMap = new LinkedHashMap<String, OptionSpec>();
 3885            private final Map<Character, OptionSpec> posixOptionsByKeyMap = new LinkedHashMap<Character, OptionSpec>();
 3886            private final Map<String, CommandSpec> mixins = new LinkedHashMap<String, CommandSpec>();
 3887            private final List<ArgSpec> requiredArgs = new ArrayList<ArgSpec>();
 3888            private final List<ArgSpec> args = new ArrayList<ArgSpec>();
 3889            private final List<OptionSpec> options = new ArrayList<OptionSpec>();
 3890            private final List<PositionalParamSpec> positionalParameters = new ArrayList<PositionalParamSpec>();
 3891            private final List<UnmatchedArgsBinding> unmatchedArgs = new ArrayList<UnmatchedArgsBinding>();
 3892            private final List<ArgGroupSpec> groups = new ArrayList<ArgGroupSpec>();
 3893            private final ParserSpec parser = new ParserSpec();
 3894            private final UsageMessageSpec usageMessage = new UsageMessageSpec();
 3895
 3896            private final Object userObject;
 3897            private CommandLine commandLine;
 3898            private CommandSpec parent;
 3899            private Boolean isAddMethodSubcommands;
 3900
 3901            private String name;
 3902            private Set<String> aliases = new LinkedHashSet<String>();
 3903            private Boolean isHelpCommand;
 3904            private IVersionProvider versionProvider;
 3905            private IDefaultValueProvider defaultValueProvider;
 3906            private String[] version;
 3907            private String toString;
 3908
 3909            private CommandSpec(Object userObject) { this.userObject = userObject; }
 3910    
 3911            /** Creates and returns a new {@code CommandSpec} without any associated user object. */
 3912            public static CommandSpec create() { return wrapWithoutInspection(null); }
 3913    
 3914            /** Creates and returns a new {@code CommandSpec} with the specified associated user object.
 3915             * The specified user object is <em>not</em> inspected for annotations.
 3916             * @param userObject the associated user object. May be any object, may be {@code null}.
 3917             */
 3918            public static CommandSpec wrapWithoutInspection(Object userObject) { return new CommandSpec(userObject); }
 3919
 3920            /** Creates and returns a new {@code CommandSpec} initialized from the specified associated user object. The specified
 3921             * user object must have at least one {@link Command}, {@link Option} or {@link Parameters} annotation.
 3922             * @param userObject the user object annotated with {@link Command}, {@link Option} and/or {@link Parameters} annotations.
 3923             * @throws InitializationException if the specified object has no picocli annotations or has invalid annotations
 3924             */
 3925            public static CommandSpec forAnnotatedObject(Object userObject) { return forAnnotatedObject(userObject, new DefaultFactory()); }
 3926
 3927            /** Creates and returns a new {@code CommandSpec} initialized from the specified associated user object. The specified
 3928             * user object must have at least one {@link Command}, {@link Option} or {@link Parameters} annotation.
 3929             * @param userObject the user object annotated with {@link Command}, {@link Option} and/or {@link Parameters} annotations.
 3930             * @param factory the factory used to create instances of {@linkplain Command#subcommands() subcommands}, {@linkplain Option#converter() converters}, etc., that are registered declaratively with annotation attributes
 3931             * @throws InitializationException if the specified object has no picocli annotations or has invalid annotations
 3932             */
 3933            public static CommandSpec forAnnotatedObject(Object userObject, IFactory factory) { return CommandReflection.extractCommandSpec(userObject, factory, true); }
 3934
 3935            /** Creates and returns a new {@code CommandSpec} initialized from the specified associated user object. If the specified
 3936             * user object has no {@link Command}, {@link Option} or {@link Parameters} annotations, an empty {@code CommandSpec} is returned.
 3937             * @param userObject the user object annotated with {@link Command}, {@link Option} and/or {@link Parameters} annotations.
 3938             * @throws InitializationException if the specified object has invalid annotations
 3939             */
 3940            public static CommandSpec forAnnotatedObjectLenient(Object userObject) { return forAnnotatedObjectLenient(userObject, new DefaultFactory()); }
 3941
 3942            /** Creates and returns a new {@code CommandSpec} initialized from the specified associated user object. If the specified
 3943             * user object has no {@link Command}, {@link Option} or {@link Parameters} annotations, an empty {@code CommandSpec} is returned.
 3944             * @param userObject the user object annotated with {@link Command}, {@link Option} and/or {@link Parameters} annotations.
 3945             * @param factory the factory used to create instances of {@linkplain Command#subcommands() subcommands}, {@linkplain Option#converter() converters}, etc., that are registered declaratively with annotation attributes
 3946             * @throws InitializationException if the specified object has invalid annotations
 3947             */
 3948            public static CommandSpec forAnnotatedObjectLenient(Object userObject, IFactory factory) { return CommandReflection.extractCommandSpec(userObject, factory, false); }
 3949
 3950            /** Ensures all attributes of this {@code CommandSpec} have a valid value; throws an {@link InitializationException} if this cannot be achieved. */
 3951            void validate() {
 3952                Collections.sort(positionalParameters, new PositionalParametersSorter());
 3953                validatePositionalParameters(positionalParameters);
 3954                List<String> wrongUsageHelpAttr = new ArrayList<String>();
 3955                List<String> wrongVersionHelpAttr = new ArrayList<String>();
 3956                List<String> usageHelpAttr = new ArrayList<String>();
 3957                List<String> versionHelpAttr = new ArrayList<String>();
 3958                for (OptionSpec option : options()) {
 3959                    if (option.usageHelp()) {
 3960                        usageHelpAttr.add(option.longestName());
 3961                        if (!isBoolean(option.type())) { wrongUsageHelpAttr.add(option.longestName()); }
 3962                    }
 3963                    if (option.versionHelp()) {
 3964                        versionHelpAttr.add(option.longestName());
 3965                        if (!isBoolean(option.type())) { wrongVersionHelpAttr.add(option.longestName()); }
 3966                    }
 3967                }
 3968                String wrongType = "Non-boolean options like %s should not be marked as '%s=true'. Usually a command has one %s boolean flag that triggers display of the %s. Alternatively, consider using @Command(mixinStandardHelpOptions = true) on your command instead.";
 3969                String multiple = "Multiple options %s are marked as '%s=true'. Usually a command has only one %s option that triggers display of the %s. Alternatively, consider using @Command(mixinStandardHelpOptions = true) on your command instead.%n";
 3970                if (!wrongUsageHelpAttr.isEmpty()) {
 3971                    throw new InitializationException(String.format(wrongType, wrongUsageHelpAttr, "usageHelp", "--help", "usage help message"));
 3972                }
 3973                if (!wrongVersionHelpAttr.isEmpty()) {
 3974                    throw new InitializationException(String.format(wrongType, wrongVersionHelpAttr, "versionHelp", "--version", "version information"));
 3975                }
 3976                if (usageHelpAttr.size() > 1)   { new Tracer().warn(multiple, usageHelpAttr, "usageHelp", "--help", "usage help message"); }
 3977                if (versionHelpAttr.size() > 1) { new Tracer().warn(multiple, versionHelpAttr, "versionHelp", "--version", "version information"); }
 3978            }
 3979    
 3980            /** Returns the user object associated with this command.
 3981             * @see CommandLine#getCommand() */
 3982            public Object userObject() { return userObject; }
 3983    
 3984            /** Returns the CommandLine constructed with this {@code CommandSpec} model. */
 3985            public CommandLine commandLine() { return commandLine;}
 3986    
 3987            /** Sets the CommandLine constructed with this {@code CommandSpec} model. */
 3988            protected CommandSpec commandLine(CommandLine commandLine) {
 3989                this.commandLine = commandLine;
 3990                for (CommandSpec mixedInSpec : mixins.values()) {
 3991                    mixedInSpec.commandLine(commandLine);
 3992                }
 3993                for (CommandLine sub : commands.values()) {
 3994                    sub.getCommandSpec().parent(this);
 3995                }
 3996                return this;
 3997            }
 3998
 3999            /** Returns the parser specification for this command. */
 4000            public ParserSpec parser() { return parser; }
 4001            /** Initializes the parser specification for this command from the specified settings and returns this commandSpec.*/
 4002            public CommandSpec parser(ParserSpec settings) { parser.initFrom(settings); return this; }
 4003
 4004            /** Returns the usage help message specification for this command. */
 4005            public UsageMessageSpec usageMessage() { return usageMessage; }
 4006            /** Initializes the usageMessage specification for this command from the specified settings and returns this commandSpec.*/
 4007            public CommandSpec usageMessage(UsageMessageSpec settings) { usageMessage.initFrom(settings, this); return this; }
 4008
 4009            /** Returns the resource bundle base name for this command.
 4010             * @return the resource bundle base name from the {@linkplain UsageMessageSpec#messages()}
 4011             * @since 4.0 */
 4012            public String resourceBundleBaseName() { return Messages.resourceBundleBaseName(usageMessage.messages()); }
 4013            /** Initializes the resource bundle for this command: sets the {@link UsageMessageSpec#messages(Messages) UsageMessageSpec.messages} to
 4014             * a {@link Messages Messages} object created from this command spec and the specified bundle, and then sets the
 4015             * {@link ArgSpec#messages(Messages) ArgSpec.messages} of all options and positional parameters in this command
 4016             * to the same {@code Messages} instance. Subcommands are not modified.
 4017             * <p>This method is preferable to {@link #resourceBundle(ResourceBundle)} for pre-Java 8</p>
 4018             * @param resourceBundleBaseName the base name of the ResourceBundle to set, may be {@code null}
 4019             * @return this commandSpec
 4020             * @see #addSubcommand(String, CommandLine)
 4021             * @since 4.0 */
 4022            public CommandSpec resourceBundleBaseName(String resourceBundleBaseName) {
 4023                ResourceBundle bundle = empty(resourceBundleBaseName) ? null : ResourceBundle.getBundle(resourceBundleBaseName);
 4024                setBundle(resourceBundleBaseName, bundle);
 4025                return this;
 4026            }
 4027            /** Returns the resource bundle for this command.
 4028             * @return the resource bundle from the {@linkplain UsageMessageSpec#messages()}
 4029             * @since 3.6 */
 4030            public ResourceBundle resourceBundle() { return Messages.resourceBundle(usageMessage.messages()); }
 4031            /** Initializes the resource bundle for this command: sets the {@link UsageMessageSpec#messages(Messages) UsageMessageSpec.messages} to
 4032             * a {@link Messages Messages} object created from this command spec and the specified bundle, and then sets the
 4033             * {@link ArgSpec#messages(Messages) ArgSpec.messages} of all options and positional parameters in this command
 4034             * to the same {@code Messages} instance. Subcommands are not modified.
 4035             * @param bundle the ResourceBundle to set, may be {@code null}
 4036             * @return this commandSpec
 4037             * @see #addSubcommand(String, CommandLine)
 4038             * @since 3.6 */
 4039            public CommandSpec resourceBundle(ResourceBundle bundle) {
 4040                setBundle(Messages.extractName(bundle), bundle);
 4041                return this;
 4042            }
 4043            private void setBundle(String bundleBaseName, ResourceBundle bundle) {
 4044                usageMessage().messages(new Messages(this, bundleBaseName, bundle));
 4045                updateArgSpecMessages();
 4046            }
 4047            private void updateArgSpecMessages() {
 4048                for (OptionSpec opt : options()) { opt.messages(usageMessage().messages()); }
 4049                for (PositionalParamSpec pos : positionalParameters()) { pos.messages(usageMessage().messages()); }
 4050                for (ArgGroupSpec group : argGroups()) { group.messages(usageMessage().messages()); }
 4051            }
 4052
 4053            /** Returns a read-only view of the subcommand map. */
 4054            public Map<String, CommandLine> subcommands() { return Collections.unmodifiableMap(commands); }
 4055    
 4056            /** Adds the specified subcommand with the specified name.
 4057             * If the specified subcommand does not have a ResourceBundle set, it is initialized to the ResourceBundle of this command spec.
 4058             * @param name subcommand name - when this String is encountered in the command line arguments the subcommand is invoked
 4059             * @param subcommand describes the subcommand to envoke when the name is encountered on the command line
 4060             * @return this {@code CommandSpec} object for method chaining */
 4061            public CommandSpec addSubcommand(String name, CommandSpec subcommand) {
 4062                return addSubcommand(name, new CommandLine(subcommand));
 4063            }
 4064    
 4065            /** Adds the specified subcommand with the specified name.
 4066             * If the specified subcommand does not have a ResourceBundle set, it is initialized to the ResourceBundle of this command spec.
 4067             * @param name subcommand name - when this String is encountered in the command line arguments the subcommand is invoked
 4068             * @param subCommandLine the subcommand to envoke when the name is encountered on the command line
 4069             * @return this {@code CommandSpec} object for method chaining */
 4070            public CommandSpec addSubcommand(String name, CommandLine subCommandLine) {
 4071                Tracer t = new Tracer();
 4072                if (t.isDebug()) {t.debug("Adding subcommand '%s' to '%s'%n", name, this.qualifiedName());}
 4073                CommandLine previous = commands.put(name, subCommandLine);
 4074                if (previous != null && previous != subCommandLine) { throw new InitializationException("Another subcommand named '" + name + "' already exists for command '" + this.name() + "'"); }
 4075                CommandSpec subSpec = subCommandLine.getCommandSpec();
 4076                if (subSpec.name == null) { subSpec.name(name); }
 4077                subSpec.parent(this);
 4078                for (String alias : subSpec.aliases()) {
 4079                    if (t.isDebug()) {t.debug("Adding alias '%s' for subcommand '%s' to '%s'%n", alias, name, this.qualifiedName());}
 4080                    previous = commands.put(alias, subCommandLine);
 4081                    if (previous != null && previous != subCommandLine) { throw new InitializationException("Alias '" + alias + "' for subcommand '" + name + "' is already used by another subcommand of '" + this.name() + "'"); }
 4082                }
 4083                subSpec.initCommandHierarchyWithResourceBundle(resourceBundleBaseName(), resourceBundle());
 4084                return this;
 4085            }
 4086            private void initCommandHierarchyWithResourceBundle(String bundleBaseName, ResourceBundle rb) {
 4087                if (resourceBundle() == null) {
 4088                    setBundle(bundleBaseName, rb);
 4089                }
 4090                for (CommandLine sub : commands.values()) { // percolate down the hierarchy
 4091                    sub.getCommandSpec().initCommandHierarchyWithResourceBundle(bundleBaseName, rb);
 4092                }
 4093            }
 4094
 4095            /** Returns whether method commands should be added as subcommands. Used by the annotation processor.
 4096             * @since 4.0 */
 4097            public boolean isAddMethodSubcommands() { return (isAddMethodSubcommands == null) ? DEFAULT_IS_ADD_METHOD_SUBCOMMANDS : isAddMethodSubcommands; }
 4098            /** Sets whether method commands should be added as subcommands. Used by the annotation processor.
 4099             * @since 4.0 */
 4100            public CommandSpec setAddMethodSubcommands(Boolean addMethodSubcommands) { isAddMethodSubcommands = addMethodSubcommands; return this; }
 4101
 4102            /** Reflects on the class of the {@linkplain #userObject() user object} and registers any command methods
 4103             * (class methods annotated with {@code @Command}) as subcommands.
 4104             *
 4105             * @return this {@link CommandSpec} object for method chaining
 4106             * @see #addMethodSubcommands(IFactory)
 4107             * @see #addSubcommand(String, CommandLine)
 4108             * @since 3.6.0
 4109             */
 4110            public CommandSpec addMethodSubcommands() { return addMethodSubcommands(new DefaultFactory()); }
 4111
 4112            /** Reflects on the class of the {@linkplain #userObject() user object} and registers any command methods
 4113             * (class methods annotated with {@code @Command}) as subcommands.
 4114             * @param factory the factory used to create instances of subcommands, converters, etc., that are registered declaratively with annotation attributes
 4115             * @return this {@link CommandSpec} object for method chaining
 4116             * @see #addSubcommand(String, CommandLine)
 4117             * @since 3.7.0
 4118             */
 4119            public CommandSpec addMethodSubcommands(IFactory factory) {
 4120                if (userObject() instanceof Method) {
 4121                     throw new InitializationException("Cannot discover subcommand methods of this Command Method: " + userObject());
 4122                }
 4123                for (CommandLine sub : createMethodSubcommands(userObject().getClass(), factory)) {
 4124                    addSubcommand(sub.getCommandName(), sub);
 4125                }
 4126                isAddMethodSubcommands = true;
 4127                return this;
 4128            }
 4129            static List<CommandLine> createMethodSubcommands(Class<?> cls, IFactory factory) {
 4130                List<CommandLine> result = new ArrayList<CommandLine>();
 4131                for (Method method : getCommandMethods(cls, null)) {
 4132                    result.add(new CommandLine(method, factory));
 4133                }
 4134                return result;
 4135            }
 4136
 4137            /** Returns the parent command of this subcommand, or {@code null} if this is a top-level command. */
 4138            public CommandSpec parent() { return parent; }
 4139    
 4140            /** Sets the parent command of this subcommand.
 4141             * @return this CommandSpec for method chaining */
 4142            public CommandSpec parent(CommandSpec parent) { this.parent = parent; return this; }
 4143    
 4144            /** Adds the specified option spec or positional parameter spec to the list of configured arguments to expect.
 4145             * @param arg the option spec or positional parameter spec to add
 4146             * @return this CommandSpec for method chaining */
 4147            public CommandSpec add(ArgSpec arg) { return arg.isOption() ? addOption((OptionSpec) arg) : addPositional((PositionalParamSpec) arg); }
 4148    
 4149            /** Adds the specified option spec to the list of configured arguments to expect.
 4150             * The option's {@linkplain OptionSpec#description()} may now return Strings from this
 4151             * CommandSpec's {@linkplain UsageMessageSpec#messages() messages}.
 4152             * The option parameter's {@linkplain OptionSpec#defaultValueString()} may
 4153             * now return Strings from this CommandSpec's {@link CommandSpec#defaultValueProvider()} IDefaultValueProvider}.
 4154             * @param option the option spec to add
 4155             * @return this CommandSpec for method chaining
 4156             * @throws DuplicateOptionAnnotationsException if any of the names of the specified option is the same as the name of another option */
 4157            public CommandSpec addOption(OptionSpec option) {
 4158                for (String name : option.names()) { // cannot be null or empty
 4159                    OptionSpec existing = optionsByNameMap.put(name, option);
 4160                    if (existing != null) { /* was: && !existing.equals(option)) {*/ // since 4.0 ArgGroups: an option cannot be in multiple groups
 4161                        throw DuplicateOptionAnnotationsException.create(name, option, existing);
 4162                    }
 4163                    if (name.length() == 2 && name.startsWith("-")) { posixOptionsByKeyMap.put(name.charAt(1), option); }
 4164                }
 4165                options.add(option);
 4166                return addArg(option);
 4167            }
 4168            /** Adds the specified positional parameter spec to the list of configured arguments to expect.
 4169             * The positional parameter's {@linkplain PositionalParamSpec#description()} may
 4170             * now return Strings from this CommandSpec's {@linkplain UsageMessageSpec#messages() messages}.
 4171             * The positional parameter's {@linkplain PositionalParamSpec#defaultValueString()} may
 4172             * now return Strings from this CommandSpec's {@link CommandSpec#defaultValueProvider()} IDefaultValueProvider}.
 4173             * @param positional the positional parameter spec to add
 4174             * @return this CommandSpec for method chaining */
 4175            public CommandSpec addPositional(PositionalParamSpec positional) {
 4176                positionalParameters.add(positional);
 4177                return addArg(positional);
 4178            }
 4179            private CommandSpec addArg(ArgSpec arg) {
 4180                args.add(arg);
 4181                if (arg.required() && arg.group() == null) { requiredArgs.add(arg); }
 4182                arg.messages(usageMessage().messages());
 4183                arg.commandSpec = this;
 4184                return this;
 4185            }
 4186
 4187            /** Adds the specified {@linkplain ArgGroupSpec argument group} to the groups in this command.
 4188             * @param group the group spec to add
 4189             * @return this CommandSpec for method chaining
 4190             * @throws InitializationException if the specified group or one of its {@linkplain ArgGroupSpec#parentGroup() ancestors} has already been added
 4191             * @since 4.0 */
 4192            public CommandSpec addArgGroup(ArgGroupSpec group) {
 4193                Assert.notNull(group, "group");
 4194                if (group.parentGroup() != null) {
 4195                    throw new InitializationException("Groups that are part of another group should not be added to a command. Add only the top-level group.");
 4196                }
 4197                check(group, flatten(groups, new HashSet<ArgGroupSpec>()));
 4198                this.groups.add(group);
 4199                addGroupArgsToCommand(group, new HashMap<String, ArgGroupSpec>());
 4200                return this;
 4201            }
 4202            private void addGroupArgsToCommand(ArgGroupSpec group, Map<String, ArgGroupSpec> added) {
 4203                for (ArgSpec arg : group.args()) {
 4204                    if (arg.isOption()) {
 4205                        for (String name : ((OptionSpec) arg).names()) {
 4206                            if (added.containsKey(name)) {
 4207                                throw new DuplicateNameException("An option cannot be in multiple groups but " + name + " is in " + group.synopsis() + " and " + added.get(name).synopsis() + ". Refactor to avoid this. For example, (-a | (-a -b)) can be rewritten as (-a [-b]), and (-a -b | -a -c) can be rewritten as (-a (-b | -c)).");
 4208                            }
 4209                        }
 4210                        for (String name : ((OptionSpec) arg).names()) { added.put(name, group); }
 4211                    }
 4212                    add(arg);
 4213                }
 4214                for (ArgGroupSpec sub : group.subgroups()) { addGroupArgsToCommand(sub, added); }
 4215            }
 4216            private Set<ArgGroupSpec> flatten(Collection<ArgGroupSpec> groups, Set<ArgGroupSpec> result) {
 4217                for (ArgGroupSpec group : groups) { flatten(group, result); } return result;
 4218            }
 4219            private Set<ArgGroupSpec> flatten(ArgGroupSpec group, Set<ArgGroupSpec> result) {
 4220                result.add(group);
 4221                for (ArgGroupSpec sub : group.subgroups()) { flatten(sub, result); }
 4222                return result;
 4223            }
 4224            private void check(ArgGroupSpec group, Set<ArgGroupSpec> existing) {
 4225                if (existing.contains(group)) {
 4226                    throw new InitializationException("The specified group " + group.synopsis() + " has already been added to the " + qualifiedName() + " command.");
 4227                }
 4228                for (ArgGroupSpec sub : group.subgroups()) { check(sub, existing); }
 4229            }
 4230
 4231            /** Adds the specified mixin {@code CommandSpec} object to the map of mixins for this command.
 4232             * @param name the name that can be used to later retrieve the mixin
 4233             * @param mixin the mixin whose options and positional parameters and other attributes to add to this command
 4234             * @return this CommandSpec for method chaining */
 4235            public CommandSpec addMixin(String name, CommandSpec mixin) {
 4236                mixins.put(name, mixin);
 4237    
 4238                parser.initSeparator(mixin.parser.separator());
 4239                initName(mixin.name());
 4240                initVersion(mixin.version());
 4241                initHelpCommand(mixin.helpCommand());
 4242                initVersionProvider(mixin.versionProvider());
 4243                initDefaultValueProvider(mixin.defaultValueProvider());
 4244                usageMessage.initFromMixin(mixin.usageMessage, this);
 4245
 4246                for (Map.Entry<String, CommandLine> entry : mixin.subcommands().entrySet()) {
 4247                    addSubcommand(entry.getKey(), entry.getValue());
 4248                }
 4249                for (OptionSpec optionSpec         : mixin.options())              { addOption(optionSpec); }
 4250                for (PositionalParamSpec paramSpec : mixin.positionalParameters()) { addPositional(paramSpec); }
 4251                return this;
 4252            }
 4253
 4254            /** Adds the specified {@code UnmatchedArgsBinding} to the list of model objects to capture unmatched arguments for this command.
 4255             * @param spec the unmatched arguments binding to capture unmatched arguments
 4256             * @return this CommandSpec for method chaining */
 4257            public CommandSpec addUnmatchedArgsBinding(UnmatchedArgsBinding spec) { unmatchedArgs.add(spec); parser().unmatchedArgumentsAllowed(true); return this; }
 4258    
 4259            /** Returns a map of the mixin names to mixin {@code CommandSpec} objects configured for this command.
 4260             * @return an immutable map of mixins added to this command. */
 4261            public Map<String, CommandSpec> mixins() { return Collections.unmodifiableMap(mixins); }
 4262    
 4263            /** Returns the list of options configured for this command.
 4264             * @return an immutable list of options that this command recognizes. */
 4265            public List<OptionSpec> options() { return Collections.unmodifiableList(options); }
 4266    
 4267            /** Returns the list of positional parameters configured for this command.
 4268             * @return an immutable list of positional parameters that this command recognizes. */
 4269            public List<PositionalParamSpec> positionalParameters() { return Collections.unmodifiableList(positionalParameters); }
 4270
 4271            /** Returns the {@linkplain ArgGroupSpec argument groups} in this command.
 4272             * @return an immutable list of groups of options and positional parameters in this command
 4273             * @since 4.0 */
 4274            public List<ArgGroupSpec> argGroups() { return Collections.unmodifiableList(groups); }
 4275
 4276            /** Returns a map of the option names to option spec objects configured for this command.
 4277             * @return an immutable map of options that this command recognizes. */
 4278            public Map<String, OptionSpec> optionsMap() { return Collections.unmodifiableMap(optionsByNameMap); }
 4279    
 4280            /** Returns a map of the short (single character) option names to option spec objects configured for this command.
 4281             * @return an immutable map of options that this command recognizes. */
 4282            public Map<Character, OptionSpec> posixOptionsMap() { return Collections.unmodifiableMap(posixOptionsByKeyMap); }
 4283
 4284            /** Returns the list of required options and positional parameters configured for this command.
 4285             * This does not include options and positional parameters that are part of a {@linkplain ArgGroupSpec group}.
 4286             * @return an immutable list of the required options and positional parameters for this command. */
 4287            public List<ArgSpec> requiredArgs() { return Collections.unmodifiableList(requiredArgs); }
 4288
 4289            /** Returns the list of {@link UnmatchedArgsBinding UnmatchedArgumentsBindings} configured for this command;
 4290             * each {@code UnmatchedArgsBinding} captures the arguments that could not be matched to any options or positional parameters. */
 4291            public List<UnmatchedArgsBinding> unmatchedArgsBindings() { return Collections.unmodifiableList(unmatchedArgs); }
 4292    
 4293            /** Returns name of this command. Used in the synopsis line of the help message.
 4294             * {@link #DEFAULT_COMMAND_NAME} by default, initialized from {@link Command#name()} if defined.
 4295             * @see #qualifiedName() */
 4296            public String name() { return (name == null) ? DEFAULT_COMMAND_NAME : name; }
 4297
 4298            /** Returns the alias command names of this subcommand.
 4299             * @since 3.1 */
 4300            public String[] aliases() { return aliases.toArray(new String[0]); }
 4301
 4302            /** Returns all names of this command, including {@link #name()} and {@link #aliases()}.
 4303             * @since 3.9 */
 4304            public Set<String> names() {
 4305                Set<String> result = new LinkedHashSet<String>();
 4306                result.add(name());
 4307                result.addAll(Arrays.asList(aliases()));
 4308                return result;
 4309            }
 4310
 4311            /** Returns the list of all options and positional parameters configured for this command.
 4312             * @return an immutable list of all options and positional parameters for this command. */
 4313            public List<ArgSpec> args() { return Collections.unmodifiableList(args); }
 4314            Object[] argValues() {
 4315                Map<Class<?>, CommandSpec> allMixins = null;
 4316                int argsLength = args.size();
 4317                int shift = 0;
 4318                for (Map.Entry<String, CommandSpec> mixinEntry : mixins.entrySet()) {
 4319                    if (mixinEntry.getKey().equals(AutoHelpMixin.KEY)) {
 4320                        shift = 2;
 4321                        argsLength -= shift;
 4322                        continue;
 4323                    }
 4324                    CommandSpec mixin = mixinEntry.getValue();
 4325                    int mixinArgs = mixin.args.size();
 4326                    argsLength -= (mixinArgs - 1); // subtract 1 because that's the mixin
 4327                    if (allMixins == null) {
 4328                        allMixins = new IdentityHashMap<Class<?>, CommandSpec>(mixins.size());
 4329                    }
 4330                    allMixins.put(mixin.userObject.getClass(), mixin);
 4331                }
 4332
 4333                Object[] values = new Object[argsLength];
 4334                if (allMixins == null) {
 4335                    for (int i = 0; i < values.length; i++) { values[i] = args.get(i + shift).getValue(); }
 4336                } else {
 4337                    int argIndex = shift;
 4338                    Class<?>[] methodParams = ((Method) userObject).getParameterTypes();
 4339                    for (int i = 0; i < methodParams.length; i++) {
 4340                        final Class<?> param = methodParams[i];
 4341                        CommandSpec mixin = allMixins.remove(param);
 4342                        if (mixin == null) {
 4343                            values[i] = args.get(argIndex++).getValue();
 4344                        } else {
 4345                            values[i] = mixin.userObject;
 4346                            argIndex += mixin.args.size();
 4347                        }
 4348                    }
 4349                }
 4350                return values;
 4351            }
 4352
 4353            /** Returns the String to use as the program name in the synopsis line of the help message:
 4354             * this command's {@link #name() name}, preceded by the qualified name of the parent command, if any, separated by a space.
 4355             * @return {@link #DEFAULT_COMMAND_NAME} by default, initialized from {@link Command#name()} and the parent command if defined.
 4356             * @since 3.0.1 */
 4357            public String qualifiedName() { return qualifiedName(" "); }
 4358            /** Returns this command's fully qualified name, which is its {@link #name() name}, preceded by the qualified name of the parent command, if this command has a parent command.
 4359             * @return {@link #DEFAULT_COMMAND_NAME} by default, initialized from {@link Command#name()} and the parent command if any.
 4360             * @param separator the string to put between the names of the commands in the hierarchy
 4361             * @since 3.6 */
 4362            public String qualifiedName(String separator) {
 4363                String result = name();
 4364                if (parent() != null) { result = parent().qualifiedName(separator) + separator + result; }
 4365                return result;
 4366            }
 4367
 4368            /** Returns version information for this command, to print to the console when the user specifies an
 4369             * {@linkplain OptionSpec#versionHelp() option} to request version help. This is not part of the usage help message.
 4370             * @return the version strings generated by the {@link #versionProvider() version provider} if one is set, otherwise the {@linkplain #version(String...) version literals}*/
 4371            public String[] version() {
 4372                if (versionProvider != null) {
 4373                    try {
 4374                        return versionProvider.getVersion();
 4375                    } catch (Exception ex) {
 4376                        String msg = "Could not get version info from " + versionProvider + ": " + ex;
 4377                        throw new ExecutionException(this.commandLine, msg, ex);
 4378                    }
 4379                }
 4380                return version == null ? UsageMessageSpec.DEFAULT_MULTI_LINE : version;
 4381            }
 4382    
 4383            /** Returns the version provider for this command, to generate the {@link #version()} strings.
 4384             * @return the version provider or {@code null} if the version strings should be returned from the {@linkplain #version(String...) version literals}.*/
 4385            public IVersionProvider versionProvider() { return versionProvider; }
 4386
 4387            /** Returns whether this subcommand is a help command, and required options and positional
 4388             * parameters of the parent command should not be validated.
 4389             * @return {@code true} if this subcommand is a help command and picocli should not check for missing required
 4390             *      options and positional parameters on the parent command
 4391             * @see Command#helpCommand() */
 4392            public boolean helpCommand() { return (isHelpCommand == null) ? DEFAULT_IS_HELP_COMMAND : isHelpCommand; }
 4393
 4394            /** Returns {@code true} if the standard help options have been mixed in with this command, {@code false} otherwise. */
 4395            public boolean mixinStandardHelpOptions() { return mixins.containsKey(AutoHelpMixin.KEY); }
 4396
 4397            /** Returns a string representation of this command, used in error messages and trace messages. */
 4398            public String toString() { return toString; }
 4399
 4400            /** Sets the String to use as the program name in the synopsis line of the help message.
 4401             * @return this CommandSpec for method chaining */
 4402            public CommandSpec name(String name) { this.name = name; return this; }
 4403
 4404            /** Sets the alternative names by which this subcommand is recognized on the command line.
 4405             * @return this CommandSpec for method chaining
 4406             * @since 3.1 */
 4407            public CommandSpec aliases(String... aliases) {
 4408                this.aliases = new LinkedHashSet<String>(Arrays.asList(aliases == null ? new String[0] : aliases));
 4409                return this;
 4410            }
 4411
 4412            /** Returns the default value provider for this command.
 4413             * @return the default value provider or {@code null}
 4414             * @since 3.6 */
 4415            public IDefaultValueProvider defaultValueProvider() { return defaultValueProvider; }
 4416
 4417            /** Sets default value provider for this command.
 4418             * @param defaultValueProvider the default value provider to use, or {@code null}.
 4419             * @return this CommandSpec for method chaining
 4420             * @since 3.6 */
 4421            public CommandSpec defaultValueProvider(IDefaultValueProvider  defaultValueProvider) { this.defaultValueProvider = defaultValueProvider; return this; }
 4422
 4423            /** Sets version information literals for this command, to print to the console when the user specifies an
 4424             * {@linkplain OptionSpec#versionHelp() option} to request version help. Only used if no {@link #versionProvider() versionProvider} is set.
 4425             * @return this CommandSpec for method chaining */
 4426            public CommandSpec version(String... version) { this.version = version; return this; }
 4427    
 4428            /** Sets version provider for this command, to generate the {@link #version()} strings.
 4429             * @param versionProvider the version provider to use to generate the version strings, or {@code null} if the {@linkplain #version(String...) version literals} should be used.
 4430             * @return this CommandSpec for method chaining */
 4431            public CommandSpec versionProvider(IVersionProvider versionProvider) { this.versionProvider = versionProvider; return this; }
 4432
 4433            /** Sets whether this is a help command and required parameter checking should be suspended.
 4434             * @return this CommandSpec for method chaining
 4435             * @see Command#helpCommand() */
 4436            public CommandSpec helpCommand(boolean newValue) {isHelpCommand = newValue; return this;}
 4437
 4438            /** Sets whether the standard help options should be mixed in with this command.
 4439             * @return this CommandSpec for method chaining
 4440             * @see Command#mixinStandardHelpOptions() */
 4441            public CommandSpec mixinStandardHelpOptions(boolean newValue) {
 4442                if (newValue) {
 4443                    CommandSpec mixin = CommandSpec.forAnnotatedObject(new AutoHelpMixin(), new DefaultFactory());
 4444                    addMixin(AutoHelpMixin.KEY, mixin);
 4445                } else {
 4446                    CommandSpec helpMixin = mixins.remove(AutoHelpMixin.KEY);
 4447                    if (helpMixin != null) {
 4448                        options.removeAll(helpMixin.options);
 4449                        for (OptionSpec option : helpMixin.options()) {
 4450                            for (String name : option.names) {
 4451                                optionsByNameMap.remove(name);
 4452                                if (name.length() == 2 && name.startsWith("-")) { posixOptionsByKeyMap.remove(name.charAt(1)); }
 4453                            }
 4454                        }
 4455                    }
 4456                }
 4457                return this;
 4458            }
 4459
 4460            /** Sets the string representation of this command, used in error messages and trace messages.
 4461             * @param newValue the string representation
 4462             * @return this CommandSpec for method chaining */
 4463            public CommandSpec withToString(String newValue) { this.toString = newValue; return this; }
 4464
 4465            /**
 4466             * Updates the following attributes from the specified {@code @Command} annotation:
 4467             * aliases, {@link ParserSpec#separator() parser separator}, command name, version, help command,
 4468             * version provider, default provider and {@link UsageMessageSpec usage message spec}.
 4469             * @param cmd the {@code @Command} annotation to get attribute values from
 4470             * @param factory factory used to instantiate classes
 4471             * @since 3.7
 4472             */
 4473            public void updateCommandAttributes(Command cmd, IFactory factory) {
 4474                aliases(cmd.aliases());
 4475                parser().updateSeparator(cmd.separator());
 4476                updateName(cmd.name());
 4477                updateVersion(cmd.version());
 4478                updateHelpCommand(cmd.helpCommand());
 4479                updateAddMethodSubcommands(cmd.addMethodSubcommands());
 4480                usageMessage().updateFromCommand(cmd, this);
 4481
 4482                if (factory != null) {
 4483                    updateVersionProvider(cmd.versionProvider(), factory);
 4484                    initDefaultValueProvider(cmd.defaultValueProvider(), factory);
 4485                }
 4486            }
 4487
 4488            void initName(String value)                 { if (initializable(name, value, DEFAULT_COMMAND_NAME))                           {name = value;} }
 4489            void initHelpCommand(boolean value)         { if (initializable(isHelpCommand, value, DEFAULT_IS_HELP_COMMAND))               {isHelpCommand = value;} }
 4490            void initVersion(String[] value)            { if (initializable(version, value, UsageMessageSpec.DEFAULT_MULTI_LINE))         {version = value.clone();} }
 4491            void initVersionProvider(IVersionProvider value) { if (versionProvider == null) { versionProvider = value; } }
 4492            void initDefaultValueProvider(IDefaultValueProvider value) { if (defaultValueProvider == null) { defaultValueProvider = value; } }
 4493            void initDefaultValueProvider(Class<? extends IDefaultValueProvider> value, IFactory factory) {
 4494                if (initializable(defaultValueProvider, value, NoDefaultProvider.class)) { defaultValueProvider = (DefaultFactory.createDefaultValueProvider(factory, value)); }
 4495            }
 4496            void updateName(String value)               { if (isNonDefault(value, DEFAULT_COMMAND_NAME))                 {name = value;} }
 4497            void updateHelpCommand(boolean value)       { if (isNonDefault(value, DEFAULT_IS_HELP_COMMAND))              {isHelpCommand = value;} }
 4498            void updateAddMethodSubcommands(boolean value) { if (isNonDefault(value, DEFAULT_IS_ADD_METHOD_SUBCOMMANDS)) {isAddMethodSubcommands = value;} }
 4499            void updateVersion(String[] value)          { if (isNonDefault(value, UsageMessageSpec.DEFAULT_MULTI_LINE))  {version = value.clone();} }
 4500            void updateVersionProvider(Class<? extends IVersionProvider> value, IFactory factory) {
 4501                if (isNonDefault(value, NoVersionProvider.class)) { versionProvider = (DefaultFactory.createVersionProvider(factory, value)); }
 4502            }
 4503
 4504            /** Returns the option with the specified short name, or {@code null} if no option with that name is defined for this command. */
 4505            public OptionSpec findOption(char shortName) { return findOption(shortName, options()); }
 4506            /** Returns the option with the specified name, or {@code null} if no option with that name is defined for this command.
 4507             * @param name used to search the options. May include option name prefix characters or not. */
 4508            public OptionSpec findOption(String name) { return findOption(name, options()); }
 4509
 4510            static OptionSpec findOption(char shortName, Iterable<OptionSpec> options) {
 4511                for (OptionSpec option : options) {
 4512                    for (String name : option.names()) {
 4513                        if (name.length() == 2 && name.charAt(0) == '-' && name.charAt(1) == shortName) { return option; }
 4514                        if (name.length() == 1 && name.charAt(0) == shortName) { return option; }
 4515                    }
 4516                }
 4517                return null;
 4518            }
 4519            static OptionSpec findOption(String name, List<OptionSpec> options) {
 4520                for (OptionSpec option : options) {
 4521                    for (String prefixed : option.names()) {
 4522                        if (prefixed.equals(name) || stripPrefix(prefixed).equals(name)) { return option; }
 4523                    }
 4524                }
 4525                return null;
 4526            }
 4527            static String stripPrefix(String prefixed) {
 4528                for (int i = 0; i < prefixed.length(); i++) {
 4529                    if (Character.isJavaIdentifierPart(prefixed.charAt(i))) { return prefixed.substring(i); }
 4530                }
 4531                return prefixed;
 4532            }
 4533            List<String> findOptionNamesWithPrefix(String prefix) {
 4534                List<String> result = new ArrayList<String>();
 4535                for (OptionSpec option : options()) {
 4536                    for (String name : option.names()) {
 4537                        if (stripPrefix(name).startsWith(prefix)) { result.add(name); }
 4538                    }
 4539                }
 4540                return result;
 4541            }
 4542
 4543            boolean resemblesOption(String arg, Tracer tracer) {
 4544                if (parser().unmatchedOptionsArePositionalParams()) {
 4545                    if (tracer != null && tracer.isDebug()) {tracer.debug("Parser is configured to treat all unmatched options as positional parameter%n", arg);}
 4546                    return false;
 4547                }
 4548                if (arg.length() == 1) {
 4549                    if (tracer != null && tracer.isDebug()) {tracer.debug("Single-character arguments that don't match known options are considered positional parameters%n", arg);}
 4550                    return false;
 4551                }
 4552                if (options().isEmpty()) {
 4553                    boolean result = arg.startsWith("-");
 4554                    if (tracer != null && tracer.isDebug()) {tracer.debug("'%s' %s an option%n", arg, (result ? "resembles" : "doesn't resemble"));}
 4555                    return result;
 4556                }
 4557                int count = 0;
 4558                for (String optionName : optionsMap().keySet()) {
 4559                    for (int i = 0; i < arg.length(); i++) {
 4560                        if (optionName.length() > i && arg.charAt(i) == optionName.charAt(i)) { count++; } else { break; }
 4561                    }
 4562                }
 4563                boolean result = count > 0 && count * 10 >= optionsMap().size() * 9; // at least one prefix char in common with 9 out of 10 options
 4564                if (tracer != null && tracer.isDebug()) {tracer.debug("'%s' %s an option: %d matching prefix chars out of %d option names%n", arg, (result ? "resembles" : "doesn't resemble"), count, optionsMap().size());}
 4565                return result;
 4566            }
 4567        }
 4568        private static boolean initializable(Object current, Object candidate, Object defaultValue) {
 4569            return current == null && isNonDefault(candidate, defaultValue);
 4570        }
 4571        private static boolean initializable(Object current, Object[] candidate, Object[] defaultValue) {
 4572            return current == null && isNonDefault(candidate, defaultValue);
 4573        }
 4574        private static boolean isNonDefault(Object candidate, Object defaultValue) {
 4575            return !Assert.notNull(defaultValue, "defaultValue").equals(candidate);
 4576        }
 4577        private static boolean isNonDefault(Object[] candidate, Object[] defaultValue) {
 4578            return !Arrays.equals(Assert.notNull(defaultValue, "defaultValue"), candidate);
 4579        }
 4580        /** Models the usage help message specification and can be used to customize the usage help message.
 4581         * <p>
 4582         * This class provides two ways to customize the usage help message:
 4583         * </p>
 4584         * <ul>
 4585         *     <li>Change the text of the predefined sections (this may also be done declaratively using the annotations)</li>
 4586         *     <li>Add custom sections, or remove or re-order predefined sections</li>
 4587         * </ul>
 4588         * <p>
 4589         * The pre-defined sections have getters and setters that return a String (or array of Strings). For example:
 4590         * {@link #description()} and {@link #description(String...)} or {@link #header()} and {@link #header(String...)}.
 4591         * </p><p>
 4592         * Changing the section order, or adding custom sections can be accomplished with {@link #sectionKeys(List)} and {@link #sectionMap(Map)}.
 4593         * This gives complete freedom on how a usage help message section is rendered, but it also means that the {@linkplain IHelpSectionRenderer section renderer}
 4594         * is responsible for all aspects of rendering the section, including layout and emitting ANSI escape codes.
 4595         * The {@link Help.TextTable} and {@link Help.Ansi.Text} classes, and the {@link CommandLine.Help.Ansi#string(String)} and {@link CommandLine.Help.Ansi#text(String)} methods may be useful.
 4596         * </p><p>
 4597         * The usage help message is created more or less like this:
 4598         * </p>
 4599         * <pre>
 4600         * // CommandLine.usage(...) or CommandLine.getUsageMessage(...)
 4601         * Help.ColorScheme colorScheme = Help.defaultColorScheme(Help.Ansi.AUTO);
 4602         * Help help = getHelpFactory().create(getCommandSpec(), colorScheme)
 4603         * StringBuilder result = new StringBuilder();
 4604         * for (String key : getHelpSectionKeys()) {
 4605         *     IHelpSectionRenderer renderer = getHelpSectionMap().get(key);
 4606         *     if (renderer != null) { result.append(renderer.render(help)); }
 4607         * }
 4608         * // return or print result
 4609         * </pre>
 4610         * <p>
 4611         * Where the default {@linkplain #sectionMap() help section map} is constructed like this:</p>
 4612         * <pre>{@code
 4613         * // The default section renderers delegate to methods in Help for their implementation
 4614         * // (using Java 8 lambda notation for brevity):
 4615         * Map<String, IHelpSectionRenderer> sectionMap = new HashMap<>();
 4616         * sectionMap.put(SECTION_KEY_HEADER_HEADING,         help -> help.headerHeading());
 4617         * sectionMap.put(SECTION_KEY_HEADER,                 help -> help.header());
 4618         * sectionMap.put(SECTION_KEY_SYNOPSIS_HEADING,       help -> help.synopsisHeading());      //e.g. Usage:
 4619         * sectionMap.put(SECTION_KEY_SYNOPSIS,               help -> help.synopsis(help.synopsisHeadingLength())); //e.g. <cmd> [OPTIONS] <subcmd> [COMMAND-OPTIONS] [ARGUMENTS]
 4620         * sectionMap.put(SECTION_KEY_DESCRIPTION_HEADING,    help -> help.descriptionHeading());   //e.g. %nDescription:%n%n
 4621         * sectionMap.put(SECTION_KEY_DESCRIPTION,            help -> help.description());          //e.g. {"Converts foos to bars.", "Use options to control conversion mode."}
 4622         * sectionMap.put(SECTION_KEY_PARAMETER_LIST_HEADING, help -> help.parameterListHeading()); //e.g. %nPositional parameters:%n%n
 4623         * sectionMap.put(SECTION_KEY_PARAMETER_LIST,         help -> help.parameterList());        //e.g. [FILE...] the files to convert
 4624         * sectionMap.put(SECTION_KEY_OPTION_LIST_HEADING,    help -> help.optionListHeading());    //e.g. %nOptions:%n%n
 4625         * sectionMap.put(SECTION_KEY_OPTION_LIST,            help -> help.optionList());           //e.g. -h, --help   displays this help and exits
 4626         * sectionMap.put(SECTION_KEY_COMMAND_LIST_HEADING,   help -> help.commandListHeading());   //e.g. %nCommands:%n%n
 4627         * sectionMap.put(SECTION_KEY_COMMAND_LIST,           help -> help.commandList());          //e.g.    add       adds the frup to the frooble
 4628         * sectionMap.put(SECTION_KEY_FOOTER_HEADING,         help -> help.footerHeading());
 4629         * sectionMap.put(SECTION_KEY_FOOTER,                 help -> help.footer());
 4630         * }</pre>
 4631         *
 4632         * @since 3.0 */
 4633        public static class UsageMessageSpec {
 4634
 4635            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Header Heading section.
 4636             * The default renderer for this section calls {@link Help#headerHeading(Object...)}.
 4637             * @since 3.9 */
 4638            public static final String SECTION_KEY_HEADER_HEADING = "headerHeading";
 4639
 4640            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Header section.
 4641             * The default renderer for this section calls {@link Help#header(Object...)}.
 4642             * @since 3.9 */
 4643            public static final String SECTION_KEY_HEADER = "header";
 4644
 4645            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Synopsis Heading section.
 4646             * The default renderer for this section calls {@link Help#synopsisHeading(Object...)}.
 4647             * @since 3.9 */
 4648            public static final String SECTION_KEY_SYNOPSIS_HEADING = "synopsisHeading";
 4649
 4650            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Synopsis section.
 4651             * The default renderer for this section calls {@link Help#synopsis(int)}.
 4652             * @since 3.9 */
 4653            public static final String SECTION_KEY_SYNOPSIS = "synopsis";
 4654
 4655            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Description Heading section.
 4656             * The default renderer for this section calls {@link Help#descriptionHeading(Object...)}.
 4657             * @since 3.9 */
 4658            public static final String SECTION_KEY_DESCRIPTION_HEADING = "descriptionHeading";
 4659
 4660            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Description section.
 4661             * The default renderer for this section calls {@link Help#description(Object...)}.
 4662             * @since 3.9 */
 4663            public static final String SECTION_KEY_DESCRIPTION = "description";
 4664
 4665            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Parameter List Heading section.
 4666             * The default renderer for this section calls {@link Help#parameterListHeading(Object...)}.
 4667             * @since 3.9 */
 4668            public static final String SECTION_KEY_PARAMETER_LIST_HEADING = "parameterListHeading";
 4669
 4670            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Parameter List section.
 4671             * The default renderer for this section calls {@link Help#parameterList()}.
 4672             * @since 3.9 */
 4673            public static final String SECTION_KEY_PARAMETER_LIST = "parameterList";
 4674
 4675            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Option List Heading section.
 4676             * The default renderer for this section calls {@link Help#optionListHeading(Object...)}.
 4677             * @since 3.9 */
 4678            public static final String SECTION_KEY_OPTION_LIST_HEADING = "optionListHeading";
 4679
 4680            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Option List section.
 4681             * The default renderer for this section calls {@link Help#optionList()}.
 4682             * @since 3.9 */
 4683            public static final String SECTION_KEY_OPTION_LIST = "optionList";
 4684
 4685            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Subcommand List Heading section.
 4686             * The default renderer for this section calls {@link Help#commandListHeading(Object...)}.
 4687             * @since 3.9 */
 4688            public static final String SECTION_KEY_COMMAND_LIST_HEADING = "commandListHeading";
 4689
 4690            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Subcommand List section.
 4691             * The default renderer for this section calls {@link Help#commandList()}.
 4692             * @since 3.9 */
 4693            public static final String SECTION_KEY_COMMAND_LIST = "commandList";
 4694
 4695            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Footer Heading section.
 4696             * The default renderer for this section calls {@link Help#footerHeading(Object...)}.
 4697             * @since 3.9 */
 4698            public static final String SECTION_KEY_FOOTER_HEADING = "footerHeading";
 4699
 4700            /** {@linkplain #sectionKeys() Section key} to {@linkplain #sectionMap() control} the {@linkplain IHelpSectionRenderer section renderer} for the Footer section.
 4701             * The default renderer for this section calls {@link Help#footer(Object...)}.
 4702             * @since 3.9 */
 4703            public static final String SECTION_KEY_FOOTER = "footer";
 4704
 4705            /** Constant holding the default usage message width: <code>{@value}</code>. */
 4706            public  final static int DEFAULT_USAGE_WIDTH = 80;
 4707            private final static int MINIMUM_USAGE_WIDTH = 55;
 4708
 4709            /** Constant String holding the default synopsis heading: <code>{@value}</code>. */
 4710            static final String DEFAULT_SYNOPSIS_HEADING = "Usage: ";
 4711
 4712            /** Constant String holding the default command list heading: <code>{@value}</code>. */
 4713            static final String DEFAULT_COMMAND_LIST_HEADING = "Commands:%n";
 4714
 4715            /** Constant String holding the default string that separates options from option parameters: {@code ' '} ({@value}). */
 4716            static final char DEFAULT_REQUIRED_OPTION_MARKER = ' ';
 4717
 4718            /** Constant Boolean holding the default setting for whether to abbreviate the synopsis: <code>{@value}</code>.*/
 4719            static final Boolean DEFAULT_ABBREVIATE_SYNOPSIS = Boolean.FALSE;
 4720
 4721            /** Constant Boolean holding the default setting for whether to sort the options alphabetically: <code>{@value}</code>.*/
 4722            static final Boolean DEFAULT_SORT_OPTIONS = Boolean.TRUE;
 4723
 4724            /** Constant Boolean holding the default setting for whether to show default values in the usage help message: <code>{@value}</code>.*/
 4725            static final Boolean DEFAULT_SHOW_DEFAULT_VALUES = Boolean.FALSE;
 4726
 4727            /** Constant Boolean holding the default setting for whether this command should be listed in the usage help of the parent command: <code>{@value}</code>.*/
 4728            static final Boolean DEFAULT_HIDDEN = Boolean.FALSE;
 4729
 4730            static final String DEFAULT_SINGLE_VALUE = "";
 4731            static final String[] DEFAULT_MULTI_LINE = {};
 4732
 4733            private IHelpFactory helpFactory;
 4734
 4735            private List<String> sectionKeys = Collections.unmodifiableList(Arrays.asList(
 4736                    SECTION_KEY_HEADER_HEADING,
 4737                    SECTION_KEY_HEADER,
 4738                    SECTION_KEY_SYNOPSIS_HEADING,
 4739                    SECTION_KEY_SYNOPSIS,
 4740                    SECTION_KEY_DESCRIPTION_HEADING,
 4741                    SECTION_KEY_DESCRIPTION,
 4742                    SECTION_KEY_PARAMETER_LIST_HEADING,
 4743                    SECTION_KEY_PARAMETER_LIST,
 4744                    SECTION_KEY_OPTION_LIST_HEADING,
 4745                    SECTION_KEY_OPTION_LIST,
 4746                    SECTION_KEY_COMMAND_LIST_HEADING,
 4747                    SECTION_KEY_COMMAND_LIST,
 4748                    SECTION_KEY_FOOTER_HEADING,
 4749                    SECTION_KEY_FOOTER));
 4750
 4751            private Map<String, IHelpSectionRenderer> helpSectionRendererMap = createHelpSectionRendererMap();
 4752
 4753            private String[] description;
 4754            private String[] customSynopsis;
 4755            private String[] header;
 4756            private String[] footer;
 4757            private Boolean abbreviateSynopsis;
 4758            private Boolean sortOptions;
 4759            private Boolean showDefaultValues;
 4760            private Boolean hidden;
 4761            private Character requiredOptionMarker;
 4762            private String headerHeading;
 4763            private String synopsisHeading;
 4764            private String descriptionHeading;
 4765            private String parameterListHeading;
 4766            private String optionListHeading;
 4767            private String commandListHeading;
 4768            private String footerHeading;
 4769            private int width = DEFAULT_USAGE_WIDTH;
 4770
 4771            private Messages messages;
 4772
 4773            /**
 4774             * Sets the maximum usage help message width to the specified value. Longer values are wrapped.
 4775             * @param newValue the new maximum usage help message width. Must be 55 or greater.
 4776             * @return this {@code UsageMessageSpec} for method chaining
 4777             * @throws IllegalArgumentException if the specified width is less than 55
 4778             */
 4779            public UsageMessageSpec width(int newValue) {
 4780                if (newValue < MINIMUM_USAGE_WIDTH) {
 4781                    throw new InitializationException("Invalid usage message width " + newValue + ". Minimum value is " + MINIMUM_USAGE_WIDTH);
 4782                }
 4783                width = newValue; return this;
 4784            }
 4785
 4786            private static int getSysPropertyWidthOrDefault(int defaultWidth) {
 4787                String userValue = System.getProperty("picocli.usage.width");
 4788                if (userValue == null) { return defaultWidth; }
 4789                try {
 4790                    int width = Integer.parseInt(userValue);
 4791                    if (width < MINIMUM_USAGE_WIDTH) {
 4792                        new Tracer().warn("Invalid picocli.usage.width value %d. Using minimum usage width %d.%n", width, MINIMUM_USAGE_WIDTH);
 4793                        return MINIMUM_USAGE_WIDTH;
 4794                    }
 4795                    return width;
 4796                } catch (NumberFormatException ex) {
 4797                    new Tracer().warn("Invalid picocli.usage.width value '%s'. Using usage width %d.%n", userValue, defaultWidth);
 4798                    return defaultWidth;
 4799                }
 4800            }
 4801
 4802            /** Returns the maximum usage help message width. Derived from system property {@code "picocli.usage.width"}
 4803             * if set, otherwise returns the value set via the {@link #width(int)} method, or if not set, the {@linkplain #DEFAULT_USAGE_WIDTH default width}.
 4804             * @return the maximum usage help message width. Never returns less than 55. */
 4805            public int width() { return getSysPropertyWidthOrDefault(width); }
 4806
 4807            /** Returns the help section renderers for the predefined section keys. see: {@link #sectionKeys()} */
 4808            private Map<String, IHelpSectionRenderer> createHelpSectionRendererMap() {
 4809                Map<String, IHelpSectionRenderer> result = new HashMap<String, IHelpSectionRenderer>();
 4810
 4811                result.put(SECTION_KEY_HEADER_HEADING,         new IHelpSectionRenderer() { public String render(Help help) { return help.headerHeading(); } });
 4812                result.put(SECTION_KEY_HEADER,                 new IHelpSectionRenderer() { public String render(Help help) { return help.header(); } });
 4813                //e.g. Usage:
 4814                result.put(SECTION_KEY_SYNOPSIS_HEADING,       new IHelpSectionRenderer() { public String render(Help help) { return help.synopsisHeading(); } });
 4815                //e.g. &lt;main class&gt; [OPTIONS] &lt;command&gt; [COMMAND-OPTIONS] [ARGUMENTS]
 4816                result.put(SECTION_KEY_SYNOPSIS,               new IHelpSectionRenderer() { public String render(Help help) { return help.synopsis(help.synopsisHeadingLength()); } });
 4817                //e.g. %nDescription:%n%n
 4818                result.put(SECTION_KEY_DESCRIPTION_HEADING,    new IHelpSectionRenderer() { public String render(Help help) { return help.descriptionHeading(); } });
 4819                //e.g. {"Converts foos to bars.", "Use options to control conversion mode."}
 4820                result.put(SECTION_KEY_DESCRIPTION,            new IHelpSectionRenderer() { public String render(Help help) { return help.description(); } });
 4821                //e.g. %nPositional parameters:%n%n
 4822                result.put(SECTION_KEY_PARAMETER_LIST_HEADING, new IHelpSectionRenderer() { public String render(Help help) { return help.parameterListHeading(); } });
 4823                //e.g. [FILE...] the files to convert
 4824                result.put(SECTION_KEY_PARAMETER_LIST,         new IHelpSectionRenderer() { public String render(Help help) { return help.parameterList(); } });
 4825                //e.g. %nOptions:%n%n
 4826                result.put(SECTION_KEY_OPTION_LIST_HEADING,    new IHelpSectionRenderer() { public String render(Help help) { return help.optionListHeading(); } });
 4827                //e.g. -h, --help   displays this help and exits
 4828                result.put(SECTION_KEY_OPTION_LIST,            new IHelpSectionRenderer() { public String render(Help help) { return help.optionList(); } });
 4829                //e.g. %nCommands:%n%n
 4830                result.put(SECTION_KEY_COMMAND_LIST_HEADING,   new IHelpSectionRenderer() { public String render(Help help) { return help.commandListHeading(); } });
 4831                //e.g.    add       adds the frup to the frooble
 4832                result.put(SECTION_KEY_COMMAND_LIST,           new IHelpSectionRenderer() { public String render(Help help) { return help.commandList(); } });
 4833                result.put(SECTION_KEY_FOOTER_HEADING,         new IHelpSectionRenderer() { public String render(Help help) { return help.footerHeading(); } });
 4834                result.put(SECTION_KEY_FOOTER,                 new IHelpSectionRenderer() { public String render(Help help) { return help.footer(); } });
 4835                return result;
 4836            }
 4837
 4838            /**
 4839             * Returns the section keys in the order that the usage help message should render the sections.
 4840             * This ordering may be modified with the {@link #sectionKeys(List) sectionKeys setter}. The default keys are (in order):
 4841             * <ol>
 4842             *   <li>{@link UsageMessageSpec#SECTION_KEY_HEADER_HEADING SECTION_KEY_HEADER_HEADING}</li>
 4843             *   <li>{@link UsageMessageSpec#SECTION_KEY_HEADER SECTION_KEY_HEADER}</li>
 4844             *   <li>{@link UsageMessageSpec#SECTION_KEY_SYNOPSIS_HEADING SECTION_KEY_SYNOPSIS_HEADING}</li>
 4845             *   <li>{@link UsageMessageSpec#SECTION_KEY_SYNOPSIS SECTION_KEY_SYNOPSIS}</li>
 4846             *   <li>{@link UsageMessageSpec#SECTION_KEY_DESCRIPTION_HEADING SECTION_KEY_DESCRIPTION_HEADING}</li>
 4847             *   <li>{@link UsageMessageSpec#SECTION_KEY_DESCRIPTION SECTION_KEY_DESCRIPTION}</li>
 4848             *   <li>{@link UsageMessageSpec#SECTION_KEY_PARAMETER_LIST_HEADING SECTION_KEY_PARAMETER_LIST_HEADING}</li>
 4849             *   <li>{@link UsageMessageSpec#SECTION_KEY_PARAMETER_LIST SECTION_KEY_PARAMETER_LIST}</li>
 4850             *   <li>{@link UsageMessageSpec#SECTION_KEY_OPTION_LIST_HEADING SECTION_KEY_OPTION_LIST_HEADING}</li>
 4851             *   <li>{@link UsageMessageSpec#SECTION_KEY_OPTION_LIST SECTION_KEY_OPTION_LIST}</li>
 4852             *   <li>{@link UsageMessageSpec#SECTION_KEY_COMMAND_LIST_HEADING SECTION_KEY_COMMAND_LIST_HEADING}</li>
 4853             *   <li>{@link UsageMessageSpec#SECTION_KEY_COMMAND_LIST SECTION_KEY_COMMAND_LIST}</li>
 4854             *   <li>{@link UsageMessageSpec#SECTION_KEY_FOOTER_HEADING SECTION_KEY_FOOTER_HEADING}</li>
 4855             *   <li>{@link UsageMessageSpec#SECTION_KEY_FOOTER SECTION_KEY_FOOTER}</li>
 4856             * </ol>
 4857             * @since 3.9
 4858             */
 4859            public List<String> sectionKeys() { return sectionKeys; }
 4860
 4861            /**
 4862             * Sets the section keys in the order that the usage help message should render the sections.
 4863             * @see #sectionKeys
 4864             * @since 3.9
 4865             */
 4866            public UsageMessageSpec sectionKeys(List<String> keys) { sectionKeys = Collections.unmodifiableList(new ArrayList<String>(keys)); return this; }
 4867
 4868            /**
 4869             * Returns the map of section keys and renderers used to construct the usage help message.
 4870             * The usage help message can be customized by adding, replacing and removing section renderers from this map.
 4871             * Sections can be reordered with the {@link #sectionKeys(List) sectionKeys setter}.
 4872             * Sections that are either not in this map or not in the list returned by {@link #sectionKeys() sectionKeys} are omitted.
 4873             * @see #sectionKeys
 4874             * @since 3.9
 4875             */
 4876            public Map<String, IHelpSectionRenderer> sectionMap() { return helpSectionRendererMap; }
 4877
 4878            /**
 4879             * Sets the map of section keys and renderers used to construct the usage help message to a copy of the specified map.
 4880             * @param map the mapping of section keys to their renderers, must be non-{@code null}.
 4881             * @return this UsageMessageSpec for method chaining
 4882             * @see #sectionKeys
 4883             * @see #setHelpSectionMap(Map)
 4884             * @since 3.9
 4885             */
 4886            public UsageMessageSpec sectionMap(Map<String, IHelpSectionRenderer> map) { this.helpSectionRendererMap = new HashMap<String, IHelpSectionRenderer>(map); return this; }
 4887
 4888            /** Returns the {@code IHelpFactory} that is used to construct the usage help message.
 4889             * @see #setHelpFactory(IHelpFactory)
 4890             * @since 3.9
 4891             */
 4892            public IHelpFactory helpFactory() {
 4893                if (helpFactory == null) {
 4894                    helpFactory = new DefaultHelpFactory();
 4895                }
 4896                return helpFactory;
 4897            }
 4898
 4899            /** Sets a new {@code IHelpFactory} to customize the usage help message.
 4900             * @param helpFactory the new help factory. Must be non-{@code null}.
 4901             * @return this {@code UsageMessageSpec} object, to allow method chaining
 4902             */
 4903            public UsageMessageSpec helpFactory(IHelpFactory helpFactory) {
 4904                this.helpFactory = Assert.notNull(helpFactory, "helpFactory");
 4905                return this;
 4906            }
 4907
 4908            private String str(String localized, String value, String defaultValue) {
 4909                return localized != null ? localized : (value != null ? value : defaultValue);
 4910            }
 4911            private String[] arr(String[] localized, String[] value, String[] defaultValue) {
 4912                return localized != null ? localized : (value != null ? value.clone() : defaultValue);
 4913            }
 4914            private String   resourceStr(String key) { return messages == null ? null : messages.getString(key, null); }
 4915            private String[] resourceArr(String key) { return messages == null ? null : messages.getStringArray(key, null); }
 4916
 4917            /** Returns the optional heading preceding the header section. Initialized from {@link Command#headerHeading()}, or null. */
 4918            public String headerHeading() { return str(resourceStr("usage.headerHeading"), headerHeading, DEFAULT_SINGLE_VALUE); }
 4919
 4920            /** Returns the optional header lines displayed at the top of the help message. For subcommands, the first header line is
 4921             * displayed in the list of commands. Values are initialized from {@link Command#header()}
 4922             * if the {@code Command} annotation is present, otherwise this is an empty array and the help message has no
 4923             * header. Applications may programmatically set this field to create a custom help message. */
 4924            public String[] header() { return arr(resourceArr("usage.header"), header, DEFAULT_MULTI_LINE); }
 4925
 4926            /** Returns the optional heading preceding the synopsis. Initialized from {@link Command#synopsisHeading()}, {@code "Usage: "} by default. */
 4927            public String synopsisHeading() { return str(resourceStr("usage.synopsisHeading"), synopsisHeading, DEFAULT_SYNOPSIS_HEADING); }
 4928
 4929            /** Returns whether the synopsis line(s) should show an abbreviated synopsis without detailed option names. */
 4930            public boolean abbreviateSynopsis() { return (abbreviateSynopsis == null) ? DEFAULT_ABBREVIATE_SYNOPSIS : abbreviateSynopsis; }
 4931
 4932            /** Returns the optional custom synopsis lines to use instead of the auto-generated synopsis.
 4933             * Initialized from {@link Command#customSynopsis()} if the {@code Command} annotation is present,
 4934             * otherwise this is an empty array and the synopsis is generated.
 4935             * Applications may programmatically set this field to create a custom help message. */
 4936            public String[] customSynopsis() { return arr(resourceArr("usage.customSynopsis"), customSynopsis, DEFAULT_MULTI_LINE); }
 4937
 4938            /** Returns the optional heading preceding the description section. Initialized from {@link Command#descriptionHeading()}, or null. */
 4939            public String descriptionHeading() { return str(resourceStr("usage.descriptionHeading"), descriptionHeading, DEFAULT_SINGLE_VALUE); }
 4940
 4941            /** Returns the optional text lines to use as the description of the help message, displayed between the synopsis and the
 4942             * options list. Initialized from {@link Command#description()} if the {@code Command} annotation is present,
 4943             * otherwise this is an empty array and the help message has no description.
 4944             * Applications may programmatically set this field to create a custom help message. */
 4945            public String[] description() { return arr(resourceArr("usage.description"), description, DEFAULT_MULTI_LINE); }
 4946
 4947            /** Returns the optional heading preceding the parameter list. Initialized from {@link Command#parameterListHeading()}, or null. */
 4948            public String parameterListHeading() { return str(resourceStr("usage.parameterListHeading"), parameterListHeading, DEFAULT_SINGLE_VALUE); }
 4949
 4950            /** Returns the optional heading preceding the options list. Initialized from {@link Command#optionListHeading()}, or null. */
 4951            public String optionListHeading() { return str(resourceStr("usage.optionListHeading"), optionListHeading, DEFAULT_SINGLE_VALUE); }
 4952
 4953            /** Returns whether the options list in the usage help message should be sorted alphabetically. */
 4954            public boolean sortOptions() { return (sortOptions == null) ? DEFAULT_SORT_OPTIONS : sortOptions; }
 4955
 4956            /** Returns the character used to prefix required options in the options list. */
 4957            public char requiredOptionMarker() { return (requiredOptionMarker == null) ? DEFAULT_REQUIRED_OPTION_MARKER : requiredOptionMarker; }
 4958
 4959            /** Returns whether the options list in the usage help message should show default values for all non-boolean options. */
 4960            public boolean showDefaultValues() { return (showDefaultValues == null) ? DEFAULT_SHOW_DEFAULT_VALUES : showDefaultValues; }
 4961
 4962            /**
 4963             * Returns whether this command should be hidden from the usage help message of the parent command.
 4964             * @return {@code true} if this command should not appear in the usage help message of the parent command
 4965             */
 4966            public boolean hidden() { return (hidden == null) ? DEFAULT_HIDDEN : hidden; }
 4967
 4968            /** Returns the optional heading preceding the subcommand list. Initialized from {@link Command#commandListHeading()}. {@code "Commands:%n"} by default. */
 4969            public String commandListHeading() { return str(resourceStr("usage.commandListHeading"), commandListHeading, DEFAULT_COMMAND_LIST_HEADING); }
 4970
 4971            /** Returns the optional heading preceding the footer section. Initialized from {@link Command#footerHeading()}, or null. */
 4972            public String footerHeading() { return str(resourceStr("usage.footerHeading"), footerHeading, DEFAULT_SINGLE_VALUE); }
 4973
 4974            /** Returns the optional footer text lines displayed at the bottom of the help message. Initialized from
 4975             * {@link Command#footer()} if the {@code Command} annotation is present, otherwise this is an empty array and
 4976             * the help message has no footer.
 4977             * Applications may programmatically set this field to create a custom help message. */
 4978            public String[] footer() { return arr(resourceArr("usage.footer"), footer, DEFAULT_MULTI_LINE); }
 4979
 4980            /** Sets the heading preceding the header section. Initialized from {@link Command#headerHeading()}, or null.
 4981             * @return this UsageMessageSpec for method chaining */
 4982            public UsageMessageSpec headerHeading(String headerHeading) { this.headerHeading = headerHeading; return this; }
 4983
 4984            /** Sets the optional header lines displayed at the top of the help message. For subcommands, the first header line is
 4985             * displayed in the list of commands.
 4986             * @return this UsageMessageSpec for method chaining */
 4987            public UsageMessageSpec header(String... header) { this.header = header; return this; }
 4988
 4989            /** Sets the optional heading preceding the synopsis.
 4990             * @return this UsageMessageSpec for method chaining */
 4991            public UsageMessageSpec synopsisHeading(String newValue) {synopsisHeading = newValue; return this;}
 4992
 4993            /** Sets whether the synopsis line(s) should show an abbreviated synopsis without detailed option names.
 4994             * @return this UsageMessageSpec for method chaining */
 4995            public UsageMessageSpec abbreviateSynopsis(boolean newValue) {abbreviateSynopsis = newValue; return this;}
 4996
 4997            /** Sets the optional custom synopsis lines to use instead of the auto-generated synopsis.
 4998             * @return this UsageMessageSpec for method chaining */
 4999            public UsageMessageSpec customSynopsis(String... customSynopsis) { this.customSynopsis = customSynopsis; return this; }
 5000
 5001            /** Sets the heading preceding the description section.
 5002             * @return this UsageMessageSpec for method chaining */
 5003            public UsageMessageSpec descriptionHeading(String newValue) {descriptionHeading = newValue; return this;}
 5004
 5005            /** Sets the optional text lines to use as the description of the help message, displayed between the synopsis and the
 5006             * options list.
 5007             * @return this UsageMessageSpec for method chaining */
 5008            public UsageMessageSpec description(String... description) { this.description = description; return this; }
 5009
 5010            /** Sets the optional heading preceding the parameter list.
 5011             * @return this UsageMessageSpec for method chaining */
 5012            public UsageMessageSpec parameterListHeading(String newValue) {parameterListHeading = newValue; return this;}
 5013
 5014            /** Sets the heading preceding the options list.
 5015             * @return this UsageMessageSpec for method chaining */
 5016            public UsageMessageSpec optionListHeading(String newValue) {optionListHeading = newValue; return this;}
 5017
 5018            /** Sets whether the options list in the usage help message should be sorted alphabetically.
 5019             * @return this UsageMessageSpec for method chaining */
 5020            public UsageMessageSpec sortOptions(boolean newValue) {sortOptions = newValue; return this;}
 5021
 5022            /** Sets the character used to prefix required options in the options list.
 5023             * @return this UsageMessageSpec for method chaining */
 5024            public UsageMessageSpec requiredOptionMarker(char newValue) {requiredOptionMarker = newValue; return this;}
 5025
 5026            /** Sets whether the options list in the usage help message should show default values for all non-boolean options.
 5027             * @return this UsageMessageSpec for method chaining */
 5028            public UsageMessageSpec showDefaultValues(boolean newValue) {showDefaultValues = newValue; return this;}
 5029
 5030            /**
 5031             * Set the hidden flag on this command to control whether to show or hide it in the help usage text of the parent command.
 5032             * @param value enable or disable the hidden flag
 5033             * @return this UsageMessageSpec for method chaining
 5034             * @see Command#hidden() */
 5035            public UsageMessageSpec hidden(boolean value) { hidden = value; return this; }
 5036
 5037            /** Sets the optional heading preceding the subcommand list.
 5038             * @return this UsageMessageSpec for method chaining */
 5039            public UsageMessageSpec commandListHeading(String newValue) {commandListHeading = newValue; return this;}
 5040
 5041            /** Sets the optional heading preceding the footer section.
 5042             * @return this UsageMessageSpec for method chaining */
 5043            public UsageMessageSpec footerHeading(String newValue) {footerHeading = newValue; return this;}
 5044
 5045            /** Sets the optional footer text lines displayed at the bottom of the help message.
 5046             * @return this UsageMessageSpec for method chaining */
 5047            public UsageMessageSpec footer(String... footer) { this.footer = footer; return this; }
 5048            /** Returns the Messages for this usage help message specification, or {@code null}.
 5049             * @return the Messages object that encapsulates this {@linkplain CommandSpec#resourceBundle() command's resource bundle}
 5050             * @since 3.6 */
 5051            public Messages messages() { return messages; }
 5052            /** Sets the Messages for this usageMessage specification, and returns this UsageMessageSpec.
 5053             * @param msgs the new Messages value that encapsulates this {@linkplain CommandSpec#resourceBundle() command's resource bundle}, may be {@code null}
 5054             * @since 3.6 */
 5055            public UsageMessageSpec messages(Messages msgs) { messages = msgs; return this; }
 5056            void updateFromCommand(Command cmd, CommandSpec commandSpec) {
 5057                if (isNonDefault(cmd.synopsisHeading(), DEFAULT_SYNOPSIS_HEADING))            {synopsisHeading = cmd.synopsisHeading();}
 5058                if (isNonDefault(cmd.commandListHeading(), DEFAULT_COMMAND_LIST_HEADING))     {commandListHeading = cmd.commandListHeading();}
 5059                if (isNonDefault(cmd.requiredOptionMarker(), DEFAULT_REQUIRED_OPTION_MARKER)) {requiredOptionMarker = cmd.requiredOptionMarker();}
 5060                if (isNonDefault(cmd.abbreviateSynopsis(), DEFAULT_ABBREVIATE_SYNOPSIS))      {abbreviateSynopsis = cmd.abbreviateSynopsis();}
 5061                if (isNonDefault(cmd.sortOptions(), DEFAULT_SORT_OPTIONS))                    {sortOptions = cmd.sortOptions();}
 5062                if (isNonDefault(cmd.showDefaultValues(), DEFAULT_SHOW_DEFAULT_VALUES))       {showDefaultValues = cmd.showDefaultValues();}
 5063                if (isNonDefault(cmd.hidden(), DEFAULT_HIDDEN))                               {hidden = cmd.hidden();}
 5064                if (isNonDefault(cmd.customSynopsis(), DEFAULT_MULTI_LINE))                   {customSynopsis = cmd.customSynopsis().clone();}
 5065                if (isNonDefault(cmd.description(), DEFAULT_MULTI_LINE))                      {description = cmd.description().clone();}
 5066                if (isNonDefault(cmd.descriptionHeading(), DEFAULT_SINGLE_VALUE))             {descriptionHeading = cmd.descriptionHeading();}
 5067                if (isNonDefault(cmd.header(), DEFAULT_MULTI_LINE))                           {header = cmd.header().clone();}
 5068                if (isNonDefault(cmd.headerHeading(), DEFAULT_SINGLE_VALUE))                  {headerHeading = cmd.headerHeading();}
 5069                if (isNonDefault(cmd.footer(), DEFAULT_MULTI_LINE))                           {footer = cmd.footer().clone();}
 5070                if (isNonDefault(cmd.footerHeading(), DEFAULT_SINGLE_VALUE))                  {footerHeading = cmd.footerHeading();}
 5071                if (isNonDefault(cmd.parameterListHeading(), DEFAULT_SINGLE_VALUE))           {parameterListHeading = cmd.parameterListHeading();}
 5072                if (isNonDefault(cmd.optionListHeading(), DEFAULT_SINGLE_VALUE))              {optionListHeading = cmd.optionListHeading();}
 5073                if (isNonDefault(cmd.usageHelpWidth(), DEFAULT_USAGE_WIDTH))                  {width(cmd.usageHelpWidth());} // validate
 5074
 5075                if (!empty(cmd.resourceBundle())) { // else preserve superclass bundle
 5076                    messages(new Messages(commandSpec, cmd.resourceBundle()));
 5077                }
 5078            }
 5079            void initFromMixin(UsageMessageSpec mixin, CommandSpec commandSpec) {
 5080                if (initializable(synopsisHeading, mixin.synopsisHeading(), DEFAULT_SYNOPSIS_HEADING))                 {synopsisHeading = mixin.synopsisHeading();}
 5081                if (initializable(commandListHeading, mixin.commandListHeading(), DEFAULT_COMMAND_LIST_HEADING))       {commandListHeading = mixin.commandListHeading();}
 5082                if (initializable(requiredOptionMarker, mixin.requiredOptionMarker(), DEFAULT_REQUIRED_OPTION_MARKER)) {requiredOptionMarker = mixin.requiredOptionMarker();}
 5083                if (initializable(abbreviateSynopsis, mixin.abbreviateSynopsis(), DEFAULT_ABBREVIATE_SYNOPSIS))        {abbreviateSynopsis = mixin.abbreviateSynopsis();}
 5084                if (initializable(sortOptions, mixin.sortOptions(), DEFAULT_SORT_OPTIONS))                             {sortOptions = mixin.sortOptions();}
 5085                if (initializable(showDefaultValues, mixin.showDefaultValues(), DEFAULT_SHOW_DEFAULT_VALUES))          {showDefaultValues = mixin.showDefaultValues();}
 5086                if (initializable(hidden, mixin.hidden(), DEFAULT_HIDDEN))                                             {hidden = mixin.hidden();}
 5087                if (initializable(customSynopsis, mixin.customSynopsis(), DEFAULT_MULTI_LINE))                         {customSynopsis = mixin.customSynopsis().clone();}
 5088                if (initializable(description, mixin.description(), DEFAULT_MULTI_LINE))                               {description = mixin.description().clone();}
 5089                if (initializable(descriptionHeading, mixin.descriptionHeading(), DEFAULT_SINGLE_VALUE))               {descriptionHeading = mixin.descriptionHeading();}
 5090                if (initializable(header, mixin.header(), DEFAULT_MULTI_LINE))                                         {header = mixin.header().clone();}
 5091                if (initializable(headerHeading, mixin.headerHeading(), DEFAULT_SINGLE_VALUE))                         {headerHeading = mixin.headerHeading();}
 5092                if (initializable(footer, mixin.footer(), DEFAULT_MULTI_LINE))                                         {footer = mixin.footer().clone();}
 5093                if (initializable(footerHeading, mixin.footerHeading(), DEFAULT_SINGLE_VALUE))                         {footerHeading = mixin.footerHeading();}
 5094                if (initializable(parameterListHeading, mixin.parameterListHeading(), DEFAULT_SINGLE_VALUE))           {parameterListHeading = mixin.parameterListHeading();}
 5095                if (initializable(optionListHeading, mixin.optionListHeading(), DEFAULT_SINGLE_VALUE))                 {optionListHeading = mixin.optionListHeading();}
 5096                if (Messages.empty(messages)) { messages(Messages.copy(commandSpec, mixin.messages())); }
 5097            }
 5098            void initFrom(UsageMessageSpec settings, CommandSpec commandSpec) {
 5099                description = settings.description;
 5100                customSynopsis = settings.customSynopsis;
 5101                header = settings.header;
 5102                footer = settings.footer;
 5103                abbreviateSynopsis = settings.abbreviateSynopsis;
 5104                sortOptions = settings.sortOptions;
 5105                showDefaultValues = settings.showDefaultValues;
 5106                hidden = settings.hidden;
 5107                requiredOptionMarker = settings.requiredOptionMarker;
 5108                headerHeading = settings.headerHeading;
 5109                synopsisHeading = settings.synopsisHeading;
 5110                descriptionHeading = settings.descriptionHeading;
 5111                parameterListHeading = settings.parameterListHeading;
 5112                optionListHeading = settings.optionListHeading;
 5113                commandListHeading = settings.commandListHeading;
 5114                footerHeading = settings.footerHeading;
 5115                width = settings.width;
 5116                messages = Messages.copy(commandSpec, settings.messages());
 5117            }
 5118        }
 5119        /** Models parser configuration specification.
 5120         * @since 3.0 */
 5121        public static class ParserSpec {
 5122
 5123            /** Constant String holding the default separator between options and option parameters: <code>{@value}</code>.*/
 5124            static final String DEFAULT_SEPARATOR = "=";
 5125            private String separator;
 5126            private boolean stopAtUnmatched = false;
 5127            private boolean stopAtPositional = false;
 5128            private String endOfOptionsDelimiter = "--";
 5129            private boolean toggleBooleanFlags = true;
 5130            private boolean overwrittenOptionsAllowed = false;
 5131            private boolean unmatchedArgumentsAllowed = false;
 5132            private boolean expandAtFiles = true;
 5133            private boolean useSimplifiedAtFiles = false;
 5134            private Character atFileCommentChar = '#';
 5135            private boolean posixClusteredShortOptionsAllowed = true;
 5136            private boolean unmatchedOptionsArePositionalParams = false;
 5137            private boolean limitSplit = false;
 5138            private boolean aritySatisfiedByAttachedOptionParam = false;
 5139            private boolean collectErrors = false;
 5140            private boolean caseInsensitiveEnumValuesAllowed = false;
 5141            private boolean trimQuotes = shouldTrimQuotes();
 5142            private boolean splitQuotedStrings = false;
 5143
 5144            /** Returns the String to use as the separator between options and option parameters. {@code "="} by default,
 5145             * initialized from {@link Command#separator()} if defined.*/
 5146            public String separator() { return (separator == null) ? DEFAULT_SEPARATOR : separator; }
 5147
 5148            /** @see CommandLine#isStopAtUnmatched() */
 5149            public boolean stopAtUnmatched()                   { return stopAtUnmatched; }
 5150            /** @see CommandLine#isStopAtPositional() */
 5151            public boolean stopAtPositional()                  { return stopAtPositional; }
 5152            /** @see CommandLine#getEndOfOptionsDelimiter()
 5153             * @since 3.5 */
 5154            public String endOfOptionsDelimiter()             { return endOfOptionsDelimiter; }
 5155            /** @see CommandLine#isToggleBooleanFlags() */
 5156            public boolean toggleBooleanFlags()                { return toggleBooleanFlags; }
 5157            /** @see CommandLine#isOverwrittenOptionsAllowed() */
 5158            public boolean overwrittenOptionsAllowed()         { return overwrittenOptionsAllowed; }
 5159            /** @see CommandLine#isUnmatchedArgumentsAllowed() */
 5160            public boolean unmatchedArgumentsAllowed()         { return unmatchedArgumentsAllowed; }
 5161            /** @see CommandLine#isExpandAtFiles() */
 5162            public boolean expandAtFiles()                     { return expandAtFiles; }
 5163            /** @see CommandLine#getAtFileCommentChar()
 5164             * @since 3.5 */
 5165            public Character atFileCommentChar()               { return atFileCommentChar; }
 5166            /** @see CommandLine#isUseSimplifiedAtFiles()
 5167             * @since 3.9 */
 5168            public boolean useSimplifiedAtFiles()              {
 5169                String value = System.getProperty("picocli.useSimplifiedAtFiles");
 5170                if (value != null) {
 5171                    return "".equals(value) || Boolean.valueOf(value);
 5172                }
 5173                return useSimplifiedAtFiles;
 5174            }
 5175            /** @see CommandLine#isPosixClusteredShortOptionsAllowed() */
 5176            public boolean posixClusteredShortOptionsAllowed() { return posixClusteredShortOptionsAllowed; }
 5177            /** @see CommandLine#isCaseInsensitiveEnumValuesAllowed()
 5178             * @since 3.4 */
 5179            public boolean caseInsensitiveEnumValuesAllowed()  { return caseInsensitiveEnumValuesAllowed; }
 5180            /** @see CommandLine#isTrimQuotes()
 5181             * @since 3.7 */
 5182            public boolean trimQuotes()  { return trimQuotes; }
 5183            /** @see CommandLine#isSplitQuotedStrings()
 5184             * @since 3.7 */
 5185            public boolean splitQuotedStrings()  { return splitQuotedStrings; }
 5186            /** @see CommandLine#isUnmatchedOptionsArePositionalParams() */
 5187            public boolean unmatchedOptionsArePositionalParams() { return unmatchedOptionsArePositionalParams; }
 5188            private boolean splitFirst()                       { return limitSplit(); }
 5189            /** Returns true if arguments should be split first before any further processing and the number of
 5190             * parts resulting from the split is limited to the max arity of the argument. */
 5191            public boolean limitSplit()                        { return limitSplit; }
 5192            /** Returns true if options with attached arguments should not consume subsequent arguments and should not validate arity. The default is {@code false}. */
 5193            public boolean aritySatisfiedByAttachedOptionParam() { return aritySatisfiedByAttachedOptionParam; }
 5194            /** Returns true if exceptions during parsing should be collected instead of thrown.
 5195             * Multiple errors may be encountered during parsing. These can be obtained from {@link ParseResult#errors()}.
 5196             * @since 3.2 */
 5197            public boolean collectErrors()                     { return collectErrors; }
 5198
 5199            /** Sets the String to use as the separator between options and option parameters.
 5200             * @return this ParserSpec for method chaining */
 5201            public ParserSpec separator(String separator)                                  { this.separator = separator; return this; }
 5202            /** @see CommandLine#setStopAtUnmatched(boolean) */
 5203            public ParserSpec stopAtUnmatched(boolean stopAtUnmatched)                     { this.stopAtUnmatched = stopAtUnmatched; return this; }
 5204            /** @see CommandLine#setStopAtPositional(boolean) */
 5205            public ParserSpec stopAtPositional(boolean stopAtPositional)                   { this.stopAtPositional = stopAtPositional; return this; }
 5206            /** @see CommandLine#setEndOfOptionsDelimiter(String)
 5207             * @since 3.5 */
 5208            public ParserSpec endOfOptionsDelimiter(String delimiter)                      { this.endOfOptionsDelimiter = Assert.notNull(delimiter, "end-of-options delimiter"); return this; }
 5209            /** @see CommandLine#setToggleBooleanFlags(boolean) */
 5210            public ParserSpec toggleBooleanFlags(boolean toggleBooleanFlags)               { this.toggleBooleanFlags = toggleBooleanFlags; return this; }
 5211            /** @see CommandLine#setOverwrittenOptionsAllowed(boolean) */
 5212            public ParserSpec overwrittenOptionsAllowed(boolean overwrittenOptionsAllowed) { this.overwrittenOptionsAllowed = overwrittenOptionsAllowed; return this; }
 5213            /** @see CommandLine#setUnmatchedArgumentsAllowed(boolean) */
 5214            public ParserSpec unmatchedArgumentsAllowed(boolean unmatchedArgumentsAllowed) { this.unmatchedArgumentsAllowed = unmatchedArgumentsAllowed; return this; }
 5215            /** @see CommandLine#setExpandAtFiles(boolean) */
 5216            public ParserSpec expandAtFiles(boolean expandAtFiles)                         { this.expandAtFiles = expandAtFiles; return this; }
 5217            /** @see CommandLine#setAtFileCommentChar(Character)
 5218             * @since 3.5 */
 5219            public ParserSpec atFileCommentChar(Character atFileCommentChar)               { this.atFileCommentChar = atFileCommentChar; return this; }
 5220            /** @see CommandLine#setUseSimplifiedAtFiles(boolean)
 5221             * @since 3.9 */
 5222            public ParserSpec useSimplifiedAtFiles(boolean useSimplifiedAtFiles)           { this.useSimplifiedAtFiles = useSimplifiedAtFiles; return this; }
 5223            /** @see CommandLine#setPosixClusteredShortOptionsAllowed(boolean) */
 5224            public ParserSpec posixClusteredShortOptionsAllowed(boolean posixClusteredShortOptionsAllowed) { this.posixClusteredShortOptionsAllowed = posixClusteredShortOptionsAllowed; return this; }
 5225            /** @see CommandLine#setCaseInsensitiveEnumValuesAllowed(boolean)
 5226             * @since 3.4 */
 5227            public ParserSpec caseInsensitiveEnumValuesAllowed(boolean caseInsensitiveEnumValuesAllowed) { this.caseInsensitiveEnumValuesAllowed = caseInsensitiveEnumValuesAllowed; return this; }
 5228            /** @see CommandLine#setTrimQuotes(boolean)
 5229             * @since 3.7 */
 5230            public ParserSpec trimQuotes(boolean trimQuotes) { this.trimQuotes = trimQuotes; return this; }
 5231            /** @see CommandLine#setSplitQuotedStrings(boolean)
 5232             * @since 3.7 */
 5233            public ParserSpec splitQuotedStrings(boolean splitQuotedStrings)  { this.splitQuotedStrings = splitQuotedStrings; return this; }
 5234            /** @see CommandLine#setUnmatchedOptionsArePositionalParams(boolean) */
 5235            public ParserSpec unmatchedOptionsArePositionalParams(boolean unmatchedOptionsArePositionalParams) { this.unmatchedOptionsArePositionalParams = unmatchedOptionsArePositionalParams; return this; }
 5236            /** Sets whether exceptions during parsing should be collected instead of thrown.
 5237             * Multiple errors may be encountered during parsing. These can be obtained from {@link ParseResult#errors()}.
 5238             * @since 3.2 */
 5239            public ParserSpec collectErrors(boolean collectErrors)                         { this.collectErrors = collectErrors; return this; }
 5240
 5241            /** Returns true if options with attached arguments should not consume subsequent arguments and should not validate arity. The default is {@code false}.*/
 5242            public ParserSpec aritySatisfiedByAttachedOptionParam(boolean newValue) { aritySatisfiedByAttachedOptionParam = newValue; return this; }
 5243
 5244            /** Sets whether arguments should be {@linkplain ArgSpec#splitRegex() split} first before any further processing.
 5245             * If true, the original argument will only be split into as many parts as allowed by max arity. */
 5246            public ParserSpec limitSplit(boolean limitSplit)                               { this.limitSplit = limitSplit; return this; }
 5247
 5248            private boolean shouldTrimQuotes() {
 5249                String value = System.getProperty("picocli.trimQuotes");
 5250                if ("".equals(value)) { value = "true"; }
 5251                return Boolean.valueOf(value);
 5252            }
 5253
 5254            void initSeparator(String value)   { if (initializable(separator, value, DEFAULT_SEPARATOR)) {separator = value;} }
 5255            void updateSeparator(String value) { if (isNonDefault(value, DEFAULT_SEPARATOR))             {separator = value;} }
 5256            public String toString() {
 5257                return String.format("posixClusteredShortOptionsAllowed=%s, stopAtPositional=%s, stopAtUnmatched=%s, " +
 5258                                "separator=%s, overwrittenOptionsAllowed=%s, unmatchedArgumentsAllowed=%s, expandAtFiles=%s, " +
 5259                                "atFileCommentChar=%s, useSimplifiedAtFiles=%s, endOfOptionsDelimiter=%s, limitSplit=%s, aritySatisfiedByAttachedOptionParam=%s, " +
 5260                                "toggleBooleanFlags=%s, unmatchedOptionsArePositionalParams=%s, collectErrors=%s," +
 5261                                "caseInsensitiveEnumValuesAllowed=%s, trimQuotes=%s, splitQuotedStrings=%s",
 5262                        posixClusteredShortOptionsAllowed, stopAtPositional, stopAtUnmatched,
 5263                        separator, overwrittenOptionsAllowed, unmatchedArgumentsAllowed, expandAtFiles,
 5264                        atFileCommentChar, useSimplifiedAtFiles, endOfOptionsDelimiter, limitSplit, aritySatisfiedByAttachedOptionParam,
 5265                        toggleBooleanFlags, unmatchedOptionsArePositionalParams, collectErrors,
 5266                        caseInsensitiveEnumValuesAllowed, trimQuotes, splitQuotedStrings);
 5267            }
 5268
 5269            void initFrom(ParserSpec settings) {
 5270                separator = settings.separator;
 5271                stopAtUnmatched = settings.stopAtUnmatched;
 5272                stopAtPositional = settings.stopAtPositional;
 5273                endOfOptionsDelimiter = settings.endOfOptionsDelimiter;
 5274                toggleBooleanFlags = settings.toggleBooleanFlags;
 5275                overwrittenOptionsAllowed = settings.overwrittenOptionsAllowed;
 5276                unmatchedArgumentsAllowed = settings.unmatchedArgumentsAllowed;
 5277                expandAtFiles = settings.expandAtFiles;
 5278                atFileCommentChar = settings.atFileCommentChar;
 5279                posixClusteredShortOptionsAllowed = settings.posixClusteredShortOptionsAllowed;
 5280                unmatchedOptionsArePositionalParams = settings.unmatchedOptionsArePositionalParams;
 5281                limitSplit = settings.limitSplit;
 5282                aritySatisfiedByAttachedOptionParam = settings.aritySatisfiedByAttachedOptionParam;
 5283                collectErrors = settings.collectErrors;
 5284                caseInsensitiveEnumValuesAllowed = settings.caseInsensitiveEnumValuesAllowed;
 5285                trimQuotes = settings.trimQuotes;
 5286                splitQuotedStrings = settings.splitQuotedStrings;
 5287            }
 5288        }
 5289        /** Models the shared attributes of {@link OptionSpec} and {@link PositionalParamSpec}.
 5290         * @since 3.0 */
 5291        public abstract static class ArgSpec {
 5292            static final String DESCRIPTION_VARIABLE_DEFAULT_VALUE = "${DEFAULT-VALUE}";
 5293            static final String DESCRIPTION_VARIABLE_COMPLETION_CANDIDATES = "${COMPLETION-CANDIDATES}";
 5294            private static final String NO_DEFAULT_VALUE = "__no_default_value__";
 5295
 5296            // help-related fields
 5297            private final boolean hidden;
 5298            private final String paramLabel;
 5299            private final boolean hideParamSyntax;
 5300            private final String[] description;
 5301            private final String descriptionKey;
 5302            private final Help.Visibility showDefaultValue;
 5303            private Messages messages;
 5304            CommandSpec commandSpec;
 5305            private ArgGroupSpec group;
 5306            private final Object userObject;
 5307
 5308            // parser fields
 5309            private final boolean interactive;
 5310            private final boolean required;
 5311            private final String splitRegex;
 5312            private final ITypeInfo typeInfo;
 5313            private final ITypeConverter<?>[] converters;
 5314            private final Iterable<String> completionCandidates;
 5315            private final String defaultValue;
 5316            private final Object initialValue;
 5317            private final boolean hasInitialValue;
 5318            private final IGetter getter;
 5319            private final ISetter setter;
 5320            private final IScope scope;
 5321            private final Range arity;
 5322            private List<String> stringValues = new ArrayList<String>();
 5323            private List<String> originalStringValues = new ArrayList<String>();
 5324            protected String toString;
 5325            private List<Object> typedValues = new ArrayList<Object>();
 5326            Map<Integer, Object> typedValueAtPosition = new TreeMap<Integer, Object>();
 5327
 5328            /** Constructs a new {@code ArgSpec}. */
 5329            private <T extends Builder<T>> ArgSpec(Builder<T> builder) {
 5330                userObject = builder.userObject;
 5331                description = builder.description == null ? new String[0] : builder.description;
 5332                descriptionKey = builder.descriptionKey;
 5333                splitRegex = builder.splitRegex == null ? "" : builder.splitRegex;
 5334                paramLabel = empty(builder.paramLabel) ? "PARAM" : builder.paramLabel;
 5335                hideParamSyntax = builder.hideParamSyntax;
 5336                converters = builder.converters == null ? new ITypeConverter<?>[0] : builder.converters;
 5337                showDefaultValue = builder.showDefaultValue == null ? Help.Visibility.ON_DEMAND : builder.showDefaultValue;
 5338                hidden = builder.hidden;
 5339                interactive = builder.interactive;
 5340                initialValue = builder.initialValue;
 5341                hasInitialValue = builder.hasInitialValue;
 5342                defaultValue = NO_DEFAULT_VALUE.equals(builder.defaultValue) ? null : builder.defaultValue;
 5343                required = builder.required && defaultValue == null; //#261 not required if it has a default
 5344                toString = builder.toString;
 5345                getter = builder.getter;
 5346                setter = builder.setter;
 5347                scope  = builder.scope;
 5348
 5349                Range tempArity = builder.arity;
 5350                if (tempArity == null) {
 5351                    if (isOption()) {
 5352                        tempArity = (builder.type == null || isBoolean(builder.type)) ? Range.valueOf("0") : Range.valueOf("1");
 5353                    } else {
 5354                        tempArity = Range.valueOf("1");
 5355                    }
 5356                    tempArity = tempArity.unspecified(true);
 5357                }
 5358                arity = tempArity;
 5359
 5360                if (builder.typeInfo == null) {
 5361                    this.typeInfo = RuntimeTypeInfo.create(builder.type, builder.auxiliaryTypes,
 5362                            Collections.<String>emptyList(), arity, (isOption() ? boolean.class : String.class));
 5363                } else {
 5364                    this.typeInfo = builder.typeInfo;
 5365                }
 5366
 5367                if (builder.completionCandidates == null && typeInfo.isEnum()) {
 5368                    List<String> list = new ArrayList<String>();
 5369                    for (Object c : typeInfo.getEnumConstantNames()) { list.add(c.toString()); }
 5370                    completionCandidates = Collections.unmodifiableList(list);
 5371                } else {
 5372                    completionCandidates = builder.completionCandidates;
 5373                }
 5374                if (interactive && (arity.min != 1 || arity.max != 1)) {
 5375                    throw new InitializationException("Interactive options and positional parameters are only supported for arity=1, not for arity=" + arity);
 5376                }
 5377            }
 5378            void applyInitialValue(Tracer tracer) {
 5379                if (hasInitialValue()) {
 5380                    try {
 5381                        setter().set(initialValue());
 5382                        tracer.debug("Set initial value for %s of type %s to %s.%n", this, type(), String.valueOf(initialValue()));
 5383                    } catch (Exception ex) {
 5384                        tracer.warn("Could not set initial value for %s of type %s to %s: %s%n", this, type(), String.valueOf(initialValue()), ex);
 5385                    }
 5386                } else {
 5387                    tracer.debug("Initial value not available for %s%n", this);
 5388                }
 5389            }
 5390
 5391            /** Returns whether this is a required option or positional parameter.
 5392             * If this argument is part of a {@linkplain ArgGroup group}, this method returns whether this argument is required <em>within the group</em> (so it is not necessarily a required argument for the command).
 5393             * @see Option#required() */
 5394            public boolean required()      { return required; }
 5395
 5396            /** Returns whether this option will prompt the user to enter a value on the command line.
 5397             * @see Option#interactive() */
 5398            public boolean interactive()   { return interactive; }
 5399
 5400            /** Returns the description template of this option, before variables are rendered.
 5401             * @see Option#description() */
 5402            public String[] description()  { return description.clone(); }
 5403
 5404            /** Returns the description key of this arg spec, used to get the description from a resource bundle.
 5405             * @see Option#descriptionKey()
 5406             * @see Parameters#descriptionKey()
 5407             * @since 3.6 */
 5408            public String descriptionKey()  { return descriptionKey; }
 5409
 5410            /** Returns the description of this option, after variables are rendered. Used when generating the usage documentation.
 5411             * @see Option#description()
 5412             * @since 3.2 */
 5413            public String[] renderedDescription()  {
 5414                String[] desc = description();
 5415                if (desc.length == 0) { return desc; }
 5416                StringBuilder candidates = new StringBuilder();
 5417                if (completionCandidates() != null) {
 5418                    for (String c : completionCandidates()) {
 5419                        if (candidates.length() > 0) { candidates.append(", "); }
 5420                        candidates.append(c);
 5421                    }
 5422                }
 5423                String defaultValueString = defaultValueString();
 5424                String[] result = new String[desc.length];
 5425                for (int i = 0; i < desc.length; i++) {
 5426                    result[i] = format(desc[i].replace(DESCRIPTION_VARIABLE_DEFAULT_VALUE, defaultValueString.replace("%", "%%"))
 5427                            .replace(DESCRIPTION_VARIABLE_COMPLETION_CANDIDATES, candidates.toString()));
 5428                }
 5429                return result;
 5430            }
 5431
 5432            /** Returns how many arguments this option or positional parameter requires.
 5433             * @see Option#arity() */
 5434            public Range arity()           { return arity; }
 5435    
 5436            /** Returns the name of the option or positional parameter used in the usage help message.
 5437             * @see Option#paramLabel() {@link Parameters#paramLabel()} */
 5438            public String paramLabel()     { return paramLabel; }
 5439    
 5440            /** Returns whether usage syntax decorations around the {@linkplain #paramLabel() paramLabel} should be suppressed.
 5441             * The default is {@code false}: by default, the paramLabel is surrounded with {@code '['} and {@code ']'} characters
 5442             * if the value is optional and followed by ellipses ("...") when multiple values can be specified.
 5443             * @since 3.6.0 */
 5444            public boolean hideParamSyntax()     { return hideParamSyntax; }
 5445    
 5446            /** Returns auxiliary type information used when the {@link #type()} is a generic {@code Collection}, {@code Map} or an abstract class.
 5447             * @see Option#type() */
 5448            public Class<?>[] auxiliaryTypes() { return typeInfo.getAuxiliaryTypes(); }
 5449    
 5450            /** Returns one or more {@link CommandLine.ITypeConverter type converters} to use to convert the command line
 5451             * argument into a strongly typed value (or key-value pair for map fields). This is useful when a particular
 5452             * option or positional parameter should use a custom conversion that is different from the normal conversion for the arg spec's type.
 5453             * @see Option#converter() */
 5454            public ITypeConverter<?>[] converters() { return converters.clone(); }
 5455    
 5456            /** Returns a regular expression to split option parameter values or {@code ""} if the value should not be split.
 5457             * @see Option#split() */
 5458            public String splitRegex()     { return splitRegex; }
 5459    
 5460            /** Returns whether this option should be excluded from the usage message.
 5461             * @see Option#hidden() */
 5462            public boolean hidden()        { return hidden; }
 5463    
 5464            /** Returns the type to convert the option or positional parameter to before {@linkplain #setValue(Object) setting} the value. */
 5465            public Class<?> type()         { return typeInfo.getType(); }
 5466
 5467            /** Returns the {@code ITypeInfo} that can be used both at compile time (by annotation processors) and at runtime.
 5468             * @since 4.0 */
 5469            public ITypeInfo typeInfo()    { return typeInfo; }
 5470
 5471            /** Returns the user object associated with this option or positional parameters.
 5472             * @return may return the annotated program element, or some other useful object
 5473             * @since 4.0 */
 5474            public Object userObject()     { return userObject; }
 5475    
 5476            /** Returns the default value of this option or positional parameter, before splitting and type conversion.
 5477             * This method returns the programmatically set value; this may differ from the default value that is actually used:
 5478             * if this ArgSpec is part of a CommandSpec with a {@link IDefaultValueProvider}, picocli will first try to obtain
 5479             * the default value from the default value provider, and this method is only called if the default provider is
 5480             * {@code null} or returned a {@code null} value.
 5481             * @return the programmatically set default value of this option/positional parameter,
 5482             *      returning {@code null} means this option or positional parameter does not have a default
 5483             * @see CommandSpec#defaultValueProvider()
 5484             */
 5485            public String defaultValue()   { return defaultValue; }
 5486            /** Returns the initial value this option or positional parameter. If {@link #hasInitialValue()} is true,
 5487             * the option will be reset to the initial value before parsing (regardless of whether a default value exists),
 5488             * to clear values that would otherwise remain from parsing previous input. */
 5489            public Object initialValue()     { return initialValue; }
 5490            /** Determines whether the option or positional parameter will be reset to the {@link #initialValue()}
 5491             * before parsing new input.*/
 5492            public boolean hasInitialValue() { return hasInitialValue; }
 5493    
 5494            /** Returns whether this option or positional parameter's default value should be shown in the usage help. */
 5495            public Help.Visibility showDefaultValue() { return showDefaultValue; }
 5496
 5497            /** Returns the default value String displayed in the description. If this ArgSpec is part of a
 5498             * CommandSpec with a {@link IDefaultValueProvider}, this method will first try to obtain
 5499             * the default value from the default value provider; if the provider is {@code null} or if it
 5500             * returns a {@code null} value, then next any value set to {@link ArgSpec#defaultValue()}
 5501             * is returned, and if this is also {@code null}, finally the {@linkplain ArgSpec#initialValue() initial value} is returned.
 5502             * @see CommandSpec#defaultValueProvider()
 5503             * @see ArgSpec#defaultValue() */
 5504            public String defaultValueString() {
 5505                String fromProvider = defaultValueFromProvider();
 5506                String defaultVal = fromProvider == null ? this.defaultValue() : fromProvider;
 5507                Object value = defaultVal == null ? initialValue() : defaultVal;
 5508                if (value != null && value.getClass().isArray()) {
 5509                    StringBuilder sb = new StringBuilder();
 5510                    for (int i = 0; i < Array.getLength(value); i++) {
 5511                        sb.append(i > 0 ? ", " : "").append(Array.get(value, i));
 5512                    }
 5513                    return sb.insert(0, "[").append("]").toString();
 5514                }
 5515                return String.valueOf(value);
 5516            }
 5517
 5518            private String defaultValueFromProvider() {
 5519                String fromProvider = null;
 5520                IDefaultValueProvider defaultValueProvider = null;
 5521                try {
 5522                    defaultValueProvider = commandSpec.defaultValueProvider();
 5523                    fromProvider = defaultValueProvider == null ? null : defaultValueProvider.defaultValue(this);
 5524                } catch (Exception ex) {
 5525                    new Tracer().info("Error getting default value for %s from %s: %s", this, defaultValueProvider, ex);
 5526                }
 5527                return fromProvider;
 5528            }
 5529
 5530            /** Returns the explicitly set completion candidates for this option or positional parameter, valid enum
 5531             * constant names, or {@code null} if this option or positional parameter does not have any completion
 5532             * candidates and its type is not an enum.
 5533             * @return the completion candidates for this option or positional parameter, valid enum constant names,
 5534             * or {@code null}
 5535             * @since 3.2 */
 5536            public Iterable<String> completionCandidates() { return completionCandidates; }
 5537
 5538            /** Returns the {@link IGetter} that is responsible for supplying the value of this argument. */
 5539            public IGetter getter()        { return getter; }
 5540            /** Returns the {@link ISetter} that is responsible for modifying the value of this argument. */
 5541            public ISetter setter()        { return setter; }
 5542            /** Returns the {@link IScope} that determines on which object to set the value (or from which object to get the value) of this argument. */
 5543            public IScope scope()          { return scope; }
 5544
 5545            /** Returns the current value of this argument. Delegates to the current {@link #getter()}. */
 5546            public <T> T getValue() throws PicocliException {
 5547                try {
 5548                    return getter.get();
 5549                } catch (PicocliException ex) { throw ex;
 5550                } catch (Exception ex) {        throw new PicocliException("Could not get value for " + this + ": " + ex, ex);
 5551                }
 5552            }
 5553            /** Sets the value of this argument to the specified value and returns the previous value. Delegates to the current {@link #setter()}. */
 5554            public <T> T setValue(T newValue) throws PicocliException {
 5555                try {
 5556                    return setter.set(newValue);
 5557                } catch (PicocliException ex) { throw ex;
 5558                } catch (Exception ex) {        throw new PicocliException("Could not set value (" + newValue + ") for " + this + ": " + ex, ex);
 5559                }
 5560            }
 5561            /** Sets the value of this argument to the specified value and returns the previous value. Delegates to the current {@link #setter()}.
 5562             * @deprecated use {@link #setValue(Object)} instead. This was a design mistake.
 5563             * @since 3.5 */
 5564            @Deprecated public <T> T setValue(T newValue, CommandLine commandLine) throws PicocliException {
 5565                return setValue(newValue);
 5566            }
 5567
 5568            /** Returns {@code true} if this argument's {@link #type()} is an array, a {@code Collection} or a {@code Map}, {@code false} otherwise. */
 5569            public boolean isMultiValue()     { return typeInfo.isMultiValue(); }
 5570            /** Returns {@code true} if this argument is a named option, {@code false} otherwise. */
 5571            public abstract boolean isOption();
 5572            /** Returns {@code true} if this argument is a positional parameter, {@code false} otherwise. */
 5573            public abstract boolean isPositional();
 5574
 5575            /** Returns the groups this option or positional parameter belongs to, or {@code null} if this option is not part of a group.
 5576             * @since 4.0 */
 5577            public ArgGroupSpec group() { return group; }
 5578
 5579            /** Returns the untyped command line arguments matched by this option or positional parameter spec.
 5580             * @return the matched arguments after {@linkplain #splitRegex() splitting}, but before type conversion.
 5581             *      For map properties, {@code "key=value"} values are split into the key and the value part. */
 5582            public List<String> stringValues() { return Collections.unmodifiableList(stringValues); }
 5583
 5584            /** Returns the typed command line arguments matched by this option or positional parameter spec.
 5585             * @return the matched arguments after {@linkplain #splitRegex() splitting} and type conversion.
 5586             *      For map properties, {@code "key=value"} values are split into the key and the value part. */
 5587            public List<Object> typedValues() { return Collections.unmodifiableList(typedValues); }
 5588
 5589            /** Sets the {@code stringValues} to a new list instance. */
 5590            protected void resetStringValues() { stringValues = new ArrayList<String>(); }
 5591
 5592            /** Returns the original command line arguments matched by this option or positional parameter spec.
 5593             * @return the matched arguments as found on the command line: empty Strings for options without value, the
 5594             *      values have not been {@linkplain #splitRegex() split}, and for map properties values may look like {@code "key=value"}*/
 5595            public List<String> originalStringValues() { return Collections.unmodifiableList(originalStringValues); }
 5596
 5597            /** Sets the {@code originalStringValues} to a new list instance. */
 5598            protected void resetOriginalStringValues() { originalStringValues = new ArrayList<String>(); }
 5599
 5600            /** Returns whether the default for this option or positional parameter should be shown, potentially overriding the specified global setting.
 5601             * @param usageHelpShowDefaults whether the command's UsageMessageSpec is configured to show default values. */
 5602            protected boolean internalShowDefaultValue(boolean usageHelpShowDefaults) {
 5603                if (showDefaultValue() == Help.Visibility.ALWAYS)   { return true; }  // override global usage help setting
 5604                if (showDefaultValue() == Help.Visibility.NEVER)    { return false; } // override global usage help setting
 5605                if (initialValue == null && defaultValue() == null && defaultValueFromProvider() == null) { return false; } // no default value to show
 5606                return usageHelpShowDefaults && !isBoolean(type());
 5607            }
 5608            /** Returns the Messages for this arg specification, or {@code null}.
 5609             * @since 3.6 */
 5610            public Messages messages() { return messages; }
 5611            /** Sets the Messages for this ArgSpec, and returns this ArgSpec.
 5612             * @param msgs the new Messages value, may be {@code null}
 5613             * @see Command#resourceBundle()
 5614             * @see OptionSpec#description()
 5615             * @see PositionalParamSpec#description()
 5616             * @since 3.6 */
 5617            public ArgSpec messages(Messages msgs) { messages = msgs; return this; }
 5618
 5619            /** Returns a string respresentation of this option or positional parameter. */
 5620            public String toString() { return toString; }
 5621    
 5622            String[] splitValue(String value, ParserSpec parser, Range arity, int consumed) {
 5623                if (splitRegex().length() == 0) { return new String[] {value}; }
 5624                int limit = parser.limitSplit() ? Math.max(arity.max - consumed, 0) : 0;
 5625                if (parser.splitQuotedStrings()) {
 5626                    return debug(value.split(splitRegex(), limit), "Split (ignoring quotes)", value);
 5627                }
 5628                return debug(splitRespectingQuotedStrings(value, limit, parser, this, splitRegex()), "Split", value);
 5629            }
 5630            private String[] debug(String[] result, String msg, String value) {
 5631                Tracer t = new Tracer();
 5632                if (t.isDebug()) {t.debug("%s with regex '%s' resulted in %s parts: %s%n", msg, splitRegex(), result.length, Arrays.asList(result));}
 5633                return result;
 5634            }
 5635            // @since 3.7
 5636            private static String[] splitRespectingQuotedStrings(String value, int limit, ParserSpec parser, ArgSpec argSpec, String splitRegex) {
 5637                StringBuilder splittable = new StringBuilder();
 5638                StringBuilder temp = new StringBuilder();
 5639                StringBuilder current = splittable;
 5640                Queue<String> quotedValues = new LinkedList<String>();
 5641                boolean escaping = false, inQuote = false;
 5642                for (int ch = 0, i = 0; i < value.length(); i += Character.charCount(ch)) {
 5643                    ch = value.codePointAt(i);
 5644                    switch (ch) {
 5645                        case '\\': escaping = !escaping; break;
 5646                        case '\"':
 5647                            if (!escaping) {
 5648                                inQuote = !inQuote;
 5649                                current = inQuote ? temp : splittable;
 5650                                if (inQuote) {
 5651                                    splittable.appendCodePoint(ch);
 5652                                    continue;
 5653                                } else {
 5654                                    quotedValues.add(temp.toString());
 5655                                    temp.setLength(0);
 5656                                }
 5657                            }
 5658                            break;
 5659                        default: escaping = false; break;
 5660                    }
 5661                    current.appendCodePoint(ch);
 5662                }
 5663                if (temp.length() > 0) {
 5664                    new Tracer().warn("Unbalanced quotes in [%s] for %s (value=%s)%n", temp, argSpec, value);
 5665                    quotedValues.add(temp.toString());
 5666                    temp.setLength(0);
 5667                }
 5668                String[] result = splittable.toString().split(splitRegex, limit);
 5669                for (int i = 0; i < result.length; i++) {
 5670                    result[i] = restoreQuotedValues(result[i], quotedValues, parser);
 5671                }
 5672                if (!quotedValues.isEmpty()) {
 5673                    new Tracer().warn("Unable to respect quotes while splitting value %s for %s (unprocessed remainder: %s)%n", value, argSpec, quotedValues);
 5674                    return value.split(splitRegex, limit);
 5675                }
 5676                return result;
 5677            }
 5678
 5679            private static String restoreQuotedValues(String part, Queue<String> quotedValues, ParserSpec parser) {
 5680                StringBuilder result = new StringBuilder();
 5681                boolean escaping = false, inQuote = false, skip = false;
 5682                for (int ch = 0, i = 0; i < part.length(); i += Character.charCount(ch)) {
 5683                    ch = part.codePointAt(i);
 5684                    switch (ch) {
 5685                        case '\\': escaping = !escaping; break;
 5686                        case '\"':
 5687                            if (!escaping) {
 5688                                inQuote = !inQuote;
 5689                                if (!inQuote) { result.append(quotedValues.remove()); }
 5690                                skip = parser.trimQuotes();
 5691                            }
 5692                            break;
 5693                        default: escaping = false; break;
 5694                    }
 5695                    if (!skip) { result.appendCodePoint(ch); }
 5696                    skip = false;
 5697                }
 5698                return result.toString();
 5699            }
 5700
 5701            protected boolean equalsImpl(ArgSpec other) {
 5702                boolean result = Assert.equals(this.defaultValue, other.defaultValue)
 5703                        && Assert.equals(this.arity, other.arity)
 5704                        && Assert.equals(this.hidden, other.hidden)
 5705                        && Assert.equals(this.paramLabel, other.paramLabel)
 5706                        && Assert.equals(this.hideParamSyntax, other.hideParamSyntax)
 5707                        && Assert.equals(this.required, other.required)
 5708                        && Assert.equals(this.splitRegex, other.splitRegex)
 5709                        && Arrays.equals(this.description, other.description)
 5710                        && Assert.equals(this.descriptionKey, other.descriptionKey)
 5711                        && this.typeInfo.equals(other.typeInfo)
 5712                        ;
 5713                return result;
 5714            }
 5715            protected int hashCodeImpl() {
 5716                return 17
 5717                        + 37 * Assert.hashCode(defaultValue)
 5718                        + 37 * Assert.hashCode(arity)
 5719                        + 37 * Assert.hashCode(hidden)
 5720                        + 37 * Assert.hashCode(paramLabel)
 5721                        + 37 * Assert.hashCode(hideParamSyntax)
 5722                        + 37 * Assert.hashCode(required)
 5723                        + 37 * Assert.hashCode(splitRegex)
 5724                        + 37 * Arrays.hashCode(description)
 5725                        + 37 * Assert.hashCode(descriptionKey)
 5726                        + 37 * typeInfo.hashCode()
 5727                        ;
 5728            }
 5729
 5730            private static String describe(Collection<ArgSpec> args) {
 5731                StringBuilder sb = new StringBuilder();
 5732                for (ArgSpec arg : args) {
 5733                    if (sb.length() > 0) { sb.append(", "); }
 5734                    sb.append(describe(arg, "="));
 5735                }
 5736                return sb.toString();
 5737            }
 5738            /** Returns a description of the option or positional arg, e.g. {@code -a=<a>}
 5739             * @param separator separator between arg and arg parameter label, usually '=' */
 5740            private static String describe(ArgSpec argSpec, String separator) {
 5741                return describe(argSpec, separator, argSpec.paramLabel());
 5742            }
 5743            /** Returns a description of the option or positional arg
 5744             * @param separator separator between arg and arg parameter value, usually '='
 5745             * @param value the value to append after the separator*/
 5746            private static String describe(ArgSpec argSpec, String separator, String value) {
 5747                String prefix = (argSpec.isOption())
 5748                        ? ((OptionSpec) argSpec).longestName()
 5749                        : "params[" + ((PositionalParamSpec) argSpec).index() + "]";
 5750                return argSpec.arity().min > 0 ? prefix + separator + value : prefix;
 5751            }
 5752            abstract static class Builder<T extends Builder<T>> {
 5753                private Object userObject;
 5754                private Range arity;
 5755                private String[] description;
 5756                private String descriptionKey;
 5757                private boolean required;
 5758                private boolean interactive;
 5759                private String paramLabel;
 5760                private boolean hideParamSyntax;
 5761                private String splitRegex;
 5762                private boolean hidden;
 5763                private Class<?> type;
 5764                private Class<?>[] auxiliaryTypes;
 5765                private ITypeInfo typeInfo;
 5766                private ITypeConverter<?>[] converters;
 5767                private String defaultValue;
 5768                private Object initialValue;
 5769                private boolean hasInitialValue = true;
 5770                private Help.Visibility showDefaultValue;
 5771                private Iterable<String> completionCandidates;
 5772                private String toString;
 5773                private IGetter getter = new ObjectBinding();
 5774                private ISetter setter = (ISetter) getter;
 5775                private IScope scope = new ObjectScope(null);
 5776
 5777                Builder() {}
 5778                Builder(ArgSpec original) {
 5779                    userObject = original.userObject;
 5780                    arity = original.arity;
 5781                    converters = original.converters;
 5782                    defaultValue = original.defaultValue;
 5783                    description = original.description;
 5784                    getter = original.getter;
 5785                    setter = original.setter;
 5786                    hidden = original.hidden;
 5787                    paramLabel = original.paramLabel;
 5788                    hideParamSyntax = original.hideParamSyntax;
 5789                    required = original.required;
 5790                    interactive = original.interactive;
 5791                    showDefaultValue = original.showDefaultValue;
 5792                    completionCandidates = original.completionCandidates;
 5793                    splitRegex = original.splitRegex;
 5794                    toString = original.toString;
 5795                    descriptionKey = original.descriptionKey;
 5796                    setTypeInfo(original.typeInfo);
 5797                }
 5798                Builder(IAnnotatedElement source) {
 5799                    userObject = source.userObject();
 5800                    setTypeInfo(source.getTypeInfo());
 5801                    toString = source.getToString();
 5802                    getter = source.getter();
 5803                    setter = source.setter();
 5804                    scope = source.scope();
 5805                    hasInitialValue = source.hasInitialValue();
 5806                    try { initialValue = source.getter().get(); } catch (Exception ex) { initialValue = null; hasInitialValue = false; }
 5807                }
 5808                Builder(Option option, IAnnotatedElement source, IFactory factory) {
 5809                    this(source);
 5810                    arity = Range.optionArity(source);
 5811                    required = option.required();
 5812
 5813                    paramLabel = inferLabel(option.paramLabel(), source.getName(), source.getTypeInfo());
 5814
 5815                    hideParamSyntax = option.hideParamSyntax();
 5816                    interactive = option.interactive();
 5817                    description = option.description();
 5818                    descriptionKey = option.descriptionKey();
 5819                    splitRegex = option.split();
 5820                    hidden = option.hidden();
 5821                    defaultValue = option.defaultValue();
 5822                    showDefaultValue = option.showDefaultValue();
 5823                    if (factory != null) {
 5824                        converters = DefaultFactory.createConverter(factory, option.converter());
 5825                        if (!NoCompletionCandidates.class.equals(option.completionCandidates())) {
 5826                            completionCandidates = DefaultFactory.createCompletionCandidates(factory, option.completionCandidates());
 5827                        }
 5828                    }
 5829                }
 5830                Builder(Parameters parameters, IAnnotatedElement source, IFactory factory) {
 5831                    this(source);
 5832                    arity = Range.parameterArity(source);
 5833                    required = arity.min > 0;
 5834
 5835                    // method parameters may be positional parameters without @Parameters annotation
 5836                    if (parameters == null) {
 5837                        paramLabel = inferLabel(null, source.getName(), source.getTypeInfo());
 5838                    } else {
 5839                        paramLabel = inferLabel(parameters.paramLabel(), source.getName(), source.getTypeInfo());
 5840
 5841                        hideParamSyntax = parameters.hideParamSyntax();
 5842                        interactive = parameters.interactive();
 5843                        description = parameters.description();
 5844                        descriptionKey = parameters.descriptionKey();
 5845                        splitRegex = parameters.split();
 5846                        hidden = parameters.hidden();
 5847                        defaultValue = parameters.defaultValue();
 5848                        showDefaultValue = parameters.showDefaultValue();
 5849                        if (factory != null) { // annotation processors will pass a null factory
 5850                            converters = DefaultFactory.createConverter(factory, parameters.converter());
 5851                            if (!NoCompletionCandidates.class.equals(parameters.completionCandidates())) {
 5852                                completionCandidates = DefaultFactory.createCompletionCandidates(factory, parameters.completionCandidates());
 5853                            }
 5854                        }
 5855                    }
 5856                }
 5857                private static String inferLabel(String label, String fieldName, ITypeInfo typeInfo) {
 5858                    if (!empty(label)) { return label.trim(); }
 5859                    String name = fieldName;
 5860                    if (typeInfo.isMap()) { // #195 better param labels for map fields
 5861                        List<ITypeInfo> aux = typeInfo.getAuxiliaryTypeInfos();
 5862                        if (aux.size() < 2 || aux.get(0) == null || aux.get(1) == null) {
 5863                            name = "String=String";
 5864                        } else { name = aux.get(0).getClassSimpleName() + "=" + aux.get(1).getClassSimpleName(); }
 5865                    }
 5866                    return "<" + name + ">";
 5867                }
 5868
 5869                public    abstract ArgSpec build();
 5870                protected abstract T self(); // subclasses must override to return "this"
 5871                /** Returns whether this is a required option or positional parameter.
 5872                 * @see Option#required() */
 5873                public boolean required()      { return required; }
 5874                /** Returns whether this option prompts the user to enter a value on the command line.
 5875                 * @see Option#interactive() */
 5876                public boolean interactive()   { return interactive; }
 5877
 5878                /** Returns the description of this option, used when generating the usage documentation.
 5879                 * @see Option#description() */
 5880                public String[] description()  { return description; }
 5881
 5882                /** Returns the description key of this arg spec, used to get the description from a resource bundle.
 5883                 * @see Option#descriptionKey()
 5884                 * @see Parameters#descriptionKey()
 5885                 * @since 3.6 */
 5886                public String descriptionKey()  { return descriptionKey; }
 5887
 5888                /** Returns how many arguments this option or positional parameter requires.
 5889                 * @see Option#arity() */
 5890                public Range arity()           { return arity; }
 5891    
 5892                /** Returns the name of the option or positional parameter used in the usage help message.
 5893                 * @see Option#paramLabel() {@link Parameters#paramLabel()} */
 5894                public String paramLabel()     { return paramLabel; }
 5895
 5896                /** Returns whether usage syntax decorations around the {@linkplain #paramLabel() paramLabel} should be suppressed.
 5897                 * The default is {@code false}: by default, the paramLabel is surrounded with {@code '['} and {@code ']'} characters
 5898                 * if the value is optional and followed by ellipses ("...") when multiple values can be specified.
 5899                 * @since 3.6.0 */
 5900                public boolean hideParamSyntax()     { return hideParamSyntax; }
 5901
 5902                /** Returns auxiliary type information used when the {@link #type()} is a generic {@code Collection}, {@code Map} or an abstract class.
 5903                 * @see Option#type() */
 5904                public Class<?>[] auxiliaryTypes() { return auxiliaryTypes; }
 5905
 5906                /** Returns one or more {@link CommandLine.ITypeConverter type converters} to use to convert the command line
 5907                 * argument into a strongly typed value (or key-value pair for map fields). This is useful when a particular
 5908                 * option or positional parameter should use a custom conversion that is different from the normal conversion for the arg spec's type.
 5909                 * @see Option#converter() */
 5910                public ITypeConverter<?>[] converters() { return converters; }
 5911
 5912                /** Returns a regular expression to split option parameter values or {@code ""} if the value should not be split.
 5913                 * @see Option#split() */
 5914                public String splitRegex()     { return splitRegex; }
 5915
 5916                /** Returns whether this option should be excluded from the usage message.
 5917                 * @see Option#hidden() */
 5918                public boolean hidden()        { return hidden; }
 5919
 5920                /** Returns the type to convert the option or positional parameter to before {@linkplain #setValue(Object) setting} the value. */
 5921                public Class<?> type()         { return type; }
 5922
 5923                /** Returns the type info for this option or positional parameter.
 5924                 * @return type information that does not require {@code Class} objects and be constructed both at runtime and compile time
 5925                 * @since 4.0
 5926                 */
 5927                public ITypeInfo typeInfo()    { return typeInfo; }
 5928
 5929                /** Returns the user object associated with this option or positional parameters.
 5930                 * @return may return the annotated program element, or some other useful object
 5931                 * @since 4.0 */
 5932                public Object userObject()     { return userObject; }
 5933
 5934                /** Returns the default value of this option or positional parameter, before splitting and type conversion.
 5935                 * A value of {@code null} means this option or positional parameter does not have a default. */
 5936                public String defaultValue()   { return defaultValue; }
 5937                /** Returns the initial value this option or positional parameter. If {@link #hasInitialValue()} is true,
 5938                 * the option will be reset to the initial value before parsing (regardless of whether a default value exists),
 5939                 * to clear values that would otherwise remain from parsing previous input. */
 5940                public Object initialValue()     { return initialValue; }
 5941                /** Determines whether the option or positional parameter will be reset to the {@link #initialValue()}
 5942                 * before parsing new input.*/
 5943                public boolean hasInitialValue() { return hasInitialValue; }
 5944
 5945                /** Returns whether this option or positional parameter's default value should be shown in the usage help. */
 5946                public Help.Visibility showDefaultValue() { return showDefaultValue; }
 5947
 5948                /** Returns the completion candidates for this option or positional parameter, or {@code null}.
 5949                 * @since 3.2 */
 5950                public Iterable<String> completionCandidates() { return completionCandidates; }
 5951
 5952                /** Returns the {@link IGetter} that is responsible for supplying the value of this argument. */
 5953                public IGetter getter()        { return getter; }
 5954                /** Returns the {@link ISetter} that is responsible for modifying the value of this argument. */
 5955                public ISetter setter()        { return setter; }
 5956                /** Returns the {@link IScope} that determines where the setter sets the value (or the getter gets the value) of this argument. */
 5957                public IScope scope()          { return scope; }
 5958
 5959                public String toString() { return toString; }
 5960
 5961                /** Sets whether this is a required option or positional parameter, and returns this builder. */
 5962                public T required(boolean required)          { this.required = required; return self(); }
 5963
 5964                /** Sets whether this option prompts the user to enter a value on the command line, and returns this builder. */
 5965                public T interactive(boolean interactive)    { this.interactive = interactive; return self(); }
 5966
 5967                /** Sets the description of this option, used when generating the usage documentation, and returns this builder.
 5968                 * @see Option#description() */
 5969                public T description(String... description)  { this.description = Assert.notNull(description, "description").clone(); return self(); }
 5970
 5971                /** Sets the description key that is used to look up the description in a resource bundle, and returns this builder.
 5972                 * @see Option#descriptionKey()
 5973                 * @see Parameters#descriptionKey()
 5974                 * @since 3.6 */
 5975                public T descriptionKey(String descriptionKey) { this.descriptionKey = descriptionKey; return self(); }
 5976
 5977                /** Sets how many arguments this option or positional parameter requires, and returns this builder. */
 5978                public T arity(String range)                 { return arity(Range.valueOf(range)); }
 5979    
 5980                /** Sets how many arguments this option or positional parameter requires, and returns this builder. */
 5981                public T arity(Range arity)                  { this.arity = Assert.notNull(arity, "arity"); return self(); }
 5982    
 5983                /** Sets the name of the option or positional parameter used in the usage help message, and returns this builder. */
 5984                public T paramLabel(String paramLabel)       { this.paramLabel = Assert.notNull(paramLabel, "paramLabel"); return self(); }
 5985
 5986                /** Sets whether usage syntax decorations around the {@linkplain #paramLabel() paramLabel} should be suppressed.
 5987                 * The default is {@code false}: by default, the paramLabel is surrounded with {@code '['} and {@code ']'} characters
 5988                 * if the value is optional and followed by ellipses ("...") when multiple values can be specified.
 5989                 * @since 3.6.0 */
 5990                public T hideParamSyntax(boolean hideParamSyntax) { this.hideParamSyntax = hideParamSyntax; return self(); }
 5991    
 5992                /** Sets auxiliary type information, and returns this builder.
 5993                 * @param types  the element type(s) when the {@link #type()} is a generic {@code Collection} or a {@code Map};
 5994                 * or the concrete type when the {@link #type()} is an abstract class. */
 5995                public T auxiliaryTypes(Class<?>... types)   { this.auxiliaryTypes = Assert.notNull(types, "types").clone(); return self(); }
 5996    
 5997                /** Sets option/positional param-specific converter (or converters for Maps), and returns this builder. */
 5998                public T converters(ITypeConverter<?>... cs) { this.converters = Assert.notNull(cs, "type converters").clone(); return self(); }
 5999    
 6000                /** Sets a regular expression to split option parameter values or {@code ""} if the value should not be split, and returns this builder. */
 6001                public T splitRegex(String splitRegex)       { this.splitRegex = Assert.notNull(splitRegex, "splitRegex"); return self(); }
 6002    
 6003                /** Sets whether this option or positional parameter's default value should be shown in the usage help, and returns this builder. */
 6004                public T showDefaultValue(Help.Visibility visibility) { showDefaultValue = Assert.notNull(visibility, "visibility"); return self(); }
 6005
 6006                /** Sets the completion candidates for this option or positional parameter, and returns this builder.
 6007                 * @since 3.2 */
 6008                public T completionCandidates(Iterable<String> completionCandidates) { this.completionCandidates = completionCandidates; return self(); }
 6009
 6010                /** Sets whether this option should be excluded from the usage message, and returns this builder. */
 6011                public T hidden(boolean hidden)              { this.hidden = hidden; return self(); }
 6012    
 6013                /** Sets the type to convert the option or positional parameter to before {@linkplain #setValue(Object) setting} the value, and returns this builder.
 6014                 * @param propertyType the type of this option or parameter. For multi-value options and positional parameters this can be an array, or a (sub-type of) Collection or Map. */
 6015                public T type(Class<?> propertyType)         { this.type = Assert.notNull(propertyType, "type"); return self(); }
 6016
 6017                /** Sets the type info for this option or positional parameter, and returns this builder.
 6018                 * @param typeInfo type information that does not require {@code Class} objects and be constructed both at runtime and compile time
 6019                 * @since 4.0 */
 6020                public T typeInfo(ITypeInfo typeInfo) {
 6021                    setTypeInfo(Assert.notNull(typeInfo, "typeInfo"));
 6022                    return self();
 6023                }
 6024                private void setTypeInfo(ITypeInfo newValue) {
 6025                    this.typeInfo = newValue;
 6026                    if (typeInfo != null) {
 6027                        type = typeInfo.getType();
 6028                        auxiliaryTypes = typeInfo.getAuxiliaryTypes();
 6029                    }
 6030                }
 6031
 6032                /** Sets the user object associated with this option or positional parameters, and returns this builder.
 6033                 * @param userObject may be the annotated program element, or some other useful object
 6034                 * @since 4.0 */
 6035                public T userObject(Object userObject)     { this.userObject = Assert.notNull(userObject, "userObject"); return self(); }
 6036
 6037                /** Sets the default value of this option or positional parameter to the specified value, and returns this builder.
 6038                 * Before parsing the command line, the result of {@linkplain #splitRegex() splitting} and {@linkplain #converters() type converting}
 6039                 * this default value is applied to the option or positional parameter. A value of {@code null} or {@code "__no_default_value__"} means no default. */
 6040                public T defaultValue(String defaultValue)   { this.defaultValue = defaultValue; return self(); }
 6041
 6042                /** Sets the initial value of this option or positional parameter to the specified value, and returns this builder.
 6043                 * If {@link #hasInitialValue()} is true, the option will be reset to the initial value before parsing (regardless
 6044                 * of whether a default value exists), to clear values that would otherwise remain from parsing previous input. */
 6045                public T initialValue(Object initialValue)   { this.initialValue = initialValue; return self(); }
 6046
 6047                /** Determines whether the option or positional parameter will be reset to the {@link #initialValue()}
 6048                 * before parsing new input.*/
 6049                public T hasInitialValue(boolean hasInitialValue)   { this.hasInitialValue = hasInitialValue; return self(); }
 6050
 6051                /** Sets the {@link IGetter} that is responsible for getting the value of this argument, and returns this builder. */
 6052                public T getter(IGetter getter)              { this.getter = getter; return self(); }
 6053                /** Sets the {@link ISetter} that is responsible for modifying the value of this argument, and returns this builder. */
 6054                public T setter(ISetter setter)              { this.setter = setter; return self(); }
 6055                /** Sets the {@link IScope} that targets where the setter sets the value, and returns this builder. */
 6056                public T scope(IScope scope)                 { this.scope = scope; return self(); }
 6057
 6058                /** Sets the string respresentation of this option or positional parameter to the specified value, and returns this builder. */
 6059                public T withToString(String toString)       { this.toString = toString; return self(); }
 6060            }
 6061        }
 6062        /** The {@code OptionSpec} class models aspects of a <em>named option</em> of a {@linkplain CommandSpec command}, including whether
 6063         * it is required or optional, the option parameters supported (or required) by the option,
 6064         * and attributes for the usage help message describing the option.
 6065         * <p>
 6066         * An option has one or more names. The option is matched when the parser encounters one of the option names in the command line arguments.
 6067         * Depending on the option's {@link #arity() arity},
 6068         * the parser may expect it to have option parameters. The parser will call {@link #setValue(Object) setValue} on
 6069         * the matched option for each of the option parameters encountered.
 6070         * </p><p>
 6071         * For multi-value options, the {@code type} may be an array, a {@code Collection} or a {@code Map}. In this case
 6072         * the parser will get the data structure by calling {@link #getValue() getValue} and modify the contents of this data structure.
 6073         * (In the case of arrays, the array is replaced with a new instance with additional elements.)
 6074         * </p><p>
 6075         * Before calling the setter, picocli converts the option parameter value from a String to the option parameter's type.
 6076         * </p>
 6077         * <ul>
 6078         *   <li>If a option-specific {@link #converters() converter} is configured, this will be used for type conversion.
 6079         *   If the option's type is a {@code Map}, the map may have different types for its keys and its values, so
 6080         *   {@link #converters() converters} should provide two converters: one for the map keys and one for the map values.</li>
 6081         *   <li>Otherwise, the option's {@link #type() type} is used to look up a converter in the list of
 6082         *   {@linkplain CommandLine#registerConverter(Class, ITypeConverter) registered converters}.
 6083         *   For multi-value options,
 6084         *   the {@code type} may be an array, or a {@code Collection} or a {@code Map}. In that case the elements are converted
 6085         *   based on the option's {@link #auxiliaryTypes() auxiliaryTypes}. The auxiliaryType is used to look up
 6086         *   the converter(s) to use to convert the individual parameter values.
 6087         *   Maps may have different types for its keys and its values, so {@link #auxiliaryTypes() auxiliaryTypes}
 6088         *   should provide two types: one for the map keys and one for the map values.</li>
 6089         * </ul>
 6090         * <p>
 6091         * {@code OptionSpec} objects are used by the picocli command line interpreter and help message generator.
 6092         * Picocli can construct an {@code OptionSpec} automatically from fields and methods with {@link Option @Option}
 6093         * annotations. Alternatively an {@code OptionSpec} can be constructed programmatically.
 6094         * </p><p>
 6095         * When an {@code OptionSpec} is created from an {@link Option @Option} -annotated field or method, it is "bound"
 6096         * to that field or method: this field is set (or the method is invoked) when the option is matched and
 6097         * {@link #setValue(Object) setValue} is called.
 6098         * Programmatically constructed {@code OptionSpec} instances will remember the value passed to the
 6099         * {@link #setValue(Object) setValue} method so it can be retrieved with the {@link #getValue() getValue} method.
 6100         * This behaviour can be customized by installing a custom {@link IGetter} and {@link ISetter} on the {@code OptionSpec}.
 6101         * </p>
 6102         * @since 3.0 */
 6103        public static class OptionSpec extends ArgSpec implements IOrdered {
 6104            static final int DEFAULT_ORDER = -1;
 6105            private String[] names;
 6106            private boolean help;
 6107            private boolean usageHelp;
 6108            private boolean versionHelp;
 6109            private int order;
 6110
 6111            public static OptionSpec.Builder builder(String name, String... names) {
 6112                String[] copy = new String[Assert.notNull(names, "names").length + 1];
 6113                copy[0] = Assert.notNull(name, "name");
 6114                System.arraycopy(names, 0, copy, 1, names.length);
 6115                return new Builder(copy);
 6116            }
 6117            public static OptionSpec.Builder builder(String[] names) { return new Builder(names); }
 6118            public static OptionSpec.Builder builder(IAnnotatedElement source, IFactory factory) { return new Builder(source, factory); }
 6119
 6120            /** Ensures all attributes of this {@code OptionSpec} have a valid value; throws an {@link InitializationException} if this cannot be achieved. */
 6121            private OptionSpec(Builder builder) {
 6122                super(builder);
 6123                if (builder.names == null) {
 6124                    throw new InitializationException("OptionSpec names cannot be null. Specify at least one option name.");
 6125                }
 6126                names = builder.names.clone();
 6127                help = builder.help;
 6128                usageHelp = builder.usageHelp;
 6129                versionHelp = builder.versionHelp;
 6130                order = builder.order;
 6131
 6132                if (names.length == 0 || Arrays.asList(names).contains("")) {
 6133                    throw new InitializationException("Invalid names: " + Arrays.toString(names));
 6134                }
 6135                if (toString() == null) { toString = "option " + longestName(); }
 6136
 6137//                if (arity().max == 0 && !(isBoolean(type()) || (isMultiValue() && isBoolean(auxiliaryTypes()[0])))) {
 6138//                    throw new InitializationException("Option " + longestName() + " is not a boolean so should not be defined with arity=" + arity());
 6139//                }
 6140            }
 6141    
 6142            /** Returns a new Builder initialized with the attributes from this {@code OptionSpec}. Calling {@code build} immediately will return a copy of this {@code OptionSpec}.
 6143             * @return a builder that can create a copy of this spec
 6144             */
 6145            public Builder toBuilder()    { return new Builder(this); }
 6146            @Override public boolean isOption()     { return true; }
 6147            @Override public boolean isPositional() { return false; }
 6148
 6149            protected boolean internalShowDefaultValue(boolean usageMessageShowDefaults) {
 6150                return super.internalShowDefaultValue(usageMessageShowDefaults) && !help() && !versionHelp() && !usageHelp();
 6151            }
 6152
 6153            /** Returns the description template of this option, before variables are {@linkplain Option#description() rendered}.
 6154             * If a resource bundle has been {@linkplain ArgSpec#messages(Messages) set}, this method will first try to find a value in the resource bundle:
 6155             * If the resource bundle has no entry for the {@code fully qualified commandName + "." + descriptionKey} or for the unqualified {@code descriptionKey},
 6156             * an attempt is made to find the option description using any of the option names (without leading hyphens) as key,
 6157             * first with the {@code fully qualified commandName + "."} prefix, then without.
 6158             * @see CommandSpec#qualifiedName(String)
 6159             * @see Option#description() */
 6160            @Override public String[] description() {
 6161                if (messages() == null) { return super.description(); }
 6162                String[] newValue = messages().getStringArray(descriptionKey(), null);
 6163                if (newValue != null) { return newValue; }
 6164                for (String name : names()) {
 6165                    newValue = messages().getStringArray(CommandSpec.stripPrefix(name), null);
 6166                    if (newValue != null) { return newValue; }
 6167                }
 6168                return super.description();
 6169            }
 6170
 6171            /** Returns one or more option names. The returned array will contain at least one option name.
 6172             * @see Option#names() */
 6173            public String[] names() { return names.clone(); }
 6174
 6175            /** Returns the longest {@linkplain #names() option name}. */
 6176            public String longestName() { return Help.ShortestFirst.longestFirst(names.clone())[0]; }
 6177
 6178            /** Returns the shortest {@linkplain #names() option name}.
 6179             * @since 3.8 */
 6180            public String shortestName() { return Help.ShortestFirst.sort(names.clone())[0]; }
 6181
 6182            /** Returns the position in the options list in the usage help message at which this option should be shown.
 6183             * Options with a lower number are shown before options with a higher number.
 6184             * This attribute is only honored if {@link UsageMessageSpec#sortOptions()} is {@code false} for this command.
 6185             * @see Option#order()
 6186             * @since 3.9 */
 6187            public int order() { return this.order; }
 6188
 6189            /** Returns whether this option disables validation of the other arguments.
 6190             * @see Option#help()
 6191             * @deprecated Use {@link #usageHelp()} and {@link #versionHelp()} instead. */
 6192            @Deprecated public boolean help() { return help; }
 6193    
 6194            /** Returns whether this option allows the user to request usage help.
 6195             * @see Option#usageHelp()  */
 6196            public boolean usageHelp()    { return usageHelp; }
 6197    
 6198            /** Returns whether this option allows the user to request version information.
 6199             * @see Option#versionHelp()  */
 6200            public boolean versionHelp()  { return versionHelp; }
 6201            public boolean equals(Object obj) {
 6202                if (obj == this) { return true; }
 6203                if (!(obj instanceof OptionSpec)) { return false; }
 6204                OptionSpec other = (OptionSpec) obj;
 6205                boolean result = super.equalsImpl(other)
 6206                        && help == other.help
 6207                        && usageHelp == other.usageHelp
 6208                        && versionHelp == other.versionHelp
 6209                        && order == other.order
 6210                        && new HashSet<String>(Arrays.asList(names)).equals(new HashSet<String>(Arrays.asList(other.names)));
 6211                return result;
 6212            }
 6213            public int hashCode() {
 6214                return super.hashCodeImpl()
 6215                        + 37 * Assert.hashCode(help)
 6216                        + 37 * Assert.hashCode(usageHelp)
 6217                        + 37 * Assert.hashCode(versionHelp)
 6218                        + 37 * Arrays.hashCode(names)
 6219                        + 37 * order;
 6220            }
 6221    
 6222            /** Builder responsible for creating valid {@code OptionSpec} objects.
 6223             * @since 3.0
 6224             */
 6225            public static class Builder extends ArgSpec.Builder<Builder> {
 6226                private String[] names;
 6227                private boolean help;
 6228                private boolean usageHelp;
 6229                private boolean versionHelp;
 6230                private int order = DEFAULT_ORDER;
 6231
 6232                private Builder(String[] names) { this.names = names; }
 6233                private Builder(OptionSpec original) {
 6234                    super(original);
 6235                    names = original.names;
 6236                    help = original.help;
 6237                    usageHelp = original.usageHelp;
 6238                    versionHelp = original.versionHelp;
 6239                    order = original.order;
 6240                }
 6241                private Builder(IAnnotatedElement member, IFactory factory) {
 6242                    super(member.getAnnotation(Option.class), member, factory);
 6243                    Option option = member.getAnnotation(Option.class);
 6244                    names = option.names();
 6245                    help = option.help();
 6246                    usageHelp = option.usageHelp();
 6247                    versionHelp = option.versionHelp();
 6248                    order = option.order();
 6249                }
 6250
 6251                /** Returns a valid {@code OptionSpec} instance. */
 6252                @Override public OptionSpec build() { return new OptionSpec(this); }
 6253                /** Returns this builder. */
 6254                @Override protected Builder self() { return this; }
 6255
 6256                /** Returns one or more option names. At least one option name is required.
 6257                 * @see Option#names() */
 6258                public String[] names()       { return names; }
 6259
 6260                /** Returns whether this option disables validation of the other arguments.
 6261                 * @see Option#help()
 6262                 * @deprecated Use {@link #usageHelp()} and {@link #versionHelp()} instead. */
 6263                @Deprecated public boolean help() { return help; }
 6264
 6265                /** Returns whether this option allows the user to request usage help.
 6266                 * @see Option#usageHelp()  */
 6267                public boolean usageHelp()    { return usageHelp; }
 6268
 6269                /** Returns whether this option allows the user to request version information.
 6270                 * @see Option#versionHelp()  */
 6271                public boolean versionHelp()  { return versionHelp; }
 6272
 6273                /** Returns the position in the options list in the usage help message at which this option should be shown.
 6274                 * Options with a lower number are shown before options with a higher number.
 6275                 * This attribute is only honored if {@link UsageMessageSpec#sortOptions()} is {@code false} for this command.
 6276                 * @see Option#order()
 6277                 * @since 3.9 */
 6278                public int order()  { return order; }
 6279
 6280                /** Replaces the option names with the specified values. At least one option name is required, and returns this builder.
 6281                 * @return this builder instance to provide a fluent interface */
 6282                public Builder names(String... names)           { this.names = Assert.notNull(names, "names").clone(); return self(); }
 6283    
 6284                /** Sets whether this option disables validation of the other arguments, and returns this builder. */
 6285                public Builder help(boolean help)               { this.help = help; return self(); }
 6286    
 6287                /** Sets whether this option allows the user to request usage help, and returns this builder. */
 6288                public Builder usageHelp(boolean usageHelp)     { this.usageHelp = usageHelp; return self(); }
 6289    
 6290                /** Sets whether this option allows the user to request version information, and returns this builder.*/
 6291                public Builder versionHelp(boolean versionHelp) { this.versionHelp = versionHelp; return self(); }
 6292
 6293                /** Sets the position in the options list in the usage help message at which this option should be shown, and returns this builder.
 6294                 * @since 3.9 */
 6295                public Builder order(int order) { this.order = order; return self(); }
 6296            }
 6297        }
 6298        /** The {@code PositionalParamSpec} class models aspects of a <em>positional parameter</em> of a {@linkplain CommandSpec command}, including whether
 6299         * it is required or optional, and attributes for the usage help message describing the positional parameter.
 6300         * <p>
 6301         * Positional parameters have an {@link #index() index} (or a range of indices). A positional parameter is matched when the parser
 6302         * encounters a command line argument at that index. Named options and their parameters do not change the index counter,
 6303         * so the command line can contain a mixture of positional parameters and named options.
 6304         * </p><p>
 6305         * Depending on the positional parameter's {@link #arity() arity}, the parser may consume multiple command line
 6306         * arguments starting from the current index. The parser will call {@link #setValue(Object) setValue} on
 6307         * the {@code PositionalParamSpec} for each of the parameters encountered.
 6308         * For multi-value positional parameters, the {@code type} may be an array, a {@code Collection} or a {@code Map}. In this case
 6309         * the parser will get the data structure by calling {@link #getValue() getValue} and modify the contents of this data structure.
 6310         * (In the case of arrays, the array is replaced with a new instance with additional elements.)
 6311         * </p><p>
 6312         * Before calling the setter, picocli converts the positional parameter value from a String to the parameter's type.
 6313         * </p>
 6314         * <ul>
 6315         *   <li>If a positional parameter-specific {@link #converters() converter} is configured, this will be used for type conversion.
 6316         *   If the positional parameter's type is a {@code Map}, the map may have different types for its keys and its values, so
 6317         *   {@link #converters() converters} should provide two converters: one for the map keys and one for the map values.</li>
 6318         *   <li>Otherwise, the positional parameter's {@link #type() type} is used to look up a converter in the list of
 6319         *   {@linkplain CommandLine#registerConverter(Class, ITypeConverter) registered converters}. For multi-value positional parameters,
 6320         *   the {@code type} may be an array, or a {@code Collection} or a {@code Map}. In that case the elements are converted
 6321         *   based on the positional parameter's {@link #auxiliaryTypes() auxiliaryTypes}. The auxiliaryType is used to look up
 6322         *   the converter(s) to use to convert the individual parameter values.
 6323         *   Maps may have different types for its keys and its values, so {@link #auxiliaryTypes() auxiliaryTypes}
 6324         *   should provide two types: one for the map keys and one for the map values.</li>
 6325         * </ul>
 6326         * <p>
 6327         * {@code PositionalParamSpec} objects are used by the picocli command line interpreter and help message generator.
 6328         * Picocli can construct a {@code PositionalParamSpec} automatically from fields and methods with {@link Parameters @Parameters}
 6329         * annotations. Alternatively a {@code PositionalParamSpec} can be constructed programmatically.
 6330         * </p><p>
 6331         * When a {@code PositionalParamSpec} is created from a {@link Parameters @Parameters} -annotated field or method,
 6332         * it is "bound" to that field or method: this field is set (or the method is invoked) when the position is matched
 6333         * and {@link #setValue(Object) setValue} is called.
 6334         * Programmatically constructed {@code PositionalParamSpec} instances will remember the value passed to the
 6335         * {@link #setValue(Object) setValue} method so it can be retrieved with the {@link #getValue() getValue} method.
 6336         * This behaviour can be customized by installing a custom {@link IGetter} and {@link ISetter} on the {@code PositionalParamSpec}.
 6337         * </p>
 6338         * @since 3.0 */
 6339        public static class PositionalParamSpec extends ArgSpec {
 6340            private Range index;
 6341            private Range capacity;
 6342
 6343            /** Ensures all attributes of this {@code PositionalParamSpec} have a valid value; throws an {@link InitializationException} if this cannot be achieved. */
 6344            private PositionalParamSpec(Builder builder) {
 6345                super(builder);
 6346                index = builder.index == null ? Range.valueOf("*") : builder.index; 
 6347                capacity = builder.capacity == null ? Range.parameterCapacity(arity(), index) : builder.capacity;
 6348                if (toString == null) { toString = "positional parameter[" + index() + "]"; }
 6349            }
 6350            public static Builder builder() { return new Builder(); }
 6351            public static Builder builder(IAnnotatedElement source, IFactory factory) { return new Builder(source, factory); }
 6352            /** Returns a new Builder initialized with the attributes from this {@code PositionalParamSpec}. Calling {@code build} immediately will return a copy of this {@code PositionalParamSpec}.
 6353             * @return a builder that can create a copy of this spec
 6354             */
 6355            public Builder toBuilder()    { return new Builder(this); }
 6356            @Override public boolean isOption()     { return false; }
 6357            @Override public boolean isPositional() { return true; }
 6358
 6359            /** Returns the description template of this positional parameter, before variables are {@linkplain Parameters#description() rendered}.
 6360             * If a resource bundle has been {@linkplain ArgSpec#messages(Messages) set}, this method will first try to find a value in the resource bundle:
 6361             * If the resource bundle has no entry for the {@code fully qualified commandName + "." + descriptionKey} or for the unqualified {@code descriptionKey},
 6362             * an attempt is made to find the positional parameter description using {@code paramLabel() + "[" + index() + "]"} as key,
 6363             * first with the {@code fully qualified commandName + "."} prefix, then without.
 6364             * @see Parameters#description()
 6365             * @see CommandSpec#qualifiedName(String)
 6366             * @since 3.6 */
 6367            @Override public String[] description() {
 6368                if (messages() == null) { return super.description(); }
 6369                String[] newValue = messages().getStringArray(descriptionKey(), null);
 6370                if (newValue != null) { return newValue; }
 6371                newValue = messages().getStringArray(paramLabel() + "[" + index() + "]", null);
 6372                if (newValue != null) { return newValue; }
 6373                return super.description();
 6374            }
 6375
 6376            /** Returns an index or range specifying which of the command line arguments should be assigned to this positional parameter.
 6377             * @see Parameters#index() */
 6378            public Range index()            { return index; }
 6379            private Range capacity()        { return capacity; }
 6380
 6381            public int hashCode() {
 6382                return super.hashCodeImpl()
 6383                        + 37 * Assert.hashCode(capacity)
 6384                        + 37 * Assert.hashCode(index);
 6385            }
 6386            public boolean equals(Object obj) {
 6387                if (obj == this) {
 6388                    return true;
 6389                }
 6390                if (!(obj instanceof PositionalParamSpec)) {
 6391                    return false;
 6392                }
 6393                PositionalParamSpec other = (PositionalParamSpec) obj;
 6394                return super.equalsImpl(other)
 6395                        && Assert.equals(this.capacity, other.capacity)
 6396                        && Assert.equals(this.index, other.index);
 6397            }
 6398    
 6399            /** Builder responsible for creating valid {@code PositionalParamSpec} objects.
 6400             * @since 3.0
 6401             */
 6402            public static class Builder extends ArgSpec.Builder<Builder> {
 6403                private Range capacity;
 6404                private Range index;
 6405                private Builder() {}
 6406                private Builder(PositionalParamSpec original) {
 6407                    super(original);
 6408                    index = original.index;
 6409                    capacity = original.capacity;
 6410                }
 6411                private Builder(IAnnotatedElement member, IFactory factory) {
 6412                    super(member.getAnnotation(Parameters.class), member, factory);
 6413                    index = Range.parameterIndex(member);
 6414                    capacity = Range.parameterCapacity(member);
 6415                }
 6416                /** Returns a valid {@code PositionalParamSpec} instance. */
 6417                @Override public PositionalParamSpec build() { return new PositionalParamSpec(this); }
 6418                /** Returns this builder. */
 6419                @Override protected Builder self()  { return this; }
 6420
 6421                /** Returns an index or range specifying which of the command line arguments should be assigned to this positional parameter.
 6422                 * @see Parameters#index() */
 6423                public Range index()            { return index; }
 6424
 6425                /** Sets the index or range specifying which of the command line arguments should be assigned to this positional parameter, and returns this builder. */
 6426                public Builder index(String range)  { return index(Range.valueOf(range)); }
 6427    
 6428                /** Sets the index or range specifying which of the command line arguments should be assigned to this positional parameter, and returns this builder. */
 6429                public Builder index(Range index)   { this.index = index; return self(); }
 6430
 6431                Range capacity()                   { return capacity; }
 6432                Builder capacity(Range capacity)   { this.capacity = capacity; return self(); }
 6433            }
 6434        }
 6435
 6436        /** Interface for sorting {@link OptionSpec options} and {@link ArgGroupSpec groups} together.
 6437         * @since 4.0 */
 6438        public interface IOrdered {
 6439            /** Returns the position in the options list in the usage help message at which this element should be shown.
 6440             * Elements with a lower number are shown before elements with a higher number.
 6441             * This attribute is only honored if {@link UsageMessageSpec#sortOptions()} is {@code false} for this command. */
 6442            int order();
 6443        }
 6444
 6445        /** The {@code ArgGroupSpec} class models a {@link ArgGroup group} of arguments (options, positional parameters or a mixture of the two).
 6446         * @see ArgGroup
 6447         * @since 4.0 */
 6448        public static class ArgGroupSpec implements IOrdered {
 6449            static final int DEFAULT_ORDER = -1;
 6450            private static final String NO_HEADING = "__no_heading__";
 6451            private static final String NO_HEADING_KEY = "__no_heading_key__";
 6452            private final String heading;
 6453            private final String headingKey;
 6454            private final boolean exclusive;
 6455            private final Range multiplicity;
 6456            private final boolean validate;
 6457            private final int order;
 6458            private final IGetter getter;
 6459            private final ISetter setter;
 6460            private final IScope scope;
 6461            private final ITypeInfo typeInfo;
 6462            private final List<ArgGroupSpec> subgroups;
 6463            private final Set<ArgSpec> args;
 6464            private Messages messages;
 6465            private ArgGroupSpec parentGroup;
 6466            private String id = "1";
 6467
 6468            ArgGroupSpec(ArgGroupSpec.Builder builder) {
 6469                heading          = NO_HEADING    .equals(builder.heading)    ? null : builder.heading;
 6470                headingKey       = NO_HEADING_KEY.equals(builder.headingKey) ? null : builder.headingKey;
 6471                exclusive        = builder.exclusive;
 6472                multiplicity     = builder.multiplicity;
 6473                validate         = builder.validate;
 6474                order            = builder.order;
 6475                typeInfo         = builder.typeInfo;
 6476                getter           = builder.getter;
 6477                setter           = builder.setter;
 6478                scope            = builder.scope;
 6479
 6480                args      = Collections.unmodifiableSet(new LinkedHashSet<ArgSpec>(builder.args()));
 6481                subgroups = Collections.unmodifiableList(new ArrayList<ArgGroupSpec>(builder.subgroups()));
 6482                if (args.isEmpty() && subgroups.isEmpty()) { throw new InitializationException("ArgGroup has no options or positional parameters, and no subgroups"); }
 6483
 6484                int i = 1;
 6485                for (ArgGroupSpec sub : subgroups) { sub.parentGroup = this; sub.id = id + "." + i++; }
 6486                for (ArgSpec arg : args)           { arg.group = this; }
 6487            }
 6488
 6489            /** Returns a new {@link Builder}.
 6490             * @return a new ArgGroupSpec.Builder instance */
 6491            public static Builder builder() { return new Builder(); }
 6492
 6493            /** Returns a new {@link Builder} associated with the specified annotated element.
 6494             * @param annotatedElement the annotated element containing {@code @Option} and {@code @Parameters}
 6495             * @return a new ArgGroupSpec.Builder instance */
 6496            public static Builder builder(IAnnotatedElement annotatedElement) { return new Builder(Assert.notNull(annotatedElement, "annotatedElement")); }
 6497
 6498            /** Returns whether this is a mutually exclusive group; {@code true} by default.
 6499             * If {@code false}, this is a co-occurring group. Ignored if {@link #validate()} is {@code false}.
 6500             * @see ArgGroup#exclusive() */
 6501            public boolean exclusive() { return exclusive; }
 6502
 6503            /** Returns the multiplicity of this group: how many occurrences it may have on the command line; {@code "0..1"} (optional) by default.
 6504             * A group can be made required by specifying a multiplicity of {@code "1"}. For a group of mutually exclusive arguments,
 6505             * being required means that one of the arguments in the group must appear on the command line, or a MissingParameterException is thrown.
 6506             * For a group of co-occurring arguments, being required means that all arguments in the group must appear on the command line.
 6507             * Ignored if {@link #validate()} is {@code false}.
 6508             * @see ArgGroup#multiplicity() */
 6509            public Range multiplicity() { return multiplicity; }
 6510
 6511            /** Returns whether picocli should validate the rules of this group:
 6512             * for a mutually exclusive group this means that no more than one arguments in the group is specified on the command line;
 6513             * for a co-ocurring group this means that all arguments in the group are specified on the command line.
 6514             * {@code true} by default.
 6515             * @see ArgGroup#validate() */
 6516            public boolean validate() { return validate; }
 6517
 6518            /** Returns the position in the options list in the usage help message at which this group should be shown.
 6519             * Options with a lower number are shown before options with a higher number.
 6520             * This attribute is only honored if {@link UsageMessageSpec#sortOptions()} is {@code false} for this command. */
 6521            public int order() { return this.order; }
 6522
 6523            /** Returns the heading of this group (may be {@code null}), used when generating the usage documentation.
 6524             * @see ArgGroup#heading() */
 6525            public String heading()  {
 6526                if (messages() == null) { return heading; }
 6527                String newValue = messages().getString(headingKey(), null);
 6528                if (newValue != null) { return newValue; }
 6529                return heading;
 6530            }
 6531
 6532            /** Returns the heading key of this group (may be {@code null}), used to get the heading from a resource bundle.
 6533             * @see ArgGroup#headingKey()  */
 6534            public String headingKey() { return headingKey; }
 6535
 6536            /**
 6537             * Returns the parent group that this group is part of, or {@code null} if this group is not part of a composite.
 6538             */
 6539            public ArgGroupSpec parentGroup() { return parentGroup; }
 6540
 6541            /** Return the subgroups that this group is composed of; may be empty but not {@code null}.
 6542             * @return immutable list of subgroups that this group is composed of. */
 6543            public List<ArgGroupSpec> subgroups() { return subgroups; }
 6544
 6545            /**
 6546             * Returns {@code true} if this group is a subgroup (or a nested sub-subgroup, to any level of depth)
 6547             * of the specified group, {@code false} otherwise.
 6548             * @param group the group to check if it contains this group
 6549             * @return {@code true} if this group is a subgroup or a nested sub-subgroup of the specified group
 6550             */
 6551            public boolean isSubgroupOf(ArgGroupSpec group) {
 6552                for (ArgGroupSpec sub : group.subgroups) {
 6553                    if (this == sub) { return true; }
 6554                    if (isSubgroupOf(sub)) { return true; }
 6555                }
 6556                return false;
 6557            }
 6558            /** Returns the type info for the annotated program element associated with this group.
 6559             * @return type information that does not require {@code Class} objects and be constructed both at runtime and compile time
 6560             */
 6561            public ITypeInfo typeInfo()    { return typeInfo; }
 6562
 6563            /** Returns the {@link IGetter} that is responsible for supplying the value of the annotated program element associated with this group. */
 6564            public IGetter getter()        { return getter; }
 6565            /** Returns the {@link ISetter} that is responsible for modifying the value of the annotated program element associated with this group. */
 6566            public ISetter setter()        { return setter; }
 6567            /** Returns the {@link IScope} that determines where the setter sets the value (or the getter gets the value) of the annotated program element associated with this group. */
 6568            public IScope scope()          { return scope; }
 6569
 6570            Object userObject() { try { return getter.get(); } catch (Exception ex) { return ex.toString(); } }
 6571            String id() { return id; }
 6572
 6573            /** Returns the options and positional parameters in this group; may be empty but not {@code null}. */
 6574            public Set<ArgSpec> args() { return args; }
 6575            /** Returns the required options and positional parameters in this group; may be empty but not {@code null}. */
 6576            public Set<ArgSpec> requiredArgs() {
 6577                Set<ArgSpec> result = new LinkedHashSet<ArgSpec>(args);
 6578                for (Iterator<ArgSpec> iter = result.iterator(); iter.hasNext(); ) {
 6579                    if (!iter.next().required()) { iter.remove(); }
 6580                }
 6581                return Collections.unmodifiableSet(result);
 6582            }
 6583
 6584            /** Returns the list of positional parameters configured for this group.
 6585             * @return an immutable list of positional parameters in this group. */
 6586            public List<PositionalParamSpec> positionalParameters() {
 6587                List<PositionalParamSpec> result = new ArrayList<PositionalParamSpec>();
 6588                for (ArgSpec arg : args()) { if (arg instanceof PositionalParamSpec) { result.add((PositionalParamSpec) arg); } }
 6589                return Collections.unmodifiableList(result);
 6590            }
 6591            /** Returns the list of options configured for this group.
 6592             * @return an immutable list of options in this group. */
 6593            public List<OptionSpec> options() {
 6594                List<OptionSpec> result = new ArrayList<OptionSpec>();
 6595                for (ArgSpec arg : args()) { if (arg instanceof OptionSpec) { result.add((OptionSpec) arg); } }
 6596                return Collections.unmodifiableList(result);
 6597            }
 6598
 6599            public String synopsis() {
 6600                return synopsisText(new Help.ColorScheme(Help.Ansi.OFF)).toString();
 6601            }
 6602
 6603            public Text synopsisText(Help.ColorScheme colorScheme) {
 6604                String infix = exclusive() ? " | " : " ";
 6605                Text synopsis = colorScheme.ansi().new Text(0);
 6606                for (ArgSpec arg : args()) {
 6607                    if (synopsis.length > 0) { synopsis = synopsis.concat(infix); }
 6608                    if (arg instanceof OptionSpec) {
 6609                        synopsis = concatOptionText(synopsis, colorScheme, (OptionSpec) arg);
 6610                    } else {
 6611                        synopsis = concatPositionalText(synopsis, colorScheme, (PositionalParamSpec) arg);
 6612                    }
 6613                }
 6614                for (ArgGroupSpec subgroup : subgroups()) {
 6615                    if (synopsis.length > 0) { synopsis = synopsis.concat(infix); }
 6616                    synopsis = synopsis.concat(subgroup.synopsisText(colorScheme));
 6617                }
 6618                String prefix = multiplicity().min > 0 ? "(" : "[";
 6619                String postfix = multiplicity().min > 0 ? ")" : "]";
 6620                Text result = colorScheme.ansi().text(prefix).concat(synopsis).concat(postfix);
 6621                int i = 1;
 6622                for (; i < multiplicity.min; i++) {
 6623                    result = result.concat(" (").concat(synopsis).concat(")");
 6624                }
 6625                if (multiplicity().isVariable) {
 6626                    result = result.concat("...");
 6627                } else {
 6628                    for (; i < multiplicity.max; i++) {
 6629                        result = result.concat(" [").concat(synopsis).concat("]");
 6630                    }
 6631                }
 6632                return result;
 6633            }
 6634
 6635            private Text concatOptionText(Text text, Help.ColorScheme colorScheme, OptionSpec option) {
 6636                if (!option.hidden()) {
 6637                    Text name = colorScheme.optionText(option.shortestName());
 6638                    Text param = createLabelRenderer(option.commandSpec).renderParameterLabel(option, colorScheme.ansi(), colorScheme.optionParamStyles);
 6639                    text = text.concat(open(option)).concat(name).concat(param).concat(close(option));
 6640                    if (option.isMultiValue()) { // e.g., -x=VAL [-x=VAL]...
 6641                        text = text.concat(" [").concat(name).concat(param).concat("]...");
 6642                    }
 6643                }
 6644                return text;
 6645            }
 6646
 6647            private Text concatPositionalText(Text text, Help.ColorScheme colorScheme, PositionalParamSpec positionalParam) {
 6648                if (!positionalParam.hidden()) {
 6649                    Text label = createLabelRenderer(positionalParam.commandSpec).renderParameterLabel(positionalParam, colorScheme.ansi(), colorScheme.parameterStyles);
 6650                    text = text.concat(open(positionalParam)).concat(label).concat(close(positionalParam));
 6651                }
 6652                return text;
 6653            }
 6654            private String open(ArgSpec argSpec)  { return argSpec.required() ? "" : "["; }
 6655            private String close(ArgSpec argSpec) { return argSpec.required() ? "" : "]"; }
 6656
 6657            public Help.IParamLabelRenderer createLabelRenderer(CommandSpec commandSpec) {
 6658                return new Help.DefaultParamLabelRenderer(commandSpec == null ? CommandSpec.create() : commandSpec);
 6659            }
 6660            /** Returns the Messages for this argument group specification, or {@code null}. */
 6661            public Messages messages() { return messages; }
 6662            /** Sets the Messages for this ArgGroupSpec, and returns this ArgGroupSpec.
 6663             * @param msgs the new Messages value, may be {@code null}
 6664             * @see Command#resourceBundle()
 6665             * @see #headingKey()
 6666             */
 6667            public ArgGroupSpec messages(Messages msgs) {
 6668                messages = msgs;
 6669                for (ArgGroupSpec sub : subgroups()) { sub.messages(msgs); }
 6670                return this;
 6671            }
 6672
 6673            @Override public boolean equals(Object obj) {
 6674                if (obj == this) { return true; }
 6675                if (!(obj instanceof ArgGroupSpec)) { return false; }
 6676                ArgGroupSpec other = (ArgGroupSpec) obj;
 6677                return exclusive == other.exclusive
 6678                        && Assert.equals(multiplicity, other.multiplicity)
 6679                        && validate == other.validate
 6680                        && order == other.order
 6681                        && Assert.equals(heading, other.heading)
 6682                        && Assert.equals(headingKey, other.headingKey)
 6683                        && Assert.equals(subgroups, other.subgroups)
 6684                        && Assert.equals(args, other.args);
 6685            }
 6686
 6687            @Override public int hashCode() {
 6688                int result = 17;
 6689                result += 37 * result + Assert.hashCode(exclusive);
 6690                result += 37 * result + Assert.hashCode(multiplicity);
 6691                result += 37 * result + Assert.hashCode(validate);
 6692                result += 37 * result + order;
 6693                result += 37 * result + Assert.hashCode(heading);
 6694                result += 37 * result + Assert.hashCode(headingKey);
 6695                result += 37 * result + Assert.hashCode(subgroups);
 6696                result += 37 * result + Assert.hashCode(args);
 6697                return result;
 6698            }
 6699
 6700            @Override public String toString() {
 6701                List<String> argNames = new ArrayList<String>();
 6702                for (ArgSpec arg : args()) {
 6703                    if (arg instanceof OptionSpec) {
 6704                        argNames.add(((OptionSpec) arg).shortestName());
 6705                    } else {
 6706                        PositionalParamSpec p = (PositionalParamSpec) arg;
 6707                        argNames.add(p.index() + " (" + p.paramLabel() + ")");
 6708                    }
 6709                }
 6710                return "ArgGroup[exclusive=" + exclusive + ", multiplicity=" + multiplicity +
 6711                        ", validate=" + validate + ", order=" + order + ", args=[" + ArgSpec.describe(args()) +
 6712                        "], headingKey=" + quote(headingKey) + ", heading=" + quote(heading) +
 6713                        ", subgroups=" + subgroups + "]";
 6714            }
 6715            private static String quote(String s) { return s == null ? "null" : "'" + s + "'"; }
 6716
 6717            void initUserObject(CommandLine commandLine) {
 6718                if (commandLine == null) { new Tracer().debug("Could not create user object for %s with null CommandLine%n.", this); }
 6719                try {
 6720                    tryInitUserObject(commandLine);
 6721                } catch (PicocliException ex) {
 6722                    throw ex;
 6723                } catch (Exception ex) {
 6724                    throw new InitializationException("Could not create user object for " + this, ex);
 6725                }
 6726            }
 6727            void tryInitUserObject(CommandLine commandLine) throws Exception {
 6728                Tracer tracer = commandLine.tracer;
 6729                if (typeInfo() != null) {
 6730                    tracer.debug("Creating new user object of type %s for group %s%n", typeInfo().getAuxiliaryTypes()[0], synopsis());
 6731                    Object userObject = DefaultFactory.create(commandLine.factory, typeInfo().getAuxiliaryTypes()[0]);
 6732                    tracer.debug("Created %s, invoking setter %s with scope %s%n", userObject, setter(), scope());
 6733                    setUserObject(userObject, commandLine.factory);
 6734                    for (ArgSpec arg : args()) {
 6735                        tracer.debug("Initializing %s in group %s: setting scope to user object %s and initializing initial and default values%n", ArgSpec.describe(arg, "="), synopsis(), userObject);
 6736                        arg.scope().set(userObject); // flip the actual user object for the arg (and all other args in this group; they share the same IScope instance)
 6737                        commandLine.interpreter.parseResultBuilder.isInitializingDefaultValues = true;
 6738                        arg.applyInitialValue(tracer);
 6739                        commandLine.interpreter.applyDefault(commandLine.getCommandSpec().defaultValueProvider(), arg);
 6740                        commandLine.interpreter.parseResultBuilder.isInitializingDefaultValues = false;
 6741                    }
 6742                    for (ArgGroupSpec subgroup : subgroups()) {
 6743                        tracer.debug("Setting scope for subgroup %s with setter=%s in group %s to user object %s%n", subgroup.synopsis(), subgroup.setter(), synopsis(), userObject);
 6744                        subgroup.scope().set(userObject); // flip the actual user object for the arg (and all other args in this group; they share the same IScope instance)
 6745                    }
 6746                } else {
 6747                    tracer.debug("No type information available for group %s: cannot create new user object. Scope for arg setters is not changed.%n", synopsis());
 6748                }
 6749                tracer.debug("Initialization complete for group %s%n", synopsis());
 6750            }
 6751
 6752            void setUserObject(Object userObject, IFactory factory) throws Exception {
 6753                if (typeInfo().isCollection()) {
 6754                    @SuppressWarnings("unchecked") Collection<Object> c = (Collection<Object>) getter().get();
 6755                    if (c == null) {
 6756                        @SuppressWarnings("unchecked")
 6757                        Collection<Object> c2 = (Collection<Object>) DefaultFactory.create(factory, typeInfo.getType());
 6758                        setter().set(c = c2);
 6759                    }
 6760                    (c).add(userObject);
 6761                } else if (typeInfo().isArray()) {
 6762                    Object old = getter().get();
 6763                    int oldSize = old == null ? 0 : Array.getLength(old);
 6764                    Object array = Array.newInstance(typeInfo().getAuxiliaryTypes()[0], oldSize + 1);
 6765                    for (int i = 0; i < oldSize; i++) {
 6766                        Array.set(array, i, Array.get(old, i));
 6767                    }
 6768                    Array.set(array, oldSize, userObject);
 6769                    setter().set(array);
 6770                } else {
 6771                    setter().set(userObject);
 6772                }
 6773            }
 6774
 6775            enum GroupValidationResult {
 6776                SUCCESS_PRESENT, SUCCESS_ABSENT,
 6777                FAILURE_PRESENT, FAILURE_ABSENT, FAILURE_PARTIAL;
 6778                static boolean containsBlockingFailure(EnumSet<GroupValidationResult> set) {
 6779                    return set.contains(FAILURE_PRESENT) || set.contains(FAILURE_PARTIAL);
 6780                }
 6781                /** FAILURE_PRESENT or FAILURE_PARTIAL */
 6782                boolean blockingFailure() { return this == FAILURE_PRESENT || this == FAILURE_PARTIAL; }
 6783                boolean present()         { return this == SUCCESS_PRESENT /*|| this == FAILURE_PRESENT*/; }
 6784                boolean success()         { return this == SUCCESS_ABSENT  || this == SUCCESS_PRESENT; }
 6785            }
 6786
 6787            private ParameterException validationException;
 6788            private GroupValidationResult validationResult;
 6789
 6790            /** Clears temporary validation state for this group and its subgroups. */
 6791            void clearValidationResult() {
 6792                validationException = null;
 6793                validationResult = null;
 6794                for (ArgGroupSpec sub : subgroups()) { sub.clearValidationResult(); }
 6795            }
 6796
 6797            /** Throws an exception if the constraints in this group are not met by the specified match. */
 6798            void validateConstraints(ParseResult parseResult) {
 6799                if (!validate()) { return; }
 6800                CommandLine commandLine = parseResult.commandSpec().commandLine();
 6801
 6802                // first validate args in this group
 6803                validationResult = validateArgs(commandLine, parseResult);
 6804                if (validationResult.blockingFailure()) {
 6805                    commandLine.interpreter.maybeThrow(validationException); // composite parent validations cannot succeed anyway
 6806                }
 6807                // then validate sub groups
 6808                EnumSet<GroupValidationResult> validationResults = validateSubgroups(parseResult);
 6809                if (GroupValidationResult.containsBlockingFailure(validationResults)) {
 6810                    commandLine.interpreter.maybeThrow(validationException); // composite parent validations cannot succeed anyway
 6811                }
 6812                List<MatchedGroup> matchedGroups = parseResult.findMatchedGroup(this);
 6813                if (matchedGroups.isEmpty()) {
 6814                    // TODO can/should we verify minimum multiplicity here?
 6815                    if (multiplicity().min > 0) {
 6816                        if (validationResult.success()) {
 6817                            validationResult = GroupValidationResult.FAILURE_ABSENT;
 6818                            validationException = new MissingParameterException(commandLine, args(),
 6819                                    "Error: Group: " + synopsis() + " must be specified " + multiplicity().min + " times but was missing");
 6820                        }
 6821                    }
 6822                }
 6823                for (MatchedGroup matchedGroup : matchedGroups) {
 6824                    int matchCount = matchedGroup.multiples().size();
 6825                    // note: matchCount == 0 if only subgroup(s) are matched for a group without args (subgroups-only)
 6826                    boolean checkMinimum = matchCount > 0 || !args().isEmpty();
 6827                    if (checkMinimum && matchCount < multiplicity().min) {
 6828                        if (validationResult.success()) {
 6829                            validationResult = matchCount == 0 ? GroupValidationResult.FAILURE_ABSENT: GroupValidationResult.FAILURE_PARTIAL;
 6830                            validationException = new MissingParameterException(commandLine, args(),
 6831                                    "Error: Group: " + synopsis() + " must be specified " + multiplicity().min + " times but was matched " + matchCount + " times");
 6832                        }
 6833                    } else if (matchCount > multiplicity().max) {
 6834                        if (!validationResult.blockingFailure()) {
 6835                            validationResult = GroupValidationResult.FAILURE_PRESENT;
 6836                            validationException = new MaxValuesExceededException(commandLine,
 6837                                    "Error: Group: " + synopsis() + " can only be specified " + multiplicity().max + " times but was matched " + matchCount + " times.");
 6838                        }
 6839                    }
 6840                    if (validationResult.blockingFailure()) {
 6841                        commandLine.interpreter.maybeThrow(validationException);
 6842                    }
 6843                }
 6844                if (validationException != null && parentGroup == null) {
 6845                    commandLine.interpreter.maybeThrow(validationException);
 6846                }
 6847            }
 6848
 6849            private EnumSet<GroupValidationResult> validateSubgroups(ParseResult parseResult) {
 6850                EnumSet<GroupValidationResult> validationResults = EnumSet.of(validationResult);
 6851                if (subgroups().isEmpty()) { return validationResults; }
 6852                for (ArgGroupSpec subgroup : subgroups()) {
 6853                    subgroup.validateConstraints(parseResult);
 6854                    validationResults.add(Assert.notNull(subgroup.validationResult, "subgroup validation result"));
 6855                    if (subgroup.validationResult.blockingFailure()) { this.validationException = subgroup.validationException; break; }
 6856                }
 6857                // now do some coarse-grained checking for exclusive subgroups
 6858                int elementCount = args().size() + subgroups().size();
 6859                int presentCount = validationResult.present() ? 1 : 0;
 6860                String exclusiveElements = "";
 6861                for (ArgGroupSpec subgroup : subgroups()) {
 6862                    if (!parseResult.findMatchedGroup(subgroup).isEmpty()) { presentCount++; }
 6863                    //presentCount += parseResult.findMatchedGroup(subgroup).size(); // this would give incorrect error message if A and B are exclusive and A is matched 2x and B is not matched
 6864                    if (exclusiveElements.length() > 0) { exclusiveElements += " and "; }
 6865                    exclusiveElements += subgroup.synopsis();
 6866                }
 6867                validationResult = validate(parseResult.commandSpec().commandLine(), presentCount, presentCount < elementCount,
 6868                        presentCount > 0 && presentCount < elementCount, exclusiveElements, synopsis(), synopsis());
 6869                validationResults.add(validationResult);
 6870                return validationResults;
 6871            }
 6872
 6873            private GroupValidationResult validateArgs(CommandLine commandLine, ParseResult parseResult) {
 6874                if (args().isEmpty()) { return GroupValidationResult.SUCCESS_ABSENT; }
 6875                return validateArgs(commandLine, parseResult.findMatchedGroup(this));
 6876            }
 6877
 6878            private GroupValidationResult validateArgs(CommandLine commandLine, List<MatchedGroup> matchedGroups) {
 6879                if (matchedGroups.isEmpty()) {
 6880                    int presentCount = 0;
 6881                    boolean haveMissing = true;
 6882                    boolean someButNotAllSpecified = false;
 6883                    String exclusiveElements = "";
 6884                    String missingElements = ArgSpec.describe(requiredArgs());
 6885                    return validate(commandLine, presentCount, haveMissing, someButNotAllSpecified, exclusiveElements, missingElements, missingElements);
 6886                }
 6887                GroupValidationResult result = GroupValidationResult.SUCCESS_ABSENT;
 6888                Map<MatchedGroup, List<MatchedGroup>> byParent = groupByParent(matchedGroups);
 6889                for (Map.Entry<MatchedGroup, List<MatchedGroup>> entry : byParent.entrySet()) {
 6890                    List<MatchedGroup> allForOneParent = entry.getValue();
 6891                    for (MatchedGroup oneForOneParent : allForOneParent) {
 6892                        result = validateMultiples(commandLine, oneForOneParent.multiples());
 6893                        if (result.blockingFailure()) { return result; }
 6894                    }
 6895                }
 6896                return result;
 6897            }
 6898
 6899            private Map<MatchedGroup, List<MatchedGroup>> groupByParent(List<MatchedGroup> matchedGroups) {
 6900                Map<MatchedGroup, List<MatchedGroup>> result = new HashMap<MatchedGroup, List<MatchedGroup>>();
 6901                for (MatchedGroup mg : matchedGroups) {
 6902                    addValueToListInMap(result, mg.parentMatchedGroup(), mg);
 6903                }
 6904                return result;
 6905            }
 6906
 6907            private List<ParseResult.MatchedGroupMultiple> flatListMultiples(Collection<MatchedGroup> matchedGroups) {
 6908                List<ParseResult.MatchedGroupMultiple> all = new ArrayList<ParseResult.MatchedGroupMultiple>();
 6909                for (MatchedGroup matchedGroup : matchedGroups) {
 6910                    all.addAll(matchedGroup.multiples());
 6911                }
 6912                return all;
 6913            }
 6914
 6915            private GroupValidationResult validateMultiples(CommandLine commandLine, List<ParseResult.MatchedGroupMultiple> multiples) {
 6916                Set<ArgSpec> intersection = new LinkedHashSet<ArgSpec>(this.args());
 6917                Set<ArgSpec> missing = new LinkedHashSet<ArgSpec>(this.requiredArgs());
 6918                Set<ArgSpec> found = new LinkedHashSet<ArgSpec>();
 6919                for (ParseResult.MatchedGroupMultiple multiple : multiples) {
 6920                    found.addAll(multiple.matchedValues.keySet());
 6921                    missing.removeAll(multiple.matchedValues.keySet());
 6922                }
 6923                intersection.retainAll(found);
 6924                int presentCount = intersection.size();
 6925                boolean haveMissing = !missing.isEmpty();
 6926                boolean someButNotAllSpecified = haveMissing && !intersection.isEmpty();
 6927                String exclusiveElements = ArgSpec.describe(intersection);
 6928                String requiredElements = ArgSpec.describe(requiredArgs());
 6929                String missingElements = ArgSpec.describe(missing);
 6930
 6931                return validate(commandLine, presentCount, haveMissing, someButNotAllSpecified, exclusiveElements, requiredElements, missingElements);
 6932            }
 6933
 6934            private GroupValidationResult validate(CommandLine commandLine, int presentCount, boolean haveMissing, boolean someButNotAllSpecified, String exclusiveElements, String requiredElements, String missingElements) {
 6935                if (exclusive()) {
 6936                    if (presentCount > 1) {
 6937                        validationException = new MutuallyExclusiveArgsException(commandLine,
 6938                                "Error: " + exclusiveElements + " are mutually exclusive (specify only one)");
 6939                        return GroupValidationResult.FAILURE_PRESENT;
 6940                    }
 6941                    // check that exactly one member was matched
 6942                    if (multiplicity().min > 0 && presentCount < 1) {
 6943                        validationException = new MissingParameterException(commandLine, args(),
 6944                                "Error: Missing required argument (specify one of these): " + requiredElements);
 6945                        return GroupValidationResult.FAILURE_ABSENT;
 6946                    }
 6947                    return GroupValidationResult.SUCCESS_PRESENT;
 6948                } else { // co-occurring group
 6949                    if (someButNotAllSpecified) {
 6950                        validationException = new MissingParameterException(commandLine, args(),
 6951                                "Error: Missing required argument(s): " + missingElements);
 6952                        return GroupValidationResult.FAILURE_PARTIAL;
 6953                    }
 6954                    if ((multiplicity().min > 0 && haveMissing)) {
 6955                        validationException = new MissingParameterException(commandLine, args(),
 6956                                "Error: Missing required argument(s): " + missingElements);
 6957                        return GroupValidationResult.FAILURE_ABSENT;
 6958                    }
 6959                    return haveMissing ? GroupValidationResult.SUCCESS_ABSENT : GroupValidationResult.SUCCESS_PRESENT;
 6960                }
 6961            }
 6962
 6963            /** Builder responsible for creating valid {@code ArgGroupSpec} objects.
 6964             * @since 4.0 */
 6965            public static class Builder {
 6966                private IGetter getter;
 6967                private ISetter setter;
 6968                private IScope scope;
 6969                private ITypeInfo typeInfo;
 6970                private String heading;
 6971                private String headingKey;
 6972                private boolean exclusive  = true;
 6973                private Range multiplicity = Range.valueOf("0..1");
 6974                private boolean validate   = true;
 6975                private int order          = DEFAULT_ORDER;
 6976                private List<ArgSpec> args = new ArrayList<ArgSpec>();
 6977                private List<ArgGroupSpec> subgroups = new ArrayList<ArgGroupSpec>();
 6978
 6979                // for topological sorting; private only
 6980                private Boolean topologicalSortDone;
 6981                private List<Builder> compositesReferencingMe = new ArrayList<Builder>();
 6982
 6983                Builder() { }
 6984                Builder(IAnnotatedElement source) {
 6985                    typeInfo = source.getTypeInfo();
 6986                    getter = source.getter();
 6987                    setter = source.setter();
 6988                    scope = source.scope();
 6989                }
 6990
 6991                /** Updates this builder from the specified annotation values.
 6992                 * @param group annotation values
 6993                 * @return this builder for method chaining */
 6994                public Builder updateArgGroupAttributes(ArgGroup group) {
 6995                    return this
 6996                            .heading(group.heading())
 6997                            .headingKey(group.headingKey())
 6998                            .exclusive(group.exclusive())
 6999                            .multiplicity(group.multiplicity())
 7000                            .validate(group.validate())
 7001                            .order(group.order());
 7002                }
 7003
 7004                /** Returns a valid {@code ArgGroupSpec} instance. */
 7005                public ArgGroupSpec build() { return new ArgGroupSpec(this); }
 7006
 7007                /** Returns whether this is a mutually exclusive group; {@code true} by default.
 7008                 * If {@code false}, this is a co-occurring group. Ignored if {@link #validate()} is {@code false}.
 7009                 * @see ArgGroup#exclusive() */
 7010                public boolean exclusive() { return exclusive; }
 7011                /** Sets whether this is a mutually exclusive group; {@code true} by default.
 7012                 * If {@code false}, this is a co-occurring group. Ignored if {@link #validate()} is {@code false}.
 7013                 * @see ArgGroup#exclusive() */
 7014                public Builder exclusive(boolean newValue) { exclusive = newValue; return this; }
 7015
 7016                /** Returns the multiplicity of this group: how many occurrences it may have on the command line; {@code "0..1"} (optional) by default.
 7017                 * A group can be made required by specifying a multiplicity of {@code "1"}. For a group of mutually exclusive arguments,
 7018                 * being required means that one of the arguments in the group must appear on the command line, or a MissingParameterException is thrown.
 7019                 * For a group of co-occurring arguments, being required means that all arguments in the group must appear on the command line.
 7020                 * Ignored if {@link #validate()} is {@code false}.
 7021                 * @see ArgGroup#multiplicity() */
 7022                public Range multiplicity() { return multiplicity; }
 7023                /** Sets the multiplicity of this group: how many occurrences it may have on the command line; {@code "0..1"} (optional) by default.
 7024                 * A group can be made required by specifying a multiplicity of {@code "1"}. For a group of mutually exclusive arguments,
 7025                 * being required means that one of the arguments in the group must appear on the command line, or a MissingParameterException is thrown.
 7026                 * For a group of co-occurring arguments, being required means that all arguments in the group must appear on the command line.
 7027                 * Ignored if {@link #validate()} is {@code false}.
 7028                 * @see ArgGroup#multiplicity() */
 7029                public Builder multiplicity(String newValue) { return multiplicity(Range.valueOf(newValue)); }
 7030                /** Sets the multiplicity of this group: how many occurrences it may have on the command line; {@code "0..1"} (optional) by default.
 7031                 * A group can be made required by specifying a multiplicity of {@code "1"}. For a group of mutually exclusive arguments,
 7032                 * being required means that one of the arguments in the group must appear on the command line, or a MissingParameterException is thrown.
 7033                 * For a group of co-occurring arguments, being required means that all arguments in the group must appear on the command line.
 7034                 * Ignored if {@link #validate()} is {@code false}.
 7035                 * @see ArgGroup#multiplicity() */
 7036                public Builder multiplicity(Range newValue) { multiplicity = newValue; return this; }
 7037
 7038                /** Returns whether picocli should validate the rules of this group:
 7039                 * for a mutually exclusive group this means that no more than one arguments in the group is specified on the command line;
 7040                 * for a co-ocurring group this means that all arguments in the group are specified on the command line.
 7041                 * {@code true} by default.
 7042                 * @see ArgGroup#validate() */
 7043                public boolean validate() { return validate; }
 7044                /** Sets whether picocli should validate the rules of this group:
 7045                 * for a mutually exclusive group this means that no more than one arguments in the group is specified on the command line;
 7046                 * for a co-ocurring group this means that all arguments in the group are specified on the command line.
 7047                 * {@code true} by default.
 7048                 * @see ArgGroup#validate() */
 7049                public Builder validate(boolean newValue) { validate = newValue; return this; }
 7050
 7051                /** Returns the position in the options list in the usage help message at which this group should be shown.
 7052                 * Options with a lower number are shown before options with a higher number.
 7053                 * This attribute is only honored if {@link UsageMessageSpec#sortOptions()} is {@code false} for this command.*/
 7054                public int order() { return order; }
 7055
 7056                /** Sets the position in the options list in the usage help message at which this group should be shown, and returns this builder. */
 7057                public Builder order(int order) { this.order = order; return this; }
 7058
 7059                /** Returns the heading of this group, used when generating the usage documentation.
 7060                 * @see ArgGroup#heading() */
 7061                public String heading() { return heading; }
 7062
 7063                /** Sets the heading of this group (may be {@code null}), used when generating the usage documentation.
 7064                 * @see ArgGroup#heading() */
 7065                public Builder heading(String newValue) { this.heading = newValue; return this; }
 7066
 7067                /** Returns the heading key of this group, used to get the heading from a resource bundle.
 7068                 * @see ArgGroup#headingKey()  */
 7069                public String headingKey() { return headingKey; }
 7070                /** Sets the heading key of this group, used to get the heading from a resource bundle.
 7071                 * @see ArgGroup#headingKey()  */
 7072                public Builder headingKey(String newValue) { this.headingKey = newValue; return this; }
 7073
 7074                /** Returns the type info for the annotated program element associated with this group.
 7075                 * @return type information that does not require {@code Class} objects and be constructed both at runtime and compile time
 7076                 */
 7077                public ITypeInfo typeInfo()    { return typeInfo; }
 7078                /** Sets the type info for the annotated program element associated with this group, and returns this builder.
 7079                 * @param newValue type information that does not require {@code Class} objects and be constructed both at runtime and compile time
 7080                 */
 7081                public Builder typeInfo(ITypeInfo newValue) { this.typeInfo = newValue; return this; }
 7082
 7083                /** Returns the {@link IGetter} that is responsible for supplying the value of the annotated program element associated with this group. */
 7084                public IGetter getter()        { return getter; }
 7085                /** Sets the {@link IGetter} that is responsible for getting the value of the annotated program element associated with this group, and returns this builder. */
 7086                public Builder getter(IGetter getter)       { this.getter = getter; return this; }
 7087
 7088                /** Returns the {@link ISetter} that is responsible for modifying the value of the annotated program element associated with this group. */
 7089                public ISetter setter()        { return setter; }
 7090                /** Sets the {@link ISetter} that is responsible for modifying the value of the annotated program element associated with this group, and returns this builder. */
 7091                public Builder setter(ISetter setter)       { this.setter = setter; return this; }
 7092
 7093                /** Returns the {@link IScope} that determines where the setter sets the value (or the getter gets the value) of the annotated program element associated with this group. */
 7094                public IScope scope()          { return scope; }
 7095                /** Sets the {@link IScope} that targets where the setter sets the value of the annotated program element associated with this group, and returns this builder. */
 7096                public Builder scope(IScope scope)          { this.scope = scope; return this; }
 7097
 7098                /** Adds the specified argument to the list of options and positional parameters that depend on this group. */
 7099                public Builder addArg(ArgSpec arg) { args.add(arg); return this; }
 7100
 7101                /** Returns the list of options and positional parameters that depend on this group.*/
 7102                public List<ArgSpec> args() { return args; }
 7103
 7104                /** Adds the specified group to the list of subgroups that this group is composed of. */
 7105                public Builder addSubgroup(ArgGroupSpec group) { subgroups.add(group); return this; }
 7106
 7107                /** Returns the list of subgroups that this group is composed of.*/
 7108                public List<ArgGroupSpec> subgroups() { return subgroups; }
 7109            }
 7110        }
 7111
 7112        /** This class allows applications to specify a custom binding that will be invoked for unmatched arguments.
 7113         * A binding can be created with a {@code ISetter} that consumes the unmatched arguments {@code String[]}, or with a
 7114         * {@code IGetter} that produces a {@code Collection<String>} that the unmatched arguments can be added to.
 7115         * @since 3.0 */
 7116        public static class UnmatchedArgsBinding {
 7117            private final IGetter getter;
 7118            private final ISetter setter;
 7119
 7120            /** Creates a {@code UnmatchedArgsBinding} for a setter that consumes {@code String[]} objects.
 7121             * @param setter consumes the String[] array with unmatched arguments. */
 7122            public static UnmatchedArgsBinding forStringArrayConsumer(ISetter setter) { return new UnmatchedArgsBinding(null, setter); }
 7123
 7124            /** Creates a {@code UnmatchedArgsBinding} for a getter that produces a {@code Collection<String>} that the unmatched arguments can be added to.
 7125             * @param getter supplies a {@code Collection<String>} that the unmatched arguments can be added to. */
 7126            public static UnmatchedArgsBinding forStringCollectionSupplier(IGetter getter) { return new UnmatchedArgsBinding(getter, null); }
 7127
 7128            private UnmatchedArgsBinding(IGetter getter, ISetter setter) {
 7129                if (getter == null && setter == null) { throw new IllegalArgumentException("Getter and setter cannot both be null"); }
 7130                this.setter = setter;
 7131                this.getter = getter;
 7132            }
 7133            /** Returns the getter responsible for producing a {@code Collection} that the unmatched arguments can be added to. */
 7134            public IGetter getter() { return getter; }
 7135            /** Returns the setter responsible for consuming the unmatched arguments. */
 7136            public ISetter setter() { return setter; }
 7137            void addAll(String[] unmatched) {
 7138                if (setter != null) {
 7139                    try {
 7140                        setter.set(unmatched);
 7141                    } catch (Exception ex) {
 7142                        throw new PicocliException(String.format("Could not invoke setter (%s) with unmatched argument array '%s': %s", setter, Arrays.toString(unmatched), ex), ex);
 7143                    }
 7144                }
 7145                if (getter != null) {
 7146                    try {
 7147                        Collection<String> collection = getter.get();
 7148                        Assert.notNull(collection, "getter returned null Collection");
 7149                        collection.addAll(Arrays.asList(unmatched));
 7150                    } catch (Exception ex) {
 7151                        throw new PicocliException(String.format("Could not add unmatched argument array '%s' to collection returned by getter (%s): %s",
 7152                                Arrays.toString(unmatched), getter, ex), ex);
 7153                    }
 7154                }
 7155            }
 7156        }
 7157        /** Command method parameter, similar to java.lang.reflect.Parameter (not available before Java 8).
 7158         * @since 4.0 */
 7159        public static class MethodParam extends AccessibleObject {
 7160            final Method method;
 7161            final int paramIndex;
 7162            final String name;
 7163            int position;
 7164
 7165            public MethodParam(Method method, int paramIndex) {
 7166                this.method = method;
 7167                this.paramIndex = paramIndex;
 7168                String tmp = "arg" + paramIndex;
 7169                try {
 7170                    Method getParameters = Method.class.getMethod("getParameters");
 7171                    Object parameters = getParameters.invoke(method);
 7172                    Object parameter = Array.get(parameters, paramIndex);
 7173                    tmp = (String) Class.forName("java.lang.reflect.Parameter").getDeclaredMethod("getName").invoke(parameter);
 7174                } catch (Exception ignored) {}
 7175                this.name = tmp;
 7176            }
 7177            public Type getParameterizedType() { return method.getGenericParameterTypes()[paramIndex]; }
 7178            public String getName() { return name; }
 7179            public Class<?> getType() { return method.getParameterTypes()[paramIndex]; }
 7180            public Method getDeclaringExecutable() { return method; }
 7181            @Override public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
 7182                for (Annotation annotation : getDeclaredAnnotations()) {
 7183                    if (annotationClass.isAssignableFrom(annotation.getClass())) { return annotationClass.cast(annotation); }
 7184                }
 7185                return null;
 7186            }
 7187            @Override public Annotation[] getDeclaredAnnotations() { return method.getParameterAnnotations()[paramIndex]; }
 7188            @Override public void setAccessible(boolean flag) throws SecurityException { method.setAccessible(flag); }
 7189            @Override public boolean isAccessible() throws SecurityException { return method.isAccessible(); }
 7190            @Override public String toString() { return method.toString() + ":" + getName(); }
 7191        }
 7192
 7193        /** Encapculates type information for an option or parameter to make this information available both at runtime
 7194         * and at compile time (when {@code Class} values are not available).
 7195         * Most of the methods in this interface (but not all!) are safe to use by annotation processors.
 7196         * @since 4.0
 7197         */
 7198        public interface ITypeInfo {
 7199            /** Returns {@code true} if {@link #getType()} is {@code boolean} or {@code java.lang.Boolean}. */
 7200            boolean isBoolean();
 7201            /** Returns {@code true} if {@link #getType()} is an array, map or collection. */
 7202            boolean isMultiValue();
 7203            boolean isArray();
 7204            boolean isCollection();
 7205            boolean isMap();
 7206            /** Returns {@code true} if {@link #getType()} is an enum. */
 7207            boolean isEnum();
 7208            List<String> getEnumConstantNames();
 7209            String getClassName();
 7210            String getClassSimpleName();
 7211            /** Returns type information of components or elements of a {@link #isMultiValue() multivalue} type. */
 7212            List<ITypeInfo> getAuxiliaryTypeInfos();
 7213            /** Returns the names of the type arguments if this is a generic type. For example, returns {@code ["java.lang.String"]} if this type is {@code List<String>}. */
 7214            List<String> getActualGenericTypeArguments();
 7215
 7216            /** Returns the class that the option or parameter value should be converted to when matched on the command
 7217             * line. This method is <em>not</em> safe for annotation processors to use.
 7218             * @return the class that the option or parameter value should be converted to
 7219             */
 7220            Class<?> getType();
 7221            /** Returns the component class of an array, or the parameter type of a generic Collection, or the parameter
 7222             * types of the key and the value of a generic Map.
 7223             * This method is <em>not</em> safe for annotation processors to use.
 7224             * @return the component type or types of an array, Collection or Map type
 7225             */
 7226            Class<?>[] getAuxiliaryTypes();
 7227        }
 7228        static class RuntimeTypeInfo implements ITypeInfo {
 7229            private final Class<?> type;
 7230            private final Class<?>[] auxiliaryTypes;
 7231            private final List<String> actualGenericTypeArguments;
 7232
 7233            RuntimeTypeInfo(Class<?> type, Class<?>[] auxiliaryTypes, List<String> actualGenericTypeArguments) {
 7234                this.type = Assert.notNull(type, "type");
 7235                this.auxiliaryTypes = Assert.notNull(auxiliaryTypes, "auxiliaryTypes").clone();
 7236                this.actualGenericTypeArguments = actualGenericTypeArguments == null ? Collections.<String>emptyList() : Collections.unmodifiableList(new ArrayList<String>(actualGenericTypeArguments));
 7237            }
 7238
 7239            static ITypeInfo createForAuxType(Class<?> type) {
 7240                return create(type, new Class[0], (Type) null, Range.valueOf("1"), String.class);
 7241            }
 7242            public static ITypeInfo create(Class<?> type,
 7243                                           Class<?>[] annotationTypes,
 7244                                           Type genericType,
 7245                                           Range arity,
 7246                                           Class<?> defaultType) {
 7247                Class<?>[] auxiliaryTypes = RuntimeTypeInfo.inferTypes(type, annotationTypes, genericType);
 7248                List<String> actualGenericTypeArguments = new ArrayList<String>();
 7249                if (genericType instanceof ParameterizedType)  {
 7250                    Class[] declaredTypeParameters = extractTypeParameters((ParameterizedType) genericType);
 7251                    for (Class<?> c : declaredTypeParameters) { actualGenericTypeArguments.add(c.getName()); }
 7252                }
 7253                return create(type, auxiliaryTypes, actualGenericTypeArguments, arity, defaultType);
 7254            }
 7255
 7256            public static ITypeInfo create(Class<?> type, Class<?>[] auxiliaryTypes, List<String> actualGenericTypeArguments, Range arity, Class<?> defaultType) {
 7257                if (type == null) {
 7258                    if (auxiliaryTypes == null || auxiliaryTypes.length == 0) {
 7259                        if (arity.isVariable || arity.max > 1) {
 7260                            type = String[].class;
 7261                        } else if (arity.max == 1) {
 7262                            type = String.class;
 7263                        } else {
 7264                            type = defaultType;
 7265                        }
 7266                    } else {
 7267                        type = auxiliaryTypes[0];
 7268                    }
 7269                }
 7270                if (auxiliaryTypes == null || auxiliaryTypes.length == 0) {
 7271                    if (type.isArray()) {
 7272                        auxiliaryTypes = new Class<?>[] {type.getComponentType()};
 7273                    } else if (Collection.class.isAssignableFrom(type)) { // type is a collection but element type is unspecified
 7274                        auxiliaryTypes = new Class<?>[] {String.class}; // use String elements
 7275                    } else if (Map.class.isAssignableFrom(type)) { // type is a map but element type is unspecified
 7276                        auxiliaryTypes = new Class<?>[] {String.class, String.class}; // use String keys and String values
 7277                    } else {
 7278                        auxiliaryTypes = new Class<?>[] {type};
 7279                    }
 7280                }
 7281                return new RuntimeTypeInfo(type, auxiliaryTypes, actualGenericTypeArguments);
 7282            }
 7283            static Class<?>[] inferTypes(Class<?> propertyType, Class<?>[] annotationTypes, Type genericType) {
 7284                if (annotationTypes != null && annotationTypes.length > 0) { return annotationTypes; }
 7285                if (propertyType.isArray()) { return new Class<?>[] { propertyType.getComponentType() }; }
 7286                if (CommandLine.isMultiValue(propertyType)) {
 7287                    if (genericType instanceof ParameterizedType) {// e.g. Map<Long, ? extends Number>
 7288                        return extractTypeParameters((ParameterizedType) genericType);
 7289                    }
 7290                    return new Class<?>[] {String.class, String.class}; // field is multi-value but not ParameterizedType
 7291                }
 7292                return new Class<?>[] {propertyType}; // not a multi-value field
 7293            }
 7294
 7295            static Class<?>[] extractTypeParameters(ParameterizedType genericType) {
 7296                ParameterizedType parameterizedType = genericType;
 7297                Type[] paramTypes = parameterizedType.getActualTypeArguments(); // e.g. ? extends Number
 7298                Class<?>[] result = new Class<?>[paramTypes.length];
 7299                for (int i = 0; i < paramTypes.length; i++) {
 7300                    if (paramTypes[i] instanceof Class) { result[i] = (Class<?>) paramTypes[i]; continue; } // e.g. Long
 7301                    if (paramTypes[i] instanceof WildcardType) { // e.g. ? extends Number
 7302                        WildcardType wildcardType = (WildcardType) paramTypes[i];
 7303                        Type[] lower = wildcardType.getLowerBounds(); // e.g. []
 7304                        if (lower.length > 0 && lower[0] instanceof Class) { result[i] = (Class<?>) lower[0]; continue; }
 7305                        Type[] upper = wildcardType.getUpperBounds(); // e.g. Number
 7306                        if (upper.length > 0 && upper[0] instanceof Class) { result[i] = (Class<?>) upper[0]; continue; }
 7307                    }
 7308                    Arrays.fill(result, String.class); return result; // too convoluted generic type, giving up
 7309                }
 7310                return result; // we inferred all types from ParameterizedType
 7311            }
 7312
 7313            public boolean isBoolean()            { return auxiliaryTypes[0] == boolean.class || auxiliaryTypes[0] == Boolean.class; }
 7314            public boolean isMultiValue()         { return CommandLine.isMultiValue(type); }
 7315            public boolean isArray()              { return type.isArray(); }
 7316            public boolean isCollection()         { return Collection.class.isAssignableFrom(type); }
 7317            public boolean isMap()                { return Map.class.isAssignableFrom(type); }
 7318            public boolean isEnum()               { return auxiliaryTypes[0].isEnum(); }
 7319            public String getClassName()          { return type.getName(); }
 7320            public String getClassSimpleName()    { return type.getSimpleName(); }
 7321            public Class<?> getType()             { return type; }
 7322            public Class<?>[] getAuxiliaryTypes() { return auxiliaryTypes; }
 7323            public List<String> getActualGenericTypeArguments() { return actualGenericTypeArguments; }
 7324
 7325            public List<ITypeInfo> getAuxiliaryTypeInfos()  {
 7326                List<ITypeInfo> result = new ArrayList<ITypeInfo>();
 7327                for (Class<?> c : auxiliaryTypes) { result.add(createForAuxType(c)); }
 7328                return result;
 7329            }
 7330            public List<String> getEnumConstantNames() {
 7331                if (!isEnum()) { return Collections.emptyList(); }
 7332                List<String> result = new ArrayList<String>();
 7333                for (Object c : auxiliaryTypes[0].getEnumConstants()) { result.add(c.toString()); }
 7334                return result;
 7335            }
 7336
 7337            public boolean equals(Object obj) {
 7338                if (obj == this) { return true; }
 7339                if (!(obj instanceof RuntimeTypeInfo)) { return false; }
 7340                RuntimeTypeInfo other = (RuntimeTypeInfo) obj;
 7341                return Arrays.equals(other.auxiliaryTypes, auxiliaryTypes) && type.equals(other.type);
 7342            }
 7343            public int hashCode() {
 7344                return Arrays.hashCode(auxiliaryTypes) + 37 * Assert.hashCode(type);
 7345            }
 7346            public String toString() {
 7347                return String.format("RuntimeTypeInfo(%s, aux=%s, collection=%s, map=%s)",
 7348                        type.getCanonicalName(), Arrays.toString(auxiliaryTypes), isCollection(), isMap());
 7349            }
 7350        }
 7351        /** Internal interface to allow annotation processors to construct a command model at compile time.
 7352         * @since 4.0 */
 7353        public interface IAnnotatedElement {
 7354            Object userObject();
 7355            boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);
 7356            <T extends Annotation> T getAnnotation(Class<T> annotationClass);
 7357            String getName();
 7358            String getMixinName();
 7359            boolean isArgSpec();
 7360            boolean isOption();
 7361            boolean isParameter();
 7362            boolean isArgGroup();
 7363            boolean isMixin();
 7364            boolean isUnmatched();
 7365            boolean isInjectSpec();
 7366            boolean isMultiValue();
 7367            boolean hasInitialValue();
 7368            boolean isMethodParameter();
 7369            int getMethodParamPosition();
 7370            CommandLine.Model.IScope scope();
 7371            CommandLine.Model.IGetter getter();
 7372            CommandLine.Model.ISetter setter();
 7373            ITypeInfo getTypeInfo();
 7374            String getToString();
 7375        }
 7376
 7377        static class TypedMember implements IAnnotatedElement {
 7378            final AccessibleObject accessible;
 7379            final String name;
 7380            final ITypeInfo typeInfo;
 7381            boolean hasInitialValue;
 7382            private IScope scope;
 7383            private IGetter getter;
 7384            private ISetter setter;
 7385            static TypedMember createIfAnnotated(Field field, IScope scope) {
 7386                return isAnnotated(field) ? new TypedMember(field, scope) : null;
 7387            }
 7388            static boolean isAnnotated(AnnotatedElement e) {
 7389                return false
 7390                        || e.isAnnotationPresent(Option.class)
 7391                        || e.isAnnotationPresent(Parameters.class)
 7392                        || e.isAnnotationPresent(ArgGroup.class)
 7393                        || e.isAnnotationPresent(Unmatched.class)
 7394                        || e.isAnnotationPresent(Mixin.class)
 7395                        || e.isAnnotationPresent(Spec.class)
 7396                        || e.isAnnotationPresent(ParentCommand.class);
 7397            }
 7398            TypedMember(Field field) {
 7399                accessible = Assert.notNull(field, "field");
 7400                accessible.setAccessible(true);
 7401                name = field.getName();
 7402                typeInfo = createTypeInfo(field.getType(), field.getGenericType());
 7403                hasInitialValue = true;
 7404            }
 7405            private TypedMember(Field field, IScope scope) {
 7406                this(field);
 7407                Object obj = ObjectScope.tryGet(scope);
 7408                if (obj != null && Proxy.isProxyClass(obj.getClass())) {
 7409                    throw new InitializationException("Invalid picocli annotation on interface field");
 7410                }
 7411                FieldBinding binding = new FieldBinding(scope, field);
 7412                getter = binding; setter = binding;
 7413                this.scope = scope;
 7414                hasInitialValue &= obj != null ;
 7415            }
 7416            static TypedMember createIfAnnotated(Method method, IScope scope, CommandSpec spec) {
 7417                return isAnnotated(method) ? new TypedMember(method, scope, spec) : null;
 7418            }
 7419            private TypedMember(Method method, IScope scope, CommandSpec spec) {
 7420                accessible = Assert.notNull(method, "method");
 7421                accessible.setAccessible(true);
 7422                name = propertyName(method.getName());
 7423                Class<?>[] parameterTypes = method.getParameterTypes();
 7424                boolean isGetter = parameterTypes.length == 0 && method.getReturnType() != Void.TYPE && method.getReturnType() != Void.class;
 7425                boolean isSetter = parameterTypes.length > 0;
 7426                if (isSetter == isGetter) { throw new InitializationException("Invalid method, must be either getter or setter: " + method); }
 7427                if (isGetter) {
 7428                    hasInitialValue = true;
 7429                    typeInfo = createTypeInfo(method.getReturnType(), method.getGenericReturnType());
 7430                    Object proxy = ObjectScope.tryGet(scope);
 7431                    if (Proxy.isProxyClass(proxy.getClass())) {
 7432                        PicocliInvocationHandler handler = (PicocliInvocationHandler) Proxy.getInvocationHandler(proxy);
 7433                        PicocliInvocationHandler.ProxyBinding binding = handler.new ProxyBinding(method);
 7434                        getter = binding; setter = binding;
 7435                        initializeInitialValue(method);
 7436                    } else {
 7437                        //throw new IllegalArgumentException("Getter method but not a proxy: " + scope + ": " + method);
 7438                        MethodBinding binding = new MethodBinding(scope, method, spec);
 7439                        getter = binding; setter = binding;
 7440                    }
 7441                } else {
 7442                    hasInitialValue = false;
 7443                    typeInfo = createTypeInfo(parameterTypes[0], method.getGenericParameterTypes()[0]);
 7444                    MethodBinding binding = new MethodBinding(scope, method, spec);
 7445                    getter = binding; setter = binding;
 7446                }
 7447            }
 7448            TypedMember(MethodParam param, IScope scope) {
 7449                accessible = Assert.notNull(param, "command method parameter");
 7450                accessible.setAccessible(true);
 7451                name = param.getName();
 7452                typeInfo = createTypeInfo(param.getType(), param.getParameterizedType());
 7453                // bind parameter
 7454                ObjectBinding binding = new ObjectBinding();
 7455                getter = binding; setter = binding;
 7456                initializeInitialValue(param);
 7457                hasInitialValue = true;
 7458            }
 7459
 7460            private ITypeInfo createTypeInfo(Class<?> type, Type genericType) {
 7461                Range arity = null;
 7462                if (isOption())    { arity = Range.valueOf(getAnnotation(Option.class).arity()); }
 7463                if (isParameter()) { arity = Range.valueOf(getAnnotation(Parameters.class).arity()); }
 7464                if (arity == null || arity.isUnspecified) {
 7465                    if (isOption()) {
 7466                        arity = (type == null || isBoolean(type)) ? Range.valueOf("0") : Range.valueOf("1");
 7467                    } else {
 7468                        arity = Range.valueOf("1");
 7469                    }
 7470                    arity = arity.unspecified(true);
 7471                }
 7472                return RuntimeTypeInfo.create(type, annotationTypes(), genericType, arity, (isOption() ? boolean.class : String.class));
 7473            }
 7474
 7475            private void initializeInitialValue(Object arg) {
 7476                Class<?> type = typeInfo.getType();
 7477                try {
 7478                    if      (type == Boolean.TYPE  ) { setter.set(false); }
 7479                    else if (type == Byte.TYPE     ) { setter.set(Byte.valueOf((byte) 0)); }
 7480                    else if (type == Character.TYPE) { setter.set(Character.valueOf((char) 0)); }
 7481                    else if (type == Short.TYPE    ) { setter.set(Short.valueOf((short) 0)); }
 7482                    else if (type == Integer.TYPE  ) { setter.set(Integer.valueOf(0)); }
 7483                    else if (type == Long.TYPE     ) { setter.set(Long.valueOf(0L)); }
 7484                    else if (type == Float.TYPE    ) { setter.set(Float.valueOf(0f)); }
 7485                    else if (type == Double.TYPE   ) { setter.set(Double.valueOf(0d)); }
 7486                    else {                             setter.set(null); }
 7487                } catch (Exception ex) {
 7488                    throw new InitializationException("Could not set initial value for " + arg + ": " + ex.toString(), ex);
 7489                }
 7490            }
 7491            public Object userObject()      { return accessible; }
 7492            public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { return accessible.isAnnotationPresent(annotationClass); }
 7493            public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { return accessible.getAnnotation(annotationClass); }
 7494            public String getName()         { return name; }
 7495            public boolean isArgSpec()      { return isOption() || isParameter() || (isMethodParameter() && !isMixin()); }
 7496            public boolean isOption()       { return isAnnotationPresent(Option.class); }
 7497            public boolean isParameter()    { return isAnnotationPresent(Parameters.class); }
 7498            public boolean isArgGroup()     { return isAnnotationPresent(ArgGroup.class); }
 7499            public boolean isMixin()        { return isAnnotationPresent(Mixin.class); }
 7500            public boolean isUnmatched()    { return isAnnotationPresent(Unmatched.class); }
 7501            public boolean isInjectSpec()   { return isAnnotationPresent(Spec.class); }
 7502            public boolean isMultiValue()   { return CommandLine.isMultiValue(getType()); }
 7503            public IScope  scope()          { return scope; }
 7504            public IGetter getter()         { return getter; }
 7505            public ISetter setter()         { return setter; }
 7506            public ITypeInfo getTypeInfo()  { return typeInfo; }
 7507            public Class<?> getType()       { return typeInfo.getType(); }
 7508            public Class<?>[] getAuxiliaryTypes() { return typeInfo.getAuxiliaryTypes(); }
 7509            private Class<?>[] annotationTypes() {
 7510                if (isOption())    { return getAnnotation(Option.class).type(); }
 7511                if (isParameter()) { return getAnnotation(Parameters.class).type(); }
 7512                return new Class[0];
 7513            }
 7514            public String toString() { return accessible.toString(); }
 7515            public String getToString()  {
 7516                if (isMixin()) { return abbreviate("mixin from member " + toGenericString()); }
 7517                return (accessible instanceof Field ? "field " : accessible instanceof Method ? "method " : accessible.getClass().getSimpleName() + " ") + abbreviate(toGenericString());
 7518            }
 7519            public String toGenericString() { return accessible instanceof Field ? ((Field) accessible).toGenericString() : accessible instanceof Method ? ((Method) accessible).toGenericString() : ((MethodParam)accessible).toString(); }
 7520            public boolean hasInitialValue()    { return hasInitialValue; }
 7521            public boolean isMethodParameter()  { return accessible instanceof MethodParam; }
 7522            public int getMethodParamPosition() { return isMethodParameter() ? ((MethodParam) accessible).position : -1; }
 7523            public String getMixinName()    {
 7524                String annotationName = getAnnotation(Mixin.class).name();
 7525                return empty(annotationName) ? getName() : annotationName;
 7526            }
 7527            static String propertyName(String methodName) {
 7528                if (methodName.length() > 3 && (methodName.startsWith("get") || methodName.startsWith("set"))) { return decapitalize(methodName.substring(3)); }
 7529                return decapitalize(methodName);
 7530            }
 7531            private static String decapitalize(String name) {
 7532                if (name == null || name.length() == 0) { return name; }
 7533                char[] chars = name.toCharArray();
 7534                chars[0] = Character.toLowerCase(chars[0]);
 7535                return new String(chars);
 7536            }
 7537            static String abbreviate(String text) {
 7538                return text.replace("private ", "")
 7539                        .replace("protected ", "")
 7540                        .replace("public ", "")
 7541                        .replace("java.lang.", "");
 7542            }
 7543        }
 7544
 7545        /** Utility class for getting resource bundle strings.
 7546         * Enhances the standard <a href="https://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html">ResourceBundle</a>
 7547         * with support for String arrays and qualified keys: keys that may or may not be prefixed with the fully qualified command name.
 7548         * <p>Example properties resource bundle:</p><pre>
 7549         * # Usage Help Message Sections
 7550         * # ---------------------------
 7551         * # Numbered resource keys can be used to create multi-line sections.
 7552         * usage.headerHeading = This is my app. There are other apps like it but this one is mine.%n
 7553         * usage.header   = header first line
 7554         * usage.header.0 = header second line
 7555         * usage.descriptionHeading = Description:%n
 7556         * usage.description.0 = first line
 7557         * usage.description.1 = second line
 7558         * usage.description.2 = third line
 7559         * usage.synopsisHeading = Usage:&#92;u0020
 7560         * # Leading whitespace is removed by default. Start with &#92;u0020 to keep the leading whitespace.
 7561         * usage.customSynopsis.0 =      Usage: ln [OPTION]... [-T] TARGET LINK_NAME   (1st form)
 7562         * usage.customSynopsis.1 = &#92;u0020 or:  ln [OPTION]... TARGET                  (2nd form)
 7563         * usage.customSynopsis.2 = &#92;u0020 or:  ln [OPTION]... TARGET... DIRECTORY     (3rd form)
 7564         * # Headings can contain the %n character to create multi-line values.
 7565         * usage.parameterListHeading = %nPositional parameters:%n
 7566         * usage.optionListHeading = %nOptions:%n
 7567         * usage.commandListHeading = %nCommands:%n
 7568         * usage.footerHeading = Powered by picocli%n
 7569         * usage.footer = footer
 7570         *
 7571         * # Option Descriptions
 7572         * # -------------------
 7573         * # Use numbered keys to create multi-line descriptions.
 7574         * help = Show this help message and exit.
 7575         * version = Print version information and exit.
 7576         * </pre>
 7577         * <p>Resources for multiple commands can be specified in a single ResourceBundle. Keys and their value can be
 7578         * shared by multiple commands (so you don't need to repeat them for every command), but keys can be prefixed with
 7579         * {@code fully qualified command name + "."} to specify different values for different commands.
 7580         * The most specific key wins. For example: </p>
 7581         * <pre>
 7582         * jfrog.rt.usage.header = Artifactory commands
 7583         * jfrog.rt.config.usage.header = Configure Artifactory details.
 7584         * jfrog.rt.upload.usage.header = Upload files.
 7585         *
 7586         * jfrog.bt.usage.header = Bintray commands
 7587         * jfrog.bt.config.usage.header = Configure Bintray details.
 7588         * jfrog.bt.upload.usage.header = Upload files.
 7589         *
 7590         * # shared between all commands
 7591         * usage.footerHeading = Environment Variables:
 7592         * usage.footer.0 = footer line 0
 7593         * usage.footer.1 = footer line 1
 7594         * </pre>
 7595         * @see Command#resourceBundle()
 7596         * @see Option#descriptionKey()
 7597         * @see OptionSpec#description()
 7598         * @see PositionalParamSpec#description()
 7599         * @see CommandSpec#qualifiedName(String)
 7600         * @since 3.6 */
 7601        public static class Messages {
 7602            private final CommandSpec spec;
 7603            private final String bundleBaseName;
 7604            private final ResourceBundle rb;
 7605            private final Set<String> keys;
 7606            public Messages(CommandSpec spec, String baseName) {
 7607                this(spec, baseName, createBundle(baseName));
 7608            }
 7609            public Messages(CommandSpec spec, ResourceBundle rb) {
 7610                this(spec, extractName(rb), rb);
 7611            }
 7612            public Messages(CommandSpec spec, String baseName, ResourceBundle rb) {
 7613                this.spec = Assert.notNull(spec, "CommandSpec");
 7614                this.bundleBaseName = baseName;
 7615                this.rb = rb;
 7616                this.keys = keys(rb);
 7617            }
 7618            private static ResourceBundle createBundle(String baseName) {
 7619                return ResourceBundle.getBundle(baseName);
 7620            }
 7621            private static String extractName(ResourceBundle rb) {
 7622                try { // ResourceBundle.getBaseBundleName was introduced in Java 8
 7623                    return (String) ResourceBundle.class.getDeclaredMethod("getBaseBundleName").invoke(rb);
 7624                } catch (Exception ignored) { return ""; }
 7625            }
 7626            private static Set<String> keys(ResourceBundle rb) {
 7627                if (rb == null) { return Collections.emptySet(); }
 7628                Set<String> keys = new LinkedHashSet<String>();
 7629                for (Enumeration<String> k = rb.getKeys(); k.hasMoreElements(); keys.add(k.nextElement()));
 7630                return keys;
 7631            }
 7632
 7633            /** Returns a copy of the specified Messages object with the CommandSpec replaced by the specified one.
 7634             * @param spec the CommandSpec of the returned Messages
 7635             * @param original the Messages object whose ResourceBundle to reference
 7636             * @return a Messages object with the specified CommandSpec and the ResourceBundle of the specified Messages object
 7637             */
 7638            public static Messages copy(CommandSpec spec, Messages original) {
 7639                return original == null ? null : new Messages(spec, original.bundleBaseName, original.rb);
 7640            }
 7641            /** Returns {@code true} if the specified {@code Messages} is {@code null} or has a {@code null ResourceBundle}. */
 7642            public static boolean empty(Messages messages) { return messages == null || messages.rb == null; }
 7643
 7644            /** Returns the String value found in the resource bundle for the specified key, or the specified default value if not found.
 7645             * @param key unqualified resource bundle key. This method will first try to find a value by qualifying the key with the command's fully qualified name,
 7646             *             and if not found, it will try with the unqualified key.
 7647             * @param defaultValue value to return if the resource bundle is null or empty, or if no value was found by the qualified or unqualified key
 7648             * @return the String value found in the resource bundle for the specified key, or the specified default value
 7649             */
 7650            public String getString(String key, String defaultValue) {
 7651                if (isEmpty()) { return defaultValue; }
 7652                String cmd = spec.qualifiedName(".");
 7653                if (keys.contains(cmd + "." + key)) { return rb.getString(cmd + "." + key); }
 7654                if (keys.contains(key)) { return rb.getString(key); }
 7655                return defaultValue;
 7656            }
 7657
 7658            boolean isEmpty() { return rb == null || keys.isEmpty(); }
 7659
 7660            /** Returns the String array value found in the resource bundle for the specified key, or the specified default value if not found.
 7661             * Multi-line strings can be specified in the resource bundle with {@code key.0}, {@code key.1}, {@code key.2}, etc.
 7662             * @param key unqualified resource bundle key. This method will first try to find a value by qualifying the key with the command's fully qualified name,
 7663             *            and if not found, it will try with the unqualified key.
 7664             * @param defaultValues value to return if the resource bundle is null or empty, or if no value was found by the qualified or unqualified key
 7665             * @return the String array value found in the resource bundle for the specified key, or the specified default value
 7666             */
 7667            public String[] getStringArray(String key, String[] defaultValues) {
 7668                if (isEmpty()) { return defaultValues; }
 7669                String cmd = spec.qualifiedName(".");
 7670                List<String> result = addAllWithPrefix(rb, cmd + "." + key, keys, new ArrayList<String>());
 7671                if (!result.isEmpty()) { return result.toArray(new String[0]); }
 7672                addAllWithPrefix(rb, key, keys, result);
 7673                return result.isEmpty() ? defaultValues : result.toArray(new String[0]);
 7674            }
 7675            private static List<String> addAllWithPrefix(ResourceBundle rb, String key, Set<String> keys, List<String> result) {
 7676                if (keys.contains(key)) { result.add(rb.getString(key)); }
 7677                for (int i = 0; true; i++) {
 7678                    String elementKey = key + "." + i;
 7679                    if (keys.contains(elementKey)) {
 7680                        result.add(rb.getString(elementKey));
 7681                    } else {
 7682                        return result;
 7683                    }
 7684                }
 7685            }
 7686            /** Returns the ResourceBundle of the specified Messages object or {@code null} if the specified Messages object is {@code null}.
 7687             * @since 4.0 */
 7688            public static String resourceBundleBaseName(Messages messages) { return messages == null ? null : messages.resourceBundleBaseName(); }
 7689            /** Returns the ResourceBundle of the specified Messages object or {@code null} if the specified Messages object is {@code null}. */
 7690            public static ResourceBundle resourceBundle(Messages messages) { return messages == null ? null : messages.resourceBundle(); }
 7691            /** Returns the base name of the ResourceBundle of this object or {@code null}.
 7692             * @since 4.0 */
 7693            public String resourceBundleBaseName() { return bundleBaseName; }
 7694            /** Returns the ResourceBundle of this object or {@code null}. */
 7695            public ResourceBundle resourceBundle() { return rb; }
 7696            /** Returns the CommandSpec of this object, never {@code null}. */
 7697            public CommandSpec commandSpec() { return spec; }
 7698        }
 7699        private static class CommandReflection {
 7700            static ArgGroupSpec extractArgGroupSpec(IAnnotatedElement member, IFactory factory, CommandSpec commandSpec, boolean annotationsAreMandatory) throws Exception {
 7701                Object instance = null;
 7702                try { instance = member.getter().get(); } catch (Exception ignored) {}
 7703                Class<?> cls = instance == null ? member.getTypeInfo().getType() : instance.getClass();
 7704                Tracer t = new Tracer();
 7705
 7706                if (member.isMultiValue()) {
 7707                    cls = member.getTypeInfo().getAuxiliaryTypes()[0];
 7708                }
 7709                IScope scope = new ObjectScope(instance);
 7710                ArgGroupSpec.Builder builder = ArgGroupSpec.builder(member);
 7711                builder.updateArgGroupAttributes(member.getAnnotation(ArgGroup.class));
 7712                if (member.isOption() || member.isParameter()) {
 7713                    if (member instanceof TypedMember) { validateArgSpecMember((TypedMember) member); }
 7714                    builder.addArg(buildArgForMember(member, factory));
 7715                }
 7716
 7717                Stack<Class<?>> hierarchy = new Stack<Class<?>>();
 7718                while (cls != null) { hierarchy.add(cls); cls = cls.getSuperclass(); }
 7719                boolean hasArgAnnotation = false;
 7720                while (!hierarchy.isEmpty()) {
 7721                    cls = hierarchy.pop();
 7722                    hasArgAnnotation |= initFromAnnotatedFields(scope, cls, commandSpec, builder, factory);
 7723                }
 7724                ArgGroupSpec result = builder.build();
 7725                if (annotationsAreMandatory) {validateArgGroupSpec(result, hasArgAnnotation, cls.getName()); }
 7726                return result;
 7727            }
 7728            static CommandSpec extractCommandSpec(Object command, IFactory factory, boolean annotationsAreMandatory) {
 7729                Class<?> cls = command.getClass();
 7730                Tracer t = new Tracer();
 7731                t.debug("Creating CommandSpec for object of class %s with factory %s%n", cls.getName(), factory.getClass().getName());
 7732                if (command instanceof CommandSpec) { return (CommandSpec) command; }
 7733
 7734                Object[] tmp = getOrCreateInstance(cls, command, factory, t);
 7735                cls = (Class<?>) tmp[0];
 7736                Object instance = tmp[1];
 7737                String commandClassName = (String) tmp[2];
 7738
 7739                CommandSpec result = CommandSpec.wrapWithoutInspection(Assert.notNull(instance, "command"));
 7740                ObjectScope scope = new ObjectScope(instance);
 7741
 7742                Stack<Class<?>> hierarchy = new Stack<Class<?>>();
 7743                while (cls != null) { hierarchy.add(cls); cls = cls.getSuperclass(); }
 7744                boolean hasCommandAnnotation = false;
 7745                boolean mixinStandardHelpOptions = false;
 7746                while (!hierarchy.isEmpty()) {
 7747                    cls = hierarchy.pop();
 7748                    Command cmd = cls.getAnnotation(Command.class);
 7749                    if (cmd != null) {
 7750                        result.updateCommandAttributes(cmd, factory);
 7751                        initSubcommands(cmd, cls, result, factory);
 7752                        // addGroups(cmd, groupBuilders); // TODO delete
 7753                        hasCommandAnnotation = true;
 7754                    }
 7755                    hasCommandAnnotation |= initFromAnnotatedFields(scope, cls, result, null, factory);
 7756                    if (cls.isAnnotationPresent(Command.class)) {
 7757                        mixinStandardHelpOptions |= cls.getAnnotation(Command.class).mixinStandardHelpOptions();
 7758                    }
 7759                }
 7760                result.mixinStandardHelpOptions(mixinStandardHelpOptions); //#377 Standard help options should be added last
 7761                if (command instanceof Method) {
 7762                    Method method = (Method) command;
 7763                    t.debug("Using method %s as command %n", method);
 7764                    commandClassName = method.toString();
 7765                    Command cmd = method.getAnnotation(Command.class);
 7766                    result.updateCommandAttributes(cmd, factory);
 7767                    result.setAddMethodSubcommands(false); // method commands don't have method subcommands
 7768                    initSubcommands(cmd, null, result, factory);
 7769                    hasCommandAnnotation = true;
 7770                    result.mixinStandardHelpOptions(method.getAnnotation(Command.class).mixinStandardHelpOptions());
 7771                    initFromMethodParameters(scope, method, result, null, factory);
 7772                    // set command name to method name, unless @Command#name is set
 7773                    result.initName(((Method)command).getName());
 7774                }
 7775                result.updateArgSpecMessages();
 7776
 7777                if (annotationsAreMandatory) {validateCommandSpec(result, hasCommandAnnotation, commandClassName); }
 7778                result.withToString(commandClassName).validate();
 7779                return result;
 7780            }
 7781
 7782            private static Object[] getOrCreateInstance(Class<?> cls, Object command, IFactory factory, Tracer t) {
 7783                Object instance = command;
 7784                String commandClassName = cls.getName();
 7785                if (command instanceof Class) {
 7786                    cls = (Class) command;
 7787                    commandClassName = cls.getName();
 7788                    try {
 7789                        t.debug("Getting a %s instance from the factory%n", cls.getName());
 7790                        instance = DefaultFactory.create(factory, cls);
 7791                        cls = instance.getClass();
 7792                        commandClassName = cls.getName();
 7793                        t.debug("Factory returned a %s instance%n", commandClassName);
 7794                    } catch (InitializationException ex) {
 7795                        if (cls.isInterface()) {
 7796                            t.debug("%s. Creating Proxy for interface %s%n", ex.getCause(), cls.getName());
 7797                            instance = Proxy.newProxyInstance(cls.getClassLoader(), new Class<?>[]{cls}, new PicocliInvocationHandler());
 7798                        } else {
 7799                            throw ex;
 7800                        }
 7801                    }
 7802                } else if (command instanceof Method) {
 7803                    cls = null; // don't mix in options/positional params from outer class @Command
 7804                } else if (instance == null) {
 7805                    t.debug("Getting a %s instance from the factory%n", cls.getName());
 7806                    instance = DefaultFactory.create(factory, cls);
 7807                    t.debug("Factory returned a %s instance%n", instance.getClass().getName());
 7808                }
 7809                return new Object[] { cls, instance, commandClassName };
 7810            }
 7811            private static void initSubcommands(Command cmd, Class<?> cls, CommandSpec parent, IFactory factory) {
 7812                for (Class<?> sub : cmd.subcommands()) {
 7813                    try {
 7814                        if (Help.class == sub) { throw new InitializationException(Help.class.getName() + " is not a valid subcommand. Did you mean " + HelpCommand.class.getName() + "?"); }
 7815                        CommandLine subcommandLine = toCommandLine(factory.create(sub), factory);
 7816                        parent.addSubcommand(subcommandName(sub), subcommandLine);
 7817                        initParentCommand(subcommandLine.getCommandSpec().userObject(), parent.userObject());
 7818                    }
 7819                    catch (InitializationException ex) { throw ex; }
 7820                    catch (NoSuchMethodException ex) { throw new InitializationException("Cannot instantiate subcommand " +
 7821                            sub.getName() + ": the class has no constructor", ex); }
 7822                    catch (Exception ex) {
 7823                        throw new InitializationException("Could not instantiate and add subcommand " +
 7824                                sub.getName() + ": " + ex, ex);
 7825                    }
 7826                }
 7827                if (cmd.addMethodSubcommands() && cls != null) {
 7828                    for (CommandLine sub : CommandSpec.createMethodSubcommands(cls, factory)) {
 7829                        parent.addSubcommand(sub.getCommandName(), sub);
 7830                    }
 7831                }
 7832            }
 7833            static void initParentCommand(Object subcommand, Object parent) {
 7834                if (subcommand == null) { return; }
 7835                try {
 7836                    Class<?> cls = subcommand.getClass();
 7837                    while (cls != null) {
 7838                        for (Field f : cls.getDeclaredFields()) {
 7839                            if (f.isAnnotationPresent(ParentCommand.class)) {
 7840                                f.setAccessible(true);
 7841                                f.set(subcommand, parent);
 7842                            }
 7843                        }
 7844                        cls = cls.getSuperclass();
 7845                    }
 7846                } catch (Exception ex) {
 7847                    throw new InitializationException("Unable to initialize @ParentCommand field: " + ex, ex);
 7848                }
 7849            }
 7850            private static String subcommandName(Class<?> sub) {
 7851                Command subCommand = sub.getAnnotation(Command.class);
 7852                if (subCommand == null || Help.DEFAULT_COMMAND_NAME.equals(subCommand.name())) {
 7853                    throw new InitializationException("Subcommand " + sub.getName() +
 7854                            " is missing the mandatory @Command annotation with a 'name' attribute");
 7855                }
 7856                return subCommand.name();
 7857            }
 7858            private static boolean initFromAnnotatedFields(IScope scope, Class<?> cls, CommandSpec receiver, ArgGroupSpec.Builder groupBuilder, IFactory factory) {
 7859                boolean result = false;
 7860                for (Field field : cls.getDeclaredFields()) {
 7861                    result |= initFromAnnotatedTypedMembers(TypedMember.createIfAnnotated(field, scope), receiver, groupBuilder, factory);
 7862                }
 7863                for (Method method : cls.getDeclaredMethods()) {
 7864                    result |= initFromAnnotatedTypedMembers(TypedMember.createIfAnnotated(method, scope, receiver), receiver, groupBuilder, factory);
 7865                }
 7866                return result;
 7867            }
 7868            @SuppressWarnings("unchecked")
 7869            private static boolean initFromAnnotatedTypedMembers(TypedMember member,
 7870                                                                 CommandSpec commandSpec,
 7871                                                                 ArgGroupSpec.Builder groupBuilder,
 7872                                                                 IFactory factory) {
 7873                boolean result = false;
 7874                if (member == null) { return result; }
 7875                if (member.isMixin()) {
 7876                    assertNoDuplicateAnnotations(member, Mixin.class, Option.class, Parameters.class, Unmatched.class, Spec.class, ArgGroup.class);
 7877                    if (groupBuilder != null) {
 7878                        throw new InitializationException("@Mixins are not supported on @ArgGroups");
 7879                        // TODO groupBuilder.addMixin(member.getMixinName(), buildMixinForMember(member, factory));
 7880                    } else {
 7881                        commandSpec.addMixin(member.getMixinName(), buildMixinForMember(member, factory));
 7882                    }
 7883                    result = true;
 7884                }
 7885                if (member.isArgGroup()) {
 7886                    assertNoDuplicateAnnotations(member, ArgGroup.class, Spec.class, Parameters.class, Option.class, Unmatched.class, Mixin.class);
 7887                    if (groupBuilder != null) {
 7888                        groupBuilder.addSubgroup(buildArgGroupForMember(member, factory, commandSpec));
 7889                    } else {
 7890                        commandSpec.addArgGroup(buildArgGroupForMember(member, factory, commandSpec));
 7891                    }
 7892                    return true;
 7893                }
 7894                if (member.isUnmatched()) {
 7895                    assertNoDuplicateAnnotations(member, Unmatched.class, Mixin.class, Option.class, Parameters.class, Spec.class, ArgGroup.class);
 7896                    if (groupBuilder != null) {
 7897                        // we don't support @Unmatched on @ArgGroup class members...
 7898                        throw new InitializationException("@Unmatched are not supported on @ArgGroups");
 7899                    } else {
 7900                        commandSpec.addUnmatchedArgsBinding(buildUnmatchedForMember(member));
 7901                    }
 7902                }
 7903                if (member.isArgSpec()) {
 7904                    validateArgSpecMember(member);
 7905                    if (groupBuilder != null) {
 7906                        groupBuilder.addArg(buildArgForMember(member, factory));
 7907                    } else {
 7908                        commandSpec.add(buildArgForMember(member, factory));
 7909                    }
 7910                    result = true;
 7911                }
 7912                if (member.isInjectSpec()) {
 7913                    validateInjectSpec(member);
 7914                    try { member.setter().set(commandSpec); } catch (Exception ex) { throw new InitializationException("Could not inject spec", ex); }
 7915                }
 7916                return result;
 7917            }
 7918            private static boolean initFromMethodParameters(IScope scope, Method method, CommandSpec receiver, ArgGroupSpec.Builder groupBuilder, IFactory factory) {
 7919                boolean result = false;
 7920                int optionCount = 0;
 7921                for (int i = 0, count = method.getParameterTypes().length; i < count; i++) {
 7922                    MethodParam param = new MethodParam(method, i);
 7923                    if (param.isAnnotationPresent(Option.class) || param.isAnnotationPresent(Mixin.class)) {
 7924                        optionCount++;
 7925                    } else {
 7926                        param.position = i - optionCount;
 7927                    }
 7928                    result |= initFromAnnotatedTypedMembers(new TypedMember(param, scope), receiver, groupBuilder, factory);
 7929                }
 7930                return result;
 7931            }
 7932            @SuppressWarnings("unchecked")
 7933            private static void validateArgSpecMember(TypedMember member) {
 7934                if (!member.isArgSpec()) { throw new IllegalStateException("Bug: validateArgSpecMember() should only be called with an @Option or @Parameters member"); }
 7935                if (member.isOption()) {
 7936                    assertNoDuplicateAnnotations(member, Option.class, Unmatched.class, Mixin.class, Parameters.class, Spec.class, ArgGroup.class);
 7937                } else {
 7938                    assertNoDuplicateAnnotations(member, Parameters.class, Option.class, Unmatched.class, Mixin.class, Spec.class, ArgGroup.class);
 7939                }
 7940                if (!(member.accessible instanceof Field)) { return; }
 7941                Field field = (Field) member.accessible;
 7942                if (Modifier.isFinal(field.getModifiers()) && (field.getType().isPrimitive() || String.class.isAssignableFrom(field.getType()))) {
 7943                    throw new InitializationException("Constant (final) primitive and String fields like " + field + " cannot be used as " +
 7944                            (member.isOption() ? "an @Option" : "a @Parameter") + ": compile-time constant inlining may hide new values written to it.");
 7945                }
 7946            }
 7947            private static void validateCommandSpec(CommandSpec result, boolean hasCommandAnnotation, String commandClassName) {
 7948                if (!hasCommandAnnotation && result.positionalParameters.isEmpty() && result.optionsByNameMap.isEmpty() && result.unmatchedArgs.isEmpty()) {
 7949                    throw new InitializationException(commandClassName + " is not a command: it has no @Command, @Option, @Parameters or @Unmatched annotations");
 7950                }
 7951            }
 7952            private static void validateArgGroupSpec(ArgGroupSpec result, boolean hasArgAnnotation, String className) {
 7953                if (!hasArgAnnotation && result.args().isEmpty()) {
 7954                    throw new InitializationException(className + " is not a group: it has no @Option or @Parameters annotations");
 7955                }
 7956            }
 7957            @SuppressWarnings("unchecked")
 7958            private static void validateInjectSpec(TypedMember member) {
 7959                if (!member.isInjectSpec()) { throw new IllegalStateException("Bug: validateInjectSpec() should only be called with @Spec members"); }
 7960                assertNoDuplicateAnnotations(member, Spec.class, Parameters.class, Option.class, Unmatched.class, Mixin.class, ArgGroup.class);
 7961                if (!CommandSpec.class.getName().equals(member.getTypeInfo().getClassName())) {
 7962                    throw new InitializationException("@picocli.CommandLine.Spec annotation is only supported on fields of type " + CommandSpec.class.getName());
 7963                }
 7964            }
 7965            private static void assertNoDuplicateAnnotations(TypedMember member, Class<? extends Annotation> myAnnotation, Class<? extends Annotation>... forbidden) {
 7966                for (Class<? extends Annotation> annotation : forbidden) {
 7967                    if (member.isAnnotationPresent(annotation)) {
 7968                        throw new DuplicateOptionAnnotationsException("A member cannot have both @" + myAnnotation.getSimpleName() + " and @" + annotation.getSimpleName() + " annotations, but '" + member + "' has both.");
 7969                    }
 7970                }
 7971            }
 7972            private static CommandSpec buildMixinForMember(IAnnotatedElement member, IFactory factory) {
 7973                try {
 7974                    Object userObject = member.getter().get();
 7975                    if (userObject == null) {
 7976                        userObject = factory.create(member.getTypeInfo().getType());
 7977                        member.setter().set(userObject);
 7978                    }
 7979                    CommandSpec result = CommandSpec.forAnnotatedObject(userObject, factory);
 7980                    return result.withToString(member.getToString());
 7981                } catch (InitializationException ex) {
 7982                    throw ex;
 7983                } catch (Exception ex) {
 7984                    throw new InitializationException("Could not access or modify mixin member " + member + ": " + ex, ex);
 7985                }
 7986            }
 7987            private static ArgSpec buildArgForMember(IAnnotatedElement member, IFactory factory) {
 7988                if (member.isOption())         { return OptionSpec.builder(member, factory).build(); }
 7989                else if (member.isParameter()) { return PositionalParamSpec.builder(member, factory).build(); }
 7990                else                           { return PositionalParamSpec.builder(member, factory).build(); }
 7991            }
 7992            private static ArgGroupSpec buildArgGroupForMember(IAnnotatedElement member, IFactory factory, CommandSpec commandSpec) {
 7993                try {
 7994                    return extractArgGroupSpec(member, factory, commandSpec, true);
 7995                } catch (InitializationException ex) {
 7996                    throw ex;
 7997                } catch (Exception ex) {
 7998                    throw new InitializationException("Could not access or modify ArgGroup member " + member + ": " + ex, ex);
 7999                }
 8000            }
 8001            private static UnmatchedArgsBinding buildUnmatchedForMember(final IAnnotatedElement member) {
 8002                ITypeInfo info = member.getTypeInfo();
 8003                if (!(info.getClassName().equals(String[].class.getName()) ||
 8004                        (info.isCollection() && info.getActualGenericTypeArguments().equals(Arrays.asList(String.class.getName()))))) {
 8005                    throw new InitializationException("Invalid type for " + member + ": must be either String[] or List<String>");
 8006                }
 8007                if (info.getClassName().equals(String[].class.getName())) {
 8008                    return UnmatchedArgsBinding.forStringArrayConsumer(member.setter());
 8009                } else {
 8010                    return UnmatchedArgsBinding.forStringCollectionSupplier(new IGetter() {
 8011                        @SuppressWarnings("unchecked") public <T> T get() throws Exception {
 8012                            List<String> result = (List<String>) member.getter().get();
 8013                            if (result == null) {
 8014                                result = new ArrayList<String>();
 8015                                member.setter().set(result);
 8016                            }
 8017                            return (T) result;
 8018                        }
 8019                    });
 8020                }
 8021            }
 8022        }
 8023
 8024        static class FieldBinding implements IGetter, ISetter {
 8025            private final IScope scope;
 8026            private final Field field;
 8027            private static IScope asScope(Object scope) { return scope instanceof IScope ? ((IScope) scope) : new ObjectScope(scope); }
 8028            FieldBinding(Object scope, Field field) { this(asScope(scope), field); }
 8029            FieldBinding(IScope scope, Field field) { this.scope = scope; this.field = field; }
 8030            public <T> T get() throws PicocliException {
 8031                Object obj = null;
 8032                try { obj = scope.get(); }
 8033                catch (Exception ex) { throw new PicocliException("Could not get scope for field " + field, ex); }
 8034                try {
 8035                    @SuppressWarnings("unchecked") T result = (T) field.get(obj);
 8036                    return result;
 8037                } catch (Exception ex) {
 8038                    throw new PicocliException("Could not get value for field " + field, ex);
 8039                }
 8040            }
 8041            public <T> T set(T value) throws PicocliException {
 8042                Object obj = null;
 8043                try { obj = scope.get(); }
 8044                catch (Exception ex) { throw new PicocliException("Could not get scope for field " + field, ex); }
 8045                try {
 8046                    @SuppressWarnings("unchecked") T result = (T) field.get(obj);
 8047                    field.set(obj, value);
 8048                    return result;
 8049                } catch (Exception ex) {
 8050                    throw new PicocliException("Could not set value for field " + field + " to " + value, ex);
 8051                }
 8052            }
 8053            public String toString() {
 8054                return String.format("%s(%s %s.%s)", getClass().getSimpleName(), field.getType().getName(),
 8055                        field.getDeclaringClass().getName(), field.getName());
 8056            }
 8057        }
 8058        static class MethodBinding implements IGetter, ISetter {
 8059            private final IScope scope;
 8060            private final Method method;
 8061            private final CommandSpec spec;
 8062            private Object currentValue;
 8063            MethodBinding(IScope scope, Method method, CommandSpec spec) {
 8064                this.scope = scope;
 8065                this.method = method;
 8066                this.spec = spec;
 8067            }
 8068            @SuppressWarnings("unchecked") public <T> T get() { return (T) currentValue; }
 8069            public <T> T set(T value) throws PicocliException {
 8070                Object obj = null;
 8071                try { obj = scope.get(); }
 8072                catch (Exception ex) { throw new PicocliException("Could not get scope for method " + method, ex); }
 8073                try {
 8074                    @SuppressWarnings("unchecked") T result = (T) currentValue;
 8075                    method.invoke(obj, value);
 8076                    currentValue = value;
 8077                    return result;
 8078                } catch (InvocationTargetException ex) {
 8079                    if (ex.getCause() instanceof PicocliException) { throw (PicocliException) ex.getCause(); }
 8080                    throw createParameterException(value, ex.getCause());
 8081                } catch (Exception ex) {
 8082                    throw createParameterException(value, ex);
 8083                }
 8084            }
 8085            private ParameterException createParameterException(Object value, Throwable t) {
 8086                CommandLine cmd = spec.commandLine() == null ? new CommandLine(spec) : spec.commandLine();
 8087                return new ParameterException(cmd, "Could not invoke " + method + " with " + value, t);
 8088            }
 8089            public String toString() {
 8090                return String.format("%s(%s)", getClass().getSimpleName(), method);
 8091            }
 8092        }
 8093        private static class PicocliInvocationHandler implements InvocationHandler {
 8094            final Map<String, Object> map = new HashMap<String, Object>();
 8095            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 8096                return map.get(method.getName());
 8097            }
 8098            class ProxyBinding implements IGetter, ISetter {
 8099                private final Method method;
 8100                ProxyBinding(Method method) { this.method = Assert.notNull(method, "method"); }
 8101                @SuppressWarnings("unchecked") public <T> T get() { return (T) map.get(method.getName()); }
 8102                public <T> T set(T value) {
 8103                    T result = get();
 8104                    map.put(method.getName(), value);
 8105                    return result;
 8106                }
 8107            }
 8108        }
 8109        private static class ObjectBinding implements IGetter, ISetter {
 8110            private Object value;
 8111            @SuppressWarnings("unchecked") public <T> T get() { return (T) value; }
 8112            public <T> T set(T value) {
 8113                @SuppressWarnings("unchecked") T result = value;
 8114                this.value = value;
 8115                return result;
 8116            }
 8117            public String toString() {
 8118                return String.format("%s(value=%s)", getClass().getSimpleName(), value);
 8119            }
 8120        }
 8121        static class ObjectScope implements IScope {
 8122            private Object value;
 8123            public ObjectScope(Object value) { this.value = value; }
 8124            @SuppressWarnings("unchecked") public <T> T get() { return (T) value; }
 8125            @SuppressWarnings("unchecked") public <T> T set(T value) { T old = (T) this.value; this.value = value; return old; }
 8126            public static Object tryGet(IScope scope) {
 8127                try {
 8128                    return scope.get();
 8129                } catch (Exception e) {
 8130                    throw new InitializationException("Could not get scope value", e);
 8131                }
 8132            }
 8133            public String toString() { return String.format("Scope(value=%s)", value); }
 8134        }
 8135    }
 8136
 8137    /** Encapsulates the result of parsing an array of command line arguments.
 8138     * @since 3.0 */
 8139    public static class ParseResult {
 8140        private final CommandSpec commandSpec;
 8141        private final List<OptionSpec> matchedOptions;
 8142        private final List<PositionalParamSpec> matchedUniquePositionals;
 8143        private final List<String> originalArgs;
 8144        private final List<String> unmatched;
 8145        private final List<List<PositionalParamSpec>> matchedPositionalParams;
 8146        private final List<Exception> errors;
 8147        private final MatchedGroup matchedGroup;
 8148        final List<Object> tentativeMatch;
 8149
 8150        private final ParseResult subcommand;
 8151        private final boolean usageHelpRequested;
 8152        private final boolean versionHelpRequested;
 8153
 8154        private ParseResult(ParseResult.Builder builder) {
 8155            commandSpec = builder.commandSpec;
 8156            subcommand = builder.subcommand;
 8157            matchedOptions = new ArrayList<OptionSpec>(builder.options);
 8158            unmatched = new ArrayList<String>(builder.unmatched);
 8159            originalArgs = new ArrayList<String>(builder.originalArgList);
 8160            matchedUniquePositionals = new ArrayList<PositionalParamSpec>(builder.positionals);
 8161            matchedPositionalParams = new ArrayList<List<PositionalParamSpec>>(builder.positionalParams);
 8162            errors = new ArrayList<Exception>(builder.errors);
 8163            usageHelpRequested = builder.usageHelpRequested;
 8164            versionHelpRequested = builder.versionHelpRequested;
 8165            tentativeMatch = builder.nowProcessing;
 8166            matchedGroup = builder.matchedGroup.trim();
 8167        }
 8168        /** Creates and returns a new {@code ParseResult.Builder} for the specified command spec. */
 8169        public static Builder builder(CommandSpec commandSpec) { return new Builder(commandSpec); }
 8170
 8171        /**
 8172         * Returns the matches for the specified argument group.
 8173         * @since 4.0 */
 8174        public List<MatchedGroup> findMatchedGroup(ArgGroupSpec group) {
 8175            return matchedGroup.findMatchedGroup(group, new ArrayList<MatchedGroup>());
 8176        }
 8177
 8178        /**
 8179         * Returns the top-level container for the {@link ArgGroupSpec ArgGroupSpec} match or matches found.
 8180         * <p>
 8181         * If the user input was a valid combination of group arguments, the returned list should contain a single
 8182         * {@linkplain MatchedGroupMultiple multiple}. Details of the {@linkplain MatchedGroup matched groups} encountered
 8183         * on the command line can be obtained via its {@link MatchedGroupMultiple#matchedSubgroups() matchedSubgroups()} method.
 8184         * The top-level multiple returned by this method contains no {@linkplain MatchedGroupMultiple#matchedValues(ArgSpec) matched arguments}.
 8185         * </p><p>
 8186         * If the returned list contains more than one {@linkplain MatchedGroupMultiple multiple}, the user input was invalid:
 8187         * the maximum {@linkplain ArgGroup#multiplicity() multiplicity} of a group was exceeded, and the parser created an extra
 8188         * {@code multiple} to capture the values. Usually this results in a {@link ParameterException ParameterException}
 8189         * being thrown by the {@code parse} method, unless the parser is configured to {@linkplain ParserSpec#collectErrors() collect errors}.
 8190         * </p>
 8191         * @since 4.0 */
 8192        public List<MatchedGroupMultiple> getMatchedGroupMultiples() {
 8193            return matchedGroup.multiples();
 8194        }
 8195        /** Returns the option with the specified short name, or {@code null} if no option with that name was matched
 8196         * on the command line.
 8197         * <p>Use {@link OptionSpec#getValue() getValue} on the returned {@code OptionSpec} to get the matched value (or values),
 8198         * converted to the type of the option. Alternatively, use {@link OptionSpec#stringValues() stringValues}
 8199         * to get the matched String values after they were {@linkplain OptionSpec#splitRegex() split} into parts, or
 8200         * {@link OptionSpec#originalStringValues() originalStringValues} to get the original String values that were
 8201         * matched on the command line, before any processing.
 8202         * </p><p>To get the {@linkplain OptionSpec#defaultValue() default value} of an option that was
 8203         * {@linkplain #hasMatchedOption(char) <em>not</em> matched} on the command line, use
 8204         * {@code parseResult.commandSpec().findOption(shortName).getValue()}. </p>
 8205         * @see CommandSpec#findOption(char)  */
 8206        public OptionSpec matchedOption(char shortName) { return CommandSpec.findOption(shortName, matchedOptions); }
 8207
 8208        /** Returns the option with the specified name, or {@code null} if no option with that name was matched on the command line.
 8209         * <p>Use {@link OptionSpec#getValue() getValue} on the returned {@code OptionSpec} to get the matched value (or values),
 8210         * converted to the type of the option. Alternatively, use {@link OptionSpec#stringValues() stringValues}
 8211         * to get the matched String values after they were {@linkplain OptionSpec#splitRegex() split} into parts, or
 8212         * {@link OptionSpec#originalStringValues() originalStringValues} to get the original String values that were
 8213         * matched on the command line, before any processing.
 8214         * </p><p>To get the {@linkplain OptionSpec#defaultValue() default value} of an option that was
 8215         * {@linkplain #hasMatchedOption(String) <em>not</em> matched} on the command line, use
 8216         * {@code parseResult.commandSpec().findOption(String).getValue()}. </p>
 8217         * @see CommandSpec#findOption(String)
 8218         * @param name used to search the matched options. May be an alias of the option name that was actually specified on the command line.
 8219         *      The specified name may include option name prefix characters or not. */
 8220        public OptionSpec matchedOption(String name) { return CommandSpec.findOption(name, matchedOptions); }
 8221
 8222        /** Returns the first {@code PositionalParamSpec} that matched an argument at the specified position, or {@code null} if no positional parameters were matched at that position. */
 8223        public PositionalParamSpec matchedPositional(int position) {
 8224            if (matchedPositionalParams.size() <= position || matchedPositionalParams.get(position).isEmpty()) { return null; }
 8225            return matchedPositionalParams.get(position).get(0);
 8226        }
 8227
 8228        /** Returns all {@code PositionalParamSpec} objects that matched an argument at the specified position, or an empty list if no positional parameters were matched at that position. */
 8229        public List<PositionalParamSpec> matchedPositionals(int position) {
 8230            if (matchedPositionalParams.size() <= position) { return Collections.emptyList(); }
 8231            return matchedPositionalParams.get(position) == null ? Collections.<PositionalParamSpec>emptyList() : matchedPositionalParams.get(position);
 8232        }
 8233        /** Returns the {@code CommandSpec} for the matched command. */
 8234        public CommandSpec commandSpec()                    { return commandSpec; }
 8235
 8236        /** Returns whether an option whose aliases include the specified short name was matched on the command line.
 8237         * @param shortName used to search the matched options. May be an alias of the option name that was actually specified on the command line. */
 8238        public boolean hasMatchedOption(char shortName)     { return matchedOption(shortName) != null; }
 8239        /** Returns whether an option whose aliases include the specified name was matched on the command line.
 8240         * @param name used to search the matched options. May be an alias of the option name that was actually specified on the command line.
 8241         *      The specified name may include option name prefix characters or not. */
 8242        public boolean hasMatchedOption(String name)        { return matchedOption(name) != null; }
 8243        /** Returns whether the specified option was matched on the command line. */
 8244        public boolean hasMatchedOption(OptionSpec option)  { return matchedOptions.contains(option); }
 8245
 8246        /** Returns whether a positional parameter was matched at the specified position. */
 8247        public boolean hasMatchedPositional(int position)   { return matchedPositional(position) != null; }
 8248        /** Returns whether the specified positional parameter was matched on the command line. */
 8249        public boolean hasMatchedPositional(PositionalParamSpec positional) { return matchedUniquePositionals.contains(positional); }
 8250
 8251        /** Returns a list of matched options, in the order they were found on the command line. */
 8252        public List<OptionSpec> matchedOptions()            { return Collections.unmodifiableList(matchedOptions); }
 8253
 8254        /** Returns a list of matched positional parameters. */
 8255        public List<PositionalParamSpec> matchedPositionals() { return Collections.unmodifiableList(matchedUniquePositionals); }
 8256
 8257        /** Returns a list of command line arguments that did not match any options or positional parameters. */
 8258        public List<String> unmatched()                     { return Collections.unmodifiableList(unmatched); }
 8259
 8260        /** Returns the command line arguments that were parsed. */
 8261        public List<String> originalArgs()                  { return Collections.unmodifiableList(originalArgs); }
 8262
 8263        /** If {@link ParserSpec#collectErrors} is {@code true}, returns the list of exceptions that were encountered during parsing, otherwise, returns an empty list.
 8264         * @since 3.2 */
 8265        public List<Exception> errors()                     { return Collections.unmodifiableList(errors); }
 8266
 8267        /** Returns the command line argument value of the option with the specified name, converted to the {@linkplain OptionSpec#type() type} of the option, or the specified default value if no option with the specified name was matched. */
 8268        public <T> T matchedOptionValue(char shortName, T defaultValue)    { return matchedOptionValue(matchedOption(shortName), defaultValue); }
 8269        /** Returns the command line argument value of the option with the specified name, converted to the {@linkplain OptionSpec#type() type} of the option, or the specified default value if no option with the specified name was matched. */
 8270        public <T> T matchedOptionValue(String name, T defaultValue)       { return matchedOptionValue(matchedOption(name), defaultValue); }
 8271        /** Returns the command line argument value of the specified option, converted to the {@linkplain OptionSpec#type() type} of the option, or the specified default value if the specified option is {@code null}. */
 8272        @SuppressWarnings("unchecked")
 8273        private <T> T matchedOptionValue(OptionSpec option, T defaultValue) { return option == null ? defaultValue : (T) option.getValue(); }
 8274
 8275        /** Returns the command line argument value of the positional parameter at the specified position, converted to the {@linkplain PositionalParamSpec#type() type} of the positional parameter, or the specified default value if no positional parameter was matched at that position. */
 8276        public <T> T matchedPositionalValue(int position, T defaultValue)  { return matchedPositionalValue(matchedPositional(position), defaultValue); }
 8277        /** Returns the command line argument value of the specified positional parameter, converted to the {@linkplain PositionalParamSpec#type() type} of the positional parameter, or the specified default value if the specified positional parameter is {@code null}. */
 8278        @SuppressWarnings("unchecked")
 8279        private <T> T matchedPositionalValue(PositionalParamSpec positional, T defaultValue) { return positional == null ? defaultValue : (T) positional.getValue(); }
 8280
 8281        /** Returns {@code true} if a subcommand was matched on the command line, {@code false} otherwise. */
 8282        public boolean hasSubcommand()          { return subcommand != null; }
 8283
 8284        /** Returns the {@code ParseResult} for the subcommand of this command that was matched on the command line, or {@code null} if no subcommand was matched. */
 8285        public ParseResult subcommand()         { return subcommand; }
 8286
 8287        /** Returns {@code true} if one of the options that was matched on the command line is a {@link OptionSpec#usageHelp() usageHelp} option. */
 8288        public boolean isUsageHelpRequested()   { return usageHelpRequested; }
 8289
 8290        /** Returns {@code true} if one of the options that was matched on the command line is a {@link OptionSpec#versionHelp() versionHelp} option. */
 8291        public boolean isVersionHelpRequested() { return versionHelpRequested; }
 8292
 8293        /** Returns this {@code ParseResult} as a list of {@code CommandLine} objects, one for each matched command/subcommand.
 8294         * For backwards compatibility with pre-3.0 methods. */
 8295        public List<CommandLine> asCommandLineList() {
 8296            List<CommandLine> result = new ArrayList<CommandLine>();
 8297            ParseResult pr = this;
 8298            while (pr != null) { result.add(pr.commandSpec().commandLine()); pr = pr.hasSubcommand() ? pr.subcommand() : null; }
 8299            return result;
 8300        }
 8301
 8302        /** Builds immutable {@code ParseResult} instances. */
 8303        public static class Builder {
 8304            private final CommandSpec commandSpec;
 8305            private final Set<OptionSpec> options = new LinkedHashSet<OptionSpec>();
 8306            private final Set<PositionalParamSpec> positionals = new LinkedHashSet<PositionalParamSpec>();
 8307            private final List<String> unmatched = new ArrayList<String>();
 8308            private final List<String> originalArgList = new ArrayList<String>();
 8309            private final List<List<PositionalParamSpec>> positionalParams = new ArrayList<List<PositionalParamSpec>>();
 8310            private ParseResult subcommand;
 8311            private boolean usageHelpRequested;
 8312            private boolean versionHelpRequested;
 8313            boolean isInitializingDefaultValues;
 8314            private List<Exception> errors = new ArrayList<Exception>(1);
 8315            private List<Object> nowProcessing;
 8316            private MatchedGroup matchedGroup = new MatchedGroup(null, null);
 8317
 8318            private Builder(CommandSpec spec) { commandSpec = Assert.notNull(spec, "commandSpec"); }
 8319            /** Creates and returns a new {@code ParseResult} instance for this builder's configuration. */
 8320            public ParseResult build() {
 8321                return new ParseResult(this);
 8322            }
 8323
 8324            private void nowProcessing(ArgSpec spec, Object value) {
 8325                if (nowProcessing != null && !isInitializingDefaultValues) {
 8326                    nowProcessing.add(spec.isPositional() ? spec : value);
 8327                }
 8328            }
 8329
 8330            /** Adds the specified {@code OptionSpec} or {@code PositionalParamSpec} to the list of options and parameters
 8331             * that were matched on the command line.
 8332             * @param arg the matched {@code OptionSpec} or {@code PositionalParamSpec}
 8333             * @param position the command line position at which the  {@code PositionalParamSpec} was matched. Ignored for {@code OptionSpec}s.
 8334             * @return this builder for method chaining */
 8335            public Builder add(ArgSpec arg, int position) {
 8336                if (arg.isOption()) {
 8337                    addOption((OptionSpec) arg);
 8338                } else {
 8339                    addPositionalParam((PositionalParamSpec) arg, position);
 8340                }
 8341                afterMatchingGroupElement(arg, position);
 8342                return this;
 8343            }
 8344
 8345            /** Adds the specified {@code OptionSpec} to the list of options that were matched on the command line. */
 8346            public Builder addOption(OptionSpec option) { if (!isInitializingDefaultValues) {options.add(option);} return this; }
 8347            /** Adds the specified {@code PositionalParamSpec} to the list of parameters that were matched on the command line.
 8348             * @param positionalParam the matched {@code PositionalParamSpec}
 8349             * @param position the command line position at which the  {@code PositionalParamSpec} was matched.
 8350             * @return this builder for method chaining */
 8351            public Builder addPositionalParam(PositionalParamSpec positionalParam, int position) {
 8352                if (isInitializingDefaultValues) { return this; }
 8353                positionals.add(positionalParam);
 8354                while (positionalParams.size() <= position) { positionalParams.add(new ArrayList<PositionalParamSpec>()); }
 8355                positionalParams.get(position).add(positionalParam);
 8356                return this;
 8357            }
 8358            /** Adds the specified command line argument to the list of unmatched command line arguments. */
 8359            public Builder addUnmatched(String arg) { unmatched.add(arg); return this; }
 8360            /** Adds all elements of the specified command line arguments stack to the list of unmatched command line arguments. */
 8361            public Builder addUnmatched(Stack<String> args) { while (!args.isEmpty()) { addUnmatched(args.pop()); } return this; }
 8362            /** Sets the specified {@code ParseResult} for a subcommand that was matched on the command line. */
 8363            public Builder subcommand(ParseResult subcommand) { this.subcommand = subcommand; return this; }
 8364            /** Sets the specified command line arguments that were parsed. */
 8365            public Builder originalArgs(String[] originalArgs) { originalArgList.addAll(Arrays.asList(originalArgs)); return this;}
 8366
 8367            void addStringValue        (ArgSpec argSpec, String value) { if (!isInitializingDefaultValues) { argSpec.stringValues.add(value);} }
 8368            void addOriginalStringValue(ArgSpec argSpec, String value) {
 8369                if (!isInitializingDefaultValues) {
 8370                    argSpec.originalStringValues.add(value);
 8371                    if (argSpec.group() != null) {
 8372                        MatchedGroup matchedGroup = this.matchedGroup.findOrCreateMatchingGroup(argSpec, commandSpec.commandLine);
 8373                        matchedGroup.multiple().addOriginalStringValue(argSpec, value);
 8374                    }
 8375                }
 8376            }
 8377
 8378            void addTypedValues(ArgSpec argSpec, int position, Object typedValue) {
 8379                if (!isInitializingDefaultValues) {
 8380                    argSpec.typedValues.add(typedValue);
 8381                    if (argSpec.group() == null) {
 8382                        argSpec.typedValueAtPosition.put(position, typedValue);
 8383                    } else {
 8384                        MatchedGroup matchedGroup = this.matchedGroup.findOrCreateMatchingGroup(argSpec, commandSpec.commandLine);
 8385                        matchedGroup.multiple().addMatchedValue(argSpec, position, typedValue, commandSpec.commandLine.tracer);
 8386                    }
 8387                }
 8388            }
 8389
 8390            public void addError(PicocliException ex) {
 8391                errors.add(Assert.notNull(ex, "exception"));
 8392            }
 8393
 8394            void beforeMatchingGroupElement(ArgSpec argSpec) throws Exception {
 8395                ArgGroupSpec group = argSpec.group();
 8396                if (group == null || isInitializingDefaultValues) { return; }
 8397                MatchedGroup foundMatchedGroup = this.matchedGroup.findOrCreateMatchingGroup(argSpec, commandSpec.commandLine);
 8398                if (foundMatchedGroup.multiple().matchedMinElements() && argSpec.required()) {
 8399                    // we need to create a new multiple; if maxMultiplicity has been reached, we need to add a new MatchedGroup.
 8400                    String elementDescription = ArgSpec.describe(argSpec, "=");
 8401                    Tracer tracer = commandSpec.commandLine.tracer;
 8402                    tracer.info("MatchedGroupMultiple %s is complete: its mandatory elements are all matched. (User object: %s.) %s is required in the group, so it starts a new MatchedGroupMultiple.%n", foundMatchedGroup.multiple(), foundMatchedGroup.group.userObject(), elementDescription);
 8403                    foundMatchedGroup.addMultiple(commandSpec.commandLine);
 8404                }
 8405            }
 8406
 8407            private void afterMatchingGroupElement(ArgSpec argSpec, int position) {
 8408//                ArgGroupSpec group = argSpec.group();
 8409//                if (group == null || isInitializingDefaultValues) { return; }
 8410//                MatchedGroup matchedGroup = this.matchedGroup.findOrCreateMatchingGroup(argSpec, commandSpec.commandLine);
 8411//                promotePartiallyMatchedGroupToMatched(group, matchedGroup, true);
 8412            }
 8413
 8414            private void promotePartiallyMatchedGroupToMatched(ArgGroupSpec group, MatchedGroup matchedGroup, boolean allRequired) {
 8415                if (!matchedGroup.matchedFully(allRequired)) { return; }
 8416
 8417                // FIXME: before promoting the child group, check to see if the parent is matched, given the child group
 8418
 8419                Tracer tracer = commandSpec.commandLine.tracer;
 8420                if (matchedGroup.matchedMaxElements()) {
 8421                    tracer.info("Marking matched group %s as complete: max elements reached. User object: %s%n", matchedGroup, matchedGroup.group.userObject());
 8422                    matchedGroup.complete(commandSpec.commandLine());
 8423                }
 8424            }
 8425        }
 8426
 8427        /** Provides information about an {@link ArgGroup} that was matched on the command line.
 8428         * <p>
 8429         * The {@code ParseResult} may have more than one {@code MatchedGroup} for an {@code ArgGroupSpec}, when the
 8430         * group was matched more often than its maximum {@linkplain ArgGroup#multiplicity() multiplicity}.
 8431         * This is not necessarily a problem: the parser will add a multiple to the {@linkplain MatchedGroup#parentMatchedGroup() parent matched group}
 8432         * until the maximum multiplicity of the parent group is exceeded, in which case parser will add a multiple to the parent's parent group, etc.
 8433         * </p><p>
 8434         * Ultimately, as long as the {@link ParseResult#getMatchedGroupMultiples()} method does not return more than one multiple, the maximum number of elements is not exceeded.
 8435         * </p>
 8436         * @since 4.0 */
 8437        public static class MatchedGroup {
 8438            private final ArgGroupSpec group;
 8439            private MatchedGroup parentMatchedGroup;
 8440            private List<MatchedGroupMultiple> multiples = new ArrayList<MatchedGroupMultiple>();
 8441
 8442            MatchedGroup(ArgGroupSpec group, CommandLine cmd) { this.group = group; addMultiple(cmd);}
 8443
 8444            /** Returns the {@code ArgGroupSpec} whose matches are captured in this {@code MatchedGroup}. */
 8445            public ArgGroupSpec group() { return group; }
 8446            /** Returns the {@code MatchedGroup} of the parent {@code ArgGroupSpec}, or {@code null} if this group has no parent. */
 8447            public MatchedGroup parentMatchedGroup() { return parentMatchedGroup; }
 8448            /** Returns the list of {@code MatchedGroupMultiple} instances: {@code ArgGroupSpec}s with a multiplicity greater than one may be matched multiple times. */
 8449            public List<MatchedGroupMultiple> multiples() { return Collections.unmodifiableList(multiples); }
 8450
 8451            void addMultiple(CommandLine commandLine) {
 8452                Tracer tracer = commandLine == null ? new Tracer() : commandLine.tracer;
 8453                if (group != null && isMaxMultiplicityReached()) {
 8454                    tracer.info("Completing MatchedGroup %s: max multiplicity is reached.%n", this);
 8455                    complete(commandLine);
 8456                } else {
 8457                    if (group != null) {
 8458                        tracer.info("Adding multiple to MatchedGroup %s (group=%s %s).%n", this, group == null ? "?" : group.id(), group == null ? "ROOT" : group.synopsis());
 8459                    }
 8460                    multiples.add(new MatchedGroupMultiple(this));
 8461                    if (group == null) { return; }
 8462                }
 8463                group.initUserObject(commandLine);
 8464            }
 8465            void complete(CommandLine commandLine) {
 8466                if (parentMatchedGroup == null) {
 8467                    addMultiple(commandLine); // we have no choice but to potentially exceed the max multiplicity of this group...
 8468                } else {
 8469                    parentMatchedGroup.addMultiple(commandLine);
 8470                }
 8471            }
 8472            /** Returns the "active" multiple of this MatchedGroup. */
 8473            MatchedGroupMultiple multiple()    { return multiples.get(multiples.size() - 1); }
 8474            /** Returns {@code true} if no more {@code MatchedGroupMultiples} can be added to this {@code MatchedGroup}. Each multiple may be a complete or an incomplete match.*/
 8475            boolean isMaxMultiplicityReached() { return multiples.size() >= group.multiplicity.max; }
 8476            /** Returns {@code true} if this {@code MatchedGroup} has at least the minimum number of {@code MatchedGroupMultiples}. Each multiple may be a complete or an incomplete match. */
 8477            boolean isMinMultiplicityReached() { return multiples.size() >= group.multiplicity.min; }
 8478
 8479            /** Returns {@code true} if the minimum number of multiples has been matched for the multiplicity of this group,
 8480             * and each multiple has matched at least the {@linkplain MatchedGroupMultiple#matchedMinElements() minimum number of elements}.*/
 8481            boolean matchedMinElements() { return matchedFully(false); }
 8482            /** Returns {@code true} if the maximum number of multiples has been matched for the multiplicity of this group,
 8483             * and the last multiple has {@linkplain MatchedGroupMultiple#matchedMaxElements() matched the maximum number of elements},
 8484             * while all other multiples have matched at least the {@linkplain MatchedGroupMultiple#matchedMinElements() minimum number of elements}.*/
 8485            boolean matchedMaxElements() { return matchedFully(true); }
 8486            private boolean matchedFully(boolean allRequired) {
 8487                for (MatchedGroupMultiple multiple : multiples) {
 8488                    boolean actuallyAllRequired = allRequired && multiple == multiple();
 8489                    if (!multiple.matchedFully(actuallyAllRequired)) { return false; }
 8490                }
 8491                return allRequired ? isMaxMultiplicityReached() : isMinMultiplicityReached();
 8492            }
 8493
 8494            private MatchedGroup findOrCreateMatchingGroup(ArgSpec argSpec, CommandLine commandLine) {
 8495                ArgGroupSpec searchGroup = Assert.notNull(argSpec.group(), "group for " + argSpec);
 8496                MatchedGroup match = this;
 8497                if (searchGroup == match.group()) { return match; }
 8498                List<ArgGroupSpec> keys = new ArrayList<ArgGroupSpec>();
 8499                while (searchGroup != null) {
 8500                    keys.add(searchGroup);
 8501                    searchGroup = searchGroup.parentGroup();
 8502                }
 8503                Collections.reverse(keys);
 8504                for (ArgGroupSpec key : keys) {
 8505                    MatchedGroup sub = match.multiple().matchedSubgroups().get(key);
 8506                    if (sub == null) {
 8507                        sub = createMatchedGroup(key, match, commandLine);
 8508                    }
 8509                    match = sub;
 8510                }
 8511                return match;
 8512            }
 8513            private MatchedGroup createMatchedGroup(ArgGroupSpec group, MatchedGroup parent, CommandLine commandLine) {
 8514                MatchedGroup result = new MatchedGroup(group, commandLine);
 8515                result.parentMatchedGroup = parent;
 8516                parent.multiple().matchedSubgroups.put(group, result);
 8517                return result;
 8518            }
 8519            MatchedGroup trim() {
 8520                for (Iterator<MatchedGroupMultiple> iter = multiples.iterator(); iter.hasNext(); ) {
 8521                    MatchedGroupMultiple multiple = iter.next();
 8522                    if (multiple.isEmpty()) { iter.remove(); }
 8523                    for (MatchedGroup sub : multiple.matchedSubgroups.values()) { sub.trim(); }
 8524                }
 8525                return this;
 8526            }
 8527
 8528            List<MatchedGroup> findMatchedGroup(ArgGroupSpec group, List<MatchedGroup> result) {
 8529                if (this.group == group) { result.add(this); return result; }
 8530                for (MatchedGroupMultiple multiple : multiples()) {
 8531                    for (MatchedGroup mg : multiple.matchedSubgroups.values()) {
 8532                        mg.findMatchedGroup(group, result);
 8533                    }
 8534                }
 8535                return result;
 8536            }
 8537
 8538            @Override public String toString() {
 8539                return toString(new StringBuilder()).toString();
 8540            }
 8541
 8542            private StringBuilder toString(StringBuilder result) {
 8543                String prefix = result.length() == 0 ? "={" : "";
 8544                String suffix = result.length() == 0 ? "}" : "";
 8545                if (group != null && result.length() == 0) {
 8546                    result.append(group.synopsis());
 8547                }
 8548                result.append(prefix);
 8549                String infix = "";
 8550                for (MatchedGroupMultiple occurrence : multiples) {
 8551                    result.append(infix);
 8552                    occurrence.toString(result);
 8553                    infix = " ";
 8554                }
 8555                return result.append(suffix);
 8556
 8557            }
 8558        }
 8559
 8560        /** A group's {@linkplain ArgGroup#multiplicity() multiplicity} specifies how many multiples of a group can/must
 8561         * appear on the command line before a group is fully matched. This class models a single "multiple".
 8562         * For example, this group: {@code (-a -b) (-a -b)} requires two multiples of its arguments to fully match.
 8563         * @since 4.0
 8564         */
 8565        public static class MatchedGroupMultiple {
 8566            int position;
 8567            final MatchedGroup container;
 8568
 8569            Map<ArgGroupSpec, MatchedGroup> matchedSubgroups = new LinkedHashMap<ArgGroupSpec, MatchedGroup>(2); // preserve order: used in toString()
 8570            Map<ArgSpec, List<Object>> matchedValues         = new IdentityHashMap<ArgSpec, List<Object>>(); // identity map for performance
 8571            Map<ArgSpec, List<String>> originalStringValues  = new LinkedHashMap<ArgSpec, List<String>>(); // preserve order: used in toString()
 8572            Map<ArgSpec, Map<Integer, List<Object>>> matchedValuesAtPosition = new IdentityHashMap<ArgSpec, Map<Integer, List<Object>>>();
 8573
 8574            MatchedGroupMultiple(MatchedGroup container) { this.container = container; }
 8575
 8576            /** Returns {@code true} if this multiple has no matched arguments and no matched subgroups. */
 8577            public boolean isEmpty() { return originalStringValues.isEmpty() && matchedSubgroups.isEmpty(); }
 8578            /** Returns the {@code ArgGroupSpec} of the container {@code MatchedGroup} of this multiple. */
 8579            public ArgGroupSpec group() { return container.group; }
 8580            /** Returns the container {@code MatchedGroup} of this multiple. */
 8581            public MatchedGroup container() { return container; }
 8582            /** Returns matches for the subgroups, if any. */
 8583            public Map<ArgGroupSpec, MatchedGroup> matchedSubgroups() { return Collections.unmodifiableMap(matchedSubgroups); }
 8584            int matchCount(ArgSpec argSpec)                    { return matchedValues.get(argSpec) == null ? 0 : matchedValues.get(argSpec).size(); }
 8585            /** Returns the values matched for the specified argument, converted to the type of the argument. */
 8586            public List<Object> matchedValues(ArgSpec argSpec) { return matchedValues.get(argSpec) == null ? Collections.emptyList() : Collections.unmodifiableList(matchedValues.get(argSpec)); }
 8587            void addOriginalStringValue(ArgSpec argSpec, String value) {
 8588                addValueToListInMap(originalStringValues, argSpec, value);
 8589            }
 8590            void addMatchedValue(ArgSpec argSpec, int matchPosition, Object stronglyTypedValue, Tracer tracer) {
 8591                addValueToListInMap(matchedValues, argSpec, stronglyTypedValue);
 8592
 8593                Map<Integer, List<Object>> positionalValues = matchedValuesAtPosition.get(argSpec);
 8594                if (positionalValues == null) {
 8595                    positionalValues = new TreeMap<Integer, List<Object>>();
 8596                    matchedValuesAtPosition.put(argSpec, positionalValues);
 8597                }
 8598                addValueToListInMap(positionalValues, matchPosition, stronglyTypedValue);
 8599            }
 8600            boolean hasMatchedValueAtPosition(ArgSpec arg, int position) { Map<Integer, List<Object>> atPos = matchedValuesAtPosition.get(arg); return atPos != null && atPos.containsKey(position); }
 8601
 8602            /** Returns {@code true} if the minimum number of elements have been matched for this multiple:
 8603             * all required arguments have been matched, and for each subgroup,
 8604             * the {@linkplain MatchedGroup#matchedMinElements() minimum number of elements have been matched}.*/
 8605            boolean matchedMinElements() { return matchedFully(false); }
 8606            /** Returns {@code true} if the maximum number of multiples has been matched for this multiple:
 8607             * all arguments (required or not) have been matched, and for each subgroup,
 8608             * the {@linkplain MatchedGroup#matchedMaxElements() maximum number of elements have been matched}.*/
 8609            boolean matchedMaxElements() { return matchedFully(true); }
 8610            private boolean matchedFully(boolean allRequired) {
 8611                if (group().exclusive()) { return !matchedValues.isEmpty() || hasFullyMatchedSubgroup(allRequired); }
 8612                for (ArgSpec arg : group().args()) {
 8613                    if (matchedValues.get(arg) == null && (arg.required() || allRequired)) { return false; }
 8614                }
 8615                for (ArgGroupSpec subgroup : group().subgroups()) {
 8616                    MatchedGroup matchedGroup = matchedSubgroups.get(subgroup);
 8617                    if (matchedGroup != null) {
 8618                        if (!matchedGroup.matchedFully(allRequired)) { return false; }
 8619                    } else {
 8620                        if (allRequired || subgroup.multiplicity().min > 0) { return false; }
 8621                    }
 8622                }
 8623                return true;
 8624            }
 8625            private boolean hasFullyMatchedSubgroup(boolean allRequired) {
 8626                for (MatchedGroup sub : matchedSubgroups.values()) { if (sub.matchedFully(allRequired)) { return true; } }
 8627                return false;
 8628            }
 8629            @Override public String toString() {
 8630                return toString(new StringBuilder()).toString();
 8631            }
 8632
 8633            private StringBuilder toString(StringBuilder result) {
 8634                int originalLength = result.length();
 8635                for (ArgSpec arg : originalStringValues.keySet()) {
 8636                    List<String> values = originalStringValues.get(arg);
 8637                    for (String value : values) {
 8638                        if (result.length() != originalLength) { result.append(" "); }
 8639                        result.append(ArgSpec.describe(arg, "=", value));
 8640                    }
 8641                }
 8642                for (MatchedGroup sub : matchedSubgroups.values()) {
 8643                    if (result.length() != originalLength) { result.append(" "); }
 8644                    if (originalLength == 0) {
 8645                        result.append(sub.toString()); // include synopsis
 8646                    } else {
 8647                        sub.toString(result); // without synopsis
 8648                    }
 8649                }
 8650                return result;
 8651            }
 8652        }
 8653    }
 8654    static <K, T> void addValueToListInMap(Map<K, List<T>> map, K key, T value) {
 8655        List<T> values = map.get(key);
 8656        if (values == null) { values = new ArrayList<T>(); map.put(key, values); }
 8657        values.add(value);
 8658    }
 8659    static <T> List<T> flatList(Collection<? extends Collection<T>> collection) {
 8660        List<T> result = new ArrayList<T>();
 8661        for (Collection<T> sub : collection) { result.addAll(sub); }
 8662        return result;
 8663    }
 8664    private enum LookBehind { SEPARATE, ATTACHED, ATTACHED_WITH_SEPARATOR;
 8665        public boolean isAttached() { return this != LookBehind.SEPARATE; }
 8666    }
 8667    /**
 8668     * Helper class responsible for processing command line arguments.
 8669     */
 8670    private class Interpreter {
 8671        private final Map<Class<?>, ITypeConverter<?>> converterRegistry = new HashMap<Class<?>, ITypeConverter<?>>();
 8672        private boolean isHelpRequested;
 8673        private int position;
 8674        private boolean endOfOptions;
 8675        private ParseResult.Builder parseResultBuilder;
 8676
 8677        Interpreter() { registerBuiltInConverters(); }
 8678
 8679        private void registerBuiltInConverters() {
 8680            converterRegistry.put(Object.class,        new BuiltIn.StringConverter());
 8681            converterRegistry.put(String.class,        new BuiltIn.StringConverter());
 8682            converterRegistry.put(StringBuilder.class, new BuiltIn.StringBuilderConverter());
 8683            converterRegistry.put(CharSequence.class,  new BuiltIn.CharSequenceConverter());
 8684            converterRegistry.put(Byte.class,          new BuiltIn.ByteConverter());
 8685            converterRegistry.put(Byte.TYPE,           new BuiltIn.ByteConverter());
 8686            converterRegistry.put(Boolean.class,       new BuiltIn.BooleanConverter());
 8687            converterRegistry.put(Boolean.TYPE,        new BuiltIn.BooleanConverter());
 8688            converterRegistry.put(Character.class,     new BuiltIn.CharacterConverter());
 8689            converterRegistry.put(Character.TYPE,      new BuiltIn.CharacterConverter());
 8690            converterRegistry.put(Short.class,         new BuiltIn.ShortConverter());
 8691            converterRegistry.put(Short.TYPE,          new BuiltIn.ShortConverter());
 8692            converterRegistry.put(Integer.class,       new BuiltIn.IntegerConverter());
 8693            converterRegistry.put(Integer.TYPE,        new BuiltIn.IntegerConverter());
 8694            converterRegistry.put(Long.class,          new BuiltIn.LongConverter());
 8695            converterRegistry.put(Long.TYPE,           new BuiltIn.LongConverter());
 8696            converterRegistry.put(Float.class,         new BuiltIn.FloatConverter());
 8697            converterRegistry.put(Float.TYPE,          new BuiltIn.FloatConverter());
 8698            converterRegistry.put(Double.class,        new BuiltIn.DoubleConverter());
 8699            converterRegistry.put(Double.TYPE,         new BuiltIn.DoubleConverter());
 8700            converterRegistry.put(File.class,          new BuiltIn.FileConverter());
 8701            converterRegistry.put(URI.class,           new BuiltIn.URIConverter());
 8702            converterRegistry.put(URL.class,           new BuiltIn.URLConverter());
 8703            converterRegistry.put(Date.class,          new BuiltIn.ISO8601DateConverter());
 8704            converterRegistry.put(BigDecimal.class,    new BuiltIn.BigDecimalConverter());
 8705            converterRegistry.put(BigInteger.class,    new BuiltIn.BigIntegerConverter());
 8706            converterRegistry.put(Charset.class,       new BuiltIn.CharsetConverter());
 8707            converterRegistry.put(InetAddress.class,   new BuiltIn.InetAddressConverter());
 8708            converterRegistry.put(Pattern.class,       new BuiltIn.PatternConverter());
 8709            converterRegistry.put(UUID.class,          new BuiltIn.UUIDConverter());
 8710            converterRegistry.put(Currency.class,      new BuiltIn.CurrencyConverter());
 8711            converterRegistry.put(TimeZone.class,      new BuiltIn.TimeZoneConverter());
 8712            converterRegistry.put(ByteOrder.class,     new BuiltIn.ByteOrderConverter());
 8713            converterRegistry.put(Class.class,         new BuiltIn.ClassConverter());
 8714            converterRegistry.put(NetworkInterface.class, new BuiltIn.NetworkInterfaceConverter());
 8715
 8716            BuiltIn.ISO8601TimeConverter.registerIfAvailable(converterRegistry, tracer);
 8717            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.sql.Connection", "java.sql.DriverManager","getConnection", String.class);
 8718            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.sql.Driver", "java.sql.DriverManager","getDriver", String.class);
 8719            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.sql.Timestamp", "java.sql.Timestamp","valueOf", String.class);
 8720
 8721            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.Duration", "parse", CharSequence.class);
 8722            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.Instant", "parse", CharSequence.class);
 8723            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.LocalDate", "parse", CharSequence.class);
 8724            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.LocalDateTime", "parse", CharSequence.class);
 8725            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.LocalTime", "parse", CharSequence.class);
 8726            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.MonthDay", "parse", CharSequence.class);
 8727            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.OffsetDateTime", "parse", CharSequence.class);
 8728            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.OffsetTime", "parse", CharSequence.class);
 8729            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.Period", "parse", CharSequence.class);
 8730            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.Year", "parse", CharSequence.class);
 8731            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.YearMonth", "parse", CharSequence.class);
 8732            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.ZonedDateTime", "parse", CharSequence.class);
 8733            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.ZoneId", "of", String.class);
 8734            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.time.ZoneOffset", "of", String.class);
 8735
 8736            BuiltIn.registerIfAvailable(converterRegistry, tracer, "java.nio.file.Path", "java.nio.file.Paths", "get", String.class, String[].class);
 8737        }
 8738        private ParserSpec config() { return commandSpec.parser(); }
 8739        /**
 8740         * Entry point into parsing command line arguments.
 8741         * @param args the command line arguments
 8742         * @return a list with all commands and subcommands initialized by this method
 8743         * @throws ParameterException if the specified command line arguments are invalid
 8744         */
 8745        List<CommandLine> parse(String... args) {
 8746            Assert.notNull(args, "argument array");
 8747            if (tracer.isInfo()) {tracer.info("Picocli version: %s%n", versionString());}
 8748            if (tracer.isInfo()) {tracer.info("Parsing %d command line args %s%n", args.length, Arrays.toString(args));}
 8749            if (tracer.isDebug()){tracer.debug("Parser configuration: %s%n", config());}
 8750            if (tracer.isDebug()){tracer.debug("(ANSI is %s by default: isatty=%s, XTERM=%s, OSTYPE=%s, isWindows=%s, JansiConsoleInstalled=%s, ANSICON=%s, ConEmuANSI=%s, NO_COLOR=%s, CLICOLOR=%s, CLICOLOR_FORCE=%s)%n",
 8751                    Help.Ansi.ansiPossible() ? "enabled" : "disabled", Help.Ansi.isTTY(), System.getenv("XTERM"), System.getenv("OSTYPE"), Help.Ansi.isWindows(), Help.Ansi.isJansiConsoleInstalled(), System.getenv("ANSICON"), System.getenv("ConEmuANSI"), System.getenv("NO_COLOR"), System.getenv("CLICOLOR"), System.getenv("CLICOLOR_FORCE"));}
 8752            List<String> expanded = new ArrayList<String>();
 8753            for (String arg : args) { addOrExpand(arg, expanded, new LinkedHashSet<String>()); }
 8754            Stack<String> arguments = new Stack<String>();
 8755            arguments.addAll(reverseList(expanded));
 8756            List<CommandLine> result = new ArrayList<CommandLine>();
 8757            parse(result, arguments, args, new ArrayList<Object>());
 8758            return result;
 8759        }
 8760
 8761        private void addOrExpand(String arg, List<String> arguments, Set<String> visited) {
 8762            if (config().expandAtFiles() && !arg.equals("@") && arg.startsWith("@")) {
 8763                arg = arg.substring(1);
 8764                if (arg.startsWith("@")) {
 8765                    if (tracer.isInfo()) { tracer.info("Not expanding @-escaped argument %s (trimmed leading '@' char)%n", arg); }
 8766                } else {
 8767                    if (tracer.isInfo()) { tracer.info("Expanding argument file @%s%n", arg); }
 8768                    expandArgumentFile(arg, arguments, visited);
 8769                    return;
 8770                }
 8771            }
 8772            arguments.add(arg);
 8773        }
 8774        private void expandArgumentFile(String fileName, List<String> arguments, Set<String> visited) {
 8775            File file = new File(fileName);
 8776            if (!file.canRead()) {
 8777                if (tracer.isInfo()) {tracer.info("File %s does not exist or cannot be read; treating argument literally%n", fileName);}
 8778                arguments.add("@" + fileName);
 8779            } else if (visited.contains(file.getAbsolutePath())) {
 8780                if (tracer.isInfo()) {tracer.info("Already visited file %s; ignoring...%n", file.getAbsolutePath());}
 8781            } else {
 8782                expandValidArgumentFile(fileName, file, arguments, visited);
 8783            }
 8784        }
 8785        private void expandValidArgumentFile(String fileName, File file, List<String> arguments, Set<String> visited) {
 8786            List<String> result = new ArrayList<String>();
 8787            LineNumberReader reader = null;
 8788            try {
 8789                visited.add(file.getAbsolutePath());
 8790                reader = new LineNumberReader(new FileReader(file));
 8791                if (commandSpec.parser().useSimplifiedAtFiles()) {
 8792                    String token;
 8793                    while ((token = reader.readLine()) != null) {
 8794                        if (token.length() > 0 && !token.trim().startsWith(String.valueOf(commandSpec.parser().atFileCommentChar()))) {
 8795                            addOrExpand(token, result, visited);
 8796                        }
 8797                    }
 8798                } else {
 8799                    StreamTokenizer tok = new StreamTokenizer(reader);
 8800                    tok.resetSyntax();
 8801                    tok.wordChars(' ', 255);
 8802                    tok.whitespaceChars(0, ' ');
 8803                    tok.quoteChar('"');
 8804                    tok.quoteChar('\'');
 8805                    if (commandSpec.parser().atFileCommentChar() != null) {
 8806                        tok.commentChar(commandSpec.parser().atFileCommentChar());
 8807                    }
 8808                    while (tok.nextToken() != StreamTokenizer.TT_EOF) {
 8809                        addOrExpand(tok.sval, result, visited);
 8810                    }
 8811                }
 8812            } catch (Exception ex) {
 8813                throw new InitializationException("Could not read argument file @" + fileName, ex);
 8814            } finally {
 8815                if (reader != null) { try {reader.close();} catch (Exception ignored) {} }
 8816            }
 8817            if (tracer.isInfo()) {tracer.info("Expanded file @%s to arguments %s%n", fileName, result);}
 8818            arguments.addAll(result);
 8819        }
 8820        private void clear() {
 8821            position = 0;
 8822            endOfOptions = false;
 8823            isHelpRequested = false;
 8824            parseResultBuilder = ParseResult.builder(getCommandSpec());
 8825            for (OptionSpec option : getCommandSpec().options())                           { clear(option); }
 8826            for (PositionalParamSpec positional : getCommandSpec().positionalParameters()) { clear(positional); }
 8827        }
 8828        private void clear(ArgSpec argSpec) {
 8829            argSpec.resetStringValues();
 8830            argSpec.resetOriginalStringValues();
 8831            argSpec.typedValues.clear();
 8832            argSpec.typedValueAtPosition.clear();
 8833            if (argSpec.group() == null) { argSpec.applyInitialValue(tracer); } // groups do their own initialization
 8834        }
 8835
 8836        private void maybeThrow(PicocliException ex) throws PicocliException {
 8837            if (commandSpec.parser().collectErrors) {
 8838                parseResultBuilder.addError(ex);
 8839            } else {
 8840                throw ex;
 8841            }
 8842        }
 8843
 8844        private void parse(List<CommandLine> parsedCommands, Stack<String> argumentStack, String[] originalArgs, List<Object> nowProcessing) {
 8845            clear(); // first reset any state in case this CommandLine instance is being reused
 8846            if (tracer.isDebug()) {
 8847                tracer.debug("Initializing %s: %d options, %d positional parameters, %d required, %d groups, %d subcommands.%n",
 8848                        commandSpec.toString(), new HashSet<ArgSpec>(commandSpec.optionsMap().values()).size(),
 8849                        commandSpec.positionalParameters().size(), commandSpec.requiredArgs().size(),
 8850                        commandSpec.argGroups().size(), commandSpec.subcommands().size());
 8851            }
 8852            parsedCommands.add(CommandLine.this);
 8853            List<ArgSpec> required = new ArrayList<ArgSpec>(commandSpec.requiredArgs());
 8854            Set<ArgSpec> initialized = new LinkedHashSet<ArgSpec>();
 8855            Collections.sort(required, new PositionalParametersSorter());
 8856            boolean continueOnError = commandSpec.parser().collectErrors();
 8857            do {
 8858                int stackSize = argumentStack.size();
 8859                try {
 8860                    applyDefaultValues(required);
 8861                    processArguments(parsedCommands, argumentStack, required, initialized, originalArgs, nowProcessing);
 8862                } catch (ParameterException ex) {
 8863                    maybeThrow(ex);
 8864                } catch (Exception ex) {
 8865                    int offendingArgIndex = originalArgs.length - argumentStack.size() - 1;
 8866                    String arg = offendingArgIndex >= 0 && offendingArgIndex < originalArgs.length ? originalArgs[offendingArgIndex] : "?";
 8867                    maybeThrow(ParameterException.create(CommandLine.this, ex, arg, offendingArgIndex, originalArgs));
 8868                }
 8869                if (continueOnError && stackSize == argumentStack.size() && stackSize > 0) {
 8870                    parseResultBuilder.unmatched.add(argumentStack.pop());
 8871                }
 8872            } while (!argumentStack.isEmpty() && continueOnError);
 8873
 8874            if (!isAnyHelpRequested()) {
 8875                validateConstraints(argumentStack, required, initialized);
 8876            }
 8877        }
 8878
 8879        private void validateConstraints(Stack<String> argumentStack, List<ArgSpec> required, Set<ArgSpec> matched) {
 8880            if (!required.isEmpty()) {
 8881                for (ArgSpec missing : required) {
 8882                    Assert.assertTrue(missing.group() == null, "Arguments in a group are not necessarily required for the command");
 8883                    if (missing.isOption()) {
 8884                        maybeThrow(MissingParameterException.create(CommandLine.this, required, config().separator()));
 8885                    } else {
 8886                        assertNoMissingParameters(missing, missing.arity(), argumentStack);
 8887                    }
 8888                }
 8889            }
 8890            if (!parseResultBuilder.unmatched.isEmpty()) {
 8891                String[] unmatched = parseResultBuilder.unmatched.toArray(new String[0]);
 8892                for (UnmatchedArgsBinding unmatchedArgsBinding : getCommandSpec().unmatchedArgsBindings()) {
 8893                    unmatchedArgsBinding.addAll(unmatched.clone());
 8894                }
 8895                if (!isUnmatchedArgumentsAllowed()) { maybeThrow(new UnmatchedArgumentException(CommandLine.this, Collections.unmodifiableList(parseResultBuilder.unmatched))); }
 8896                if (tracer.isInfo()) { tracer.info("Unmatched arguments: %s%n", parseResultBuilder.unmatched); }
 8897            }
 8898            for (ArgGroupSpec group : commandSpec.argGroups()) {
 8899                group.clearValidationResult();
 8900            }
 8901            ParseResult pr = parseResultBuilder.build();
 8902            for (ArgGroupSpec group : commandSpec.argGroups()) {
 8903                group.validateConstraints(pr);
 8904            }
 8905            List<ParseResult.MatchedGroupMultiple> matchedGroupMultiples = pr.getMatchedGroupMultiples();
 8906            if (matchedGroupMultiples.size() > 1) {
 8907                failGroupMultiplicityExceeded(matchedGroupMultiples);
 8908            }
 8909        }
 8910
 8911        private void failGroupMultiplicityExceeded(List<ParseResult.MatchedGroupMultiple> matchedGroupMultiples) {
 8912            Map<ArgGroupSpec, List<List<ParseResult.MatchedGroupMultiple>>> multiplesPerGroup = new IdentityHashMap<ArgGroupSpec, List<List<ParseResult.MatchedGroupMultiple>>>();
 8913            String msg = "";
 8914            for (ParseResult.MatchedGroupMultiple multiple : matchedGroupMultiples) {
 8915                if (msg.length() > 0) { msg += " and "; }
 8916                msg += multiple.toString();
 8917                Map<ArgGroupSpec, MatchedGroup> subgroups = multiple.matchedSubgroups();
 8918                for (ArgGroupSpec group : subgroups.keySet()) {
 8919                    addValueToListInMap(multiplesPerGroup, group, subgroups.get(group).multiples());
 8920                }
 8921            }
 8922            if (!simplifyErrorMessageForSingleGroup(multiplesPerGroup)) {
 8923                maybeThrow(new MaxValuesExceededException(CommandLine.this, "Error: expected only one match but got " + msg));
 8924            }
 8925        }
 8926
 8927        private boolean simplifyErrorMessageForSingleGroup(Map<ArgGroupSpec, List<List<ParseResult.MatchedGroupMultiple>>> multiplesPerGroup) {
 8928            if (multiplesPerGroup.size() == 1) { // all multiples were matches for a single group
 8929                ArgGroupSpec group = multiplesPerGroup.keySet().iterator().next();
 8930                List<ParseResult.MatchedGroupMultiple> flat = flatList(multiplesPerGroup.get(group));
 8931                for (ParseResult.MatchedGroupMultiple multiple : flat) {
 8932                    if (!multiple.matchedSubgroups().isEmpty()) { return false; }
 8933                }
 8934                group.validationException = null;
 8935                group.validateMultiples(CommandLine.this, flat);
 8936                if (group.validationException != null) {
 8937                    maybeThrow(group.validationException);
 8938                    return true;
 8939                }
 8940            }
 8941            return false;
 8942        }
 8943
 8944        private void applyDefaultValues(List<ArgSpec> required) throws Exception {
 8945            parseResultBuilder.isInitializingDefaultValues = true;
 8946            for (ArgSpec arg : commandSpec.args()) {
 8947                if (arg.group() == null) {
 8948                    if (applyDefault(commandSpec.defaultValueProvider(), arg)) { required.remove(arg); }
 8949                }
 8950            }
 8951            parseResultBuilder.isInitializingDefaultValues = false;
 8952        }
 8953
 8954        private boolean applyDefault(IDefaultValueProvider defaultValueProvider, ArgSpec arg) throws Exception {
 8955
 8956            // Default value provider return value is only used if provider exists and if value
 8957            // is not null otherwise the original default or initial value are used
 8958            String fromProvider = defaultValueProvider == null ? null : defaultValueProvider.defaultValue(arg);
 8959            String defaultValue = fromProvider == null ? arg.defaultValue() : fromProvider;
 8960
 8961            if (defaultValue != null) {
 8962                if (tracer.isDebug()) {tracer.debug("Applying defaultValue (%s) to %s%n", defaultValue, arg);}
 8963                Range arity = arg.arity().min(Math.max(1, arg.arity().min));
 8964                applyOption(arg, LookBehind.SEPARATE, arity, stack(defaultValue), new HashSet<ArgSpec>(), arg.toString);
 8965            }
 8966            return defaultValue != null;
 8967        }
 8968
 8969        private Stack<String> stack(String value) {Stack<String> result = new Stack<String>(); result.push(value); return result;}
 8970
 8971        private void processArguments(List<CommandLine> parsedCommands,
 8972                                      Stack<String> args,
 8973                                      Collection<ArgSpec> required,
 8974                                      Set<ArgSpec> initialized,
 8975                                      String[] originalArgs,
 8976                                      List<Object> nowProcessing) throws Exception {
 8977            // arg must be one of:
 8978            // 1. the "--" double dash separating options from positional arguments
 8979            // 1. a stand-alone flag, like "-v" or "--verbose": no value required, must map to boolean or Boolean field
 8980            // 2. a short option followed by an argument, like "-f file" or "-ffile": may map to any type of field
 8981            // 3. a long option followed by an argument, like "-file out.txt" or "-file=out.txt"
 8982            // 3. one or more remaining arguments without any associated options. Must be the last in the list.
 8983            // 4. a combination of stand-alone options, like "-vxr". Equivalent to "-v -x -r", "-v true -x true -r true"
 8984            // 5. a combination of stand-alone options and one option with an argument, like "-vxrffile"
 8985
 8986            parseResultBuilder.originalArgs(originalArgs);
 8987            parseResultBuilder.nowProcessing = nowProcessing;
 8988            String separator = config().separator();
 8989            while (!args.isEmpty()) {
 8990                if (endOfOptions) {
 8991                    processRemainderAsPositionalParameters(required, initialized, args);
 8992                    return;
 8993                }
 8994                String arg = args.pop();
 8995                if (tracer.isDebug()) {tracer.debug("Processing argument '%s'. Remainder=%s%n", arg, reverse(copy(args)));}
 8996
 8997                // Double-dash separates options from positional arguments.
 8998                // If found, then interpret the remaining args as positional parameters.
 8999                if (commandSpec.parser.endOfOptionsDelimiter().equals(arg)) {
 9000                    tracer.info("Found end-of-options delimiter '--'. Treating remainder as positional parameters.%n");
 9001                    endOfOptions = true;
 9002                    processRemainderAsPositionalParameters(required, initialized, args);
 9003                    return; // we are done
 9004                }
 9005
 9006                // if we find another command, we are done with the current command
 9007                if (commandSpec.subcommands().containsKey(arg)) {
 9008                    CommandLine subcommand = commandSpec.subcommands().get(arg);
 9009                    nowProcessing.add(subcommand.commandSpec);
 9010                    updateHelpRequested(subcommand.commandSpec);
 9011                    if (!isAnyHelpRequested() && !required.isEmpty()) { // ensure current command portion is valid
 9012                        throw MissingParameterException.create(CommandLine.this, required, separator);
 9013                    }
 9014                    if (tracer.isDebug()) {tracer.debug("Found subcommand '%s' (%s)%n", arg, subcommand.commandSpec.toString());}
 9015                    subcommand.interpreter.parse(parsedCommands, args, originalArgs, nowProcessing);
 9016                    parseResultBuilder.subcommand(subcommand.interpreter.parseResultBuilder.build());
 9017                    return; // remainder done by the command
 9018                }
 9019
 9020                // First try to interpret the argument as a single option (as opposed to a compact group of options).
 9021                // A single option may be without option parameters, like "-v" or "--verbose" (a boolean value),
 9022                // or an option may have one or more option parameters.
 9023                // A parameter may be attached to the option.
 9024                boolean paramAttachedToOption = false;
 9025                int separatorIndex = arg.indexOf(separator);
 9026                if (separatorIndex > 0) {
 9027                    String key = arg.substring(0, separatorIndex);
 9028                    // be greedy. Consume the whole arg as an option if possible.
 9029                    if (commandSpec.optionsMap().containsKey(key) && commandSpec.optionsMap().containsKey(arg)) {
 9030                        tracer.warn("Both '%s' and '%s' are valid option names in %s. Using '%s'...%n", arg, key, getCommandName(), arg);
 9031                    } else if (commandSpec.optionsMap().containsKey(key)) {
 9032                        paramAttachedToOption = true;
 9033                        String optionParam = arg.substring(separatorIndex + separator.length());
 9034                        args.push(optionParam);
 9035                        arg = key;
 9036                        if (tracer.isDebug()) {tracer.debug("Separated '%s' option from '%s' option parameter%n", key, optionParam);}
 9037                    } else {
 9038                        if (tracer.isDebug()) {tracer.debug("'%s' contains separator '%s' but '%s' is not a known option%n", arg, separator, key);}
 9039                    }
 9040                } else {
 9041                    if (tracer.isDebug()) {tracer.debug("'%s' cannot be separated into <option>%s<option-parameter>%n", arg, separator);}
 9042                }
 9043                if (isStandaloneOption(arg)) {
 9044                    processStandaloneOption(required, initialized, arg, args, paramAttachedToOption);
 9045                }
 9046                // Compact (single-letter) options can be grouped with other options or with an argument.
 9047                // only single-letter options can be combined with other options or with an argument
 9048                else if (config().posixClusteredShortOptionsAllowed() && arg.length() > 2 && arg.startsWith("-")) {
 9049                    if (tracer.isDebug()) {tracer.debug("Trying to process '%s' as clustered short options%n", arg, args);}
 9050                    processClusteredShortOptions(required, initialized, arg, args);
 9051                }
 9052                // The argument could not be interpreted as an option: process it as a positional argument
 9053                else {
 9054                    args.push(arg);
 9055                    if (tracer.isDebug()) {tracer.debug("Could not find option '%s', deciding whether to treat as unmatched option or positional parameter...%n", arg);}
 9056                    if (commandSpec.resemblesOption(arg, tracer)) { handleUnmatchedArgument(args); continue; } // #149
 9057                    if (tracer.isDebug()) {tracer.debug("No option named '%s' found. Processing as positional parameter%n", arg);}
 9058                    processPositionalParameter(required, initialized, args);
 9059                }
 9060            }
 9061        }
 9062
 9063        private boolean isStandaloneOption(String arg) {
 9064            return commandSpec.optionsMap().containsKey(arg);
 9065        }
 9066        private void handleUnmatchedArgument(Stack<String> args) throws Exception {
 9067            if (!args.isEmpty()) { handleUnmatchedArgument(args.pop()); }
 9068            if (config().stopAtUnmatched()) {
 9069                // addAll would give args in reverse order
 9070                while (!args.isEmpty()) { handleUnmatchedArgument(args.pop()); }
 9071            }
 9072        }
 9073        private void handleUnmatchedArgument(String arg) {
 9074            parseResultBuilder.unmatched.add(arg);
 9075        }
 9076
 9077        private void processRemainderAsPositionalParameters(Collection<ArgSpec> required, Set<ArgSpec> initialized, Stack<String> args) throws Exception {
 9078            while (!args.empty()) {
 9079                processPositionalParameter(required, initialized, args);
 9080            }
 9081        }
 9082        private void processPositionalParameter(Collection<ArgSpec> required, Set<ArgSpec> initialized, Stack<String> args) throws Exception {
 9083            if (tracer.isDebug()) {tracer.debug("Processing next arg as a positional parameter. Command-local position=%d. Remainder=%s%n", position, reverse(copy(args)));}
 9084            if (config().stopAtPositional()) {
 9085                if (!endOfOptions && tracer.isDebug()) {tracer.debug("Parser was configured with stopAtPositional=true, treating remaining arguments as positional parameters.%n");}
 9086                endOfOptions = true;
 9087            }
 9088            int consumedByGroup = 0;
 9089            int argsConsumed = 0;
 9090            int interactiveConsumed = 0;
 9091            int originalNowProcessingSize = parseResultBuilder.nowProcessing.size();
 9092            Map<PositionalParamSpec, Integer> newPositions = new IdentityHashMap<PositionalParamSpec, Integer>();
 9093            for (PositionalParamSpec positionalParam : commandSpec.positionalParameters()) {
 9094                Range indexRange = positionalParam.index();
 9095                int localPosition = getPosition(positionalParam);
 9096                if (positionalParam.group() != null) { // does the positionalParam's index range contain the current position in the currently matching group
 9097                    MatchedGroup matchedGroup = parseResultBuilder.matchedGroup.findOrCreateMatchingGroup(positionalParam, commandSpec.commandLine());
 9098                    if (!indexRange.contains(localPosition) || (matchedGroup != null && matchedGroup.multiple().hasMatchedValueAtPosition(positionalParam, localPosition))) {
 9099                        continue;
 9100                    }
 9101                } else {
 9102                    if (!indexRange.contains(localPosition) || positionalParam.typedValueAtPosition.get(localPosition) != null) {
 9103                        continue;
 9104                    }
 9105                }
 9106                Stack<String> argsCopy = copy(args);
 9107                Range arity = positionalParam.arity();
 9108                if (tracer.isDebug()) {tracer.debug("Position %s is in index range %s. Trying to assign args to %s, arity=%s%n", positionDesc(positionalParam), indexRange, positionalParam, arity);}
 9109                if (!assertNoMissingParameters(positionalParam, arity, argsCopy)) { break; } // #389 collectErrors parsing
 9110                int originalSize = argsCopy.size();
 9111                int actuallyConsumed = applyOption(positionalParam, LookBehind.SEPARATE, arity, argsCopy, initialized, "args[" + indexRange + "] at position " + localPosition);
 9112                int count = originalSize - argsCopy.size();
 9113                if (count > 0 || actuallyConsumed > 0) {
 9114                    required.remove(positionalParam);
 9115                    if (positionalParam.interactive()) { interactiveConsumed++; }
 9116                }
 9117                if (positionalParam.group() == null) { // don't update the command-level position for group args
 9118                    argsConsumed = Math.max(argsConsumed, count);
 9119                } else {
 9120                    newPositions.put(positionalParam, localPosition + count);
 9121                    consumedByGroup = Math.max(consumedByGroup, count);
 9122                }
 9123                while (parseResultBuilder.nowProcessing.size() > originalNowProcessingSize + count) {
 9124                    parseResultBuilder.nowProcessing.remove(parseResultBuilder.nowProcessing.size() - 1);
 9125                }
 9126            }
 9127            // remove processed args from the stack
 9128            int maxConsumed = Math.max(consumedByGroup, argsConsumed);
 9129            for (int i = 0; i < maxConsumed; i++) { args.pop(); }
 9130            position += argsConsumed + interactiveConsumed;
 9131            if (tracer.isDebug()) {tracer.debug("Consumed %d arguments and %d interactive values, moving command-local position to index %d.%n", argsConsumed, interactiveConsumed, position);}
 9132            for (PositionalParamSpec positional : newPositions.keySet()) {
 9133                MatchedGroup inProgress = parseResultBuilder.matchedGroup.findOrCreateMatchingGroup(positional, commandSpec.commandLine());
 9134                if (inProgress != null) {
 9135                    inProgress.multiple().position = newPositions.get(positional);
 9136                    if (tracer.isDebug()) {tracer.debug("Updated group position to %s for group %s.%n", inProgress.multiple().position, inProgress);}
 9137                }
 9138            }
 9139            if (consumedByGroup == 0 && argsConsumed == 0 && interactiveConsumed == 0 && !args.isEmpty()) {
 9140                handleUnmatchedArgument(args);
 9141            }
 9142        }
 9143
 9144        private void processStandaloneOption(Collection<ArgSpec> required,
 9145                                             Set<ArgSpec> initialized,
 9146                                             String arg,
 9147                                             Stack<String> args,
 9148                                             boolean paramAttachedToKey) throws Exception {
 9149            ArgSpec argSpec = commandSpec.optionsMap().get(arg);
 9150            required.remove(argSpec);
 9151            Range arity = argSpec.arity();
 9152            if (paramAttachedToKey) {
 9153                arity = arity.min(Math.max(1, arity.min)); // if key=value, minimum arity is at least 1
 9154            }
 9155            LookBehind lookBehind = paramAttachedToKey ? LookBehind.ATTACHED_WITH_SEPARATOR : LookBehind.SEPARATE;
 9156            if (tracer.isDebug()) {tracer.debug("Found option named '%s': %s, arity=%s%n", arg, argSpec, arity);}
 9157            parseResultBuilder.nowProcessing.add(argSpec);
 9158            applyOption(argSpec, lookBehind, arity, args, initialized, "option " + arg);
 9159        }
 9160
 9161        private void processClusteredShortOptions(Collection<ArgSpec> required,
 9162                                                  Set<ArgSpec> initialized,
 9163                                                  String arg,
 9164                                                  Stack<String> args) throws Exception {
 9165            String prefix = arg.substring(0, 1);
 9166            String cluster = arg.substring(1);
 9167            boolean paramAttachedToOption = true;
 9168            boolean first = true;
 9169            do {
 9170                if (cluster.length() > 0 && commandSpec.posixOptionsMap().containsKey(cluster.charAt(0))) {
 9171                    ArgSpec argSpec = commandSpec.posixOptionsMap().get(cluster.charAt(0));
 9172                    Range arity = argSpec.arity();
 9173                    String argDescription = "option " + prefix + cluster.charAt(0);
 9174                    if (tracer.isDebug()) {tracer.debug("Found option '%s%s' in %s: %s, arity=%s%n", prefix, cluster.charAt(0), arg,
 9175                            argSpec, arity);}
 9176                    required.remove(argSpec);
 9177                    cluster = cluster.substring(1);
 9178                    paramAttachedToOption = cluster.length() > 0;
 9179                    LookBehind lookBehind = paramAttachedToOption ? LookBehind.ATTACHED : LookBehind.SEPARATE;
 9180                    if (cluster.startsWith(config().separator())) {// attached with separator, like -f=FILE or -v=true
 9181                        lookBehind = LookBehind.ATTACHED_WITH_SEPARATOR;
 9182                        cluster = cluster.substring(config().separator().length());
 9183                        arity = arity.min(Math.max(1, arity.min)); // if key=value, minimum arity is at least 1
 9184                    }
 9185                    if (arity.min > 0 && !empty(cluster)) {
 9186                        if (tracer.isDebug()) {tracer.debug("Trying to process '%s' as option parameter%n", cluster);}
 9187                    }
 9188                    // arity may be >= 1, or
 9189                    // arity <= 0 && !cluster.startsWith(separator)
 9190                    // e.g., boolean @Option("-v", arity=0, varargs=true); arg "-rvTRUE", remainder cluster="TRUE"
 9191                    if (!empty(cluster)) {
 9192                        args.push(cluster); // interpret remainder as option parameter (CAUTION: may be empty string!)
 9193                    }
 9194                    if (first) {
 9195                        parseResultBuilder.nowProcessing.add(argSpec);
 9196                        first = false;
 9197                    } else {
 9198                        parseResultBuilder.nowProcessing.set(parseResultBuilder.nowProcessing.size() - 1, argSpec); // replace
 9199                    }
 9200                    int argCount = args.size();
 9201                    int consumed = applyOption(argSpec, lookBehind, arity, args, initialized, argDescription);
 9202                    // if cluster was consumed as a parameter or if this field was the last in the cluster we're done; otherwise continue do-while loop
 9203                    if (empty(cluster) || args.isEmpty() || args.size() < argCount) {
 9204                        return;
 9205                    }
 9206                    cluster = args.pop();
 9207                } else { // cluster is empty || cluster.charAt(0) is not a short option key
 9208                    if (cluster.length() == 0) { // we finished parsing a group of short options like -rxv
 9209                        return; // return normally and parse the next arg
 9210                    }
 9211                    // We get here when the remainder of the cluster group is neither an option,
 9212                    // nor a parameter that the last option could consume.
 9213                    if (arg.endsWith(cluster)) {
 9214                        args.push(paramAttachedToOption ? prefix + cluster : cluster);
 9215                        if (args.peek().equals(arg)) { // #149 be consistent between unmatched short and long options
 9216                            if (tracer.isDebug()) {tracer.debug("Could not match any short options in %s, deciding whether to treat as unmatched option or positional parameter...%n", arg);}
 9217                            if (commandSpec.resemblesOption(arg, tracer)) { handleUnmatchedArgument(args); return; } // #149
 9218                            processPositionalParameter(required, initialized, args);
 9219                            return;
 9220                        }
 9221                        // remainder was part of a clustered group that could not be completely parsed
 9222                        if (tracer.isDebug()) {tracer.debug("No option found for %s in %s%n", cluster, arg);}
 9223                        String tmp = args.pop();
 9224                        tmp = tmp + " (while processing option: '" + arg + "')";
 9225                        args.push(tmp);
 9226                        handleUnmatchedArgument(args);
 9227                    } else {
 9228                        args.push(cluster);
 9229                        if (tracer.isDebug()) {tracer.debug("%s is not an option parameter for %s%n", cluster, arg);}
 9230                        processPositionalParameter(required, initialized, args);
 9231                    }
 9232                    return;
 9233                }
 9234            } while (true);
 9235        }
 9236
 9237        private int applyOption(ArgSpec argSpec,
 9238                                LookBehind lookBehind,
 9239                                Range arity,
 9240                                Stack<String> args,
 9241                                Set<ArgSpec> initialized,
 9242                                String argDescription) throws Exception {
 9243            updateHelpRequested(argSpec);
 9244            boolean consumeOnlyOne = commandSpec.parser().aritySatisfiedByAttachedOptionParam() && lookBehind.isAttached();
 9245            Stack<String> workingStack = args;
 9246            if (consumeOnlyOne) {
 9247                workingStack = args.isEmpty() ? args : stack(args.pop());
 9248            } else {
 9249                if (!assertNoMissingParameters(argSpec, arity, args)) { return 0; } // #389 collectErrors parsing
 9250            }
 9251
 9252            if (argSpec.interactive()) {
 9253                String name = argSpec.isOption() ? ((OptionSpec) argSpec).longestName() : "position " + position;
 9254                String prompt = String.format("Enter value for %s (%s): ", name, str(argSpec.renderedDescription(), 0));
 9255                if (tracer.isDebug()) {tracer.debug("Reading value for %s from console...%n", name);}
 9256                char[] value = readPassword(prompt);
 9257                if (tracer.isDebug()) {tracer.debug("User entered '%s' for %s.%n", value, name);}
 9258                workingStack.push(new String(value));
 9259            }
 9260
 9261            parseResultBuilder.beforeMatchingGroupElement(argSpec);
 9262
 9263            int result;
 9264            if (argSpec.type().isArray()) {
 9265                result = applyValuesToArrayField(argSpec, lookBehind, arity, workingStack, initialized, argDescription);
 9266            } else if (Collection.class.isAssignableFrom(argSpec.type())) {
 9267                result = applyValuesToCollectionField(argSpec, lookBehind, arity, workingStack, initialized, argDescription);
 9268            } else if (Map.class.isAssignableFrom(argSpec.type())) {
 9269                result = applyValuesToMapField(argSpec, lookBehind, arity, workingStack, initialized, argDescription);
 9270            } else {
 9271                result = applyValueToSingleValuedField(argSpec, lookBehind, arity, workingStack, initialized, argDescription);
 9272            }
 9273            if (workingStack != args && !workingStack.isEmpty()) {
 9274                args.push(workingStack.pop());
 9275                Assert.assertTrue(workingStack.isEmpty(), "Working stack should be empty but was " + new ArrayList<String>(workingStack));
 9276            }
 9277            return result;
 9278        }
 9279
 9280        private int applyValueToSingleValuedField(ArgSpec argSpec,
 9281                                                  LookBehind lookBehind,
 9282                                                  Range derivedArity,
 9283                                                  Stack<String> args,
 9284                                                  Set<ArgSpec> initialized,
 9285                                                  String argDescription) throws Exception {
 9286            boolean noMoreValues = args.isEmpty();
 9287            String value = args.isEmpty() ? null : trim(args.pop()); // unquote the value
 9288            Range arity = argSpec.arity().isUnspecified ? derivedArity : argSpec.arity(); // #509
 9289            if (arity.max == 0 && !arity.isUnspecified && lookBehind == LookBehind.ATTACHED_WITH_SEPARATOR) { // #509
 9290                throw new MaxValuesExceededException(CommandLine.this, optionDescription("", argSpec, 0) +
 9291                        " should be specified without '" + value + "' parameter");
 9292            }
 9293            int result = arity.min; // the number or args we need to consume
 9294
 9295            Class<?> cls = argSpec.auxiliaryTypes()[0]; // field may be interface/abstract type, use annotation to get concrete type
 9296            if (arity.min <= 0) { // value may be optional
 9297
 9298                // special logic for booleans: BooleanConverter accepts only "true" or "false".
 9299                if (cls == Boolean.class || cls == Boolean.TYPE) {
 9300
 9301                    // boolean option with arity = 0..1 or 0..*: value MAY be a param
 9302                    if (arity.max > 0 && ("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value))) {
 9303                        result = 1;            // if it is a varargs we only consume 1 argument if it is a boolean value
 9304                        if (!lookBehind.isAttached()) { parseResultBuilder.nowProcessing(argSpec, value); }
 9305                    } else if (lookBehind != LookBehind.ATTACHED_WITH_SEPARATOR) { // if attached, try converting the value to boolean (and fail if invalid value)
 9306                        // it's okay to ignore value if not attached to option
 9307                        if (value != null) {
 9308                            args.push(value); // we don't consume the value
 9309                        }
 9310                        if (commandSpec.parser().toggleBooleanFlags()) {
 9311                            Boolean currentValue = (Boolean) argSpec.getValue();
 9312                            value = String.valueOf(currentValue == null || !currentValue); // #147 toggle existing boolean value
 9313                        } else {
 9314                            value = "true";
 9315                        }
 9316                    }
 9317                } else { // non-boolean option with optional value #325, #279
 9318                    if (isOption(value)) {
 9319                        args.push(value); // we don't consume the value
 9320                        value = "";
 9321                    } else if (value == null) {
 9322                        value = "";
 9323                    } else {
 9324                        if (!lookBehind.isAttached()) { parseResultBuilder.nowProcessing(argSpec, value); }
 9325                    }
 9326                }
 9327            } else {
 9328                if (!lookBehind.isAttached()) { parseResultBuilder.nowProcessing(argSpec, value); }
 9329            }
 9330            if (noMoreValues && value == null) {
 9331                return 0;
 9332            }
 9333            ITypeConverter<?> converter = getTypeConverter(cls, argSpec, 0);
 9334            Object newValue = tryConvert(argSpec, -1, converter, value, cls);
 9335            Object oldValue = argSpec.getValue();
 9336            String traceMessage = "Setting %s to '%3$s' (was '%2$s') for %4$s%n";
 9337            if (argSpec.group() == null && initialized.contains(argSpec)) {
 9338                if (!isOverwrittenOptionsAllowed()) {
 9339                    throw new OverwrittenOptionException(CommandLine.this, argSpec, optionDescription("", argSpec, 0) +  " should be specified only once");
 9340                }
 9341                traceMessage = "Overwriting %s value '%s' with '%s' for %s%n";
 9342            }
 9343            initialized.add(argSpec);
 9344
 9345            if (tracer.isInfo()) { tracer.info(traceMessage, argSpec.toString(), String.valueOf(oldValue), String.valueOf(newValue), argDescription); }
 9346            int pos = getPosition(argSpec);
 9347            argSpec.setValue(newValue);
 9348            parseResultBuilder.addOriginalStringValue(argSpec, value);// #279 track empty string value if no command line argument was consumed
 9349            parseResultBuilder.addStringValue(argSpec, value);
 9350            parseResultBuilder.addTypedValues(argSpec, pos, newValue);
 9351            parseResultBuilder.add(argSpec, pos);
 9352            return result;
 9353        }
 9354        private int applyValuesToMapField(ArgSpec argSpec,
 9355                                          LookBehind lookBehind,
 9356                                          Range arity,
 9357                                          Stack<String> args,
 9358                                          Set<ArgSpec> initialized,
 9359                                          String argDescription) throws Exception {
 9360            Class<?>[] classes = argSpec.auxiliaryTypes();
 9361            if (classes.length < 2) { throw new ParameterException(CommandLine.this, argSpec.toString() + " needs two types (one for the map key, one for the value) but only has " + classes.length + " types configured.",argSpec, null); }
 9362            ITypeConverter<?> keyConverter   = getTypeConverter(classes[0], argSpec, 0);
 9363            ITypeConverter<?> valueConverter = getTypeConverter(classes[1], argSpec, 1);
 9364            @SuppressWarnings("unchecked") Map<Object, Object> map = (Map<Object, Object>) argSpec.getValue();
 9365            if (map == null || (!map.isEmpty() && !initialized.contains(argSpec))) {
 9366                tracer.debug("Initializing binding for %s with empty %s%n", optionDescription("", argSpec, 0), argSpec.type().getSimpleName());
 9367                map = createMap(argSpec.type()); // map class
 9368                argSpec.setValue(map);
 9369            }
 9370            initialized.add(argSpec);
 9371            int originalSize = map.size();
 9372            int pos = getPosition(argSpec);
 9373            consumeMapArguments(argSpec, lookBehind, arity, args, classes, keyConverter, valueConverter, map, argDescription);
 9374            parseResultBuilder.add(argSpec, pos);
 9375            argSpec.setValue(map);
 9376            return map.size() - originalSize;
 9377        }
 9378
 9379        private void consumeMapArguments(ArgSpec argSpec,
 9380                                         LookBehind lookBehind,
 9381                                         Range arity,
 9382                                         Stack<String> args,
 9383                                         Class<?>[] classes,
 9384                                         ITypeConverter<?> keyConverter,
 9385                                         ITypeConverter<?> valueConverter,
 9386                                         Map<Object, Object> result,
 9387                                         String argDescription) throws Exception {
 9388
 9389            // don't modify Interpreter.position: same position may be consumed by multiple ArgSpec objects
 9390            int currentPosition = getPosition(argSpec);
 9391
 9392            // first do the arity.min mandatory parameters
 9393            int initialSize = argSpec.stringValues().size();
 9394            int consumed = consumedCountMap(0, initialSize, argSpec);
 9395            for (int i = 0; consumed < arity.min && !args.isEmpty(); i++) {
 9396                Map<Object, Object> typedValuesAtPosition = new LinkedHashMap<Object, Object>();
 9397                parseResultBuilder.addTypedValues(argSpec, currentPosition++, typedValuesAtPosition);
 9398                assertNoMissingMandatoryParameter(argSpec, args, i, arity);
 9399                consumeOneMapArgument(argSpec, lookBehind, arity, consumed, args.pop(), classes, keyConverter, valueConverter, typedValuesAtPosition, i, argDescription);
 9400                result.putAll(typedValuesAtPosition);
 9401                consumed = consumedCountMap(i + 1, initialSize, argSpec);
 9402                lookBehind = LookBehind.SEPARATE;
 9403            }
 9404            // now process the varargs if any
 9405            for (int i = consumed; consumed < arity.max && !args.isEmpty(); i++) {
 9406                if (!varargCanConsumeNextValue(argSpec, args.peek())) { break; }
 9407
 9408                Map<Object, Object> typedValuesAtPosition = new LinkedHashMap<Object, Object>();
 9409                parseResultBuilder.addTypedValues(argSpec, currentPosition++, typedValuesAtPosition);
 9410                if (!canConsumeOneMapArgument(argSpec, arity, consumed, args.peek(), classes, keyConverter, valueConverter, argDescription)) {
 9411                    break; // leave empty map at argSpec.typedValueAtPosition[currentPosition] so we won't try to consume that position again
 9412                }
 9413                consumeOneMapArgument(argSpec, lookBehind, arity, consumed, args.pop(), classes, keyConverter, valueConverter, typedValuesAtPosition, i, argDescription);
 9414                result.putAll(typedValuesAtPosition);
 9415                consumed = consumedCountMap(i + 1, initialSize, argSpec);
 9416                lookBehind = LookBehind.SEPARATE;
 9417            }
 9418        }
 9419
 9420        private void consumeOneMapArgument(ArgSpec argSpec,
 9421                                           LookBehind lookBehind,
 9422                                           Range arity, int consumed,
 9423                                           String arg,
 9424                                           Class<?>[] classes,
 9425                                           ITypeConverter<?> keyConverter, ITypeConverter<?> valueConverter,
 9426                                           Map<Object, Object> result,
 9427                                           int index,
 9428                                           String argDescription) throws Exception {
 9429            if (!lookBehind.isAttached()) { parseResultBuilder.nowProcessing(argSpec, arg); }
 9430            String raw = trim(arg);
 9431            String[] values = argSpec.splitValue(raw, commandSpec.parser(), arity, consumed);
 9432            for (String value : values) {
 9433                String[] keyValue = splitKeyValue(argSpec, value);
 9434                Object mapKey =   tryConvert(argSpec, index, keyConverter,   keyValue[0], classes[0]);
 9435                Object mapValue = tryConvert(argSpec, index, valueConverter, keyValue[1], classes[1]);
 9436                result.put(mapKey, mapValue);
 9437                if (tracer.isInfo()) { tracer.info("Putting [%s : %s] in %s<%s, %s> %s for %s%n", String.valueOf(mapKey), String.valueOf(mapValue),
 9438                        result.getClass().getSimpleName(), classes[0].getSimpleName(), classes[1].getSimpleName(), argSpec.toString(), argDescription); }
 9439                parseResultBuilder.addStringValue(argSpec, keyValue[0]);
 9440                parseResultBuilder.addStringValue(argSpec, keyValue[1]);
 9441            }
 9442            parseResultBuilder.addOriginalStringValue(argSpec, raw);
 9443        }
 9444
 9445        private boolean canConsumeOneMapArgument(ArgSpec argSpec, Range arity, int consumed,
 9446                                                 String raw, Class<?>[] classes,
 9447                                                 ITypeConverter<?> keyConverter, ITypeConverter<?> valueConverter,
 9448                                                 String argDescription) {
 9449            String[] values = argSpec.splitValue(raw, commandSpec.parser(), arity, consumed);
 9450            try {
 9451                for (String value : values) {
 9452                    String[] keyValue = splitKeyValue(argSpec, value);
 9453                    tryConvert(argSpec, -1, keyConverter, keyValue[0], classes[0]);
 9454                    tryConvert(argSpec, -1, valueConverter, keyValue[1], classes[1]);
 9455                }
 9456                return true;
 9457            } catch (PicocliException ex) {
 9458                tracer.debug("$s cannot be assigned to %s: type conversion fails: %s.%n", raw, argDescription, ex.getMessage());
 9459                return false;
 9460            }
 9461        }
 9462
 9463        private String[] splitKeyValue(ArgSpec argSpec, String value) {
 9464            String[] keyValue = ArgSpec.splitRespectingQuotedStrings(value, 2, config(), argSpec, "=");
 9465
 9466                if (keyValue.length < 2) {
 9467                String splitRegex = argSpec.splitRegex();
 9468                if (splitRegex.length() == 0) {
 9469                    throw new ParameterException(CommandLine.this, "Value for option " + optionDescription("",
 9470                            argSpec, 0) + " should be in KEY=VALUE format but was " + value, argSpec, value);
 9471                } else {
 9472                    throw new ParameterException(CommandLine.this, "Value for option " + optionDescription("",
 9473                            argSpec, 0) + " should be in KEY=VALUE[" + splitRegex + "KEY=VALUE]... format but was " + value, argSpec, value);
 9474                }
 9475            }
 9476            return keyValue;
 9477        }
 9478
 9479        private void assertNoMissingMandatoryParameter(ArgSpec argSpec, Stack<String> args, int i, Range arity) {
 9480            if (!varargCanConsumeNextValue(argSpec, args.peek())) {
 9481                String desc = arity.min > 1 ? (i + 1) + " (of " + arity.min + " mandatory parameters) " : "";
 9482                throw new MissingParameterException(CommandLine.this, argSpec, "Expected parameter " + desc + "for " + optionDescription("", argSpec, -1) + " but found '" + args.peek() + "'");
 9483            }
 9484        }
 9485        private int applyValuesToArrayField(ArgSpec argSpec,
 9486                                            LookBehind lookBehind,
 9487                                            Range arity,
 9488                                            Stack<String> args,
 9489                                            Set<ArgSpec> initialized,
 9490                                            String argDescription) throws Exception {
 9491            Object existing = argSpec.getValue();
 9492            int length = existing == null ? 0 : Array.getLength(existing);
 9493            Class<?> type = argSpec.auxiliaryTypes()[0];
 9494            int pos = getPosition(argSpec);
 9495            List<Object> converted = consumeArguments(argSpec, lookBehind, arity, args, type, argDescription);
 9496            List<Object> newValues = new ArrayList<Object>();
 9497            if (initialized.contains(argSpec)) { // existing values are default values if initialized does NOT contain argsSpec
 9498                for (int i = 0; i < length; i++) {
 9499                    newValues.add(Array.get(existing, i)); // keep non-default values
 9500                }
 9501            }
 9502            initialized.add(argSpec);
 9503            for (Object obj : converted) {
 9504                if (obj instanceof Collection<?>) {
 9505                    newValues.addAll((Collection<?>) obj);
 9506                } else {
 9507                    newValues.add(obj);
 9508                }
 9509            }
 9510            Object array = Array.newInstance(type, newValues.size());
 9511            for (int i = 0; i < newValues.size(); i++) {
 9512                Array.set(array, i, newValues.get(i));
 9513            }
 9514            argSpec.setValue(array);
 9515            parseResultBuilder.add(argSpec, pos);
 9516            return converted.size(); // return how many args were consumed
 9517        }
 9518
 9519        @SuppressWarnings("unchecked")
 9520        private int applyValuesToCollectionField(ArgSpec argSpec,
 9521                                                 LookBehind lookBehind,
 9522                                                 Range arity,
 9523                                                 Stack<String> args,
 9524                                                 Set<ArgSpec> initialized,
 9525                                                 String argDescription) throws Exception {
 9526            Collection<Object> collection = (Collection<Object>) argSpec.getValue();
 9527            Class<?> type = argSpec.auxiliaryTypes()[0];
 9528            int pos = getPosition(argSpec);
 9529            List<Object> converted = consumeArguments(argSpec, lookBehind, arity, args, type, argDescription);
 9530            if (collection == null || (!collection.isEmpty() && !initialized.contains(argSpec))) {
 9531                tracer.debug("Initializing binding for %s with empty %s%n", optionDescription("", argSpec, 0), argSpec.type().getSimpleName());
 9532                collection = createCollection(argSpec.type(), type); // collection type, element type
 9533                argSpec.setValue(collection);
 9534            }
 9535            initialized.add(argSpec);
 9536            for (Object element : converted) {
 9537                if (element instanceof Collection<?>) {
 9538                    collection.addAll((Collection<?>) element);
 9539                } else {
 9540                    collection.add(element);
 9541                }
 9542            }
 9543            parseResultBuilder.add(argSpec, pos);
 9544            argSpec.setValue(collection);
 9545            return converted.size();
 9546        }
 9547
 9548        private List<Object> consumeArguments(ArgSpec argSpec,
 9549                                              LookBehind lookBehind,
 9550                                              Range arity,
 9551                                              Stack<String> args,
 9552                                              Class<?> type,
 9553                                              String argDescription) throws Exception {
 9554            List<Object> result = new ArrayList<Object>();
 9555
 9556            // don't modify Interpreter.position: same position may be consumed by multiple ArgSpec objects
 9557            int currentPosition = getPosition(argSpec);
 9558
 9559            // first do the arity.min mandatory parameters
 9560            int initialSize = argSpec.stringValues().size();
 9561            int consumed = consumedCount(0, initialSize, argSpec);
 9562            for (int i = 0; consumed < arity.min && !args.isEmpty(); i++) {
 9563                List<Object> typedValuesAtPosition = new ArrayList<Object>();
 9564                parseResultBuilder.addTypedValues(argSpec, currentPosition++, typedValuesAtPosition);
 9565                assertNoMissingMandatoryParameter(argSpec, args, i, arity);
 9566                consumeOneArgument(argSpec, lookBehind, arity, consumed, args.pop(), type, typedValuesAtPosition, i, argDescription);
 9567                result.addAll(typedValuesAtPosition);
 9568                consumed = consumedCount(i + 1, initialSize, argSpec);
 9569                lookBehind = LookBehind.SEPARATE;
 9570            }
 9571            // now process the varargs if any
 9572            for (int i = consumed; consumed < arity.max && !args.isEmpty(); i++) {
 9573                if (!varargCanConsumeNextValue(argSpec, args.peek())) { break; }
 9574
 9575                List<Object> typedValuesAtPosition = new ArrayList<Object>();
 9576                parseResultBuilder.addTypedValues(argSpec, currentPosition++, typedValuesAtPosition);
 9577                if (!canConsumeOneArgument(argSpec, arity, consumed, args.peek(), type, argDescription)) {
 9578                    break; // leave empty list at argSpec.typedValueAtPosition[currentPosition] so we won't try to consume that position again
 9579                }
 9580                consumeOneArgument(argSpec, lookBehind, arity, consumed, args.pop(), type, typedValuesAtPosition, i, argDescription);
 9581                result.addAll(typedValuesAtPosition);
 9582                consumed = consumedCount(i + 1, initialSize, argSpec);
 9583                lookBehind = LookBehind.SEPARATE;
 9584            }
 9585            if (result.isEmpty() && arity.min == 0 && arity.max <= 1 && isBoolean(type)) {
 9586                return Arrays.asList((Object) Boolean.TRUE);
 9587            }
 9588            return result;
 9589        }
 9590
 9591        private int consumedCount(int i, int initialSize, ArgSpec arg) {
 9592            return commandSpec.parser().splitFirst() ? arg.stringValues().size() - initialSize : i;
 9593        }
 9594
 9595        private int consumedCountMap(int i, int initialSize, ArgSpec arg) {
 9596            return commandSpec.parser().splitFirst() ? (arg.stringValues().size() - initialSize) / 2 : i;
 9597        }
 9598
 9599        private int consumeOneArgument(ArgSpec argSpec,
 9600                                       LookBehind lookBehind,
 9601                                       Range arity,
 9602                                       int consumed,
 9603                                       String arg,
 9604                                       Class<?> type,
 9605                                       List<Object> result,
 9606                                       int index,
 9607                                       String argDescription) {
 9608            if (!lookBehind.isAttached()) { parseResultBuilder.nowProcessing(argSpec, arg); }
 9609            String raw = trim(arg);
 9610            String[] values = argSpec.splitValue(raw, commandSpec.parser(), arity, consumed);
 9611            ITypeConverter<?> converter = getTypeConverter(type, argSpec, 0);
 9612            for (int j = 0; j < values.length; j++) {
 9613                Object stronglyTypedValue = tryConvert(argSpec, index, converter, values[j], type);
 9614                result.add(stronglyTypedValue);
 9615                if (tracer.isInfo()) {
 9616                    tracer.info("Adding [%s] to %s for %s%n", String.valueOf(result.get(result.size() - 1)), argSpec.toString(), argDescription);
 9617                }
 9618                parseResultBuilder.addStringValue(argSpec, values[j]);
 9619            }
 9620            parseResultBuilder.addOriginalStringValue(argSpec, raw);
 9621            return ++index;
 9622        }
 9623        private boolean canConsumeOneArgument(ArgSpec argSpec, Range arity, int consumed, String arg, Class<?> type, String argDescription) {
 9624            ITypeConverter<?> converter = getTypeConverter(type, argSpec, 0);
 9625            try {
 9626                String[] values = argSpec.splitValue(trim(arg), commandSpec.parser(), arity, consumed);
 9627//                if (!argSpec.acceptsValues(values.length, commandSpec.parser())) {
 9628//                    tracer.debug("$s would split into %s values but %s cannot accept that many values.%n", arg, values.length, argDescription);
 9629//                    return false;
 9630//                }
 9631                for (String value : values) {
 9632                    tryConvert(argSpec, -1, converter, value, type);
 9633                }
 9634                return true;
 9635            } catch (PicocliException ex) {
 9636                tracer.debug("$s cannot be assigned to %s: type conversion fails: %s.%n", arg, argDescription, ex.getMessage());
 9637                return false;
 9638            }
 9639        }
 9640
 9641        /** Returns whether the next argument can be assigned to a vararg option/positional parameter.
 9642         * <p>
 9643         * Usually, we stop if we encounter '--', a command, or another option.
 9644         * However, if end-of-options has been reached, positional parameters may consume all remaining arguments. </p>*/
 9645        private boolean varargCanConsumeNextValue(ArgSpec argSpec, String nextValue) {
 9646            if (endOfOptions && argSpec.isPositional()) { return true; }
 9647            boolean isCommand = commandSpec.subcommands().containsKey(nextValue);
 9648            return !isCommand && !isOption(nextValue);
 9649        }
 9650
 9651        /**
 9652         * Called when parsing varargs parameters for a multi-value option.
 9653         * When an option is encountered, the remainder should not be interpreted as vararg elements.
 9654         * @param arg the string to determine whether it is an option or not
 9655         * @return true if it is an option, false otherwise
 9656         */
 9657        private boolean isOption(String arg) {
 9658            if (arg == null)      { return false; }
 9659            if ("--".equals(arg)) { return true; }
 9660
 9661            // not just arg prefix: we may be in the middle of parsing -xrvfFILE
 9662            if (commandSpec.optionsMap().containsKey(arg)) { // -v or -f or --file (not attached to param or other option)
 9663                return true;
 9664            }
 9665            int separatorIndex = arg.indexOf(config().separator());
 9666            if (separatorIndex > 0) { // -f=FILE or --file==FILE (attached to param via separator)
 9667                if (commandSpec.optionsMap().containsKey(arg.substring(0, separatorIndex))) {
 9668                    return true;
 9669                }
 9670            }
 9671            return (arg.length() > 2 && arg.startsWith("-") && commandSpec.posixOptionsMap().containsKey(arg.charAt(1)));
 9672        }
 9673        private Object tryConvert(ArgSpec argSpec, int index, ITypeConverter<?> converter, String value, Class<?> type)
 9674                throws ParameterException {
 9675            try {
 9676                return converter.convert(value);
 9677            } catch (TypeConversionException ex) {
 9678                String msg = String.format("Invalid value for %s: %s", optionDescription("", argSpec, index), ex.getMessage());
 9679                throw new ParameterException(CommandLine.this, msg, argSpec, value);
 9680            } catch (Exception other) {
 9681                String desc = optionDescription("", argSpec, index);
 9682                String msg = String.format("Invalid value for %s: cannot convert '%s' to %s (%s)", desc, value, type.getSimpleName(), other);
 9683                throw new ParameterException(CommandLine.this, msg, other, argSpec, value);
 9684            }
 9685        }
 9686
 9687        private String optionDescription(String prefix, ArgSpec argSpec, int index) {
 9688            String desc = "";
 9689            if (argSpec.isOption()) {
 9690                desc = prefix + "option '" + ((OptionSpec) argSpec).longestName() + "'";
 9691                if (index >= 0) {
 9692                    if (argSpec.arity().max > 1) {
 9693                        desc += " at index " + index;
 9694                    }
 9695                    desc += " (" + argSpec.paramLabel() + ")";
 9696                }
 9697            } else {
 9698                desc = prefix + "positional parameter at index " + ((PositionalParamSpec) argSpec).index() + " (" + argSpec.paramLabel() + ")";
 9699            }
 9700            return desc;
 9701        }
 9702
 9703        private boolean isAnyHelpRequested() { return isHelpRequested || parseResultBuilder.versionHelpRequested || parseResultBuilder.usageHelpRequested; }
 9704
 9705        private void updateHelpRequested(CommandSpec command) {
 9706            isHelpRequested |= command.helpCommand();
 9707        }
 9708        private void updateHelpRequested(ArgSpec argSpec) {
 9709            if (!parseResultBuilder.isInitializingDefaultValues && argSpec.isOption()) {
 9710                OptionSpec option = (OptionSpec) argSpec;
 9711                isHelpRequested                  |= is(argSpec, "help", option.help());
 9712                parseResultBuilder.versionHelpRequested |= is(argSpec, "versionHelp", option.versionHelp());
 9713                parseResultBuilder.usageHelpRequested   |= is(argSpec, "usageHelp", option.usageHelp());
 9714            }
 9715        }
 9716        private boolean is(ArgSpec p, String attribute, boolean value) {
 9717            if (value) { if (tracer.isInfo()) {tracer.info("%s has '%s' annotation: not validating required fields%n", p.toString(), attribute); }}
 9718            return value;
 9719        }
 9720        @SuppressWarnings("unchecked")
 9721        private Collection<Object> createCollection(Class<?> collectionClass, Class<?> elementType) throws Exception {
 9722            if (EnumSet.class.isAssignableFrom(collectionClass) && Enum.class.isAssignableFrom(elementType)) {
 9723                Object enumSet = EnumSet.noneOf((Class<Enum>) elementType);
 9724                return (Collection<Object>) enumSet;
 9725            }
 9726            // custom Collection implementation class must have default constructor
 9727            return (Collection<Object>) factory.create(collectionClass);
 9728        }
 9729        @SuppressWarnings("unchecked") private Map<Object, Object> createMap(Class<?> mapClass) throws Exception {
 9730            return (Map<Object, Object>) factory.create(mapClass);
 9731        }
 9732        private ITypeConverter<?> getTypeConverter(final Class<?> type, ArgSpec argSpec, int index) {
 9733            if (argSpec.converters().length > index) { return argSpec.converters()[index]; }
 9734            if (converterRegistry.containsKey(type)) { return converterRegistry.get(type); }
 9735            if (type.isEnum()) {
 9736                return new ITypeConverter<Object>() {
 9737                    @SuppressWarnings("unchecked")
 9738                    public Object convert(String value) throws Exception {
 9739                        String sensitivity = "case-sensitive";
 9740                        if (commandSpec.parser().caseInsensitiveEnumValuesAllowed()) {
 9741                            String upper = value.toUpperCase();
 9742                            for (Object enumConstant : type.getEnumConstants()) {
 9743                                if (upper.equals(String.valueOf(enumConstant).toUpperCase())) { return enumConstant; }
 9744                            }
 9745                            sensitivity = "case-insensitive";
 9746                        }
 9747                        try { return Enum.valueOf((Class<Enum>) type, value); }
 9748                        catch (Exception ex) {
 9749                            Enum<?>[] constants = ((Class<Enum<?>>) type).getEnumConstants();
 9750                            String[] names = new String[constants.length];
 9751                            for (int i = 0; i < names.length; i++) { names[i] = constants[i].name(); }
 9752                            throw new TypeConversionException(
 9753                                String.format("expected one of %s (%s) but was '%s'", Arrays.asList(names), sensitivity, value)); }
 9754                    }
 9755                };
 9756            }
 9757            throw new MissingTypeConverterException(CommandLine.this, "No TypeConverter registered for " + type.getName() + " of " + argSpec);
 9758        }
 9759
 9760        private boolean assertNoMissingParameters(ArgSpec argSpec, Range arity, Stack<String> args) {
 9761            if (argSpec.interactive()) { return true; }
 9762            int available = args.size();
 9763            if (available > 0 && commandSpec.parser().splitFirst() && argSpec.splitRegex().length() > 0) {
 9764                available += argSpec.splitValue(args.peek(), commandSpec.parser(), arity, 0).length - 1;
 9765            }
 9766            if (arity.min > available) {
 9767                if (arity.min == 1) {
 9768                    if (argSpec.isOption()) {
 9769                        maybeThrow(new MissingParameterException(CommandLine.this, argSpec, "Missing required parameter for " +
 9770                                optionDescription("", argSpec, 0)));
 9771                        return false;
 9772                    }
 9773                    Range indexRange = ((PositionalParamSpec) argSpec).index();
 9774                    String sep = "";
 9775                    String names = ": ";
 9776                    int count = 0;
 9777                    List<PositionalParamSpec> positionalParameters = commandSpec.positionalParameters();
 9778                    for (int i = indexRange.min; i < positionalParameters.size(); i++) {
 9779                        if (positionalParameters.get(i).arity().min > 0) {
 9780                            names += sep + positionalParameters.get(i).paramLabel();
 9781                            sep = ", ";
 9782                            count++;
 9783                        }
 9784                    }
 9785                    String msg = "Missing required parameter";
 9786                    Range paramArity = argSpec.arity();
 9787                    if (count > 1 || arity.min - available > 1) {
 9788                        msg += "s";
 9789                    }
 9790                    maybeThrow(new MissingParameterException(CommandLine.this, argSpec, msg + names));
 9791                } else if (args.isEmpty()) {
 9792                    maybeThrow(new MissingParameterException(CommandLine.this, argSpec, optionDescription("", argSpec, 0) +
 9793                            " requires at least " + arity.min + " values, but none were specified."));
 9794                } else {
 9795                    maybeThrow(new MissingParameterException(CommandLine.this, argSpec, optionDescription("", argSpec, 0) +
 9796                            " requires at least " + arity.min + " values, but only " + available + " were specified: " + reverse(args)));
 9797                }
 9798                return false;
 9799            }
 9800            return true;
 9801        }
 9802        private String trim(String value) {
 9803            return unquote(value);
 9804        }
 9805
 9806        private String unquote(String value) {
 9807            if (!commandSpec.parser().trimQuotes()) { return value; }
 9808            return value == null
 9809                    ? null
 9810                    : (value.length() > 1 && value.startsWith("\"") && value.endsWith("\""))
 9811                        ? value.substring(1, value.length() - 1)
 9812                        : value;
 9813        }
 9814
 9815        char[] readPassword(String prompt) {
 9816            try {
 9817                Object console = System.class.getDeclaredMethod("console").invoke(null);
 9818                Method method = Class.forName("java.io.Console").getDeclaredMethod("readPassword", String.class, Object[].class);
 9819                return (char[]) method.invoke(console, prompt, new Object[0]);
 9820            } catch (Exception e) {
 9821                System.out.print(prompt);
 9822                InputStreamReader isr = new InputStreamReader(System.in);
 9823                BufferedReader in = new BufferedReader(isr);
 9824                try {
 9825                    return in.readLine().toCharArray();
 9826                } catch (IOException ex2) {
 9827                    throw new IllegalStateException(ex2);
 9828                }
 9829            }
 9830        }
 9831        int getPosition(ArgSpec arg) {
 9832            if (arg.group() == null) { return position; }
 9833            MatchedGroup matchedGroup = parseResultBuilder.matchedGroup.findOrCreateMatchingGroup(arg, commandSpec.commandLine());
 9834            return matchedGroup == null ? 0 : matchedGroup.multiple().position;
 9835        }
 9836        String positionDesc(ArgSpec arg) {
 9837            int pos = getPosition(arg);
 9838            return (arg.group() == null) ? pos + " (command-local)" : pos + " (in group " + arg.group().synopsis() + ")";
 9839        }
 9840    }
 9841    private static class PositionalParametersSorter implements Comparator<ArgSpec> {
 9842        private static final Range OPTION_INDEX = new Range(0, 0, false, true, "0");
 9843        public int compare(ArgSpec p1, ArgSpec p2) {
 9844            int result = index(p1).compareTo(index(p2));
 9845            return (result == 0) ? p1.arity().compareTo(p2.arity()) : result;
 9846        }
 9847        private Range index(ArgSpec arg) { return arg.isOption() ? OPTION_INDEX : ((PositionalParamSpec) arg).index(); }
 9848    }
 9849    /**
 9850     * Inner class to group the built-in {@link ITypeConverter} implementations.
 9851     */
 9852    private static class BuiltIn {
 9853        static class StringConverter implements ITypeConverter<String> {
 9854            public String convert(String value) { return value; }
 9855        }
 9856        static class StringBuilderConverter implements ITypeConverter<StringBuilder> {
 9857            public StringBuilder convert(String value) { return new StringBuilder(value); }
 9858        }
 9859        static class CharSequenceConverter implements ITypeConverter<CharSequence> {
 9860            public String convert(String value) { return value; }
 9861        }
 9862        /** Converts {@code "true"} or {@code "false"} to a {@code Boolean}. Other values result in a ParameterException.*/
 9863        static class BooleanConverter implements ITypeConverter<Boolean> {
 9864            public Boolean convert(String value) {
 9865                if ("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value)) {
 9866                    return Boolean.parseBoolean(value);
 9867                } else {
 9868                    throw new TypeConversionException("'" + value + "' is not a boolean");
 9869                }
 9870            }
 9871        }
 9872        static class CharacterConverter implements ITypeConverter<Character> {
 9873            public Character convert(String value) {
 9874                if (value.length() > 1) {
 9875                    throw new TypeConversionException("'" + value + "' is not a single character");
 9876                }
 9877                return value.charAt(0);
 9878            }
 9879        }
 9880        private static TypeConversionException fail(String value, Class<?> c) { return fail(value, c, "'%s' is not a %s"); }
 9881        private static TypeConversionException fail(String value, Class<?> c, String template) {
 9882            return new TypeConversionException(String.format(template, value, c.getSimpleName()));
 9883        }
 9884        /** Converts text to a {@code Byte} by delegating to {@link Byte#valueOf(String)}.*/
 9885        static class ByteConverter implements ITypeConverter<Byte> {
 9886            public Byte convert(String value) { try {return Byte.valueOf(value);} catch (Exception ex) {throw fail(value, Byte.TYPE);} }
 9887        }
 9888        /** Converts text to a {@code Short} by delegating to {@link Short#valueOf(String)}.*/
 9889        static class ShortConverter implements ITypeConverter<Short> {
 9890            public Short convert(String value) { try {return Short.valueOf(value);} catch (Exception ex) {throw fail(value, Short.TYPE);}  }
 9891        }
 9892        /** Converts text to an {@code Integer} by delegating to {@link Integer#valueOf(String)}.*/
 9893        static class IntegerConverter implements ITypeConverter<Integer> {
 9894            public Integer convert(String value) { try {return Integer.valueOf(value);} catch (Exception ex) {throw fail(value, Integer.TYPE, "'%s' is not an %s");}  }
 9895        }
 9896        /** Converts text to a {@code Long} by delegating to {@link Long#valueOf(String)}.*/
 9897        static class LongConverter implements ITypeConverter<Long> {
 9898            public Long convert(String value) { try {return Long.valueOf(value);} catch (Exception ex) {throw fail(value, Long.TYPE);}  }
 9899        }
 9900        static class FloatConverter implements ITypeConverter<Float> {
 9901            public Float convert(String value) { try {return Float.valueOf(value);} catch (Exception ex) {throw fail(value, Float.TYPE);}  }
 9902        }
 9903        static class DoubleConverter implements ITypeConverter<Double> {
 9904            public Double convert(String value) { try {return Double.valueOf(value);} catch (Exception ex) {throw fail(value, Double.TYPE);}  }
 9905        }
 9906        static class FileConverter implements ITypeConverter<File> {
 9907            public File convert(String value) { return new File(value); }
 9908        }
 9909        static class URLConverter implements ITypeConverter<URL> {
 9910            public URL convert(String value) throws MalformedURLException { return new URL(value); }
 9911        }
 9912        static class URIConverter implements ITypeConverter<URI> {
 9913            public URI convert(String value) throws URISyntaxException { return new URI(value); }
 9914        }
 9915        /** Converts text in {@code yyyy-mm-dd} format to a {@code java.util.Date}. ParameterException on failure. */
 9916        static class ISO8601DateConverter implements ITypeConverter<Date> {
 9917            public Date convert(String value) {
 9918                try {
 9919                    return new SimpleDateFormat("yyyy-MM-dd").parse(value);
 9920                } catch (ParseException e) {
 9921                    throw new TypeConversionException("'" + value + "' is not a yyyy-MM-dd date");
 9922                }
 9923            }
 9924        }
 9925        /** Converts text in any of the following formats to a {@code java.sql.Time}: {@code HH:mm}, {@code HH:mm:ss},
 9926         * {@code HH:mm:ss.SSS}, {@code HH:mm:ss,SSS}. Other formats result in a ParameterException. */
 9927        static class ISO8601TimeConverter implements ITypeConverter<Object> {
 9928            // Implementation note: use reflection so that picocli only requires the java.base module in Java 9.
 9929            private static /*final*/ String FQCN = "java.sql.Time"; // non-final for testing
 9930            public Object convert(String value) {
 9931                try {
 9932                    if (value.length() <= 5) {
 9933                        return createTime(new SimpleDateFormat("HH:mm").parse(value).getTime());
 9934                    } else if (value.length() <= 8) {
 9935                        return createTime(new SimpleDateFormat("HH:mm:ss").parse(value).getTime());
 9936                    } else if (value.length() <= 12) {
 9937                        try {
 9938                            return createTime(new SimpleDateFormat("HH:mm:ss.SSS").parse(value).getTime());
 9939                        } catch (ParseException e2) {
 9940                            return createTime(new SimpleDateFormat("HH:mm:ss,SSS").parse(value).getTime());
 9941                        }
 9942                    }
 9943                } catch (ParseException ignored) {
 9944                    // ignored because we throw a ParameterException below
 9945                }
 9946                throw new TypeConversionException("'" + value + "' is not a HH:mm[:ss[.SSS]] time");
 9947            }
 9948
 9949            private Object createTime(long epochMillis) {
 9950                try {
 9951                    Class<?> timeClass = Class.forName(FQCN);
 9952                    Constructor<?> constructor = timeClass.getDeclaredConstructor(long.class);
 9953                    return constructor.newInstance(epochMillis);
 9954                } catch (Exception e) {
 9955                    throw new TypeConversionException("Unable to create new java.sql.Time with long value " + epochMillis + ": " + e.getMessage());
 9956                }
 9957            }
 9958
 9959            public static void registerIfAvailable(Map<Class<?>, ITypeConverter<?>> registry, Tracer tracer) {
 9960                if (excluded(FQCN, tracer)) { return; }
 9961                try {
 9962                    registry.put(Class.forName(FQCN), new ISO8601TimeConverter());
 9963                } catch (Exception e) {
 9964                    if (!traced.contains(FQCN)) {
 9965                        tracer.debug("Could not register converter for %s: %s%n", FQCN, e.toString());
 9966                    }
 9967                    traced.add(FQCN);
 9968                }
 9969            }
 9970        }
 9971        static class BigDecimalConverter implements ITypeConverter<BigDecimal> {
 9972            public BigDecimal convert(String value) { return new BigDecimal(value); }
 9973        }
 9974        static class BigIntegerConverter implements ITypeConverter<BigInteger> {
 9975            public BigInteger convert(String value) { return new BigInteger(value); }
 9976        }
 9977        static class CharsetConverter implements ITypeConverter<Charset> {
 9978            public Charset convert(String s) { return Charset.forName(s); }
 9979        }
 9980        /** Converts text to a {@code InetAddress} by delegating to {@link InetAddress#getByName(String)}. */
 9981        static class InetAddressConverter implements ITypeConverter<InetAddress> {
 9982            public InetAddress convert(String s) throws Exception { return InetAddress.getByName(s); }
 9983        }
 9984        static class PatternConverter implements ITypeConverter<Pattern> {
 9985            public Pattern convert(String s) { return Pattern.compile(s); }
 9986        }
 9987        static class UUIDConverter implements ITypeConverter<UUID> {
 9988            public UUID convert(String s) throws Exception { return UUID.fromString(s); }
 9989        }
 9990        static class CurrencyConverter implements ITypeConverter<Currency> {
 9991            public Currency convert(String s) throws Exception { return Currency.getInstance(s); }
 9992        }
 9993        static class TimeZoneConverter implements ITypeConverter<TimeZone> {
 9994            public TimeZone convert(String s) throws Exception { return TimeZone.getTimeZone(s); }
 9995        }
 9996        static class ByteOrderConverter implements ITypeConverter<ByteOrder> {
 9997            public ByteOrder convert(String s) throws Exception {
 9998                if (s.equalsIgnoreCase(ByteOrder.BIG_ENDIAN.toString())) { return ByteOrder.BIG_ENDIAN; }
 9999                if (s.equalsIgnoreCase(ByteOrder.LITTLE_ENDIAN.toString())) { return ByteOrder.LITTLE_ENDIAN; }
10000                throw new TypeConversionException("'" + s + "' is not a valid ByteOrder");
10001            }
10002        }
10003        static class ClassConverter implements ITypeConverter<Class<?>> {
10004            public Class<?> convert(String s) throws Exception { return Class.forName(s); }
10005        }
10006        static class NetworkInterfaceConverter implements ITypeConverter<NetworkInterface> {
10007            public NetworkInterface convert(String s) throws Exception {
10008                try {
10009                    InetAddress addr = new InetAddressConverter().convert(s);
10010                    return NetworkInterface.getByInetAddress(addr);
10011                } catch (Exception ex) {
10012                    try { return NetworkInterface.getByName(s);
10013                    } catch (Exception ex2) {
10014                        throw new TypeConversionException("'" + s + "' is not an InetAddress or NetworkInterface name");
10015                    }
10016                }
10017            }
10018        }
10019        static void registerIfAvailable(Map<Class<?>, ITypeConverter<?>> registry, Tracer tracer, String fqcn, String factoryMethodName, Class<?>... paramTypes) {
10020            registerIfAvailable(registry, tracer, fqcn, fqcn, factoryMethodName, paramTypes);
10021        }
10022        static void registerIfAvailable(Map<Class<?>, ITypeConverter<?>> registry, Tracer tracer, String fqcn, String factoryClass, String factoryMethodName, Class<?>... paramTypes) {
10023            if (excluded(fqcn, tracer)) { return; }
10024            try {
10025                Class<?> cls = Class.forName(fqcn);
10026                Class<?> factory = Class.forName(factoryClass);
10027                Method method = factory.getDeclaredMethod(factoryMethodName, paramTypes);
10028                registry.put(cls, new ReflectionConverter(method, paramTypes));
10029            } catch (Exception e) {
10030                if (!traced.contains(fqcn)) {
10031                    tracer.debug("Could not register converter for %s: %s%n", fqcn, e.toString());
10032                }
10033                traced.add(fqcn);
10034            }
10035        }
10036        static boolean excluded(String fqcn, Tracer tracer) {
10037            String[] excludes = System.getProperty("picocli.converters.excludes", "").split(",");
10038            for (String regex : excludes) {
10039                if (fqcn.matches(regex)) {
10040                    tracer.debug("BuiltIn type converter for %s is not loaded: (picocli.converters.excludes=%s)%n", fqcn, System.getProperty("picocli.converters.excludes"));
10041                    return true;
10042                }
10043            }
10044            return false;
10045        }
10046        static Set<String> traced = new HashSet<String>();
10047        static class ReflectionConverter implements ITypeConverter<Object> {
10048            private final Method method;
10049            private Class<?>[] paramTypes;
10050
10051            public ReflectionConverter(Method method, Class<?>... paramTypes) {
10052                this.method = Assert.notNull(method, "method");
10053                this.paramTypes = Assert.notNull(paramTypes, "paramTypes");
10054            }
10055
10056            public Object convert(String s) {
10057                try {
10058                    if (paramTypes.length > 1) {
10059                        return method.invoke(null, s, new String[0]);
10060                    } else {
10061                        return method.invoke(null, s);
10062                    }
10063                } catch (InvocationTargetException e) {
10064                    throw new TypeConversionException(String.format("cannot convert '%s' to %s (%s)", s, method.getReturnType(), e.getTargetException()));
10065                } catch (Exception e) {
10066                    throw new TypeConversionException(String.format("Internal error converting '%s' to %s (%s)", s, method.getReturnType(), e));
10067                }
10068            }
10069        }
10070        private BuiltIn() {} // private constructor: never instantiate
10071    }
10072
10073    static class AutoHelpMixin {
10074        private static final String KEY = "mixinStandardHelpOptions";
10075
10076        @Option(names = {"-h", "--help"}, usageHelp = true, descriptionKey = "mixinStandardHelpOptions.help",
10077                description = "Show this help message and exit.")
10078        private boolean helpRequested;
10079
10080        @Option(names = {"-V", "--version"}, versionHelp = true, descriptionKey = "mixinStandardHelpOptions.version",
10081                description = "Print version information and exit.")
10082        private boolean versionRequested;
10083    }
10084
10085    /** Help command that can be installed as a subcommand on all application commands. When invoked with a subcommand
10086     * argument, it prints usage help for the specified subcommand. For example:<pre>
10087     *
10088     * // print help for subcommand
10089     * command help subcommand
10090     * </pre><p>
10091     * When invoked without additional parameters, it prints usage help for the parent command. For example:
10092     * </p><pre>
10093     *
10094     * // print help for command
10095     * command help
10096     * </pre>
10097     * For {@linkplain Messages internationalization}: this command has a {@code --help} option with {@code descriptionKey = "helpCommand.help"},
10098     * and a {@code COMMAND} positional parameter with {@code descriptionKey = "helpCommand.command"}.
10099     * @since 3.0
10100     */
10101    @Command(name = "help", header = "Displays help information about the specified command",
10102            synopsisHeading = "%nUsage: ", helpCommand = true,
10103            description = {"%nWhen no COMMAND is given, the usage help for the main command is displayed.",
10104                    "If a COMMAND is specified, the help for that command is shown.%n"})
10105    public static final class HelpCommand implements IHelpCommandInitializable, Runnable {
10106
10107        @Option(names = {"-h", "--help"}, usageHelp = true, descriptionKey = "helpCommand.help",
10108                description = "Show usage help for the help command and exit.")
10109        private boolean helpRequested;
10110
10111        @Parameters(paramLabel = "COMMAND", descriptionKey = "helpCommand.command",
10112                    description = "The COMMAND to display the usage help message for.")
10113        private String[] commands = new String[0];
10114
10115        private CommandLine self;
10116        private PrintStream out;
10117        private PrintStream err;
10118        private Help.Ansi ansi;
10119
10120        /** Invokes {@link #usage(PrintStream, Help.Ansi) usage} for the specified command, or for the parent command. */
10121        public void run() {
10122            CommandLine parent = self == null ? null : self.getParent();
10123            if (parent == null) { return; }
10124            if (commands.length > 0) {
10125                CommandLine subcommand = parent.getSubcommands().get(commands[0]);
10126                if (subcommand != null) {
10127                    subcommand.usage(out, ansi);
10128                } else {
10129                    throw new ParameterException(parent, "Unknown subcommand '" + commands[0] + "'.", null, commands[0]);
10130                }
10131            } else {
10132                parent.usage(out, ansi);
10133            }
10134        }
10135        /** {@inheritDoc} */
10136        public void init(CommandLine helpCommandLine, Help.Ansi ansi, PrintStream out, PrintStream err) {
10137            this.self = Assert.notNull(helpCommandLine, "helpCommandLine");
10138            this.ansi = Assert.notNull(ansi, "ansi");
10139            this.out  = Assert.notNull(out, "out");
10140            this.err  = Assert.notNull(err, "err");
10141        }
10142    }
10143
10144    /** Help commands that provide usage help for other commands can implement this interface to be initialized with the information they need.
10145     * <p>The {@link #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi) CommandLine::printHelpIfRequested} method calls the
10146     * {@link #init(CommandLine, picocli.CommandLine.Help.Ansi, PrintStream, PrintStream) init} method on commands marked as {@link Command#helpCommand() helpCommand}
10147     * before the help command's {@code run} or {@code call} method is called.</p>
10148     * <p><b>Implementation note:</b></p><p>
10149     * If an error occurs in the {@code run} or {@code call} method while processing the help request, it is recommended custom Help
10150     * commands throw a {@link ParameterException ParameterException} with a reference to the parent command. The {@link DefaultExceptionHandler DefaultExceptionHandler} will print
10151     * the error message and the usage for the parent command, and will terminate with the exit code of the exception handler if one was set.
10152     * </p>
10153     * @since 3.0 */
10154    public static interface IHelpCommandInitializable {
10155        /** Initializes this object with the information needed to implement a help command that provides usage help for other commands.
10156         * @param helpCommandLine the {@code CommandLine} object associated with this help command. Implementors can use
10157         *                        this to walk the command hierarchy and get access to the help command's parent and sibling commands.
10158         * @param ansi whether to use Ansi colors or not
10159         * @param out the stream to print the usage help message to
10160         * @param err the error stream to print any diagnostic messages to, in addition to the output from the exception handler
10161         */
10162        void init(CommandLine helpCommandLine, Help.Ansi ansi, PrintStream out, PrintStream err);
10163    }
10164
10165    /**
10166     * Renders a section of the usage help message. The usage help message can be customized:
10167     * use the {@link #setHelpSectionKeys(List)} and {@link #setHelpSectionMap(Map)} to change the order of sections,
10168     * delete standard sections, add custom sections or replace the renderer of a standard sections with a custom one.
10169     * <p>
10170     * This gives complete freedom on how a usage help message section is rendered, but it also means that the section renderer
10171     * is responsible for all aspects of rendering the section, including layout and emitting ANSI escape codes.
10172     * The {@link Help.TextTable} and {@link Help.Ansi.Text} classes, and the {@link CommandLine.Help.Ansi#string(String)} and {@link CommandLine.Help.Ansi#text(String)} methods may be useful.
10173     * </p>
10174     * @see UsageMessageSpec
10175     * @since 3.9
10176     */
10177    public interface IHelpSectionRenderer {
10178        /**
10179         * Renders a section of the usage help, like header heading, header, synopsis heading,
10180         * synopsis, description heading, description, etc.
10181         * @param help the {@code Help} instance for which to render a section
10182         * @return the text for this section; may contain {@linkplain Help.Ansi ANSI} escape codes
10183         * @since 3.9
10184         */
10185        String render(Help help);
10186    }
10187
10188    /**
10189     * A collection of methods and inner classes that provide fine-grained control over the contents and layout of
10190     * the usage help message to display to end users when help is requested or invalid input values were specified.
10191     * <h2>Class Diagram of the CommandLine.Help API</h2>
10192     * <p>
10193     * <img src="doc-files/class-diagram-help-api.png" alt="Class Diagram of the CommandLine.Help API">
10194     * </p>
10195     * <h2>Layered API</h2>
10196     * <p>The {@link Command} annotation and the {@link UsageMessageSpec} programmatic API equivalent
10197     * provide the easiest way to configure the usage help message. See
10198     * the <a href="https://remkop.github.io/picocli/index.html#_usage_help">Manual</a> for details.</p>
10199     * <p>This Help class provides high-level functions to create sections of the usage help message and headings
10200     * for these sections. Instead of calling the {@link CommandLine#usage(PrintStream, CommandLine.Help.ColorScheme)}
10201     * method, application authors may want to create a custom usage help message by reorganizing sections in a
10202     * different order and/or adding custom sections.</p>
10203     * <p>Finally, the Help class contains inner classes and interfaces that can be used to create custom help messages.</p>
10204     * <h3>IOptionRenderer and IParameterRenderer</h3>
10205     * <p>Renders a field annotated with {@link Option} or {@link Parameters} to an array of {@link Text} values.
10206     * By default, these values are</p><ul>
10207     * <li>mandatory marker character (if the option/parameter is {@link Option#required() required})</li>
10208     * <li>short option name (empty for parameters)</li>
10209     * <li>comma or empty (empty for parameters)</li>
10210     * <li>long option names (the parameter {@link IParamLabelRenderer label} for parameters)</li>
10211     * <li>description</li>
10212     * </ul>
10213     * <p>Other components rely on this ordering.</p>
10214     * <h3>Layout</h3>
10215     * <p>Delegates to the renderers to create {@link Text} values for the annotated fields, and uses a
10216     * {@link TextTable} to display these values in tabular format. Layout is responsible for deciding which values
10217     * to display where in the table. By default, Layout shows one option or parameter per table row.</p>
10218     * <h3>TextTable</h3>
10219     * <p>Responsible for spacing out {@link Text} values according to the {@link Column} definitions the table was
10220     * created with. Columns have a width, indentation, and an overflow policy that decides what to do if a value is
10221     * longer than the column's width.</p>
10222     * <h3>Text</h3>
10223     * <p>Encapsulates rich text with styles and colors in a way that other components like {@link TextTable} are
10224     * unaware of the embedded ANSI escape codes.</p>
10225     */
10226    public static class Help {
10227
10228        /** Constant String holding the default program name, value defined in {@link CommandSpec#DEFAULT_COMMAND_NAME}. */
10229        protected static final String DEFAULT_COMMAND_NAME = CommandSpec.DEFAULT_COMMAND_NAME;
10230
10231        /** Constant String holding the default string that separates options from option parameters, value defined in {@link ParserSpec#DEFAULT_SEPARATOR}. */
10232        protected static final String DEFAULT_SEPARATOR = ParserSpec.DEFAULT_SEPARATOR;
10233
10234        private final static int defaultOptionsColumnWidth = 24;
10235        private final CommandSpec commandSpec;
10236        private final ColorScheme colorScheme;
10237        private final Map<String, Help> commands = new LinkedHashMap<String, Help>();
10238        private List<String> aliases = Collections.emptyList();
10239
10240        private IParamLabelRenderer parameterLabelRenderer;
10241
10242        /** Constructs a new {@code Help} instance with a default color scheme, initialized from annotatations
10243         * on the specified class and superclasses.
10244         * @param command the annotated object to create usage help for */
10245        public Help(Object command) {
10246            this(command, Ansi.AUTO);
10247        }
10248
10249        /** Constructs a new {@code Help} instance with a default color scheme, initialized from annotatations
10250         * on the specified class and superclasses.
10251         * @param command the annotated object to create usage help for
10252         * @param ansi whether to emit ANSI escape codes or not */
10253        public Help(Object command, Ansi ansi) {
10254            this(command, defaultColorScheme(ansi));
10255        }
10256        /** Constructs a new {@code Help} instance with the specified color scheme, initialized from annotatations
10257         * on the specified class and superclasses.
10258         * @param command the annotated object to create usage help for
10259         * @param colorScheme the color scheme to use
10260         * @deprecated use {@link picocli.CommandLine.Help#Help(picocli.CommandLine.Model.CommandSpec, picocli.CommandLine.Help.ColorScheme)}  */
10261        @Deprecated public Help(Object command, ColorScheme colorScheme) {
10262            this(CommandSpec.forAnnotatedObject(command, new DefaultFactory()), colorScheme);
10263        }
10264        /** Constructs a new {@code Help} instance with the specified color scheme, initialized from annotatations
10265         * on the specified class and superclasses.
10266         * @param commandSpec the command model to create usage help for
10267         * @param colorScheme the color scheme to use */
10268        public Help(CommandSpec commandSpec, ColorScheme colorScheme) {
10269            this.commandSpec = Assert.notNull(commandSpec, "commandSpec");
10270            this.aliases = new ArrayList<String>(Arrays.asList(commandSpec.aliases()));
10271            this.aliases.add(0, commandSpec.name());
10272            this.colorScheme = Assert.notNull(colorScheme, "colorScheme").applySystemProperties();
10273            parameterLabelRenderer = createDefaultParamLabelRenderer(); // uses help separator
10274
10275            this.addAllSubcommands(commandSpec.subcommands());
10276        }
10277
10278        Help withCommandNames(List<String> aliases) { this.aliases = aliases; return this; }
10279
10280        /** Returns the {@code CommandSpec} model that this Help was constructed with.
10281         * @since 3.9 */
10282        public CommandSpec commandSpec() { return commandSpec; }
10283
10284        /** Returns the {@code ColorScheme} model that this Help was constructed with.
10285         * @since 3.0 */
10286        public ColorScheme colorScheme() { return colorScheme; }
10287
10288        /** Returns the {@code IHelpFactory} that this Help was constructed with.
10289         * @since 3.9 */
10290        private IHelpFactory getHelpFactory() { return commandSpec.usageMessage().helpFactory(); }
10291
10292        /** Returns the map of subcommand {@code Help} instances for this command Help.
10293         * @since 3.9 */
10294        protected Map<String, Help> subcommands() { return Collections.unmodifiableMap(commands); }
10295
10296        /** Returns the list of aliases for the command in this Help.
10297         * @since 3.9 */
10298        protected List<String> aliases() { return Collections.unmodifiableList(aliases); }
10299
10300        /** Option and positional parameter value label renderer used for the synopsis line(s) and the option list.
10301         * By default initialized to the result of {@link #createDefaultParamLabelRenderer()}, which takes a snapshot
10302         * of the {@link ParserSpec#separator()} at construction time. If the separator is modified after Help construction, you
10303         * may need to re-initialize this field by calling {@link #createDefaultParamLabelRenderer()} again. */
10304        public IParamLabelRenderer parameterLabelRenderer() {return parameterLabelRenderer;}
10305
10306        /** Registers all specified subcommands with this Help.
10307         * @param commands maps the command names to the associated CommandLine object
10308         * @return this Help instance (for method chaining)
10309         * @see CommandLine#getSubcommands()
10310         */
10311        public Help addAllSubcommands(Map<String, CommandLine> commands) {
10312            if (commands != null) {
10313                // first collect aliases
10314                Map<CommandLine, List<String>> done = new IdentityHashMap<CommandLine, List<String>>();
10315                for (CommandLine cmd : commands.values()) {
10316                    if (!done.containsKey(cmd)) {
10317                        done.put(cmd, new ArrayList<String>(Arrays.asList(cmd.commandSpec.aliases())));
10318                    }
10319                }
10320                // then loop over all names that the command was registered with and add this name to the front of the list (if it isn't already in the list)
10321                for (Map.Entry<String, CommandLine> entry : commands.entrySet()) {
10322                    List<String> aliases = done.get(entry.getValue());
10323                    if (!aliases.contains(entry.getKey())) { aliases.add(0, entry.getKey()); }
10324                }
10325                // The aliases list for each command now has at least one entry, with the main name at the front.
10326                // Now we loop over the commands in the order that they were registered on their parent command.
10327                for (Map.Entry<String, CommandLine> entry : commands.entrySet()) {
10328                    // not registering hidden commands is easier than suppressing display in Help.commandList():
10329                    // if all subcommands are hidden, help should not show command list header
10330                    if (!entry.getValue().getCommandSpec().usageMessage().hidden()) {
10331                        List<String> aliases = done.remove(entry.getValue());
10332                        if (aliases != null) { // otherwise we already processed this command by another alias
10333                            addSubcommand(aliases, entry.getValue());
10334                        }
10335                    }
10336                }
10337            }
10338            return this;
10339        }
10340
10341        /** Registers the specified subcommand with this Help.
10342         * @param commandNames the name and aliases of the subcommand to display in the usage message
10343         * @param commandLine the {@code CommandLine} object to get more information from
10344         * @return this Help instance (for method chaining) */
10345        Help addSubcommand(List<String> commandNames, CommandLine commandLine) {
10346            String all = commandNames.toString();
10347            commands.put(all.substring(1, all.length() - 1), getHelpFactory().create(commandLine.commandSpec, colorScheme).withCommandNames(commandNames));
10348            return this;
10349        }
10350
10351        /** Registers the specified subcommand with this Help.
10352         * @param commandName the name of the subcommand to display in the usage message
10353         * @param command the {@code CommandSpec} or {@code @Command} annotated object to get more information from
10354         * @return this Help instance (for method chaining)
10355         * @deprecated
10356         */
10357        @Deprecated public Help addSubcommand(String commandName, Object command) {
10358            commands.put(commandName,
10359                    getHelpFactory().create(CommandSpec.forAnnotatedObject(command, commandSpec.commandLine().factory), defaultColorScheme(Ansi.AUTO)));
10360            return this;
10361        }
10362
10363        List<OptionSpec> options() { return commandSpec.options(); }
10364        List<PositionalParamSpec> positionalParameters() { return commandSpec.positionalParameters(); }
10365        String commandName() { return commandSpec.name(); }
10366
10367        /** Returns a synopsis for the command without reserving space for the synopsis heading.
10368         * @return a synopsis
10369         * @see #abbreviatedSynopsis()
10370         * @see #detailedSynopsis(Comparator, boolean)
10371         * @deprecated use {@link #synopsis(int)} instead
10372         */
10373        @Deprecated public String synopsis() { return synopsis(0); }
10374
10375        /**
10376         * Returns a synopsis for the command, reserving the specified space for the synopsis heading.
10377         * @param synopsisHeadingLength the length of the synopsis heading that will be displayed on the same line
10378         * @return a synopsis
10379         * @see #abbreviatedSynopsis()
10380         * @see #detailedSynopsis(Comparator, boolean)
10381         * @see #synopsisHeading
10382         */
10383        public String synopsis(int synopsisHeadingLength) {
10384            if (!empty(commandSpec.usageMessage().customSynopsis())) { return customSynopsis(); }
10385            return commandSpec.usageMessage().abbreviateSynopsis() ? abbreviatedSynopsis()
10386                    : detailedSynopsis(synopsisHeadingLength, createShortOptionArityAndNameComparator(), true);
10387        }
10388
10389        /** Generates a generic synopsis like {@code <command name> [OPTIONS] [PARAM1 [PARAM2]...]}, omitting parts
10390         * that don't apply to the command (e.g., does not show [OPTIONS] if the command has no options).
10391         * @return a generic synopsis */
10392        public String abbreviatedSynopsis() {
10393            StringBuilder sb = new StringBuilder();
10394            if (!commandSpec.optionsMap().isEmpty()) { // only show if annotated object actually has options
10395                sb.append(" [OPTIONS]");
10396            }
10397            // sb.append(" [--] "); // implied
10398            for (PositionalParamSpec positionalParam : commandSpec.positionalParameters()) {
10399                if (!positionalParam.hidden()) {
10400                    sb.append(' ').append(parameterLabelRenderer().renderParameterLabel(positionalParam, ansi(), colorScheme.parameterStyles));
10401                }
10402            }
10403
10404            // only show if object has subcommands
10405            if (!commandSpec.subcommands().isEmpty()) {
10406                sb.append(" [COMMAND]");
10407            }
10408
10409            return colorScheme.commandText(commandSpec.qualifiedName()).toString()
10410                    + (sb.toString()) + System.getProperty("line.separator");
10411        }
10412        /** Generates a detailed synopsis message showing all options and parameters. Follows the unix convention of
10413         * showing optional options and parameters in square brackets ({@code [ ]}).
10414         * @param optionSort comparator to sort options or {@code null} if options should not be sorted
10415         * @param clusterBooleanOptions {@code true} if boolean short options should be clustered into a single string
10416         * @return a detailed synopsis
10417         * @deprecated use {@link #detailedSynopsis(int, Comparator, boolean)} instead. */
10418        @Deprecated public String detailedSynopsis(Comparator<OptionSpec> optionSort, boolean clusterBooleanOptions) {
10419            return detailedSynopsis(0, optionSort, clusterBooleanOptions);
10420        }
10421
10422        /** Generates a detailed synopsis message showing all options and parameters. Follows the unix convention of
10423         * showing optional options and parameters in square brackets ({@code [ ]}).
10424         * @param synopsisHeadingLength the length of the synopsis heading that will be displayed on the same line
10425         * @param optionSort comparator to sort options or {@code null} if options should not be sorted
10426         * @param clusterBooleanOptions {@code true} if boolean short options should be clustered into a single string
10427         * @return a detailed synopsis
10428         * @since 3.0 */
10429        public String detailedSynopsis(int synopsisHeadingLength, Comparator<OptionSpec> optionSort, boolean clusterBooleanOptions) {
10430            Set<ArgSpec> argsInGroups = new HashSet<ArgSpec>();
10431            Text groupsText = createDetailedSynopsisGroupsText(argsInGroups);
10432            Text optionText = createDetailedSynopsisOptionsText(argsInGroups, optionSort, clusterBooleanOptions);
10433            Text positionalParamText = createDetailedSynopsisPositionalsText(argsInGroups);
10434            Text commandText = createDetailedSynopsisCommandText();
10435
10436            Text text = groupsText.concat(optionText).concat(positionalParamText).concat(commandText);
10437
10438            return insertSynopsisCommandName(synopsisHeadingLength, text);
10439        }
10440
10441        /** Returns a Text object containing a partial detailed synopsis showing only the options and positional parameters in
10442         * the specified {@linkplain ArgGroup#validate() validating} {@linkplain ArgGroup groups}, starting with a {@code " "} space.
10443         * @param outparam_groupArgs all options and positional parameters in the groups this method generates a synopsis for;
10444         *                           these options and positional parameters should be excluded from appearing elsewhere in the synopsis
10445         * @return the formatted groups synopsis elements, starting with a {@code " "} space, or an empty Text if this command has no validating groups
10446         * @since 4.0 */
10447        protected Text createDetailedSynopsisGroupsText(Set<ArgSpec> outparam_groupArgs) {
10448            Set<ArgGroupSpec> remove = new HashSet<ArgGroupSpec>();
10449            List<ArgGroupSpec> groups = new ArrayList<ArgGroupSpec>(commandSpec().argGroups());
10450            for (ArgGroupSpec group : groups) {
10451                if (group.validate()) {
10452                    // remove subgroups
10453                    remove.addAll(group.subgroups());
10454
10455                    // exclude options and positional parameters in this group
10456                    outparam_groupArgs.addAll(group.args());
10457
10458                    // exclude options and positional parameters in the subgroups
10459                    for (ArgGroupSpec subgroup : group.subgroups()) {
10460                        outparam_groupArgs.addAll(subgroup.args());
10461                    }
10462                } else {
10463                    remove.add(group); // non-validating groups should not impact synopsis
10464                }
10465            }
10466            groups.removeAll(remove);
10467            Text groupText = ansi().new Text(0);
10468            for (ArgGroupSpec group : groups) {
10469                groupText = groupText.concat(" ").concat(group.synopsisText(colorScheme()));
10470            }
10471            return groupText;
10472        }
10473        /** Returns a Text object containing a partial detailed synopsis showing only the options, starting with a {@code " "} space.
10474         * Follows the unix convention of showing optional options and parameters in square brackets ({@code [ ]}).
10475         * @param done the list of options and positional parameters for which a synopsis was already generated. Options in this set should be excluded.
10476         * @param optionSort comparator to sort options or {@code null} if options should not be sorted
10477         * @param clusterBooleanOptions {@code true} if boolean short options should be clustered into a single string
10478         * @return the formatted options, starting with a {@code " "} space, or an empty Text if this command has no named options
10479         * @since 3.9 */
10480        protected Text createDetailedSynopsisOptionsText(Collection<ArgSpec> done, Comparator<OptionSpec> optionSort, boolean clusterBooleanOptions) {
10481            Text optionText = ansi().new Text(0);
10482            List<OptionSpec> options = new ArrayList<OptionSpec>(commandSpec.options()); // iterate in declaration order
10483            if (optionSort != null) {
10484                Collections.sort(options, optionSort);// iterate in specified sort order
10485            }
10486            options.removeAll(done);
10487            if (clusterBooleanOptions) { // cluster all short boolean options into a single string
10488                List<OptionSpec> booleanOptions = new ArrayList<OptionSpec>();
10489                StringBuilder clusteredRequired = new StringBuilder("-");
10490                StringBuilder clusteredOptional = new StringBuilder("-");
10491                for (OptionSpec option : options) {
10492                    if (option.hidden()) { continue; }
10493                    boolean isFlagOption = option.typeInfo().isBoolean();
10494                    if (isFlagOption && option.arity().max <= 0) { // #612 consider arity: boolean options may require a parameter
10495                        String shortestName = option.shortestName();
10496                        if (shortestName.length() == 2 && shortestName.startsWith("-")) {
10497                            booleanOptions.add(option);
10498                            if (option.required()) {
10499                                clusteredRequired.append(shortestName.substring(1));
10500                            } else {
10501                                clusteredOptional.append(shortestName.substring(1));
10502                            }
10503                        }
10504                    }
10505                }
10506                options.removeAll(booleanOptions);
10507                if (clusteredRequired.length() > 1) { // initial length was 1
10508                    optionText = optionText.concat(" ").concat(colorScheme.optionText(clusteredRequired.toString()));
10509                }
10510                if (clusteredOptional.length() > 1) { // initial length was 1
10511                    optionText = optionText.concat(" [").concat(colorScheme.optionText(clusteredOptional.toString())).concat("]");
10512                }
10513            }
10514            for (OptionSpec option : options) {
10515                if (!option.hidden()) {
10516                    Text name = colorScheme.optionText(option.shortestName());
10517                    Text param = parameterLabelRenderer().renderParameterLabel(option, colorScheme.ansi(), colorScheme.optionParamStyles);
10518                    if (option.required()) { // e.g., -x=VAL
10519                        optionText = optionText.concat(" ").concat(name).concat(param).concat("");
10520                        if (option.isMultiValue()) { // e.g., -x=VAL [-x=VAL]...
10521                            optionText = optionText.concat(" [").concat(name).concat(param).concat("]...");
10522                        }
10523                    } else {
10524                        optionText = optionText.concat(" [").concat(name).concat(param).concat("]");
10525                        if (option.isMultiValue()) { // add ellipsis to show option is repeatable
10526                            optionText = optionText.concat("...");
10527                        }
10528                    }
10529                }
10530            }
10531            return optionText;
10532        }
10533
10534        /** Returns a Text object containing a partial detailed synopsis showing only the positional parameters, starting with a {@code " "} space.
10535         * Follows the unix convention of showing optional options and parameters in square brackets ({@code [ ]}).
10536         * @param done the list of options and positional parameters for which a synopsis was already generated. Positional parameters in this set should be excluded.
10537         * @return the formatted positional parameters, starting with a {@code " "} space, or an empty Text if this command has no positional parameters
10538         * @since 3.9 */
10539        protected Text createDetailedSynopsisPositionalsText(Collection<ArgSpec> done) {
10540            Text positionalParamText = ansi().new Text(0);
10541            List<PositionalParamSpec> positionals = new ArrayList<PositionalParamSpec>(commandSpec.positionalParameters()); // iterate in declaration order
10542            positionals.removeAll(done);
10543            for (PositionalParamSpec positionalParam : positionals) {
10544                if (!positionalParam.hidden()) {
10545                    positionalParamText = positionalParamText.concat(" ");
10546                    Text label = parameterLabelRenderer().renderParameterLabel(positionalParam, colorScheme.ansi(), colorScheme.parameterStyles);
10547                    positionalParamText = positionalParamText.concat(label);
10548                }
10549            }
10550            return positionalParamText;
10551        }
10552
10553        /** Returns a Text object containing a partial detailed synopsis showing only the subcommands, starting with a {@code " "} space.
10554         * Follows the unix convention of showing optional elements in square brackets ({@code [ ]}).
10555         * @return this implementation returns a hard-coded string {@code " [COMMAND]"} if this command has subcommands, an empty Text otherwise
10556         * @since 3.9 */
10557        protected Text createDetailedSynopsisCommandText() {
10558            Text commandText = ansi().new Text(0);
10559            if (!commandSpec.subcommands().isEmpty()){
10560                commandText = commandText.concat(" [")
10561                        .concat("COMMAND")
10562                        .concat("]");
10563            }
10564            return commandText;
10565        }
10566
10567        /**
10568         * Returns the detailed synopsis text by inserting the command name before the specified text with options and positional parameters details.
10569         * @param synopsisHeadingLength length of the synopsis heading string to be displayed on the same line as the first synopsis line.
10570         *                              For example, if the synopsis heading is {@code "Usage: "}, this value is 7.
10571         * @param optionsAndPositionalsAndCommandsDetails formatted string with options, positional parameters and subcommands.
10572         *          Follows the unix convention of showing optional options and parameters in square brackets ({@code [ ]}).
10573         * @return the detailed synopsis text, in multiple lines if the length exceeds the usage width
10574         */
10575        protected String insertSynopsisCommandName(int synopsisHeadingLength, Text optionsAndPositionalsAndCommandsDetails) {
10576            // Fix for #142: first line of synopsis overshoots max. characters
10577            String commandName = commandSpec.qualifiedName();
10578            int firstColumnLength = commandName.length() + synopsisHeadingLength;
10579
10580            // synopsis heading ("Usage: ") may be on the same line, so adjust column width
10581            TextTable textTable = TextTable.forColumnWidths(ansi(), firstColumnLength, width() - firstColumnLength);
10582            textTable.indentWrappedLines = 1; // don't worry about first line: options (2nd column) always start with a space
10583
10584            // right-adjust the command name by length of synopsis heading
10585            Text PADDING = Ansi.OFF.new Text(stringOf('X', synopsisHeadingLength));
10586            textTable.addRowValues(PADDING.concat(colorScheme.commandText(commandName)), optionsAndPositionalsAndCommandsDetails);
10587            return textTable.toString().substring(synopsisHeadingLength); // cut off leading synopsis heading spaces
10588        }
10589
10590        /** Returns the number of characters the synopsis heading will take on the same line as the synopsis.
10591         * @return the number of characters the synopsis heading will take on the same line as the synopsis.
10592         * @see #detailedSynopsis(int, Comparator, boolean)
10593         */
10594        public int synopsisHeadingLength() {
10595            String[] lines = Ansi.OFF.new Text(commandSpec.usageMessage().synopsisHeading()).toString().split("\\r?\\n|\\r|%n", -1);
10596            return lines[lines.length - 1].length();
10597        }
10598        /**
10599         * <p>Returns a description of the {@linkplain Option options} supported by the application.
10600         * This implementation {@linkplain #createShortOptionNameComparator() sorts options alphabetically}, and shows
10601         * only the {@linkplain Option#hidden() non-hidden} options in a {@linkplain TextTable tabular format}
10602         * using the {@linkplain #createDefaultOptionRenderer() default renderer} and {@linkplain Layout default layout}.</p>
10603         * @return the fully formatted option list
10604         * @see #optionList(Layout, Comparator, IParamLabelRenderer)
10605         */
10606        public String optionList() {
10607            Comparator<OptionSpec> sortOrder = commandSpec.usageMessage().sortOptions()
10608                    ? createShortOptionNameComparator()
10609                    : createOrderComparatorIfNecessary(commandSpec.options());
10610
10611            return optionList(createLayout(calcLongOptionColumnWidth()), sortOrder, parameterLabelRenderer());
10612        }
10613
10614        private static Comparator<OptionSpec> createOrderComparatorIfNecessary(List<OptionSpec> options) {
10615            for (OptionSpec option : options) { if (option.order() != OptionSpec.DEFAULT_ORDER) { return createOrderComparator(); } }
10616            return null;
10617        }
10618
10619        private int calcLongOptionColumnWidth() {
10620            int max = 0;
10621            IOptionRenderer optionRenderer = new DefaultOptionRenderer(false, " ");
10622            for (OptionSpec option : commandSpec.options()) {
10623                Text[][] values = optionRenderer.render(option, parameterLabelRenderer(), colorScheme);
10624                int len = values[0][3].length;
10625                if (len < Help.defaultOptionsColumnWidth - 3) { max = Math.max(max, len); }
10626            }
10627            IParameterRenderer paramRenderer = new DefaultParameterRenderer(false, " ");
10628            for (PositionalParamSpec positional : commandSpec.positionalParameters()) {
10629                Text[][] values = paramRenderer.render(positional, parameterLabelRenderer(), colorScheme);
10630                int len = values[0][3].length;
10631                if (len < Help.defaultOptionsColumnWidth - 3) { max = Math.max(max, len); }
10632            }
10633            return max + 3;
10634        }
10635
10636        /** Sorts all {@code Options} with the specified {@code comparator} (if the comparator is non-{@code null}),
10637         * then {@linkplain Layout#addOption(CommandLine.Model.OptionSpec, CommandLine.Help.IParamLabelRenderer) adds} all non-hidden options to the
10638         * specified TextTable and returns the result of TextTable.toString().
10639         * @param layout responsible for rendering the option list
10640         * @param valueLabelRenderer used for options with a parameter
10641         * @return the fully formatted option list
10642         * @since 3.0 */
10643        public String optionList(Layout layout, Comparator<OptionSpec> optionSort, IParamLabelRenderer valueLabelRenderer) {
10644            List<OptionSpec> options = new ArrayList<OptionSpec>(commandSpec.options()); // options are stored in order of declaration
10645            if (optionSort != null) {
10646                Collections.sort(options, optionSort); // default: sort options ABC
10647            }
10648            List<ArgGroupSpec> groups = optionListGroups();
10649            for (ArgGroupSpec group : groups) { options.removeAll(group.options()); }
10650
10651            StringBuilder sb = new StringBuilder();
10652            layout.addOptions(options, valueLabelRenderer);
10653            sb.append(layout.toString());
10654
10655            int longOptionColumnWidth = calcLongOptionColumnWidth();
10656            Collections.sort(groups, new SortByOrder<ArgGroupSpec>());
10657            for (ArgGroupSpec group : groups) {
10658                sb.append(heading(ansi(), width(), group.heading()));
10659
10660                Layout groupLayout = createLayout(longOptionColumnWidth);
10661                groupLayout.addPositionalParameters(group.positionalParameters(), valueLabelRenderer);
10662                List<OptionSpec> groupOptions = new ArrayList<OptionSpec>(group.options());
10663                if (optionSort != null) {
10664                    Collections.sort(groupOptions, optionSort);
10665                }
10666                groupLayout.addOptions(groupOptions, valueLabelRenderer);
10667                sb.append(groupLayout);
10668            }
10669            return sb.toString();
10670        }
10671
10672        /** Returns the list of {@code ArgGroupSpec}s with a non-{@code null} heading. */
10673        private List<ArgGroupSpec> optionListGroups() {
10674            List<ArgGroupSpec> result = new ArrayList<ArgGroupSpec>();
10675            optionListGroups(commandSpec.argGroups(), result);
10676            return result;
10677        }
10678        private static void optionListGroups(List<ArgGroupSpec> groups, List<ArgGroupSpec> result) {
10679            for (ArgGroupSpec group : groups) {
10680                optionListGroups(group.subgroups(), result);
10681                if (group.heading() != null) { result.add(group); }
10682            }
10683        }
10684
10685        /**
10686         * Returns the section of the usage help message that lists the parameters with their descriptions.
10687         * @return the section of the usage help message that lists the parameters
10688         */
10689        public String parameterList() {
10690            return parameterList(createLayout(calcLongOptionColumnWidth()), parameterLabelRenderer());
10691        }
10692        /**
10693         * Returns the section of the usage help message that lists the parameters with their descriptions.
10694         * @param layout the layout to use
10695         * @param paramLabelRenderer for rendering parameter names
10696         * @return the section of the usage help message that lists the parameters
10697         */
10698        public String parameterList(Layout layout, IParamLabelRenderer paramLabelRenderer) {
10699            List<PositionalParamSpec> positionals = new ArrayList<PositionalParamSpec>(commandSpec.positionalParameters());
10700            List<ArgGroupSpec> groups = optionListGroups();
10701            for (ArgGroupSpec group : groups) { positionals.removeAll(group.positionalParameters()); }
10702
10703            layout.addPositionalParameters(positionals, paramLabelRenderer);
10704            return layout.toString();
10705        }
10706
10707        private static String heading(Ansi ansi, int usageWidth, String values, Object... params) {
10708            StringBuilder sb = join(ansi, usageWidth, new String[] {values}, new StringBuilder(), params);
10709            return trimLineSeparator(sb.toString()) + new String(spaces(countTrailingSpaces(values)));
10710        }
10711        static String trimLineSeparator(String result) {
10712            return result.endsWith(System.getProperty("line.separator"))
10713                    ? result.substring(0, result.length() - System.getProperty("line.separator").length()) : result;
10714        }
10715
10716        private static char[] spaces(int length) { char[] result = new char[length]; Arrays.fill(result, ' '); return result; }
10717        private static int countTrailingSpaces(String str) {
10718            if (str == null) {return 0;}
10719            int trailingSpaces = 0;
10720            for (int i = str.length() - 1; i >= 0 && str.charAt(i) == ' '; i--) { trailingSpaces++; }
10721            return trailingSpaces;
10722        }
10723
10724        /** Formats each of the specified values and appends it to the specified StringBuilder.
10725         * @param ansi whether the result should contain ANSI escape codes or not
10726         * @param usageHelpWidth the width of the usage help message
10727         * @param values the values to format and append to the StringBuilder
10728         * @param sb the StringBuilder to collect the formatted strings
10729         * @param params the parameters to pass to the format method when formatting each value
10730         * @return the specified StringBuilder */
10731        public static StringBuilder join(Ansi ansi, int usageHelpWidth, String[] values, StringBuilder sb, Object... params) {
10732            if (values != null) {
10733                TextTable table = TextTable.forColumnWidths(ansi, usageHelpWidth);
10734                table.indentWrappedLines = 0;
10735                for (String summaryLine : values) {
10736                    Text[] lines = ansi.new Text(format(summaryLine, params)).splitLines();
10737                    for (Text line : lines) {  table.addRowValues(line); }
10738                }
10739                table.toString(sb);
10740            }
10741            return sb;
10742        }
10743        private int width() { return commandSpec.usageMessage().width(); }
10744        /** Returns command custom synopsis as a string. A custom synopsis can be zero or more lines, and can be
10745         * specified declaratively with the {@link Command#customSynopsis()} annotation attribute or programmatically
10746         * by setting the Help instance's {@link Help#customSynopsis} field.
10747         * @param params Arguments referenced by the format specifiers in the synopsis strings
10748         * @return the custom synopsis lines combined into a single String (which may be empty)
10749         */
10750        public String customSynopsis(Object... params) {
10751            return join(ansi(), width(), commandSpec.usageMessage().customSynopsis(), new StringBuilder(), params).toString();
10752        }
10753        /** Returns command description text as a string. Description text can be zero or more lines, and can be specified
10754         * declaratively with the {@link Command#description()} annotation attribute or programmatically by
10755         * setting the Help instance's {@link Help#description} field.
10756         * @param params Arguments referenced by the format specifiers in the description strings
10757         * @return the description lines combined into a single String (which may be empty)
10758         */
10759        public String description(Object... params) {
10760            return join(ansi(), width(), commandSpec.usageMessage().description(), new StringBuilder(), params).toString();
10761        }
10762        /** Returns the command header text as a string. Header text can be zero or more lines, and can be specified
10763         * declaratively with the {@link Command#header()} annotation attribute or programmatically by
10764         * setting the Help instance's {@link Help#header} field.
10765         * @param params Arguments referenced by the format specifiers in the header strings
10766         * @return the header lines combined into a single String (which may be empty)
10767         */
10768        public String header(Object... params) {
10769            return join(ansi(), width(), commandSpec.usageMessage().header(), new StringBuilder(), params).toString();
10770        }
10771        /** Returns command footer text as a string. Footer text can be zero or more lines, and can be specified
10772         * declaratively with the {@link Command#footer()} annotation attribute or programmatically by
10773         * setting the Help instance's {@link Help#footer} field.
10774         * @param params Arguments referenced by the format specifiers in the footer strings
10775         * @return the footer lines combined into a single String (which may be empty)
10776         */
10777        public String footer(Object... params) {
10778            return join(ansi(), width(), commandSpec.usageMessage().footer(), new StringBuilder(), params).toString();
10779        }
10780
10781        /** Returns the text displayed before the header text; the result of {@code String.format(headerHeading, params)}.
10782         * @param params the parameters to use to format the header heading
10783         * @return the formatted header heading */
10784        public String headerHeading(Object... params) {
10785            return heading(ansi(), width(), commandSpec.usageMessage().headerHeading(), params);
10786        }
10787
10788        /** Returns the text displayed before the synopsis text; the result of {@code String.format(synopsisHeading, params)}.
10789         * @param params the parameters to use to format the synopsis heading
10790         * @return the formatted synopsis heading */
10791        public String synopsisHeading(Object... params) {
10792            return heading(ansi(), width(), commandSpec.usageMessage().synopsisHeading(), params);
10793        }
10794
10795        /** Returns the text displayed before the description text; an empty string if there is no description,
10796         * otherwise the result of {@code String.format(descriptionHeading, params)}.
10797         * @param params the parameters to use to format the description heading
10798         * @return the formatted description heading */
10799        public String descriptionHeading(Object... params) {
10800            return empty(commandSpec.usageMessage().descriptionHeading()) ? "" : heading(ansi(), width(), commandSpec.usageMessage().descriptionHeading(), params);
10801        }
10802
10803        /** Returns the text displayed before the positional parameter list; an empty string if there are no positional
10804         * parameters, otherwise the result of {@code String.format(parameterListHeading, params)}.
10805         * @param params the parameters to use to format the parameter list heading
10806         * @return the formatted parameter list heading */
10807        public String parameterListHeading(Object... params) {
10808            return commandSpec.positionalParameters().isEmpty() ? "" : heading(ansi(), width(), commandSpec.usageMessage().parameterListHeading(), params);
10809        }
10810
10811        /** Returns the text displayed before the option list; an empty string if there are no options,
10812         * otherwise the result of {@code String.format(optionListHeading, params)}.
10813         * @param params the parameters to use to format the option list heading
10814         * @return the formatted option list heading */
10815        public String optionListHeading(Object... params) {
10816            return commandSpec.optionsMap().isEmpty() ? "" : heading(ansi(), width(), commandSpec.usageMessage().optionListHeading(), params);
10817        }
10818
10819        /** Returns the text displayed before the command list; an empty string if there are no commands,
10820         * otherwise the result of {@code String.format(commandListHeading, params)}.
10821         * @param params the parameters to use to format the command list heading
10822         * @return the formatted command list heading */
10823        public String commandListHeading(Object... params) {
10824            return commands.isEmpty() ? "" : heading(ansi(), width(), commandSpec.usageMessage().commandListHeading(), params);
10825        }
10826
10827        /** Returns the text displayed before the footer text; the result of {@code String.format(footerHeading, params)}.
10828         * @param params the parameters to use to format the footer heading
10829         * @return the formatted footer heading */
10830        public String footerHeading(Object... params) {
10831            return heading(ansi(), width(), commandSpec.usageMessage().footerHeading(), params);
10832        }
10833        /** Returns a 2-column list with command names and the first line of their header or (if absent) description.
10834         * @return a usage help section describing the added commands */
10835        public String commandList() {
10836            if (subcommands().isEmpty()) { return ""; }
10837            int commandLength = maxLength(subcommands().keySet());
10838            Help.TextTable textTable = Help.TextTable.forColumns(ansi(),
10839                    new Help.Column(commandLength + 2, 2, Help.Column.Overflow.SPAN),
10840                    new Help.Column(width() - (commandLength + 2), 2, Help.Column.Overflow.WRAP));
10841
10842            for (Map.Entry<String, Help> entry : subcommands().entrySet()) {
10843                Help help = entry.getValue();
10844                UsageMessageSpec usage = help.commandSpec().usageMessage();
10845                String header = !empty(usage.header())
10846                        ? usage.header()[0]
10847                        : (!empty(usage.description()) ? usage.description()[0] : "");
10848                Text[] lines = ansi().text(format(header)).splitLines();
10849                for (int i = 0; i < lines.length; i++) {
10850                    textTable.addRowValues(i == 0 ? help.commandNamesText(", ") : Ansi.EMPTY_TEXT, lines[i]);
10851                }
10852            }
10853            return textTable.toString();
10854        }
10855        private static int maxLength(Collection<String> any) {
10856            List<String> strings = new ArrayList<String>(any);
10857            Collections.sort(strings, Collections.reverseOrder(Help.shortestFirst()));
10858            return strings.get(0).length();
10859        }
10860
10861        /** Returns a {@code Text} object containing the command name and all aliases, separated with the specified separator.
10862         * Command names will use the {@link ColorScheme#commandText(String) command style} for the color scheme of this Help.
10863         * @since 3.9 */
10864        public Text commandNamesText(String separator) {
10865            Text result = colorScheme().commandText(aliases().get(0));
10866            for (int i = 1; i < aliases().size(); i++) {
10867                result = result.concat(separator).concat(colorScheme().commandText(aliases().get(i)));
10868            }
10869            return result;
10870        }
10871        private static String join(String[] names, int offset, int length, String separator) {
10872            if (names == null) { return ""; }
10873            StringBuilder result = new StringBuilder();
10874            for (int i = offset; i < offset + length; i++) {
10875                result.append((i > offset) ? separator : "").append(names[i]);
10876            }
10877            return result.toString();
10878        }
10879        private static String stringOf(char chr, int length) {
10880                             char[] buff = new char[length];
10881            Arrays.fill(buff, chr);
10882            return new String(buff);
10883        }
10884
10885        /** Returns a {@code Layout} instance configured with the user preferences captured in this Help instance.
10886         * @return a Layout */
10887        public Layout createDefaultLayout() {
10888            return createLayout(Help.defaultOptionsColumnWidth);
10889        }
10890
10891        private Layout createLayout(int longOptionsColumnWidth) {
10892            return new Layout(colorScheme, TextTable.forDefaultColumns(colorScheme.ansi(), longOptionsColumnWidth, width()), createDefaultOptionRenderer(), createDefaultParameterRenderer());
10893        }
10894
10895        /** Returns a new default OptionRenderer which converts {@link OptionSpec Options} to five columns of text to match
10896         *  the default {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
10897         * <ol>
10898         * <li>the required option marker</li>
10899         * <li>2-character short option name (or empty string if no short option exists)</li>
10900         * <li>comma separator (only if both short option and long option exist, empty string otherwise)</li>
10901         * <li>comma-separated string with long option name(s)</li>
10902         * <li>first element of the {@link OptionSpec#description()} array</li>
10903         * </ol>
10904         * <p>Following this, there will be one row for each of the remaining elements of the {@link
10905         *   OptionSpec#description()} array, and these rows look like {@code {"", "", "", "", option.description()[i]}}.</p>
10906         * <p>If configured, this option renderer adds an additional row to display the default field value.</p>
10907         * @return a new default OptionRenderer
10908         */
10909        public IOptionRenderer createDefaultOptionRenderer() {
10910            return new DefaultOptionRenderer(commandSpec.usageMessage.showDefaultValues(), "" +commandSpec.usageMessage().requiredOptionMarker());
10911        }
10912        /** Returns a new minimal OptionRenderer which converts {@link OptionSpec Options} to a single row with two columns
10913         * of text: an option name and a description. If multiple names or descriptions exist, the first value is used.
10914         * @return a new minimal OptionRenderer */
10915        public static IOptionRenderer createMinimalOptionRenderer() {
10916            return new MinimalOptionRenderer();
10917        }
10918
10919        /** Returns a new default ParameterRenderer which converts {@linkplain PositionalParamSpec positional parameters} to four columns of
10920         * text to match the default {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
10921         * <ol>
10922         * <li>empty string </li>
10923         * <li>empty string </li>
10924         * <li>parameter(s) label as rendered by the {@link IParamLabelRenderer}</li>
10925         * <li>first element of the {@link PositionalParamSpec#description()} array</li>
10926         * </ol>
10927         * <p>Following this, there will be one row for each of the remaining elements of the {@link
10928         *   PositionalParamSpec#description()} array, and these rows look like {@code {"", "", "", param.description()[i]}}.</p>
10929         * <p>If configured, this parameter renderer adds an additional row to display the default field value.</p>
10930         * @return a new default ParameterRenderer
10931         */
10932        public IParameterRenderer createDefaultParameterRenderer() {
10933            return new DefaultParameterRenderer(commandSpec.usageMessage.showDefaultValues(), "" + commandSpec.usageMessage().requiredOptionMarker());
10934        }
10935        /** Returns a new minimal ParameterRenderer which converts {@linkplain PositionalParamSpec positional parameters}
10936         * to a single row with two columns of text: an option name and a description. If multiple descriptions exist, the first value is used.
10937         * @return a new minimal ParameterRenderer */
10938        public static IParameterRenderer createMinimalParameterRenderer() {
10939            return new MinimalParameterRenderer();
10940        }
10941
10942        /** Returns a value renderer that returns the {@code paramLabel} if defined or the field name otherwise.
10943         * @return a new minimal ParamLabelRenderer */
10944        public static IParamLabelRenderer createMinimalParamLabelRenderer() {
10945            return new IParamLabelRenderer() {
10946                public Text renderParameterLabel(ArgSpec argSpec, Ansi ansi, List<IStyle> styles) {
10947                    return ansi.apply(argSpec.paramLabel(), styles);
10948                }
10949                public String separator() { return ""; }
10950            };
10951        }
10952        /** Returns a new default param label renderer that separates option parameters from their option name
10953         * with the specified separator string, and, unless {@link ArgSpec#hideParamSyntax()} is true,
10954         * surrounds optional parameters with {@code '['} and {@code ']'}
10955         * characters and uses ellipses ("...") to indicate that any number of a parameter are allowed.
10956         * @return a new default ParamLabelRenderer
10957         */
10958        public IParamLabelRenderer createDefaultParamLabelRenderer() {
10959            return new DefaultParamLabelRenderer(commandSpec);
10960        }
10961        /** Sorts {@link OptionSpec OptionSpecs} by their option name in case-insensitive alphabetic order. If an
10962         * option has multiple names, the shortest name is used for the sorting. Help options follow non-help options.
10963         * @return a comparator that sorts OptionSpecs by their option name in case-insensitive alphabetic order */
10964        public static Comparator<OptionSpec> createShortOptionNameComparator() {
10965            return new SortByShortestOptionNameAlphabetically();
10966        }
10967        /** Sorts {@link OptionSpec OptionSpecs} by their option {@linkplain Range#max max arity} first, by
10968         * {@linkplain Range#min min arity} next, and by {@linkplain #createShortOptionNameComparator() option name} last.
10969         * @return a comparator that sorts OptionSpecs by arity first, then their option name */
10970        public static Comparator<OptionSpec> createShortOptionArityAndNameComparator() {
10971            return new SortByOptionArityAndNameAlphabetically();
10972        }
10973        /** Sorts short strings before longer strings.
10974         * @return a comparators that sorts short strings before longer strings */
10975        public static Comparator<String> shortestFirst() { return new ShortestFirst(); }
10976        /** Sorts {@link OptionSpec options} by their option {@linkplain IOrdered#order() order}, lowest first, highest last.
10977         * @return a comparator that sorts OptionSpecs by their order
10978         * @since 3.9*/
10979        static Comparator<OptionSpec> createOrderComparator() {
10980            return new SortByOrder<OptionSpec>();
10981        }
10982
10983        /** Returns whether ANSI escape codes are enabled or not.
10984         * @return whether ANSI escape codes are enabled or not
10985         */
10986        public Ansi ansi() { return colorScheme.ansi; }
10987
10988        /** Controls the visibility of certain aspects of the usage help message. */
10989        public enum Visibility { ALWAYS, NEVER, ON_DEMAND }
10990
10991        /** When customizing online help for {@link OptionSpec Option} details, a custom {@code IOptionRenderer} can be
10992         * used to create textual representation of an Option in a tabular format: one or more rows, each containing
10993         * one or more columns. The {@link Layout Layout} is responsible for placing these text values in the
10994         * {@link TextTable TextTable}. */
10995        public interface IOptionRenderer {
10996            /**
10997             * Returns a text representation of the specified option and its parameter(s) if any.
10998             * @param option the command line option to show online usage help for
10999             * @param parameterLabelRenderer responsible for rendering option parameters to text
11000             * @param scheme color scheme for applying ansi color styles to options and option parameters
11001             * @return a 2-dimensional array of text values: one or more rows, each containing one or more columns
11002             * @since 3.0
11003             */
11004            Text[][] render(OptionSpec option, IParamLabelRenderer parameterLabelRenderer, ColorScheme scheme);
11005        }
11006        /** The DefaultOptionRenderer converts {@link OptionSpec Options} to five columns of text to match the default
11007         * {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
11008         * <ol>
11009         * <li>the required option marker (if the option is required)</li>
11010         * <li>2-character short option name (or empty string if no short option exists)</li>
11011         * <li>comma separator (only if both short option and long option exist, empty string otherwise)</li>
11012         * <li>comma-separated string with long option name(s)</li>
11013         * <li>first element of the {@link OptionSpec#description()} array</li>
11014         * </ol>
11015         * <p>Following this, there will be one row for each of the remaining elements of the {@link
11016         *   OptionSpec#description()} array, and these rows look like {@code {"", "", "", option.description()[i]}}.</p>
11017         */
11018        static class DefaultOptionRenderer implements IOptionRenderer {
11019            private String requiredMarker = " ";
11020            private boolean showDefaultValues;
11021            private String sep;
11022            public DefaultOptionRenderer(boolean showDefaultValues, String requiredMarker) {
11023                this.showDefaultValues = showDefaultValues;
11024                this.requiredMarker = Assert.notNull(requiredMarker, "requiredMarker");
11025            }
11026            public Text[][] render(OptionSpec option, IParamLabelRenderer paramLabelRenderer, ColorScheme scheme) {
11027                String[] names = ShortestFirst.sort(option.names());
11028                int shortOptionCount = names[0].length() == 2 ? 1 : 0;
11029                String shortOption = shortOptionCount > 0 ? names[0] : "";
11030                sep = shortOptionCount > 0 && names.length > 1 ? "," : "";
11031
11032                String longOption = join(names, shortOptionCount, names.length - shortOptionCount, ", ");
11033                Text longOptionText = createLongOptionText(option, paramLabelRenderer, scheme, longOption);
11034
11035                String requiredOption = option.required() ? requiredMarker : "";
11036                return renderDescriptionLines(option, scheme, requiredOption, shortOption, longOptionText);
11037            }
11038
11039            private Text createLongOptionText(OptionSpec option, IParamLabelRenderer renderer, ColorScheme scheme, String longOption) {
11040                Text paramLabelText = renderer.renderParameterLabel(option, scheme.ansi(), scheme.optionParamStyles);
11041
11042                // if no long option, fill in the space between the short option name and the param label value
11043                if (paramLabelText.length > 0 && longOption.length() == 0) {
11044                    sep = renderer.separator();
11045                    // #181 paramLabelText may be =LABEL or [=LABEL...]
11046                    int sepStart = paramLabelText.plainString().indexOf(sep);
11047                    Text prefix = paramLabelText.substring(0, sepStart);
11048                    paramLabelText = prefix.concat(paramLabelText.substring(sepStart + sep.length()));
11049                }
11050                Text longOptionText = scheme.optionText(longOption);
11051                longOptionText = longOptionText.concat(paramLabelText);
11052                return longOptionText;
11053            }
11054
11055            private Text[][] renderDescriptionLines(OptionSpec option,
11056                                                    ColorScheme scheme,
11057                                                    String requiredOption,
11058                                                    String shortOption,
11059                                                    Text longOptionText) {
11060                Text EMPTY = Ansi.EMPTY_TEXT;
11061                boolean[] showDefault = {option.internalShowDefaultValue(showDefaultValues)};
11062                List<Text[]> result = new ArrayList<Text[]>();
11063                String[] description = option.renderedDescription();
11064                Text[] descriptionFirstLines = createDescriptionFirstLines(scheme, option, description, showDefault);
11065                result.add(new Text[] { scheme.optionText(requiredOption), scheme.optionText(shortOption),
11066                        scheme.ansi().new Text(sep), longOptionText, descriptionFirstLines[0] });
11067                for (int i = 1; i < descriptionFirstLines.length; i++) {
11068                    result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, descriptionFirstLines[i] });
11069                }
11070                for (int i = 1; i < description.length; i++) {
11071                    Text[] descriptionNextLines = scheme.ansi().new Text(description[i]).splitLines();
11072                    for (Text line : descriptionNextLines) {
11073                        result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, line });
11074                    }
11075                }
11076                if (showDefault[0]) { addTrailingDefaultLine(result, option, scheme); }
11077                return result.toArray(new Text[result.size()][]);
11078            }
11079        }
11080        /** The MinimalOptionRenderer converts {@link OptionSpec Options} to a single row with two columns of text: an
11081         * option name and a description. If multiple names or description lines exist, the first value is used. */
11082        static class MinimalOptionRenderer implements IOptionRenderer {
11083            public Text[][] render(OptionSpec option, IParamLabelRenderer parameterLabelRenderer, ColorScheme scheme) {
11084                Text optionText = scheme.optionText(option.names()[0]);
11085                Text paramLabelText = parameterLabelRenderer.renderParameterLabel(option, scheme.ansi(), scheme.optionParamStyles);
11086                optionText = optionText.concat(paramLabelText);
11087                return new Text[][] {{ optionText,
11088                                        scheme.ansi().new Text(option.description().length == 0 ? "" : option.description()[0]) }};
11089            }
11090        }
11091        /** The MinimalParameterRenderer converts {@linkplain PositionalParamSpec positional parameters} to a single row with two columns of
11092         * text: the parameters label and a description. If multiple description lines exist, the first value is used. */
11093        static class MinimalParameterRenderer implements IParameterRenderer {
11094            public Text[][] render(PositionalParamSpec param, IParamLabelRenderer parameterLabelRenderer, ColorScheme scheme) {
11095                return new Text[][] {{ parameterLabelRenderer.renderParameterLabel(param, scheme.ansi(), scheme.parameterStyles),
11096                        scheme.ansi().new Text(param.description().length == 0 ? "" : param.description()[0]) }};
11097            }
11098        }
11099        /** When customizing online help for {@linkplain PositionalParamSpec positional parameters} details, a custom {@code IParameterRenderer}
11100         * can be used to create textual representation of a Parameters field in a tabular format: one or more rows,
11101         * each containing one or more columns. The {@link Layout Layout} is responsible for placing these text
11102         * values in the {@link TextTable TextTable}. */
11103        public interface IParameterRenderer {
11104            /**
11105             * Returns a text representation of the specified positional parameter.
11106             * @param param the positional parameter to show online usage help for
11107             * @param parameterLabelRenderer responsible for rendering parameter labels to text
11108             * @param scheme color scheme for applying ansi color styles to positional parameters
11109             * @return a 2-dimensional array of text values: one or more rows, each containing one or more columns
11110             * @since 3.0
11111             */
11112            Text[][] render(PositionalParamSpec param, IParamLabelRenderer parameterLabelRenderer, ColorScheme scheme);
11113        }
11114        /** The DefaultParameterRenderer converts {@linkplain PositionalParamSpec positional parameters} to five columns of text to match the
11115         * default {@linkplain TextTable TextTable} column layout. The first row of values looks like this:
11116         * <ol>
11117         * <li>the required option marker (if the parameter's arity is to have at least one value)</li>
11118         * <li>empty string </li>
11119         * <li>empty string </li>
11120         * <li>parameter(s) label as rendered by the {@link IParamLabelRenderer}</li>
11121         * <li>first element of the {@link PositionalParamSpec#description()} array</li>
11122         * </ol>
11123         * <p>Following this, there will be one row for each of the remaining elements of the {@link
11124         *   PositionalParamSpec#description()} array, and these rows look like {@code {"", "", "", param.description()[i]}}.</p>
11125         */
11126        static class DefaultParameterRenderer implements IParameterRenderer {
11127            private String requiredMarker = " ";
11128            private boolean showDefaultValues;
11129            public DefaultParameterRenderer(boolean showDefaultValues, String requiredMarker) {
11130                this.showDefaultValues = showDefaultValues;
11131                this.requiredMarker = Assert.notNull(requiredMarker, "requiredMarker");
11132            }
11133            public Text[][] render(PositionalParamSpec param, IParamLabelRenderer paramLabelRenderer, ColorScheme scheme) {
11134                Text label = paramLabelRenderer.renderParameterLabel(param, scheme.ansi(), scheme.parameterStyles);
11135                Text requiredParameter = scheme.parameterText(param.arity().min > 0 ? requiredMarker : "");
11136
11137                Text EMPTY = Ansi.EMPTY_TEXT;
11138                boolean[] showDefault = {param.internalShowDefaultValue(showDefaultValues)};
11139                List<Text[]> result = new ArrayList<Text[]>();
11140                String[] description = param.renderedDescription();
11141                Text[] descriptionFirstLines = createDescriptionFirstLines(scheme, param, description, showDefault);
11142                result.add(new Text[] { requiredParameter, EMPTY, EMPTY, label, descriptionFirstLines[0] });
11143                for (int i = 1; i < descriptionFirstLines.length; i++) {
11144                    result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, descriptionFirstLines[i] });
11145                }
11146                for (int i = 1; i < description.length; i++) {
11147                    Text[] descriptionNextLines = scheme.ansi().new Text(description[i]).splitLines();
11148                    for (Text line : descriptionNextLines) {
11149                        result.add(new Text[] { EMPTY, EMPTY, EMPTY, EMPTY, line });
11150                    }
11151                }
11152                if (showDefault[0]) { addTrailingDefaultLine(result, param, scheme); }
11153                return result.toArray(new Text[result.size()][]);
11154            }
11155        }
11156
11157        private static void addTrailingDefaultLine(List<Text[]> result, ArgSpec arg, ColorScheme scheme) {
11158            Text EMPTY = Ansi.EMPTY_TEXT;
11159            result.add(new Text[]{EMPTY, EMPTY, EMPTY, EMPTY, scheme.ansi().new Text("  Default: " + arg.defaultValueString())});
11160        }
11161
11162        private static Text[] createDescriptionFirstLines(ColorScheme scheme, ArgSpec arg, String[] description, boolean[] showDefault) {
11163            Text[] result = scheme.ansi().new Text(str(description, 0)).splitLines();
11164            if (result.length == 0 || (result.length == 1 && result[0].plain.length() == 0)) {
11165                if (showDefault[0]) {
11166                    result = new Text[]{scheme.ansi().new Text("  Default: " + arg.defaultValueString())};
11167                    showDefault[0] = false; // don't show the default value twice
11168                } else {
11169                    result = new Text[]{ Ansi.EMPTY_TEXT };
11170                }
11171            }
11172            return result;
11173        }
11174
11175        /** When customizing online usage help for an option parameter or a positional parameter, a custom
11176         * {@code IParamLabelRenderer} can be used to render the parameter name or label to a String. */
11177        public interface IParamLabelRenderer {
11178
11179            /** Returns a text rendering of the option parameter or positional parameter; returns an empty string
11180             * {@code ""} if the option is a boolean and does not take a parameter.
11181             * @param argSpec the named or positional parameter with a parameter label
11182             * @param ansi determines whether ANSI escape codes should be emitted or not
11183             * @param styles the styles to apply to the parameter label
11184             * @return a text rendering of the Option parameter or positional parameter
11185             * @since 3.0 */
11186            Text renderParameterLabel(ArgSpec argSpec, Ansi ansi, List<IStyle> styles);
11187
11188            /** Returns the separator between option name and param label.
11189             * @return the separator between option name and param label */
11190            String separator();
11191        }
11192        /**
11193         * DefaultParamLabelRenderer separates option parameters from their {@linkplain OptionSpec option names} with a
11194         * {@linkplain CommandLine.Model.ParserSpec#separator() separator} string, and, unless
11195         * {@link ArgSpec#hideParamSyntax()} is true, surrounds optional values with {@code '['} and {@code ']'} characters
11196         * and uses ellipses ("...") to indicate that any number of values is allowed for options or parameters with variable arity.
11197         */
11198        static class DefaultParamLabelRenderer implements IParamLabelRenderer {
11199            private final CommandSpec commandSpec;
11200            /** Constructs a new DefaultParamLabelRenderer with the specified separator string. */
11201            public DefaultParamLabelRenderer(CommandSpec commandSpec) {
11202                this.commandSpec = Assert.notNull(commandSpec, "commandSpec");
11203            }
11204            public String separator() { return commandSpec.parser().separator(); }
11205            public Text renderParameterLabel(ArgSpec argSpec, Ansi ansi, List<IStyle> styles) {
11206                Range capacity = argSpec.isOption() ? argSpec.arity() : ((PositionalParamSpec)argSpec).capacity();
11207                if (capacity.max == 0) { return ansi.new Text(""); }
11208                if (argSpec.hideParamSyntax()) { return ansi.apply((argSpec.isOption() ? separator() : "") + argSpec.paramLabel(), styles); }
11209                
11210                Text paramName = ansi.apply(argSpec.paramLabel(), styles);
11211                String split = argSpec.splitRegex();
11212                String mandatorySep = empty(split) ? " "  : split;
11213                String optionalSep  = empty(split) ? " [" : "[" + split;
11214
11215                boolean unlimitedSplit = !empty(split) && !commandSpec.parser().limitSplit();
11216                boolean limitedSplit =   !empty(split) &&  commandSpec.parser().limitSplit();
11217                Text repeating = paramName;
11218                int paramCount = 1;
11219                if (unlimitedSplit) {
11220                    repeating = paramName.concat("[" + split).concat(paramName).concat("...]");
11221                    paramCount++;
11222                    mandatorySep = " ";
11223                    optionalSep = " [";
11224                }
11225                Text result = repeating;
11226
11227                int done = 1;
11228                for (; done < capacity.min; done++) {
11229                    result = result.concat(mandatorySep).concat(repeating); // " PARAM" or ",PARAM"
11230                    paramCount += paramCount;
11231                }
11232                if (!capacity.isVariable) {
11233                    for (int i = done; i < capacity.max; i++) {
11234                        result = result.concat(optionalSep).concat(paramName); // " [PARAM" or "[,PARAM"
11235                        paramCount++;
11236                    }
11237                    for (int i = done; i < capacity.max; i++) {
11238                        result = result.concat("]");
11239                    }
11240                }
11241                // show an extra trailing "[,PARAM]" if split and either max=* or splitting is not restricted to max
11242                boolean effectivelyVariable = capacity.isVariable || (limitedSplit && paramCount == 1);
11243                if (limitedSplit && effectivelyVariable && paramCount == 1) {
11244                    result = result.concat(optionalSep).concat(repeating).concat("]"); // PARAM[,PARAM]...
11245                }
11246                if (effectivelyVariable) {
11247                    if (!argSpec.arity().isVariable && argSpec.arity().min > 1) {
11248                        result = ansi.new Text("(").concat(result).concat(")"); // repeating group
11249                    }
11250                    result = result.concat("..."); // PARAM...
11251                }
11252                String optionSeparator = argSpec.isOption() ? separator() : "";
11253                if (capacity.min == 0) { // optional
11254                    String sep2 = empty(optionSeparator.trim()) ? optionSeparator + "[" : "[" + optionSeparator;
11255                    result = ansi.new Text(sep2).concat(result).concat("]");
11256                } else {
11257                    result = ansi.new Text(optionSeparator).concat(result);
11258                }
11259                return result;
11260            }
11261        }
11262        /** Use a Layout to format usage help text for options and parameters in tabular format.
11263         * <p>Delegates to the renderers to create {@link Text} values for the annotated fields, and uses a
11264         * {@link TextTable} to display these values in tabular format. Layout is responsible for deciding which values
11265         * to display where in the table. By default, Layout shows one option or parameter per table row.</p>
11266         * <p>Customize by overriding the {@link #layout(CommandLine.Model.ArgSpec, CommandLine.Help.Ansi.Text[][])} method.</p>
11267         * @see IOptionRenderer rendering options to text
11268         * @see IParameterRenderer rendering parameters to text
11269         * @see TextTable showing values in a tabular format
11270         */
11271        public static class Layout {
11272            protected final ColorScheme colorScheme;
11273            protected final TextTable table;
11274            protected IOptionRenderer optionRenderer;
11275            protected IParameterRenderer parameterRenderer;
11276
11277            /** Constructs a Layout with the specified color scheme, a new default TextTable, the
11278             * {@linkplain Help#createDefaultOptionRenderer() default option renderer}, and the
11279             * {@linkplain Help#createDefaultParameterRenderer() default parameter renderer}.
11280             * @param colorScheme the color scheme to use for common, auto-generated parts of the usage help message */
11281            public Layout(ColorScheme colorScheme, int tableWidth) { this(colorScheme, TextTable.forDefaultColumns(colorScheme.ansi(), tableWidth)); }
11282
11283            /** Constructs a Layout with the specified color scheme, the specified TextTable, the
11284             * {@linkplain Help#createDefaultOptionRenderer() default option renderer}, and the
11285             * {@linkplain Help#createDefaultParameterRenderer() default parameter renderer}.
11286             * @param colorScheme the color scheme to use for common, auto-generated parts of the usage help message
11287             * @param textTable the TextTable to lay out parts of the usage help message in tabular format */
11288            public Layout(ColorScheme colorScheme, TextTable textTable) {
11289                this(colorScheme, textTable, new DefaultOptionRenderer(false, " "), new DefaultParameterRenderer(false, " "));
11290            }
11291            /** Constructs a Layout with the specified color scheme, the specified TextTable, the
11292             * specified option renderer and the specified parameter renderer.
11293             * @param colorScheme the color scheme to use for common, auto-generated parts of the usage help message
11294             * @param optionRenderer the object responsible for rendering Options to Text
11295             * @param parameterRenderer the object responsible for rendering Parameters to Text
11296             * @param textTable the TextTable to lay out parts of the usage help message in tabular format */
11297            public Layout(ColorScheme colorScheme, TextTable textTable, IOptionRenderer optionRenderer, IParameterRenderer parameterRenderer) {
11298                this.colorScheme       = Assert.notNull(colorScheme, "colorScheme");
11299                this.table             = Assert.notNull(textTable, "textTable");
11300                this.optionRenderer    = Assert.notNull(optionRenderer, "optionRenderer");
11301                this.parameterRenderer = Assert.notNull(parameterRenderer, "parameterRenderer");
11302            }
11303            /**
11304             * Copies the specified text values into the correct cells in the {@link TextTable}. This implementation
11305             * delegates to {@link TextTable#addRowValues(CommandLine.Help.Ansi.Text...)} for each row of values.
11306             * <p>Subclasses may override.</p>
11307             * @param argSpec the Option or Parameters
11308             * @param cellValues the text values representing the Option/Parameters, to be displayed in tabular form
11309             * @since 3.0 */
11310            public void layout(ArgSpec argSpec, Text[][] cellValues) {
11311                for (Text[] oneRow : cellValues) {
11312                    table.addRowValues(oneRow);
11313                }
11314            }
11315            /** Calls {@link #addOption(CommandLine.Model.OptionSpec, CommandLine.Help.IParamLabelRenderer)} for all non-hidden Options in the list.
11316             * @param options options to add usage descriptions for
11317             * @param paramLabelRenderer object that knows how to render option parameters
11318             * @since 3.0 */
11319            public void addOptions(List<OptionSpec> options, IParamLabelRenderer paramLabelRenderer) {
11320                for (OptionSpec option : options) {
11321                    if (!option.hidden()) {
11322                        addOption(option, paramLabelRenderer);
11323                    }
11324                }
11325            }
11326            /**
11327             * Delegates to the {@link #optionRenderer option renderer} of this layout to obtain
11328             * text values for the specified {@link OptionSpec}, and then calls the {@link #layout(CommandLine.Model.ArgSpec, CommandLine.Help.Ansi.Text[][])}
11329             * method to write these text values into the correct cells in the TextTable.
11330             * @param option the option argument
11331             * @param paramLabelRenderer knows how to render option parameters
11332             * @since 3.0 */
11333            public void addOption(OptionSpec option, IParamLabelRenderer paramLabelRenderer) {
11334                Text[][] values = optionRenderer.render(option, paramLabelRenderer, colorScheme);
11335                layout(option, values);
11336            }
11337            /** Calls {@link #addPositionalParameter(CommandLine.Model.PositionalParamSpec, CommandLine.Help.IParamLabelRenderer)} for all non-hidden Parameters in the list.
11338             * @param params positional parameters to add usage descriptions for
11339             * @param paramLabelRenderer knows how to render option parameters
11340             * @since 3.0 */
11341            public void addPositionalParameters(List<PositionalParamSpec> params, IParamLabelRenderer paramLabelRenderer) {
11342                for (PositionalParamSpec param : params) {
11343                    if (!param.hidden()) {
11344                        addPositionalParameter(param, paramLabelRenderer);
11345                    }
11346                }
11347            }
11348            /**
11349             * Delegates to the {@link #parameterRenderer parameter renderer} of this layout
11350             * to obtain text values for the specified {@linkplain PositionalParamSpec positional parameter}, and then calls
11351             * {@link #layout(CommandLine.Model.ArgSpec, CommandLine.Help.Ansi.Text[][])} to write these text values into the correct cells in the TextTable.
11352             * @param param the positional parameter
11353             * @param paramLabelRenderer knows how to render option parameters
11354             * @since 3.0 */
11355            public void addPositionalParameter(PositionalParamSpec param, IParamLabelRenderer paramLabelRenderer) {
11356                Text[][] values = parameterRenderer.render(param, paramLabelRenderer, colorScheme);
11357                layout(param, values);
11358            }
11359            /** Returns the section of the usage help message accumulated in the TextTable owned by this layout. */
11360            @Override public String toString() { return table.toString(); }
11361        }
11362        /** Sorts short strings before longer strings. */
11363        static class ShortestFirst implements Comparator<String> {
11364            public int compare(String o1, String o2) {
11365                return o1.length() - o2.length();
11366            }
11367            /** Sorts the specified array of Strings shortest-first and returns it. */
11368            public static String[] sort(String[] names) {
11369                Arrays.sort(names, new ShortestFirst());
11370                return names;
11371            }
11372            /** Sorts the specified array of Strings longest-first and returns it. */
11373            public static String[] longestFirst(String[] names) {
11374                Arrays.sort(names, Collections.reverseOrder(new ShortestFirst()));
11375                return names;
11376            }
11377        }
11378        /** Sorts {@code OptionSpec} instances by their name in case-insensitive alphabetic order. If an option has
11379         * multiple names, the shortest name is used for the sorting. Help options follow non-help options. */
11380        static class SortByShortestOptionNameAlphabetically implements Comparator<OptionSpec> {
11381            public int compare(OptionSpec o1, OptionSpec o2) {
11382                if (o1 == null) { return 1; } else if (o2 == null) { return -1; } // options before params
11383                String[] names1 = ShortestFirst.sort(o1.names());
11384                String[] names2 = ShortestFirst.sort(o2.names());
11385                int result = names1[0].toUpperCase().compareTo(names2[0].toUpperCase()); // case insensitive sort
11386                result = result == 0 ? -names1[0].compareTo(names2[0]) : result; // lower case before upper case
11387                return o1.help() == o2.help() ? result : o2.help() ? -1 : 1; // help options come last
11388            }
11389        }
11390        /** Sorts {@code OptionSpec} instances by their max arity first, then their min arity, then delegates to super class. */
11391        static class SortByOptionArityAndNameAlphabetically extends SortByShortestOptionNameAlphabetically {
11392            public int compare(OptionSpec o1, OptionSpec o2) {
11393                Range arity1 = o1.arity();
11394                Range arity2 = o2.arity();
11395                int result = arity1.max - arity2.max;
11396                if (result == 0) {
11397                    result = arity1.min - arity2.min;
11398                }
11399                if (result == 0) { // arity is same
11400                    if (o1.isMultiValue() && !o2.isMultiValue()) { result = 1; } // f1 > f2
11401                    if (!o1.isMultiValue() && o2.isMultiValue()) { result = -1; } // f1 < f2
11402                }
11403                return result == 0 ? super.compare(o1, o2) : result;
11404            }
11405        }
11406        static class SortByOrder<T extends IOrdered> implements Comparator<T> {
11407            public int compare(T o1, T o2) {
11408                return Integer.signum(o1.order() - o2.order());
11409            }
11410        }
11411        /**
11412         * <p>Responsible for spacing out {@link Text} values according to the {@link Column} definitions the table was
11413         * created with. Columns have a width, indentation, and an overflow policy that decides what to do if a value is
11414         * longer than the column's width.</p>
11415         */
11416        public static class TextTable {
11417            /**
11418             * Helper class to index positions in a {@code Help.TextTable}.
11419             * @since 2.0
11420             */
11421            public static class Cell {
11422                /** Table column index (zero based). */
11423                public final int column;
11424                /** Table row index (zero based). */
11425                public final int row;
11426                /** Constructs a new Cell with the specified coordinates in the table.
11427                 * @param column the zero-based table column
11428                 * @param row the zero-based table row */
11429                public Cell(int column, int row) { this.column = column; this.row = row; }
11430            }
11431
11432            private static final int OPTION_SEPARATOR_COLUMN = 2;
11433            private static final int LONG_OPTION_COLUMN = 3;
11434
11435            /** The column definitions of this table. */
11436            private final Column[] columns;
11437
11438            /** The {@code char[]} slots of the {@code TextTable} to copy text values into. */
11439            protected final List<Text> columnValues = new ArrayList<Text>();
11440
11441            /** By default, indent wrapped lines by 2 spaces. */
11442            public int indentWrappedLines = 2;
11443
11444            private final Ansi ansi;
11445            private final int tableWidth;
11446
11447            /** Constructs a TextTable with five columns as follows:
11448             * <ol>
11449             * <li>required option/parameter marker (width: 2, indent: 0, TRUNCATE on overflow)</li>
11450             * <li>short option name (width: 2, indent: 0, TRUNCATE on overflow)</li>
11451             * <li>comma separator (width: 1, indent: 0, TRUNCATE on overflow)</li>
11452             * <li>long option name(s) (width: 24, indent: 1, SPAN multiple columns on overflow)</li>
11453             * <li>description line(s) (width: 51, indent: 1, WRAP to next row on overflow)</li>
11454             * </ol>
11455             * @param ansi whether to emit ANSI escape codes or not
11456             * @param usageHelpWidth the total width of the columns combined
11457             */
11458            public static TextTable forDefaultColumns(Ansi ansi, int usageHelpWidth) {
11459                return forDefaultColumns(ansi, defaultOptionsColumnWidth, usageHelpWidth);
11460            }
11461
11462            /** Constructs a TextTable with five columns as follows:
11463             * <ol>
11464             * <li>required option/parameter marker (width: 2, indent: 0, TRUNCATE on overflow)</li>
11465             * <li>short option name (width: 2, indent: 0, TRUNCATE on overflow)</li>
11466             * <li>comma separator (width: 1, indent: 0, TRUNCATE on overflow)</li>
11467             * <li>long option name(s) (width: 24, indent: 1, SPAN multiple columns on overflow)</li>
11468             * <li>description line(s) (width: 51, indent: 1, WRAP to next row on overflow)</li>
11469             * </ol>
11470             * @param ansi whether to emit ANSI escape codes or not
11471             * @param longOptionsColumnWidth the width of the long options column
11472             * @param usageHelpWidth the total width of the columns combined
11473             */
11474            public static TextTable forDefaultColumns(Ansi ansi, int longOptionsColumnWidth, int usageHelpWidth) {
11475                // "* -c, --create                Creates a ...."
11476                return forColumns(ansi,
11477                        new Column(2,                                       0, TRUNCATE), // "*"
11478                        new Column(2,                                       0, TRUNCATE), // "-c"
11479                        new Column(1,                                       0, TRUNCATE), // ","
11480                        new Column(longOptionsColumnWidth,                         1, SPAN),  // " --create"
11481                        new Column(usageHelpWidth - longOptionsColumnWidth, 1, WRAP)); // " Creates a ..."
11482            }
11483
11484            /** Constructs a new TextTable with columns with the specified width, all SPANning  multiple columns on
11485             * overflow except the last column which WRAPS to the next row.
11486             * @param ansi whether to emit ANSI escape codes or not
11487             * @param columnWidths the width of each table column (all columns have zero indent)
11488             */
11489            public static TextTable forColumnWidths(Ansi ansi, int... columnWidths) {
11490                Column[] columns = new Column[columnWidths.length];
11491                for (int i = 0; i < columnWidths.length; i++) {
11492                    columns[i] = new Column(columnWidths[i], 0, i == columnWidths.length - 1 ? WRAP : SPAN);
11493                }
11494                return new TextTable(ansi, columns);
11495            }
11496            /** Constructs a {@code TextTable} with the specified columns.
11497             * @param ansi whether to emit ANSI escape codes or not
11498             * @param columns columns to construct this TextTable with */
11499            public static TextTable forColumns(Ansi ansi, Column... columns) { return new TextTable(ansi, columns); }
11500            protected TextTable(Ansi ansi, Column[] columns) {
11501                this.ansi = Assert.notNull(ansi, "ansi");
11502                this.columns = Assert.notNull(columns, "columns").clone();
11503                if (columns.length == 0) { throw new IllegalArgumentException("At least one column is required"); }
11504                int totalWidth = 0;
11505                for (Column col : columns) { totalWidth += col.width; }
11506                tableWidth = totalWidth;
11507            }
11508            /** The column definitions of this table. */
11509            public Column[] columns() { return columns.clone(); }
11510            /** Returns the {@code Text} slot at the specified row and column to write a text value into.
11511             * @param row the row of the cell whose Text to return
11512             * @param col the column of the cell whose Text to return
11513             * @return the Text object at the specified row and column
11514             * @since 2.0 */
11515            public Text textAt(int row, int col) { return columnValues.get(col + (row * columns.length)); }
11516
11517            /** Returns the {@code Text} slot at the specified row and column to write a text value into.
11518             * @param row the row of the cell whose Text to return
11519             * @param col the column of the cell whose Text to return
11520             * @return the Text object at the specified row and column
11521             * @deprecated use {@link #textAt(int, int)} instead */
11522            @Deprecated public Text cellAt(int row, int col) { return textAt(row, col); }
11523
11524            /** Returns the current number of rows of this {@code TextTable}.
11525             * @return the current number of rows in this TextTable */
11526            public int rowCount() { return columnValues.size() / columns.length; }
11527
11528            /** Adds the required {@code char[]} slots for a new row to the {@link #columnValues} field. */
11529            public void addEmptyRow() {
11530                for (int i = 0; i < columns.length; i++) {
11531                    columnValues.add(ansi.new Text(columns[i].width));
11532                }
11533            }
11534
11535            /** Delegates to {@link #addRowValues(CommandLine.Help.Ansi.Text...)}.
11536             * @param values the text values to display in each column of the current row */
11537            public void addRowValues(String... values) {
11538                Text[] array = new Text[values.length];
11539                for (int i = 0; i < array.length; i++) {
11540                    array[i] = values[i] == null ? Ansi.EMPTY_TEXT : ansi.new Text(values[i]);
11541                }
11542                addRowValues(array);
11543            }
11544            /**
11545             * Adds a new {@linkplain TextTable#addEmptyRow() empty row}, then calls {@link
11546             * TextTable#putValue(int, int, CommandLine.Help.Ansi.Text) putValue} for each of the specified values, adding more empty rows
11547             * if the return value indicates that the value spanned multiple columns or was wrapped to multiple rows.
11548             * @param values the values to write into a new row in this TextTable
11549             * @throws IllegalArgumentException if the number of values exceeds the number of Columns in this table
11550             */
11551            public void addRowValues(Text... values) {
11552                if (values.length > columns.length) {
11553                    throw new IllegalArgumentException(values.length + " values don't fit in " +
11554                            columns.length + " columns");
11555                }
11556                addEmptyRow();
11557                int oldIndent = unindent(values);
11558                for (int col = 0; col < values.length; col++) {
11559                    int row = rowCount() - 1;// write to last row: previous value may have wrapped to next row
11560                    Cell cell = putValue(row, col, values[col]);
11561
11562                    // add row if a value spanned/wrapped and there are still remaining values
11563                    if ((cell.row != row || cell.column != col) && col != values.length - 1) {
11564                        addEmptyRow();
11565                    }
11566                }
11567                reindent(oldIndent);
11568            }
11569            private int unindent(Text[] values) {
11570                if (columns.length <= LONG_OPTION_COLUMN) { return 0; }
11571                int oldIndent = columns[LONG_OPTION_COLUMN].indent;
11572                if ("=".equals(values[OPTION_SEPARATOR_COLUMN].toString())) {
11573                    columns[LONG_OPTION_COLUMN].indent = 0;
11574                }
11575                return oldIndent;
11576            }
11577            private void reindent(int oldIndent) {
11578                if (columns.length <= LONG_OPTION_COLUMN) { return; }
11579                columns[LONG_OPTION_COLUMN].indent = oldIndent;
11580            }
11581
11582            /**
11583             * Writes the specified value into the cell at the specified row and column and returns the last row and
11584             * column written to. Depending on the Column's {@link Column#overflow Overflow} policy, the value may span
11585             * multiple columns or wrap to multiple rows when larger than the column width.
11586             * @param row the target row in the table
11587             * @param col the target column in the table to write to
11588             * @param value the value to write
11589             * @return a Cell indicating the position in the table that was last written to (since 2.0)
11590             * @throws IllegalArgumentException if the specified row exceeds the table's {@linkplain
11591             *          TextTable#rowCount() row count}
11592             * @since 2.0 (previous versions returned a {@code java.awt.Point} object)
11593             */
11594            public Cell putValue(int row, int col, Text value) {
11595                if (row > rowCount() - 1) {
11596                    throw new IllegalArgumentException("Cannot write to row " + row + ": rowCount=" + rowCount());
11597                }
11598                if (value == null || value.plain.length() == 0) { return new Cell(col, row); }
11599                Column column = columns[col];
11600                int indent = column.indent;
11601                switch (column.overflow) {
11602                    case TRUNCATE:
11603                        copy(value, textAt(row, col), indent);
11604                        return new Cell(col, row);
11605                    case SPAN:
11606                        int startColumn = col;
11607                        do {
11608                            boolean lastColumn = col == columns.length - 1;
11609                            int charsWritten = lastColumn
11610                                    ? copy(BreakIterator.getLineInstance(), value, textAt(row, col), indent)
11611                                    : copy(value, textAt(row, col), indent);
11612                            value = value.substring(charsWritten);
11613                            indent = 0;
11614                            if (value.length > 0) { // value did not fit in column
11615                                ++col;                // write remainder of value in next column
11616                            }
11617                            if (value.length > 0 && col >= columns.length) { // we filled up all columns on this row
11618                                addEmptyRow();
11619                                row++;
11620                                col = startColumn;
11621                                indent = column.indent + indentWrappedLines;
11622                            }
11623                        } while (value.length > 0);
11624                        return new Cell(col, row);
11625                    case WRAP:
11626                        BreakIterator lineBreakIterator = BreakIterator.getLineInstance();
11627                        do {
11628                            int charsWritten = copy(lineBreakIterator, value, textAt(row, col), indent);
11629                            value = value.substring(charsWritten);
11630                            indent = column.indent + indentWrappedLines;
11631                            if (value.length > 0) {  // value did not fit in column
11632                                ++row;                 // write remainder of value in next row
11633                                addEmptyRow();
11634                            }
11635                        } while (value.length > 0);
11636                        return new Cell(col, row);
11637                }
11638                throw new IllegalStateException(column.overflow.toString());
11639            }
11640            private static int length(Text str) {
11641                return str.length; // TODO count some characters as double length
11642            }
11643
11644            private int copy(BreakIterator line, Text text, Text columnValue, int offset) {
11645                // Deceive the BreakIterator to ensure no line breaks after '-' character
11646                line.setText(text.plainString().replace("-", "\u00ff"));
11647                int done = 0;
11648                for (int start = line.first(), end = line.next(); end != BreakIterator.DONE; start = end, end = line.next()) {
11649                    Text word = text.substring(start, end); //.replace("\u00ff", "-"); // not needed
11650                    if (columnValue.maxLength >= offset + done + length(word)) {
11651                        done += copy(word, columnValue, offset + done); // TODO messages length
11652                    } else {
11653                        break;
11654                    }
11655                }
11656                if (done == 0 && length(text) + offset > columnValue.maxLength) {
11657                    // The value is a single word that is too big to be written to the column. Write as much as we can.
11658                    done = copy(text, columnValue, offset);
11659                }
11660                return done;
11661            }
11662            private static int copy(Text value, Text destination, int offset) {
11663                int length = Math.min(value.length, destination.maxLength - offset);
11664                value.getStyledChars(value.from, length, destination, offset);
11665                return length;
11666            }
11667
11668            /** Copies the text representation that we built up from the options into the specified StringBuilder.
11669             * @param text the StringBuilder to write into
11670             * @return the specified StringBuilder object (to allow method chaining and a more fluid API) */
11671            public StringBuilder toString(StringBuilder text) {
11672                int columnCount = this.columns.length;
11673                StringBuilder row = new StringBuilder(tableWidth);
11674                for (int i = 0; i < columnValues.size(); i++) {
11675                    Text column = columnValues.get(i);
11676                    row.append(column.toString());
11677                    row.append(new String(spaces(columns[i % columnCount].width - column.length)));
11678                    if (i % columnCount == columnCount - 1) {
11679                        int lastChar = row.length() - 1;
11680                        while (lastChar >= 0 && row.charAt(lastChar) == ' ') {lastChar--;} // rtrim
11681                        row.setLength(lastChar + 1);
11682                        text.append(row.toString()).append(System.getProperty("line.separator"));
11683                        row.setLength(0);
11684                    }
11685                }
11686                return text;
11687            }
11688            public String toString() { return toString(new StringBuilder()).toString(); }
11689        }
11690        /** Columns define the width, indent (leading number of spaces in a column before the value) and
11691         * {@linkplain Overflow Overflow} policy of a column in a {@linkplain TextTable TextTable}. */
11692        public static class Column {
11693
11694            /** Policy for handling text that is longer than the column width:
11695             *  span multiple columns, wrap to the next row, or simply truncate the portion that doesn't fit. */
11696            public enum Overflow { TRUNCATE, SPAN, WRAP }
11697
11698            /** Column width in characters */
11699            public final int width;
11700
11701            /** Indent (number of empty spaces at the start of the column preceding the text value) */
11702            public int indent;
11703
11704            /** Policy that determines how to handle values larger than the column width. */
11705            public final Overflow overflow;
11706            public Column(int width, int indent, Overflow overflow) {
11707                this.width = width;
11708                this.indent = indent;
11709                this.overflow = Assert.notNull(overflow, "overflow");
11710            }
11711        }
11712
11713        /** All usage help message are generated with a color scheme that assigns certain styles and colors to common
11714         * parts of a usage message: the command name, options, positional parameters and option parameters.
11715         * Users may customize these styles by creating Help with a custom color scheme.
11716         * <p>Note that these options and styles may not be rendered if ANSI escape codes are not
11717         * {@linkplain Ansi#enabled() enabled}.</p>
11718         * @see Help#defaultColorScheme(Ansi)
11719         */
11720        public static class ColorScheme {
11721            public final List<IStyle> commandStyles = new ArrayList<IStyle>();
11722            public final List<IStyle> optionStyles = new ArrayList<IStyle>();
11723            public final List<IStyle> parameterStyles = new ArrayList<IStyle>();
11724            public final List<IStyle> optionParamStyles = new ArrayList<IStyle>();
11725            private final Ansi ansi;
11726
11727            /** Constructs a new empty ColorScheme with {@link Help.Ansi#AUTO}. */
11728            public ColorScheme() { this(Ansi.AUTO); }
11729
11730            /** Constructs a new empty ColorScheme with the specified Ansi enabled mode.
11731             * @see Help#defaultColorScheme(Ansi)
11732             * @param ansi whether to emit ANSI escape codes or not
11733             */
11734            public ColorScheme(Ansi ansi) {this.ansi = Assert.notNull(ansi, "ansi"); }
11735
11736            /** Adds the specified styles to the registered styles for commands in this color scheme and returns this color scheme.
11737             * @param styles the styles to add to the registered styles for commands in this color scheme
11738             * @return this color scheme to enable method chaining for a more fluent API */
11739            public ColorScheme commands(IStyle... styles)     { return addAll(commandStyles, styles); }
11740            /** Adds the specified styles to the registered styles for options in this color scheme and returns this color scheme.
11741             * @param styles the styles to add to registered the styles for options in this color scheme
11742             * @return this color scheme to enable method chaining for a more fluent API */
11743            public ColorScheme options(IStyle... styles)      { return addAll(optionStyles, styles);}
11744            /** Adds the specified styles to the registered styles for positional parameters in this color scheme and returns this color scheme.
11745             * @param styles the styles to add to registered the styles for parameters in this color scheme
11746             * @return this color scheme to enable method chaining for a more fluent API */
11747            public ColorScheme parameters(IStyle... styles)   { return addAll(parameterStyles, styles);}
11748            /** Adds the specified styles to the registered styles for option parameters in this color scheme and returns this color scheme.
11749             * @param styles the styles to add to the registered styles for option parameters in this color scheme
11750             * @return this color scheme to enable method chaining for a more fluent API */
11751            public ColorScheme optionParams(IStyle... styles) { return addAll(optionParamStyles, styles);}
11752            /** Returns a Text with all command styles applied to the specified command string.
11753             * @param command the command string to apply the registered command styles to
11754             * @return a Text with all command styles applied to the specified command string */
11755            public Ansi.Text commandText(String command)         { return ansi().apply(command,     commandStyles); }
11756            /** Returns a Text with all option styles applied to the specified option string.
11757             * @param option the option string to apply the registered option styles to
11758             * @return a Text with all option styles applied to the specified option string */
11759            public Ansi.Text optionText(String option)           { return ansi().apply(option,      optionStyles); }
11760            /** Returns a Text with all parameter styles applied to the specified parameter string.
11761             * @param parameter the parameter string to apply the registered parameter styles to
11762             * @return a Text with all parameter styles applied to the specified parameter string */
11763            public Ansi.Text parameterText(String parameter)     { return ansi().apply(parameter,   parameterStyles); }
11764            /** Returns a Text with all optionParam styles applied to the specified optionParam string.
11765             * @param optionParam the option parameter string to apply the registered option parameter styles to
11766             * @return a Text with all option parameter styles applied to the specified option parameter string */
11767            public Ansi.Text optionParamText(String optionParam) { return ansi().apply(optionParam, optionParamStyles); }
11768
11769            /** Replaces colors and styles in this scheme with ones specified in system properties, and returns this scheme.
11770             * Supported property names:<ul>
11771             *     <li>{@code picocli.color.commands}</li>
11772             *     <li>{@code picocli.color.options}</li>
11773             *     <li>{@code picocli.color.parameters}</li>
11774             *     <li>{@code picocli.color.optionParams}</li>
11775             * </ul><p>Property values can be anything that {@link Help.Ansi.Style#parse(String)} can handle.</p>
11776             * @return this ColorScheme
11777             */
11778            public ColorScheme applySystemProperties() {
11779                replace(commandStyles,     System.getProperty("picocli.color.commands"));
11780                replace(optionStyles,      System.getProperty("picocli.color.options"));
11781                replace(parameterStyles,   System.getProperty("picocli.color.parameters"));
11782                replace(optionParamStyles, System.getProperty("picocli.color.optionParams"));
11783                return this;
11784            }
11785            private void replace(List<IStyle> styles, String property) {
11786                if (property != null) {
11787                    styles.clear();
11788                    addAll(styles, Style.parse(property));
11789                }
11790            }
11791            private ColorScheme addAll(List<IStyle> styles, IStyle... add) {
11792                styles.addAll(Arrays.asList(add));
11793                return this;
11794            }
11795
11796            public Ansi ansi() { return ansi; }
11797        }
11798
11799        /** Creates and returns a new {@link ColorScheme} initialized with picocli default values: commands are bold,
11800         *  options and parameters use a yellow foreground, and option parameters use italic.
11801         * @param ansi whether the usage help message should contain ANSI escape codes or not
11802         * @return a new default color scheme
11803         */
11804        public static ColorScheme defaultColorScheme(Ansi ansi) {
11805            return new ColorScheme(ansi)
11806                    .commands(Style.bold)
11807                    .options(Style.fg_yellow)
11808                    .parameters(Style.fg_yellow)
11809                    .optionParams(Style.italic);
11810        }
11811
11812        /** Provides methods and inner classes to support using ANSI escape codes in usage help messages. */
11813        public enum Ansi {
11814            /** Only emit ANSI escape codes if the platform supports it and system property {@code "picocli.ansi"}
11815             * is not set to any value other than {@code "true"} (case insensitive). */
11816            AUTO,
11817            /** Forced ON: always emit ANSI escape code regardless of the platform. */
11818            ON,
11819            /** Forced OFF: never emit ANSI escape code regardless of the platform. */
11820            OFF;
11821            static Text EMPTY_TEXT = OFF.new Text(0);
11822
11823            static Boolean tty;
11824            static boolean isTTY() {
11825                if (tty == null) { tty = calcTTY(); }
11826                return tty;
11827            }
11828            static final boolean isWindows()    { return System.getProperty("os.name").startsWith("Windows"); }
11829            static final boolean isXterm()      { return System.getenv("TERM") != null && System.getenv("TERM").startsWith("xterm"); }
11830            // null on Windows unless on Cygwin or MSYS
11831            static final boolean hasOsType()    { return System.getenv("OSTYPE") != null; }
11832
11833            // see Jan Niklas Hasse's https://bixense.com/clicolors/ proposal
11834            // https://conemu.github.io/en/AnsiEscapeCodes.html#Environment_variable
11835            static final boolean hintDisabled() { return "0".equals(System.getenv("CLICOLOR"))
11836                                               || "OFF".equals(System.getenv("ConEmuANSI")); }
11837
11838            /** https://github.com/adoxa/ansicon/blob/master/readme.txt,
11839             * Jan Niklas Hasse's https://bixense.com/clicolors/ proposal,
11840             * https://conemu.github.io/en/AnsiEscapeCodes.html#Environment_variable */
11841            static final boolean hintEnabled() { return System.getenv("ANSICON") != null
11842                                               || "1".equals(System.getenv("CLICOLOR"))
11843                                               || "ON".equals(System.getenv("ConEmuANSI")); }
11844            /** https://no-color.org/ */
11845            static final boolean forceDisabled() { return System.getenv("NO_COLOR") != null; }
11846
11847            /** Jan Niklas Hasse's https://bixense.com/clicolors/ proposal */
11848            static final boolean forceEnabled() { return System.getenv("CLICOLOR_FORCE") != null
11849                                               && !"0".equals(System.getenv("CLICOLOR_FORCE"));}
11850            /** http://stackoverflow.com/questions/1403772/how-can-i-check-if-a-java-programs-input-output-streams-are-connected-to-a-term */
11851            static boolean calcTTY() {
11852                try { return System.class.getDeclaredMethod("console").invoke(null) != null; }
11853                catch (Throwable reflectionFailed) { return true; }
11854            }
11855            /** Cygwin and MSYS use pseudo-tty and console is always null... */
11856            static boolean isPseudoTTY() { return isWindows() && (isXterm() || hasOsType()); }
11857
11858            static boolean ansiPossible() {
11859                if (forceDisabled())                          { return false; }
11860                if (forceEnabled())                           { return true; }
11861                if (isWindows() && isJansiConsoleInstalled()) { return true; } // #630 JVM crash loading jansi.AnsiConsole on Linux
11862                if (hintDisabled())                           { return false; }
11863                if (!isTTY() && !isPseudoTTY())               { return false; }
11864                return hintEnabled() || !isWindows() || isXterm() || hasOsType();
11865            }
11866            static boolean isJansiConsoleInstalled() {
11867                try {
11868                    Class<?> ansiConsole = Class.forName("org.fusesource.jansi.AnsiConsole");
11869                    Field out = ansiConsole.getField("out");
11870                    return out.get(null) == System.out;
11871                } catch (Exception reflectionFailed) {
11872                    return false;
11873                }
11874            }
11875            
11876            /** Returns {@code true} if ANSI escape codes should be emitted, {@code false} otherwise.
11877             * @return ON: {@code true}, OFF: {@code false}, AUTO: if system property {@code "picocli.ansi"} is
11878             *      defined then return its boolean value, otherwise return whether the platform supports ANSI escape codes */
11879            public boolean enabled() {
11880                if (this == ON)  { return true; }
11881                if (this == OFF) { return false; }
11882                String ansi = System.getProperty("picocli.ansi");
11883                boolean auto = ansi == null || "AUTO".equalsIgnoreCase(ansi);
11884                return auto ? ansiPossible() : Boolean.getBoolean("picocli.ansi");
11885            }
11886            /**
11887             * Returns a new Text object for this Ansi mode, encapsulating the specified string
11888             * which may contain markup like {@code @|bg(red),white,underline some text|@}.
11889             * <p>
11890             * Calling {@code toString()} on the returned Text will either include ANSI escape codes
11891             * (if this Ansi mode is ON), or suppress ANSI escape codes (if this Ansi mode is OFF).
11892             * <p>
11893             * Equivalent to {@code this.new Text(stringWithMarkup)}.
11894             * @since 3.4 */
11895            public Text text(String stringWithMarkup) { return this.new Text(stringWithMarkup); }
11896
11897            /**
11898             * Returns a String where any markup like
11899             * {@code @|bg(red),white,underline some text|@} is converted to ANSI escape codes
11900             * if this Ansi is ON, or suppressed if this Ansi is OFF.
11901             * <p>
11902             * Equivalent to {@code this.new Text(stringWithMarkup).toString()}.
11903             * @since 3.4 */
11904            public String string(String stringWithMarkup) { return this.new Text(stringWithMarkup).toString(); }
11905
11906            /** Returns Ansi.ON if the specified {@code enabled} flag is true, Ansi.OFF otherwise.
11907             * @since 3.4 */
11908            public static Ansi valueOf(boolean enabled) {return enabled ? ON : OFF; }
11909
11910            /** Defines the interface for an ANSI escape sequence. */
11911            public interface IStyle {
11912
11913                /** The Control Sequence Introducer (CSI) escape sequence {@value}. */
11914                String CSI = "\u001B[";
11915
11916                /** Returns the ANSI escape code for turning this style on.
11917                 * @return the ANSI escape code for turning this style on */
11918                String on();
11919
11920                /** Returns the ANSI escape code for turning this style off.
11921                 * @return the ANSI escape code for turning this style off */
11922                String off();
11923            }
11924
11925            /**
11926             * A set of pre-defined ANSI escape code styles and colors, and a set of convenience methods for parsing
11927             * text with embedded markup style names, as well as convenience methods for converting
11928             * styles to strings with embedded escape codes.
11929             */
11930            public enum Style implements IStyle {
11931                reset(0, 0), bold(1, 21), faint(2, 22), italic(3, 23), underline(4, 24), blink(5, 25), reverse(7, 27),
11932                fg_black(30, 39), fg_red(31, 39), fg_green(32, 39), fg_yellow(33, 39), fg_blue(34, 39), fg_magenta(35, 39), fg_cyan(36, 39), fg_white(37, 39),
11933                bg_black(40, 49), bg_red(41, 49), bg_green(42, 49), bg_yellow(43, 49), bg_blue(44, 49), bg_magenta(45, 49), bg_cyan(46, 49), bg_white(47, 49),
11934                ;
11935                private final int startCode;
11936                private final int endCode;
11937
11938                Style(int startCode, int endCode) {this.startCode = startCode; this.endCode = endCode; }
11939                public String on() { return CSI + startCode + "m"; }
11940                public String off() { return CSI + endCode + "m"; }
11941
11942                /** Returns the concatenated ANSI escape codes for turning all specified styles on.
11943                 * @param styles the styles to generate ANSI escape codes for
11944                 * @return the concatenated ANSI escape codes for turning all specified styles on */
11945                public static String on(IStyle... styles) {
11946                    StringBuilder result = new StringBuilder();
11947                    for (IStyle style : styles) {
11948                        result.append(style.on());
11949                    }
11950                    return result.toString();
11951                }
11952                /** Returns the concatenated ANSI escape codes for turning all specified styles off.
11953                 * @param styles the styles to generate ANSI escape codes for
11954                 * @return the concatenated ANSI escape codes for turning all specified styles off */
11955                public static String off(IStyle... styles) {
11956                    StringBuilder result = new StringBuilder();
11957                    for (IStyle style : styles) {
11958                        result.append(style.off());
11959                    }
11960                    return result.toString();
11961                }
11962                /** Parses the specified style markup and returns the associated style.
11963                 *  The markup may be one of the Style enum value names, or it may be one of the Style enum value
11964                 *  names when {@code "fg_"} is prepended, or it may be one of the indexed colors in the 256 color palette.
11965                 * @param str the case-insensitive style markup to convert, e.g. {@code "blue"} or {@code "fg_blue"},
11966                 *          or {@code "46"} (indexed color) or {@code "0;5;0"} (RGB components of an indexed color)
11967                 * @return the IStyle for the specified converter
11968                 */
11969                public static IStyle fg(String str) {
11970                    try { return Style.valueOf(str.toLowerCase(ENGLISH)); } catch (Exception ignored) {}
11971                    try { return Style.valueOf("fg_" + str.toLowerCase(ENGLISH)); } catch (Exception ignored) {}
11972                    return new Palette256Color(true, str);
11973                }
11974                /** Parses the specified style markup and returns the associated style.
11975                 *  The markup may be one of the Style enum value names, or it may be one of the Style enum value
11976                 *  names when {@code "bg_"} is prepended, or it may be one of the indexed colors in the 256 color palette.
11977                 * @param str the case-insensitive style markup to convert, e.g. {@code "blue"} or {@code "bg_blue"},
11978                 *          or {@code "46"} (indexed color) or {@code "0;5;0"} (RGB components of an indexed color)
11979                 * @return the IStyle for the specified converter
11980                 */
11981                public static IStyle bg(String str) {
11982                    try { return Style.valueOf(str.toLowerCase(ENGLISH)); } catch (Exception ignored) {}
11983                    try { return Style.valueOf("bg_" + str.toLowerCase(ENGLISH)); } catch (Exception ignored) {}
11984                    return new Palette256Color(false, str);
11985                }
11986                /** Parses the specified comma-separated sequence of style descriptors and returns the associated
11987                 *  styles. For each markup, strings starting with {@code "bg("} are delegated to
11988                 *  {@link #bg(String)}, others are delegated to {@link #bg(String)}.
11989                 * @param commaSeparatedCodes one or more descriptors, e.g. {@code "bg(blue),underline,red"}
11990                 * @return an array with all styles for the specified descriptors
11991                 */
11992                public static IStyle[] parse(String commaSeparatedCodes) {
11993                    String[] codes = commaSeparatedCodes.split(",");
11994                    IStyle[] styles = new IStyle[codes.length];
11995                    for(int i = 0; i < codes.length; ++i) {
11996                        if (codes[i].toLowerCase(ENGLISH).startsWith("fg(")) {
11997                            int end = codes[i].indexOf(')');
11998                            styles[i] = Style.fg(codes[i].substring(3, end < 0 ? codes[i].length() : end));
11999                        } else if (codes[i].toLowerCase(ENGLISH).startsWith("bg(")) {
12000                            int end = codes[i].indexOf(')');
12001                            styles[i] = Style.bg(codes[i].substring(3, end < 0 ? codes[i].length() : end));
12002                        } else {
12003                            styles[i] = Style.fg(codes[i]);
12004                        }
12005                    }
12006                    return styles;
12007                }
12008            }
12009
12010            /** Defines a palette map of 216 colors: 6 * 6 * 6 cube (216 colors):
12011             * 16 + 36 * r + 6 * g + b (0 &lt;= r, g, b &lt;= 5). */
12012            static class Palette256Color implements IStyle {
12013                private final int fgbg;
12014                private final int color;
12015
12016                Palette256Color(boolean foreground, String color) {
12017                    this.fgbg = foreground ? 38 : 48;
12018                    String[] rgb = color.split(";");
12019                    if (rgb.length == 3) {
12020                        this.color = 16 + 36 * Integer.decode(rgb[0]) + 6 * Integer.decode(rgb[1]) + Integer.decode(rgb[2]);
12021                    } else {
12022                        this.color = Integer.decode(color);
12023                    }
12024                }
12025                public String on() { return String.format(CSI + "%d;5;%dm", fgbg, color); }
12026                public String off() { return CSI + (fgbg + 1) + "m"; }
12027            }
12028            private static class StyledSection {
12029                int startIndex, length;
12030                String startStyles, endStyles;
12031                StyledSection(int start, int len, String style1, String style2) {
12032                    startIndex = start; length = len; startStyles = style1; endStyles = style2;
12033                }
12034                StyledSection withStartIndex(int newStart) {
12035                    return new StyledSection(newStart, length, startStyles, endStyles);
12036                }
12037            }
12038
12039            /**
12040             * Returns a new Text object where all the specified styles are applied to the full length of the
12041             * specified plain text.
12042             * @param plainText the string to apply all styles to. Must not contain markup!
12043             * @param styles the styles to apply to the full plain text
12044             * @return a new Text object
12045             */
12046            public Text apply(String plainText, List<IStyle> styles) {
12047                if (plainText.length() == 0) { return new Text(0); }
12048                Text result = new Text(plainText.length());
12049                IStyle[] all = styles.toArray(new IStyle[styles.size()]);
12050                result.sections.add(new StyledSection(
12051                        0, plainText.length(), Style.on(all), Style.off(reverse(all)) + Style.reset.off()));
12052                result.plain.append(plainText);
12053                result.length = result.plain.length();
12054                return result;
12055            }
12056
12057            private static <T> T[] reverse(T[] all) {
12058                for (int i = 0; i < all.length / 2; i++) {
12059                    T temp = all[i];
12060                    all[i] = all[all.length - i - 1];
12061                    all[all.length - i - 1] = temp;
12062                }
12063                return all;
12064            }
12065            /** Encapsulates rich text with styles and colors. Text objects may be constructed with Strings containing
12066             * markup like {@code @|bg(red),white,underline some text|@}, and this class converts the markup to ANSI
12067             * escape codes.
12068             * <p>
12069             * Internally keeps both an enriched and a plain text representation to allow layout components to calculate
12070             * text width while remaining unaware of the embedded ANSI escape codes.</p> */
12071            public class Text implements Cloneable {
12072                private final int maxLength;
12073                private int from;
12074                private int length;
12075                private StringBuilder plain = new StringBuilder();
12076                private List<StyledSection> sections = new ArrayList<StyledSection>();
12077
12078                /** Constructs a Text with the specified max length (for use in a TextTable Column).
12079                 * @param maxLength max length of this text */
12080                public Text(int maxLength) { this.maxLength = maxLength; }
12081
12082                /** Copy constructor.
12083                 * @since 3.9 */
12084                public Text(Text other) {
12085                    this.maxLength = other.maxLength;
12086                    this.from = other.from;
12087                    this.length = other.length;
12088                    this.plain = new StringBuilder(other.plain);
12089                    this.sections = new ArrayList<StyledSection>(other.sections);
12090                }
12091                /**
12092                 * Constructs a Text with the specified String, which may contain markup like
12093                 * {@code @|bg(red),white,underline some text|@}.
12094                 * @param input the string with markup to parse
12095                 */
12096                public Text(String input) {
12097                    maxLength = -1;
12098                    plain.setLength(0);
12099                    int i = 0;
12100
12101                    while (true) {
12102                        int j = input.indexOf("@|", i);
12103                        if (j == -1) {
12104                            if (i == 0) {
12105                                plain.append(input);
12106                                length = plain.length();
12107                                return;
12108                            }
12109                            plain.append(input.substring(i, input.length()));
12110                            length = plain.length();
12111                            return;
12112                        }
12113                        plain.append(input.substring(i, j));
12114                        int k = input.indexOf("|@", j);
12115                        if (k == -1) {
12116                            plain.append(input);
12117                            length = plain.length();
12118                            return;
12119                        }
12120
12121                        j += 2;
12122                        String spec = input.substring(j, k);
12123                        String[] items = spec.split(" ", 2);
12124                        if (items.length == 1) {
12125                            plain.append(input);
12126                            length = plain.length();
12127                            return;
12128                        }
12129
12130                        IStyle[] styles = Style.parse(items[0]);
12131                        addStyledSection(plain.length(), items[1].length(),
12132                                Style.on(styles), Style.off(reverse(styles)) + Style.reset.off());
12133                        plain.append(items[1]);
12134                        i = k + 2;
12135                    }
12136                }
12137                private void addStyledSection(int start, int length, String startStyle, String endStyle) {
12138                    sections.add(new StyledSection(start, length, startStyle, endStyle));
12139                }
12140                public Object clone() { return new Text(this); }
12141
12142                public Text[] splitLines() {
12143                    List<Text> result = new ArrayList<Text>();
12144                    int start = 0, end = 0;
12145                    for (int i = 0; i < plain.length(); i++, end = i) {
12146                        char c = plain.charAt(i);
12147                        boolean eol = c == '\n';
12148                        if (c == '\r' && i + 1 < plain.length() && plain.charAt(i + 1) == '\n') { eol = true; i++; } // \r\n
12149                        eol |= c == '\r';
12150                        if (eol) {
12151                            result.add(this.substring(start, end));
12152                            start = i + 1;
12153                        }
12154                    }
12155                    // add remainder (may be empty string)
12156                    result.add(this.substring(start, plain.length()));
12157                    return result.toArray(new Text[result.size()]);
12158                }
12159
12160                /** Returns a new {@code Text} instance that is a substring of this Text. Does not modify this instance!
12161                 * @param start index in the plain text where to start the substring
12162                 * @return a new Text instance that is a substring of this Text */
12163                public Text substring(int start) {
12164                    return substring(start, length);
12165                }
12166
12167                /** Returns a new {@code Text} instance that is a substring of this Text. Does not modify this instance!
12168                 * @param start index in the plain text where to start the substring
12169                 * @param end index in the plain text where to end the substring
12170                 * @return a new Text instance that is a substring of this Text */
12171                public Text substring(int start, int end) {
12172                    Text result = (Text) clone();
12173                    result.from = from + start;
12174                    result.length = end - start;
12175                    return result;
12176                }
12177                /** @deprecated use {@link #concat(String)} instead */
12178                @Deprecated public Text append(String string) { return concat(string); }
12179                /** @deprecated use {@link #concat(Text)} instead */
12180                @Deprecated public Text append(Text text) { return concat(text); }
12181
12182                /** Returns a copy of this {@code Text} instance with the specified text concatenated to the end. Does not modify this instance!
12183                 * @param string the text to concatenate to the end of this Text
12184                 * @return a new Text instance
12185                 * @since 3.0 */
12186                public Text concat(String string) { return concat(new Text(string)); }
12187
12188                /** Returns a copy of this {@code Text} instance with the specified text concatenated to the end. Does not modify this instance!
12189                 * @param other the text to concatenate to the end of this Text
12190                 * @return a new Text instance
12191                 * @since 3.0 */
12192                public Text concat(Text other) {
12193                    Text result = (Text) clone();
12194                    result.plain = new StringBuilder(plain.toString().substring(from, from + length));
12195                    result.from = 0;
12196                    result.sections = new ArrayList<StyledSection>();
12197                    for (StyledSection section : sections) {
12198                        result.sections.add(section.withStartIndex(section.startIndex - from));
12199                    }
12200                    result.plain.append(other.plain.toString().substring(other.from, other.from + other.length));
12201                    for (StyledSection section : other.sections) {
12202                        int index = result.length + section.startIndex - other.from;
12203                        result.sections.add(section.withStartIndex(index));
12204                    }
12205                    result.length = result.plain.length();
12206                    return result;
12207                }
12208
12209                /**
12210                 * Copies the specified substring of this Text into the specified destination, preserving the markup.
12211                 * @param from start of the substring
12212                 * @param length length of the substring
12213                 * @param destination destination Text to modify
12214                 * @param offset indentation (padding)
12215                 */
12216                public void getStyledChars(int from, int length, Text destination, int offset) {
12217                    if (destination.length < offset) {
12218                        for (int i = destination.length; i < offset; i++) {
12219                            destination.plain.append(' ');
12220                        }
12221                        destination.length = offset;
12222                    }
12223                    for (StyledSection section : sections) {
12224                        destination.sections.add(section.withStartIndex(section.startIndex - from + destination.length));
12225                    }
12226                    destination.plain.append(plain.toString().substring(from, from + length));
12227                    destination.length = destination.plain.length();
12228                }
12229                /** Returns the plain text without any formatting.
12230                 * @return the plain text without any formatting */
12231                public String plainString() {  return plain.toString().substring(from, from + length); }
12232
12233                public boolean equals(Object obj) { return toString().equals(String.valueOf(obj)); }
12234                public int hashCode() { return toString().hashCode(); }
12235
12236                /** Returns a String representation of the text with ANSI escape codes embedded, unless ANSI is
12237                 * {@linkplain Ansi#enabled()} not enabled}, in which case the plain text is returned.
12238                 * @return a String representation of the text with ANSI escape codes embedded (if enabled) */
12239                public String toString() {
12240                    if (!Ansi.this.enabled()) {
12241                        return plain.toString().substring(from, from + length);
12242                    }
12243                    if (length == 0) { return ""; }
12244                    StringBuilder sb = new StringBuilder(plain.length() + 20 * sections.size());
12245                    StyledSection current = null;
12246                    int end = Math.min(from + length, plain.length());
12247                    for (int i = from; i < end; i++) {
12248                        StyledSection section = findSectionContaining(i);
12249                        if (section != current) {
12250                            if (current != null) { sb.append(current.endStyles); }
12251                            if (section != null) { sb.append(section.startStyles); }
12252                            current = section;
12253                        }
12254                        sb.append(plain.charAt(i));
12255                    }
12256                    if (current != null) { sb.append(current.endStyles); }
12257                    return sb.toString();
12258                }
12259
12260                private StyledSection findSectionContaining(int index) {
12261                    for (StyledSection section : sections) {
12262                        if (index >= section.startIndex && index < section.startIndex + section.length) {
12263                            return section;
12264                        }
12265                    }
12266                    return null;
12267                }
12268            }
12269        }
12270    }
12271
12272    /**
12273     * Utility class providing some defensive coding convenience methods.
12274     */
12275    private static final class Assert {
12276        /**
12277         * Throws a NullPointerException if the specified object is null.
12278         * @param object the object to verify
12279         * @param description error message
12280         * @param <T> type of the object to check
12281         * @return the verified object
12282         */
12283        static <T> T notNull(T object, String description) {
12284            if (object == null) {
12285                throw new NullPointerException(description);
12286            }
12287            return object;
12288        }
12289        static boolean equals(Object obj1, Object obj2) { return obj1 == null ? obj2 == null : obj1.equals(obj2); }
12290        static int hashCode(Object obj) {return obj == null ? 0 : obj.hashCode(); }
12291        static int hashCode(boolean bool) {return bool ? 1 : 0; }
12292        static void assertTrue(boolean condition, String message) {
12293            if (!condition) throw new IllegalStateException(message);
12294        }
12295        private Assert() {} // private constructor: never instantiate
12296    }
12297    private enum TraceLevel { OFF, WARN, INFO, DEBUG;
12298        public boolean isEnabled(TraceLevel other) { return ordinal() >= other.ordinal(); }
12299        private void print(Tracer tracer, String msg, Object... params) {
12300            if (tracer.level.isEnabled(this)) { tracer.stream.printf(prefix(msg), params); }
12301        }
12302        private String prefix(String msg) { return "[picocli " + this + "] " + msg; }
12303        static TraceLevel lookup(String key) { return key == null ? WARN : empty(key) || "true".equalsIgnoreCase(key) ? INFO : valueOf(key); }
12304    }
12305    static class Tracer {
12306        TraceLevel level = TraceLevel.lookup(System.getProperty("picocli.trace"));
12307        PrintStream stream = System.err;
12308        void warn (String msg, Object... params) { TraceLevel.WARN.print(this, msg, params); }
12309        void info (String msg, Object... params) { TraceLevel.INFO.print(this, msg, params); }
12310        void debug(String msg, Object... params) { TraceLevel.DEBUG.print(this, msg, params); }
12311        boolean isWarn()  { return level.isEnabled(TraceLevel.WARN); }
12312        boolean isInfo()  { return level.isEnabled(TraceLevel.INFO); }
12313        boolean isDebug() { return level.isEnabled(TraceLevel.DEBUG); }
12314    }
12315    /**
12316     * Uses cosine similarity to find matches from a candidate set for a specified input.
12317     * Based on code from http://www.nearinfinity.com/blogs/seth_schroeder/groovy_cosine_similarity_in_grails.html
12318     *
12319     * @author Burt Beckwith
12320     */
12321    private static class CosineSimilarity {
12322        static List<String> mostSimilar(String pattern, Iterable<String> candidates) { return mostSimilar(pattern, candidates, 0); }
12323        static List<String> mostSimilar(String pattern, Iterable<String> candidates, double threshold) {
12324            pattern = pattern.toLowerCase();
12325            SortedMap<Double, String> sorted = new TreeMap<Double, String>();
12326            for (String candidate : candidates) {
12327                double score = similarity(pattern, candidate.toLowerCase(), 2);
12328                if (score > threshold) { sorted.put(score, candidate); }
12329            }
12330            return reverseList(new ArrayList<String>(sorted.values()));
12331        }
12332
12333        private static double similarity(String sequence1, String sequence2, int degree) {
12334            Map<String, Integer> m1 = countNgramFrequency(sequence1, degree);
12335            Map<String, Integer> m2 = countNgramFrequency(sequence2, degree);
12336            return dotProduct(m1, m2) / Math.sqrt(dotProduct(m1, m1) * dotProduct(m2, m2));
12337        }
12338
12339        private static Map<String, Integer> countNgramFrequency(String sequence, int degree) {
12340            Map<String, Integer> m = new HashMap<String, Integer>();
12341            for (int i = 0; i + degree <= sequence.length(); i++) {
12342                String gram = sequence.substring(i, i + degree);
12343                m.put(gram, 1 + (m.containsKey(gram) ? m.get(gram) : 0));
12344            }
12345            return m;
12346        }
12347
12348        private static double dotProduct(Map<String, Integer> m1, Map<String, Integer> m2) {
12349            double result = 0;
12350            for (String key : m1.keySet()) { result += m1.get(key) * (m2.containsKey(key) ? m2.get(key) : 0); }
12351            return result;
12352        }
12353    }
12354    /** Base class of all exceptions thrown by {@code picocli.CommandLine}.
12355     * <h2>Class Diagram of the Picocli Exceptions</h2>
12356     * <p>
12357     * <img src="doc-files/class-diagram-exceptions.png" alt="Class Diagram of the Picocli Exceptions">
12358     * </p>
12359     * @since 2.0 */
12360    public static class PicocliException extends RuntimeException {
12361        private static final long serialVersionUID = -2574128880125050818L;
12362        public PicocliException(String msg) { super(msg); }
12363        public PicocliException(String msg, Throwable t) { super(msg, t); }
12364    }
12365    /** Exception indicating a problem during {@code CommandLine} initialization.
12366     * @since 2.0 */
12367    public static class InitializationException extends PicocliException {
12368        private static final long serialVersionUID = 8423014001666638895L;
12369        public InitializationException(String msg) { super(msg); }
12370        public InitializationException(String msg, Exception ex) { super(msg, ex); }
12371    }
12372    /** Exception indicating a problem while invoking a command or subcommand.
12373     * @since 2.0 */
12374    public static class ExecutionException extends PicocliException {
12375        private static final long serialVersionUID = 7764539594267007998L;
12376        private final CommandLine commandLine;
12377        public ExecutionException(CommandLine commandLine, String msg) {
12378            super(msg);
12379            this.commandLine = Assert.notNull(commandLine, "commandLine");
12380        }
12381        public ExecutionException(CommandLine commandLine, String msg, Throwable t) {
12382            super(msg, t);
12383            this.commandLine = Assert.notNull(commandLine, "commandLine");
12384        }
12385        /** Returns the {@code CommandLine} object for the (sub)command that could not be invoked.
12386         * @return the {@code CommandLine} object for the (sub)command where invocation failed.
12387         */
12388        public CommandLine getCommandLine() { return commandLine; }
12389    }
12390
12391    /** Exception thrown by {@link ITypeConverter} implementations to indicate a String could not be converted. */
12392    public static class TypeConversionException extends PicocliException {
12393        private static final long serialVersionUID = 4251973913816346114L;
12394        public TypeConversionException(String msg) { super(msg); }
12395    }
12396    /** Exception indicating something went wrong while parsing command line options. */
12397    public static class ParameterException extends PicocliException {
12398        private static final long serialVersionUID = 1477112829129763139L;
12399        private final CommandLine commandLine;
12400        private ArgSpec argSpec = null;
12401        private String value = null;
12402
12403        /** Constructs a new ParameterException with the specified CommandLine and error message.
12404         * @param commandLine the command or subcommand whose input was invalid
12405         * @param msg describes the problem
12406         * @since 2.0 */
12407        public ParameterException(CommandLine commandLine, String msg) {
12408            super(msg);
12409            this.commandLine = Assert.notNull(commandLine, "commandLine");
12410        }
12411
12412        /** Constructs a new ParameterException with the specified CommandLine and error message.
12413         * @param commandLine the command or subcommand whose input was invalid
12414         * @param msg describes the problem
12415         * @param t the throwable that caused this ParameterException
12416         * @since 2.0 */
12417        public ParameterException(CommandLine commandLine, String msg, Throwable t) {
12418            super(msg, t);
12419            this.commandLine = Assert.notNull(commandLine, "commandLine");
12420        }
12421
12422        /** Constructs a new ParameterException with the specified CommandLine and error message.
12423         * @param commandLine the command or subcommand whose input was invalid
12424         * @param msg describes the problem
12425         * @param t the throwable that caused this ParameterException
12426         * @param argSpec the argSpec that caused this ParameterException
12427         * @param value the value that caused this ParameterException
12428         * @since 3.2 */
12429        public ParameterException(CommandLine commandLine, String msg, Throwable t, ArgSpec argSpec, String value) {
12430            super(msg, t);
12431            this.commandLine = Assert.notNull(commandLine, "commandLine");
12432            if (argSpec == null && value == null) { throw new IllegalArgumentException("ArgSpec and value cannot both be null"); }
12433            this.argSpec = argSpec;
12434            this.value = value;
12435        }
12436
12437        /** Constructs a new ParameterException with the specified CommandLine and error message.
12438         * @param commandLine the command or subcommand whose input was invalid
12439         * @param msg describes the problem
12440         * @param argSpec the argSpec that caused this ParameterException
12441         * @param value the value that caused this ParameterException
12442         * @since 3.2 */
12443        public ParameterException(CommandLine commandLine, String msg, ArgSpec argSpec, String value) {
12444            super(msg);
12445            this.commandLine = Assert.notNull(commandLine, "commandLine");
12446            if (argSpec == null && value == null) { throw new IllegalArgumentException("ArgSpec and value cannot both be null"); }
12447            this.argSpec = argSpec;
12448            this.value = value;
12449        }
12450
12451
12452        /** Returns the {@code CommandLine} object for the (sub)command whose input could not be parsed.
12453         * @return the {@code CommandLine} object for the (sub)command where parsing failed.
12454         * @since 2.0
12455         */
12456        public CommandLine getCommandLine() { return commandLine; }
12457
12458        /** Returns the {@code ArgSpec} object for the (sub)command whose input could not be parsed.
12459         * @return the {@code ArgSpec} object for the (sub)command where parsing failed.
12460         * @since 3.2
12461         */
12462        public ArgSpec getArgSpec() { return argSpec; }
12463
12464        /** Returns the {@code String} value for the (sub)command whose input could not be parsed.
12465         * @return the {@code String} value for the (sub)command where parsing failed.
12466         * @since 3.2
12467         */
12468        public String getValue() { return value; }
12469
12470        private static ParameterException create(CommandLine cmd, Exception ex, String arg, int i, String[] args) {
12471            String msg = ex.getClass().getSimpleName() + ": " + ex.getLocalizedMessage()
12472                    + " while processing argument at or before arg[" + i + "] '" + arg + "' in " + Arrays.toString(args) + ": " + ex.toString();
12473            return new ParameterException(cmd, msg, ex, null, arg);
12474        }
12475    }
12476    /**
12477     * Exception indicating that a required parameter was not specified.
12478     */
12479    public static class MissingParameterException extends ParameterException {
12480        private static final long serialVersionUID = 5075678535706338753L;
12481        private final List<ArgSpec> missing;
12482        public MissingParameterException(CommandLine commandLine, ArgSpec missing, String msg) { this(commandLine, Arrays.asList(missing), msg); }
12483        public MissingParameterException(CommandLine commandLine, Collection<ArgSpec> missing, String msg) {
12484            super(commandLine, msg);
12485            this.missing = Collections.unmodifiableList(new ArrayList<ArgSpec>(missing));
12486        }
12487        public List<ArgSpec> getMissing() { return missing; }
12488        private static MissingParameterException create(CommandLine cmd, Collection<ArgSpec> missing, String separator) {
12489            if (missing.size() == 1) {
12490                return new MissingParameterException(cmd, missing, "Missing required option '"
12491                        + ArgSpec.describe(missing.iterator().next(), separator) + "'");
12492            }
12493            List<String> names = new ArrayList<String>(missing.size());
12494            for (ArgSpec argSpec : missing) {
12495                names.add(ArgSpec.describe(argSpec, separator));
12496            }
12497            return new MissingParameterException(cmd, missing, "Missing required options " + names.toString());
12498        }
12499    }
12500    /** Exception indicating that the user input included multiple arguments from a mutually exclusive group.
12501     * @since 4.0 */
12502    public static class MutuallyExclusiveArgsException extends ParameterException {
12503        private static final long serialVersionUID = -5557715106221420986L;
12504        public MutuallyExclusiveArgsException(CommandLine commandLine, String msg) { super(commandLine, msg); }
12505    }
12506
12507    /** Exception indicating that multiple named elements have incorrectly used the same name.
12508     * @since 4.0 */
12509    public static class DuplicateNameException extends InitializationException {
12510        private static final long serialVersionUID = -4126747467955626054L;
12511        public DuplicateNameException(String msg) { super(msg); }
12512    }
12513    /**
12514     * Exception indicating that multiple fields have been annotated with the same Option name.
12515     */
12516    public static class DuplicateOptionAnnotationsException extends DuplicateNameException {
12517        private static final long serialVersionUID = -3355128012575075641L;
12518        public DuplicateOptionAnnotationsException(String msg) { super(msg); }
12519
12520        private static DuplicateOptionAnnotationsException create(String name, ArgSpec argSpec1, ArgSpec argSpec2) {
12521            return new DuplicateOptionAnnotationsException("Option name '" + name + "' is used by both " +
12522                    argSpec1.toString() + " and " + argSpec2.toString());
12523        }
12524    }
12525    /** Exception indicating that there was a gap in the indices of the fields annotated with {@link Parameters}. */
12526    public static class ParameterIndexGapException extends InitializationException {
12527        private static final long serialVersionUID = -1520981133257618319L;
12528        public ParameterIndexGapException(String msg) { super(msg); }
12529    }
12530    /** Exception indicating that a command line argument could not be mapped to any of the fields annotated with
12531     * {@link Option} or {@link Parameters}. */
12532    public static class UnmatchedArgumentException extends ParameterException {
12533        private static final long serialVersionUID = -8700426380701452440L;
12534        private List<String> unmatched = Collections.<String>emptyList();
12535        public UnmatchedArgumentException(CommandLine commandLine, String msg) { super(commandLine, msg); }
12536        public UnmatchedArgumentException(CommandLine commandLine, Stack<String> args) { this(commandLine, new ArrayList<String>(reverse(args))); }
12537        public UnmatchedArgumentException(CommandLine commandLine, List<String> args) {
12538            this(commandLine, describe(args, commandLine) + (args.size() == 1 ? ": " : "s: ") + str(args));
12539            unmatched = args == null ? Collections.<String>emptyList() : args;
12540        }
12541        /** Returns {@code true} and prints suggested solutions to the specified stream if such solutions exist, otherwise returns {@code false}.
12542         * @since 3.3.0 */
12543        public static boolean printSuggestions(ParameterException ex, PrintStream out) {
12544            return ex instanceof UnmatchedArgumentException && ((UnmatchedArgumentException) ex).printSuggestions(out);
12545        }
12546        /** Returns the unmatched command line arguments.
12547         * @since 3.3.0 */
12548        public List<String> getUnmatched() { return stripErrorMessage(unmatched); }
12549        static List<String> stripErrorMessage(List<String> unmatched) {
12550            List<String> result = new ArrayList<String>();
12551            for (String s : unmatched) {
12552                if (s == null) { result.add(null); }
12553                int pos = s.indexOf(" (while processing option:");
12554                result.add(pos < 0 ? s : s.substring(0, pos));
12555            }
12556            return Collections.unmodifiableList(result);
12557        }
12558        /** Returns {@code true} if the first unmatched command line arguments resembles an option, {@code false} otherwise.
12559         * @since 3.3.0 */
12560        public boolean isUnknownOption() { return isUnknownOption(unmatched, getCommandLine()); }
12561        /** Returns {@code true} and prints suggested solutions to the specified stream if such solutions exist, otherwise returns {@code false}.
12562         * @since 3.3.0 */
12563        public boolean printSuggestions(PrintStream out) {
12564            List<String> suggestions = getSuggestions();
12565            if (!suggestions.isEmpty()) {
12566                out.println(isUnknownOption()
12567                        ? "Possible solutions: " + str(suggestions)
12568                        : "Did you mean: " + str(suggestions).replace(", ", " or ") + "?");
12569            }
12570            return !suggestions.isEmpty();
12571        }
12572        /** Returns suggested solutions if such solutions exist, otherwise returns an empty list.
12573         * @since 3.3.0 */
12574        public List<String> getSuggestions() {
12575            if (unmatched == null || unmatched.isEmpty()) { return Collections.emptyList(); }
12576            String arg = unmatched.get(0);
12577            String stripped = CommandSpec.stripPrefix(arg);
12578            CommandSpec spec = getCommandLine().getCommandSpec();
12579            if (spec.resemblesOption(arg, null)) {
12580                return spec.findOptionNamesWithPrefix(stripped.substring(0, Math.min(2, stripped.length())));
12581            } else if (!spec.subcommands().isEmpty()) {
12582                List<String> mostSimilar = CosineSimilarity.mostSimilar(arg, spec.subcommands().keySet());
12583                return mostSimilar.subList(0, Math.min(3, mostSimilar.size()));
12584            }
12585            return Collections.emptyList();
12586        }
12587        private static boolean isUnknownOption(List<String> unmatch, CommandLine cmd) {
12588            return unmatch != null && !unmatch.isEmpty() && cmd.getCommandSpec().resemblesOption(unmatch.get(0), null);
12589        }
12590        private static String describe(List<String> unmatch, CommandLine cmd) {
12591            return isUnknownOption(unmatch, cmd) ? "Unknown option" : "Unmatched argument";
12592        }
12593        static String str(List<String> list) {
12594            String s = list.toString();
12595            return s.substring(0, s.length() - 1).substring(1);
12596        }
12597    }
12598    /** Exception indicating that more values were specified for an option or parameter than its {@link Option#arity() arity} allows. */
12599    public static class MaxValuesExceededException extends ParameterException {
12600        private static final long serialVersionUID = 6536145439570100641L;
12601        public MaxValuesExceededException(CommandLine commandLine, String msg) { super(commandLine, msg); }
12602    }
12603    /** Exception indicating that an option for a single-value option field has been specified multiple times on the command line. */
12604    public static class OverwrittenOptionException extends ParameterException {
12605        private static final long serialVersionUID = 1338029208271055776L;
12606        private final ArgSpec overwrittenArg;
12607        public OverwrittenOptionException(CommandLine commandLine, ArgSpec overwritten, String msg) {
12608            super(commandLine, msg);
12609            overwrittenArg = overwritten;
12610        }
12611        /** Returns the {@link ArgSpec} for the option which was being overwritten.
12612         * @since 3.8 */
12613        public ArgSpec getOverwritten() { return overwrittenArg; }
12614    }
12615    /**
12616     * Exception indicating that an annotated field had a type for which no {@link ITypeConverter} was
12617     * {@linkplain #registerConverter(Class, ITypeConverter) registered}.
12618     */
12619    public static class MissingTypeConverterException extends ParameterException {
12620        private static final long serialVersionUID = -6050931703233083760L;
12621        public MissingTypeConverterException(CommandLine commandLine, String msg) { super(commandLine, msg); }
12622    }
12623}